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; + } +}