<script lang="ts" setup>
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { HrmEmployeeApi } from '#/api/hrm/employee';
|
import type { HrmTrainingApi } from '#/api/hrm/training';
|
|
import { ref } from 'vue';
|
|
import { useVbenModal } from '@vben/common-ui';
|
|
import { message, Modal as AntModal, Tag } from 'ant-design-vue';
|
|
import { useVbenForm } from '#/adapter/form';
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
import {
|
addTrainingParticipants,
|
deleteTrainingParticipants,
|
getTrainingParticipants,
|
updateTrainingParticipant,
|
} from '#/api/hrm/training';
|
import { $t } from '#/locales';
|
|
import { HrmEmployeeSelectDialog } from '#/views/hrm/employee/components';
|
|
defineOptions({ name: 'HrmTrainingParticipants' });
|
|
const emit = defineEmits(['success']);
|
|
const trainingId = ref<number>();
|
|
/** 参训人员编辑表单 */
|
const participantFormData = ref<HrmTrainingApi.Participant>();
|
const editVisible = ref(false);
|
const editSaving = ref(false);
|
const [EditForm, editFormApi] = useVbenForm({
|
commonConfig: {
|
componentProps: {
|
class: 'w-full',
|
},
|
labelWidth: 120,
|
},
|
wrapperClass: 'grid-cols-2',
|
layout: 'vertical',
|
schema: [
|
{
|
fieldName: 'id',
|
component: 'Input',
|
dependencies: {
|
triggerFields: [''],
|
show: () => false,
|
},
|
},
|
{
|
fieldName: 'attended',
|
label: '是否参训',
|
component: 'Select',
|
componentProps: {
|
options: [
|
{ label: '是', value: 1 },
|
{ label: '否', value: 0 },
|
],
|
placeholder: '是否参训',
|
},
|
},
|
{
|
fieldName: 'score',
|
label: '成绩',
|
component: 'InputNumber',
|
componentProps: {
|
placeholder: '请输入成绩',
|
min: 0,
|
precision: 1,
|
style: { width: '100%' },
|
},
|
},
|
{
|
fieldName: 'isPass',
|
label: '是否合格',
|
component: 'Select',
|
componentProps: {
|
options: [
|
{ label: '是', value: 1 },
|
{ label: '否', value: 0 },
|
],
|
placeholder: '是否合格',
|
},
|
},
|
{
|
fieldName: 'remark',
|
label: '备注',
|
component: 'Textarea',
|
componentProps: {
|
placeholder: '请输入备注',
|
autoSize: { minRows: 1, maxRows: 2 },
|
},
|
formItemClass: 'col-span-2',
|
},
|
],
|
showDefaultActions: false,
|
});
|
|
/** 打开编辑弹窗 */
|
function openEditForm(row: HrmTrainingApi.Participant) {
|
participantFormData.value = row;
|
editFormApi.setValues({
|
id: row.id,
|
attended: row.attended ? 1 : 0,
|
score: row.score,
|
isPass: row.isPass ? 1 : 0,
|
remark: row.remark,
|
});
|
editVisible.value = true;
|
}
|
|
/** 保存参训记录 */
|
async function handleEditSave() {
|
const { valid } = await editFormApi.validate();
|
if (!valid) {
|
return;
|
}
|
editSaving.value = true;
|
const values = await editFormApi.getValues<HrmTrainingApi.Participant>();
|
try {
|
await updateTrainingParticipant({
|
id: values.id,
|
attended: Boolean(values.attended),
|
score: values.score,
|
isPass: Boolean(values.isPass),
|
remark: values.remark,
|
} as HrmTrainingApi.Participant);
|
message.success($t('ui.actionMessage.operationSuccess'));
|
editVisible.value = false;
|
await loadParticipants();
|
} finally {
|
editSaving.value = false;
|
}
|
}
|
|
/** 删除参训记录 */
|
async function handleDelete(row: HrmTrainingApi.Participant) {
|
await deleteTrainingParticipants([row.id!]);
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
await loadParticipants();
|
}
|
|
/** 员工选择弹窗(多选) */
|
const employeeDialogRef = ref<InstanceType<typeof HrmEmployeeSelectDialog>>();
|
function openEmployeeSelect() {
|
employeeDialogRef.value?.open([], { multiple: true });
|
}
|
|
async function handleEmployeesSelected(rows: HrmEmployeeApi.Employee[]) {
|
const employeeIds = rows
|
.map((item) => item.id)
|
.filter((id): id is number => id !== undefined && id !== null);
|
if (employeeIds.length === 0) {
|
return;
|
}
|
try {
|
await addTrainingParticipants(trainingId.value!, employeeIds);
|
message.success('添加参训人员成功');
|
await loadParticipants();
|
emit('success');
|
} catch (e) {
|
// 后端兜底提示已弹出
|
}
|
}
|
|
async function loadParticipants() {
|
if (!trainingId.value) {
|
return;
|
}
|
const list = await getTrainingParticipants(trainingId.value);
|
gridApi.grid.loadData(list);
|
}
|
|
const [Grid, gridApi] = useVbenVxeGrid({
|
gridOptions: {
|
columns: [
|
{ type: 'seq', title: '序号', width: 60 },
|
{ field: 'employeeNo', title: '员工编号', width: 130 },
|
{ field: 'employeeName', title: '员工姓名', minWidth: 120 },
|
{
|
field: 'attended',
|
title: '是否参训',
|
width: 100,
|
slots: { default: 'attended' },
|
},
|
{
|
field: 'score',
|
title: '成绩',
|
width: 90,
|
},
|
{
|
field: 'isPass',
|
title: '是否合格',
|
width: 100,
|
slots: { default: 'isPass' },
|
},
|
{ field: 'remark', title: '备注', minWidth: 120 },
|
{
|
field: 'action',
|
title: '操作',
|
width: 140,
|
fixed: 'right',
|
slots: { default: 'actions' },
|
},
|
],
|
height: 'auto',
|
keepSource: true,
|
rowConfig: {
|
keyField: 'id',
|
isHover: true,
|
},
|
toolbarConfig: {
|
refresh: false,
|
search: false,
|
},
|
} as VxeTableGridOptions<HrmTrainingApi.Participant>,
|
});
|
|
const [Modal, modalApi] = useVbenModal({
|
onOpenChange(isOpen) {
|
if (!isOpen) {
|
trainingId.value = undefined;
|
return;
|
}
|
const data = modalApi.getData<{ trainingId?: number }>();
|
trainingId.value = data?.trainingId;
|
if (trainingId.value) {
|
loadParticipants();
|
}
|
},
|
});
|
</script>
|
|
<template>
|
<Modal title="参训人员管理" class="w-[900px]" :show-confirm-button="false">
|
<HrmEmployeeSelectDialog
|
ref="employeeDialogRef"
|
@selected="handleEmployeesSelected"
|
/>
|
<Grid table-title="参训人员列表">
|
<template #toolbar-tools>
|
<a-button type="primary" @click="openEmployeeSelect">
|
<i-ant-design-plus-outlined class="mr-1" />添加参训人员
|
</a-button>
|
</template>
|
<template #attended="{ row }">
|
<Tag v-if="row.attended" color="success">是</Tag>
|
<Tag v-else color="default">否</Tag>
|
</template>
|
<template #isPass="{ row }">
|
<Tag v-if="row.isPass" color="success">合格</Tag>
|
<Tag v-else-if="row.attended" color="error">不合格</Tag>
|
<Tag v-else color="default">-</Tag>
|
</template>
|
<template #actions="{ row }">
|
<a-button type="link" size="small" @click="openEditForm(row)">编辑</a-button>
|
<a-popconfirm
|
:title="$t('ui.actionMessage.deleteConfirm', [row.employeeName ?? row.id])"
|
@confirm="handleDelete(row)"
|
>
|
<a-button type="link" danger size="small">删除</a-button>
|
</a-popconfirm>
|
</template>
|
</Grid>
|
|
<AntModal
|
v-model:open="editVisible"
|
title="编辑参训记录"
|
width="480px"
|
:confirm-loading="editSaving"
|
@ok="handleEditSave"
|
>
|
<EditForm class="pt-4" />
|
</AntModal>
|
</Modal>
|
</template>
|