549 lines
19 KiB
Vue
549 lines
19 KiB
Vue
<script lang="ts" setup>
|
|
import BussApi from '@/api/BussApi';
|
|
import type { LessonTask, FileUploadDestination } from '@/types/api/lesson';
|
|
import { extractLessonStage, getLessonSteps } from '@/utils/lesson';
|
|
import { ProgressStatus } from '@/types/api/lesson';
|
|
import { computed, nextTick, onMounted, ref } from 'vue';
|
|
import { useMessage, useToast } from 'wot-design-uni';
|
|
import StatusBlock from './StatusBlock.vue';
|
|
import { useRoute } from 'uni-mini-router';
|
|
import { useUser } from '@/stores/useUser';
|
|
import { onPullDownRefresh } from '@dcloudio/uni-app'
|
|
|
|
const route = useRoute()
|
|
const message = useMessage()
|
|
const message_reject = useMessage('wd-message-box-slot')
|
|
const toast = useToast()
|
|
const user = useUser()
|
|
|
|
type GroupedLessons = { [key: string]: LessonTask[] }
|
|
|
|
const groupedLessons = ref<GroupedLessons>({})
|
|
|
|
const pickerCourseColumns = ref<string[]>([])
|
|
const pickerCourseValue = ref()
|
|
|
|
const pickerLessonColumns = computed(() => {
|
|
return pickerCourseValue.value ? groupedLessons.value[pickerCourseValue.value].map((lesson: LessonTask) => {
|
|
return {
|
|
label: (extractLessonStage(lesson).step === 5 ? '✅ ' : '') + lesson.microLessonName,
|
|
value: lesson.id,
|
|
}
|
|
}) : []
|
|
})
|
|
const pickerLessonValue = ref()
|
|
const adviseTextValue = ref<string>('')
|
|
|
|
const selectedLesson = computed(() => {
|
|
if (!pickerLessonValue.value) return null
|
|
return groupedLessons.value[pickerCourseValue.value].find((lesson: LessonTask) => lesson.id === pickerLessonValue.value)
|
|
})
|
|
|
|
const selectedLessonStage = computed(() => {
|
|
if (!selectedLesson.value) return null
|
|
return extractLessonStage(selectedLesson.value)
|
|
})
|
|
|
|
/**
|
|
* 判断advise是否为驳回状态
|
|
* @param advise 修改建议字符串
|
|
* @returns {boolean} 是否为驳回状态
|
|
*/
|
|
const isRejectAdvise = (advise: string | undefined): boolean => {
|
|
try {
|
|
if (!advise) return false
|
|
const adviseObj = JSON.parse(advise)
|
|
return 'reject' in adviseObj
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
const adviseText = computed(() => {
|
|
try {
|
|
if (!selectedLesson.value?.advise) return '暂无修改建议'
|
|
const adviseObj = JSON.parse(selectedLesson.value.advise)
|
|
return adviseObj.reject || '暂无修改建议'
|
|
} catch {
|
|
return selectedLesson?.value?.advise || '暂无修改建议'
|
|
}
|
|
})
|
|
|
|
const getAdviseText = (adviseString: string | undefined): string => {
|
|
try {
|
|
if (!adviseString) return ''
|
|
const adviseObj = JSON.parse(adviseString)
|
|
const rejectText = adviseObj.reject || ''
|
|
return rejectText
|
|
} catch (e) {
|
|
console.error('JSON解析失败:', e)
|
|
return ''
|
|
}
|
|
}
|
|
|
|
const onCoursePick = ({ value }: { value: string }) => {
|
|
pickerCourseValue.value = value
|
|
pickerLessonValue.value = undefined
|
|
}
|
|
|
|
const onLessonPick = ({ value }: { value: number }) => {
|
|
pickerLessonValue.value = value
|
|
}
|
|
|
|
/**
|
|
* lesson progress modifition steps
|
|
*/
|
|
|
|
const script_file_destination = ref<FileUploadDestination>('wechat')
|
|
|
|
const onStep0 = () => {
|
|
message.confirm({
|
|
title: '提交脚本',
|
|
msg: '请确认已经通过微信或平台上传了脚本文件,再确认提交'
|
|
}).then(() => {
|
|
if (!selectedLesson.value?.id) {
|
|
toast.error({
|
|
msg: '参数错误'
|
|
})
|
|
return
|
|
}
|
|
toast.loading({
|
|
msg: '正在提交...'
|
|
})
|
|
const params = {
|
|
advise: JSON.stringify({ confirm: "" }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.SCRIPT_CREATING//1
|
|
|
|
}
|
|
BussApi.updateLessonTask(selectedLesson.value.id, params).then(res => {
|
|
toast.success({
|
|
msg: '提交成功'
|
|
})
|
|
setTimeout(() => {
|
|
updateLessons()
|
|
}, 1500);
|
|
}).catch(err => {
|
|
toast.error({ msg: err.message })
|
|
})
|
|
})
|
|
}
|
|
|
|
|
|
const onStep1 = (rejected: boolean = false) => {
|
|
const msg = rejected ? message_reject : message
|
|
msg
|
|
.confirm({
|
|
title: rejected ? '驳回脚本' : '通过脚本',
|
|
msg: rejected ? '脚本不符合要求,驳回制作方重做' : '请确认脚本合格无误后,再确认审核通过'
|
|
}).then(() => {
|
|
if (!selectedLesson.value?.id) {
|
|
toast.error({
|
|
msg: '参数错误'
|
|
})
|
|
return
|
|
}
|
|
toast.loading({
|
|
msg: '正在处理...'
|
|
})
|
|
BussApi.updateLessonTask(
|
|
selectedLesson.value.id,
|
|
rejected ? {
|
|
advise: JSON.stringify({ reject: adviseTextValue.value.toString() }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.NOT_STARTED//0
|
|
} : {
|
|
advise: JSON.stringify({ confirm: "" }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.SCRIPT_REVIEW//2
|
|
}).then(res => {
|
|
toast.success({
|
|
msg: rejected ? '驳回成功' : '审核通过'
|
|
})
|
|
setTimeout(() => {
|
|
updateLessons()
|
|
}, 1500);
|
|
}).catch(err => {
|
|
toast.error({ msg: err.message })
|
|
})
|
|
})
|
|
}
|
|
|
|
const onStep2 = (rejected: boolean = false) => {
|
|
const msg = rejected ? message_reject : message
|
|
msg.confirm({
|
|
title: rejected ? '驳回确认脚本内容' : '通过确认脚本内容',
|
|
msg: rejected ? '脚本内容不符合要求,驳回脚本审核方重做' : '请确认脚本内容合格无误后,再确认审核通过'
|
|
}).then(() => {
|
|
if (!selectedLesson.value?.id) {
|
|
toast.error({
|
|
msg: '参数错误'
|
|
})
|
|
return
|
|
}
|
|
toast.loading({
|
|
msg: '正在处理...'
|
|
})
|
|
BussApi.updateLessonTask(
|
|
selectedLesson.value.id,
|
|
rejected ? {
|
|
advise: JSON.stringify({ reject: adviseTextValue.value.toString() }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.SCRIPT_CREATING//1
|
|
} : {
|
|
advise: JSON.stringify({ confirm: "" }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.SCRIPT_CONFIRMED//3
|
|
}).then(res => {
|
|
toast.success({
|
|
msg: rejected ? '驳回成功' : '审核通过'
|
|
})
|
|
setTimeout(() => {
|
|
updateLessons()
|
|
}, 1500);
|
|
}).catch(err => {
|
|
toast.error({ msg: err.message })
|
|
})
|
|
})
|
|
}
|
|
|
|
const onStep3 = (rejected: boolean = false) => {
|
|
const msg = rejected ? message_reject : message
|
|
msg.confirm({
|
|
title: rejected ? '驳回视频拍摄制作' : '通过视频拍摄制作',
|
|
msg: rejected ? '视频拍摄制作不符合要求,驳回拍摄方重新拍摄' : '请确认视频拍摄制作合格无误后,再确认审核通过'
|
|
}).then(() => {
|
|
if (!selectedLesson.value?.id) {
|
|
toast.error({
|
|
msg: '参数错误'
|
|
})
|
|
return
|
|
}
|
|
toast.loading({
|
|
msg: '正在处理...'
|
|
})
|
|
BussApi.updateLessonTask(
|
|
selectedLesson.value.id,
|
|
rejected ? {
|
|
advise: JSON.stringify({ reject: 'huertian' + adviseTextValue.value.toString() }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.SCRIPT_CONFIRMED//3
|
|
} : {
|
|
advise: JSON.stringify({ confirm: "" }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.VIDEO_CREATING//4
|
|
}).then(res => {
|
|
toast.success({
|
|
msg: rejected ? '驳回成功' : '审核通过'
|
|
})
|
|
setTimeout(() => {
|
|
updateLessons()
|
|
}, 1500);
|
|
}).catch(err => {
|
|
toast.error({ msg: err.message })
|
|
})
|
|
})
|
|
}
|
|
const onStep4 = (rejected: boolean = false) => {
|
|
const msg = rejected ? message_reject : message
|
|
msg.confirm({
|
|
title: rejected ? '驳回视频内容' : '通过视频内容',
|
|
msg: rejected ? '视频内容不符合要求,驳回制作方重新制作' : '请确认视频内容合格无误后,再确认审核通过'
|
|
}).then(() => {
|
|
if (!selectedLesson.value?.id) {
|
|
toast.error({
|
|
msg: '参数错误'
|
|
})
|
|
return
|
|
}
|
|
toast.loading({
|
|
msg: '正在处理...'
|
|
})
|
|
BussApi.updateLessonTask(
|
|
selectedLesson.value.id,
|
|
rejected ? {
|
|
advise: JSON.stringify({ reject: adviseTextValue.value.toString() }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.SCRIPT_CONFIRMED//3
|
|
} : {
|
|
advise: JSON.stringify({ confirm: "" }),
|
|
courseName: selectedLesson.value.courseName,
|
|
microLessonName: selectedLesson.value.microLessonName,
|
|
userId: selectedLesson.value.userId,
|
|
progressStatus: ProgressStatus.VIDEO_CONFIRMED//5
|
|
}).then(res => {
|
|
toast.success({
|
|
msg: rejected ? '驳回成功' : '审核通过'
|
|
})
|
|
setTimeout(() => {
|
|
updateLessons()
|
|
}, 1500);
|
|
}).catch(err => {
|
|
toast.error({ msg: err.message })
|
|
})
|
|
})
|
|
}
|
|
|
|
const updateLessons = async () => {
|
|
adviseTextValue.value = ""
|
|
if (!user.userinfo) {
|
|
toast.error({ msg: '请先登录' })
|
|
return
|
|
}
|
|
|
|
toast.loading({
|
|
msg: '加载中...'
|
|
})
|
|
|
|
try {
|
|
let res
|
|
if (user.canViewAllCourses()) {
|
|
res = await BussApi.getLessonTasks(1, 512)
|
|
} else {
|
|
res = await BussApi.getLessonTasks(1, 512, user.userinfo.id)
|
|
}
|
|
|
|
const groupData = res.data.content.sort((a: LessonTask, b: LessonTask) => {
|
|
return a.id - b.id
|
|
}).reduce((acc: any, cur: any) => {
|
|
if (!acc[cur.courseName]) {
|
|
acc[cur.courseName] = []
|
|
}
|
|
acc[cur.courseName].push(cur)
|
|
return acc
|
|
}, {})
|
|
groupedLessons.value = groupData
|
|
pickerCourseColumns.value = [
|
|
...Object.keys(groupData)
|
|
]
|
|
|
|
if (route.params?.courseName) {
|
|
onCoursePick({ value: decodeURI(route.params.courseName) })
|
|
if (route.params?.lessonId) {
|
|
if (typeof route.params.lessonId === 'string') {
|
|
onLessonPick({ value: parseInt(route.params.lessonId) })
|
|
}
|
|
}
|
|
}
|
|
} catch (err: unknown) {
|
|
if (err instanceof Error) {
|
|
toast.error({ msg: err.message })
|
|
} else {
|
|
toast.error({ msg: '发生未知错误' })
|
|
}
|
|
} finally {
|
|
toast.close()
|
|
}
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
updateLessons()
|
|
})
|
|
|
|
const refresh = async () => {
|
|
try {
|
|
const startTime = Date.now()
|
|
await updateLessons()
|
|
const endTime = Date.now()
|
|
const duration = endTime - startTime
|
|
if (duration < 500) {
|
|
await new Promise(resolve => setTimeout(resolve, 500 - duration))
|
|
}
|
|
} catch (err) {
|
|
} finally {
|
|
uni.stopPullDownRefresh()
|
|
}
|
|
}
|
|
onPullDownRefresh(() => {
|
|
refresh()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<page-wrapper>
|
|
<div class="shadow-md shadow-op-50 overflow-hidden">
|
|
<wd-picker :columns="pickerCourseColumns" label="课程选择" v-model="pickerCourseValue" @confirm="onCoursePick"
|
|
:columns-height="280" label-width="80px" safe-area-inset-bottom title="课程选择" />
|
|
<wd-picker :columns="pickerLessonColumns" label="微课选择" v-model="pickerLessonValue" @confirm="onLessonPick"
|
|
:columns-height="280" label-width="80px" safe-area-inset-bottom title="微课选择" :disabled="!pickerCourseValue" />
|
|
</div>
|
|
<wd-message-box selector="wd-message-box-slot">
|
|
<wd-textarea v-model="adviseTextValue" type="text" clear-trigger="focus" clearable auto-height show-word-limit
|
|
:focus-when-clear="false" :maxlength="100" placeholder="请输入审核建议..." block />
|
|
</wd-message-box>
|
|
<div class="p-2 pt-4">
|
|
<wd-status-tip v-if="!pickerLessonValue"
|
|
image="https://registry.npmmirror.com/wot-design-uni-assets/*/files/search.png" tip="请先选择微课" />
|
|
<div v-else class="space-y-6">
|
|
<div>
|
|
<wd-steps :active="selectedLessonStage?.step || 0" align-center>
|
|
<wd-step v-for="(step, index) in getLessonSteps(selectedLesson!, true)" :key="index" :title="step.title"
|
|
:description="(selectedLessonStage?.step || 0 <= index) ? step.description : undefined" />
|
|
</wd-steps>
|
|
</div>
|
|
|
|
<div v-if="selectedLessonStage?.step === 0" class="px-2">
|
|
<div v-if="user.hasRole('teacher')">
|
|
<div v-if="isRejectAdvise(selectedLesson?.advise)" class="m-2 text-sm">
|
|
<wd-card title="修改建议">
|
|
{{ adviseText }}
|
|
</wd-card>
|
|
</div>
|
|
<wd-cell-group>
|
|
<wd-cell title="脚本提交途径" :title-width="'100px'" center custom-class="mb-4">
|
|
<wd-radio-group v-model="script_file_destination" shape="button">
|
|
<wd-radio value="wechat">微信</wd-radio>
|
|
<wd-radio value="qq">QQ</wd-radio>
|
|
<wd-radio value="platform">平台</wd-radio>
|
|
</wd-radio-group>
|
|
</wd-cell>
|
|
</wd-cell-group>
|
|
<wd-button type="primary" block @click="onStep0" custom-class="w-full">提交脚本</wd-button>
|
|
</div>
|
|
<StatusBlock v-else title="脚本还未提交" subtitle="请耐心等待提交">
|
|
<template #icon>
|
|
<div class="i-tabler-file-upload text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
</div>
|
|
|
|
<div v-if="selectedLessonStage?.step === 1">
|
|
<div v-if="user.hasRole('teacher')">
|
|
<StatusBlock title="脚本制作已完成" subtitle="请核对并审核">
|
|
<template #icon>
|
|
<div class="i-tabler-progress-check text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
</div>
|
|
<div v-else>
|
|
<div v-if="isRejectAdvise(selectedLesson?.advise) === true" class=" m-2 text-sm">
|
|
<wd-card title="修改建议">
|
|
{{ adviseText }}
|
|
</wd-card>
|
|
</div>
|
|
<StatusBlock title="脚本已提交" subtitle="请耐心等待审核">
|
|
<template #icon>
|
|
<div class="i-tabler-progress-bolt text-7xl text-neutral-400 "></div>
|
|
</template>
|
|
</StatusBlock>
|
|
<div class="mt-4 space-y-4">
|
|
<div class="flex gap-3 px-4">
|
|
<wd-button type="primary" block @click="onStep1()">确认</wd-button>
|
|
<wd-button type="error" block @click="onStep1(true)">驳回</wd-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="selectedLessonStage?.step === 2">
|
|
<div v-if="user.hasRole('teacher')">
|
|
<StatusBlock title="脚本审核已完成" subtitle="请确认脚本内容">
|
|
<template #icon>
|
|
<div class="i-tabler-file-text text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
<div class="mt-4 space-y-4">
|
|
<div class="flex gap-3 px-4">
|
|
<wd-button type="primary" block @click="onStep2()">确认</wd-button>
|
|
<wd-button type="error" block @click="onStep2(true)">驳回</wd-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else>
|
|
<StatusBlock title="脚本确认进行中" subtitle="请等待脚本内容确认">
|
|
<template #icon>
|
|
<div class="i-tabler-file-text text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="selectedLessonStage?.step === 3">
|
|
<div v-if="user.hasRole('teacher')">
|
|
<div v-if="getAdviseText(selectedLesson?.advise).startsWith('huertian')" class=" m-2 text-sm">
|
|
<wd-card title="修改建议">
|
|
{{ getAdviseText(selectedLesson?.advise).substring('huertian'.length) }}
|
|
</wd-card>
|
|
</div>
|
|
<StatusBlock title="视频拍摄制作进行中" subtitle="请等待视频拍摄制作">
|
|
<template #icon>
|
|
<div class="i-tabler-video text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
</div>
|
|
<div v-else>
|
|
<div v-if="!getAdviseText(selectedLesson?.advise).startsWith('huertian')">
|
|
<div v-if="isRejectAdvise(selectedLesson?.advise) === true" class=" m-2 text-sm">
|
|
<wd-card title="修改建议">
|
|
{{ adviseText }}
|
|
</wd-card>
|
|
</div>
|
|
</div>
|
|
<StatusBlock title="视频拍摄制作进行中" subtitle="完成后请确认">
|
|
<template #icon>
|
|
<div class="i-tabler-video text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
<div class="mt-4 space-y-4">
|
|
<div class="flex gap-3 px-4 center">
|
|
<wd-button type="primary" block @click="onStep3()">通过</wd-button>
|
|
<wd-button type="error" block @click="onStep3(true)">驳回</wd-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="selectedLessonStage?.step === 4">
|
|
<div v-if="user.hasRole('teacher')">
|
|
<StatusBlock title="视频拍摄制作已完成" subtitle="请确认视频内容">
|
|
<template #icon>
|
|
<div class="i-tabler-brand-parsinta text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
<div class="mt-4 space-y-4">
|
|
<div class="flex gap-3 px-4">
|
|
<wd-button type="primary" block @click="onStep4()">通过</wd-button>
|
|
<wd-button type="error" block @click="onStep4(true)">驳回</wd-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else>
|
|
<StatusBlock title="视频内容确认中" subtitle="请等待视频内容确认">
|
|
<template #icon>
|
|
<div class="i-tabler-brand-parsinta text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-else-if="selectedLessonStage?.step === 5">
|
|
<StatusBlock title="已完成" subtitle="该微课已完成">
|
|
<template #icon>
|
|
<div class="i-tabler-clipboard-check text-7xl text-neutral-400"></div>
|
|
</template>
|
|
</StatusBlock>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</page-wrapper>
|
|
</template>
|
|
|
|
<style scoped></style>
|