2025-08-20 14:39:30 +08:00
|
|
|
<template>
|
2025-10-21 18:04:02 +08:00
|
|
|
<PageWrapper dense fixedHeight contentFullHeight contentClass="flex">
|
|
|
|
|
<BasicTableErp @register="registerTable" :row-selection="{ selectedRowKeys: selectedKeys, onChange: onSelectChange }">
|
|
|
|
|
<template #toolbar>
|
|
|
|
|
<template v-for="button in tableButtonConfig" :key="button.code">
|
|
|
|
|
<a-button v-if="button.isDefault" type="primary" @click="buttonClick(button.code)">
|
|
|
|
|
<template #icon><Icon :icon="button.icon" /></template>
|
|
|
|
|
{{ button.name }}
|
|
|
|
|
</a-button>
|
|
|
|
|
<a-button v-else type="primary">
|
|
|
|
|
<template #icon><Icon :icon="button.icon" /></template>
|
|
|
|
|
{{ button.name }}
|
|
|
|
|
</a-button>
|
|
|
|
|
</template>
|
2025-08-20 14:39:30 +08:00
|
|
|
</template>
|
2025-10-21 18:04:02 +08:00
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
|
|
<template v-if="column.dataIndex == 'applyDetail'">
|
|
|
|
|
<a-dropdown v-if="record.applyDetail">
|
|
|
|
|
<span>
|
|
|
|
|
{{ record.applyDetail.split(',')[0]?.split(':')[0] }}
|
|
|
|
|
<DownOutlined />
|
|
|
|
|
</span>
|
|
|
|
|
<template #overlay>
|
|
|
|
|
<a-menu>
|
|
|
|
|
<a-menu-item v-for="(item, index) in record.applyDetail.split(',')" :key="index">
|
|
|
|
|
<a href="javascript:;">{{ item }}</a>
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
</a-menu>
|
|
|
|
|
</template>
|
|
|
|
|
</a-dropdown>
|
|
|
|
|
</template>
|
|
|
|
|
<template v-if="column.dataIndex === 'action'">
|
|
|
|
|
<TableAction :actions="getActions(record)" />
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</BasicTableErp>
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
<LookProcess v-if="visibleLookProcessRef" :taskId="taskIdRef" :processId="processIdRef" @close="visibleLookProcessRef = false" :visible="visibleLookProcessRef" />
|
|
|
|
|
<LaunchProcess v-if="visibleLaunchProcessRef" :schemaId="schemaIdRef" :form-data="formDataRef" :form-id="formIdComputedRef" @close="handleCloseLaunch" />
|
|
|
|
|
<ApprovalProcess v-if="visibleApproveProcessRef" :taskId="taskIdRef" :processId="processIdRef" :schemaId="schemaIdRef" @close="handleCloseApproval" :visible="visibleApproveProcessRef" />
|
|
|
|
|
<ApplyModal @register="registerModal" @success="handleSuccess" />
|
|
|
|
|
<ApplyCheckInfo @register="registerInfoModal" />
|
|
|
|
|
</PageWrapper>
|
2025-08-20 14:39:30 +08:00
|
|
|
</template>
|
|
|
|
|
<script lang="ts" setup>
|
2025-10-21 18:04:02 +08:00
|
|
|
import { ref, computed, createVNode } from 'vue';
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
import { Modal } from 'ant-design-vue';
|
|
|
|
|
import { ExclamationCircleOutlined, DownOutlined } from '@ant-design/icons-vue';
|
|
|
|
|
import { useTable, TableAction, ActionItem } from '/@/components/Table';
|
|
|
|
|
import BasicTableErp from '/@/components/Table/src/BasicTableErp.vue';
|
|
|
|
|
import { getCaseErpApplyPage, deleteCaseErpApply, exportCaseErpApply } from '/@/api/erp/purchase/apply';
|
|
|
|
|
import { PageWrapper } from '/@/components/Page';
|
|
|
|
|
import { useMessage } from '/@/hooks/web/useMessage';
|
|
|
|
|
import { useI18n } from '/@/hooks/web/useI18n';
|
|
|
|
|
import { usePermission } from '/@/hooks/web/usePermission';
|
|
|
|
|
import { useRouter } from 'vue-router';
|
|
|
|
|
import { useModal } from '/@/components/Modal';
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
import LookProcess from '/@/views/workflow/task/components/LookProcess.vue';
|
|
|
|
|
import LaunchProcess from '/@/views/workflow/task/components/LaunchProcess.vue';
|
|
|
|
|
import ApprovalProcess from '/@/views/workflow/task/components/ApprovalProcess.vue';
|
|
|
|
|
import { getFormExecuteWorkflow } from '/@/api/form/execute';
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
import ApplyModal from './components/ApplyModal.vue';
|
|
|
|
|
import ApplyCheckInfo from './components/ApplyCheckInfo.vue';
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
import { downloadByData } from '/@/utils/file/download';
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
import { columns } from './components/config';
|
|
|
|
|
import Icon from '/@/components/Icon/index';
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const { notification } = useMessage();
|
|
|
|
|
const { t } = useI18n();
|
|
|
|
|
defineEmits(['register']);
|
|
|
|
|
const { filterColumnAuth, filterButtonAuth } = usePermission();
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const filterColumns = filterColumnAuth(columns);
|
|
|
|
|
//展示在列表内的按钮
|
|
|
|
|
const actionButtons = ref<string[]>(['view', 'edit', 'delete', 'startwork']);
|
|
|
|
|
const buttonConfigs = computed(() => {
|
|
|
|
|
const list = [
|
|
|
|
|
{ isUse: true, name: '查看', code: 'view', icon: 'ant-design:eye-outlined', isDefault: true },
|
|
|
|
|
{ isUse: true, name: '新增', code: 'add', icon: 'ant-design:plus-outlined', isDefault: true },
|
|
|
|
|
{
|
|
|
|
|
isUse: true,
|
|
|
|
|
name: '编辑',
|
|
|
|
|
code: 'edit',
|
|
|
|
|
icon: 'ant-design:form-outlined',
|
|
|
|
|
isDefault: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
isUse: true,
|
|
|
|
|
name: '删除',
|
|
|
|
|
code: 'delete',
|
|
|
|
|
icon: 'ant-design:delete-outlined',
|
|
|
|
|
isDefault: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
isUse: true,
|
|
|
|
|
name: '快速导出',
|
|
|
|
|
code: 'export',
|
|
|
|
|
icon: 'ant-design:export-outlined',
|
|
|
|
|
isDefault: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
isUse: true,
|
|
|
|
|
name: '发起审批',
|
|
|
|
|
code: 'startwork',
|
|
|
|
|
icon: 'ant-design:form-outlined',
|
|
|
|
|
isDefault: true
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
return filterButtonAuth(list);
|
|
|
|
|
});
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const tableButtonConfig = computed(() => {
|
|
|
|
|
return buttonConfigs.value?.filter((x) => !actionButtons.value.includes(x.code));
|
|
|
|
|
});
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const actionButtonConfig = computed(() => {
|
|
|
|
|
return buttonConfigs.value?.filter((x) => actionButtons.value.includes(x.code));
|
|
|
|
|
});
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const btnEvent = {
|
|
|
|
|
view: handleView,
|
|
|
|
|
add: handleAdd,
|
|
|
|
|
edit: handleEdit,
|
|
|
|
|
delete: handleDelete,
|
|
|
|
|
export: handleExport,
|
|
|
|
|
startwork: handleStartwork
|
|
|
|
|
};
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const { currentRoute } = useRouter();
|
|
|
|
|
const formIdComputedRef = computed(() => currentRoute.value.meta.formId as string);
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const visibleLookProcessRef = ref(false);
|
|
|
|
|
const processIdRef = ref('');
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const visibleLaunchProcessRef = ref(false);
|
|
|
|
|
const schemaIdRef = ref('');
|
|
|
|
|
const formDataRef = ref();
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const visibleApproveProcessRef = ref(false);
|
|
|
|
|
const taskIdRef = ref('');
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const selectedKeys = ref<string[]>([]);
|
|
|
|
|
const selectedRowsData = ref<any[]>([]);
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const [registerModal, { openModal }] = useModal();
|
|
|
|
|
const [registerInfoModal, { openModal: openInfoModal }] = useModal();
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
const [registerTable, { reload }] = useTable({
|
|
|
|
|
title: '采购申请',
|
|
|
|
|
api: getCaseErpApplyPage,
|
|
|
|
|
rowKey: 'id',
|
|
|
|
|
columns: filterColumns,
|
|
|
|
|
beforeFetch: (params) => {
|
|
|
|
|
return { ...params, FormId: formIdComputedRef.value, PK: 'id' };
|
|
|
|
|
},
|
|
|
|
|
showTableSetting: true,
|
|
|
|
|
striped: false,
|
|
|
|
|
actionColumn: {
|
|
|
|
|
width: 160,
|
|
|
|
|
title: '操作',
|
|
|
|
|
dataIndex: 'action',
|
|
|
|
|
slots: { customRender: 'action' }
|
|
|
|
|
},
|
|
|
|
|
customRow
|
2025-08-20 14:39:30 +08:00
|
|
|
});
|
|
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function buttonClick(code) {
|
|
|
|
|
btnEvent[code]();
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function handleAdd() {
|
|
|
|
|
openModal(true, {
|
|
|
|
|
isUpdate: false
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function handleEdit(record: Recordable) {
|
|
|
|
|
openModal(true, {
|
|
|
|
|
id: record.id,
|
|
|
|
|
isUpdate: true
|
2025-08-20 14:39:30 +08:00
|
|
|
});
|
2025-10-21 18:04:02 +08:00
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function handleDelete(record: Recordable) {
|
|
|
|
|
deleteList([record.id]);
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function deleteList(ids) {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: '提示信息',
|
|
|
|
|
icon: createVNode(ExclamationCircleOutlined),
|
|
|
|
|
content: '是否确认删除?',
|
|
|
|
|
okText: '确认',
|
|
|
|
|
cancelText: '取消',
|
|
|
|
|
onOk() {
|
|
|
|
|
deleteCaseErpApply(ids).then((_) => {
|
|
|
|
|
reload();
|
|
|
|
|
notification.success({
|
|
|
|
|
message: 'Tip',
|
|
|
|
|
description: t('删除成功!')
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
onCancel() {}
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function onSelectChange(selectedRowKeys: [], selectedRows) {
|
|
|
|
|
selectedKeys.value = selectedRowKeys;
|
|
|
|
|
selectedRowsData.value = selectedRows;
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function customRow(record: Recordable) {
|
|
|
|
|
return {
|
|
|
|
|
onClick: () => {
|
|
|
|
|
let selectedRowKeys = [...selectedKeys.value];
|
|
|
|
|
if (selectedRowKeys.indexOf(record.id) >= 0) {
|
|
|
|
|
let index = selectedRowKeys.indexOf(record.id);
|
|
|
|
|
selectedRowKeys.splice(index, 1);
|
|
|
|
|
} else {
|
|
|
|
|
selectedRowKeys.push(record.id);
|
|
|
|
|
}
|
|
|
|
|
selectedKeys.value = selectedRowKeys;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function handleSuccess() {
|
|
|
|
|
reload();
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function handleView(record: Recordable) {
|
|
|
|
|
openInfoModal(true, {
|
|
|
|
|
id: record.id,
|
|
|
|
|
processId: record.workflowData?.processId
|
2025-08-20 14:39:30 +08:00
|
|
|
});
|
2025-10-21 18:04:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleExport() {
|
|
|
|
|
const res = await exportCaseErpApply({ isTemplate: false });
|
|
|
|
|
downloadByData(res.data, '采购申请.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getActions(record: Recordable): ActionItem[] {
|
|
|
|
|
let actionsList: ActionItem[] = [];
|
|
|
|
|
let editAndDelBtn: ActionItem[] = [];
|
|
|
|
|
actionButtonConfig.value?.map((button) => {
|
|
|
|
|
if (button.code === 'view') {
|
|
|
|
|
actionsList.push({
|
|
|
|
|
icon: button?.icon,
|
|
|
|
|
tooltip: button?.name,
|
|
|
|
|
onClick: handleView.bind(null, record)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (['edit', 'delete'].includes(button.code)) {
|
|
|
|
|
editAndDelBtn.push({
|
|
|
|
|
icon: button?.icon,
|
|
|
|
|
tooltip: button?.name,
|
|
|
|
|
color: button.code === 'delete' ? 'error' : undefined,
|
|
|
|
|
onClick: btnEvent[button.code].bind(null, record)
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
});
|
2025-10-21 18:04:02 +08:00
|
|
|
if (record.workflowData.enabled) {
|
|
|
|
|
//与工作流有关联的表单
|
|
|
|
|
if (record.workflowData.status) {
|
|
|
|
|
//如果是本人需要审批的数据 就会有taskIds 所以需要修改绑定事件
|
|
|
|
|
const act: ActionItem = {};
|
|
|
|
|
if (record.workflowData.taskIds) {
|
|
|
|
|
act.tooltip = '查看流程(待审批)';
|
|
|
|
|
act.icon = 'daishenpi|svg';
|
|
|
|
|
act.onClick = handleApproveProcess.bind(null, record);
|
|
|
|
|
} else {
|
|
|
|
|
act.tooltip = '查看流程' + (record.workflowData.status === 'ACTIVE' ? '(审批中)' : '(已完成)');
|
|
|
|
|
act.icon = record.workflowData.status === 'ACTIVE' ? 'jinshenpi|svg' : 'shenpiwancheng|svg';
|
|
|
|
|
act.onClick = handleStartwork.bind(null, record);
|
|
|
|
|
}
|
|
|
|
|
actionsList.unshift(act);
|
|
|
|
|
} else {
|
|
|
|
|
actionsList.unshift({
|
|
|
|
|
icon: 'faqishenpi|svg',
|
|
|
|
|
tooltip: '发起审批',
|
|
|
|
|
onClick: handleLaunchProcess.bind(null, record)
|
|
|
|
|
});
|
|
|
|
|
actionsList = actionsList.concat(editAndDelBtn);
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
} else {
|
2025-10-21 18:04:02 +08:00
|
|
|
if (!record.workflowData.processId) {
|
|
|
|
|
//与工作流没有关联的表单并且在当前页面新增的数据 如选择编辑、删除按钮则加上
|
|
|
|
|
actionsList = actionsList.concat(editAndDelBtn);
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
}
|
2025-10-21 18:04:02 +08:00
|
|
|
return actionsList;
|
2025-08-20 14:39:30 +08:00
|
|
|
}
|
|
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
function handleStartwork(record: Recordable) {
|
|
|
|
|
if (record.workflowData) {
|
|
|
|
|
visibleLookProcessRef.value = true;
|
|
|
|
|
processIdRef.value = record.workflowData.processId;
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
}
|
2025-10-21 18:04:02 +08:00
|
|
|
async function handleLaunchProcess(record: Recordable) {
|
|
|
|
|
if (record.workflowData) {
|
|
|
|
|
const result = await getFormExecuteWorkflow({
|
|
|
|
|
formId: formIdComputedRef.value,
|
|
|
|
|
id: record['id']
|
|
|
|
|
});
|
2025-08-20 14:39:30 +08:00
|
|
|
|
2025-10-21 18:04:02 +08:00
|
|
|
visibleLaunchProcessRef.value = true;
|
|
|
|
|
schemaIdRef.value = record.workflowData.schemaId;
|
|
|
|
|
formDataRef.value = result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function handleApproveProcess(record: Recordable) {
|
|
|
|
|
visibleApproveProcessRef.value = true;
|
|
|
|
|
schemaIdRef.value = record.workflowData.schemaId;
|
|
|
|
|
processIdRef.value = record.workflowData.processId;
|
|
|
|
|
taskIdRef.value = record.workflowData.taskIds[0];
|
|
|
|
|
}
|
|
|
|
|
function handleCloseLaunch() {
|
|
|
|
|
visibleLaunchProcessRef.value = false;
|
|
|
|
|
reload();
|
|
|
|
|
}
|
|
|
|
|
function handleCloseApproval() {
|
|
|
|
|
visibleApproveProcessRef.value = false;
|
|
|
|
|
reload();
|
2025-08-20 14:39:30 +08:00
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
<style lang="less" scoped>
|
2025-10-21 18:04:02 +08:00
|
|
|
:deep(.ant-table-selection-col) {
|
|
|
|
|
width: 50px;
|
|
|
|
|
}
|
2025-08-20 14:39:30 +08:00
|
|
|
</style>
|