From a567edf28abb00581c93b27405ed9657b63a8bd7 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期二, 19 五月 2026 13:32:17 +0800
Subject: [PATCH] 模板类型设置

---
 src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js |  263 ++++++++++++++++++++++++++++++++-------------------
 1 files changed, 164 insertions(+), 99 deletions(-)

diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js b/src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js
index c56d055..8489e13 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js
@@ -1,24 +1,49 @@
-import { Search } from "@element-plus/icons-vue";
-import dayjs from "dayjs";
-import { ElMessageBox } from "element-plus";
-import { computed, reactive, ref, watch } from "vue";
 import {
+  addApprovalTemplate,
+  deleteApprovalTemplate,
+  getApprovalTemplateDetail,
+  listApprovalTemplate,
+  listApprovalTemplatePage,
+  TEMPLATE_TYPE_BUILTIN,
+  TEMPLATE_TYPE_CUSTOM,
+  TEMPLATE_TYPE_OPTIONS,
+  updateApprovalTemplate,
+} from "@/api/officeProcessAutomation/approvalTemplate.js";
+import { Search } from "@element-plus/icons-vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { reactive, ref } from "vue";
+import {
+  buildApprovalTemplateListParams,
   createEmptyTemplateForm,
-  createInitialMockTemplates,
   flowNodesSummary,
-  getBuiltinTemplates,
-  loadStoredTemplates,
+  mapBuiltinCardFromApi,
+  mapTemplateFromApi,
+  mapTemplateToApi,
   nodeSignModeLabel,
-  saveStoredTemplates,
+  templateTypeLabel,
+  unwrapTemplateList,
+  formatDisplayTime,
+  unwrapTemplateDetail,
   validateTemplateForm,
 } from "./approveTemplateConstants.js";
+import { parseFormConfigToData } from "./formConfigUtils.js";
+
+const LEGACY_STORAGE_KEY = "oa_approve_template_custom_v1";
+
+function clearLegacyStorage() {
+  try {
+    localStorage.removeItem(LEGACY_STORAGE_KEY);
+  } catch {
+    /* ignore */
+  }
+}
 
 export function useApproveTemplate() {
-  const stored = loadStoredTemplates();
-  const allTemplates = ref(stored?.length ? stored : createInitialMockTemplates());
+  clearLegacyStorage();
 
   const activeTab = ref("custom");
-  const builtinTemplates = getBuiltinTemplates();
+  const builtinTemplates = ref([]);
+  const builtinLoading = ref(false);
 
   const searchForm = reactive({
     keyword: "",
@@ -27,6 +52,7 @@
 
   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());
@@ -34,44 +60,22 @@
 
   const detailDialog = reactive({ visible: false });
   const detailRow = ref({});
-
-  const filteredList = computed(() => {
-    let list = [...allTemplates.value];
-    const kw = (searchForm.keyword || "").trim().toLowerCase();
-    if (kw) {
-      list = list.filter((r) => {
-        const name = (r.templateName || "").toLowerCase();
-        const desc = (r.description || "").toLowerCase();
-        return name.includes(kw) || desc.includes(kw);
-      });
-    }
-    if (searchForm.enabledOnly) {
-      list = list.filter((r) => r.enabled !== false);
-    }
-    return list.sort((a, b) => (String(a.updateTime) < String(b.updateTime) ? 1 : -1));
-  });
-
-  watch(
-    filteredList,
-    (list) => {
-      page.total = list.length;
-      const maxPage = Math.max(1, Math.ceil(list.length / page.size) || 1);
-      if (page.current > maxPage) page.current = maxPage;
-    },
-    { immediate: true }
-  );
-
-  const tableData = computed(() => {
-    const start = (page.current - 1) * page.size;
-    return filteredList.value.slice(start, start + page.size);
-  });
+  const detailLoading = ref(false);
 
   const formRules = {
     templateName: [{ required: true, message: "璇疯緭鍏ユā鏉垮悕绉�", trigger: "blur" }],
+    templateType: [{ required: true, message: "璇烽�夋嫨妯℃澘绫诲瀷", trigger: "change" }],
   };
 
   const tableColumn = ref([
     { label: "妯℃澘鍚嶇О", prop: "templateName", minWidth: 140 },
+    {
+      label: "妯℃澘绫诲瀷",
+      prop: "templateType",
+      width: 100,
+      align: "center",
+      formatData: (v) => templateTypeLabel(v),
+    },
     { label: "璇存槑", prop: "description", minWidth: 160, showOverflowTooltip: true },
     {
       label: "鑺傜偣鏁�",
@@ -96,31 +100,72 @@
       formatData: (v) => (v !== false ? "鍚敤" : "鍋滅敤"),
       formatType: (v) => (v !== false ? "success" : "info"),
     },
-    { label: "鏇存柊鏃堕棿", prop: "updateTime", width: 170 },
+    {
+      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: 200,
+      width: 220,
       operation: [
         { name: "璇︽儏", type: "text", clickFun: (row) => openDetail(row) },
         { name: "缂栬緫", type: "text", clickFun: (row) => openFormDialog("edit", row) },
-        { name: "鍒犻櫎", type: "text", clickFun: (row) => removeTemplate(row) },
+        {
+          name: "鍒犻櫎",
+          type: "danger",
+          link: true,
+          clickFun: (row) => removeTemplate(row),
+        },
       ],
     },
   ]);
 
-  function persist() {
-    saveStoredTemplates(allTemplates.value);
+  async function loadBuiltinTemplates() {
+    builtinLoading.value = true;
+    try {
+      const res = await listApprovalTemplate(TEMPLATE_TYPE_BUILTIN);
+      builtinTemplates.value = unwrapTemplateList(res).map(mapBuiltinCardFromApi);
+    } catch {
+      builtinTemplates.value = [];
+      ElMessage.warning("绯荤粺甯哥敤瀹℃壒鍔犺浇澶辫触");
+    } finally {
+      builtinLoading.value = false;
+    }
+  }
+
+  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() {
-    tableLoading.value = true;
     page.current = 1;
-    setTimeout(() => {
-      tableLoading.value = false;
-    }, 150);
+    fetchTemplateList();
   }
 
   function resetSearch() {
@@ -132,6 +177,7 @@
   function pagination({ page: p, limit }) {
     page.current = p;
     page.size = limit;
+    fetchTemplateList();
   }
 
   function resetForm(row) {
@@ -145,6 +191,11 @@
       id: row.id,
       templateName: row.templateName || "",
       description: row.description || "",
+      templateType: row.templateType ?? TEMPLATE_TYPE_CUSTOM,
+      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]])),
     });
@@ -152,19 +203,27 @@
 
   function openFormDialog(mode, row) {
     formDialog.mode = mode;
-    formDialog.title = mode === "add" ? "鏂板缓鑷畾涔夊鎵规ā鏉�" : "缂栬緫鑷畾涔夊鎵规ā鏉�";
+    formDialog.title = mode === "add" ? "鏂板缓瀹℃壒妯℃澘" : "缂栬緫瀹℃壒妯℃澘";
     resetForm(mode === "edit" ? row : null);
     formDialog.visible = true;
   }
 
-  function openDetail(row) {
-    detailRow.value = { ...row };
+  async function openDetail(row) {
+    if (row?.id == null || row.id === "") {
+      ElMessage.warning("鏃犳硶鏌ョ湅璇︽儏锛氱己灏戞ā鏉� ID");
+      return;
+    }
     detailDialog.visible = true;
-  }
-
-  function isNameDuplicate(name, excludeId) {
-    const n = (name || "").trim();
-    return allTemplates.value.some((t) => t.templateName?.trim() === n && t.id !== excludeId);
+    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() {
@@ -178,64 +237,70 @@
     if (!validated.ok) {
       return { message: validated.message };
     }
-    if (isNameDuplicate(validated.name, form.id)) {
-      return { message: "妯℃澘鍚嶇О宸插瓨鍦紝璇锋洿鎹㈠悕绉�" };
+    if (formDialog.mode === "edit" && !form.id) {
+      return { message: "缂哄皯妯℃澘 ID锛屾棤娉曚繚瀛樹慨鏀�" };
     }
-    const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
-    if (formDialog.mode === "add") {
-      allTemplates.value.unshift({
-        id: `tpl_${Date.now()}`,
-        templateName: validated.name,
-        description: (form.description || "").trim(),
-        enabled: form.enabled !== false,
-        createTime: now,
-        updateTime: now,
-        flowNodes: validated.nodes,
-      });
-    } else {
-      const hit = allTemplates.value.find((t) => t.id === form.id);
-      if (!hit) return { message: "妯℃澘涓嶅瓨鍦ㄦ垨宸插垹闄�" };
-      hit.templateName = validated.name;
-      hit.description = (form.description || "").trim();
-      hit.enabled = form.enabled !== false;
-      hit.flowNodes = validated.nodes;
-      hit.updateTime = now;
+    const dto = mapTemplateToApi(form);
+    try {
+      if (formDialog.mode === "add") {
+        await addApprovalTemplate(dto);
+      } else {
+        await updateApprovalTemplate(dto);
+      }
+    } catch {
+      return false;
     }
-    persist();
     formDialog.visible = false;
     page.current = 1;
+    await fetchTemplateList();
+    if (dto.templateType === TEMPLATE_TYPE_BUILTIN) {
+      await loadBuiltinTemplates();
+    }
     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(`纭畾鍒犻櫎妯℃澘銆�${row.templateName}銆嶅悧锛焋, "鎻愮ず", {
-        type: "warning",
-        confirmButtonText: "鍒犻櫎",
-        cancelButtonText: "鍙栨秷",
-      });
+      await ElMessageBox.confirm(
+        `纭畾瑕佸垹闄ゅ鎵规ā鏉裤��${name}銆嶅悧锛熷垹闄ゅ悗涓嶅彲鎭㈠銆俙,
+        "鍒犻櫎纭",
+        {
+          type: "warning",
+          confirmButtonText: "纭畾鍒犻櫎",
+          cancelButtonText: "鍙栨秷",
+          distinguishCancelAndClose: true,
+          autofocus: false,
+        }
+      );
     } catch {
       return;
     }
-    const idx = allTemplates.value.findIndex((t) => t.id === row.id);
-    if (idx >= 0) {
-      allTemplates.value.splice(idx, 1);
-      persist();
+    try {
+      await deleteApprovalTemplate([row.id]);
+      ElMessage.success("鍒犻櫎鎴愬姛");
+      await fetchTemplateList();
+      if (row.templateType === TEMPLATE_TYPE_BUILTIN) {
+        await loadBuiltinTemplates();
+      }
+    } catch {
+      /* 閿欒鐢辨嫤鎴櫒鎻愮ず */
     }
-  }
-
-  function toggleEnabled(row) {
-    const hit = allTemplates.value.find((t) => t.id === row.id);
-    if (!hit) return;
-    hit.enabled = !hit.enabled;
-    hit.updateTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
-    persist();
   }
 
   return {
     Search,
+    TEMPLATE_TYPE_OPTIONS,
+    templateTypeLabel,
     activeTab,
     builtinTemplates,
+    builtinLoading,
+    loadBuiltinTemplates,
+    fetchTemplateList,
     nodeSignModeLabel,
     flowNodesSummary,
     searchForm,
@@ -249,12 +314,12 @@
     formRules,
     detailDialog,
     detailRow,
+    detailLoading,
     handleQuery,
     resetSearch,
     pagination,
     openFormDialog,
     openDetail,
     submitForm,
-    toggleEnabled,
   };
 }

--
Gitblit v1.9.3