import {
|
addApprovalTemplate,
|
deleteApprovalTemplate,
|
getApprovalTemplateDetail,
|
listApprovalTemplatePage,
|
TEMPLATE_TYPE_CUSTOM,
|
updateApprovalTemplate,
|
} from "@/api/officeProcessAutomation/approvalTemplate.js";
|
import { getTypeEnums } from "@/api/basicData/enum.js";
|
import { Search } from "@element-plus/icons-vue";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
import { reactive, ref } from "vue";
|
import {
|
buildApprovalTemplateListParams,
|
createEmptyTemplateForm,
|
flowNodesSummary,
|
mapTemplateFromApi,
|
mapTemplateToApi,
|
nodeSignModeLabel,
|
formatDisplayTime,
|
unwrapTemplateDetail,
|
validateTemplateForm,
|
} from "./approveTemplateConstants.js";
|
import { parseFormConfigToData } from "./formConfigUtils.js";
|
|
const LEGACY_STORAGE_KEY = "oa_approve_template_custom_v1";
|
|
const FALLBACK_TEMPLATE_TYPE_OPTIONS = [
|
{ value: 0, label: "系统内置" },
|
{ value: 1, label: "自定义" },
|
];
|
|
function unwrapEnumList(data) {
|
if (Array.isArray(data)) return data;
|
if (!data || typeof data !== "object") return [];
|
if (Array.isArray(data.TypeEnums)) return data.TypeEnums;
|
if (Array.isArray(data.typeEnums)) return data.typeEnums;
|
const nested = Object.values(data).find((v) => Array.isArray(v));
|
return nested || [];
|
}
|
|
function normalizeTypeEnumOptions(data) {
|
return unwrapEnumList(data)
|
.map((item) => {
|
const rawValue = item?.value ?? item?.code ?? item?.businessType ?? item?.dictValue ?? item?.key;
|
if (rawValue == null || rawValue === "") return null;
|
const num = Number(rawValue);
|
const value =
|
typeof rawValue === "number" || (Number.isFinite(num) && String(rawValue).trim() !== "")
|
? num
|
: rawValue;
|
const label =
|
item?.label ?? item?.name ?? item?.desc ?? item?.dictLabel ?? item?.text ?? String(value);
|
return { label, value };
|
})
|
.filter(Boolean);
|
}
|
|
function matchTemplateTypeValue(options, type) {
|
if (type == null || type === "") return false;
|
return options.some(
|
(x) => x.value === type || x.value === Number(type) || String(x.value) === String(type)
|
);
|
}
|
|
function clearLegacyStorage() {
|
try {
|
localStorage.removeItem(LEGACY_STORAGE_KEY);
|
} catch {
|
/* ignore */
|
}
|
}
|
|
export function useApproveTemplate() {
|
clearLegacyStorage();
|
|
const templateTypeOptions = ref([...FALLBACK_TEMPLATE_TYPE_OPTIONS]);
|
|
function templateTypeLabel(type) {
|
if (type == null || type === "") return "—";
|
const hit = templateTypeOptions.value.find(
|
(x) => x.value === type || x.value === Number(type) || String(x.value) === String(type)
|
);
|
return hit?.label || "—";
|
}
|
|
const searchForm = reactive({
|
keyword: "",
|
enabledOnly: false,
|
});
|
|
const tableLoading = ref(false);
|
const page = reactive({ current: 1, size: 10, total: 0 });
|
const tableData = ref([]);
|
|
const formDialog = reactive({ visible: false, title: "", mode: "add" });
|
const form = reactive(createEmptyTemplateForm());
|
const formRef = ref();
|
|
async function loadTemplateTypeOptions() {
|
try {
|
const res = await getTypeEnums();
|
const list = normalizeTypeEnumOptions(res?.data);
|
templateTypeOptions.value = list.length ? list : [...FALLBACK_TEMPLATE_TYPE_OPTIONS];
|
} catch {
|
templateTypeOptions.value = [...FALLBACK_TEMPLATE_TYPE_OPTIONS];
|
}
|
if (!matchTemplateTypeValue(templateTypeOptions.value, form.businessType)) {
|
form.businessType = templateTypeOptions.value[0]?.value ?? "";
|
}
|
}
|
|
const detailDialog = reactive({ visible: false });
|
const detailRow = ref({});
|
const detailLoading = ref(false);
|
|
const formRules = {
|
templateName: [{ required: true, message: "请输入模板名称", trigger: "blur" }],
|
businessType: [{ required: true, message: "请选择模板类型", trigger: "change" }],
|
};
|
|
const tableColumn = ref([
|
{ label: "模板名称", prop: "templateName", minWidth: 140 },
|
{
|
label: "模板类型",
|
prop: "businessType",
|
width: 100,
|
align: "center",
|
formatData: (v) => templateTypeLabel(v),
|
},
|
{ label: "说明", prop: "description", minWidth: 160, showOverflowTooltip: true },
|
{
|
label: "节点数",
|
prop: "flowNodes",
|
width: 80,
|
align: "center",
|
formatData: (v) => (Array.isArray(v) ? v.length : 0),
|
},
|
{
|
label: "流程概要",
|
prop: "flowNodes",
|
minWidth: 220,
|
showOverflowTooltip: true,
|
formatData: (v) => flowNodesSummary(v),
|
},
|
{
|
label: "状态",
|
prop: "enabled",
|
width: 90,
|
align: "center",
|
dataType: "tag",
|
formatData: (v) => (v !== false ? "启用" : "停用"),
|
formatType: (v) => (v !== false ? "success" : "info"),
|
},
|
{
|
label: "创建时间",
|
prop: "createdTime",
|
width: 170,
|
showOverflowTooltip: true,
|
formatData: (v) => formatDisplayTime(v),
|
},
|
{
|
label: "更新时间",
|
prop: "updatedTime",
|
width: 170,
|
showOverflowTooltip: true,
|
formatData: (v) => formatDisplayTime(v),
|
},
|
{
|
dataType: "action",
|
label: "操作",
|
align: "center",
|
fixed: "right",
|
width: 220,
|
operation: [
|
{ name: "详情", type: "text", clickFun: (row) => openDetail(row) },
|
{ name: "编辑", type: "text", clickFun: (row) => openFormDialog("edit", row) },
|
{
|
name: "删除",
|
type: "danger",
|
link: true,
|
clickFun: (row) => removeTemplate(row),
|
},
|
],
|
},
|
]);
|
|
async function fetchTemplateList() {
|
tableLoading.value = true;
|
try {
|
const res = await listApprovalTemplatePage(
|
buildApprovalTemplateListParams({ page, searchForm })
|
);
|
const data = res?.data || {};
|
tableData.value = (data.records || []).map(mapTemplateFromApi);
|
page.total = Number(data.total || 0);
|
} catch {
|
tableData.value = [];
|
page.total = 0;
|
} finally {
|
tableLoading.value = false;
|
}
|
}
|
|
function handleQuery() {
|
page.current = 1;
|
fetchTemplateList();
|
}
|
|
function resetSearch() {
|
searchForm.keyword = "";
|
searchForm.enabledOnly = false;
|
handleQuery();
|
}
|
|
function pagination({ page: p, limit }) {
|
page.current = p;
|
page.size = limit;
|
fetchTemplateList();
|
}
|
|
function resetForm(row) {
|
const base = createEmptyTemplateForm();
|
if (!row) {
|
Object.assign(form, base);
|
return;
|
}
|
Object.assign(form, {
|
...base,
|
id: row.id,
|
templateName: row.templateName || "",
|
description: row.description || "",
|
businessType: row.businessType ?? "",
|
formConfig: row.formConfig || "",
|
formConfigData: JSON.parse(
|
JSON.stringify(row.formConfigData || parseFormConfigToData(row.formConfig))
|
),
|
enabled: row.enabled !== false,
|
flowNodes: JSON.parse(JSON.stringify(row.flowNodes || [base.flowNodes[0]])),
|
});
|
}
|
|
function openFormDialog(mode, row) {
|
formDialog.mode = mode;
|
formDialog.title = mode === "add" ? "新建审批模板" : "编辑审批模板";
|
resetForm(mode === "edit" ? row : null);
|
formDialog.visible = true;
|
}
|
|
async function openDetail(row) {
|
if (row?.id == null || row.id === "") {
|
ElMessage.warning("无法查看详情:缺少模板 ID");
|
return;
|
}
|
detailDialog.visible = true;
|
detailLoading.value = true;
|
detailRow.value = {};
|
try {
|
const res = await getApprovalTemplateDetail(row.id);
|
detailRow.value = mapTemplateFromApi(unwrapTemplateDetail(res));
|
} catch {
|
detailDialog.visible = false;
|
} finally {
|
detailLoading.value = false;
|
}
|
}
|
|
async function submitForm() {
|
if (!formRef.value) return false;
|
try {
|
await formRef.value.validate();
|
} catch {
|
return false;
|
}
|
const validated = validateTemplateForm(form);
|
if (!validated.ok) {
|
return { message: validated.message };
|
}
|
if (formDialog.mode === "edit" && !form.id) {
|
return { message: "缺少模板 ID,无法保存修改" };
|
}
|
const dto = mapTemplateToApi(form);
|
try {
|
if (formDialog.mode === "add") {
|
await addApprovalTemplate(dto);
|
} else {
|
await updateApprovalTemplate(dto);
|
}
|
} catch {
|
return false;
|
}
|
formDialog.visible = false;
|
page.current = 1;
|
await fetchTemplateList();
|
return { ok: true };
|
}
|
|
async function removeTemplate(row) {
|
if (row?.id == null || row.id === "") {
|
ElMessage.warning("无法删除:缺少模板 ID");
|
return;
|
}
|
const name = row.templateName || "未命名模板";
|
try {
|
await ElMessageBox.confirm(
|
`确定要删除审批模板「${name}」吗?删除后不可恢复。`,
|
"删除确认",
|
{
|
type: "warning",
|
confirmButtonText: "确定删除",
|
cancelButtonText: "取消",
|
distinguishCancelAndClose: true,
|
autofocus: false,
|
}
|
);
|
} catch {
|
return;
|
}
|
try {
|
await deleteApprovalTemplate([row.id]);
|
ElMessage.success("删除成功");
|
await fetchTemplateList();
|
} catch {
|
/* 错误由拦截器提示 */
|
}
|
}
|
|
return {
|
Search,
|
templateTypeOptions,
|
loadTemplateTypeOptions,
|
templateTypeLabel,
|
fetchTemplateList,
|
nodeSignModeLabel,
|
flowNodesSummary,
|
searchForm,
|
tableLoading,
|
page,
|
tableData,
|
tableColumn,
|
formDialog,
|
form,
|
formRef,
|
formRules,
|
detailDialog,
|
detailRow,
|
detailLoading,
|
handleQuery,
|
resetSearch,
|
pagination,
|
openFormDialog,
|
openDetail,
|
submitForm,
|
};
|
}
|