山东大学项目实训Web实验室(WebLab)(八)学生端主页面

山东大学项目实训Web实验室(WebLab)(n)界面

  • 前言
  • 任务目标
  • 我的任务
  • 展示内容
  • 代码

前言

项目仓库
本项目是为开发一套容器化的开发、运行、测试环境,用以支持Web开发、程序设计等课程的实验教学。
代码内容均为我和肖同学共同完成。

任务目标

设计并且编写主界面
主界面内容:

  • 学生界面
    • 项目中心
      • 课程任务
      • 课程通知
      • 我的项目
    • 上传中心
    • 编辑中心
    • 组织中心
  • 老师界面
    • 组织中心
    • 发布中心
    • 学生课程作业

我的任务

  • 页面外观与布局设计
  • 页面交互设计
  • 页面编写

展示内容

  • 学生端主页面

代码

view/coding-view.vue

import { FileType } from "../fileziper";
<!--login-coding-project-page-->
<template>
  <el-header>
    <topmenu :activeIndex=activeIndex @on-index-change="onIndexChange"></topmenu>
  </el-header>
  <el-main v-show="activeIndex == '5'">
    <el-header>
      <el-row :gutter="20">
        <el-col :span="3">
          <el-input v-model="invitationCode" placeholder="组织邀请码" :style="{width:'200px'} "/>
        </el-col>
        <el-col :span="6">
          <el-button text @click="addOrganization()">添加组织</el-button>
        </el-col>
        <el-col :span="6" />
        <el-col :span="6" />

      </el-row>

    </el-header>
    <el-main>
      <el-table :data="organizationData" border style="width: 100%">
        <el-table-column prop="lesson" label="课程" width="510px" />
        <el-table-column prop="class" label="班级" width="510px" />
        <el-table-column width="110px">
          <template #default="scope">
            <el-button text size="small" @click="deleteOrganization(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-main>

  </el-main>

  <el-main v-show="activeIndex == '4'">
    <el-row class="tac">
      <el-col :span="5">
        <side ref="sideRef" @set-file-context="setFileContext" @detele-file="removeTab" @rename="rename" />
      </el-col>
      <el-col :span="1"></el-col>
      <el-col :span="18">
        <div v-show="editableTabsValue != '-1'">
          <el-tabs v-model="editableTabsValue" type="card" class="demo-tabs" closable @tab-remove="removeTab"
            @tab-click="clickTab">
            <el-tab-pane v-for="item in editableTabs" :key="item.name" :label="item.title" :name="item.name">
            </el-tab-pane>
          </el-tabs>
          <code-editor-vue ref="cmRef" @on-change="onCodeChange"></code-editor-vue>
        </div>
        <div v-show="editableTabsValue == '-1'">
          <el-result title="点击打开文件">
            <template #icon>
              <el-icon :size="280">
                <files />
              </el-icon>
            </template>
          </el-result>
        </div>

        <div class="grid-content"></div>
        <el-divider content-position="center">
          <btns @save-z-i-p="saveZIP"></btns>
        </el-divider>
        <div class="grid-content"></div>
        <ResultsDisplay></ResultsDisplay>
      </el-col>
    </el-row>
  </el-main>
  <el-main v-show="activeIndex == '3'">
    <div class="login-wrap">
      <el-form class="login-container">
        <el-upload class="upload-demo" drag action="#" multiple accept=".zip" :http-request="handleUpload">
          <el-icon class="el-icon--upload">
            <upload-filled />
          </el-icon>
          <div class="el-upload__text">
            拖拽文件或
            <em>点击上传</em>
          </div>
          <template #tip>
            <div class="el-upload__tip">只支持zip压缩包</div>
          </template>
        </el-upload>
      </el-form>
    </div>
  </el-main>
  <el-main v-show="activeIndex == '2'">
    <el-tabs v-model="activeProjectTabName" class="demo-tabs" @tab-click="handleProjectTabClick">
      <el-tab-pane label="课程任务" name="1">
        <el-main>
          <el-dialog v-model="choseProjectFormVisible" title="选择项目" width="30%">
            <el-form>
              <el-form-item label="项目名称" label-width="100px">
                <el-cascader
                    v-model="choseProject"
                    placeholder="项目搜索"
                    :options="projectData"
                    filterable
                    :props="choseProjectProps"
                />
              </el-form-item>
            </el-form>
            <template #footer>
                <span class="dialog-footer">
                  <el-button @click="choseProjectFormVisible = false">取消</el-button>
                  <el-button type="primary" @click="submitProject">确认</el-button>
                </span>
            </template>
          </el-dialog>
          <el-table :data="homeworkTableData" border style="width: 100%">
            <el-table-column prop="lesson" label="课程" width="180" />
            <el-table-column prop="date" label="截止日期" sortable width="180">
              <template #default="scope">
                <div style="display: flex; align-items: center">
                  <el-icon>
                    <timer />
                  </el-icon>
                  <span style="margin-left: 10px">{{ scope.row.date }}</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column prop="mission" label="任务简介" />
            <el-table-column prop="finish" label="任务进度"  width="100"/>
            <el-table-column fixed="right" width="200">
              <template #default="scope">
                <el-button text size="small" @click="checkDetail(scope.row.missionDetail)">查看详情</el-button>
                <el-button text size="small" @click="choseProjectFormVisible=true">提交作业</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-main>

      </el-tab-pane>
      <el-tab-pane label="课程通知" name="2">
        <el-table :data="noticeTableData" border style="width: 100%">
          <el-table-column prop="className" label="课程" width="180" />
          <el-table-column prop="date" label="发布日期" sortable width="180">
            <template #default="scope">
              <div style="display: flex; align-items: center">
                <el-icon>
                  <timer />
                </el-icon>
                <span style="margin-left: 10px">{{ scope.row.date }}</span>
              </div>
            </template>
          </el-table-column>
          <el-table-column prop="detail" label="通知内容" />
          <el-table-column fixed="right" width="180">
            <template #default="scope">
              <el-button text size="small" @click="checkDetail(scope.row.detail)">查看详情</el-button>
            </template>
          </el-table-column>
        </el-table>

      </el-tab-pane>
      <el-tab-pane label="我的项目" name="3">
        <div v-show="!showDetail">
          <el-header>
            <el-button @click="addProject()">
              添加<el-icon class="el-icon--right">
                <Plus />
              </el-icon>
            </el-button>
            <el-button @click="deleteProject()">
              删除<el-icon class="el-icon--right">
                <Delete />
              </el-icon>
            </el-button>
            <el-button @click="downloadProject()">
              下载<el-icon class="el-icon--right">
                <Bottom />
              </el-icon>
            </el-button>
          </el-header>
          <el-main>
            <el-dialog v-model="createProjectFormVisible" title="添加项目" width="30%">
              <el-form :model="createProjectForm">
                <el-form-item label="项目名称" label-width="100px">
                  <el-input v-model="createProjectForm.name" autocomplete="off" />
                </el-form-item>
                <el-form-item label="项目简介" label-width="100px">
                  <el-input type="textarea" v-model="createProjectForm.description" />
                </el-form-item>
              </el-form>
              <template #footer>
                <span class="dialog-footer">
                  <el-button @click="createProjectFormVisible = false">取消</el-button>
                  <el-button type="primary" @click="confirmAddProject">确认</el-button>
                </span>
              </template>
            </el-dialog>
            <el-table ref="projectTableRef" :data="projectData" border style="width: 100%"
              @selection-change="handleProjectSelectionChange">
              <el-table-column type="selection" width="55" />
              <el-table-column prop="projectName" label="项目名字" width="180">
                <template #default="scope">
                  <div style="display: flex; align-items: center">
                    <el-icon>
                      <folder />
                    </el-icon>
                    <span style="margin-left: 10px">{{ scope.row.projectName }}</span>
                  </div>
                </template>
              </el-table-column>
              <el-table-column prop="date" label="上次更新" width="180" />
              <el-table-column prop="introduction" label="项目简介" />
              <el-table-column fixed="right" width="220">
                <template #default="scope">
                  <el-button text size="small" @click="showProjectDetail(scope.row)">项目详情</el-button>
                  <el-button text size="small" @click="editProject(scope.raw)">编辑项目</el-button>
                </template>

              </el-table-column>
            </el-table>
          </el-main>
        </div>
        <div v-show="showDetail">
          <el-main>
            <el-page-header content="项目详情" @back="closeProjectDetail" />
            <el-container>
              <el-main>
                <el-table :data="selectedProjectDetail?.files" style="width: 100%">
                  <el-table-column prop="name" label="文件夹名字" width="180">
                    <template #default="scope">
                      <div style="display: flex; align-items: center">
                        <el-icon>
                          <folder />
                        </el-icon>
                        <el-button type="text" style="margin-left: 10px">{{ scope.row.name }}</el-button>
                      </div>
                    </template>
                  </el-table-column>
                  <el-table-column prop="date" label="上次更新" width="180" />
                  <el-table-column prop="introduction" label="简介" />
                  <el-table-column fixed="right" width="120">
                    <template #default="scope">
                      <el-button text size="small" @click="deleteProjecFolder(scope.$index)">删除</el-button>
                    </template>

                  </el-table-column>
                </el-table>
                <el-main>
                  <el-divider />
                  <h6>项目输出日志</h6>
                  <div class="demo-radius">
                      <el-input type="textarea" class="example-demonstration">{{selectedProjectDetail?.outputlog}}</el-input>
                  </div>
                </el-main>

              </el-main>

              <el-aside width="300px">
                <el-row>
                  <el-col :span="2">
                    <el-divider direction="vertical" style="height: 800px" />
                  </el-col>
                  <el-col :span="22">
                    <el-form label-width="120px">
                      <el-form-item size="large" label="项目介绍">
                      </el-form-item>
                        <el-input type="textarea" class="example-demonstration">{{selectedProjectDetail?.introduction}}</el-input>
                    </el-form>
                  </el-col>
                </el-row>
              </el-aside>
            </el-container>
          </el-main>
        </div>
      </el-tab-pane>
    </el-tabs>

  </el-main>
</template>

<script lang="ts" setup>
import { ref, watch, reactive } from "vue";
import CodeEditorVue from "../components/CodeEditor.vue";
import ResultsDisplay from "../components/ResultsDisplay.vue"
import btns from "../layout/btns.vue"
import topmenu from "../layout/topmenu.vue";
import side from "../layout/sidecolumn.vue"
import { ziper } from "../fileziper"
import type { FileType } from "../fileziper";
import { useLoginStore } from '@/stores/store';
import { Files, UploadFilled } from '@element-plus/icons-vue';
import { request } from "@/network/request";
import { ElMessage, ElMessageBox } from "element-plus";
import type { TabsPaneContext, ElTable } from 'element-plus';
import { Folder, Timer, Delete, Bottom, Plus } from '@element-plus/icons-vue';
import type { ElTree } from 'element-plus'
import Node from "element-plus/es/components/tree/src/model/node";
import { h } from 'vue';

const activeIndex = ref('2');
const lstore = useLoginStore();
const onIndexChange = (idx: string) => {
  activeIndex.value = idx;
}
const getFormDate = () => {
  const Dates = new Date();

  //年份
  const Year: number = Dates.getFullYear();

  //月份下标是0-11
  const Months: any = (Dates.getMonth() + 1) < 10 ? '0' + (Dates.getMonth() + 1) : (Dates.getMonth() + 1);

  //具体的天数
  const Day: any = Dates.getDate() < 10 ? '0' + Dates.getDate() : Dates.getDate();
  return Year + '-' + Months + '-' + Day;
}
//上传中心
const upload = (param: FormData) => {
  request('/weblab/submit/submitByZip', param, lstore.getToken)
    .then(res => {
      if (res.status == 200 && res.data.msg == 'success') {
        console.log(res);
        ElMessage({
          showClose: true,
          message: '上传成功',
          type: 'success',
          center: true,
          grouping: true
        })
      }
    })
    .catch(error => {
      console.log(error);

    })
}
const handleUpload = (file: any) => {
  let param = new FormData();
  param.append('file', file.file);
  upload(param);
}

//编辑中心
const sideRef = ref();
const cmRef = ref();
const editableTabsValue = ref('-1');
interface tab {
  title: string,
  name: string
}
const editableTabs = ref<tab[]>([]);

const addTab = (name: string, id: string) => {
  editableTabs.value.push({
    title: name,
    name: id,
  })
  editableTabsValue.value = id;
}

const removeTab = (id: string) => {
  const tabs = editableTabs.value
  let activeName = editableTabsValue.value
  if (activeName === id) {
    tabs.forEach((tab, index) => {
      if (tab.name === id) {
        const nextTab = tabs[index + 1] || tabs[index - 1]
        if (nextTab) {
          activeName = nextTab.name
          const code = sideRef.value.getCode(activeName);
          cmRef.value.setCode(code.code, code.type);
        }
      }
    })
  }

  editableTabsValue.value = activeName
  editableTabs.value = tabs.filter((tab) => tab.name !== id)
  if (editableTabs.value.length == 0)
    editableTabsValue.value = '-1';
}

const clickTab = (pane: TabsPaneContext, ev: Event) => {
  const code = sideRef.value.getCode(pane.props.name);
  cmRef.value.setCode(code.code, code.type);
}

const rename = (id: string, new_name: string) => {
  const tabs = editableTabs.value
  tabs.forEach((tab, index) => {
    if (tab.name === id) {
      tab.title = new_name;
    }
  })
}
const setFileContext = (name: string, id: string, code: string | undefined, type: FileType) => {
  cmRef.value.setCode(code, type);
  const tabs = editableTabs.value
  let flag = false;
  tabs.forEach((tab, index) => {
    if (tab.name == id) {
      editableTabsValue.value = id;
      flag = true;
    }
  })
  if (!flag) {
    addTab(name, id);
  }
}

const onCodeChange = (value: string) => {
  sideRef.value.setCode(editableTabsValue.value, value);

}

const saveZIP = async () => {
  ziper.setProjectName(sideRef.value.getProjectName());
  ziper.updateProject(sideRef.value.getData());
  const param: any = await ziper.uploadFile();
  if (param != undefined)
    upload(param);
}

//组织中心
const invitationCode = ref('');

const organizationData = ref([
  {
    lesson: '项目',
    class: '软一',
  },
  {
    lesson: '实训',
    class: '软一',
  },
])
const addOrganization = () => {
  ElMessageBox.alert('是否加入班级XXX', '加入班级', {
    confirmButtonText: 'OK',
    // callback: (action: Action) => {
    //   ElMessage({
    //     type: 'info',
    //     message: `action: ${action}`,
    //   })
    // },
  })
}
const deleteOrganization = (val: any) => {
  ElMessageBox.confirm('将删除该课程,继续?', 'Warning',
    {
      confirmButtonText: 'OK',
      cancelButtonText: 'Cancel',
      type: 'warning',
    })
    .then(() => {
      const targetIdx = organizationData.value.findIndex((d) => d == val);
      organizationData.value.splice(targetIdx, 1);
    })
}


//项目中心

//课程任务
const choseProjectFormVisible = ref(false);
const choseProjectProps={
  label:'projectName',
  value:'projectName'
}
const choseProject=ref('');

const homeworkTableData = ref<hwDataIF[]>([
  {
    lesson: '项目实训',
    mission: '任务简介',
    date: '2022-05-15',
    missionDetail: '用vue3+springboot完成一个简单的前后端分离项目',
    finish:'已完成'
  },
  {
    lesson: '项目实训',
    mission: '任务简介',
    date: '2022-06-15',
    missionDetail: '用vue3+springboot完成一个简单的前后端分离项目',
    finish:'未完成'
  },
])
//查看作业详情
const checkDetail = (detail: string) => {
  ElMessageBox.alert(detail, '详情', {
    confirmButtonText: 'OK',
  })
}
//提交项目
const submitProject=()=>{
  choseProjectFormVisible.value = false
  console.log(choseProject.value)
}

//课程通知
interface noticetDataIF {
  className: string,
  date: string,
  detail: string
}
const noticeTableData=ref<noticetDataIF[]>([
  {
    className:'项目实训',
    date:'2022-5-24',
    detail:'请同学们与6-30前提交作业'
  }
]);


//我的项目
const showDetail = ref(false);
const activeProjectTabName = ref('1');
const createProjectFormVisible = ref(false);
const createProjectForm = reactive({
  name: '',
  description: ''
})

const projectTableRef = ref<InstanceType<typeof ElTable>>()
const selectedProject = ref<projectDataIF[]>();
const selectedProjectDetail = ref<projectDetailIF>();
//任务数据
interface hwDataIF {
  lesson: string,
  mission: string,
  date: string,
  missionDetail: string,
  finish:string
}

//项目数据
//项目详情内容
interface projectFilesIF {
  name: string,
  date: string,
  introduction: string
}
interface projectDetailIF {
  outputlog: string,
  introduction: string,
  files: projectFilesIF[]
}
interface projectDataIF {
  projectName: string,
  introduction: string,
  date: string,
  detail: projectDetailIF
}
const projectData = ref<projectDataIF[]>([
  {
    projectName: '项目实训',
    introduction: '项目实训简介',
    date: '2022-05-15',
    detail: {
      outputlog: '输出日志',
      introduction: '项目介绍',
      files: [
        {
          name: 'src',
          introduction: 'src',
          date: '2022-05-15',
        },
        {
          name: 'views',
          introduction: 'views',
          date: '2022-05-15',
        },
      ]
    }
  },
  {
    projectName: 'web',
    introduction: 'web简介',
    date: '2022-05-15',
    detail: {
      outputlog: '输出日志',
      introduction: '项目介绍',
      files: [
        {
          name: 'src',
          introduction: 'src',
          date: '2022-05-15',
        },
        {
          name: 'views',
          introduction: 'views',
          date: '2022-05-15',
        },
      ]
    }
  },
])


//编辑项目
const editProject = (data: projectDataIF) => {
  activeIndex.value = '4'
}
//查看项目详情
const showProjectDetail = (data: projectDataIF) => {
  const idx = projectData.value.findIndex(item => item == data);
  selectedProjectDetail.value = projectData.value[idx].detail;
  showDetail.value = true;
}
const closeProjectDetail = () => {
  showDetail.value = false;
}
//删除项目内容
const deleteProjecFolder = (index: number) => {
  ElMessageBox.confirm('将删除该文件,继续?', 'Warning',
    {
      confirmButtonText: 'OK',
      cancelButtonText: 'Cancel',
      type: 'warning',
    })
    .then(() => {
      selectedProjectDetail.value?.files.splice(index, 1);
    })
}
//添加项目
const addProject = () => {
  createProjectFormVisible.value = true;
}
const confirmAddProject = () => {
  createProjectFormVisible.value = false;
  projectData.value.push({
    projectName: createProjectForm.name,
    introduction: createProjectForm.description,
    date: getFormDate(),
    detail: {
      outputlog: '',
      introduction: '',
      files: []
    }
  })
}
//删除项目
const deleteProject = () => {
  ElMessageBox.confirm('将删除选中的项目,继续?', 'Warning',
    {
      confirmButtonText: 'OK',
      cancelButtonText: 'Cancel',
      type: 'warning',
    })
    .then(() => {
      projectData.value = projectData.value.filter((x) => !selectedProject.value!.some((item) => x.projectName === item.projectName));
      projectTableRef.value!.clearSelection();
    })

}
//下载项目
const downloadProject = () => {

  projectTableRef.value!.clearSelection();
}


const handleProjectTabClick = (pane: TabsPaneContext, ev: Event) => {
  // console.log(pane);
}

const handleProjectSelectionChange = (val: projectDataIF[]) => {
  selectedProject.value = val;
}
</script>

<style>
.grid-content {
  border-radius: 4px;
  min-height: 10px;
}

.demo-tabs>.el-tabs__content {
  padding: 0px;
  color: #6b778c;
  font-size: 32px;
  font-weight: 600;
}

.title {
  margin: 0px auto 40px auto;
  text-align: center;
  color: #505458;
}

.demo-radius {
  height: 800px;
  width: 90%;
  border: 1px solid #b7b7ba;
  border-radius: 10px;
  margin-top: 20px;
}

.example-demonstration {
  margin: 1rem;
}

.dialog-footer button:first-child {
  margin-right: 10px;
}
</style>

你可能感兴趣的:(WebLab,前端,vue.js,typescript)