This commit is contained in:
@@ -123,6 +123,10 @@ class NoticeApi {
|
||||
flowTrace(serid: number) {
|
||||
return get<FlowTraceVo>(`${NOTICE}/flow/Trace`, { serid });
|
||||
}
|
||||
/** 撤回审核(2026-09-17:后端经 SDK 托管件中转,仅创建人本人+审批中;替代原先前端直调 flow-center) */
|
||||
flowWithdraw(serid: number) {
|
||||
return postForm<void>(`${NOTICE}/flow/Withdraw`, { serid });
|
||||
}
|
||||
/** 应用级流程绑定(应用设置 > 流程绑定;发通知页据此判断「提交审核」还是「发送」) */
|
||||
getFlowBinding() {
|
||||
return get<FlowBindingVo>(`${NOTICE}/flow/Binding`);
|
||||
|
||||
@@ -118,6 +118,23 @@ export interface FlowTraceVo {
|
||||
finishTime?: string | null;
|
||||
/** 办理轨迹(traceJson 解析后的数组) */
|
||||
trace?: any[] | null;
|
||||
/** 结构化步骤(2026-09-17 接入:steps[0] 固定"发起申请",同节点多任务每人一行) */
|
||||
steps?: FlowProgressStepVo[] | null;
|
||||
}
|
||||
|
||||
/** 流程步骤(SDK FlowProgressStep 同构:后端 /flow/Trace 的 steps 元素) */
|
||||
export interface FlowProgressStepVo {
|
||||
nodeId: string;
|
||||
nodeName: string | null;
|
||||
label: string | null;
|
||||
active: boolean;
|
||||
assignees?: {
|
||||
userName?: string | null;
|
||||
status?: number | null;
|
||||
statusLabel?: string | null;
|
||||
opinion?: string | null;
|
||||
handleTime?: string | null;
|
||||
}[] | null;
|
||||
}
|
||||
|
||||
// ============================ 通知详情 ============================
|
||||
|
||||
@@ -36,35 +36,59 @@ async function loadTrace() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 撤回/催办直调 flow-center 用户面(同主域 CAS 免二次登录;本地 dev 走 flowHost CORS) */
|
||||
/**
|
||||
* 撤回:走本应用后端(2026-09-17 接入:后端经 SDK 托管件中转并复核创建人,
|
||||
* 不再前端直调 flow-center——跨应用 CAS 票据 + CORS 双重外溢且"谁能撤"落在前端)。
|
||||
* 催办:仍是"人"的动作,走 flow-center 用户面(同主域 CAS 免二次登录)。
|
||||
*/
|
||||
async function flowAction(action: "withdraw" | "urge") {
|
||||
const instanceId = detail.value?.flowInstanceId;
|
||||
if (!instanceId || !config.flowHost) return;
|
||||
if (!instanceId) return;
|
||||
flowActing.value = true;
|
||||
try {
|
||||
const resp = await fetch(`${config.flowHost}/api/flow/instance/${instanceId}/${action}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
});
|
||||
const res = await resp.json().catch(() => null);
|
||||
if (resp.ok && res && res.code === 0) {
|
||||
Message.success(action === "withdraw" ? "已撤回审核,可编辑后重新提交" : "已发送催办提醒");
|
||||
load(); // 撤回后状态刷新
|
||||
loadTrace();
|
||||
if (action === "withdraw") {
|
||||
await noticeApi.flowWithdraw(serid.value).send();
|
||||
Message.success("已撤回审核,可编辑后重新提交");
|
||||
await load();
|
||||
await loadTrace();
|
||||
} else {
|
||||
Message.error(res?.msg || (action === "withdraw" ? "撤回失败(已有人办理时不可撤回)" : "催办失败"));
|
||||
if (!config.flowHost) return;
|
||||
const resp = await fetch(`${config.flowHost}/api/flow/instance/${instanceId}/urge`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
});
|
||||
const res = await resp.json().catch(() => null);
|
||||
if (resp.ok && res && res.code === 0) {
|
||||
Message.success("已发送催办提醒");
|
||||
} else {
|
||||
Message.error(res?.msg || "催办失败");
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
Message.error("流程中心不可达:" + (e.message || e));
|
||||
Message.error(
|
||||
action === "withdraw"
|
||||
? "撤回失败(已有人办理时不可撤回):" + (e?.msg || e?.message || e)
|
||||
: "流程中心不可达:" + (e?.message || e),
|
||||
);
|
||||
} finally {
|
||||
flowActing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 查看流程图:flow-center 示意图深链(绑流程时;Notice 指定到人场景用人员视图) */
|
||||
/* 流程图弹窗(2026-09-17:后端同源出图 /flow/Diagram,img 免 token 免跨域,不再深链 flow-center) */
|
||||
const diagramVisible = ref(false);
|
||||
function openFlowDiagram() {
|
||||
if (!detail.value?.flowGuid || !config.flowHost) return;
|
||||
window.open(`${config.flowHost}/#/diagram?flowGuid=${detail.value.flowGuid}&mode=user`, "_blank");
|
||||
if (!detail.value?.flowGuid || !detail.value?.flowInstanceId) return;
|
||||
diagramVisible.value = true;
|
||||
}
|
||||
const diagramSrc = computed(() =>
|
||||
diagramVisible.value && detail.value?.flowInstanceId
|
||||
? `${config.serviceHost}/api/notice/flow/Diagram?serid=${serid.value}`
|
||||
: "",
|
||||
);
|
||||
function onDiagramError() {
|
||||
diagramVisible.value = false;
|
||||
Message.error("流程图加载失败(可能已过期,请刷新页面重试)");
|
||||
}
|
||||
const readGroups = ref<ReadGroup[]>([]);
|
||||
const showRead = ref(false);
|
||||
@@ -264,8 +288,26 @@ function openPreview(item: { name?: string; filename?: string; fileid?: number;
|
||||
办理意见:{{ flowTrace.flowResult.opinion }}
|
||||
<template v-if="flowTrace.flowResult.rejectNode">({{ flowTrace.flowResult.rejectNode }})</template>
|
||||
</div>
|
||||
<!-- 节点时间线(traceJson 解析) -->
|
||||
<div v-if="flowTrace.trace && flowTrace.trace.length" class="flow-timeline">
|
||||
<!-- 结构化步骤时间线(2026-09-17 接入 SDK progress;steps[0] 固定"发起申请",同节点多任务每人一行) -->
|
||||
<div v-if="flowTrace.steps && flowTrace.steps.length" class="flow-timeline">
|
||||
<div
|
||||
v-for="(s, i) in flowTrace.steps"
|
||||
:key="'fs' + i"
|
||||
class="flow-step"
|
||||
:class="{ 'flow-step-active': s.active }"
|
||||
>
|
||||
<span class="flow-step-node">{{ s.label || s.nodeName || `节点${i + 1}` }}</span>
|
||||
<template v-if="s.assignees && s.assignees.length">
|
||||
<span v-for="(a, j) in s.assignees" :key="j" class="flow-step-user">
|
||||
{{ a.userName || "" }}
|
||||
<em v-if="a.statusLabel" class="flow-step-status">{{ a.statusLabel }}</em>
|
||||
<em v-if="a.opinion" class="flow-step-op">({{ a.opinion }})</em>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 节点时间线(traceJson 解析,steps 不可用时的兜底) -->
|
||||
<div v-else-if="flowTrace.trace && flowTrace.trace.length" class="flow-timeline">
|
||||
<div v-for="(t, i) in flowTrace.trace" :key="i" class="flow-step">
|
||||
<span class="flow-step-node">{{ t.nodeName || t.node || t.taskName || `节点${i + 1}` }}</span>
|
||||
<span class="flow-step-user">{{ t.userName || t.assigneeName || t.handlerName || "" }}</span>
|
||||
@@ -275,6 +317,13 @@ function openPreview(item: { name?: string; filename?: string; fileid?: number;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 流程图弹窗(后端同源出图,免 token 免跨域) -->
|
||||
<Modal v-model="diagramVisible" title="流程示意图" :width="860" footer-hide>
|
||||
<div class="diagram-wrap">
|
||||
<img v-if="diagramSrc" :src="diagramSrc" alt="流程示意图" @error="onDiagramError" />
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<div v-if="viewType !== 0" class="meta">
|
||||
<span>发文单位:{{ detail.DeptName || "—" }}</span>
|
||||
<span>发布人:{{ detail.TeaName || "—" }}</span>
|
||||
@@ -410,6 +459,25 @@ function openPreview(item: { name?: string; filename?: string; fileid?: number;
|
||||
.flow-step-op {
|
||||
color: #ed4014;
|
||||
}
|
||||
.flow-step-active .flow-step-node {
|
||||
color: #2d8cf0;
|
||||
font-weight: 600;
|
||||
}
|
||||
.flow-step-status {
|
||||
font-style: normal;
|
||||
color: #808695;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.flow-step .flow-step-op {
|
||||
font-style: normal;
|
||||
}
|
||||
.diagram-wrap {
|
||||
text-align: center;
|
||||
min-height: 200px;
|
||||
}
|
||||
.diagram-wrap img {
|
||||
max-width: 100%;
|
||||
}
|
||||
.meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
Reference in New Issue
Block a user