diff --git a/.env.dev b/.env.dev
index 1ae819e..8e07cd0 100644
--- a/.env.dev
+++ b/.env.dev
@@ -6,6 +6,8 @@
VITE_BASE_HOST=http://base.yunhaixingtong.com
VITE_SSO_HOST=http://sso.yunhaixingtong.com
VITE_SERVICE_HOST=
+# 流程中心本地直连(详情页撤回/催办直调;生产同主域自动推导 /flow-center)
+VITE_FLOW_HOST=http://localhost:8085
VITE_ZIYUANKU_HOST=https://base.bestsch.com/BschZyk
VITE_ZHUANXIANG_HOST=https://base.bestsch.com/BschZncpd
VITE_IS_MOCK=false
diff --git a/src/App.vue b/src/App.vue
index cfbcd17..289cc93 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -78,7 +78,8 @@ onMounted(async () => {
diff --git a/src/api/module/notice.ts b/src/api/module/notice.ts
index 39a8ff8..aa57c1f 100644
--- a/src/api/module/notice.ts
+++ b/src/api/module/notice.ts
@@ -15,6 +15,8 @@ import type {
NoticeRequest,
NoticeQuery,
DictOption,
+ FlowOption,
+ FlowTraceVo,
DeptManageItem,
ContactGroupPage,
ContactUserPage,
@@ -107,6 +109,20 @@ class BaseApi {
}
class NoticeApi {
+ // ========== 先审后发(流程中心托管) ==========
+ /** 审核流程下拉选项(流程中心未接入时返回空数组,页面隐藏选择器) */
+ getFlowOptions(schId?: number) {
+ return get(`${NOTICE}/flow/Options`, schId ? { schId } : undefined);
+ }
+ /** 提交/重新提交审核(幂等:bizId=notice.id;审批中会被拒绝) */
+ trySubmitFlow(serid: number) {
+ return postForm(`${NOTICE}/flow/TrySubmit`, { serid });
+ }
+ /** 审批进度(详情页进度卡片;未绑流程返回 bound=false) */
+ flowTrace(serid: number) {
+ return get(`${NOTICE}/flow/Trace`, { serid });
+ }
+
// ========== 收件箱 ==========
/** 已收通知列表 */
list(params: NoticeQuery) {
diff --git a/src/assets/config/host.config.ts b/src/assets/config/host.config.ts
index d9f8849..97e06ed 100644
--- a/src/assets/config/host.config.ts
+++ b/src/assets/config/host.config.ts
@@ -23,6 +23,9 @@ let conf: BaseConf = {
baseHost: origin,
ssoHost: "",
serviceHost: seg.length >= 2 ? `${origin}/${seg[0]}` : "",
+ // 流程中心基址(Notice 详情页撤回/催办直调 /api/flow/*):生产同主域 Caddy 路由 /flow-center/;
+ // 本地 dev 由 VITE_FLOW_HOST 指向 http://localhost:8085(flow-center CORS 已收 8077)
+ flowHost: seg.length >= 2 ? `${origin}/flow-center` : "",
relayConf: {
ziyuankuHost: "",
zhuanxiangHost: "",
@@ -46,6 +49,7 @@ applyConf(conf, {
baseHost: env.VITE_BASE_HOST,
ssoHost: env.VITE_SSO_HOST,
serviceHost: env.VITE_IS_MOCK === "true" ? "" : env.VITE_SERVICE_HOST,
+ flowHost: env.VITE_FLOW_HOST,
relayConf: {
ziyuankuHost: env.VITE_ZIYUANKU_HOST,
zhuanxiangHost: env.VITE_ZHUANXIANG_HOST,
diff --git a/src/types/notice.ts b/src/types/notice.ts
index 2152e51..508192d 100644
--- a/src/types/notice.ts
+++ b/src/types/notice.ts
@@ -68,6 +68,44 @@ export interface NoticeVo {
createTime: string | null;
updateBy: string | null;
updateTime: string | null;
+ /** 绑定的审核流程 GUID(null=直发未接流程中心) */
+ flowGuid?: string | null;
+ /** 审核状态:0 待提交 / 10 审批中 / 20 已通过 / 30 已驳回 / 40 已撤回(null=未绑流程) */
+ auditStatus?: number | null;
+ /** 审核状态文案 */
+ auditStatusDesc?: string | null;
+ /** 流程中心办件 id */
+ flowInstanceId?: number | null;
+}
+
+// ============================ 先审后发(流程中心) ============================
+
+/** 审核流程下拉选项(对齐 FlowModels.FlowSummaryVo) */
+export interface FlowOption {
+ flowGuid: string;
+ name: string;
+ version: number;
+ nodeSummary: string | null;
+}
+
+/** 审批进度(GET /api/notice/flow/Trace) */
+export interface FlowTraceVo {
+ bound: boolean;
+ flowGuid: string | null;
+ flowInstanceId: number | null;
+ auditStatus: number | null;
+ auditStatusDesc: string | null;
+ status: number | null;
+ flowResult?: { result?: string; opinion?: string; rejectNode?: string } | null;
+ instanceStatus?: number | null;
+ version?: number | null;
+ nodeSummary?: string | null;
+ currentNodes?: string | null;
+ assigneeIds?: number[] | null;
+ submitTime?: string | null;
+ finishTime?: string | null;
+ /** 办理轨迹(traceJson 解析后的数组) */
+ trace?: any[] | null;
}
// ============================ 通知详情 ============================
@@ -76,6 +114,11 @@ export interface NoticeVo {
export interface NoticeDetailVo {
serid: number;
title: string;
+ flowGuid?: string | null;
+ auditStatus?: number | null;
+ auditStatusDesc?: string | null;
+ flowInstanceId?: number | null;
+ flowResult?: { result?: string; opinion?: string; rejectNode?: string } | null;
/** 通知内容(旧字段名 Contents) */
Contents: string;
/** 发布部门ID(旧字段名 DeptID) */
@@ -194,6 +237,8 @@ export interface NoticeRequest {
smsFlag?: number;
/** 转发源通知ID */
sourceId?: number;
+ /** 审核流程 GUID(非空=提交审核;空=直发) */
+ flowGuid?: string;
}
/** 通知列表查询参数(对齐 NoticeQuery.java + BasePageQuery.java) */
diff --git a/src/views/notice/NewNotice.vue b/src/views/notice/NewNotice.vue
index 5e4d1d8..14a04ec 100644
--- a/src/views/notice/NewNotice.vue
+++ b/src/views/notice/NewNotice.vue
@@ -2,11 +2,11 @@
import { ref, reactive, shallowRef, computed, onMounted, onBeforeUnmount } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useRequest } from "alova/client";
-import { Message } from "view-ui-plus";
+import { Message, Modal } from "view-ui-plus";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import "@wangeditor/editor/dist/css/style.css";
import { noticeApi } from "@/api/module/notice";
-import type { NoticeDetailVo, NoticeRequest, UpFileVo } from "@/types/notice";
+import type { NoticeDetailVo, NoticeRequest, UpFileVo, FlowOption } from "@/types/notice";
import UserCheckInput from "@/components/UserCheckInput.vue";
import NoticeUpload from "@/components/NoticeUpload.vue";
import config from "@/assets/config/host.config";
@@ -26,6 +26,13 @@ const form = reactive({
content: "",
isShortMsg: false,
});
+
+/* ============ 先审后发(审核流程绑定) ============ */
+const flowOptions = ref([]);
+const flowGuid = ref(""); // 空=直发(原链路)
+const auditStatus = ref(null); // 编辑回显的审核态
+const auditResult = ref<{ result?: string; opinion?: string; rejectNode?: string } | null>(null);
+const flowEnabled = computed(() => flowOptions.value.length > 0); // 流程中心不可用→隐藏选择器走直发
const fileids = ref([]);
const editFileList = ref<{ name: string; fileid: number }[]>([]);
const isSms = ref(false);
@@ -52,6 +59,20 @@ onMounted(async () => {
}
});
+/* 审核流程下拉(流程中心不可用/未配置 → 空数组,选择器隐藏、提交按钮走"发送") */
+onMounted(async () => {
+ try {
+ flowOptions.value = (await noticeApi.getFlowOptions().send()) || [];
+ } catch {
+ flowOptions.value = [];
+ }
+});
+
+/** 流程图:flow-center 示意图深链(Notice 指定到人场景用人员视图) */
+function openFlowDiagram() {
+ window.open(`${config.flowHost}/#/diagram?flowGuid=${flowGuid.value}&mode=user`, "_blank");
+}
+
/* ============ 富文本编辑器(wangeditor v5 for vue3) ============ */
const editorRef = shallowRef();
const editorLoading = ref(true);
@@ -134,6 +155,10 @@ onMounted(async () => {
form.dept = detail.DeptID || "";
form.rdoname = detail.tlist === "all" || !Array.isArray(detail.tlist) ? "all" : detail.tlist.join(",");
if (detail.DsfsTime) timeForm.date1 = detail.DsfsTime;
+ // 审核绑定回显(驳回/撤回态显示意见与重提按钮)
+ flowGuid.value = detail.flowGuid || "";
+ auditStatus.value = detail.auditStatus ?? null;
+ auditResult.value = detail.flowResult || null;
} else {
form.title = detail.title || "";
}
@@ -177,6 +202,7 @@ async function doAdd(_type?: string) {
deptId: form.dept,
fileIds: fileids.value.join(","), //附件
smsFlag: form.isShortMsg ? 1 : 0, //是否发送短信
+ flowGuid: flowGuid.value || undefined, //绑流程→提交审核;空→直发
};
if (isTime) {
//定时发送
@@ -211,14 +237,23 @@ async function doAdd(_type?: string) {
try {
if (!isEdit.value) {
await sendCreate(data);
- Message.success("发送成功");
+ Message.success(flowGuid.value ? "已提交审核,审核通过后自动发布" : "发送成功");
router.push("/list");
} else {
data.sourceId = serid.value;
if (data.title.indexOf("[修订稿]") == -1) data.title = "[修订稿]" + data.title;
- await sendEdit(data);
- Message.success("保存成功");
- router.push("/list");
+ // §3.6:已发布(audit=20)编辑告知——修改后重新走审批,期间对用户不可见
+ if (flowGuid.value && auditStatus.value === 20) {
+ Modal.confirm({
+ title: "重新送审确认",
+ content: "该通知已发布,修改后将重新走审批流程,期间对用户不可见,确认继续?",
+ onOk: async () => {
+ await saveEditAndLeave(data);
+ },
+ });
+ return;
+ }
+ await saveEditAndLeave(data);
}
} catch (e: any) {
Message.error(e.message || "保存失败");
@@ -226,6 +261,28 @@ async function doAdd(_type?: string) {
isLoading.value = false;
}
}
+
+/* 编辑保存 + 离开(§3.6 抽出:audit=20 先 confirm 再走这里) */
+async function saveEditAndLeave(data: NoticeRequest) {
+ await sendEdit(data);
+ // 编辑驳回/撤回态:后端 edit 内已自动重提(复用同办件 R4);待提交态由重提按钮处理
+ Message.success(flowGuid.value ? "已保存并提交审核" : "保存成功");
+ router.push("/list");
+}
+
+/* 单独重提审核(待提交/驳回/撤回态;审批中按钮隐藏) */
+async function doResubmit() {
+ isLoading.value = true;
+ try {
+ await noticeApi.trySubmitFlow(serid.value).send();
+ Message.success("已提交审核");
+ router.push("/list");
+ } catch (e: any) {
+ Message.error(e.message || "提交审核失败");
+ } finally {
+ isLoading.value = false;
+ }
+}
@@ -247,8 +304,26 @@ async function doAdd(_type?: string) {
+
+
+
+
+
+
+
+
+ 审核{{ auditStatus === 30 ? "已驳回" : "已撤回" }}
+ 办理意见:{{ auditResult.opinion }}({{ auditResult.rejectNode }})
+ 修改保存后将自动重新提交审核
+
+
@@ -262,7 +337,17 @@ async function doAdd(_type?: string) {
-
+
+
+
@@ -302,6 +387,14 @@ async function doAdd(_type?: string) {