feat: 优化工作进度管理页面的样式
- 优化工作进度管理页面的样式,使其更加美观和易读 - 更新了 StatusBlock 组件,使其支持动态传入标题和副标题 - 更新了 Lesson 类型定义,将脚本文件、拍摄文件和素材文件的类型改为字符串 - 添加了 wd-drop-menu 和 wd-drop-menu-item 组件,用于下拉菜单的展示和选择 - 更新了首页列表请求参数,添加了加载指示器 - 在 Lesson 页面增加了单位、角色和权限的展示 - 修复了一些接口请求的问题,提升了用户资料更新的效率
This commit is contained in:
parent
66289511dd
commit
fe36c1a72b
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -14,7 +14,6 @@ declare module 'vue' {
|
|||||||
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
|
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
|
||||||
WdCollapse: typeof import('wot-design-uni/components/wd-collapse/wd-collapse.vue')['default']
|
WdCollapse: typeof import('wot-design-uni/components/wd-collapse/wd-collapse.vue')['default']
|
||||||
WdCollapseItem: typeof import('wot-design-uni/components/wd-collapse-item/wd-collapse-item.vue')['default']
|
WdCollapseItem: typeof import('wot-design-uni/components/wd-collapse-item/wd-collapse-item.vue')['default']
|
||||||
WdDivider: typeof import('wot-design-uni/components/wd-divider/wd-divider.vue')['default']
|
|
||||||
WdDropMenu: typeof import('wot-design-uni/components/wd-drop-menu/wd-drop-menu.vue')['default']
|
WdDropMenu: typeof import('wot-design-uni/components/wd-drop-menu/wd-drop-menu.vue')['default']
|
||||||
WdDropMenuItem: typeof import('wot-design-uni/components/wd-drop-menu-item/wd-drop-menu-item.vue')['default']
|
WdDropMenuItem: typeof import('wot-design-uni/components/wd-drop-menu-item/wd-drop-menu-item.vue')['default']
|
||||||
WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default']
|
WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default']
|
||||||
@ -28,7 +27,6 @@ declare module 'vue' {
|
|||||||
WdStatusTip: typeof import('wot-design-uni/components/wd-status-tip/wd-status-tip.vue')['default']
|
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']
|
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']
|
WdSteps: typeof import('wot-design-uni/components/wd-steps/wd-steps.vue')['default']
|
||||||
WdSwitch: typeof import('wot-design-uni/components/wd-switch/wd-switch.vue')['default']
|
|
||||||
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.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']
|
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
|
||||||
WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default']
|
WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default']
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import BussApi from '@/api/BussApi';
|
import BussApi from '@/api/BussApi';
|
||||||
import { useDayjs } from '@/composables/useDayjs';
|
import { useDayjs } from '@/composables/useDayjs';
|
||||||
|
import { useTabbar } from '@/stores/useTabbar';
|
||||||
import type { Lesson } from '@/types/api/lesson';
|
import type { Lesson } from '@/types/api/lesson';
|
||||||
import { calcLessonProgress, extractLessonStage, getLessonSteps } from '@/utils/lesson';
|
import { calcLessonProgress, extractLessonStage, getLessonSteps } from '@/utils/lesson';
|
||||||
import { useRoute } from 'uni-mini-router';
|
import { useRoute, useRouter } from 'uni-mini-router';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useToast } from 'wot-design-uni';
|
import { useToast } from 'wot-design-uni';
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const tabbar = useTabbar()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const dayjs = useDayjs()
|
const dayjs = useDayjs()
|
||||||
|
|
||||||
@ -16,6 +19,17 @@ const lessonSteps = computed(() => lesson.value ? getLessonSteps(lesson.value) :
|
|||||||
const lessonStages = computed(() => lesson.value ? extractLessonStage(lesson.value) : null)
|
const lessonStages = computed(() => lesson.value ? extractLessonStage(lesson.value) : null)
|
||||||
const lessonProgress = computed(() => lesson.value ? calcLessonProgress(lesson.value) : 0)
|
const lessonProgress = computed(() => lesson.value ? calcLessonProgress(lesson.value) : 0)
|
||||||
|
|
||||||
|
const goProgress = (lessonId: number) => {
|
||||||
|
router.replaceAll({
|
||||||
|
name: 'progress',
|
||||||
|
params: {
|
||||||
|
courseName: `${lesson.value?.course_name}`,
|
||||||
|
lessonId: `${lessonId}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tabbar.activeTab = 'progress'
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!route.params?.courseId) {
|
if (!route.params?.courseId) {
|
||||||
toast.error({
|
toast.error({
|
||||||
@ -37,7 +51,8 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div :class="`pattern p-4 flex flex-col gap-6 relative ${lessonProgress === 100 ? 'bg-emerald' : (lessonProgress === 0 ? 'bg-neutral' : 'bg-blue')}`">
|
<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">
|
<div class="flex flex-col gap-0">
|
||||||
<h2 class="text-sm text-white font-black op-50">{{ lesson?.course_name }}</h2>
|
<h2 class="text-sm text-white font-black op-50">{{ lesson?.course_name }}</h2>
|
||||||
<h1 class="text-lg text-white font-bold">{{ lesson?.m_lesson_name }}</h1>
|
<h1 class="text-lg text-white font-bold">{{ lesson?.m_lesson_name }}</h1>
|
||||||
@ -57,6 +72,9 @@ onMounted(() => {
|
|||||||
:description="step.description" />
|
:description="step.description" />
|
||||||
</wd-steps>
|
</wd-steps>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="px-4 pt-2">
|
||||||
|
<wd-button type="primary" :round="false" plain block @click="goProgress(lesson?.id!)">进度处理</wd-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
18
src/pages/progress/StatusBlock.vue
Normal file
18
src/pages/progress/StatusBlock.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
const props = defineProps({
|
||||||
|
title: String,
|
||||||
|
subtitle: String
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="rounded-lg mx-4 p-4 py-12 bg-neutral-100 flex items-center flex-col gap-4">
|
||||||
|
<slot name="icon"></slot>
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-base">{{ title }}</p>
|
||||||
|
<p class="text-xs text-neutral-500">{{ subtitle }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -1,11 +1,14 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import BussApi from '@/api/BussApi';
|
import BussApi from '@/api/BussApi';
|
||||||
import { useDayjs } from '@/composables/useDayjs';
|
import { useDayjs } from '@/composables/useDayjs';
|
||||||
import type { Lesson, ScriptFileDestination } from '@/types/api/lesson';
|
import type { Lesson, FileUploadDestination } from '@/types/api/lesson';
|
||||||
import { extractLessonStage, getLessonSteps } from '@/utils/lesson';
|
import { extractLessonStage, getLessonSteps, getScriptFile, parseCombinedFileString } from '@/utils/lesson';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, nextTick, onMounted, ref } from 'vue';
|
||||||
import { useMessage, useToast } from 'wot-design-uni';
|
import { useMessage, useToast } from 'wot-design-uni';
|
||||||
|
import StatusBlock from './StatusBlock.vue';
|
||||||
|
import { useRoute } from 'uni-mini-router';
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const dayjs = useDayjs()
|
const dayjs = useDayjs()
|
||||||
@ -39,7 +42,7 @@ const selectedLessonStage = computed(() => {
|
|||||||
|
|
||||||
const onCoursePick = ({ value }: { value: string }) => {
|
const onCoursePick = ({ value }: { value: string }) => {
|
||||||
pickerCourseValue.value = value
|
pickerCourseValue.value = value
|
||||||
pickerLessonValue.value = void 0
|
pickerLessonValue.value = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const onLessonPick = ({ value }: { value: number }) => {
|
const onLessonPick = ({ value }: { value: number }) => {
|
||||||
@ -50,7 +53,7 @@ const onLessonPick = ({ value }: { value: number }) => {
|
|||||||
* lesson progress modifition steps
|
* lesson progress modifition steps
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const script_file_destination = ref<ScriptFileDestination>('wechat')
|
const script_file_destination = ref<FileUploadDestination>('wechat')
|
||||||
|
|
||||||
const onStep0 = () => {
|
const onStep0 = () => {
|
||||||
message.confirm({
|
message.confirm({
|
||||||
@ -67,7 +70,10 @@ const onStep0 = () => {
|
|||||||
msg: '正在提交...'
|
msg: '正在提交...'
|
||||||
})
|
})
|
||||||
BussApi.editCourse(selectedLesson.value.id, {
|
BussApi.editCourse(selectedLesson.value.id, {
|
||||||
script_file: script_file_destination.value,
|
script_file: JSON.stringify({
|
||||||
|
method: script_file_destination.value,
|
||||||
|
uploaded: false
|
||||||
|
}),
|
||||||
script_upload_time: dayjs().unix()
|
script_upload_time: dayjs().unix()
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
toast.success({
|
toast.success({
|
||||||
@ -101,6 +107,13 @@ const updateLessons = () => {
|
|||||||
pickerCourseColumns.value = [
|
pickerCourseColumns.value = [
|
||||||
...Object.keys(groupData)
|
...Object.keys(groupData)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (route.params?.courseName) {
|
||||||
|
onCoursePick({ value: decodeURI(route.params.courseName) })
|
||||||
|
if (route.params?.lessonId) {
|
||||||
|
onLessonPick({ value: parseInt(route.params.lessonId) })
|
||||||
|
}
|
||||||
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
toast.error({ msg: err.message })
|
toast.error({ msg: err.message })
|
||||||
})
|
})
|
||||||
@ -141,7 +154,25 @@ onMounted(() => {
|
|||||||
|
|
||||||
<wd-button type="primary" block @click="onStep0" custom-class="w-full">提交脚本</wd-button>
|
<wd-button type="primary" block @click="onStep0" custom-class="w-full">提交脚本</wd-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedLessonStage?.step === 1"></div>
|
<div v-if="selectedLessonStage?.step === 1">
|
||||||
|
<StatusBlock v-if="!parseCombinedFileString(selectedLesson!, 'script_file')?.uploaded" title="脚本已提交"
|
||||||
|
subtitle="请耐心等待审核">
|
||||||
|
<template #icon>
|
||||||
|
<div class="i-tabler-progress-bolt text-7xl text-neutral-400"></div>
|
||||||
|
</template>
|
||||||
|
</StatusBlock>
|
||||||
|
<div v-else>
|
||||||
|
<StatusBlock title="脚本处理已完成" subtitle="请核对并审核">
|
||||||
|
<template #icon>
|
||||||
|
<div class="i-tabler-progress-check text-7xl text-neutral-400"></div>
|
||||||
|
</template>
|
||||||
|
</StatusBlock>
|
||||||
|
<div class="mt-4 px-4 space-y-2">
|
||||||
|
<wd-button type="primary" :round="false" block>通过</wd-button>
|
||||||
|
<wd-button type="error" :round="false" block>驳回</wd-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-if="selectedLessonStage?.step === 2"></div>
|
<div v-if="selectedLessonStage?.step === 2"></div>
|
||||||
<div v-if="selectedLessonStage?.step === 3"></div>
|
<div v-if="selectedLessonStage?.step === 3"></div>
|
||||||
<div v-else-if="selectedLessonStage?.step === 4">
|
<div v-else-if="selectedLessonStage?.step === 4">
|
||||||
|
BIN
src/static/TablerProgressBolt.png
Normal file
BIN
src/static/TablerProgressBolt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
@ -8,12 +8,17 @@ export interface Lesson {
|
|||||||
script_confirm_time: number;
|
script_confirm_time: number;
|
||||||
video_capture_time: number;
|
video_capture_time: number;
|
||||||
video_confirm_time: number;
|
video_confirm_time: number;
|
||||||
script_file: ScriptFileDestination;
|
script_file: string;
|
||||||
|
capture_file: string;
|
||||||
|
material_file: string;
|
||||||
finish_time: number;
|
finish_time: number;
|
||||||
material_file: null;
|
|
||||||
capture_file: null;
|
|
||||||
advise: null;
|
advise: null;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ScriptFileDestination = "qq" | "wechat" | "platform";
|
// export interface CombinedFileString {
|
||||||
|
// method?: ScriptFileDestination;
|
||||||
|
// reupload?: string;
|
||||||
|
// }
|
||||||
|
|
||||||
|
export type FileUploadDestination = "qq" | "wechat" | "platform";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useDayjs } from "@/composables/useDayjs";
|
import { useDayjs } from "@/composables/useDayjs";
|
||||||
import type { Lesson } from "@/types/api/lesson";
|
import type { FileUploadDestination, Lesson } from "@/types/api/lesson";
|
||||||
|
|
||||||
export const extractLessonStage = (lesson: Lesson) => {
|
export const extractLessonStage = (lesson: Lesson) => {
|
||||||
const stages = {
|
const stages = {
|
||||||
@ -26,26 +26,66 @@ export const getLessonSteps = (lesson: Lesson, simplify: boolean = false) => {
|
|||||||
{
|
{
|
||||||
title: progress.script_upload ? "脚本提交" : undefined,
|
title: progress.script_upload ? "脚本提交" : undefined,
|
||||||
description: progress.script_upload
|
description: progress.script_upload
|
||||||
? (simplify ? '已完成' : `已于 ${dayjs(lesson.script_upload_time * 1000).format(dateFormat)} 完成上传`)
|
? simplify
|
||||||
|
? "已完成"
|
||||||
|
: `已于 ${dayjs(lesson.script_upload_time * 1000).format(
|
||||||
|
dateFormat
|
||||||
|
)} 完成上传`
|
||||||
: "脚本文件提交",
|
: "脚本文件提交",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: progress.script_confirm ? "脚本确认" : undefined,
|
title: progress.script_confirm ? "脚本确认" : undefined,
|
||||||
description: progress.script_confirm
|
description: progress.script_confirm
|
||||||
? (simplify ? '已完成' : `已于 ${dayjs(lesson.script_confirm_time * 1000).format(dateFormat)} 确认`)
|
? simplify
|
||||||
|
? "已完成"
|
||||||
|
: `已于 ${dayjs(lesson.script_confirm_time * 1000).format(
|
||||||
|
dateFormat
|
||||||
|
)} 确认`
|
||||||
: "脚本文件确认",
|
: "脚本文件确认",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: progress.video_capture ? "视频拍摄" : undefined,
|
title: progress.video_capture ? "视频拍摄" : undefined,
|
||||||
description: progress.video_capture
|
description: progress.video_capture
|
||||||
? (simplify ? '已完成' : `已于 ${dayjs(lesson.video_capture_time * 1000).format(dateFormat)} 完成上传`)
|
? simplify
|
||||||
|
? "已完成"
|
||||||
|
: `已于 ${dayjs(lesson.video_capture_time * 1000).format(
|
||||||
|
dateFormat
|
||||||
|
)} 完成上传`
|
||||||
: "视频拍摄提交",
|
: "视频拍摄提交",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: progress.post_production ? "后期制作" : undefined,
|
title: progress.post_production ? "后期制作" : undefined,
|
||||||
description: progress.post_production
|
description: progress.post_production
|
||||||
? (simplify ? '已完成' : `已于 ${dayjs(lesson.video_confirm_time * 1000).format(dateFormat)} 完成上传`)
|
? simplify
|
||||||
|
? "已完成"
|
||||||
|
: `已于 ${dayjs(lesson.video_confirm_time * 1000).format(
|
||||||
|
dateFormat
|
||||||
|
)} 完成上传`
|
||||||
: "视频后期制作",
|
: "视频后期制作",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getScriptFile = (lesson: Lesson) => {
|
||||||
|
const scriptFile = lesson.script_file ? lesson.script_file.split("|") : [];
|
||||||
|
return {
|
||||||
|
way: scriptFile[0] || null,
|
||||||
|
reupload: scriptFile[1] || null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parseCombinedFileString = (
|
||||||
|
lesson: Lesson,
|
||||||
|
key: keyof Pick<Lesson, "script_file" | "capture_file" | "material_file">
|
||||||
|
): {
|
||||||
|
method: FileUploadDestination;
|
||||||
|
uploaded: Boolean;
|
||||||
|
} => {
|
||||||
|
const combined = lesson[key]
|
||||||
|
? JSON.parse(lesson[key])
|
||||||
|
: {
|
||||||
|
method: null,
|
||||||
|
uploaded: false,
|
||||||
|
};
|
||||||
|
return combined;
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user