<script lang="ts" setup>
|
import type { PersonTaskItem } from './types';
|
|
import { computed, onMounted, ref } from 'vue';
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { Descriptions as ADescriptions, DescriptionsItem as ADescriptionsItem } from 'ant-design-vue';
|
|
import { getPersonTaskInfo, signPersonTask } from '#/api/x/tms/personTask';
|
import { TMS_BTN } from '#/views/x/tms/shared/ui';
|
|
import {
|
labelOfCategory,
|
labelOfEvalMode,
|
labelOfPersonStatus,
|
labelOfTrainMode,
|
loadPersonTaskDics,
|
} from './constants';
|
|
import '#/views/x/tms/shared/page.css';
|
|
defineOptions({ name: 'TmsPersonTaskDetail' });
|
|
const route = useRoute();
|
const router = useRouter();
|
const { createMessage } = useMessage();
|
|
const loading = ref(false);
|
const signing = ref(false);
|
const detail = ref<PersonTaskItem | null>(null);
|
|
const progressText = computed(() => {
|
const learned = detail.value?.learnedSeconds || 0;
|
const required = detail.value?.requiredSeconds || 0;
|
return `${formatDuration(learned)} / ${required > 0 ? formatDuration(required) : '未配置'}`;
|
});
|
|
const isClosed = computed(() => detail.value?.bizStatus === 'cancelled' || detail.value?.bizStatus === 'expired');
|
const canLearn = computed(() => Boolean(detail.value?.id) && !isClosed.value);
|
const showExam = computed(() => Boolean(detail.value?.canExam && detail.value?.paperId));
|
const tipMessage = computed(() => {
|
if (!detail.value) return '';
|
if (detail.value.bizStatus === 'cancelled') return '任务已取消,无法继续学习或考试。';
|
if (detail.value.bizStatus === 'expired') return '任务已过期,无法继续学习或考试。';
|
if (detail.value.examTip && !detail.value.canExam) return detail.value.examTip;
|
if (detail.value.signTip && detail.value.canSign) return detail.value.signTip;
|
return '';
|
});
|
|
onMounted(async () => {
|
await loadPersonTaskDics();
|
await loadData();
|
});
|
|
async function loadData() {
|
const id = String(route.params.id || '');
|
if (!id) {
|
router.replace('/tms/personTask');
|
return;
|
}
|
loading.value = true;
|
try {
|
detail.value = await getPersonTaskInfo(id);
|
} catch (e: any) {
|
createMessage.error(e?.message || '加载失败');
|
router.replace('/tms/personTask');
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
function goBack() {
|
router.push('/tms/personTask');
|
}
|
|
function goLearn() {
|
if (!detail.value?.id) return;
|
if (isClosed.value) {
|
createMessage.warning(tipMessage.value || '当前任务不可学习');
|
return;
|
}
|
router.push(`/tms/personTask/learn/${detail.value.id}`);
|
}
|
|
function goExam() {
|
if (!detail.value?.id || !showExam.value) {
|
createMessage.info(detail.value?.examTip || '当前暂不可考试');
|
return;
|
}
|
router.push(`/tms/personTask/learn/${detail.value.id}`);
|
}
|
|
async function handleSign() {
|
if (!detail.value?.id || !detail.value.canSign || signing.value) return;
|
signing.value = true;
|
try {
|
const result = await signPersonTask(detail.value.id);
|
detail.value.signTime = result.signTime;
|
detail.value.signed = result.signed ?? true;
|
detail.value.canSign = result.canSign ?? false;
|
detail.value.signTip = result.signTip || '已签到';
|
detail.value.bizStatus = result.bizStatus || detail.value.bizStatus;
|
detail.value.canExam = result.canExam;
|
detail.value.examTip = result.examTip;
|
createMessage.success(result.message || '签到成功');
|
} catch (e: any) {
|
createMessage.error(e?.message || '签到失败');
|
} finally {
|
signing.value = false;
|
}
|
}
|
|
function formatDuration(seconds: number) {
|
const h = Math.floor(seconds / 3600);
|
const m = Math.floor((seconds % 3600) / 60);
|
const s = seconds % 60;
|
if (h > 0) return `${h}小时${m}分`;
|
if (m > 0) return `${m}分${s}秒`;
|
return `${s}秒`;
|
}
|
</script>
|
|
<template>
|
<div class="jnpf-content-wrapper tms-person-task-page" v-loading="loading">
|
<div class="jnpf-content-wrapper-center">
|
<div class="jnpf-content-wrapper-content tms-person-task-wrap" v-if="detail">
|
<div class="tms-page-header">
|
<div>
|
<div class="tms-page-header__title">个人培训任务</div>
|
<div class="tms-page-header__sub">{{ detail.taskNo || '-' }} · {{ detail.subject || '-' }}</div>
|
</div>
|
<div class="tms-page-header__actions">
|
<a-button @click="goBack">{{ TMS_BTN.back }}</a-button>
|
<a-button
|
v-if="detail.canSign"
|
type="primary"
|
:ghost="showExam"
|
:loading="signing"
|
@click="handleSign"
|
>
|
{{ TMS_BTN.sign }}
|
</a-button>
|
<a-button v-if="canLearn" type="primary" ghost @click="goLearn">{{ TMS_BTN.enterLearn }}</a-button>
|
<a-button v-if="showExam" type="primary" @click="goExam">
|
{{ detail.passFlag === '0' ? TMS_BTN.retake : TMS_BTN.enterExam }}
|
</a-button>
|
</div>
|
</div>
|
|
<a-alert v-if="tipMessage" class="tms-page-tip" type="warning" show-icon :message="tipMessage" />
|
|
<ADescriptions bordered :column="2" size="small">
|
<ADescriptionsItem label="培训编号">{{ detail.taskNo || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="状态">{{ labelOfPersonStatus(detail.bizStatus) }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训主题" :span="2">{{ detail.subject || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训分类">{{ labelOfCategory(detail.category) }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训方式">{{ labelOfTrainMode(detail.trainMode) }}</ADescriptionsItem>
|
<ADescriptionsItem label="考核方式">{{ labelOfEvalMode(detail.evalMode) }}</ADescriptionsItem>
|
<ADescriptionsItem label="签到状态">
|
{{
|
detail.signed || detail.signTime
|
? `已签到${detail.signTime ? `(${detail.signTime})` : ''}`
|
: detail.signTip || '未签到'
|
}}
|
</ADescriptionsItem>
|
<ADescriptionsItem label="是否可考">
|
{{ detail.canExam ? '是' : '否' }}
|
<span v-if="!detail.canExam && detail.examTip" class="tip-inline">({{ detail.examTip }})</span>
|
</ADescriptionsItem>
|
<ADescriptionsItem label="学习进度">{{ detail.learnStatus || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="要求课时">{{ detail.requiredHours ?? '-' }} 小时</ADescriptionsItem>
|
<ADescriptionsItem label="已学/需学">{{ progressText }}</ADescriptionsItem>
|
<ADescriptionsItem label="开始时间">{{ detail.startTime || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="结束时间">{{ detail.endTime || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="关闭时间">{{ detail.closeTime || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="地点">{{ detail.placeName || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="试卷">{{ detail.paperName || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="成绩">{{ detail.examScore ?? '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训要点" :span="2">{{ detail.keyPoints || '-' }}</ADescriptionsItem>
|
</ADescriptions>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<style scoped>
|
.tms-person-task-page,
|
.tms-person-task-wrap {
|
height: 100%;
|
min-height: 0;
|
}
|
|
.tms-person-task-wrap {
|
overflow: auto;
|
background: #fff;
|
padding: 16px 20px 24px;
|
box-sizing: border-box;
|
}
|
|
.tip-inline {
|
color: #fa8c16;
|
margin-left: 4px;
|
}
|
</style>
|