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

feat: 比赛支持全媒体运营师(网络编辑)

上级 d7faba5b
...@@ -48,6 +48,7 @@ const competitionOptions = ref([ ...@@ -48,6 +48,7 @@ const competitionOptions = ref([
{ label: '网络主播赛项', value: '1' }, { label: '网络主播赛项', value: '1' },
{ label: '全媒体运营赛项', value: '2' }, { label: '全媒体运营赛项', value: '2' },
{ label: '互联网营销师(直播销售)', value: '3' }, { label: '互联网营销师(直播销售)', value: '3' },
{ label: '全媒体运营师(网络编辑)', value: '4' },
]) ])
async function fetchInfo() { async function fetchInfo() {
......
import { useGetCourseList } from './useGetCourseList' import { useGetCourseList } from './useGetCourseList'
import type { ExperimentType } from '../types' import type { ExperimentType } from '../types'
import { getExperiment, getExperimentCompetition, submitCompetition } from '../api' import { getExperiment, getExperimentCompetition, submitCompetition, getExperimentExamList } from '../api'
import { useCookies } from '@vueuse/integrations/useCookies'
interface StudentStatus { interface StudentStatus {
has_submitted: boolean has_submitted: boolean
...@@ -16,11 +17,16 @@ interface Competition { ...@@ -16,11 +17,16 @@ interface Competition {
} }
export function useCompetition() { export function useCompetition() {
const cookies = useCookies()
const competition = ref<Competition>() const competition = ref<Competition>()
const { courses } = useGetCourseList() const { courses } = useGetCourseList()
const experiments = ref<ExperimentType[]>([]) const experiments = ref<ExperimentType[]>([])
const courseId = ref('') const courseId = ref('')
const experimentId = ref('') const experimentId = ref('')
const biURL = computed<string>(() => {
return `${import.meta.env.VITE_LAB_URL}&token=${cookies.get('TGC')}`
})
watchEffect(() => { watchEffect(() => {
if (courses.value.length) { if (courses.value.length) {
...@@ -42,6 +48,9 @@ export function useCompetition() { ...@@ -42,6 +48,9 @@ export function useCompetition() {
const fetchExperimentCompetition = async () => { const fetchExperimentCompetition = async () => {
const res = await getExperimentCompetition({ experiment_id: experimentId.value }) const res = await getExperimentCompetition({ experiment_id: experimentId.value })
competition.value = res.data.detail competition.value = res.data.detail
if (res.data.detail.competition == '4') {
fetchExamList()
}
} }
watchEffect(() => { watchEffect(() => {
if (experimentId.value) { if (experimentId.value) {
...@@ -53,5 +62,22 @@ export function useCompetition() { ...@@ -53,5 +62,22 @@ export function useCompetition() {
await submitCompetition({ experiment_id: experimentId.value }) await submitCompetition({ experiment_id: experimentId.value })
await fetchExperimentCompetition() await fetchExperimentCompetition()
} }
return { competition, courseId, experimentId, experimentInfo, submit }
const examList = ref<any[]>([])
// 考试平台 URL
const examURL = computed<string>(() => {
if (!examList.value.length) return ''
const [first] = examList.value
return `${import.meta.env.VITE_EXAM_SHOW_URL}/exam/${first?.exam_id}`
// return `https://dev.ezijing.com:5173/exam/7003551966412406784?has_time=0&has_submit=0&has_save=1&show_answer=1`
})
const fetchExamList = async () => {
const res = await getExperimentExamList({ experiment_id: experimentId.value })
const resCookies = res.data.cookies
cookies.set(resCookies.key, resCookies.auth_key, { domain: '.ezijing.com', path: '/' })
examList.value = res.data.items
}
return { competition, courseId, experimentId, experimentInfo, submit, fetchExamList, examURL, biURL }
} }
...@@ -6,12 +6,13 @@ import { useNow } from '@vueuse/core' ...@@ -6,12 +6,13 @@ import { useNow } from '@vueuse/core'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { formatDuration } from '@/utils/utils' import { formatDuration } from '@/utils/utils'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { useEventListener } from '@vueuse/core'
const appConfig = useAppConfig() const appConfig = useAppConfig()
const Case = defineAsyncComponent(() => import('../components/Case.vue')) const Case = defineAsyncComponent(() => import('../components/Case.vue'))
const { courseId, experimentId, competition, submit } = useCompetition() const { courseId, experimentId, competition, submit, examURL, biURL } = useCompetition()
const LAB_URL = computed<string>(() => { const LAB_URL = computed<string>(() => {
if (competition.value?.competition == '2') { if (competition.value?.competition == '2') {
...@@ -64,6 +65,16 @@ const handleSubmit = async () => { ...@@ -64,6 +65,16 @@ const handleSubmit = async () => {
} }
) )
} }
const tabActive = ref('bi')
useEventListener(window, 'message', async (event) => {
console.log(event)
const { data } = event
if (data.action === 'submitExam') {
await submit()
isEntry.value = false
}
})
</script> </script>
<template> <template>
<DragPanel v-if="isEntry"> <DragPanel v-if="isEntry">
...@@ -76,6 +87,19 @@ const handleSubmit = async () => { ...@@ -76,6 +87,19 @@ const handleSubmit = async () => {
</div> </div>
</template> </template>
<template #right> <template #right>
<template v-if="competition?.competition == '4'">
<AppCard>
<el-button :type="tabActive === 'bi' ? 'primary' : 'default'" @click="tabActive = 'bi'">实操环境</el-button>
<el-button :type="tabActive === 'exam' ? 'primary' : 'default'" @click="tabActive = 'exam'">理论试题</el-button>
</AppCard>
<div class="iframe-box">
<iframe allow="camera; microphone" allowfullscreen :src="biURL" frameborder="0" class="iframe" ref="iframeRef"
v-show="tabActive === 'bi'"></iframe>
<iframe allow="camera; microphone" allowfullscreen :src="examURL" frameborder="0" class="iframe"
ref="iframeRef" v-show="tabActive === 'exam'"></iframe>
</div>
</template>
<template v-else>
<AppCard> <AppCard>
<div class="competition-header"> <div class="competition-header">
<div class="time"> <div class="time">
...@@ -86,15 +110,11 @@ const handleSubmit = async () => { ...@@ -86,15 +110,11 @@ const handleSubmit = async () => {
</div> </div>
</AppCard> </AppCard>
<div class="iframe-box"> <div class="iframe-box">
<iframe <iframe allow="camera; microphone" allowfullscreen :src="LAB_URL" frameborder="0" class="iframe"
allow="camera; microphone"
allowfullscreen
:src="LAB_URL"
frameborder="0"
class="iframe"
ref="iframeRef"></iframe> ref="iframeRef"></iframe>
</div> </div>
</template> </template>
</template>
</DragPanel> </DragPanel>
<template v-else> <template v-else>
<div class="welcome-box" v-if="competition?.name"> <div class="welcome-box" v-if="competition?.name">
...@@ -106,9 +126,7 @@ const handleSubmit = async () => { ...@@ -106,9 +126,7 @@ const handleSubmit = async () => {
<p>{{ competition?.start_time }}{{ competition?.end_time }}</p> <p>{{ competition?.start_time }}{{ competition?.end_time }}</p>
</div> </div>
</div> </div>
<el-button v-if="canEnter" type="primary" size="large" @click="handleEntry" class="entry-btn" <el-button v-if="canEnter" type="primary" size="large" @click="handleEntry" class="entry-btn">进入实操考试</el-button>
>进入实操考试</el-button
>
<el-button plain v-if="isSubmitted" type="primary" size="large" class="entry-btn">考试已提交</el-button> <el-button plain v-if="isSubmitted" type="primary" size="large" class="entry-btn">考试已提交</el-button>
</div> </div>
<el-empty description="暂无比赛" v-else /> <el-empty description="暂无比赛" v-else />
...@@ -121,6 +139,7 @@ const handleSubmit = async () => { ...@@ -121,6 +139,7 @@ const handleSubmit = async () => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.left-box-title { .left-box-title {
font-size: 22px; font-size: 22px;
font-weight: 600; font-weight: 600;
...@@ -129,22 +148,27 @@ const handleSubmit = async () => { ...@@ -129,22 +148,27 @@ const handleSubmit = async () => {
text-align: center; text-align: center;
margin-bottom: 20px; margin-bottom: 20px;
} }
.left-box-content { .left-box-content {
flex: 1; flex: 1;
} }
.competition-header { .competition-header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
.time { .time {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
.label { .label {
font-size: 14px; font-size: 14px;
color: var(--main-color); color: var(--main-color);
font-weight: 500; font-weight: 500;
} }
.value { .value {
font-size: 24px; font-size: 24px;
font-weight: 700; font-weight: 700;
...@@ -154,6 +178,7 @@ const handleSubmit = async () => { ...@@ -154,6 +178,7 @@ const handleSubmit = async () => {
} }
} }
} }
.iframe-box { .iframe-box {
position: relative; position: relative;
flex: 1; flex: 1;
...@@ -161,19 +186,23 @@ const handleSubmit = async () => { ...@@ -161,19 +186,23 @@ const handleSubmit = async () => {
margin-top: 20px; margin-top: 20px;
display: flex; display: flex;
} }
.iframe { .iframe {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.welcome-box { .welcome-box {
margin: -20px; margin: -20px;
height: calc(100vh - 66px); height: calc(100vh - 66px);
.entry-btn { .entry-btn {
display: block; display: block;
width: 300px; width: 300px;
margin: 100px auto; margin: 100px auto;
} }
} }
.welcome-box-header { .welcome-box-header {
height: 50%; height: 50%;
background: url('/public/images/competition_bg.jpg') no-repeat top center; background: url('/public/images/competition_bg.jpg') no-repeat top center;
...@@ -181,6 +210,7 @@ const handleSubmit = async () => { ...@@ -181,6 +210,7 @@ const handleSubmit = async () => {
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
} }
.welcome-box-header-content { .welcome-box-header-content {
width: 100%; width: 100%;
max-width: 1000px; max-width: 1000px;
...@@ -196,6 +226,7 @@ const handleSubmit = async () => { ...@@ -196,6 +226,7 @@ const handleSubmit = async () => {
letter-spacing: 7px; letter-spacing: 7px;
text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5); text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
} }
h2 { h2 {
margin-top: 20px; margin-top: 20px;
font-size: 18px; font-size: 18px;
...@@ -204,6 +235,7 @@ const handleSubmit = async () => { ...@@ -204,6 +235,7 @@ const handleSubmit = async () => {
line-height: 25px; line-height: 25px;
text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5); text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
} }
.line { .line {
width: 24px; width: 24px;
height: 2px; height: 2px;
...@@ -211,6 +243,7 @@ const handleSubmit = async () => { ...@@ -211,6 +243,7 @@ const handleSubmit = async () => {
box-shadow: 0 2px 4px #00000080; box-shadow: 0 2px 4px #00000080;
margin: 10px 0; margin: 10px 0;
} }
p { p {
font-size: 18px; font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论