<script lang="ts" setup>
|
import type { ActionItem, BasicColumn } from '@jnpf/ui/vxeTable';
|
|
import type { PaperEntity } from './types';
|
|
import { computed, onMounted, ref } from 'vue';
|
import { useRouter } from 'vue-router';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicVxeTable, TableAction, useVxeTable } from '@jnpf/ui/vxeTable';
|
|
import { getPaperList, invalidatePaper, setPaperStatus } from '#/api/x/tms/paper';
|
import { TMS_DIC_FIELD_NAMES } from '#/views/x/tms/shared/dic';
|
|
import { STATUS_OPTIONS, labelOfSortMode, labelOfStatus, loadPaperDics } from './constants';
|
|
defineOptions({ name: 'TmsPaperList' });
|
|
const router = useRouter();
|
const { createMessage } = useMessage();
|
const invalidMode = ref(false);
|
|
const activeStatusOptions = computed(() =>
|
STATUS_OPTIONS.value.filter((x) => (x.enCode || x.id) !== 'invalid'),
|
);
|
|
const columns: BasicColumn[] = [
|
{ title: '试卷编号', dataIndex: 'paperNo', width: 120 },
|
{ title: '试卷名称', dataIndex: 'paperName', minWidth: 200 },
|
{
|
title: '状态',
|
dataIndex: 'bizStatus',
|
width: 100,
|
align: 'center',
|
slots: { default: 'bizStatus' },
|
},
|
{
|
title: '时长(分钟)',
|
dataIndex: 'durationMin',
|
width: 100,
|
align: 'center',
|
},
|
{
|
title: '总分',
|
dataIndex: 'totalScore',
|
width: 90,
|
align: 'center',
|
},
|
{
|
title: '合格分',
|
dataIndex: 'passScore',
|
width: 90,
|
align: 'center',
|
},
|
{
|
title: '题量',
|
dataIndex: 'questionCount',
|
width: 80,
|
align: 'center',
|
},
|
{
|
title: '试题排序',
|
dataIndex: 'sortMode',
|
width: 110,
|
customRender: ({ record }) => labelOfSortMode((record as PaperEntity).sortMode),
|
},
|
{ title: '创建时间', dataIndex: 'creatorTime', width: 170 },
|
];
|
|
const [registerTable, { reload, getForm }] = useVxeTable({
|
api: fetchList,
|
columns,
|
immediate: false,
|
rowKey: 'id',
|
useSearchForm: true,
|
formConfig: {
|
baseColProps: { span: 6 },
|
compact: true,
|
schemas: [
|
{
|
field: 'keyword',
|
label: '关键词',
|
component: 'Input',
|
componentProps: { placeholder: '编号/名称', submitOnPressEnter: true },
|
},
|
{
|
field: 'bizStatus',
|
label: '状态',
|
component: 'Select',
|
componentProps: {
|
allowClear: true,
|
placeholder: '请选择',
|
options: STATUS_OPTIONS.value,
|
fieldNames: TMS_DIC_FIELD_NAMES,
|
},
|
},
|
],
|
},
|
actionColumn: {
|
width: 180,
|
title: '操作',
|
dataIndex: 'action',
|
fixed: 'right',
|
},
|
});
|
|
onMounted(async () => {
|
await loadPaperDics();
|
getForm()?.updateSchema?.([
|
{
|
field: 'bizStatus',
|
componentProps: {
|
allowClear: true,
|
placeholder: '请选择',
|
options: activeStatusOptions.value,
|
fieldNames: TMS_DIC_FIELD_NAMES,
|
},
|
},
|
]);
|
reload();
|
});
|
|
async function fetchList(params: Record<string, any>) {
|
const query = { ...params };
|
if (invalidMode.value) {
|
query.bizStatus = 'invalid';
|
}
|
const page = await getPaperList(query);
|
return {
|
data: {
|
list: Array.isArray(page?.list) ? page.list : [],
|
pagination: page?.pagination || { total: 0 },
|
},
|
};
|
}
|
|
function openInvalidList() {
|
invalidMode.value = true;
|
getForm()?.setFieldsValue?.({ bizStatus: undefined });
|
getForm()?.updateSchema?.([{ field: 'bizStatus', ifShow: false }]);
|
reload();
|
}
|
|
function backToNormal() {
|
invalidMode.value = false;
|
getForm()?.updateSchema?.([{ field: 'bizStatus', ifShow: true }]);
|
reload();
|
}
|
|
function statusColor(status?: string) {
|
if (status === 'open') return '#52c41a';
|
if (status === 'closed') return '#ff4d4f';
|
if (status === 'invalid') return '#999';
|
return undefined;
|
}
|
|
function handleCreate() {
|
router.push('/tms/paper/create');
|
}
|
|
function handleEdit(record: PaperEntity) {
|
if (record.bizStatus === 'open') {
|
createMessage.warning('请先停用后再编辑');
|
return;
|
}
|
if (record.bizStatus === 'invalid') {
|
createMessage.warning('已废弃试卷不可编辑');
|
return;
|
}
|
router.push(`/tms/paper/edit/${record.id}`);
|
}
|
|
function handleDetail(record: PaperEntity) {
|
router.push(`/tms/paper/detail/${record.id}`);
|
}
|
|
async function handleInvalidate(record: PaperEntity) {
|
await invalidatePaper(record.id!);
|
createMessage.success('废弃成功');
|
reload();
|
}
|
|
async function handleEnable(record: PaperEntity) {
|
await setPaperStatus(record.id!, 'open');
|
createMessage.success('已启用');
|
reload();
|
}
|
|
async function handleDisable(record: PaperEntity) {
|
await setPaperStatus(record.id!, 'closed');
|
createMessage.success('已停用');
|
reload();
|
}
|
|
function getTableActions(record: PaperEntity): ActionItem[] {
|
if (record.bizStatus === 'open') {
|
return [
|
{
|
label: '停用',
|
modelConfirm: {
|
content: `确定停用试卷「${record.paperName}」吗?停用后不可用于培训任务在线考试。`,
|
onOk: handleDisable.bind(null, record),
|
},
|
},
|
{ label: '详情', onClick: handleDetail.bind(null, record) },
|
];
|
}
|
if (record.bizStatus === 'closed') {
|
return [
|
{
|
label: '启用',
|
modelConfirm: {
|
content: `确定启用试卷「${record.paperName}」吗?启用后可用于培训任务在线考试。`,
|
onOk: handleEnable.bind(null, record),
|
},
|
},
|
{ label: '编辑', onClick: handleEdit.bind(null, record) },
|
{
|
label: '废弃',
|
color: 'error',
|
modelConfirm: {
|
content: `确定废弃试卷「${record.paperName}」吗?废弃后不可再启用,且不可用于培训任务在线考试。`,
|
onOk: handleInvalidate.bind(null, record),
|
},
|
},
|
];
|
}
|
return [{ label: '详情', onClick: handleDetail.bind(null, record) }];
|
}
|
</script>
|
|
<template>
|
<div class="jnpf-content-wrapper">
|
<div class="jnpf-content-wrapper-center">
|
<div class="jnpf-content-wrapper-content">
|
<BasicVxeTable @register="registerTable">
|
<template #tableTitle>
|
<a-space>
|
<template v-if="!invalidMode">
|
<a-button type="primary" pre-icon="icon-ym icon-ym-btn-add" @click="handleCreate">新增</a-button>
|
<a-button @click="openInvalidList">废弃列表</a-button>
|
</template>
|
<a-button v-else @click="backToNormal">返回</a-button>
|
</a-space>
|
</template>
|
<template #bizStatus="{ record }">
|
<span :style="{ color: statusColor(record.bizStatus) }">{{ labelOfStatus(record.bizStatus) }}</span>
|
</template>
|
<template #action="{ record }">
|
<TableAction :actions="getTableActions(record)" />
|
</template>
|
</BasicVxeTable>
|
</div>
|
</div>
|
</div>
|
</template>
|