<script lang="ts" setup>
|
import type { TmsRecordDetail } from './types';
|
|
import { onMounted, reactive, ref } from 'vue';
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { Table as ATable } from 'ant-design-vue';
|
import dayjs from 'dayjs';
|
|
import { getTmsRecordDetail } from '#/api/x/tms/record';
|
|
defineOptions({ name: 'TmsRecordSign' });
|
|
const route = useRoute();
|
const router = useRouter();
|
const { createMessage } = useMessage();
|
|
const loading = ref(false);
|
const submitting = ref(false);
|
const detail = ref<TmsRecordDetail | null>(null);
|
|
const form = reactive({
|
userName: '',
|
deptName: '',
|
signMode: '在线签到',
|
});
|
|
const signColumns = [
|
{ title: '序号', key: 'index', width: 70, align: 'center', customRender: ({ index }: any) => index + 1 },
|
{ title: '姓名', dataIndex: 'userName', key: 'userName', width: 120 },
|
{ title: '部门', dataIndex: 'deptName', key: 'deptName', minWidth: 140 },
|
{ title: '签到时间', dataIndex: 'signTime', key: 'signTime', width: 180 },
|
{ title: '签到方式', dataIndex: 'signMode', key: 'signMode', width: 120 },
|
];
|
|
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);
|
if (detail.value.archiveStatus === 'archived') {
|
createMessage.warning('已存档记录不可签到');
|
router.replace(`/tms/record/detail/${id}`);
|
}
|
} catch (e: any) {
|
createMessage.error(e?.message || '加载培训记录失败');
|
router.replace('/tms/record');
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
function handleSubmit() {
|
if (!form.userName.trim()) {
|
createMessage.warning('请输入签到人姓名');
|
return;
|
}
|
if (!detail.value) return;
|
submitting.value = true;
|
try {
|
detail.value.signList = [
|
{
|
id: `s-${Date.now()}`,
|
userName: form.userName.trim(),
|
deptName: form.deptName.trim() || undefined,
|
signTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
signMode: form.signMode,
|
},
|
...(detail.value.signList || []),
|
];
|
form.userName = '';
|
form.deptName = '';
|
createMessage.success('签到成功(本地 mock,联调后写入服务端)');
|
} finally {
|
submitting.value = false;
|
}
|
}
|
|
function goBack() {
|
router.push('/tms/record');
|
}
|
</script>
|
|
<template>
|
<div class="jnpf-content-wrapper tms-record-page">
|
<div class="jnpf-content-wrapper-center tms-record-center">
|
<div class="jnpf-content-wrapper-content tms-record-wrap">
|
<a-spin :spinning="loading" class="record-spin">
|
<div v-if="detail" class="record-inner">
|
<div class="record-header">
|
<div>
|
<div class="text-base font-medium">培训签到</div>
|
<div class="mt-1 text-gray-400 text-sm">
|
{{ detail.recordNo }} · {{ detail.subject }}
|
</div>
|
</div>
|
<a-button @click="goBack">返回</a-button>
|
</div>
|
|
<a-form layout="inline" class="sign-form mb-4">
|
<a-form-item label="姓名">
|
<a-input v-model:value="form.userName" placeholder="签到人姓名" class="!w-[140px]" allow-clear />
|
</a-form-item>
|
<a-form-item label="部门">
|
<a-input v-model:value="form.deptName" placeholder="部门(可选)" class="!w-[160px]" allow-clear />
|
</a-form-item>
|
<a-form-item label="方式">
|
<a-select
|
v-model:value="form.signMode"
|
class="!w-[130px]"
|
:options="[
|
{ label: '在线签到', value: '在线签到' },
|
{ label: 'APP扫码', value: 'APP扫码' },
|
{ label: '微信扫码', value: '微信扫码' },
|
]"
|
/>
|
</a-form-item>
|
<a-form-item>
|
<a-button type="primary" :loading="submitting" @click="handleSubmit">确认签到</a-button>
|
</a-form-item>
|
</a-form>
|
|
<div class="section-title">已签到人员</div>
|
<ATable
|
size="middle"
|
bordered
|
row-key="id"
|
:columns="signColumns"
|
:data-source="detail.signList || []"
|
:pagination="false"
|
:locale="{ emptyText: '暂无签到记录' }"
|
/>
|
</div>
|
</a-spin>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<style scoped>
|
.tms-record-page,
|
.tms-record-center {
|
height: 100%;
|
min-height: 0;
|
}
|
|
.tms-record-wrap {
|
display: flex !important;
|
flex-direction: column;
|
flex: 1 1 0 !important;
|
min-height: 0 !important;
|
height: 100%;
|
overflow: auto !important;
|
background: #fff;
|
}
|
|
.record-spin {
|
display: block;
|
min-height: 100%;
|
width: 100%;
|
}
|
|
.record-inner {
|
padding: 16px 20px 24px;
|
}
|
|
.record-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 16px;
|
}
|
|
.section-title {
|
font-size: 15px;
|
font-weight: 600;
|
margin: 8px 0 12px;
|
padding-left: 10px;
|
border-left: 3px solid #1677ff;
|
}
|
|
.sign-form {
|
padding: 12px;
|
background: #fafafa;
|
border-radius: 6px;
|
}
|
</style>
|