前言
项目仓库
本项目是为开发一套容器化的开发、运行、测试环境,用以支持Web开发、程序设计等课程的实验教学。
代码内容均为我和肖同学共同完成。
任务目标
设计并且编写主界面
主界面内容:
- 学生界面
- 项目中心
- 课程任务
- 课程通知
- 我的项目
- 上传中心
- 编辑中心
- 组织中心
- 项目中心
- 老师界面
- 组织中心
- 发布中心
- 学生课程作业
我的任务
- 页面外观与布局设计
- 页面交互设计
- 页面编写
展示内容
- 学生端主页面项目布置功能
- 学生端主页面市场中心
- 删除学生端主页面上传中心及项目编辑按钮
代码
view/coding.vue
import { FileType } from "../fileziper";
<!--login-student-home-page-->
<template>
<el-header>
<topmenu ref="tmRef" :activeIndex="activeIndex" :avatar-url="avatarUrl" @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="2" />
<el-col :span="6">
<el-button text @click="addOrganization()">添加组织</el-button>
</el-col>
<el-col :span="12" />
</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="teacher" 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-tabs
v-model="activeMarketName"
tab-position="left"
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane label="数据库" name="first">
<el-header>
<div class="tag-group my-2 flex flex-wrap gap-1 items-center">
<el-row>
<el-col :span="2">
<span class="tag-group__title m-1 line-height-2" style="font-size: medium">所选数据库:</span>
</el-col>
<el-col :span="1"/>
<el-col :span="21">
<el-tag
size="large"
effect="plain"
>
MySQL
</el-tag>
</el-col>
</el-row>
</div>
</el-header>
<el-main>
<el-tabs type="border-card">
<el-tab-pane label="关系型数据库">
<el-row >
<el-col :span="24">
<el-radio v-model="radio1" label="1" size="large" border >MySQL</el-radio>
<el-radio v-model="radio1" label="2" size="large" border >MariaDB</el-radio>
<el-radio v-model="radio1" label="3" size="large" border >Oracle数据库</el-radio>
</el-col>
<el-col :span="24"/>
<el-col :span="24">
<el-radio v-model="radio1" label="4" size="large" border >Microsoft Access</el-radio>
<el-radio v-model="radio1" label="5" size="large" border >Microsoft SQL Server</el-radio>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane label="非关系型数据库">
<el-row >
<el-col :span="24">
<el-radio v-model="radio1" label="6" size="large" border >MongoDB</el-radio>
<el-radio v-model="radio1" label="7" size="large" border >Cassandra</el-radio>
<el-radio v-model="radio1" label="8" size="large" border >CouchDB</el-radio>
</el-col>
<el-col :span="24"/>
</el-row>
</el-tab-pane>
<!-- <el-tab-pane label="键值数据库">-->
<!-- </el-tab-pane>-->
</el-tabs>
</el-main>
<el-footer>
<el-button size="large" type="primary" plain>
确定
</el-button>
</el-footer>
</el-tab-pane>
<el-tab-pane label="test" name="second">
</el-tab-pane>
</el-tabs>
</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">
<div v-show="!showHWDetail">
<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="checkHWDetail(scope.row)">查看详情</el-button>
<el-button text size="small" @click="choseProjectFormVisible = true; choseLab = scope.row">提交作业
</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
</div>
<div v-show="showHWDetail">
<el-page-header content="作业详情" @back="showHWDetail = false;" />
<el-container>
<el-main>
<el-row>
<el-col :span="22">
<el-form label-width="120px">
<el-form-item label="任务具体内容">
<el-input v-model="choseLab.mission" type="textarea" readonly :rows="10"
class="example-demonstration" resize="none">
</el-input>
</el-form-item>
<el-form-item label="已提交的作业">
<el-table :data="choseLab.project" border style="width: 100%">
<el-table-column prop="projectName" label="项目" />
<el-table-column prop="date" label="日期" />
</el-table>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-main>
</el-container>
</div>
</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="checkNoticeDetail(scope.row.title, 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-drawer
v-model="setProjectFormVisible"
:with-header="false"
:before-close="handleClose"
direction="rtl"
size='60%'
>
<el-form :model="setProjectForm" label-width="120px">
<el-form-item label="PSM 服务">
<el-select v-model="setProjectForm.psm" placeholder="请选择PSM 服务">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-form-item>
<el-form-item label="SCM 依赖">
<el-space direction="vertical" alignment="start" :size="10">
<el-row>
<el-select v-model="setProjectForm.scm" placeholder="请选择SCM 依赖">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-row>
</el-space>
<el-space direction="vertical" alignment="start" :size="10">
<el-row :gutter="10">
<el-col :span="6">
<el-input v-model="setProjectForm.rout" disabled placeholder="motor/motor/qaq" />
</el-col>
<el-col :span="6">
<el-select v-model="setProjectForm.git" placeholder="请选择Git分支">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-col>
<el-col :span="12">
<el-select v-model="setProjectForm.gitr" placeholder="master">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-col>
</el-row>
</el-space>
<el-space direction="vertical" alignment="start" :size="10">
<el-row :gutter="10">
<el-col :span="6">
<el-input v-model="setProjectForm.scmrout" disabled placeholder="toutiao/load" />
</el-col>
<el-col :span="6">
<el-select v-model="setProjectForm.scmver" placeholder="SCM版本">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-col>
<el-col :span="12">
<el-select v-model="setProjectForm.scmverdet" placeholder="版本1.1.1.1">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-col>
</el-row>
</el-space>
<el-space direction="vertical" alignment="start" :size="10">
<el-row :gutter="10">
<el-col :span="6">
<el-input v-model="setProjectForm.scmrout1" disabled placeholder="toutiao/runtime" />
</el-col>
<el-col :span="6">
<el-select v-model="setProjectForm.scmver1" placeholder="SCM版本">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-col>
<el-col :span="12">
<el-select v-model="setProjectForm.scmverdet1" placeholder="版本1.1.1.1(master)">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-col>
</el-row>
</el-space>
</el-form-item>
<el-form-item label="实例配置">
<el-row :gutter="10">
<el-col :span="9">
<el-input-number
v-model="setProjectForm.ch"
class="mx-4"
:min="1"
:max="10"
controls-position="right"
@change="handleChange"
/>
</el-col>
<el-col :span="3">
<span>
C(核)
</span>
</el-col>
<el-col :span="9">
<el-input-number
v-model="setProjectForm.mg"
class="mx-4"
:min="1"
:max="10"
controls-position="right"
@change="handleChange"
/>
</el-col>
<el-col :span="3">
<span>
M(G)
</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="">提交</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</el-drawer>
<el-table ref="projectTableRef" :data="projectData1" 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>
<span style="margin-left: 10px">project</span>
</div>
</template>
</el-table-column>
<el-table-column prop="date" label="上次更新" width="180" />
<el-table-column prop="introduction" label="项目简介" />
<el-table-column prop="url" label="项目地址" />
<el-table-column fixed="right" width="220">
<template #default="scope">
<el-row>
<el-col :span="24">
<el-button text size="small" @click="showProjectDetail(scope.row)">项目详情</el-button>
</el-col>
</el-row>
<!-- <el-row>-->
<!-- <el-col :span="24">-->
<!-- <el-button text size="small" @click="editProject(scope.raw)">编辑项目</el-button>-->
<!-- </el-col>-->
<!-- </el-row>-->
<el-row>
<el-col :span="24">
<el-button text size="small" @click="setProject()">项目部署</el-button>
</el-col>
</el-row>
</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: 80%">
<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 v-model="selectedProjectDetail!.outputlog" type="textarea" readonly
class="example-demonstration" :rows="20" resize="none">
</el-input>
<!-- </div> -->
<!-- </el-main> -->
</el-main>
<el-aside width="250px">
<el-row>
<el-col :span="2">
<el-divider direction="vertical" style="height: 800px" />
</el-col>
<el-col :span="20">
<el-form label-width="120px">
<el-form-item size="large" label="项目介绍">
</el-form-item>
<el-input v-model="selectedProjectDetail!.introduction" type="textarea" readonly :rows="30"
class="example-demonstration" resize="none">
</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';
import { tsParameterProperty } from "@babel/types";
import type { TagProps } from 'element-plus'
const activeName = ref('first')
const radio1 = ref('1')
const handleClick = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event)
}
const num = ref(1)
const handleChange = (value: number) => {
console.log(value)
}
const activeIndex = ref('2');
const tmRef=ref();
const store = useLoginStore();
const avatarUrl = ref('');
const onIndexChange = (idx: string) => {
activeIndex.value = idx;
if (idx == '5' && organizationData.value.length == 0) {
}
}
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, store.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('');
interface orgIF {
id: string,
lesson: string,
teacher: string
}
const organizationData = ref<orgIF[]>([])
const addOrganization = () => {
let param = new FormData();
param.append('code', invitationCode.value);
request('weblab/organization/getOrgMessageByCode', param)
.then(res => {
console.log(res);
if (res.data.msg == 'success') {
const data = res.data.pkg;
if (data != undefined && data != null) {
ElMessageBox.alert(`是否加入课程${data.name},教师${data.founderName}`, '加入班级', {
confirmButtonText: 'OK',
cancelButtonText: 'Cancel',
})
.then(() => {
let joinParam = new FormData();
joinParam.append('orgId', data.id);
request('weblab/organization/confirmJoinOrg', joinParam)
.then(res => {
if (res.data.msg == 'success') {
organizationData.value.push({
id: data.id,
lesson: data.name,
teacher: data.founderName
})
}
})
})
}
} else if (res.data.msg == 'Organization not found') {
ElMessage({
showClose: true,
message: '未找到该课程',
type: 'error',
center: true,
grouping: true
})
}
})
.catch((error) => {
console.log(error)
ElMessage({
showClose: true,
message: '未找到该课程',
type: 'error',
center: true,
grouping: true
})
})
}
const deleteOrganization = (val: orgIF) => {
ElMessageBox.confirm('将删除该课程,继续?', 'Warning',
{
confirmButtonText: 'OK',
cancelButtonText: 'Cancel',
type: 'warning',
})
.then(() => {
console.log(val);
let param = new FormData();
param.append('orgId', val.id);
request('weblab/organization/confirmQuitOrg', param)
.then(res => {
console.log(res);
if (res.data.msg == 'success') {
const targetIdx = organizationData.value.findIndex((d) => d == val);
organizationData.value.splice(targetIdx, 1);
}
})
})
}
//项目中心
//课程任务
const showHWDetail = ref(false);
const choseProjectFormVisible = ref(false);
const choseProjectProps = {
label: 'projectName',
value: 'id'
}
const choseProject = ref('');
const choseLab = ref<hwDataIF>({
id: '',
lesson: '',
mission: '',
date: '',
project: [],
});
const homeworkTableData = ref<hwDataIF[]>([])
//查看作业详情
const checkHWDetail = (hw: hwDataIF) => {
if (hw.project.length == 0) {
let param = new FormData();
param.append('labId', hw.id);
param.append('userId',store.getUserId);
request('weblab/lab/getUserProjectList', param)
.then(res => {
console.log(res);
if (res.data.msg == 'success') {
const data=res.data.pkg;
for(let d of data){
const proIdx=projectData.value.findIndex(x=>x.id==d.id);
hw.project.push(projectData.value[proIdx]);
}
}
})
}
showHWDetail.value = true;
choseLab.value = hw;
}
//提交项目
const submitProject = () => {
console.log(choseProject.value);
let param = new FormData();
param.append('labId', choseLab.value!.id);
param.append('projectId', choseProject.value);
request('weblab/lab/addProjectIntoLab', param)
.then(res => {
console.log(res);
if (res.data.msg == 'success') {
const proIdx = projectData.value.findIndex(x => x.id == choseProject.value);
choseLab.value?.project.push(projectData.value[proIdx]);
console.log(homeworkTableData.value)
choseProjectFormVisible.value = false
}
})
}
//课程通知
interface noticetDataIF {
className: string,
date: string,
detail: string,
title: string
}
const noticeTableData = ref<noticetDataIF[]>([]);
//查看通知详情
const checkNoticeDetail = (title: string, detail: string) => {
ElMessageBox.alert(detail, title, {
confirmButtonText: 'OK',
})
.catch(err => {
})
}
//我的项目
const showDetail = ref(false);
const activeProjectTabName = ref('1');
const createProjectFormVisible = ref(false);
const setProjectFormVisible = ref(false);
const createProjectForm = reactive({
name: '',
description: ''
})
const setProjectForm = reactive({
psm: '',
scm: '',
scmver:'',
scmver1:'',
scmverdet:'',
scmverdet1:'',
mg:'',
ch:'',
scmrout:'',
scmrout1:'',
rout:'',
git:'',
gitr:'',
})
const projectTableRef = ref<InstanceType<typeof ElTable>>()
const selectedProject = ref<projectDataIF[]>();
const selectedProjectDetail = ref<projectDetailIF>({
outputlog: '',
ws: undefined,
wsUrl: '',
introduction: '',
files: []
});
//任务数据
interface hwDataIF {
id: string,
lesson: string,
mission: string,
date: string,
project: projectDataIF[]
}
//项目数据
//项目详情内容
interface projectFilesIF {
name: string,
date: string,
introduction: string
}
interface projectDetailIF {
outputlog: string,
ws: WebSocket | undefined,
wsUrl: string,
introduction: string,
files: projectFilesIF[]
}
interface projectDataIF {
id: string,
projectName: string,
introduction: string,
date: string,
detail: projectDetailIF,
url: string
}
const projectData = ref<projectDataIF[]>([])
//编辑项目
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;
let param = new FormData();
param.append('projectId', data.id);
request('weblab/project/getProjectLogUrl', param)
.then(res => {
console.log(res);
if (res.data.msg == 'success') {
// selectedProjectDetail.value!.wsUrl = 'ws://127.0.0.1:8001'
selectedProjectDetail.value!.wsUrl = res.data.pkg;
console.log('创建ws')
selectedProjectDetail.value!.ws = new WebSocket(selectedProjectDetail.value!.wsUrl);
selectedProjectDetail.value!.ws.onmessage = onMsg;
selectedProjectDetail.value!.ws.onopen = onOpen;
}
})
showDetail.value = true;
}
const closeProjectDetail = () => {
showDetail.value = false;
selectedProjectDetail.value?.ws?.close();
}
//删除项目内容
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 setProject = () => {
setProjectFormVisible.value = true;
}
const confirmAddProject = () => {
createProjectFormVisible.value = false;
let param = new FormData();
param.append('name', createProjectForm.name);
param.append('description', createProjectForm.description);
request('weblab/project/createProject', param)
.then(res => {
if (res.data.msg == 'success') {
const data = res.data.pkg;
projectData.value.push({
id: data.id,
projectName: data.name,
introduction: data.description,
date: getFormDate(),
url: data.url,
detail: {
ws: undefined,
wsUrl: '',
outputlog: '',
introduction: '',
files: []
}
})
}
})
.catch(error => {
console.log(error);
})
}
//删除项目
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));
for (let data of selectedProject.value!) {
let param = new FormData();
param.append('projectId', data.id);
request('/weblab/project/deleteProjectByProjectId', param)
.then(res => {
console.log(res);
if (res.data.msg == 'success') {
projectData.value = projectData.value.filter(item => item !== data);
}
})
.catch(error => {
console.log(error);
})
}
projectTableRef.value!.clearSelection();
})
}
//下载项目
const downloadProject = () => {
projectTableRef.value!.clearSelection();
}
const projectData1 = [
{
project: '2016-05-03',
},]
//获取初始信息
request('/weblab/user/getUserWithInfo', undefined, store.getToken)
.then(async res => {
if (res.data.msg == 'success') {
const data = res.data.pkg;
console.log(data)
if (data.headImg != null){
avatarUrl.value = data.headImg;
tmRef.value.onAvatarUrlChange(avatarUrl.value);
}
store.setUserId(data.userId);
let orgParam = new FormData();
orgParam.append('userId', store.getUserId);
const orgRes = await request('weblab/organization/getOrgListByUserId', orgParam)
console.log(orgRes);
if (orgRes.data.msg == 'success') {
const orgData = orgRes.data.pkg;
for (let d of orgData) {
organizationData.value.push({
id: d.id,
lesson: d.name,
teacher: d.founderName
})
let labParam = new FormData();
labParam.append('orgId', d.id);
const labRes = await request('weblab/lab/getOrgLabList', labParam);
if (labRes.data.msg == 'success') {
console.log(labRes);
for (let lab of labRes.data.pkg) {
homeworkTableData.value.push({
id: lab.id,
lesson: d.name,
mission: lab.description,
date: lab.endTime,
project: []
})
}
}
}
}
request('/weblab/project/getProjectList', undefined)
.then(projectRes => {
if (projectRes.data.msg == 'success') {
const proData = projectRes.data.pkg;
for (let item of proData) {
projectData.value.push({
id: item.id,
projectName: item.name,
introduction: item.description,
date: item.lastModifyTime.slice(0, 10),
url: item.url,
detail: {
ws: undefined,
wsUrl: '',
outputlog: '',
introduction: '',
files: []
}
})
}
}
})
}
})
const handleProjectTabClick = (pane: TabsPaneContext, ev: Event) => {
if (pane.paneName == '2' && noticeTableData.value.length == 0) {
for (let org of organizationData.value) {
let param = new FormData();
param.append('orgId', org.id);
request('weblab/message/getOrgMessageList', param)
.then(res => {
console.log(res);
if (res.data.msg == 'success') {
const msgData = res.data.pkg;
for (let msg of msgData) {
noticeTableData.value.push({
className: org.lesson,
date: msg.createTime.slice(0, 10),
detail: msg.description,
title: msg.name
})
}
}
})
}
} else if (pane.paneName == '3' && projectData.value.length == 0) {
}
}
const handleProjectSelectionChange = (val: projectDataIF[]) => {
selectedProject.value = val;
}
//websocket
const onMsg = (data: any) => {
selectedProjectDetail.value!.outputlog += data.data + '\n';
}
const onOpen = () => {
// selectedProjectDetail.value?.ws?.send("what`s your name?");
console.log('连接建立');
}
</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>
layout/topmenu.vue
<template>
<el-menu :default-active="$props.activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="1" disabled>WebLab</el-menu-item>
<el-menu-item index="2">项目中心</el-menu-item>
<el-menu-item index="3">上传中心</el-menu-item>
<el-menu-item index="4">市场中心</el-menu-item>
<!-- <el-menu-item index="4">编辑中心</el-menu-item>-->
<!-- <el-sub-menu index="4">-->
<!-- <template #title>待补充</template>-->
<!-- <el-menu-item index="4-1">item one</el-menu-item>-->
<!-- <el-menu-item index="4-2">item two</el-menu-item>-->
<!-- <el-menu-item index="4-3">item three</el-menu-item>-->
<!-- <el-sub-menu index="4-4">-->
<!-- <template #title>item four</template>-->
<!-- <el-menu-item index="4-4-1">item one</el-menu-item>-->
<!-- <el-menu-item index="4-4-2">item two</el-menu-item>-->
<!-- <el-menu-item index="4-4-3">item three</el-menu-item>-->
<!-- </el-sub-menu>-->
<!-- </el-sub-menu>-->
<el-menu-item index="5">组织中心</el-menu-item>
<el-sub-menu index="6" style="position: absolute;right:15px;">
<template #title>
<div class="block">
<el-avatar :size="45" :icon="UserFilled" fit :src="avatarUrl" />
</div>
</template>
<el-menu-item index="5-1" @click="personal()">个人资料更新</el-menu-item>
<el-menu-item index="5-2" @click="updatePassword()">更新密码</el-menu-item>
<!-- <el-menu-item index="5-2">item two</el-menu-item> -->
<el-menu-item index="5-3" @click="logOut">登出</el-menu-item>
</el-sub-menu>
</el-menu>
<div class="h-6"></div>
</template>
<script lang="ts">
import { UserFilled } from '@element-plus/icons-vue'
import { ref, defineComponent, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRouter } from "vue-router"
import { useLoginStore } from '@/stores/store';
import { request } from '@/network/request';
export default defineComponent({
props: {
activeIndex: String,
avatarUrl: String
},
emits: ['onIndexChange'],
setup(props, context) {
const store = useLoginStore();
const router = useRouter();
// const activeIndex = ref(props.activeIndex);
const activeIndex2 = ref('2');
const avatarUrl = ref(props.avatarUrl);
const onAvatarUrlChange = (url: string) => {
avatarUrl.value = url;
}
context.expose({ onAvatarUrlChange })
const handleSelect = (key: string, keyPath: string[]) => {
// activeIndex.value = key;
context.emit('onIndexChange', key);
}
function logOut() {
ElMessageBox.confirm(
'是否确认退出?',
'退出提示',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
}
)
.then(() => {
// store.userLogout();
// router.push({ path: '/' });
let param = new FormData();
request('/weblab/user/logout', param, store.getToken)
.then(res => {
store.userLogout();
router.push({ path: '/' });
// if (res.status == 200 && res.data.msg == 'success') {
// }
})
.catch(error => {
console.log(error);
})
})
.catch(() => {
//点击取消
// activeIndex.value = '2';
context.emit('onIndexChange', '2');
})
}
function updatePassword() {
router.push({ path: '/update_password' });
}
function personal() {
router.push({ path: '/personal' });
}
return {
// activeIndex,
activeIndex2,
handleSelect,
logOut,
updatePassword,
UserFilled,
personal,
avatarUrl
}
},
});
</script>
<style>
</style>