From a1df9699594b0a0e46d26a0394eafb1eb030c68b Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期三, 20 五月 2026 17:42:09 +0800
Subject: [PATCH] 企业新闻

---
 src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue |  298 +++++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 179 insertions(+), 119 deletions(-)

diff --git a/src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue b/src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue
index f444153..13decff 100644
--- a/src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue
+++ b/src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue
@@ -1,4 +1,4 @@
-<!--OA妯″潡锛欵nterpriseNews 浼佷笟鏂伴椈锛堝垪琛ㄨ蛋瀹℃壒瀹炰緥锛屾柊澧�/淇敼淇濈暀鍘熻〃鍗� + 妯℃澘瀹℃壒娴佺▼锛�-->
+<!--OA妯″潡锛欵nterpriseNews 浼佷笟鏂伴椈锛坙istPage|save|update|delete锛屾柊寤轰繚鐣欏鎵规ā鏉匡級-->
 <template>
   <div class="app-container enterprise-news-page">
     <div class="search_form mb20">
@@ -7,7 +7,7 @@
         <el-input
           v-model="searchForm.keyword"
           style="width: 200px"
-          placeholder="鏍囬 / 缂栧彿 / 鎽樿"
+          placeholder="鏍囬"
           clearable
           :prefix-icon="Search"
           @keyup.enter="onSearch"
@@ -16,16 +16,16 @@
         <el-select v-model="searchForm.newsType" placeholder="鍏ㄩ儴" clearable style="width: 140px">
           <el-option v-for="opt in NEWS_TYPE_OPTIONS" :key="opt.value" :label="opt.label" :value="opt.value" />
         </el-select>
-        <span class="search_title" style="margin-left: 12px">瀹℃壒鐘舵�侊細</span>
+        <span class="search_title" style="margin-left: 12px">鐘舵�侊細</span>
         <el-select v-model="searchForm.status" placeholder="鍏ㄩ儴" clearable style="width: 120px">
           <el-option
-            v-for="opt in APPROVAL_STATUS_SEARCH_OPTIONS"
+            v-for="opt in ENTERPRISE_NEWS_STATUS_SEARCH_OPTIONS"
             :key="opt.value"
             :label="opt.label"
             :value="opt.value"
           />
         </el-select>
-        <span class="search_title" style="margin-left: 12px">鐢宠鏃ユ湡锛�</span>
+        <span class="search_title" style="margin-left: 12px">鍒涘缓鏃堕棿锛�</span>
         <el-date-picker
           v-model="searchForm.createTimeRange"
           type="daterange"
@@ -72,7 +72,6 @@
       @closed="onTemplateBindClosed"
     />
 
-    <!-- 鏂板缓 / 缂栬緫锛氬師浼佷笟鏂伴椈琛ㄥ崟 + 妯℃澘瀹℃壒娴佺▼ -->
     <el-dialog
       v-model="newsFormDialog.visible"
       :title="newsFormDialog.title"
@@ -171,45 +170,41 @@
         <el-form-item label="鏀跨瓥绫诲繀璇�">
           <el-switch v-model="newsForm.requireReadConfirm" active-text="闇�闃呰纭锛堜究浜庣粺璁℃湭璇伙級" />
         </el-form-item>
-        <el-form-item label="鍙戝竷浜�">
-          <el-input v-model="newsForm.publisherName" placeholder="濡傦細浜哄姏璧勬簮閮�" maxlength="50" />
-        </el-form-item>
 
-        <template v-if="activeTemplate">
+        <template v-if="hasApprovalTemplate">
           <el-divider content-position="left">瀹℃壒娴佺▼</el-divider>
           <el-form-item label="瀹℃壒妯℃澘">
-            <span class="template-name">{{ activeTemplate.label || submitForm.templateName }}</span>
+            <span class="template-name">{{ approvalTemplateLabel }}</span>
           </el-form-item>
-          <el-form-item label="瀹℃壒娴佺▼" required>
+          <el-form-item v-if="activeTemplate" label="瀹℃壒娴佺▼" required>
             <TemplateFlowEditor v-model="submitForm.flowNodes" :user-options="flowUserOptions" />
             <p class="section-tip">娴佺▼涓庡鎵逛汉鐢辨ā鏉块缃紝鍙寜闇�寰皟鑺傜偣瀹℃壒浜恒��</p>
           </el-form-item>
         </template>
-        <el-alert v-else type="warning" show-icon :closable="false" title="璇峰厛閫氳繃銆屾柊寤烘柊闂汇�嶉�夋嫨瀹℃壒妯℃澘" />
+        <el-alert
+          v-else-if="!isNewsEdit"
+          type="warning"
+          show-icon
+          :closable="false"
+          title="璇峰厛閫氳繃銆屾柊寤烘柊闂汇�嶉�夋嫨瀹℃壒妯℃澘"
+        />
       </el-form>
       <template v-if="!newsFormDialog.readonly" #footer>
         <el-button @click="newsFormDialog.visible = false">鍙� 娑�</el-button>
-        <el-button :loading="submitSaving" @click="onNewsSave('draft')">瀛樿崏绋�</el-button>
-        <el-button type="warning" :loading="submitSaving" @click="onNewsSave('submit_review')">
+        <el-button :loading="newsSaving" @click="onNewsSave('draft')">瀛樿崏绋�</el-button>
+        <el-button type="warning" :loading="newsSaving" @click="onNewsSave('submit_review')">
           鎻愪氦瀹℃牳
         </el-button>
-        <el-button type="primary" :loading="submitSaving" @click="onNewsSave('submit_review')">
+        <el-button type="primary" :loading="newsSaving" @click="onNewsSave('submit_review')">
           淇� 瀛�
         </el-button>
       </template>
     </el-dialog>
 
-    <!-- 璇︽儏 -->
     <el-dialog v-model="detailDialog.visible" title="鏂伴椈璇︽儏" width="880px" append-to-body destroy-on-close>
       <NewsDetailPanel :row="detailNewsRow" />
-      <el-divider content-position="left">瀹℃壒淇℃伅</el-divider>
-      <ApproveDetailPanel :row="detailRow" />
       <template #footer>
-        <el-button
-          v-if="canEditBusinessInstanceRow(detailRow)"
-          type="primary"
-          @click="openNewsEditFromDetail"
-        >
+        <el-button v-if="canEditEnterpriseNewsRow(detailRow)" type="primary" @click="openNewsEditFromDetail">
           淇敼
         </el-button>
         <el-button @click="detailDialog.visible = false">鍏� 闂�</el-button>
@@ -220,22 +215,27 @@
 
 <script setup>
 import { Plus, RefreshRight, Search } from "@element-plus/icons-vue";
-import { ElMessage } from "element-plus";
+import { ElMessage, ElMessageBox } from "element-plus";
+import {
+  deleteEnterpriseNews,
+  saveEnterpriseNews,
+  updateEnterpriseNews,
+} from "@/api/officeProcessAutomation/enterpriseNews.js";
 import { computed, onMounted, reactive, ref } from "vue";
-import useUserStore from "@/store/modules/user";
 import Editor from "@/components/Editor/index.vue";
 import FileUpload from "@/components/AttachmentUpload/file/index.vue";
-import { APPROVAL_STATUS_SEARCH_OPTIONS } from "../../ApproveManage/approve-list/approveListConstants.js";
-import ApproveDetailPanel from "../../ApproveManage/approve-list/components/ApproveDetailPanel.vue";
-import { buildEditFormFromInstanceRow } from "../../ApproveManage/approve-list/approveListConstants.js";
 import ApprovalTemplateBindDialog from "../../ApproveManage/approve-shared/components/ApprovalTemplateBindDialog.vue";
 import TemplateFlowEditor from "../../ApproveManage/approve-template/components/TemplateFlowEditor.vue";
 import {
   applyBindingToForm,
   validateTemplateBinding,
 } from "../../ApproveManage/approve-shared/approvalTemplateBindingUtils.js";
+import { createEmptySubmitForm } from "../../ApproveManage/approve-list/approveListConstants.js";
 import { APPROVAL_MODULE_KEYS } from "../../ApproveManage/approve-shared/approvalModuleRegistry.js";
-import { useApprovalInstanceModule } from "../../ApproveManage/approve-shared/useApprovalInstanceModule.js";
+import {
+  applyBindingToForm,
+  validateTemplateBinding,
+} from "../../ApproveManage/approve-shared/approvalTemplateBindingUtils.js";
 import { useFlowUserOptions } from "../../ApproveManage/approve-shared/useFlowUserOptions.js";
 import NewsDetailPanel from "./components/NewsDetailPanel.vue";
 import {
@@ -245,18 +245,18 @@
   PUBLISH_ROLE_OPTIONS,
   DEPT_OPTIONS,
   createEmptyForm,
+  ENTERPRISE_NEWS_STATUS_SEARCH_OPTIONS,
   newsTypeColor,
   newsTypeLabel,
   validateNewsForm,
 } from "./enterpriseNewsUtils.js";
 import {
-  enrichEnterpriseNewsListRow,
-  extractEnterpriseNewsFromRow,
-  syncNewsFormToSubmitPayload,
+  buildEnterpriseNewsSaveDto,
   buildEnterpriseNewsTableColumns,
-} from "./enterpriseNewsApprovalBridge.js";
-
-const userStore = useUserStore();
+  canEditEnterpriseNewsRow,
+  mapApiRowToNewsForm,
+} from "./enterpriseNewsMappers.js";
+import { useEnterpriseNewsList } from "./useEnterpriseNewsList.js";
 
 const searchForm = reactive({
   keyword: "",
@@ -266,6 +266,8 @@
 });
 
 const newsFormDialog = reactive({ visible: false, title: "", mode: "add", readonly: false });
+const detailDialog = reactive({ visible: false });
+const detailRow = ref({});
 const newsForm = reactive(createEmptyForm());
 const newsFormRef = ref();
 const galleryInput = ref("");
@@ -276,66 +278,44 @@
   readScope: [{ required: true, message: "璇烽�夋嫨闃呰鑼冨洿", trigger: "change" }],
 };
 
-const mod = useApprovalInstanceModule({
-  moduleKey: APPROVAL_MODULE_KEYS.ENTERPRISE_NEWS,
-  enrichListRow: enrichEnterpriseNewsListRow,
-  buildExtraListParams(sf) {
-    const extra = {};
-    const kw = (sf?.keyword || "").trim();
-    if (kw) extra.title = kw;
-    if (sf?.newsType) extra.newsType = sf.newsType;
-    return extra;
-  },
-  async beforeSave(submitForm) {
-    const v = validateNewsForm(newsForm);
-    if (!v.ok) {
-      ElMessage.warning(v.message);
-      throw new Error(v.message);
-    }
-    if (!activeTemplate.value) {
-      ElMessage.warning("璇峰厛閫夋嫨瀹℃壒妯℃澘");
-      throw new Error("no template");
-    }
-    const bindingCheck = validateTemplateBinding({ flowNodes: submitForm.flowNodes });
-    if (!bindingCheck.ok) {
-      ElMessage.warning(bindingCheck.message);
-      throw new Error(bindingCheck.message);
-    }
-    syncNewsFormToSubmitPayload(newsForm, submitForm);
-  },
-});
+const newsList = useEnterpriseNewsList();
+const { tableData, tableLoading, page, handleQuery: fetchNewsList, pagination: paginateNewsList } =
+  newsList;
 
-const {
-  tableData,
-  tableLoading,
-  page,
-  detailDialog,
-  detailRow,
-  submitDialog,
-  submitForm,
-  submitSaving,
-  isSubmitEdit,
-  activeTemplate,
-  templateBindVisible,
-  pendingTemplateBinding,
-  submitEditRow,
-  handleQuery,
-  initModuleList,
-  pagination,
-  openAddWithTemplate,
-  onTemplateBound,
-  resetSubmitForm,
-  submitInstanceForm,
-  removeInstance,
-  canEditBusinessInstanceRow,
-} = mod;
+const submitForm = reactive(createEmptySubmitForm(""));
+const templateBindVisible = ref(false);
+const pendingTemplateBinding = ref(null);
+const newsSaving = ref(false);
+
+const isNewsEdit = computed(() => newsFormDialog.mode === "edit");
+const activeTemplate = computed(() => submitForm.templateSnapshot || null);
+const hasApprovalTemplate = computed(
+  () => Boolean(activeTemplate.value || newsForm.templateId)
+);
+const approvalTemplateLabel = computed(
+  () =>
+    activeTemplate.value?.label ||
+    newsForm.templateName ||
+    submitForm.templateName ||
+    "鈥�"
+);
 
 const { flowUserOptions, loadFlowUsers } = useFlowUserOptions();
 
-const detailNewsRow = computed(() => {
-  if (!detailRow.value?.id) return {};
-  return extractEnterpriseNewsFromRow(detailRow.value);
-});
+function openAddWithTemplate() {
+  pendingTemplateBinding.value = null;
+  templateBindVisible.value = true;
+}
+
+function onTemplateBound(binding) {
+  pendingTemplateBinding.value = binding;
+}
+
+function resetSubmitForm() {
+  Object.assign(submitForm, createEmptySubmitForm(""));
+}
+
+const detailNewsRow = computed(() => mapApiRowToNewsForm(detailRow.value));
 
 const tableColumn = ref(
   buildEnterpriseNewsTableColumns(() => [
@@ -343,13 +323,14 @@
     {
       name: "淇敼",
       type: "text",
-      disabled: (row) => !canEditBusinessInstanceRow(row),
+      disabled: (row) => !canEditEnterpriseNewsRow(row),
       clickFun: (row) => openNewsEdit(row),
     },
     {
       name: "鍒犻櫎",
       type: "danger",
-      clickFun: (row) => removeInstance(row),
+      disabled: (row) => !canEditEnterpriseNewsRow(row),
+      clickFun: (row) => handleNewsDelete(row),
     },
   ])
 );
@@ -364,11 +345,9 @@
   newsFormDialog.title =
     mode === "add" ? "鏂板缓浼佷笟鏂伴椈" : mode === "edit" ? "缂栬緫浼佷笟鏂伴椈" : "鏌ョ湅浼佷笟鏂伴椈";
   if (mode === "add") {
-    resetNewsForm({
-      publisherName: userStore?.nickName || userStore?.name || "褰撳墠鐢ㄦ埛",
-    });
+    resetNewsForm();
   } else if (row) {
-    resetNewsForm(extractEnterpriseNewsFromRow(row));
+    resetNewsForm(mapApiRowToNewsForm(row));
   }
   newsFormDialog.visible = true;
 }
@@ -379,19 +358,23 @@
   pendingTemplateBinding.value = null;
   resetSubmitForm();
   applyBindingToForm(submitForm, binding);
-  submitDialog.mode = "add";
-  submitEditRow.value = null;
+  if (binding.templateId) {
+    newsForm.templateId = binding.templateId;
+    newsForm.templateName = binding.templateName || "";
+  }
   openNewsFormDialog("add");
 }
 
 function openNewsEdit(row) {
-  if (!canEditBusinessInstanceRow(row)) {
-    ElMessage.warning("杩涜涓垨宸插畬鎴愮殑瀹℃壒涓嶅彲淇敼");
+  if (!canEditEnterpriseNewsRow(row)) {
+    ElMessage.warning("褰撳墠鐘舵�佷笉鍙慨鏀�");
     return;
   }
-  submitDialog.mode = "edit";
-  submitEditRow.value = { ...row };
-  Object.assign(submitForm, buildEditFormFromInstanceRow(row));
+  resetSubmitForm();
+  if (row?.templateId != null) {
+    submitForm.templateId = row.templateId;
+    submitForm.templateName = row.templateName || "";
+  }
   openNewsFormDialog("edit", row);
 }
 
@@ -404,6 +387,40 @@
   const row = detailRow.value;
   detailDialog.visible = false;
   openNewsEdit(row);
+}
+
+async function handleNewsDelete(row) {
+  if (!canEditEnterpriseNewsRow(row)) {
+    ElMessage.warning("褰撳墠鐘舵�佷笉鍙垹闄�");
+    return;
+  }
+  if (row?.id == null || row.id === "") {
+    ElMessage.warning("鏃犳硶鍒犻櫎锛氱己灏戞柊闂� ID");
+    return;
+  }
+  const title = (row.title || "").trim() || "璇ユ潯鏂伴椈";
+  try {
+    await ElMessageBox.confirm(
+      `纭畾瑕佸垹闄ゃ��${title}銆嶅悧锛熷垹闄ゅ悗涓嶅彲鎭㈠銆俙,
+      "鍒犻櫎纭",
+      {
+        type: "warning",
+        confirmButtonText: "纭畾鍒犻櫎",
+        cancelButtonText: "鍙栨秷",
+        distinguishCancelAndClose: true,
+        autofocus: false,
+      }
+    );
+  } catch {
+    return;
+  }
+  try {
+    await deleteEnterpriseNews([row.id]);
+    ElMessage.success("鍒犻櫎鎴愬姛");
+    await fetchNewsList(searchForm);
+  } catch {
+    /* 閿欒鐢辫姹傛嫤鎴櫒鎻愮ず */
+  }
 }
 
 function onNewsFormClosed() {
@@ -425,19 +442,67 @@
     ElMessage.warning("璇峰畬鍠勮〃鍗曞繀濉」鍚庡啀淇濆瓨");
     return;
   }
-  if (action === "draft") newsForm.publishStatus = "draft";
-  else newsForm.publishStatus = "pending_review";
-  const ok = await submitInstanceForm({ skipValidate: true });
-  if (ok) {
+  const v = validateNewsForm(newsForm);
+  if (!v.ok) {
+    ElMessage.warning(v.message);
+    return;
+  }
+  const status = action === "draft" ? "DRAFT" : "PENDING";
+  newsForm.publishStatus = status;
+
+  if (!isNewsEdit.value) {
+    const templateId = newsForm.templateId || submitForm.templateId;
+    if (!templateId) {
+      ElMessage.warning("璇峰厛閫夋嫨瀹℃壒妯℃澘");
+      return;
+    }
+    if (!newsForm.templateId) newsForm.templateId = templateId;
+    if (!newsForm.templateName && submitForm.templateName) {
+      newsForm.templateName = submitForm.templateName;
+    }
+    if (action !== "draft") {
+      const bindingCheck = validateTemplateBinding({ flowNodes: submitForm.flowNodes });
+      if (!bindingCheck.ok) {
+        ElMessage.warning(bindingCheck.message);
+        return;
+      }
+    }
+  } else if (!newsForm.templateId && submitForm.templateId) {
+    newsForm.templateId = submitForm.templateId;
+    newsForm.templateName = submitForm.templateName || newsForm.templateName;
+  }
+
+  const dto = buildEnterpriseNewsSaveDto(newsForm, { status });
+  if (isNewsEdit.value) {
+    if (dto.id == null) {
+      ElMessage.warning("鏃犳硶淇敼锛氱己灏戞柊闂� ID");
+      return;
+    }
+  }
+
+  if (newsSaving.value) return;
+  newsSaving.value = true;
+  try {
+    if (isNewsEdit.value) {
+      await updateEnterpriseNews(dto);
+    } else {
+      await saveEnterpriseNews(dto);
+    }
     newsFormDialog.visible = false;
     const msg =
-      action === "draft" ? "宸蹭繚瀛樿崏绋�" : isSubmitEdit.value ? "淇敼鎴愬姛" : "宸叉彁浜ゅ鏍�";
+      action === "draft" ? "宸蹭繚瀛樿崏绋�" : isNewsEdit.value ? "淇敼鎴愬姛" : "宸叉彁浜ゅ鏍�";
     ElMessage.success(msg);
+    if (!isNewsEdit.value) page.current = 1;
+    await fetchNewsList(searchForm);
+  } catch {
+    /* 閿欒鐢辫姹傛嫤鎴櫒鎻愮ず */
+  } finally {
+    newsSaving.value = false;
   }
 }
 
 function onSearch() {
-  handleQuery(searchForm);
+  fetchNewsList(searchForm);
 }
 
 function resetSearch() {
@@ -449,17 +514,12 @@
 }
 
 function onPagination(obj) {
-  pagination(obj, searchForm);
+  paginateNewsList(obj, searchForm);
 }
 
-onMounted(async () => {
-  try {
-    localStorage.removeItem("oa_enterprise_news_v1");
-  } catch {
-    /* 娓呴櫎鍘嗗彶鏈湴婕旂ず缂撳瓨 */
-  }
+onMounted(() => {
   loadFlowUsers();
-  await initModuleList(searchForm);
+  fetchNewsList(searchForm);
 });
 </script>
 

--
Gitblit v1.9.3