From 93b8ceac34e2fbd5c57fe5ab4f5bac32c85408aa Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期五, 22 五月 2026 15:37:09 +0800
Subject: [PATCH] fix(hr): 修正岗位字段映射
---
src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue | 619 ++++++++++++++++++++++++++++++++-----------------------
1 files changed, 362 insertions(+), 257 deletions(-)
diff --git a/src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue b/src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue
index a8b743a..f263a41 100644
--- a/src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue
+++ b/src/views/officeProcessAutomation/EnterpriseNews/news-manage/index.vue
@@ -1,29 +1,33 @@
-<!--OA妯″潡锛欵nterpriseNews 浼佷笟鏂伴椈-->
+<!--OA妯″潡锛欵nterpriseNews 浼佷笟鏂伴椈锛坙istPage|save|update|delete锛屾柊寤轰繚鐣欏鎵规ā鏉匡級-->
<template>
<div class="app-container enterprise-news-page">
-
<div class="search_form mb20">
<div class="search_fields">
<span class="search_title">鍏抽敭璇嶏細</span>
<el-input
v-model="searchForm.keyword"
style="width: 200px"
- placeholder="鏍囬 / 缂栧彿 / 鎽樿"
+ placeholder="鏍囬"
clearable
:prefix-icon="Search"
- @keyup.enter="handleQuery"
+ @keyup.enter="onSearch"
/>
<span class="search_title" style="margin-left: 12px">鍒嗙被锛�</span>
<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>
- <el-select v-model="searchForm.publishStatus" placeholder="鍏ㄩ儴" clearable style="width: 120px">
- <el-option v-for="opt in PUBLISH_STATUS_OPTIONS" :key="opt.value" :label="opt.label" :value="opt.value" />
+ <el-select v-model="searchForm.status" placeholder="鍏ㄩ儴" clearable style="width: 120px">
+ <el-option
+ 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.publishTimeRange"
+ v-model="searchForm.createTimeRange"
type="daterange"
range-separator="-"
start-placeholder="寮�濮�"
@@ -33,11 +37,11 @@
style="width: 260px"
clearable
/>
- <el-button type="primary" :icon="Search" class="ml10" @click="handleQuery">鎼滅储</el-button>
+ <el-button type="primary" :icon="Search" class="ml10" @click="onSearch">鎼滅储</el-button>
<el-button :icon="RefreshRight" @click="resetSearch">閲嶇疆</el-button>
</div>
<div class="search_actions">
- <el-button type="primary" :icon="Plus" @click="openFormDialog('add')">鏂板缓鏂伴椈</el-button>
+ <el-button type="primary" :icon="Plus" @click="openAddWithTemplate">鏂板缓鏂伴椈</el-button>
</div>
</div>
@@ -50,7 +54,7 @@
:isSelection="false"
:tableLoading="tableLoading"
:total="page.total"
- @pagination="pagination"
+ @pagination="onPagination"
>
<template #newsType="{ row }">
<span class="news-type-tag" :style="{ color: newsTypeColor(row.newsType) }">
@@ -60,34 +64,41 @@
</PIMTable>
</div>
- <!-- 鏂板缓 / 缂栬緫 -->
+ <ApprovalTemplateBindDialog
+ v-model:visible="templateBindVisible"
+ :module-key="APPROVAL_MODULE_KEYS.ENTERPRISE_NEWS"
+ skip-form-confirm
+ @confirm="onTemplateBound"
+ @closed="onTemplateBindClosed"
+ />
+
<el-dialog
- v-model="formDialog.visible"
- :title="formDialog.title"
+ v-model="newsFormDialog.visible"
+ :title="newsFormDialog.title"
width="960px"
append-to-body
destroy-on-close
class="news-form-dialog"
- @closed="formRef?.resetFields?.()"
+ @closed="onNewsFormClosed"
>
<el-form
- ref="formRef"
- :model="form"
- :rules="formRules"
+ ref="newsFormRef"
+ :model="newsForm"
+ :rules="newsFormRules"
label-width="110px"
- :disabled="formDialog.readonly"
+ :disabled="newsFormDialog.readonly"
>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="鏂伴椈鍒嗙被" prop="newsType">
- <el-select v-model="form.newsType" placeholder="璇烽�夋嫨" style="width: 100%">
+ <el-select v-model="newsForm.newsType" placeholder="璇烽�夋嫨" style="width: 100%">
<el-option v-for="opt in NEWS_TYPE_OPTIONS" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="鎺掔増妯℃澘">
- <el-select v-model="form.layoutTemplate" style="width: 100%">
+ <el-select v-model="newsForm.layoutTemplate" style="width: 100%">
<el-option
v-for="opt in LAYOUT_TEMPLATE_OPTIONS"
:key="opt.value"
@@ -99,29 +110,29 @@
</el-col>
</el-row>
<el-form-item label="鏍囬" prop="title">
- <el-input v-model="form.title" placeholder="鏂伴椈鏍囬" maxlength="100" show-word-limit />
+ <el-input v-model="newsForm.title" placeholder="鏂伴椈鏍囬" maxlength="100" show-word-limit />
</el-form-item>
<el-form-item label="鎽樿">
- <el-input v-model="form.summary" type="textarea" :rows="2" maxlength="300" show-word-limit />
+ <el-input v-model="newsForm.summary" type="textarea" :rows="2" maxlength="300" show-word-limit />
</el-form-item>
<el-form-item label="姝f枃" prop="contentHtml">
- <Editor v-model="form.contentHtml" :min-height="280" />
+ <Editor v-model="newsForm.contentHtml" :min-height="280" />
</el-form-item>
<el-form-item label="闄勪欢">
- <FileUpload v-model:file-list="form.attachmentList" :limit="10" button-text="涓婁紶 PDF / 鏂囨。" />
+ <FileUpload v-model:file-list="newsForm.attachmentList" :limit="10" button-text="涓婁紶 PDF / 鏂囨。" />
</el-form-item>
- <el-form-item v-if="form.layoutTemplate === 'gallery'" label="鍥鹃泦/瑙嗛">
+ <el-form-item v-if="newsForm.layoutTemplate === 'gallery'" label="鍥鹃泦/瑙嗛">
<el-input
v-model="galleryInput"
placeholder="杈撳叆璧勬簮鍚嶇О鍚庡洖杞︽坊鍔狅紙婕旂ず锛�"
@keyup.enter="addGalleryItem"
/>
<el-tag
- v-for="(m, i) in form.mediaList"
+ v-for="(m, i) in newsForm.mediaList"
:key="i"
closable
class="media-tag"
- @close="form.mediaList.splice(i, 1)"
+ @close="newsForm.mediaList.splice(i, 1)"
>
{{ m.name }}
</el-tag>
@@ -131,276 +142,380 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="缂栬緫瑙掕壊">
- <el-select v-model="form.editorRole" style="width: 100%">
+ <el-select v-model="newsForm.editorRole" style="width: 100%">
<el-option v-for="opt in PUBLISH_ROLE_OPTIONS" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="瀹℃牳瑙掕壊">
- <el-select v-model="form.reviewerRole" style="width: 100%">
+ <el-select v-model="newsForm.reviewerRole" style="width: 100%">
<el-option v-for="opt in PUBLISH_ROLE_OPTIONS" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="闃呰鑼冨洿" prop="readScope">
- <el-radio-group v-model="form.readScope">
+ <el-radio-group v-model="newsForm.readScope">
<el-radio v-for="opt in READ_SCOPE_OPTIONS" :key="opt.value" :value="opt.value">
{{ opt.label }}
</el-radio>
</el-radio-group>
</el-form-item>
- <el-form-item v-if="form.readScope === 'department'" label="鍙閮ㄩ棬">
- <el-select v-model="form.targetDeptIds" multiple placeholder="閫夋嫨閮ㄩ棬" style="width: 100%">
+ <el-form-item v-if="newsForm.readScope === 'department'" label="鍙閮ㄩ棬">
+ <el-select v-model="newsForm.targetDeptIds" multiple placeholder="閫夋嫨閮ㄩ棬" style="width: 100%">
<el-option v-for="d in DEPT_OPTIONS" :key="d.value" :label="d.label" :value="d.value" />
</el-select>
</el-form-item>
<el-form-item label="鏀跨瓥绫诲繀璇�">
- <el-switch v-model="form.requireReadConfirm" active-text="闇�闃呰纭锛堜究浜庣粺璁℃湭璇伙級" />
+ <el-switch v-model="newsForm.requireReadConfirm" active-text="闇�闃呰纭锛堜究浜庣粺璁℃湭璇伙級" />
</el-form-item>
- <el-form-item label="鍙戝竷浜�">
- <el-input v-model="form.publisherName" placeholder="濡傦細浜哄姏璧勬簮閮�" maxlength="50" />
- </el-form-item>
+
+ <template v-if="hasApprovalTemplate">
+ <el-divider content-position="left">瀹℃壒娴佺▼</el-divider>
+ <el-form-item label="瀹℃壒妯℃澘">
+ <span class="template-name">{{ approvalTemplateLabel }}</span>
+ </el-form-item>
+ <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-if="!isNewsEdit"
+ type="warning"
+ show-icon
+ :closable="false"
+ title="璇峰厛閫氳繃銆屾柊寤烘柊闂汇�嶉�夋嫨瀹℃壒妯℃澘"
+ />
</el-form>
- <template v-if="!formDialog.readonly" #footer>
- <el-button @click="formDialog.visible = false">鍙� 娑�</el-button>
- <el-button @click="onSave('save')">瀛樿崏绋�</el-button>
- <el-button type="warning" @click="onSave('submit_review')">鎻愪氦瀹℃牳</el-button>
- <el-button type="primary" @click="onSave('publish')">鐩存帴鍙戝竷</el-button>
+ <template v-if="!newsFormDialog.readonly" #footer>
+ <el-button @click="newsFormDialog.visible = false">鍙� 娑�</el-button>
+ <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="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="detailRow"
- @like="onDetailLike"
- @comment="onDetailComment"
- />
+ <NewsDetailPanel :row="detailNewsRow" />
<template #footer>
- <el-button
- v-if="detailRow.publishStatus === 'published' && getUnreadEmployees(detailRow).length"
- type="warning"
- @click="openUnreadFromDetail"
- >
- 鏈鎻愰啋
+ <el-button v-if="canEditEnterpriseNewsRow(detailRow)" type="primary" @click="openNewsEditFromDetail">
+ 淇敼
</el-button>
- <el-button @click="openVersionFromDetail">鐗堟湰鐣欒瘉</el-button>
<el-button @click="detailDialog.visible = false">鍏� 闂�</el-button>
</template>
- </el-dialog>
-
- <!-- 鏈鎻愰啋 -->
- <el-dialog
- v-model="unreadDialog.visible"
- :title="`鏈槄璇诲憳宸� 路 ${unreadDialog.row?.title || ''}`"
- width="720px"
- append-to-body
- destroy-on-close
- >
- <el-alert type="warning" show-icon :closable="false" class="mb12">
- 鏀跨瓥浼犺揪鍦烘櫙锛氬彂甯冩柊鑰冨嫟鍒跺害绛夊繀璇讳俊鎭悗锛屽彲鍕鹃�夋湭璇诲憳宸ョ敱 HR 瀹氬悜鎻愰啋锛堟紨绀烘暟鎹紝鍚庢湡瀵规帴娑堟伅涓績锛夈��
- </el-alert>
- <div class="unread-toolbar mb12">
- <el-button size="small" @click="selectAllUnread">鍏ㄩ�夋湭璇�</el-button>
- <span class="unread-stat">鍏� {{ unreadList.length }} 浜烘湭璇�</span>
- </div>
- <el-table
- :data="unreadList"
- border
- size="small"
- max-height="360"
- @selection-change="onUnreadSelectionChange"
- >
- <el-table-column type="selection" width="48" />
- <el-table-column prop="employeeNo" label="宸ュ彿" width="100" />
- <el-table-column prop="name" label="濮撳悕" width="90" />
- <el-table-column prop="deptName" label="閮ㄩ棬" min-width="120" />
- </el-table>
- <el-divider v-if="unreadDialog.row?.remindLogs?.length" content-position="left">鎻愰啋璁板綍</el-divider>
- <el-timeline v-if="unreadDialog.row?.remindLogs?.length">
- <el-timeline-item
- v-for="(log, i) in unreadDialog.row.remindLogs"
- :key="i"
- :timestamp="log.time"
- >
- {{ log.operator }} 宸插悜 {{ log.count }} 浜哄彂閫侀槄璇绘彁閱�
- </el-timeline-item>
- </el-timeline>
- <template #footer>
- <el-button type="primary" @click="onSendRemind">鍙戦�佸畾鍚戞彁閱�</el-button>
- <el-button @click="unreadDialog.visible = false">鍏� 闂�</el-button>
- </template>
- </el-dialog>
-
- <!-- 鐗堟湰鐣欒瘉 -->
- <el-dialog
- v-model="versionDialog.visible"
- :title="`鍘嗗彶鐗堟湰鐣欒瘉 路 ${versionDialog.row?.title || ''}`"
- width="800px"
- append-to-body
- destroy-on-close
- >
- <el-alert type="info" show-icon :closable="false" class="mb12">
- 浜夎鍙戠敓鏃跺彲鏌ラ槄鍘嗗彶鐗堟湰锛岃瘉鏄庡綋鏃跺彂甯冨唴瀹逛笌鍙戝竷鏃堕棿锛堝悎瑙勭暀璇侊級銆�
- </el-alert>
- <el-descriptions :column="2" border class="mb16">
- <el-descriptions-item label="褰撳墠鐗堟湰">v{{ versionDialog.row?.versionNo || 1 }}</el-descriptions-item>
- <el-descriptions-item label="鏈�杩戝彂甯�">{{ versionDialog.row?.publishTime || "鈥�" }}</el-descriptions-item>
- </el-descriptions>
- <el-table :data="versionList" border size="small" empty-text="鏆傛棤鍘嗗彶鐗堟湰">
- <el-table-column prop="versionNo" label="鐗堟湰" width="70" align="center" />
- <el-table-column prop="title" label="鏍囬" min-width="160" show-overflow-tooltip />
- <el-table-column prop="changeNote" label="鍙樻洿璇存槑" width="120" />
- <el-table-column prop="publishTime" label="鍙戝竷鏃堕棿" width="170" />
- <el-table-column prop="archivedAt" label="褰掓。鏃堕棿" width="170" />
- <el-table-column label="鎿嶄綔" width="90" align="center">
- <template #default="{ row: ver }">
- <el-button type="primary" link @click="previewVersion(ver)">鏌ョ湅</el-button>
- </template>
- </el-table-column>
- </el-table>
- <template #footer>
- <el-button @click="versionDialog.visible = false">鍏� 闂�</el-button>
- </template>
- </el-dialog>
-
- <!-- 鐗堟湰棰勮 -->
- <el-dialog v-model="versionPreview.visible" title="鍘嗗彶鐗堟湰鍐呭" width="640px" append-to-body>
- <p class="version-meta">
- v{{ versionPreview.data?.versionNo }} 路 {{ versionPreview.data?.changeNote }} 路
- {{ versionPreview.data?.publishTime }}
- </p>
- <div class="version-html" v-html="versionPreview.data?.contentHtml || ''" />
</el-dialog>
</div>
</template>
<script setup>
-import { Plus, RefreshRight } from "@element-plus/icons-vue";
-import { ElMessage } from "element-plus";
+import { Plus, RefreshRight, Search } from "@element-plus/icons-vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import {
+ deleteEnterpriseNews,
+ saveEnterpriseNews,
+ updateEnterpriseNews,
+} from "@/api/officeProcessAutomation/enterpriseNews.js";
import { computed, onMounted, reactive, ref } from "vue";
import Editor from "@/components/Editor/index.vue";
import FileUpload from "@/components/AttachmentUpload/file/index.vue";
-import { newsTypeColor } from "./enterpriseNewsUtils.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 { useFlowUserOptions } from "../../ApproveManage/approve-shared/useFlowUserOptions.js";
import NewsDetailPanel from "./components/NewsDetailPanel.vue";
-import { useEnterpriseNews } from "./useEnterpriseNews.js";
-
-const {
- Search,
+import {
NEWS_TYPE_OPTIONS,
- PUBLISH_STATUS_OPTIONS,
LAYOUT_TEMPLATE_OPTIONS,
READ_SCOPE_OPTIONS,
PUBLISH_ROLE_OPTIONS,
DEPT_OPTIONS,
+ createEmptyForm,
+ ENTERPRISE_NEWS_STATUS_SEARCH_OPTIONS,
+ newsTypeColor,
newsTypeLabel,
- searchForm,
- tableLoading,
- page,
- tableData,
- tableColumn,
- formDialog,
- form,
- formRef,
- formRules,
- detailDialog,
- detailRow,
- unreadDialog,
- unreadList,
- versionDialog,
- getUnreadEmployees,
- handleQuery,
- resetSearch,
- pagination,
- openFormDialog,
- openDetail,
- openUnreadRemind,
- openVersionHistory,
- saveForm,
- sendUnreadRemind,
- toggleLike,
- addComment,
-} = useEnterpriseNews();
+ validateNewsForm,
+} from "./enterpriseNewsUtils.js";
+import {
+ buildEnterpriseNewsSaveDto,
+ buildEnterpriseNewsTableColumns,
+ canEditEnterpriseNewsRow,
+ mapApiRowToNewsForm,
+} from "./enterpriseNewsMappers.js";
+import { useEnterpriseNewsList } from "./useEnterpriseNewsList.js";
-const galleryInput = ref("");
-const unreadSelected = ref([]);
-const versionPreview = reactive({ visible: false, data: null });
-
-const versionList = computed(() => {
- const row = versionDialog.row;
- if (!row) return [];
- const history = [...(row.versions || [])];
- return history.sort((a, b) => (b.versionNo || 0) - (a.versionNo || 0));
+const searchForm = reactive({
+ keyword: "",
+ newsType: "",
+ status: "",
+ createTimeRange: null,
});
+
+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("");
+
+const newsFormRules = {
+ title: [{ required: true, message: "璇疯緭鍏ユ柊闂绘爣棰�", trigger: "blur" }],
+ newsType: [{ required: true, message: "璇烽�夋嫨鏂伴椈鍒嗙被", trigger: "change" }],
+ readScope: [{ required: true, message: "璇烽�夋嫨闃呰鑼冨洿", trigger: "change" }],
+};
+
+const newsList = useEnterpriseNewsList();
+const { tableData, tableLoading, page, handleQuery: fetchNewsList, pagination: paginateNewsList } =
+ newsList;
+
+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();
+
+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(() => [
+ { name: "璇︽儏", type: "text", clickFun: (row) => openNewsDetail(row) },
+ {
+ name: "淇敼",
+ type: "text",
+ disabled: (row) => !canEditEnterpriseNewsRow(row),
+ clickFun: (row) => openNewsEdit(row),
+ },
+ {
+ name: "鍒犻櫎",
+ type: "danger",
+ disabled: (row) => !canEditEnterpriseNewsRow(row),
+ clickFun: (row) => handleNewsDelete(row),
+ },
+ ])
+);
+
+function resetNewsForm(target = createEmptyForm()) {
+ Object.assign(newsForm, createEmptyForm(), target);
+}
+
+function openNewsFormDialog(mode, row) {
+ newsFormDialog.mode = mode;
+ newsFormDialog.readonly = mode === "view";
+ newsFormDialog.title =
+ mode === "add" ? "鏂板缓浼佷笟鏂伴椈" : mode === "edit" ? "缂栬緫浼佷笟鏂伴椈" : "鏌ョ湅浼佷笟鏂伴椈";
+ if (mode === "add") {
+ resetNewsForm();
+ } else if (row) {
+ resetNewsForm(mapApiRowToNewsForm(row));
+ }
+ newsFormDialog.visible = true;
+}
+
+function onTemplateBindClosed() {
+ const binding = pendingTemplateBinding.value;
+ if (!binding) return;
+ pendingTemplateBinding.value = null;
+ resetSubmitForm();
+ applyBindingToForm(submitForm, binding);
+ if (binding.templateId) {
+ newsForm.templateId = binding.templateId;
+ newsForm.templateName = binding.templateName || "";
+ }
+ openNewsFormDialog("add");
+}
+
+function openNewsEdit(row) {
+ if (!canEditEnterpriseNewsRow(row)) {
+ ElMessage.warning("褰撳墠鐘舵�佷笉鍙慨鏀�");
+ return;
+ }
+ resetSubmitForm();
+ if (row?.templateId != null) {
+ submitForm.templateId = row.templateId;
+ submitForm.templateName = row.templateName || "";
+ }
+ openNewsFormDialog("edit", row);
+}
+
+function openNewsDetail(row) {
+ detailRow.value = { ...row };
+ detailDialog.visible = true;
+}
+
+function openNewsEditFromDetail() {
+ 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() {
+ newsFormRef.value?.resetFields?.();
+}
function addGalleryItem() {
const name = (galleryInput.value || "").trim();
if (!name) return;
- form.mediaList = form.mediaList || [];
- form.mediaList.push({ type: "image", name, url: `/mock/${name}` });
+ newsForm.mediaList = newsForm.mediaList || [];
+ newsForm.mediaList.push({ type: "image", name, url: "" });
galleryInput.value = "";
}
-function onSave(action) {
- const ret = saveForm(action);
- if (ret?.message) {
- ElMessage.warning(ret.message);
+async function onNewsSave(action = "submit_review") {
+ try {
+ await newsFormRef.value?.validate();
+ } catch {
+ ElMessage.warning("璇峰畬鍠勮〃鍗曞繀濉」鍚庡啀淇濆瓨");
return;
}
- if (ret?.ok) {
- ElMessage.success(action === "publish" ? "宸插彂甯�" : action === "submit_review" ? "宸叉彁浜ゅ鏍�" : "宸蹭繚瀛�");
- }
-}
-
-function onDetailLike() {
- toggleLike(detailRow.value);
-}
-
-function onDetailComment(text) {
- const ret = addComment(detailRow.value, text);
- if (ret?.message) ElMessage.warning(ret.message);
- else if (ret?.ok) ElMessage.success("璇勮宸插彂甯�");
-}
-
-function openUnreadFromDetail() {
- const row = detailRow.value;
- detailDialog.visible = false;
- openUnreadRemind(row);
-}
-
-function openVersionFromDetail() {
- const row = detailRow.value;
- detailDialog.visible = false;
- openVersionHistory(row);
-}
-
-function onUnreadSelectionChange(rows) {
- unreadSelected.value = rows.map((r) => r.userId);
-}
-
-function selectAllUnread() {
- unreadSelected.value = unreadList.value.map((u) => u.userId);
-}
-
-function onSendRemind() {
- const ids = unreadSelected.value;
- const ret = sendUnreadRemind(ids);
- if (ret?.message) {
- ElMessage.warning(ret.message);
+ const v = validateNewsForm(newsForm);
+ if (!v.ok) {
+ ElMessage.warning(v.message);
return;
}
- if (ret?.ok) ElMessage.success(`宸插悜 ${ret.count} 鍚嶅憳宸ュ彂閫侀槄璇绘彁閱抈);
+ 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" ? "宸蹭繚瀛樿崏绋�" : isNewsEdit.value ? "淇敼鎴愬姛" : "宸叉彁浜ゅ鏍�";
+ ElMessage.success(msg);
+ if (!isNewsEdit.value) page.current = 1;
+ await fetchNewsList(searchForm);
+ } catch {
+ /* 閿欒鐢辫姹傛嫤鎴櫒鎻愮ず */
+ } finally {
+ newsSaving.value = false;
+ }
}
-function previewVersion(ver) {
- versionPreview.data = ver;
- versionPreview.visible = true;
+function onSearch() {
+ fetchNewsList(searchForm);
+}
+
+function resetSearch() {
+ searchForm.keyword = "";
+ searchForm.newsType = "";
+ searchForm.status = "";
+ searchForm.createTimeRange = null;
+ onSearch();
+}
+
+function onPagination(obj) {
+ paginateNewsList(obj, searchForm);
}
onMounted(() => {
- handleQuery();
+ loadFlowUsers();
+ fetchNewsList(searchForm);
});
</script>
@@ -421,6 +536,10 @@
.search_actions {
flex-shrink: 0;
}
+.search_title {
+ font-size: 14px;
+ color: var(--el-text-color-regular);
+}
.news-type-tag {
font-weight: 600;
font-size: 13px;
@@ -428,32 +547,18 @@
.media-tag {
margin: 6px 8px 0 0;
}
-.unread-toolbar {
- display: flex;
- align-items: center;
- gap: 12px;
+.template-name {
+ font-weight: 600;
+ color: var(--el-text-color-primary);
}
-.unread-stat {
+.section-tip {
+ font-size: 12px;
color: var(--el-text-color-secondary);
- font-size: 13px;
+ margin: 8px 0 0;
+ line-height: 1.5;
}
-.version-meta {
- color: var(--el-text-color-secondary);
- font-size: 13px;
- margin-bottom: 12px;
-}
-.version-html {
- padding: 12px;
- background: var(--el-fill-color-light);
- border-radius: 6px;
- max-height: 400px;
- overflow-y: auto;
-}
-.mb16 {
- margin-bottom: 16px;
-}
-.mb12 {
- margin-bottom: 12px;
+.mb20 {
+ margin-bottom: 20px;
}
.ml10 {
margin-left: 10px;
--
Gitblit v1.9.3