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

Merge branch 'master' into dev

...@@ -4,6 +4,32 @@ const appConfigList = [ ...@@ -4,6 +4,32 @@ const appConfigList = [
logo: 'https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo.svg', logo: 'https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo.svg',
hosts: ['saas-lab'] hosts: ['saas-lab']
}, },
{
title: '1+X实训平台(中级)',
logo: 'https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo.svg',
hosts: ['saas-x'],
studentMenus: [
{ name: '首页', path: '/' },
{ name: '我的实验', path: '/student/lab' },
{ name: '理论学习', path: 'https://saas-learn.ezijing.com' }
],
adminMenus: [
{ name: '首页', path: '/' },
{
name: '我的实验',
path: '/admin/lab',
tag: ['v1-backend-experiment', 'v1-teacher'],
children: [
{ name: '实验管理', path: '/admin/lab/experiment', tag: 'v1-backend-experiment' },
{ name: '案例原文管理', path: '/admin/lab/case', tag: 'teacher-experiment-cases' },
{ name: '实验指导书管理', path: '/admin/lab/book', tag: 'v1-teacher-book' },
{ name: '实验操作视频管理', path: '/admin/lab/video', tag: 'v1-teacher-video' },
{ name: '实验讨论交流', path: '/admin/lab/discuss', tag: 'v1-teacher-discussion' },
{ name: '实验成绩管理', path: '/admin/lab/score', tag: 'v1-teacher-record' }
]
}
]
},
{ {
system: 'game', system: 'game',
title: '商业数据分析竞赛平台', title: '商业数据分析竞赛平台',
...@@ -14,11 +40,6 @@ const appConfigList = [ ...@@ -14,11 +40,6 @@ const appConfigList = [
title: '数字营销实验室', title: '数字营销实验室',
logo: 'https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo.svg', logo: 'https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo.svg',
hosts: ['saas-dml-web'] hosts: ['saas-dml-web']
},
{
title: '2023年全国大学生商业数据分析与应用大赛',
logo: 'https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo.svg',
hosts: ['dasai']
} }
] ]
......
...@@ -46,3 +46,8 @@ export function importScore(data: { competition_id: string; file: File }) { ...@@ -46,3 +46,8 @@ export function importScore(data: { competition_id: string; file: File }) {
headers: { 'Content-Type': 'multipart/form-data' } headers: { 'Content-Type': 'multipart/form-data' }
}) })
} }
// 获取大赛学员提交报告列表
export function getReportList(params: { competition_id: string; student_id: string }) {
return httpRequest.get('/api/lab/v1/expert/report/list', { params })
}
<script setup lang="ts"> <script setup lang="ts">
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { ArrowDown } from '@element-plus/icons-vue'
import { usePrecision } from '@vueuse/math' import { usePrecision } from '@vueuse/math'
import type { ReportItem } from '../types'
import { submitScore } from '../api' import { submitScore } from '../api'
defineProps<{ reportList: ReportItem[] }>()
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update'): void (e: 'update'): void
(e: 'update:modelValue', visible: boolean): void (e: 'update:modelValue', visible: boolean): void
...@@ -57,6 +60,20 @@ function handleSubmit() { ...@@ -57,6 +60,20 @@ function handleSubmit() {
<el-form-item label="赛项名称">{{ detail.competition_id_name }}</el-form-item> <el-form-item label="赛项名称">{{ detail.competition_id_name }}</el-form-item>
<el-form-item label="选手姓名">{{ detail.student_name }}</el-form-item> <el-form-item label="选手姓名">{{ detail.student_name }}</el-form-item>
<el-form-item label="选手ID">{{ detail.login_id }}</el-form-item> <el-form-item label="选手ID">{{ detail.login_id }}</el-form-item>
<el-form-item label="报告">
<el-dropdown>
<el-button text>
查看报告<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu v-if="reportList.length">
<el-dropdown-item v-for="item in reportList" :key="item.id">
<a :href="item.url" target="_blank">{{ item.platform.name }}</a>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-form-item>
</el-form> </el-form>
<el-table :data="tableList" :header-cell-style="{ background: '#ededed' }"> <el-table :data="tableList" :header-cell-style="{ background: '#ededed' }">
<el-table-column label="评分规则" prop="name" align="center"></el-table-column> <el-table-column label="评分规则" prop="name" align="center"></el-table-column>
......
...@@ -25,3 +25,17 @@ export interface FileItem { ...@@ -25,3 +25,17 @@ export interface FileItem {
url: string url: string
upload_time: string upload_time: string
} }
export interface ReportItem {
id: string
name: string
type: string
url: string
size: number
platform: {
platform_key: string
name: string
url: string
}
created_at: string
}
<script setup lang="ts"> <script setup lang="ts">
import type { ReportItem } from '../types'
import { ArrowDown } from '@element-plus/icons-vue'
import Preview from '@/components/Preview.vue' import Preview from '@/components/Preview.vue'
import DragPanel from '@/components/DragPanel.vue' import DragPanel from '@/components/DragPanel.vue'
import { getCheckView } from '../api' import { getCheckView, getReportList } from '../api'
const ScoreDialog = defineAsyncComponent(() => import('../components/ScoreDialog.vue')) const ScoreDialog = defineAsyncComponent(() => import('../components/ScoreDialog.vue'))
...@@ -16,15 +18,39 @@ provide('detail', $$(detail)) ...@@ -16,15 +18,39 @@ provide('detail', $$(detail))
// 评分规则文件 // 评分规则文件
const file = $computed(() => { const file = $computed(() => {
return detail ? JSON.parse(detail?.competition_rubric.url) : { url: '' } return detail?.competition_rubric ? JSON.parse(detail.competition_rubric?.url) : { url: '' }
}) })
function fetchInfo() {
getCheckView({ id: props.id }).then(res => { const platformUrl = ref('')
const platformList = computed(() => {
if (!detail) return []
return detail.competition_platform_configs.filter((item: any) => item.is_show === '1')
})
watchEffect(() => {
const [first = {}] = platformList.value
platformUrl.value = first.url
})
const currentPlatformUrl = computed(() => {
return platformUrl.value + (platformUrl.value?.includes('?') ? '&' : '?') + `student_id=${detail?.student_id}`
})
async function fetchInfo() {
const res = await getCheckView({ id: props.id })
detail = res.data detail = res.data
})
} }
watchEffect(() => {
fetchInfo() const reportList = ref<ReportItem[]>([])
async function fetchReport() {
const res = await getReportList({ competition_id: detail.competition_id, student_id: detail.student_id })
reportList.value = res.data.items
}
onMounted(async () => {
await fetchInfo()
await fetchReport()
}) })
// 评分 // 评分
...@@ -34,10 +60,6 @@ let resizeKey = $ref(0) ...@@ -34,10 +60,6 @@ let resizeKey = $ref(0)
function handleResize() { function handleResize() {
resizeKey = Date.now() resizeKey = Date.now()
} }
const goPage = function (url: string) {
window.open(url)
}
</script> </script>
<template> <template>
...@@ -66,11 +88,21 @@ const goPage = function (url: string) { ...@@ -66,11 +88,21 @@ const goPage = function (url: string) {
</p> </p>
</div> </div>
<div> <div>
<template v-for="item in detail.competition_platform_configs"> <el-select v-model="platformUrl">
<el-button type="primary" :key="item.id" v-if="item.is_show === '1'" @click="goPage(item.url)">{{ <el-option v-for="item in platformList" :key="item.id" :label="item.name" :value="item.url"></el-option>
item.name </el-select>
}}</el-button> <el-dropdown style="margin: 0 10px">
<el-button plain>
查看报告<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu v-if="reportList.length">
<el-dropdown-item v-for="item in reportList" :key="item.id">
<a :href="item.url" target="_blank">{{ item.platform.name }}</a>
</el-dropdown-item>
</el-dropdown-menu>
</template> </template>
</el-dropdown>
<el-button type="primary" @click="dialogVisible = true" v-permission="'v1-expert-check-set-score'" <el-button type="primary" @click="dialogVisible = true" v-permission="'v1-expert-check-set-score'"
>评分</el-button >评分</el-button
> >
...@@ -78,11 +110,11 @@ const goPage = function (url: string) { ...@@ -78,11 +110,11 @@ const goPage = function (url: string) {
</el-row> </el-row>
</AppCard> </AppCard>
<div class="lab-box"> <div class="lab-box">
<iframe :src="detail.competition_uri" frameborder="0" class="iframe" ref="iframeRef"></iframe> <iframe :src="currentPlatformUrl" frameborder="0" class="iframe" ref="iframeRef"></iframe>
</div> </div>
</template> </template>
</DragPanel> </DragPanel>
<ScoreDialog v-model="dialogVisible"></ScoreDialog> <ScoreDialog v-model="dialogVisible" :reportList="reportList"></ScoreDialog>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
......
import type { IMenuItem } from '@/types' import type { IMenuItem } from '@/types'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { useAppConfig } from '@/composables/useAppConfig'
interface State { interface State {
studentMenus: IMenuItem[] studentMenus: IMenuItem[]
...@@ -9,141 +10,63 @@ interface State { ...@@ -9,141 +10,63 @@ interface State {
// 学生菜单 // 学生菜单
const studentMenus: IMenuItem[] = [ const studentMenus: IMenuItem[] = [
{ { name: '首页', path: '/' },
name: '首页', { name: '我的实验', path: '/student/lab' },
path: '/' { name: '理论学习', path: 'https://saas-learn.ezijing.com' },
}, { name: '我的大赛', path: '/student/contest' },
{ { name: '大赛成绩查询', path: '/student/contest/score' },
name: '我的实验', { name: '金融产品数字化营销证书', path: '/student/cert' }
path: '/student/lab'
},
{
name: '理论学习',
path: 'https://saas-learn.ezijing.com'
},
{
name: '我的大赛',
path: '/student/contest'
},
{
name: '大赛成绩查询',
path: '/student/contest/score'
},
{
name: '金融产品数字化营销证书',
path: '/student/cert'
}
] ]
// 管理员菜单 // 管理员菜单
const adminMenus: IMenuItem[] = [ const adminMenus: IMenuItem[] = [
{ { name: '首页', path: '/' },
name: '首页',
path: '/'
},
{ {
name: '我的实验', name: '我的实验',
path: '/admin/lab', path: '/admin/lab',
tag: ['v1-backend-experiment', 'v1-teacher'], tag: ['v1-backend-experiment', 'v1-teacher'],
children: [ children: [
{ { name: '实验管理', path: '/admin/lab/experiment', tag: 'v1-backend-experiment' },
name: '实验管理', { name: '案例原文管理', path: '/admin/lab/case', tag: 'teacher-experiment-cases' },
path: '/admin/lab/experiment', { name: '实验指导书管理', path: '/admin/lab/book', tag: 'v1-teacher-book' },
tag: 'v1-backend-experiment' { name: '实验操作视频管理', path: '/admin/lab/video', tag: 'v1-teacher-video' },
}, { name: '实验讨论交流', path: '/admin/lab/discuss', tag: 'v1-teacher-discussion' },
{ { name: '实验成绩管理', path: '/admin/lab/score', tag: 'v1-teacher-record' }
name: '案例原文管理',
path: '/admin/lab/case',
tag: 'teacher-experiment-cases'
},
{
name: '实验指导书管理',
path: '/admin/lab/book',
tag: 'v1-teacher-book'
},
{
name: '实验操作视频管理',
path: '/admin/lab/video',
tag: 'v1-teacher-video'
},
{
name: '实验讨论交流',
path: '/admin/lab/discuss',
tag: 'v1-teacher-discussion'
},
{
name: '实验成绩管理',
path: '/admin/lab/score',
tag: 'v1-teacher-record'
}
] ]
}, },
{ {
name: '技能大赛', name: '技能大赛',
path: '/admin/contest', path: '/admin/contest',
children: [ children: [
{ { name: '赛项管理', path: '/admin/contest/items', tag: 'competition' },
name: '赛项管理', { name: '参赛选手管理', path: '/admin/contest/contestants', tag: 'competition-competitor' },
path: '/admin/contest/items', { name: '评分专家管理', path: '/admin/contest/experts', tag: 'expert' },
tag: 'competition' { name: '大赛训练答疑', path: '/admin/contest/discuss', tag: 'v1-teacher-train-discussion' },
}, { name: '大赛评分', path: '/admin/contest/check', tag: 'v1-expert-check' },
{ { name: '大赛发布成绩', path: '/admin/contest/score', tag: 'v1-expert-score' }
name: '参赛选手管理',
path: '/admin/contest/contestants',
tag: 'competition-competitor'
},
{
name: '评分专家管理',
path: '/admin/contest/experts',
tag: 'expert'
},
{
name: '大赛训练答疑',
path: '/admin/contest/discuss',
tag: 'v1-teacher-train-discussion'
},
{
name: '大赛评分',
path: '/admin/contest/check',
tag: 'v1-expert-check'
},
{
name: '大赛发布成绩',
path: '/admin/contest/score',
tag: 'v1-expert-score'
}
] ]
}, },
{ {
name: '成绩分析', name: '成绩分析',
path: '/admin/contest/analyze', path: '/admin/contest/analyze',
children: [ children: [
{ { name: '赛项成绩画像', path: '/admin/contest/analyze/score' },
name: '赛项成绩画像', { name: '学生个人成绩画像', path: '/admin/contest/analyze/student' }
path: '/admin/contest/analyze/score'
},
{
name: '学生个人成绩画像',
path: '/admin/contest/analyze/student'
}
] ]
} }
] ]
const appConfig = useAppConfig()
export const useMenuStore = defineStore({ export const useMenuStore = defineStore({
id: 'menu', id: 'menu',
state: (): State => ({ state: (): State => ({ studentMenus, adminMenus }),
studentMenus,
adminMenus
}),
getters: { getters: {
menus: state => { menus: (state): IMenuItem[] => {
const userStore = useUserStore() const userStore = useUserStore()
if (userStore.role?.id === 1) { if (userStore.role?.id === 1) {
return state.studentMenus return appConfig.studentMenus || state.studentMenus
} else { } else {
return state.adminMenus return appConfig.adminMenus || state.adminMenus
}
} }
} }
},
actions: {}
}) })
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论