新增一键催办功能、驳回显示时间戳
This commit is contained in:
1
.vercel/project.json
Normal file
1
.vercel/project.json
Normal file
@ -0,0 +1 @@
|
||||
{"projectName":"trae_ppms-uni-vue3_8m55"}
|
3
components.d.ts
vendored
3
components.d.ts
vendored
@ -23,7 +23,9 @@ declare module 'vue' {
|
||||
WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default']
|
||||
WdIcon: typeof import('wot-design-uni/components/wd-icon/wd-icon.vue')['default']
|
||||
WdInput: typeof import('wot-design-uni/components/wd-input/wd-input.vue')['default']
|
||||
WdLoading: typeof import('wot-design-uni/components/wd-loading/wd-loading.vue')['default']
|
||||
WdMessageBox: typeof import('wot-design-uni/components/wd-message-box/wd-message-box.vue')['default']
|
||||
WdNoticeBar: typeof import('wot-design-uni/components/wd-notice-bar/wd-notice-bar.vue')['default']
|
||||
WdPicker: typeof import('wot-design-uni/components/wd-picker/wd-picker.vue')['default']
|
||||
WdProgress: typeof import('wot-design-uni/components/wd-progress/wd-progress.vue')['default']
|
||||
WdRadio: typeof import('wot-design-uni/components/wd-radio/wd-radio.vue')['default']
|
||||
@ -32,6 +34,7 @@ declare module 'vue' {
|
||||
WdStatusTip: typeof import('wot-design-uni/components/wd-status-tip/wd-status-tip.vue')['default']
|
||||
WdStep: typeof import('wot-design-uni/components/wd-step/wd-step.vue')['default']
|
||||
WdSteps: typeof import('wot-design-uni/components/wd-steps/wd-steps.vue')['default']
|
||||
WdSwipeAction: typeof import('wot-design-uni/components/wd-swipe-action/wd-swipe-action.vue')['default']
|
||||
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
|
||||
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
|
||||
WdTextarea: typeof import('wot-design-uni/components/wd-textarea/wd-textarea.vue')['default']
|
||||
|
@ -60,9 +60,9 @@
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-4020420240722002",
|
||||
"dayjs": "^1.11.13",
|
||||
"pinia": "^2.2.2",
|
||||
"vue": "^3.4.21",
|
||||
"vue": "^3.5.18",
|
||||
"vue-i18n": "^9.1.9",
|
||||
"wot-design-uni": "^1.5.1"
|
||||
"wot-design-uni": "^1.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.4.8",
|
||||
|
646
pnpm-lock.yaml
generated
646
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -360,4 +360,44 @@ export default class BussApi {
|
||||
})
|
||||
.then((res) => res.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前用户是否需要任务提醒
|
||||
* @returns Promise<boolean> 返回是否需要提醒
|
||||
* - 教师:可以催办管理员(状态 1、3)或收到管理员消息(状态 0、2、4 且有 msg)时返回 true
|
||||
* - 管理员:可以催办教师(状态 0、2、4)或有消息需要处理时返回 true
|
||||
*/
|
||||
static checkNeedReminder(): Promise<boolean> {
|
||||
const user = useUser();
|
||||
return http
|
||||
.server()
|
||||
.get("lesson-tasks/need-reminder", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${user.token}`,
|
||||
},
|
||||
})
|
||||
.then((res) => res.data.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一键催办 - 发送催办提醒
|
||||
* @param id - 课程任务ID
|
||||
* @returns Promise<LessonTask> 返回更新后的课程任务
|
||||
*/
|
||||
static sendReminder(id: number): Promise<LessonTask> {
|
||||
return this.updateLessonTask(id, {
|
||||
expediteStatus: 1
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除催办提醒
|
||||
* @param id - 课程任务ID
|
||||
* @returns Promise<LessonTask> 返回更新后的课程任务
|
||||
*/
|
||||
static clearReminder(id: number): Promise<LessonTask> {
|
||||
return this.updateLessonTask(id, {
|
||||
expediteStatus: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,130 @@ const expandedCourse = ref(['lesson'])
|
||||
const groupedLessons = ref<{ [key: string]: LessonTask[] }>({})
|
||||
const refreshKey = ref(0)
|
||||
|
||||
// 催办消息展示相关
|
||||
const reminderMessages = ref<LessonTask[]>([])
|
||||
|
||||
/**
|
||||
* 判断当前用户是否负责当前进度
|
||||
*/
|
||||
const isUserResponsibleForCurrentProgress = (lesson: LessonTask): boolean => {
|
||||
if (!lesson || !user.userinfo) return false
|
||||
|
||||
const progressStatus = lesson.progressStatus
|
||||
const userRoles = user.userinfo.roles
|
||||
const userJobs = user.userinfo.jobs
|
||||
|
||||
// 判断进度负责人
|
||||
switch (progressStatus) {
|
||||
case 0: // 脚本制作 - 教师负责
|
||||
case 1: // 脚本提交 - 教师负责
|
||||
return userRoles === 1 && userJobs === 1 // 校方教师 + 课程制作教师
|
||||
|
||||
case 2: // 脚本审核 - 审核人员负责
|
||||
return userJobs === 2 // 课程审核人员
|
||||
|
||||
case 3: // 脚本确认 - 教师负责
|
||||
return userRoles === 1 && userJobs === 1 // 校方教师 + 课程制作教师
|
||||
|
||||
case 4: // 视频制作审核 - 审核人员负责
|
||||
return userJobs === 2 // 课程审核人员
|
||||
|
||||
case 5: // 已完成
|
||||
return false
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否应该显示催办消息
|
||||
*/
|
||||
const shouldShowExpediteNotice = (lesson: LessonTask): boolean => {
|
||||
if (!lesson || !user.userinfo) return false
|
||||
|
||||
// 条件1: 当前用户所负责的课程(通过userId判断)
|
||||
const isUserCourse = lesson.userId === user.userinfo.id
|
||||
|
||||
// 条件2: 课程当前所在的进度是当前用户所负责的进度
|
||||
const isResponsibleForProgress = isUserResponsibleForCurrentProgress(lesson)
|
||||
|
||||
// 条件3: 催办信息为1
|
||||
const isExpedited = lesson.expediteStatus === 1
|
||||
|
||||
return isUserCourse && isResponsibleForProgress && isExpedited
|
||||
}
|
||||
|
||||
/**
|
||||
* 调试函数:打印当前账户所负责的课程状态
|
||||
*/
|
||||
const debugUserCourses = () => {
|
||||
console.log('🔍 [首页] 执行debugUserCourses函数...')
|
||||
|
||||
if (!user.userinfo) {
|
||||
console.log('❌ 用户未登录')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('👤 当前用户ID:', user.userinfo.id)
|
||||
|
||||
const allLessons = Object.values(groupedLessons.value).flat()
|
||||
console.log('📚 所有课程数量:', allLessons.length)
|
||||
|
||||
// 过滤出当前用户负责的课程
|
||||
const userCourses = allLessons.filter(lesson => lesson.userId === user.userinfo!.id)
|
||||
console.log('🎯 当前用户负责的课程数量:', userCourses.length)
|
||||
|
||||
// 生成简洁的ID和状态对应关系
|
||||
const courseStatusMap = userCourses.reduce((acc, lesson) => {
|
||||
acc[`ID:${lesson.id}`] = `状态:${lesson.progressStatus},催办:${lesson.expediteStatus}`
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
console.log('📋 当前用户负责的课程状态:', courseStatusMap)
|
||||
|
||||
// 需要处理的催办课程(满足三个条件)
|
||||
const needAttentionMap = userCourses
|
||||
.filter(lesson => shouldShowExpediteNotice(lesson))
|
||||
.reduce((acc, lesson) => {
|
||||
acc[`ID:${lesson.id}`] = `需处理催办`
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
if (Object.keys(needAttentionMap).length > 0) {
|
||||
console.log('⚠️ 需要处理的催办课程:', needAttentionMap)
|
||||
} else {
|
||||
console.log('✅ 当前没有需要处理的催办课程')
|
||||
}
|
||||
}
|
||||
|
||||
// 检查催办消息
|
||||
const checkReminderMessages = () => {
|
||||
const allLessons = Object.values(groupedLessons.value).flat()
|
||||
|
||||
const filteredLessons = allLessons.filter(lesson => {
|
||||
// 检查是否有催办状态
|
||||
if (lesson.expediteStatus !== 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 根据用户角色和任务状态判断是否显示催办信息
|
||||
const progressStatus = lesson.progressStatus
|
||||
|
||||
if (user.hasRole('teacher')) {
|
||||
// 教师:任务状态是 0、2、4 时显示催办信息
|
||||
return [0, 2, 4].includes(progressStatus)
|
||||
} else if (user.hasRole('admin')) {
|
||||
// 公司课程顾问(课程审核人员):任务状态是 1、3 时显示催办信息
|
||||
return [1, 3].includes(progressStatus)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
reminderMessages.value = filteredLessons
|
||||
}
|
||||
|
||||
const openLessonDetail = (courseId: number) => {
|
||||
router.push({
|
||||
name: 'lesson',
|
||||
@ -75,11 +199,22 @@ const openLessonDetail = (courseId: number) => {
|
||||
|
||||
|
||||
const loadLessons = async () => {
|
||||
console.log('🔄 [首页] 开始加载课程列表...')
|
||||
|
||||
if (!user.hasValidToken() || !user.userinfo) {
|
||||
console.log('❌ [首页] 用户未登录,跳转到登录页')
|
||||
toast.error({ msg: '请先登录' })
|
||||
router.replace('/pages/login/index')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('✅ [首页] 用户已登录,用户信息:', {
|
||||
id: user.userinfo.id,
|
||||
username: user.userinfo.username,
|
||||
roles: user.userinfo.roles,
|
||||
jobs: user.userinfo.jobs
|
||||
})
|
||||
|
||||
toast.loading({ msg: '加载中...' })
|
||||
try {
|
||||
let res;
|
||||
@ -118,6 +253,28 @@ const loadLessons = async () => {
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
// 在每个章节内部按徽标状态排序
|
||||
Object.keys(groupData).forEach(courseName => {
|
||||
// 使用冒泡排序,将有徽标的课程排在前面
|
||||
const lessons = groupData[courseName]
|
||||
for (let i = 0; i < lessons.length; i++) {
|
||||
for (let j = 0; j < lessons.length - i - 1; j++) {
|
||||
// 检查徽标是否显示:根据用户角色和课程角色判断
|
||||
const currentHasBadge = (getLessonRole(lessons[j]) === 'teacher' && user.hasRole('teacher')) ||
|
||||
(getLessonRole(lessons[j]) === 'admin' && user.hasRole('admin'))
|
||||
const nextHasBadge = (getLessonRole(lessons[j + 1]) === 'teacher' && user.hasRole('teacher')) ||
|
||||
(getLessonRole(lessons[j + 1]) === 'admin' && user.hasRole('admin'))
|
||||
|
||||
// 如果当前元素没有徽标但下一个元素有徽标,则交换位置
|
||||
if (!currentHasBadge && nextHasBadge) {
|
||||
const temp = lessons[j]
|
||||
lessons[j] = lessons[j + 1]
|
||||
lessons[j + 1] = temp
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (value.value !== 0) {
|
||||
Object.keys(groupData).forEach(courseName => {
|
||||
groupData[courseName].sort((a: LessonTask, b: LessonTask) => {
|
||||
@ -132,8 +289,26 @@ const loadLessons = async () => {
|
||||
|
||||
groupedLessons.value = groupData
|
||||
|
||||
// 调试:打印当前账户所负责的课程状态
|
||||
console.log('🚀 [首页] 开始调试用户课程状态...')
|
||||
debugUserCourses()
|
||||
console.log('✅ [首页] 调试完成')
|
||||
|
||||
const expandedGroups = Object.keys(groupData).filter(courseName => {
|
||||
const courses = groupData[courseName]
|
||||
|
||||
// 检查是否有徽标需要显示 - 新增逻辑
|
||||
const hasBadge = courses.some(lesson =>
|
||||
(getLessonRole(lesson) === 'teacher' && user.hasRole('teacher')) ||
|
||||
(getLessonRole(lesson) === 'admin' && user.hasRole('admin'))
|
||||
)
|
||||
|
||||
// 如果没有徽标需要显示,则不展开 - 新增逻辑
|
||||
if (!hasBadge) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 原有的进度逻辑
|
||||
const hasCompleted = courses.some(lesson => calcLessonProgress(lesson) === 100)
|
||||
const hasNotStarted = courses.some(lesson => calcLessonProgress(lesson) === 0)
|
||||
const hasInProgress = courses.some(lesson => {
|
||||
@ -144,6 +319,9 @@ const loadLessons = async () => {
|
||||
})
|
||||
|
||||
expandedCourse.value = expandedGroups
|
||||
|
||||
// 检查催办消息
|
||||
checkReminderMessages()
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof Error) {
|
||||
toast.error({ msg: err.message })
|
||||
@ -195,11 +373,31 @@ onPullDownRefresh(() => {
|
||||
onLoad(() => {
|
||||
loadLessons()
|
||||
})
|
||||
|
||||
const handleSwipeAction = (action: string, lesson: LessonTask) => {
|
||||
switch (action) {
|
||||
case 'edit':
|
||||
toast.show(`编辑微课: ${lesson.microLessonName}`)
|
||||
// 这里可以添加编辑逻辑
|
||||
break
|
||||
case 'delete':
|
||||
toast.show(`删除微课: ${lesson.microLessonName}`)
|
||||
// 这里可以添加删除逻辑
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<page-wrapper>
|
||||
<div>
|
||||
<!-- 催办消息展示 -->
|
||||
<div v-if="reminderMessages.length > 0" class="mb-2">
|
||||
<wd-notice-bar text="您有课程需要完成,请及时处理" type="warning" />
|
||||
</div>
|
||||
|
||||
<div v-if="!user.hasRole('teacher')" class="flex items-center justify-around gap-4 px-4">
|
||||
<wd-drop-menu>
|
||||
<wd-drop-menu-item v-model="teacherFilterValue" :options="teacherFilterOptions"
|
||||
@ -217,14 +415,9 @@ onLoad(() => {
|
||||
<template #title="{ expanded, disabled, isFirst }">
|
||||
<div class="w-full flex justify-between items-center">
|
||||
<div class="flex flex-col gap-1">
|
||||
<!-- <wd-badge is-dot :right="230" :hidden="!courses.some(lesson =>
|
||||
(getLessonRole(lesson) === 'teacher' && user.hasRole('teacher')) ||
|
||||
(getLessonRole(lesson) === 'admin' && user.hasRole('admin'))
|
||||
)"> -->
|
||||
<p class="pt-1">
|
||||
{{ courseName || '无标题课程' }}
|
||||
</p>
|
||||
<!-- </wd-badge> -->
|
||||
<div class="flex items-center gap-1">
|
||||
<wd-tag v-if="(() => {
|
||||
const hasCompleted = courses.some(lesson => calcLessonProgress(lesson) === 100)
|
||||
@ -254,10 +447,10 @@ onLoad(() => {
|
||||
共{{ courses.length }}节微课
|
||||
</wd-tag>
|
||||
<wd-tag custom-class="op-60" plain>
|
||||
已完成{{ courses.filter(lesson => calcLessonProgress(lesson) === 100).length }}·
|
||||
进行中{{ courses.filter(lesson => calcLessonProgress(lesson) !== 0 && calcLessonProgress(lesson)
|
||||
!== 100).length }}·
|
||||
未开始{{ courses.filter(lesson => calcLessonProgress(lesson) === 0).length }}
|
||||
已完成{{courses.filter(lesson => calcLessonProgress(lesson) === 100).length}}·
|
||||
进行中{{courses.filter(lesson => calcLessonProgress(lesson) !== 0 && calcLessonProgress(lesson)
|
||||
!== 100).length}}·
|
||||
未开始{{courses.filter(lesson => calcLessonProgress(lesson) === 0).length}}
|
||||
</wd-tag>
|
||||
</div>
|
||||
</div>
|
||||
@ -266,20 +459,20 @@ onLoad(() => {
|
||||
<div class="flex items-center gap-0.5">
|
||||
<div class="w-1.5 aspect-square rounded-full bg-emerald"></div>
|
||||
<span class="text-xs text-emerald font-bold font-mono">
|
||||
{{ courses.filter(lesson => calcLessonProgress(lesson) === 100).length }}
|
||||
{{courses.filter(lesson => calcLessonProgress(lesson) === 100).length}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-0.5">
|
||||
<div class="w-1.5 aspect-square rounded-full bg-blue"></div>
|
||||
<span class="text-xs text-blue font-bold font-mono">
|
||||
{{ courses.filter(lesson => calcLessonProgress(lesson) !== 0 && calcLessonProgress(lesson) !==
|
||||
100).length }}
|
||||
{{courses.filter(lesson => calcLessonProgress(lesson) !== 0 && calcLessonProgress(lesson) !==
|
||||
100).length}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-0.5">
|
||||
<div class="w-1.5 aspect-square rounded-full bg-neutral"></div>
|
||||
<span class="text-xs text-neutral font-bold font-mono">
|
||||
{{ courses.filter(lesson => calcLessonProgress(lesson) === 0).length }}
|
||||
{{courses.filter(lesson => calcLessonProgress(lesson) === 0).length}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -292,31 +485,45 @@ onLoad(() => {
|
||||
<wd-status-tip v-if="courses.length === 0"
|
||||
image="https://registry.npmmirror.com/wot-design-uni-assets/*/files/content.png" tip="没有课程小节" />
|
||||
<div v-else v-for="(lesson, i) in courses" :key="`${lesson.id}-${refreshKey}`"
|
||||
@click="openLessonDetail(lesson.id)"
|
||||
class="w-full py-2 gap-12 flex justify-between items-center border-b border-b-solid border-neutral-100 last:border-b-0 first:pt-0 last:pb-0">
|
||||
<div class="flex items-center gap-1 self-center">
|
||||
<div>
|
||||
<div v-if="calcLessonProgress(lesson) === 100" class="i-tabler-circle-check text-emerald"></div>
|
||||
<div v-else-if="calcLessonProgress(lesson) === 0" class="i-tabler-progress-x text-neutral">
|
||||
class="w-full border-b border-b-solid border-neutral-100 last:border-b-0">
|
||||
<!-- 所有用户都使用 SwipeAction 组件 -->
|
||||
<wd-swipe-action :disabled="!(user.hasRole('admin') || user.hasRole('sysadmin'))">
|
||||
<div @click="openLessonDetail(lesson.id)"
|
||||
class="w-full py-2 gap-12 flex justify-between items-center first:pt-0 last:pb-0">
|
||||
<div class="flex items-center gap-1 self-center">
|
||||
<div>
|
||||
<div v-if="calcLessonProgress(lesson) === 100" class="i-tabler-circle-check text-emerald"></div>
|
||||
<div v-else-if="calcLessonProgress(lesson) === 0" class="i-tabler-progress-x text-neutral">
|
||||
</div>
|
||||
<div v-else class="i-tabler-hourglass-empty text-blue"></div>
|
||||
</div>
|
||||
<wd-badge is-dot
|
||||
:hidden="!(getLessonRole(lesson) === 'teacher' && user.hasRole('teacher') || getLessonRole(lesson) === 'admin' && user.hasRole('admin'))">
|
||||
<span>{{ lesson.microLessonName || '无标题微课' }}</span>
|
||||
</wd-badge>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 shrink-0">
|
||||
<span v-if="!user.hasRole('teacher') && getUsernameById(lesson.userId)"
|
||||
class="text-xs text-gray-400 ml-2 whitespace-nowrap">
|
||||
{{ getUsernameById(lesson.userId) }}
|
||||
</span>
|
||||
<div class="w-16">
|
||||
<wd-progress :percentage="calcLessonProgress(lesson)"
|
||||
:color="calcLessonProgress(lesson) === 100 ? '#34d399' : '#60a5fa'" hide-text />
|
||||
</div>
|
||||
<div class="i-tabler-dots text-neutral-400 text-xl"></div>
|
||||
</div>
|
||||
<div v-else class="i-tabler-hourglass-empty text-blue"></div>
|
||||
</div>
|
||||
<wd-badge is-dot
|
||||
:hidden="!(getLessonRole(lesson) === 'teacher' && user.hasRole('teacher') || getLessonRole(lesson) === 'admin' && user.hasRole('admin'))">
|
||||
<span>{{ lesson.microLessonName || '无标题微课' }}</span>
|
||||
</wd-badge>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 shrink-0">
|
||||
<span v-if="!user.hasRole('teacher') && getUsernameById(lesson.userId)"
|
||||
class="text-xs text-gray-400 ml-2 whitespace-nowrap">
|
||||
{{ getUsernameById(lesson.userId) }}
|
||||
</span>
|
||||
<div class="w-16">
|
||||
<wd-progress :percentage="calcLessonProgress(lesson)"
|
||||
:color="calcLessonProgress(lesson) === 100 ? '#34d399' : '#60a5fa'" hide-text />
|
||||
</div>
|
||||
<div class="i-tabler-dots text-neutral-400 text-xl"></div>
|
||||
</div>
|
||||
<!-- 右滑操作按钮 - 仅管理员可见 -->
|
||||
<template #right>
|
||||
<view class="action">
|
||||
<!-- <view class="button" style="background: #f59e0b;" @click.stop="handleSwipeAction('edit', lesson)">编辑
|
||||
</view> -->
|
||||
<view class="button" style="background: #ef4444;" @click.stop="handleSwipeAction('delete', lesson)">
|
||||
删除</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-swipe-action>
|
||||
</div>
|
||||
</div>
|
||||
</wd-collapse-item>
|
||||
@ -329,4 +536,21 @@ onLoad(() => {
|
||||
.wd-collapse-item__header>view {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* SwipeAction 样式 */
|
||||
.action {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 16px;
|
||||
height: 100%;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
min-width: 60px;
|
||||
}
|
||||
</style>
|
||||
|
@ -20,6 +20,37 @@ const message = useMessage()
|
||||
|
||||
|
||||
const lesson = ref<LessonTask | null>(null)
|
||||
|
||||
// 判断当前用户是否应该处理该课程
|
||||
const shouldCurrentUserHandle = () => {
|
||||
if (!lesson.value) return false
|
||||
const role = getLessonRole(lesson.value)
|
||||
return (role === 'teacher' && user.hasRole('teacher')) ||
|
||||
(role === 'admin' && user.hasRole('admin'))
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 发送催办提醒
|
||||
const sendReminder = async () => {
|
||||
if (!lesson.value) return
|
||||
try {
|
||||
toast.loading({ msg: '发送催办中...' })
|
||||
await BussApi.sendReminder(lesson.value.id)
|
||||
toast.success({ msg: '催办成功,已通知相关人员处理' })
|
||||
// 重新加载课程详情
|
||||
await loadLesson()
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof Error) {
|
||||
toast.error({ msg: err.message })
|
||||
} else {
|
||||
toast.error({ msg: '催办失败' })
|
||||
}
|
||||
} finally {
|
||||
toast.close()
|
||||
}
|
||||
}
|
||||
|
||||
const lessonSteps = computed(() => lesson.value ? getLessonSteps(lesson.value) : [])
|
||||
const lessonStages = computed(() => lesson.value ? extractLessonStage(lesson.value) : null)
|
||||
const lessonProgress = computed(() => lesson.value ? calcLessonProgress(lesson.value) : 0)
|
||||
@ -39,31 +70,61 @@ const goProgress = (lessonId: number) => {
|
||||
return
|
||||
}
|
||||
|
||||
router.replaceAll({
|
||||
name: 'progress',
|
||||
params: {
|
||||
courseName: `${lesson.value.courseName}`,
|
||||
lessonId: `${lessonId}`
|
||||
}
|
||||
// 更新导航栏状态
|
||||
tabbar.activeTab = 'progress'
|
||||
|
||||
// 先清除之前的缓存参数,确保每次使用最新的参数
|
||||
uni.removeStorageSync('progress_params')
|
||||
|
||||
// 使用本地存储传递参数
|
||||
const courseNameParam = lesson.value.courseName
|
||||
const lessonIdParam = lessonId.toString()
|
||||
|
||||
|
||||
|
||||
// 将参数存储到本地缓存
|
||||
uni.setStorageSync('progress_params', {
|
||||
courseName: courseNameParam,
|
||||
lessonId: lessonIdParam
|
||||
})
|
||||
|
||||
// 不带参数跳转到tabBar页面
|
||||
router.pushTab({
|
||||
name: 'progress'
|
||||
})
|
||||
}
|
||||
|
||||
const loadLesson = async () => {
|
||||
if (!route.params?.courseId) {
|
||||
toast.error({
|
||||
msg: '参数错误'
|
||||
msg: '参数错误:缺少课程ID'
|
||||
})
|
||||
console.error('Missing courseId in route params:', route.params)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Loading lesson with courseId:', route.params.courseId)
|
||||
toast.loading({
|
||||
msg: '加载中...'
|
||||
})
|
||||
BussApi.getLessonTask(route.params.courseId).then(courseData => {
|
||||
toast.close()
|
||||
|
||||
try {
|
||||
// 确保courseId是数字类型
|
||||
const courseId = parseInt(route.params.courseId as string)
|
||||
if (isNaN(courseId)) {
|
||||
throw new Error('课程ID格式错误')
|
||||
}
|
||||
|
||||
const courseData = await BussApi.getLessonTask(courseId)
|
||||
console.log('Lesson data loaded:', courseData)
|
||||
lesson.value = courseData
|
||||
}).catch(err => {
|
||||
toast.error({ msg: err.message })
|
||||
})
|
||||
toast.close()
|
||||
} catch (err: any) {
|
||||
console.error('Failed to load lesson:', err)
|
||||
toast.error({
|
||||
msg: err?.message || '加载课程数据失败,请重试'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@ -92,6 +153,9 @@ onPullDownRefresh(() => {
|
||||
|
||||
// 页面加载时执行
|
||||
onLoad(() => {
|
||||
// 清除进度页面的缓存参数,避免缓存累积
|
||||
uni.removeStorageSync('progress_params')
|
||||
|
||||
loadLesson()
|
||||
})
|
||||
|
||||
@ -100,36 +164,60 @@ onLoad(() => {
|
||||
<template>
|
||||
<div>
|
||||
<wd-message-box></wd-message-box>
|
||||
<div
|
||||
:class="`pattern p-4 flex flex-col gap-6 relative ${lessonProgress === 100 ? 'bg-emerald' : (lessonProgress === 0 ? 'bg-neutral' : 'bg-blue')}`">
|
||||
<div class="flex flex-col gap-0">
|
||||
<h2 class="text-sm text-white font-black op-50">{{ lesson?.courseName }}</h2>
|
||||
<h1 class="text-lg text-white font-bold">{{ lesson?.microLessonName }}</h1>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="!lesson" class="p-4 text-center">
|
||||
<wd-loading vertical>
|
||||
加载课程信息中...
|
||||
</wd-loading>
|
||||
</div>
|
||||
|
||||
<!-- 课程信息 -->
|
||||
<div v-else>
|
||||
<div
|
||||
:class="`pattern p-4 flex flex-col gap-6 relative ${lessonProgress === 100 ? 'bg-emerald' : (lessonProgress === 0 ? 'bg-neutral' : 'bg-blue')}`">
|
||||
<div class="flex flex-col gap-0">
|
||||
<h2 class="text-sm text-white font-black op-50">{{ lesson?.courseName || '无课程名称' }}</h2>
|
||||
<h1 class="text-lg text-white font-bold">{{ lesson?.microLessonName || '无微课名称' }}</h1>
|
||||
</div>
|
||||
<p class="text-xs text-white font-bold op-50" style="line-height: 1;">
|
||||
创建于 {{ lesson?.createdAt ? dayjs(lesson.createdAt * 1000).format('YYYY-MM-DD HH:mm:ss') : '未知时间' }}
|
||||
</p>
|
||||
<p v-if="lessonProgress === 100" class="text-xs text-white font-bold op-50" style="line-height: 1;">
|
||||
完成于 {{ lesson?.finishTime ? dayjs(lesson.finishTime * 1000).format('YYYY-MM-DD HH:mm:ss') : '未知时间' }}
|
||||
</p>
|
||||
<div class="absolute text-white top-2 right-2 op-35 text-18">
|
||||
<div v-if="lessonProgress === 100" class="i-tabler-circle-check"></div>
|
||||
<div v-else-if="lessonProgress === 0" class="i-tabler-progress-x"></div>
|
||||
<div v-else class="i-tabler-hourglass-empty"></div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-white font-bold op-50" style="line-height: 1;">
|
||||
创建于 {{ lesson?.createdAt ? dayjs(lesson.createdAt * 1000).format('YYYY-MM-DD HH:mm:ss') : '-' }}
|
||||
</p>
|
||||
<p v-if="lessonProgress === 100" class="text-xs text-white font-bold op-50" style="line-height: 1;">
|
||||
完成于 {{ lesson?.finishTime ? dayjs(lesson.finishTime * 1000).format('YYYY-MM-DD HH:mm:ss') : '-' }}
|
||||
</p>
|
||||
<div class="absolute text-white top-2 right-2 op-35 text-18">
|
||||
<div v-if="lessonProgress === 100" class="i-tabler-circle-check"></div>
|
||||
<div v-else-if="lessonProgress === 0" class="i-tabler-progress-x"></div>
|
||||
<div v-else class="i-tabler-hourglass-empty"></div>
|
||||
|
||||
<div class="p-4">
|
||||
<wd-steps :active="lessonStages?.step || 0" vertical>
|
||||
<wd-step v-for="(step, index) in lessonSteps" :key="index" :title="step.title"
|
||||
:description="step.description" />
|
||||
</wd-steps>
|
||||
</div>
|
||||
|
||||
<!-- 进度处理按钮区域 -->
|
||||
<div v-if="lessonProgress !== 100" class="px-4 pt-2 ">
|
||||
<wd-button v-if="!user.hasRole('liaison')" type="primary" :round="false" plain block
|
||||
@click="goProgress(lesson?.id!)">进度处理</wd-button>
|
||||
</div>
|
||||
<div v-else class="px-4 pt-2">
|
||||
<wd-button v-if="!user.hasRole('liaison')" disabled type="success" :round="false" plain block>已完成</wd-button>
|
||||
</div>
|
||||
|
||||
<!-- 催办按钮区域 -->
|
||||
<div
|
||||
v-if="lesson && !shouldCurrentUserHandle() && lessonProgress !== 100 && (user.hasRole('teacher') || user.hasRole('admin'))"
|
||||
class="px-4 pt-2">
|
||||
<wd-button type="warning" :round="false" plain block @click="sendReminder">
|
||||
<wd-icon name="bell" class="mr-1"></wd-icon>
|
||||
催办
|
||||
</wd-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<wd-steps :active="lessonStages?.step || 0" vertical>
|
||||
<wd-step v-for="(step, index) in lessonSteps" :key="index" :title="step.title"
|
||||
:description="step.description" />
|
||||
</wd-steps>
|
||||
</div>
|
||||
<div v-if="lessonProgress !== 100" class="px-4 pt-2 ">
|
||||
<wd-button v-if="!user.hasRole('liaison')" type="primary" :round="false" plain block
|
||||
@click="goProgress(lesson?.id!)">进度处理</wd-button>
|
||||
</div>
|
||||
<div v-else class="px-4 pt-2">
|
||||
<wd-button v-if="!user.hasRole('liaison')" disabled type="success" :round="false" plain block>已完成</wd-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -37,6 +37,14 @@ const handleSubmit = () => {
|
||||
remember: model.remember
|
||||
}).then(res => {
|
||||
user.setToken(res.token)
|
||||
|
||||
// 如果用户勾选了记住密码,保存登录凭证
|
||||
if (model.remember) {
|
||||
user.saveCredentials(model.email, model.password)
|
||||
} else {
|
||||
user.clearCredentials()
|
||||
}
|
||||
|
||||
toast.loading({
|
||||
msg: '加载资料...'
|
||||
})
|
||||
@ -74,6 +82,15 @@ onPullDownRefresh(() => {
|
||||
refresh()
|
||||
})
|
||||
|
||||
// 初始化时加载登录凭证
|
||||
onLoad(() => {
|
||||
const credentials = user.getCredentials()
|
||||
if (credentials) {
|
||||
model.email = credentials.email
|
||||
model.password = credentials.password
|
||||
model.remember = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -87,7 +104,7 @@ onPullDownRefresh(() => {
|
||||
<wd-cell>
|
||||
<template #title>
|
||||
<div class="pl-[5px]">
|
||||
<wd-checkbox v-model="model.remember">记住登录</wd-checkbox>
|
||||
<wd-checkbox v-model="model.remember">记住密码</wd-checkbox>
|
||||
</div>
|
||||
</template>
|
||||
</wd-cell>
|
||||
|
@ -9,7 +9,7 @@ import StatusBlock from './StatusBlock.vue';
|
||||
import { useRoute } from 'uni-mini-router';
|
||||
import { useUser } from '@/stores/useUser';
|
||||
import { useTabbar } from '@/stores/useTabbar'
|
||||
import { onPullDownRefresh } from '@dcloudio/uni-app'
|
||||
import { onPullDownRefresh, onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import { useRouter } from 'uni-mini-router';
|
||||
|
||||
const router = useRouter()
|
||||
@ -29,8 +29,16 @@ const pickerCourseValue = ref()
|
||||
|
||||
const pickerLessonColumns = computed(() => {
|
||||
return pickerCourseValue.value ? groupedLessons.value[pickerCourseValue.value].map((lesson: LessonTask) => {
|
||||
const isCompleted = extractLessonStage(lesson).step === 5
|
||||
const shouldShowExpedite = shouldShowExpediteNotice(lesson)
|
||||
let prefix = ''
|
||||
if (isCompleted) {
|
||||
prefix = '✅ '
|
||||
} else if (shouldShowExpedite) {
|
||||
prefix = '🔔 '
|
||||
}
|
||||
return {
|
||||
label: (extractLessonStage(lesson).step === 5 ? '✅ ' : '') + lesson.microLessonName,
|
||||
label: prefix + lesson.microLessonName,
|
||||
value: lesson.id,
|
||||
}
|
||||
}) : []
|
||||
@ -48,6 +56,142 @@ const selectedLessonStage = computed(() => {
|
||||
return extractLessonStage(selectedLesson.value)
|
||||
})
|
||||
|
||||
const isExpedited = computed(() => {
|
||||
return selectedLesson.value?.expediteStatus === 1
|
||||
})
|
||||
|
||||
/**
|
||||
* 判断当前用户是否负责当前进度
|
||||
* @param lesson 课程任务
|
||||
* @returns 是否负责当前进度
|
||||
*/
|
||||
const isUserResponsibleForCurrentProgress = (lesson: LessonTask): boolean => {
|
||||
if (!lesson || !user.userinfo) return false
|
||||
|
||||
const progressStatus = lesson.progressStatus
|
||||
const userRoles = user.userinfo.roles
|
||||
const userJobs = user.userinfo.jobs
|
||||
|
||||
// 判断进度负责人
|
||||
switch (progressStatus) {
|
||||
case 0: // 脚本制作 - 教师负责
|
||||
case 1: // 脚本提交 - 教师负责
|
||||
return userRoles === 1 && userJobs === 1 // 校方教师 + 课程制作教师
|
||||
|
||||
case 2: // 脚本审核 - 审核人员负责
|
||||
return userJobs === 2 // 课程审核人员
|
||||
|
||||
case 3: // 脚本确认 - 教师负责
|
||||
return userRoles === 1 && userJobs === 1 // 校方教师 + 课程制作教师
|
||||
|
||||
case 4: // 视频制作审核 - 审核人员负责
|
||||
return userJobs === 2 // 课程审核人员
|
||||
|
||||
case 5: // 已完成
|
||||
return false
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否应该显示催办消息
|
||||
* @param lesson 课程任务
|
||||
* @returns 是否显示催办消息
|
||||
*/
|
||||
const shouldShowExpediteNotice = (lesson: LessonTask): boolean => {
|
||||
if (!lesson || !user.userinfo) return false
|
||||
|
||||
// 条件1: 当前用户所负责的课程(通过userId判断)
|
||||
const isUserCourse = lesson.userId === user.userinfo.id
|
||||
|
||||
// 条件2: 课程当前所在的进度是当前用户所负责的进度
|
||||
const isResponsibleForProgress = isUserResponsibleForCurrentProgress(lesson)
|
||||
|
||||
// 条件3: 催办信息为1
|
||||
const isExpedited = lesson.expediteStatus === 1
|
||||
|
||||
return isUserCourse && isResponsibleForProgress && isExpedited
|
||||
}
|
||||
|
||||
const shouldShowExpediteNoticeForSelected = computed(() => {
|
||||
return selectedLesson.value ? shouldShowExpediteNotice(selectedLesson.value) : false
|
||||
})
|
||||
|
||||
/**
|
||||
* 调试函数:打印当前账户所负责的课程状态
|
||||
*/
|
||||
const debugUserCourses = () => {
|
||||
console.log('🔍 执行debugUserCourses函数...')
|
||||
|
||||
if (!user.userinfo) {
|
||||
console.log('❌ 用户未登录')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('👤 当前用户ID:', user.userinfo.id)
|
||||
|
||||
const allLessons = Object.values(groupedLessons.value).flat()
|
||||
console.log('📚 所有课程数量:', allLessons.length)
|
||||
|
||||
// 过滤出当前用户负责的课程
|
||||
const userCourses = allLessons.filter(lesson => lesson.userId === user.userinfo!.id)
|
||||
console.log('🎯 当前用户负责的课程数量:', userCourses.length)
|
||||
|
||||
// 生成简洁的ID和状态对应关系
|
||||
const courseStatusMap = userCourses.reduce((acc, lesson) => {
|
||||
acc[`ID:${lesson.id}`] = `状态:${lesson.progressStatus}`
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
console.log('📋 当前用户负责的课程状态:', courseStatusMap)
|
||||
|
||||
// 催办状态的课程
|
||||
const expeditedCourseMap = userCourses
|
||||
.filter(lesson => lesson.expediteStatus === 1)
|
||||
.reduce((acc, lesson) => {
|
||||
acc[`ID:${lesson.id}`] = `催办:${lesson.expediteStatus}`
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
if (Object.keys(expeditedCourseMap).length > 0) {
|
||||
console.log('🔔 催办状态的课程:', expeditedCourseMap)
|
||||
}
|
||||
|
||||
// 需要处理的催办课程
|
||||
const needAttentionMap = userCourses
|
||||
.filter(lesson => shouldShowExpediteNotice(lesson))
|
||||
.reduce((acc, lesson) => {
|
||||
acc[`ID:${lesson.id}`] = `需处理:是`
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
if (Object.keys(needAttentionMap).length > 0) {
|
||||
console.log('⚠️ 需要处理的催办课程:', needAttentionMap)
|
||||
}
|
||||
}
|
||||
|
||||
// 自动清除催办消息的辅助函数
|
||||
const autoClearReminder = async (lessonId: number) => {
|
||||
try {
|
||||
console.log('开始清除催办消息,课程ID:', lessonId)
|
||||
await BussApi.clearReminder(lessonId)
|
||||
console.log('催办消息清除成功,课程ID:', lessonId)
|
||||
|
||||
// 显示清除成功的提示
|
||||
toast.success({
|
||||
msg: '催办消息已清除'
|
||||
})
|
||||
} catch (err: any) {
|
||||
console.error('自动清除催办消息失败:', err)
|
||||
// 显示清除失败的提示
|
||||
toast.error({
|
||||
msg: `清除催办消息失败: ${err?.message || '未知错误'}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断advise是否为驳回状态
|
||||
* @param advise 修改建议字符串
|
||||
@ -57,7 +201,7 @@ const isRejectAdvise = (advise: string | undefined): boolean => {
|
||||
try {
|
||||
if (!advise) return false
|
||||
const adviseObj = JSON.parse(advise)
|
||||
return 'reject' in adviseObj
|
||||
return 'type' in adviseObj && 'data' in adviseObj
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
@ -67,24 +211,76 @@ const adviseText = computed(() => {
|
||||
try {
|
||||
if (!selectedLesson.value?.advise) return '暂无修改建议'
|
||||
const adviseObj = JSON.parse(selectedLesson.value.advise)
|
||||
return adviseObj.reject || '暂无修改建议'
|
||||
return adviseObj.data || '暂无修改建议'
|
||||
} catch {
|
||||
return selectedLesson?.value?.advise || '暂无修改建议'
|
||||
}
|
||||
})
|
||||
|
||||
const hasValidAdvise = computed(() => {
|
||||
try {
|
||||
if (!selectedLesson.value?.advise) return false
|
||||
const adviseObj = JSON.parse(selectedLesson.value.advise)
|
||||
const dataText = adviseObj.data
|
||||
return dataText && dataText.trim() !== ''
|
||||
} catch {
|
||||
const adviseText = selectedLesson?.value?.advise
|
||||
return adviseText && adviseText.trim() !== ''
|
||||
}
|
||||
})
|
||||
|
||||
const adviseTimestamp = computed(() => {
|
||||
try {
|
||||
if (!selectedLesson.value?.advise) return null
|
||||
const adviseObj = JSON.parse(selectedLesson.value.advise)
|
||||
return adviseObj.time || null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
const formatTimestamp = (timestamp: string | null) => {
|
||||
if (!timestamp) return ''
|
||||
try {
|
||||
const date = new Date(timestamp)
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const hour = String(date.getHours()).padStart(2, '0')
|
||||
const minute = String(date.getMinutes()).padStart(2, '0')
|
||||
const formatted = `${year}/${month}/${day} ${hour}:${minute}`
|
||||
console.log('格式化时间:', timestamp, '->', formatted)
|
||||
return formatted
|
||||
} catch (error) {
|
||||
console.error('时间格式化错误:', error)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
const getAdviseText = (adviseString: string | undefined): string => {
|
||||
try {
|
||||
if (!adviseString) return ''
|
||||
const adviseObj = JSON.parse(adviseString)
|
||||
const rejectText = adviseObj.reject || ''
|
||||
return rejectText
|
||||
const dataText = adviseObj.data || ''
|
||||
return dataText
|
||||
} catch (e) {
|
||||
console.error('JSON解析失败:', e)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
const getAdviseTimestamp = (adviseString: string | undefined): string | null => {
|
||||
try {
|
||||
if (!adviseString) return null
|
||||
const adviseObj = JSON.parse(adviseString)
|
||||
return adviseObj.time || null
|
||||
} catch (e) {
|
||||
console.error('JSON解析失败:', e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const onCoursePick = ({ value }: { value: string }) => {
|
||||
pickerCourseValue.value = value
|
||||
pickerLessonValue.value = undefined
|
||||
@ -92,6 +288,28 @@ const onCoursePick = ({ value }: { value: string }) => {
|
||||
|
||||
const onLessonPick = ({ value }: { value: number }) => {
|
||||
pickerLessonValue.value = value
|
||||
|
||||
// 调试:打印选中课程的详细信息
|
||||
if (selectedLesson.value) {
|
||||
const lesson = selectedLesson.value
|
||||
const isResponsible = isUserResponsibleForCurrentProgress(lesson)
|
||||
const shouldShowExpedite = shouldShowExpediteNotice(lesson)
|
||||
|
||||
console.log('🎯 选中课程详情:', {
|
||||
id: lesson.id,
|
||||
courseName: lesson.courseName,
|
||||
microLessonName: lesson.microLessonName,
|
||||
progressStatus: lesson.progressStatus,
|
||||
expediteStatus: lesson.expediteStatus,
|
||||
userId: lesson.userId,
|
||||
currentUserId: user.userinfo?.id,
|
||||
userRoles: user.userinfo?.roles,
|
||||
userJobs: user.userinfo?.jobs,
|
||||
isUserCourse: lesson.userId === user.userinfo?.id,
|
||||
isUserResponsibleForProgress: isResponsible,
|
||||
shouldShowExpediteNotice: shouldShowExpedite
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,10 +337,19 @@ const onStep0 = () => {
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.SCRIPT_CREATING//1
|
||||
|
||||
progressStatus: ProgressStatus.SCRIPT_CREATING,//1
|
||||
msg: "" // 提交时清除催办消息
|
||||
}
|
||||
BussApi.updateLessonTask(selectedLesson.value.id, params).then(res => {
|
||||
|
||||
console.log('onStep0 请求体:', params)
|
||||
console.log('onStep0 课程ID:', selectedLesson.value.id)
|
||||
|
||||
BussApi.updateLessonTask(selectedLesson.value.id, params).then(async res => {
|
||||
// 清理催办提醒
|
||||
if (selectedLesson.value?.id) {
|
||||
await autoClearReminder(selectedLesson.value.id)
|
||||
}
|
||||
|
||||
toast.success({
|
||||
msg: '提交成功'
|
||||
})
|
||||
@ -152,30 +379,49 @@ const onStep1 = (rejected: boolean = false) => {
|
||||
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 requestData = rejected ? {
|
||||
advise: JSON.stringify({
|
||||
type: user.hasRole('teacher') ? 'teacher' : 'general_admin',
|
||||
data: adviseTextValue.value.toString(),
|
||||
time: new Date().toISOString()
|
||||
}),
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.NOT_STARTED,//0
|
||||
msg: "" // 驳回时清除催办消息
|
||||
} : {
|
||||
advise: JSON.stringify({ confirm: "" }),
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.SCRIPT_REVIEW,//2
|
||||
msg: "" // 通过时清除催办消息
|
||||
}
|
||||
|
||||
console.log('onStep1 请求体:', requestData)
|
||||
console.log('onStep1 课程ID:', selectedLesson.value.id)
|
||||
|
||||
BussApi.updateLessonTask(selectedLesson.value.id, requestData).then(async res => {
|
||||
console.log('onStep1 任务状态更新成功:', res)
|
||||
|
||||
// 清理催办提醒
|
||||
if (selectedLesson.value?.id) {
|
||||
await autoClearReminder(selectedLesson.value.id)
|
||||
}
|
||||
|
||||
toast.success({
|
||||
msg: rejected ? '驳回成功' : '审核通过'
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
updateLessons()
|
||||
}, 1500);
|
||||
}).catch(err => {
|
||||
console.error('onStep1 任务状态更新失败:', err)
|
||||
toast.error({ msg: err.message })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -194,30 +440,49 @@ const onStep2 = (rejected: boolean = false) => {
|
||||
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 requestData = rejected ? {
|
||||
advise: JSON.stringify({
|
||||
type: user.hasRole('teacher') ? 'teacher' : 'general_admin',
|
||||
data: adviseTextValue.value.toString(),
|
||||
time: new Date().toISOString()
|
||||
}),
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.SCRIPT_CREATING,//1
|
||||
msg: "" // 驳回时清除催办消息
|
||||
} : {
|
||||
advise: JSON.stringify({ confirm: "" }),
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.SCRIPT_CONFIRMED,//3
|
||||
msg: "" // 通过时清除催办消息
|
||||
}
|
||||
|
||||
console.log('onStep2 请求体:', requestData)
|
||||
console.log('onStep2 课程ID:', selectedLesson.value.id)
|
||||
|
||||
BussApi.updateLessonTask(selectedLesson.value.id, requestData).then(async res => {
|
||||
console.log('onStep2 任务状态更新成功:', res)
|
||||
|
||||
// 清理催办提醒
|
||||
if (selectedLesson.value?.id) {
|
||||
await autoClearReminder(selectedLesson.value.id)
|
||||
}
|
||||
|
||||
toast.success({
|
||||
msg: rejected ? '驳回成功' : '审核通过'
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
updateLessons()
|
||||
}, 1500);
|
||||
}).catch(err => {
|
||||
console.error('onStep2 任务状态更新失败:', err)
|
||||
toast.error({ msg: err.message })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -236,30 +501,49 @@ const onStep3 = (rejected: boolean = false) => {
|
||||
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 requestData = rejected ? {
|
||||
advise: JSON.stringify({
|
||||
type: user.hasRole('teacher') ? 'teacher' : 'general_admin',
|
||||
data: adviseTextValue.value.toString(),
|
||||
time: new Date().toISOString()
|
||||
}),
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.SCRIPT_REVIEW,//2
|
||||
msg: "" // 驳回时清除催办消息
|
||||
} : {
|
||||
advise: JSON.stringify({ confirm: "" }),
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.VIDEO_CREATING,//4
|
||||
msg: "" // 通过时清除催办消息
|
||||
}
|
||||
|
||||
console.log('onStep3 请求体:', requestData)
|
||||
console.log('onStep3 课程ID:', selectedLesson.value.id)
|
||||
|
||||
BussApi.updateLessonTask(selectedLesson.value.id, requestData).then(async res => {
|
||||
console.log('onStep3 任务状态更新成功:', res)
|
||||
|
||||
// 清理催办提醒
|
||||
if (selectedLesson.value?.id) {
|
||||
await autoClearReminder(selectedLesson.value.id)
|
||||
}
|
||||
|
||||
toast.success({
|
||||
msg: rejected ? '驳回成功' : '审核通过'
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
updateLessons()
|
||||
}, 1500);
|
||||
}).catch(err => {
|
||||
console.error('onStep3 任务状态更新失败:', err)
|
||||
toast.error({ msg: err.message })
|
||||
})
|
||||
})
|
||||
}
|
||||
const onStep4 = (rejected: boolean = false) => {
|
||||
@ -277,41 +561,69 @@ const onStep4 = (rejected: boolean = false) => {
|
||||
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 requestData = rejected ? {
|
||||
advise: JSON.stringify({
|
||||
type: user.hasRole('teacher') ? 'teacher' : 'general_admin',
|
||||
data: adviseTextValue.value.toString(),
|
||||
time: new Date().toISOString()
|
||||
}),
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.SCRIPT_CONFIRMED,//3
|
||||
msg: "" // 驳回时清除催办消息
|
||||
} : {
|
||||
advise: JSON.stringify({ confirm: "" }),
|
||||
courseName: selectedLesson.value.courseName,
|
||||
microLessonName: selectedLesson.value.microLessonName,
|
||||
userId: selectedLesson.value.userId,
|
||||
progressStatus: ProgressStatus.VIDEO_CONFIRMED,//5
|
||||
msg: "" // 通过时清除催办消息
|
||||
}
|
||||
|
||||
console.log('onStep4 请求体:', requestData)
|
||||
console.log('onStep4 课程ID:', selectedLesson.value.id)
|
||||
|
||||
BussApi.updateLessonTask(selectedLesson.value.id, requestData).then(async res => {
|
||||
console.log('onStep4 任务状态更新成功:', res)
|
||||
|
||||
// 清理催办提醒
|
||||
if (selectedLesson.value?.id) {
|
||||
await autoClearReminder(selectedLesson.value.id)
|
||||
}
|
||||
|
||||
toast.success({
|
||||
msg: rejected ? '驳回成功' : '审核通过'
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
updateLessons()
|
||||
}, 1500);
|
||||
}).catch(err => {
|
||||
console.error('onStep4 任务状态更新失败:', err)
|
||||
toast.error({ msg: err.message })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const updateLessons = async () => {
|
||||
console.log('🔄 开始更新课程列表...')
|
||||
adviseTextValue.value = ""
|
||||
if (!user.hasValidToken() || !user.userinfo) {
|
||||
console.log('❌ 用户未登录,跳转到登录页')
|
||||
toast.error({ msg: '请先登录' })
|
||||
router.replace('/pages/login/index')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('✅ 用户已登录,用户信息:', {
|
||||
id: user.userinfo.id,
|
||||
username: user.userinfo.username,
|
||||
roles: user.userinfo.roles,
|
||||
jobs: user.userinfo.jobs
|
||||
})
|
||||
|
||||
toast.loading({
|
||||
msg: '加载中...'
|
||||
})
|
||||
@ -338,11 +650,24 @@ const updateLessons = async () => {
|
||||
...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) })
|
||||
// 调试:打印当前账户所负责的课程状态
|
||||
console.log('🚀 开始调试用户课程状态...')
|
||||
debugUserCourses()
|
||||
console.log('✅ 调试完成')
|
||||
|
||||
// 从本地缓存获取参数
|
||||
const progress_params = uni.getStorageSync('progress_params')
|
||||
|
||||
if (progress_params && progress_params.courseName && progress_params.lessonId) {
|
||||
|
||||
// 选择课程
|
||||
if (Object.keys(groupData).includes(progress_params.courseName)) {
|
||||
onCoursePick({ value: progress_params.courseName })
|
||||
|
||||
// 选择课程ID
|
||||
const lessonIdValue = parseInt(progress_params.lessonId)
|
||||
if (!isNaN(lessonIdValue)) {
|
||||
onLessonPick({ value: lessonIdValue })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,9 +684,24 @@ const updateLessons = async () => {
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
console.log('📱 页面已挂载,开始加载数据...')
|
||||
|
||||
// 从本地缓存获取参数
|
||||
const progress_params = uni.getStorageSync('progress_params')
|
||||
|
||||
updateLessons()
|
||||
})
|
||||
|
||||
// 添加onShow钩子,确保每次显示页面时都刷新数据
|
||||
onShow(() => {
|
||||
const progress_params = uni.getStorageSync('progress_params')
|
||||
|
||||
// 如果有缓存参数,则需要重新加载数据
|
||||
if (progress_params && progress_params.courseName && progress_params.lessonId) {
|
||||
updateLessons()
|
||||
}
|
||||
})
|
||||
|
||||
const refresh = async () => {
|
||||
try {
|
||||
const startTime = Date.now()
|
||||
@ -405,6 +745,11 @@ const handleClick = () => {
|
||||
<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 v-if="shouldShowExpediteNoticeForSelected" class="mx-2">
|
||||
<wd-notice-bar text="🔔 此课程已被催办,请加快处理进度" type="warning" />
|
||||
</div> -->
|
||||
|
||||
<div>
|
||||
<wd-steps :active="selectedLessonStage?.step || 0" align-center>
|
||||
<wd-step v-for="(step, index) in getLessonSteps(selectedLesson!, true)" :key="index" :title="step.title"
|
||||
@ -414,20 +759,25 @@ const handleClick = () => {
|
||||
|
||||
<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">
|
||||
<div v-if="isRejectAdvise(selectedLesson?.advise) && hasValidAdvise" class="m-2 text-sm">
|
||||
<wd-card title="修改建议">
|
||||
{{ adviseText }}
|
||||
<div class="space-y-2">
|
||||
<div class="break-words whitespace-pre-wrap">{{ adviseText }}</div>
|
||||
<div v-if="adviseTimestamp" class="text-xs text-gray-500">
|
||||
时间:{{ formatTimestamp(adviseTimestamp) }}
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
<div class="mb-4">
|
||||
<div class="text-sm font-semibold text-gray-700 mb-4 ">脚本提交途径</div>
|
||||
<wd-radio-group v-model="script_file_destination" class="flex justify-center">
|
||||
<wd-radio value="wechat" shape="button" class="mx-1">微信</wd-radio>
|
||||
<wd-radio value="qq" shape="button" class="mx-1">QQ</wd-radio>
|
||||
<wd-radio value="baidu" shape="button" class="mx-1">百度网盘</wd-radio>
|
||||
<wd-radio value="platform" shape="button" class="mx-1">平台</wd-radio>
|
||||
</wd-radio-group>
|
||||
</div>
|
||||
<wd-button type="primary" block @click="onStep0" custom-class="w-full">提交脚本</wd-button>
|
||||
</div>
|
||||
<StatusBlock v-else title="脚本还未提交" subtitle="请耐心等待提交">
|
||||
@ -446,9 +796,14 @@ const handleClick = () => {
|
||||
</StatusBlock>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="isRejectAdvise(selectedLesson?.advise) === true" class=" m-2 text-sm">
|
||||
<div v-if="isRejectAdvise(selectedLesson?.advise) && hasValidAdvise" class=" m-2 text-sm">
|
||||
<wd-card title="修改建议">
|
||||
{{ adviseText }}
|
||||
<div class="space-y-2">
|
||||
<div class="break-words whitespace-pre-wrap">{{ adviseText }}</div>
|
||||
<div v-if="adviseTimestamp" class="text-xs text-gray-500">
|
||||
时间:{{ formatTimestamp(adviseTimestamp) }}
|
||||
</div>
|
||||
</div>
|
||||
</wd-card>
|
||||
</div>
|
||||
<StatusBlock title="脚本已提交" subtitle="请耐心等待审核">
|
||||
@ -457,7 +812,7 @@ const handleClick = () => {
|
||||
</template>
|
||||
</StatusBlock>
|
||||
<div class="mt-4 space-y-4">
|
||||
<div class="flex gap-3 px-4">
|
||||
<div class="flex gap-3 px-4 justify-center">
|
||||
<wd-button type="primary" block @click="onStep1()">确认</wd-button>
|
||||
<wd-button type="error" block @click="onStep1(true)">驳回</wd-button>
|
||||
</div>
|
||||
@ -467,13 +822,23 @@ const handleClick = () => {
|
||||
|
||||
<div v-if="selectedLessonStage?.step === 2">
|
||||
<div v-if="user.hasRole('teacher')">
|
||||
<div v-if="isRejectAdvise(selectedLesson?.advise) && hasValidAdvise" class="m-2 text-sm">
|
||||
<wd-card title="修改建议">
|
||||
<div class="space-y-2">
|
||||
<div class="break-words whitespace-pre-wrap">{{ adviseText }}</div>
|
||||
<div v-if="adviseTimestamp" class="text-xs text-gray-500">
|
||||
时间:{{ formatTimestamp(adviseTimestamp) }}
|
||||
</div>
|
||||
</div>
|
||||
</wd-card>
|
||||
</div>
|
||||
<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">
|
||||
<div class="flex gap-3 px-4 justify-center">
|
||||
<wd-button type="primary" block @click="onStep2()">确认</wd-button>
|
||||
<wd-button type="error" block @click="onStep2(true)">驳回</wd-button>
|
||||
</div>
|
||||
@ -490,32 +855,30 @@ const handleClick = () => {
|
||||
|
||||
<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="请等待视频拍摄制作">
|
||||
<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 v-if="isRejectAdvise(selectedLesson?.advise) && hasValidAdvise" class=" m-2 text-sm">
|
||||
<wd-card title="修改建议">
|
||||
<div class="space-y-2">
|
||||
<div class="break-words whitespace-pre-wrap">{{ adviseText }}</div>
|
||||
<div v-if="adviseTimestamp" class="text-xs text-gray-500">
|
||||
时间:{{ formatTimestamp(adviseTimestamp) }}
|
||||
</div>
|
||||
</div>
|
||||
</wd-card>
|
||||
</div>
|
||||
<StatusBlock title="视频拍摄制作进行中" subtitle="完成后请确认">
|
||||
<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">
|
||||
<div class="flex gap-3 px-4 justify-center">
|
||||
<wd-button type="primary" block @click="onStep3()">通过</wd-button>
|
||||
<wd-button type="error" block @click="onStep3(true)">驳回</wd-button>
|
||||
</div>
|
||||
@ -525,20 +888,20 @@ const handleClick = () => {
|
||||
|
||||
<div v-if="selectedLessonStage?.step === 4">
|
||||
<div v-if="user.hasRole('teacher')">
|
||||
<StatusBlock title="视频拍摄制作已完成" subtitle="请确认视频内容">
|
||||
<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">
|
||||
<div class="flex gap-3 px-4 justify-center">
|
||||
<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="请等待视频内容确认">
|
||||
<StatusBlock title="资源内容确认中" subtitle="请等待资源内容确认">
|
||||
<template #icon>
|
||||
<div class="i-tabler-brand-parsinta text-7xl text-neutral-400"></div>
|
||||
</template>
|
||||
|
@ -84,6 +84,22 @@ export const useUser = defineStore("user", () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 保存登录凭证
|
||||
function saveCredentials(email: string, password: string) {
|
||||
uni.setStorageSync('credentials', { email, password });
|
||||
}
|
||||
|
||||
// 获取登录凭证
|
||||
function getCredentials(): { email: string, password: string } | null {
|
||||
const credentials = uni.getStorageSync('credentials');
|
||||
return credentials || null;
|
||||
}
|
||||
|
||||
// 清除登录凭证
|
||||
function clearCredentials() {
|
||||
uni.removeStorageSync('credentials');
|
||||
}
|
||||
|
||||
// 检查 token 是否有效
|
||||
function hasValidToken(): boolean {
|
||||
return !!token.value && token.value.length > 0;
|
||||
@ -92,6 +108,8 @@ export const useUser = defineStore("user", () => {
|
||||
function logout() {
|
||||
token.value = null;
|
||||
userinfo.value = null;
|
||||
uni.removeStorageSync('token');
|
||||
// 不要清除登录凭证,以便用户下次能够快速登录
|
||||
}
|
||||
|
||||
return {
|
||||
@ -103,6 +121,9 @@ export const useUser = defineStore("user", () => {
|
||||
canEditCourse,
|
||||
logout,
|
||||
setToken,
|
||||
hasValidToken
|
||||
hasValidToken,
|
||||
saveCredentials,
|
||||
getCredentials,
|
||||
clearCredentials
|
||||
};
|
||||
});
|
||||
|
@ -24,8 +24,12 @@ export interface LessonTask {
|
||||
videoConfirmTime?: number;
|
||||
/** 任务完成时间(时间戳) */
|
||||
finishTime?: number;
|
||||
/** 催办状态 0:未催办 1:催办 */
|
||||
expediteStatus: number;
|
||||
/** 建议/反馈信息 */
|
||||
advise?: string;
|
||||
/** 催办消息 */
|
||||
msg?: string | null;
|
||||
/** 创建时间(时间戳) */
|
||||
createdAt: number;
|
||||
/** 更新时间(时间戳) */
|
||||
@ -47,8 +51,8 @@ export interface LessonTaskPagination {
|
||||
* NOT_STARTED = 0, // 脚本制作
|
||||
SCRIPT_CREATING = 1, // 脚本审核
|
||||
SCRIPT_REVIEW = 2, // 脚本审核
|
||||
SCRIPT_CONFIRMED = 3, // 视频拍摄与制作
|
||||
VIDEO_CREATING = 4, // 视频确认
|
||||
SCRIPT_CONFIRMED = 3, // 后期制作
|
||||
VIDEO_CREATING = 4, // 资源确认
|
||||
VIDEO_CONFIRMED = 5 // 任务完成
|
||||
*/
|
||||
// 进度状态枚举
|
||||
@ -56,12 +60,12 @@ export enum ProgressStatus {
|
||||
NOT_STARTED = 0, // 脚本制作
|
||||
SCRIPT_CREATING = 1, // 脚本审核
|
||||
SCRIPT_REVIEW = 2, // 脚本审核
|
||||
SCRIPT_CONFIRMED = 3, // 视频拍摄与制作
|
||||
VIDEO_CREATING = 4, // 视频确认
|
||||
SCRIPT_CONFIRMED = 3, // 后期制作
|
||||
VIDEO_CREATING = 4, // 资源确认
|
||||
VIDEO_CONFIRMED = 5 // 任务完成
|
||||
}
|
||||
|
||||
export type FileUploadDestination = "qq" | "wechat" | "platform";
|
||||
export type FileUploadDestination = "qq" | "wechat" | "platform" | "baidu";
|
||||
|
||||
/**
|
||||
* 创建课程任务请求参数接口
|
||||
@ -101,6 +105,10 @@ export interface UpdateLessonTaskRequest {
|
||||
videoConfirmTime?: number;
|
||||
/** 任务完成时间 */
|
||||
finishTime?: number;
|
||||
/** 催办状态 0:未催办 1:催办 */
|
||||
expediteStatus?: number;
|
||||
/** 建议信息 */
|
||||
advise?: string;
|
||||
/** 催办消息 */
|
||||
msg?: string | null;
|
||||
}
|
||||
|
@ -20,18 +20,18 @@ export interface Authority {
|
||||
|
||||
// 角色枚举
|
||||
export enum Roles {
|
||||
TEACHER = 1, // 教师
|
||||
GENERAL_ADMIN = 2, // 管理员
|
||||
CONTACTOR = 3, // 项目负责人
|
||||
SYSTEM_ADMIN = 4 // 系统管理员
|
||||
TEACHER = 1, // 校方教师
|
||||
GENERAL_ADMIN = 2, // 公司课程顾问
|
||||
CONTACTOR = 3, // 校方项目负责人
|
||||
SYSTEM_ADMIN = 4 // 公司系统管理员
|
||||
}
|
||||
|
||||
// 岗位枚举
|
||||
export enum Jobs {
|
||||
COURSE_TEACHER = 1, // 课程教师
|
||||
PROJECT_MANAGER = 2, // 项目经理
|
||||
COURSE_CONTACTOR = 3, // 课程负责人
|
||||
SYSTEM_MANAGER = 4 // 系统管理
|
||||
COURSE_TEACHER = 1, // 课程制作教师
|
||||
PROJECT_MANAGER = 2, // 课程审核人员
|
||||
COURSE_CONTACTOR = 3, // 校方项目负责人
|
||||
SYSTEM_MANAGER = 4 // 公司系统管理员
|
||||
}
|
||||
|
||||
// 用户状态枚举
|
||||
|
@ -7,8 +7,8 @@ export const extractLessonStage = (lesson: LessonTask) => {
|
||||
script_creating: currentStep >= 1, // 脚本制作
|
||||
script_review: currentStep >= 2, // 脚本审核
|
||||
script_confirmed: currentStep >= 3, // 脚本确认
|
||||
video_creating: currentStep >= 4, // 视频制作
|
||||
video_confirmed: currentStep >= 5, // 视频确认
|
||||
video_creating: currentStep >= 4, // 后期制作
|
||||
video_confirmed: currentStep >= 5, // 资源确认
|
||||
step: 0,
|
||||
};
|
||||
stages.step = currentStep;
|
||||
@ -21,7 +21,7 @@ export const getLessonRole = (lesson: LessonTask): 'teacher' | 'admin' | '' => {
|
||||
switch (lesson.progressStatus) {
|
||||
case 0: // 未开始
|
||||
case 2: // 脚本审核
|
||||
case 4: // 视频拍摄与制作
|
||||
case 4: // 后期制作
|
||||
return 'teacher';
|
||||
|
||||
case 1: // 脚本制作
|
||||
@ -37,11 +37,11 @@ export const calcLessonProgress = (lesson: LessonTask) => {
|
||||
if (!lesson) return 0;
|
||||
|
||||
// 根据 progressStatus 计算进度
|
||||
// 0-未开始, 1-脚本制作, 2-脚本审核, 3-脚本确认, 4-视频拍摄与制作, 5-视频确认
|
||||
// 0-未开始, 1-脚本制作, 2-脚本审核, 3-脚本确认, 4-后期制作, 5-资源确认
|
||||
switch (lesson.progressStatus) {
|
||||
case 5: // 视频确认
|
||||
case 5: // 资源确认
|
||||
return 100;
|
||||
case 4: // 视频拍摄与制作
|
||||
case 4: // 后期制作
|
||||
return 80;
|
||||
case 3: // 脚本确认
|
||||
return 60;
|
||||
@ -92,20 +92,20 @@ export const getLessonSteps = (lesson: LessonTask, simplify: boolean = false) =>
|
||||
: "确认脚本内容",
|
||||
},
|
||||
{
|
||||
title: progress.video_creating ? "拍摄制作" : undefined,
|
||||
title: progress.video_creating ? "后期制作" : undefined,
|
||||
description: progress.video_creating
|
||||
? simplify
|
||||
? "已完成"
|
||||
: `已于 ${formatTime(lesson.videoCreateTime)} 完成拍摄制作`
|
||||
: "拍摄制作",
|
||||
: `已于 ${formatTime(lesson.videoCreateTime)} 完成后期制作`
|
||||
: "后期制作",
|
||||
},
|
||||
{
|
||||
title: progress.video_confirmed ? "视频确认" : undefined,
|
||||
title: progress.video_confirmed ? "资源确认" : undefined,
|
||||
description: progress.video_confirmed
|
||||
? simplify
|
||||
? "已完成"
|
||||
: `已于 ${formatTime(lesson.videoConfirmTime)} 完成视频确认`
|
||||
: "确认视频内容",
|
||||
: `已于 ${formatTime(lesson.videoConfirmTime)} 完成资源确认`
|
||||
: "确认资源内容",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
Reference in New Issue
Block a user