<script lang="ts" setup>
|
import type { ActionItem, BasicColumn } from '@jnpf/ui/vxeTable';
|
|
import type { TaskEntity } from './types';
|
|
import { onMounted } from 'vue';
|
import { useRouter } from 'vue-router';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicVxeTable, TableAction, useVxeTable } from '@jnpf/ui/vxeTable';
|
|
import { Modal } from 'ant-design-vue';
|
|
import { launchFlow } from '#/api/onlineDev/visualDev';
|
import {
|
cancelTask,
|
cancelTaskBatch,
|
deleteTask,
|
getTaskInfo,
|
getTaskList,
|
publishTask,
|
restoreTask,
|
} from '#/api/x/tms/task';
|
import { TMS_DIC_FIELD_NAMES } from '#/views/x/tms/shared/dic';
|
import { TMS_BTN } from '#/views/x/tms/shared/ui';
|
|
import {
|
PUBLISH_STATUS_OPTIONS,
|
SOURCE_TYPE_OPTIONS,
|
TRAIN_MODE_OPTIONS,
|
labelOfEvalMode,
|
labelOfPublishStatus,
|
labelOfSourceType,
|
labelOfTrainMode,
|
loadTaskDics,
|
publishStatusColor,
|
} from './constants';
|
import { TMS_TASK_SUBMIT_FLOW, buildTaskSubmitLaunchDataList, isTaskInApproval } from './flow';
|
|
defineOptions({ name: 'TmsTaskList' });
|
|
const router = useRouter();
|
const { createMessage } = useMessage();
|
|
const columns: BasicColumn[] = [
|
{ title: '培训编号', dataIndex: 'taskNo', width: 140 },
|
{ title: '培训主题', dataIndex: 'subject', minWidth: 200 },
|
{
|
title: '来源类型',
|
dataIndex: 'sourceType',
|
width: 110,
|
customRender: ({ record }) => labelOfSourceType((record as TaskEntity).sourceType),
|
},
|
{
|
title: '培训方式',
|
dataIndex: 'trainMode',
|
width: 110,
|
customRender: ({ record }) => labelOfTrainMode((record as TaskEntity).trainMode),
|
},
|
{
|
title: '考核方式',
|
dataIndex: 'evalMode',
|
width: 100,
|
customRender: ({ record }) => labelOfEvalMode((record as TaskEntity).evalMode),
|
},
|
{ title: '开始时间', dataIndex: 'startTime', width: 170 },
|
{ title: '结束时间', dataIndex: 'endTime', width: 170 },
|
{ title: '地点', dataIndex: 'placeName', width: 140 },
|
{
|
title: '状态',
|
dataIndex: 'publishStatus',
|
width: 100,
|
align: 'center',
|
slots: { default: 'publishStatus' },
|
},
|
{ title: '创建时间', dataIndex: 'creatorTime', width: 170 },
|
];
|
|
const [registerTable, { reload, getForm, getSelectRows }] = 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: 'publishStatus',
|
label: '状态',
|
component: 'Select',
|
componentProps: {
|
allowClear: true,
|
placeholder: '请选择',
|
options: PUBLISH_STATUS_OPTIONS.value,
|
fieldNames: TMS_DIC_FIELD_NAMES,
|
},
|
},
|
{
|
field: 'trainMode',
|
label: '培训方式',
|
component: 'Select',
|
componentProps: {
|
allowClear: true,
|
placeholder: '请选择',
|
options: TRAIN_MODE_OPTIONS.value,
|
fieldNames: TMS_DIC_FIELD_NAMES,
|
},
|
},
|
{
|
field: 'sourceType',
|
label: '来源类型',
|
component: 'Select',
|
componentProps: {
|
allowClear: true,
|
placeholder: '请选择',
|
options: SOURCE_TYPE_OPTIONS.value,
|
fieldNames: TMS_DIC_FIELD_NAMES,
|
},
|
},
|
{
|
field: 'startTimeRange',
|
label: '开始时间',
|
component: 'DateRange',
|
componentProps: {
|
format: 'YYYY-MM-DD',
|
placeholder: ['开始', '结束'],
|
},
|
},
|
],
|
},
|
rowSelection: { type: 'checkbox' },
|
actionColumn: {
|
width: 380,
|
title: '操作',
|
dataIndex: 'action',
|
fixed: 'right',
|
},
|
});
|
|
onMounted(async () => {
|
await loadTaskDics();
|
getForm()?.updateSchema?.([
|
{
|
field: 'publishStatus',
|
componentProps: {
|
allowClear: true,
|
placeholder: '请选择',
|
options: PUBLISH_STATUS_OPTIONS.value,
|
fieldNames: TMS_DIC_FIELD_NAMES,
|
},
|
},
|
{
|
field: 'trainMode',
|
componentProps: {
|
allowClear: true,
|
placeholder: '请选择',
|
options: TRAIN_MODE_OPTIONS.value,
|
fieldNames: TMS_DIC_FIELD_NAMES,
|
},
|
},
|
{
|
field: 'sourceType',
|
componentProps: {
|
allowClear: true,
|
placeholder: '请选择',
|
options: SOURCE_TYPE_OPTIONS.value,
|
fieldNames: TMS_DIC_FIELD_NAMES,
|
},
|
},
|
]);
|
reload();
|
});
|
|
async function fetchList(params: Record<string, any>) {
|
const query = { ...params };
|
const range = query.startTimeRange;
|
if (Array.isArray(range) && range.length === 2) {
|
query.startTimeFrom = range[0];
|
query.startTimeTo = range[1];
|
}
|
delete query.startTimeRange;
|
const page = await getTaskList(query);
|
return {
|
data: {
|
list: Array.isArray(page?.list) ? page.list : [],
|
pagination: page?.pagination || { total: 0 },
|
},
|
};
|
}
|
|
function handleCreate() {
|
router.push('/tms/task/create');
|
}
|
|
function handleEdit(record: TaskEntity) {
|
if (record.publishStatus !== 'draft') {
|
createMessage.warning('仅未发布任务可维护');
|
return;
|
}
|
if (isTaskInApproval(record)) {
|
createMessage.warning('审批中的任务不可维护');
|
return;
|
}
|
router.push(`/tms/task/edit/${record.id}`);
|
}
|
|
function handleDetail(record: TaskEntity) {
|
router.push(`/tms/task/detail/${record.id}`);
|
}
|
|
/** 提问预设:草稿进编辑维护,已发布进详情查看 */
|
function handleQuizPreset(record: TaskEntity) {
|
if (record.evalMode !== 'quiz') {
|
createMessage.warning('仅考核方式为提问的任务可维护提问预设');
|
return;
|
}
|
if (record.publishStatus === 'draft' && !isTaskInApproval(record)) {
|
router.push(`/tms/task/edit/${record.id}`);
|
return;
|
}
|
router.push(`/tms/task/detail/${record.id}`);
|
}
|
|
async function handlePublish(record: TaskEntity) {
|
await publishTask(record.id!);
|
createMessage.success('发布成功');
|
reload();
|
}
|
|
async function handleSubmitForReview(record: TaskEntity) {
|
let task = record;
|
if (!task.teacherId || !task.subject) {
|
task = await getTaskInfo(record.id!);
|
}
|
if (!task?.id) {
|
createMessage.warning('任务不存在');
|
return;
|
}
|
if (task.publishStatus !== 'draft') {
|
createMessage.warning('仅未发布任务可送审');
|
return;
|
}
|
if (isTaskInApproval(task)) {
|
createMessage.warning('该任务已在审批中');
|
return;
|
}
|
if (!task.teacherId) {
|
createMessage.warning('请先维护培训师后再送审');
|
return;
|
}
|
await launchFlow(TMS_TASK_SUBMIT_FLOW.modelId, {
|
template: TMS_TASK_SUBMIT_FLOW.templateId,
|
currentUser: 1,
|
customUser: 0,
|
hasPermission: 0,
|
dataList: buildTaskSubmitLaunchDataList(task),
|
});
|
createMessage.success('已送审,请培训师在待办中审批');
|
reload();
|
}
|
|
async function handleCancel(record: TaskEntity) {
|
await cancelTask(record.id!);
|
createMessage.success('已取消');
|
reload();
|
}
|
|
async function handleRestore(record: TaskEntity) {
|
await restoreTask(record.id!);
|
createMessage.success('已恢复为草稿');
|
reload();
|
}
|
|
async function handleDelete(record: TaskEntity) {
|
await deleteTask(record.id!);
|
createMessage.success('删除成功');
|
reload();
|
}
|
|
async function handleBatchCancel() {
|
const rows = (getSelectRows?.() || []) as TaskEntity[];
|
const ids = rows.filter((r) => r.publishStatus === 'published').map((r) => r.id!).filter(Boolean);
|
if (!ids.length) {
|
createMessage.warning('请勾选已发布的任务');
|
return;
|
}
|
Modal.confirm({
|
title: '批量取消',
|
content: `确定取消选中的 ${ids.length} 个已发布任务?已有签到人员的任务将失败。`,
|
onOk: async () => {
|
await cancelTaskBatch(ids);
|
createMessage.success('批量取消成功');
|
reload();
|
},
|
});
|
}
|
|
function getTableActions(record: TaskEntity): ActionItem[] {
|
const actions: ActionItem[] = [{ label: TMS_BTN.detail, onClick: handleDetail.bind(null, record) }];
|
if (record.evalMode === 'quiz') {
|
actions.push({ label: TMS_BTN.quizPreset, onClick: handleQuizPreset.bind(null, record) });
|
}
|
if (record.publishStatus === 'draft') {
|
const approving = isTaskInApproval(record);
|
if (!approving) {
|
actions.unshift(
|
{
|
label: TMS_BTN.submitForReview,
|
modelConfirm: {
|
content: `确定将「${record.subject}」送培训师审批?通过后将自动发布。`,
|
onOk: handleSubmitForReview.bind(null, record),
|
},
|
},
|
{
|
label: TMS_BTN.publish,
|
modelConfirm: {
|
content: `确定直接发布「${record.subject}」?将生成个人任务与培训记录。`,
|
onOk: handlePublish.bind(null, record),
|
},
|
},
|
{
|
label: TMS_BTN.maintain,
|
onClick: handleEdit.bind(null, record),
|
},
|
{
|
label: TMS_BTN.delete,
|
color: 'error',
|
modelConfirm: {
|
content: `确定删除「${record.subject}」吗?`,
|
onOk: handleDelete.bind(null, record),
|
},
|
},
|
);
|
}
|
} else if (record.publishStatus === 'published') {
|
actions.unshift({
|
label: TMS_BTN.cancel,
|
color: 'error',
|
modelConfirm: {
|
content: `确定取消「${record.subject}」?已有签到人员时不可取消。`,
|
onOk: handleCancel.bind(null, record),
|
},
|
});
|
} else if (record.publishStatus === 'cancelled') {
|
actions.unshift({
|
label: TMS_BTN.restore,
|
modelConfirm: {
|
content: `确定将「${record.subject}」恢复为草稿?将清除已生成的个人任务与培训记录,需重新编辑后发布。`,
|
onOk: handleRestore.bind(null, record),
|
},
|
});
|
}
|
return actions;
|
}
|
</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>
|
<a-button type="primary" pre-icon="icon-ym icon-ym-btn-add" @click="handleCreate">
|
{{ TMS_BTN.add }}临时培训
|
</a-button>
|
<a-button danger @click="handleBatchCancel">批量{{ TMS_BTN.cancel }}</a-button>
|
</a-space>
|
</template>
|
<template #publishStatus="{ record }">
|
<a-tag :color="publishStatusColor(record.publishStatus)">
|
{{ labelOfPublishStatus(record.publishStatus) }}
|
</a-tag>
|
<a-tag v-if="isTaskInApproval(record)" color="orange" class="!ml-1">审批中</a-tag>
|
</template>
|
<template #action="{ record }">
|
<TableAction :actions="getTableActions(record)" />
|
</template>
|
</BasicVxeTable>
|
</div>
|
</div>
|
</div>
|
</template>
|