<script lang="ts" setup>
|
import type { TmsRecordDetail, TmsRecordParticipant } from './types';
|
|
import { onMounted, ref } from 'vue';
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { useMessage } from '@jnpf/hooks';
|
import {
|
Descriptions as ADescriptions,
|
DescriptionsItem as ADescriptionsItem,
|
Table as ATable,
|
} from 'ant-design-vue';
|
|
import { getTmsRecordDetail } from '#/api/x/tms/record';
|
|
defineOptions({ name: 'TmsRecordDetail' });
|
|
const route = useRoute();
|
const router = useRouter();
|
const { createMessage } = useMessage();
|
|
const loading = ref(false);
|
const detail = ref<TmsRecordDetail | null>(null);
|
|
const participantColumns = [
|
{ title: '姓名', dataIndex: 'userName', key: 'userName', width: 140, align: 'center' },
|
{ title: '部门', dataIndex: 'deptName', key: 'deptName', width: 200, align: 'center' },
|
{ title: '签到日期', dataIndex: 'signDate', key: 'signDate', width: 180, align: 'center' },
|
{ title: '考试成绩', dataIndex: 'examScore', key: 'examScore', width: 120, align: 'center' },
|
{
|
title: '是否合格',
|
dataIndex: 'passFlag',
|
key: 'passFlag',
|
width: 120,
|
align: 'center',
|
customRender: ({ record }: { record: TmsRecordParticipant }) => passText(record),
|
},
|
];
|
|
onMounted(() => {
|
loadData();
|
});
|
|
async function loadData() {
|
const id = String(route.params.id || '');
|
if (!id) {
|
router.replace('/tms/record');
|
return;
|
}
|
loading.value = true;
|
try {
|
detail.value = await getTmsRecordDetail(id);
|
} catch (e: any) {
|
createMessage.error(e?.message || '加载培训记录失败');
|
router.replace('/tms/record');
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
function goBack() {
|
const from = String(route.query.from || '');
|
if (from === 'archived') {
|
router.push('/tms/record/archived');
|
return;
|
}
|
if (from === 'ready') {
|
router.push('/tms/record/ready');
|
return;
|
}
|
if (from === 'main') {
|
router.push('/tms/record');
|
return;
|
}
|
router.back();
|
}
|
|
function passText(row: TmsRecordParticipant) {
|
if (row.passFlag === '1') return '合格';
|
if (row.passFlag === '0') return '不合格';
|
return '';
|
}
|
|
function openAttachment(url?: string) {
|
if (!url || url === '#') {
|
createMessage.info('附件预览联调后生效');
|
return;
|
}
|
window.open(url, '_blank');
|
}
|
</script>
|
|
<template>
|
<div class="jnpf-content-wrapper tms-record-detail-page">
|
<div class="jnpf-content-wrapper-center tms-record-detail-center">
|
<div class="jnpf-content-wrapper-content tms-record-detail-wrap">
|
<a-spin :spinning="loading" class="detail-spin">
|
<div v-if="detail" class="detail-inner">
|
<div class="detail-header">
|
<div class="text-base font-medium">培训记录</div>
|
<a-button type="primary" @click="goBack">返回</a-button>
|
</div>
|
|
<ADescriptions bordered :column="2" size="middle" class="detail-desc">
|
<ADescriptionsItem label="培训编号">{{ detail.recordNo }}</ADescriptionsItem>
|
<ADescriptionsItem label="任务关闭时间">{{ detail.closeTime || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训主题" :span="2">
|
<div class="pre-line">{{ detail.subject }}</div>
|
</ADescriptionsItem>
|
<ADescriptionsItem label="培训要点" :span="2">
|
<div class="pre-line">{{ detail.keyPoints || '-' }}</div>
|
</ADescriptionsItem>
|
<ADescriptionsItem label="培训开始时间">{{ detail.startTime }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训结束时间">{{ detail.endTime || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训地点" :span="2">{{ detail.placeName || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训分类">{{ detail.category }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训方式">{{ detail.trainMode || detail.trainType || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训师">{{ detail.trainerName }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训考核方式">{{ detail.evalMode }}</ADescriptionsItem>
|
<ADescriptionsItem label="培训对象" :span="2">{{ detail.trainees || '-' }}</ADescriptionsItem>
|
<ADescriptionsItem label="附件" :span="2">
|
<div v-if="detail.attachments?.length" class="attach-list">
|
<div v-for="file in detail.attachments" :key="file.id" class="attach-item">
|
<span>{{ file.name }}</span>
|
<a class="attach-link" @click.prevent="openAttachment(file.url)">原文</a>
|
</div>
|
</div>
|
<span v-else>-</span>
|
</ADescriptionsItem>
|
<ADescriptionsItem label="备注" :span="2">{{ detail.remark || '-' }}</ADescriptionsItem>
|
</ADescriptions>
|
|
<div class="section-title">参加人员名单如下</div>
|
<div class="participant-table">
|
<ATable
|
size="middle"
|
bordered
|
row-key="id"
|
table-layout="fixed"
|
:columns="participantColumns"
|
:data-source="detail.participants || []"
|
:pagination="false"
|
:scroll="{ x: 760 }"
|
:locale="{ emptyText: '暂无参加人员' }"
|
/>
|
</div> </div>
|
</a-spin>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<style scoped>
|
/* 全局 jnpf-content-wrapper* 为 overflow:hidden 且无 min-height:0,整条高度链补齐才能滚 */
|
.tms-record-detail-page {
|
height: 100%;
|
min-height: 0;
|
}
|
|
.tms-record-detail-center {
|
height: 100% !important;
|
min-height: 0 !important;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.tms-record-detail-wrap {
|
display: flex !important;
|
flex-direction: column;
|
flex: 1 1 0 !important;
|
min-height: 0 !important;
|
height: 100%;
|
overflow: auto !important;
|
background: #fff;
|
padding: 0;
|
}
|
|
.detail-spin {
|
display: block;
|
min-height: 100%;
|
width: 100%;
|
}
|
|
.detail-spin :deep(.ant-spin-container) {
|
min-height: 100%;
|
width: 100%;
|
}
|
|
.detail-inner {
|
padding: 16px 20px 24px;
|
box-sizing: border-box;
|
}
|
|
.detail-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 16px;
|
padding-bottom: 12px;
|
border-bottom: 1px solid #f0f0f0;
|
}
|
|
.detail-desc {
|
margin-bottom: 16px;
|
}
|
|
.pre-line {
|
white-space: pre-wrap;
|
line-height: 1.5;
|
}
|
|
.attach-list {
|
display: flex;
|
flex-direction: column;
|
gap: 6px;
|
}
|
|
.attach-item {
|
display: flex;
|
align-items: flex-start;
|
gap: 12px;
|
}
|
|
.attach-link {
|
flex-shrink: 0;
|
color: var(--primary-color, #1677ff);
|
cursor: pointer;
|
}
|
|
.attach-link:hover {
|
text-decoration: underline;
|
}
|
|
.section-title {
|
margin: 8px 0 12px;
|
font-size: 15px;
|
font-weight: 600;
|
}
|
|
.participant-table :deep(.ant-table-table) {
|
table-layout: fixed !important;
|
}
|
|
.participant-table :deep(.ant-table-thead > tr > th),
|
.participant-table :deep(.ant-table-tbody > tr > td) {
|
text-align: center;
|
}
|
|
.participant-table :deep(.ant-table-placeholder .ant-table-cell) {
|
text-align: center;
|
}
|
</style>
|