提交 904ff7ae authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 1ff6e7fe
...@@ -32,7 +32,7 @@ const defaultActive = computed(() => { ...@@ -32,7 +32,7 @@ const defaultActive = computed(() => {
}) })
const logout = async () => { const logout = async () => {
await userStore.logout() await userStore.logout()
location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(location.href)}` location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(location.origin)}`
} }
</script> </script>
...@@ -47,15 +47,26 @@ const logout = async () => { ...@@ -47,15 +47,26 @@ const logout = async () => {
<div class="app-header-nav"> <div class="app-header-nav">
<el-menu mode="horizontal" router :default-active="defaultActive"> <el-menu mode="horizontal" router :default-active="defaultActive">
<template v-for="item in menus" :key="item.path"> <template v-for="item in menus" :key="item.path">
<el-sub-menu :index="item.path" :popper-offset="0" popper-class="sub-menu-popper" v-if="item.children"> <el-sub-menu
:index="item.path"
:popper-offset="0"
popper-class="sub-menu-popper"
v-permission="item.tag"
v-if="item.children"
>
<template #title> <template #title>
{{ item.name }} {{ item.name }}
</template> </template>
<el-menu-item :index="subitem.path" v-for="subitem in item.children" :key="subitem.path"> <el-menu-item
:index="subitem.path"
v-for="subitem in item.children"
:key="subitem.path"
v-permission="subitem.tag"
>
{{ subitem.name }} {{ subitem.name }}
</el-menu-item> </el-menu-item>
</el-sub-menu> </el-sub-menu>
<el-menu-item :index="item.path" v-else> <el-menu-item :index="item.path" v-permission="item.tag" v-else>
{{ item.name }} {{ item.name }}
</el-menu-item> </el-menu-item>
</template> </template>
......
...@@ -46,11 +46,23 @@ function handleRefetch() { ...@@ -46,11 +46,23 @@ function handleRefetch() {
</el-descriptions> </el-descriptions>
<AppList v-bind="listOptions" ref="appList"> <AppList v-bind="listOptions" ref="appList">
<template #header-buttons> <template #header-buttons>
<el-button type="primary" round :icon="CirclePlus" @click="dialogVisible = true">新增分组</el-button> <el-button
type="primary"
round
:icon="CirclePlus"
@click="dialogVisible = true"
v-permission="'v1-backend-experiment-team-add'"
>新增分组</el-button
>
</template> </template>
<template #table-x="{ row }"> <template #table-x="{ row }">
<el-button type="primary" link> <el-button type="primary" link>
<router-link :to="`/admin/system/experiment/group/${row.id}`" target="_blank">小组成员</router-link> <router-link
:to="`/admin/system/experiment/group/${row.id}`"
target="_blank"
v-permission="'v1-backend-experiment-team-view'"
>小组成员</router-link
>
</el-button> </el-button>
</template> </template>
</AppList> </AppList>
......
...@@ -71,10 +71,23 @@ function handleRemoveStudent(row: StudentItem) { ...@@ -71,10 +71,23 @@ function handleRemoveStudent(row: StudentItem) {
</el-descriptions> </el-descriptions>
<AppList v-bind="listOptions" ref="appList"> <AppList v-bind="listOptions" ref="appList">
<template #header-buttons> <template #header-buttons>
<el-button type="primary" round :icon="CirclePlus" @click="selectStudentVisible = true">添加小组成员</el-button> <el-button
type="primary"
round
:icon="CirclePlus"
@click="selectStudentVisible = true"
v-permission="'v1-backend-experiment-team-add-student'"
>添加小组成员</el-button
>
</template> </template>
<template #table-x="{ row }"> <template #table-x="{ row }">
<el-button type="primary" round @click="handleRemoveStudent(row)">移除</el-button> <el-button
type="primary"
round
@click="handleRemoveStudent(row)"
v-permission="'v1-backend-experiment-team-add-student'"
>移除</el-button
>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
......
...@@ -60,17 +60,21 @@ function onUpdateSuccess() { ...@@ -60,17 +60,21 @@ function onUpdateSuccess() {
<AppCard title="实验管理"> <AppCard title="实验管理">
<AppList v-bind="listOptions" ref="appList"> <AppList v-bind="listOptions" ref="appList">
<template #header-buttons> <template #header-buttons>
<el-button type="primary" :icon="CirclePlus" @click="handleAdd">新增实验</el-button> <el-button type="primary" :icon="CirclePlus" v-permission="'v1-backend-experiment-create'" @click="handleAdd"
>新增实验</el-button
>
</template> </template>
<template #table-x="{ row }: { row: ExperimentItem }"> <template #table-x="{ row }: { row: ExperimentItem }">
<el-button type="primary" round> <el-button type="primary" round v-permission="'v1-backend-experiment-view'">
<router-link :to="`/admin/system/experiment/${row.id}`" target="_blank">查看</router-link> <router-link :to="`/admin/system/experiment/${row.id}`" target="_blank">查看</router-link>
</el-button> </el-button>
<el-button type="primary" round> <el-button type="primary" round v-permission="'v1-backend-experiment-view'">
<router-link :to="`/admin/system/experiment/${row.id}`" target="_blank">关联班级与分组</router-link> <router-link :to="`/admin/system/experiment/${row.id}`" target="_blank">关联班级与分组</router-link>
</el-button> </el-button>
<el-button type="primary" round @click="handleUpdate(row)">编辑</el-button> <el-button type="primary" round @click="handleUpdate(row)" v-permission="'v1-backend-experiment-update'"
>编辑</el-button
>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
......
...@@ -81,12 +81,32 @@ function handleRemoveClass(row: ClassItem) { ...@@ -81,12 +81,32 @@ function handleRemoveClass(row: ClassItem) {
</el-descriptions> </el-descriptions>
<AppList v-bind="listOptions" ref="appList"> <AppList v-bind="listOptions" ref="appList">
<template #header-buttons> <template #header-buttons>
<el-button type="primary" :icon="CirclePlus" @click="selectClassVisible = true">关联班级</el-button> <el-button
type="primary"
:icon="CirclePlus"
@click="selectClassVisible = true"
v-permission="'v1-backend-experiment-class-add'"
>关联班级</el-button
>
</template> </template>
<template #table-x="{ row }"> <template #table-x="{ row }">
<el-button type="primary" round @click="handleViewStudent(row)">查看学生</el-button> <el-button
<el-button type="primary" round @click="handleStudentGroup(row)">学生分组</el-button> type="primary"
<el-button type="primary" round @click="handleRemoveClass(row)">移除</el-button> round
@click="handleViewStudent(row)"
v-permission="'v1-backend-experiment-class-students'"
>查看学生</el-button
>
<el-button
type="primary"
round
@click="handleStudentGroup(row)"
v-permission="'v1-backend-experiment-class-teams'"
>学生分组</el-button
>
<el-button type="primary" round @click="handleRemoveClass(row)" v-permission="'v1-backend-experiment-class-add'"
>移除</el-button
>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
......
...@@ -9,3 +9,8 @@ export function getTopInfo() { ...@@ -9,3 +9,8 @@ export function getTopInfo() {
export function getExperimentList() { export function getExperimentList() {
return httpRequest.get('/api/lab/v1/teacher/index/index') return httpRequest.get('/api/lab/v1/teacher/index/index')
} }
// 获取课程列表
export function getCourseList() {
return httpRequest.get('/api/lab/v1/student/course/all')
}
<script setup lang="ts"> <script setup lang="ts">
import type { ExperimentItem } from '../types' import type { CourseType } from '../types'
import { getExperimentList } from '../api' import { getCourseList } from '../api'
const router = useRouter() const router = useRouter()
let list = $ref<ExperimentItem[]>([]) let list = $ref<CourseType[]>([])
function fetchList() { function fetchList() {
getExperimentList().then(res => { getCourseList().then(res => {
list = res.data.list list = res.data.list
}) })
} }
...@@ -14,9 +14,7 @@ onMounted(() => { ...@@ -14,9 +14,7 @@ onMounted(() => {
}) })
function handleChange(id: string, type: number) { function handleChange(id: string, type: number) {
if (type === 1) { if (type === 1) {
router.push({ path: '/admin/lab/book', query: { experiment_id: id } }) router.push({ path: '/student/lab', query: { course_id: id } })
} else if (type === 2) {
router.push({ path: '/admin/lab/video', query: { experiment_id: id } })
} }
} }
</script> </script>
...@@ -27,7 +25,7 @@ function handleChange(id: string, type: number) { ...@@ -27,7 +25,7 @@ function handleChange(id: string, type: number) {
<el-select size="large" placeholder="我的实验课程" @change="handleChange($event, 1)"> <el-select size="large" placeholder="我的实验课程" @change="handleChange($event, 1)">
<el-option v-for="item in list" :key="item.id" :label="item.name" :value="item.id"></el-option> <el-option v-for="item in list" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select> </el-select>
<el-select size="large" placeholder="我的陪练项目" @change="handleChange($event, 2)"> <!-- <el-select size="large" placeholder="我的陪练项目" @change="handleChange($event, 2)">
<el-option v-for="item in list" :key="item.id" :label="item.name" :value="item.id"></el-option> <el-option v-for="item in list" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select> </el-select>
<el-select size="large" placeholder="我的大赛项目" @change="handleChange($event, 3)"> <el-select size="large" placeholder="我的大赛项目" @change="handleChange($event, 3)">
...@@ -35,7 +33,7 @@ function handleChange(id: string, type: number) { ...@@ -35,7 +33,7 @@ function handleChange(id: string, type: number) {
</el-select> </el-select>
<el-select size="large" placeholder="我的大赛成绩" @change="handleChange($event, 4)"> <el-select size="large" placeholder="我的大赛成绩" @change="handleChange($event, 4)">
<el-option v-for="item in list" :key="item.id" :label="item.name" :value="item.id"></el-option> <el-option v-for="item in list" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select> </el-select> -->
</div> </div>
</template> </template>
......
...@@ -2,3 +2,17 @@ export interface ExperimentItem { ...@@ -2,3 +2,17 @@ export interface ExperimentItem {
id: string id: string
name: string name: string
} }
export interface CourseType {
id: string
name: string
cover: string
experiments: ExperimentType[]
}
export interface ExperimentType {
id: string
name: string
course_id: string
organ_id: string
}
<script setup lang="ts"> <script setup lang="ts">
import type { CourseType, ExperimentRecord } from '../types' import type { CourseType, ExperimentRecord } from '../types'
import { HomeFilled, Select, UploadFilled, FullScreen } from '@element-plus/icons-vue' import { HomeFilled } from '@element-plus/icons-vue'
import { useGetCourseList } from '../composables/useGetCourseList' import { useGetCourseList } from '../composables/useGetCourseList'
import { upload } from '@/utils/upload' import { upload } from '@/utils/upload'
import { getExperimentRecord, uploadExperimentPicture, submitExperimentRecord } from '../api' import { getExperimentRecord, uploadExperimentPicture, submitExperimentRecord } from '../api'
...@@ -12,16 +12,19 @@ const Discuss = defineAsyncComponent(() => import('../components/Discuss.vue')) ...@@ -12,16 +12,19 @@ const Discuss = defineAsyncComponent(() => import('../components/Discuss.vue'))
const Result = defineAsyncComponent(() => import('../components/Result.vue')) const Result = defineAsyncComponent(() => import('../components/Result.vue'))
const ReportDialog = defineAsyncComponent(() => import('../components/ReportDialog.vue')) const ReportDialog = defineAsyncComponent(() => import('../components/ReportDialog.vue'))
const route = useRoute()
// 左侧 // 左侧
const form = reactive<{ course?: CourseType; experiment_id: string }>({ const form = reactive<{ course_id: string; experiment_id: string }>({
course: undefined, course_id: (route.query.course_id as string) || '',
experiment_id: '6965149866569760768' experiment_id: ''
}) })
// 课程列表 // 课程列表
const { courses } = useGetCourseList() const { courses } = useGetCourseList()
// 实验列表 // 实验列表
const experimentList = $computed(() => { const experimentList = $computed(() => {
return form.course?.experiments || [] const course = courses.value.find((item: CourseType) => item.id === form.course_id)
return course?.experiments || []
}) })
let detail = $ref<ExperimentRecord>() let detail = $ref<ExperimentRecord>()
provide('detail', $$(detail)) provide('detail', $$(detail))
...@@ -104,8 +107,8 @@ function handleSubmit() { ...@@ -104,8 +107,8 @@ function handleSubmit() {
<div class="lab-left"> <div class="lab-left">
<el-form :model="form" label-suffix=":" hide-required-asterisk> <el-form :model="form" label-suffix=":" hide-required-asterisk>
<el-form-item label="请选择课程"> <el-form-item label="请选择课程">
<el-select value-key="id" v-model="form.course" style="width: 100%"> <el-select v-model="form.course_id" style="width: 100%">
<el-option v-for="item in courses" :key="item.id" :label="item.name" :value="item"></el-option> <el-option v-for="item in courses" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="请选择实验" prop="experiment_id"> <el-form-item label="请选择实验" prop="experiment_id">
...@@ -136,16 +139,9 @@ function handleSubmit() { ...@@ -136,16 +139,9 @@ function handleSubmit() {
>返回首页</el-button >返回首页</el-button
> >
<div> <div>
<el-button type="primary" :icon="Select" :disabled="disabled" @click="handleSubmit">提交</el-button> <el-button type="primary" :disabled="disabled" @click="handleSubmit">提交</el-button>
<el-button type="primary" :icon="UploadFilled" :disabled="disabled" @click="reportDialogVisible = true" <el-button type="primary" :disabled="disabled" @click="reportDialogVisible = true">上传报告</el-button>
>上传报告</el-button <el-button type="primary" :disabled="disabled" :loading="screenshotLoading" @click="handleCapture"
>
<el-button
type="primary"
:icon="FullScreen"
:disabled="disabled"
:loading="screenshotLoading"
@click="handleCapture"
>截图</el-button >截图</el-button
> >
</div> </div>
...@@ -174,15 +170,24 @@ function handleSubmit() { ...@@ -174,15 +170,24 @@ function handleSubmit() {
.lab-left { .lab-left {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 500px; width: 400px;
padding: 20px; padding: 20px;
background-color: rgba(45, 48, 55, 1); background-color: #e1e4eb;
border-radius: 6px; border-radius: 6px;
box-sizing: border-box; box-sizing: border-box;
.el-tabs { .el-tabs {
flex: 1; flex: 1;
border: 0;
overflow: hidden; overflow: hidden;
} }
:deep(.el-tabs__header) {
background-color: #e1e4eb;
}
:deep(.el-tabs__item) {
padding: 0 14px !important;
border: 0;
border-radius: 6px 6px 0px 0px;
}
:deep(.el-tabs__content) { :deep(.el-tabs__content) {
height: calc(100% - 40px); height: calc(100% - 40px);
box-sizing: border-box; box-sizing: border-box;
......
import type { IMenuItem } from '@/types' import type { IMenuItem } from '@/types'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { Notebook, VideoCamera, ChatSquare, Finished, ScaleToOriginal } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
interface State { interface State {
...@@ -13,68 +12,70 @@ const studentMenus: IMenuItem[] = [ ...@@ -13,68 +12,70 @@ const studentMenus: IMenuItem[] = [
{ {
name: '智能营销', name: '智能营销',
path: '/student/lab' path: '/student/lab'
},
{
name: '智能陪练',
path: '/student/ai'
},
{
name: '成绩分析',
path: '/admin/contest/score'
},
{
name: '技能大赛',
path: '/student/contest'
} }
// {
// name: '智能陪练',
// path: '/student/ai'
// },
// {
// name: '成绩分析',
// path: '/admin/contest/score'
// },
// {
// name: '技能大赛',
// path: '/student/contest'
// }
] ]
// 教师、管理员菜单 // 教师、管理员菜单
const adminMenus: IMenuItem[] = [ const adminMenus: IMenuItem[] = [
{ {
name: '智能营销', name: '智能营销',
path: '/admin/lab', path: '/admin/lab',
tag: 'v1-teacher',
children: [ children: [
{ {
icon: markRaw(Notebook),
name: '实验指导书管理', name: '实验指导书管理',
path: '/admin/lab/book' path: '/admin/lab/book',
tag: 'v1-teacher-book'
}, },
{ {
icon: markRaw(VideoCamera),
name: '实验操作视频管理', name: '实验操作视频管理',
path: '/admin/lab/video' path: '/admin/lab/video',
tag: 'v1-teacher-video'
}, },
{ {
icon: markRaw(ChatSquare),
name: '实验讨论交流', name: '实验讨论交流',
path: '/admin/lab/discuss' path: '/admin/lab/discuss',
tag: 'v1-teacher-discussion'
}, },
{ {
icon: markRaw(Finished),
name: '实验成绩管理', name: '实验成绩管理',
path: '/admin/lab/record' path: '/admin/lab/record',
tag: 'v1-teacher-record'
} }
] ]
}, },
{ // {
name: '智能陪练', // name: '智能陪练',
path: '/admin/ai' // path: '/admin/ai'
}, // },
{ // {
name: '成绩分析', // name: '成绩分析',
path: '/admin/contest/score' // path: '/admin/contest/score'
}, // },
{ // {
name: '技能大赛', // name: '技能大赛',
path: '/admin/contest' // path: '/admin/contest'
}, // },
{ {
name: '系统管理', name: '系统管理',
path: '/admin/system', path: '/admin/system',
tag: 'v1-backend-experiment',
children: [ children: [
{ {
icon: markRaw(ScaleToOriginal),
name: '实验管理', name: '实验管理',
path: '/admin/system/experiment' path: '/admin/system/experiment',
tag: 'v1-backend-experiment'
} }
] ]
} }
......
...@@ -51,7 +51,7 @@ httpRequest.interceptors.response.use( ...@@ -51,7 +51,7 @@ httpRequest.interceptors.response.use(
// 未登录 // 未登录
if (status === 403) { if (status === 403) {
location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(location.href)}` location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(location.href)}`
} else if (status === 402) { } else if (status === 401 || status === 402) {
// 未授权 // 未授权
router.push('/401') router.push('/401')
} else { } else {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论