import {
|
deleteApprovalInstance,
|
listApprovalInstancePage,
|
saveApprovalInstance,
|
updateApprovalInstance,
|
} from "@/api/officeProcessAutomation/approvalInstance.js";
|
import useUserStore from "@/store/modules/user";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
import { computed, reactive, ref } from "vue";
|
import {
|
applyBindingToForm,
|
buildFormPayloadRules,
|
validateTemplateBinding,
|
} from "./approvalTemplateBindingUtils.js";
|
import {
|
buildApprovalInstanceListParams,
|
buildEditFormFromInstanceRow,
|
buildInstanceDto,
|
canEditBusinessInstanceRow,
|
createEmptySubmitForm,
|
mapInstanceFromApi,
|
resolveInstanceFormFields,
|
unwrapInstancePage,
|
} from "../approve-list/approveListConstants.js";
|
import { fetchBusinessTypeOptions } from "../approve-template/approveTemplateConstants.js";
|
import {
|
collectOptionSourcesFromFields,
|
fetchSelectOptionCaches,
|
} from "../approve-template/selectOptionSource.js";
|
import { enrichInstanceRowFromFormConfig } from "./approvalInstanceFormConfigTable.js";
|
import {
|
getApprovalModuleConfig,
|
getModuleListBusinessType,
|
resolveModuleBusinessType,
|
} from "./approvalModuleRegistry.js";
|
|
/**
|
* 业务申请页共用:审批实例列表查询、新增/修改保存、详情/编辑弹窗(与审批列表一致)
|
*
|
* @param {object} options
|
* @param {string} options.moduleKey approvalModuleRegistry 中的 key
|
* @param {(row: object) => object} [options.enrichListRow] 列表行增强(从 formPayload 解析展示字段)
|
* @param {(base: object) => object} [options.buildExtraListParams] 追加查询参数
|
* @param {() => void} [options.beforeSave] 保存前钩子(如同步业务字段到 formPayload)
|
* @param {import('vue').ComputedRef|object} [options.extraFormRules] 额外表单校验
|
*/
|
export function useApprovalInstanceModule(options = {}) {
|
const {
|
moduleKey,
|
enrichListRow,
|
buildExtraListParams,
|
beforeSave,
|
extraFormRules,
|
} = options;
|
|
const userStore = useUserStore();
|
const moduleConfig = computed(() => getApprovalModuleConfig(moduleKey));
|
const businessTypeOptions = ref([]);
|
|
/** 与审批列表一致:优先用 TypeEnums 的 value,匹配不到再回退 approvalType */
|
const defaultListBusinessType = computed(() => {
|
const resolved = resolveModuleBusinessType(moduleKey, businessTypeOptions.value);
|
if (resolved != null && resolved !== "") return resolved;
|
return getModuleListBusinessType(moduleKey);
|
});
|
|
async function loadBusinessTypeOptions() {
|
if (businessTypeOptions.value.length) return;
|
try {
|
businessTypeOptions.value = await fetchBusinessTypeOptions();
|
} catch {
|
businessTypeOptions.value = [];
|
}
|
}
|
|
const tableData = ref([]);
|
const tableLoading = ref(false);
|
const page = reactive({ current: 1, size: 10, total: 0 });
|
|
const detailDialog = reactive({ visible: false });
|
const detailRow = ref({});
|
|
const submitDialog = reactive({ visible: false, mode: "add" });
|
const submitEditRow = ref(null);
|
const submitForm = reactive(createEmptySubmitForm(""));
|
const submitFormRef = ref();
|
const submitSaving = ref(false);
|
|
const templateBindVisible = ref(false);
|
const pendingTemplateBinding = ref(null);
|
/** 最近一次列表查询条件(保存后刷新列表时沿用) */
|
let lastListSearchForm = null;
|
|
const isSubmitEdit = computed(() => submitDialog.mode === "edit");
|
const activeTemplate = computed(() => submitForm.templateSnapshot || null);
|
const submitFormFields = computed(() => {
|
const tplFields = activeTemplate.value?.fields;
|
if (tplFields?.length) return tplFields;
|
return submitForm.formFieldDefs || [];
|
});
|
|
const submitFormRules = computed(() => ({
|
...buildFormPayloadRules(submitFormFields.value),
|
...(extraFormRules?.value ?? extraFormRules ?? {}),
|
}));
|
|
const submitDialogTitle = computed(() => {
|
const label = moduleConfig.value?.label || "申请";
|
if (submitDialog.mode === "edit") {
|
return `修改${activeTemplate.value?.label || submitForm.templateName || label}`;
|
}
|
return `新增${label}`;
|
});
|
|
function mapListRow(row, caches) {
|
const mapped = mapInstanceFromApi(row);
|
const fromFormConfig = enrichInstanceRowFromFormConfig(mapped, caches);
|
return enrichListRow ? enrichListRow(fromFormConfig) : fromFormConfig;
|
}
|
|
async function fetchList(searchForm = {}) {
|
await loadBusinessTypeOptions();
|
tableLoading.value = true;
|
try {
|
let extraParams = {};
|
if (buildExtraListParams) {
|
extraParams = buildExtraListParams(searchForm) || {};
|
}
|
const res = await listApprovalInstancePage(
|
buildApprovalInstanceListParams({
|
page,
|
searchForm,
|
businessType: defaultListBusinessType.value,
|
extraParams,
|
})
|
);
|
const { records, total } = unwrapInstancePage(res);
|
const mapped = records.map(mapInstanceFromApi);
|
const allFields = [];
|
for (const row of mapped) {
|
const { fields } = resolveInstanceFormFields(row);
|
allFields.push(...fields);
|
}
|
const caches = await fetchSelectOptionCaches(
|
collectOptionSourcesFromFields(allFields)
|
);
|
tableData.value = mapped.map((row) => mapListRow(row, caches));
|
page.total = total;
|
} catch {
|
tableData.value = [];
|
page.total = 0;
|
ElMessage.error(`${moduleConfig.value?.label || "申请"}列表加载失败`);
|
} finally {
|
tableLoading.value = false;
|
}
|
}
|
|
function handleQuery(searchForm) {
|
lastListSearchForm = searchForm;
|
page.current = 1;
|
return fetchList(searchForm);
|
}
|
|
/** 进入页面:先拉 TypeEnums 解析 businessType,再查列表 */
|
async function initModuleList(searchForm) {
|
await loadBusinessTypeOptions();
|
return handleQuery(searchForm);
|
}
|
|
function pagination({ page: p, limit }, searchForm) {
|
page.current = p;
|
page.size = limit;
|
return fetchList(searchForm);
|
}
|
|
function openDetail(row) {
|
detailRow.value = { ...row };
|
detailDialog.visible = true;
|
}
|
|
function openEdit(row) {
|
if (!canEditBusinessInstanceRow(row)) {
|
ElMessage.warning("进行中或已完成的审批不可修改");
|
return;
|
}
|
if (!row?.id) {
|
ElMessage.warning("无法修改:缺少审批实例 ID");
|
return;
|
}
|
submitDialog.mode = "edit";
|
submitEditRow.value = { ...row };
|
Object.assign(submitForm, buildEditFormFromInstanceRow(row));
|
submitDialog.visible = true;
|
}
|
|
function openEditFromDetail() {
|
const row = detailRow.value;
|
detailDialog.visible = false;
|
openEdit(row);
|
}
|
|
function resetSubmitForm() {
|
Object.assign(submitForm, createEmptySubmitForm(""));
|
submitEditRow.value = null;
|
}
|
|
function openAddWithTemplate() {
|
submitDialog.visible = false;
|
pendingTemplateBinding.value = null;
|
templateBindVisible.value = true;
|
}
|
|
function onTemplateBound(binding) {
|
pendingTemplateBinding.value = binding;
|
}
|
|
function onTemplateBindClosed() {
|
const binding = pendingTemplateBinding.value;
|
if (!binding) return;
|
pendingTemplateBinding.value = null;
|
openAddFromBinding(binding);
|
}
|
|
function openAddFromBinding(binding) {
|
resetSubmitForm();
|
applyBindingToForm(submitForm, binding);
|
submitDialog.mode = "add";
|
submitEditRow.value = null;
|
submitDialog.visible = true;
|
}
|
|
function closeSubmitDialog() {
|
submitDialog.visible = false;
|
}
|
|
async function submitInstanceForm(options = {}) {
|
const { skipValidate = false } = options;
|
if (!skipValidate) {
|
if (!submitFormRef.value?.validate) {
|
ElMessage.warning("表单未就绪,请关闭弹窗后重试");
|
return false;
|
}
|
try {
|
await submitFormRef.value.validate();
|
} catch {
|
ElMessage.warning("请完善表单必填项后再保存");
|
return false;
|
}
|
}
|
if (!activeTemplate.value) {
|
ElMessage.warning("未加载审批模板,无法保存");
|
return false;
|
}
|
const bindingCheck = validateTemplateBinding({ flowNodes: submitForm.flowNodes });
|
if (!bindingCheck.ok) {
|
ElMessage.warning(bindingCheck.message);
|
return false;
|
}
|
if (!submitForm.templateId) {
|
ElMessage.warning("缺少模板 ID,无法提交");
|
return false;
|
}
|
if (beforeSave) {
|
try {
|
await beforeSave(submitForm, { isEdit: isSubmitEdit.value, editRow: submitEditRow.value });
|
} catch {
|
return false;
|
}
|
}
|
if (submitSaving.value) return false;
|
submitSaving.value = true;
|
try {
|
const dto = buildInstanceDto({
|
submitForm,
|
activeTemplate: activeTemplate.value,
|
userStore,
|
flowNodes: bindingCheck.nodes,
|
existingRow: isSubmitEdit.value ? submitEditRow.value : null,
|
});
|
if (isSubmitEdit.value) {
|
await updateApprovalInstance(dto);
|
} else {
|
await saveApprovalInstance(dto);
|
}
|
submitDialog.visible = false;
|
if (!isSubmitEdit.value) page.current = 1;
|
await fetchList(lastListSearchForm ?? {});
|
if (detailDialog.visible && detailRow.value?.id === submitForm.instanceId) {
|
const hit = tableData.value.find((r) => r.id === submitForm.instanceId);
|
if (hit) detailRow.value = { ...hit };
|
else detailDialog.visible = false;
|
}
|
return true;
|
} catch {
|
ElMessage.error(isSubmitEdit.value ? "保存失败" : "提交失败");
|
return false;
|
} finally {
|
submitSaving.value = false;
|
}
|
}
|
|
async function removeInstance(row) {
|
if (row?.id == null || row.id === "") {
|
ElMessage.warning("无法删除:缺少审批实例 ID");
|
return;
|
}
|
const title = row.title || row.templateName || row.instanceNo || "该审批";
|
try {
|
await ElMessageBox.confirm(
|
`确定要删除审批「${title}」吗?删除后不可恢复。`,
|
"删除确认",
|
{
|
type: "warning",
|
confirmButtonText: "确定删除",
|
cancelButtonText: "取消",
|
distinguishCancelAndClose: true,
|
autofocus: false,
|
}
|
);
|
} catch {
|
return;
|
}
|
try {
|
await deleteApprovalInstance([row.id]);
|
ElMessage.success("删除成功");
|
if (detailDialog.visible && detailRow.value?.id === row.id) {
|
detailDialog.visible = false;
|
}
|
if (submitDialog.visible && submitEditRow.value?.id === row.id) {
|
submitDialog.visible = false;
|
}
|
await fetchList(lastListSearchForm ?? {});
|
} catch {
|
/* 错误由拦截器提示 */
|
}
|
}
|
|
/** 构建标准操作列:详情、修改、删除(与审批列表一致) */
|
function buildTableActions(extraOperations = []) {
|
return [
|
{ name: "详情", type: "text", clickFun: (row) => openDetail(row) },
|
{
|
name: "修改",
|
type: "text",
|
disabled: (row) => !canEditBusinessInstanceRow(row),
|
clickFun: (row) => openEdit(row),
|
},
|
{
|
name: "删除",
|
type: "danger",
|
clickFun: (row) => removeInstance(row),
|
},
|
...extraOperations,
|
];
|
}
|
|
return {
|
moduleConfig,
|
defaultListBusinessType,
|
tableData,
|
tableLoading,
|
page,
|
detailDialog,
|
detailRow,
|
submitDialog,
|
submitEditRow,
|
submitForm,
|
submitFormRef,
|
submitSaving,
|
isSubmitEdit,
|
activeTemplate,
|
submitFormFields,
|
submitFormRules,
|
submitDialogTitle,
|
templateBindVisible,
|
pendingTemplateBinding,
|
fetchList,
|
handleQuery,
|
initModuleList,
|
pagination,
|
openDetail,
|
openEdit,
|
openEditFromDetail,
|
openAddWithTemplate,
|
onTemplateBound,
|
onTemplateBindClosed,
|
openAddFromBinding,
|
closeSubmitDialog,
|
resetSubmitForm,
|
submitInstanceForm,
|
removeInstance,
|
buildTableActions,
|
loadBusinessTypeOptions,
|
canEditBusinessInstanceRow,
|
};
|
}
|