This commit is contained in:
@@ -123,6 +123,10 @@ class NoticeApi {
|
|||||||
flowTrace(serid: number) {
|
flowTrace(serid: number) {
|
||||||
return get<FlowTraceVo>(`${NOTICE}/flow/Trace`, { serid });
|
return get<FlowTraceVo>(`${NOTICE}/flow/Trace`, { serid });
|
||||||
}
|
}
|
||||||
|
/** 撤回审核(2026-09-17:后端经 SDK 托管件中转,仅创建人本人+审批中;替代原先前端直调 flow-center) */
|
||||||
|
flowWithdraw(serid: number) {
|
||||||
|
return postForm<void>(`${NOTICE}/flow/Withdraw`, { serid });
|
||||||
|
}
|
||||||
/** 应用级流程绑定(应用设置 > 流程绑定;发通知页据此判断「提交审核」还是「发送」) */
|
/** 应用级流程绑定(应用设置 > 流程绑定;发通知页据此判断「提交审核」还是「发送」) */
|
||||||
getFlowBinding() {
|
getFlowBinding() {
|
||||||
return get<FlowBindingVo>(`${NOTICE}/flow/Binding`);
|
return get<FlowBindingVo>(`${NOTICE}/flow/Binding`);
|
||||||
|
|||||||
@@ -118,6 +118,23 @@ export interface FlowTraceVo {
|
|||||||
finishTime?: string | null;
|
finishTime?: string | null;
|
||||||
/** 办理轨迹(traceJson 解析后的数组) */
|
/** 办理轨迹(traceJson 解析后的数组) */
|
||||||
trace?: any[] | null;
|
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") {
|
async function flowAction(action: "withdraw" | "urge") {
|
||||||
const instanceId = detail.value?.flowInstanceId;
|
const instanceId = detail.value?.flowInstanceId;
|
||||||
if (!instanceId || !config.flowHost) return;
|
if (!instanceId) return;
|
||||||
flowActing.value = true;
|
flowActing.value = true;
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(`${config.flowHost}/api/flow/instance/${instanceId}/${action}`, {
|
if (action === "withdraw") {
|
||||||
|
await noticeApi.flowWithdraw(serid.value).send();
|
||||||
|
Message.success("已撤回审核,可编辑后重新提交");
|
||||||
|
await load();
|
||||||
|
await loadTrace();
|
||||||
|
} else {
|
||||||
|
if (!config.flowHost) return;
|
||||||
|
const resp = await fetch(`${config.flowHost}/api/flow/instance/${instanceId}/urge`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
});
|
});
|
||||||
const res = await resp.json().catch(() => null);
|
const res = await resp.json().catch(() => null);
|
||||||
if (resp.ok && res && res.code === 0) {
|
if (resp.ok && res && res.code === 0) {
|
||||||
Message.success(action === "withdraw" ? "已撤回审核,可编辑后重新提交" : "已发送催办提醒");
|
Message.success("已发送催办提醒");
|
||||||
load(); // 撤回后状态刷新
|
|
||||||
loadTrace();
|
|
||||||
} else {
|
} else {
|
||||||
Message.error(res?.msg || (action === "withdraw" ? "撤回失败(已有人办理时不可撤回)" : "催办失败"));
|
Message.error(res?.msg || "催办失败");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
Message.error("流程中心不可达:" + (e.message || e));
|
Message.error(
|
||||||
|
action === "withdraw"
|
||||||
|
? "撤回失败(已有人办理时不可撤回):" + (e?.msg || e?.message || e)
|
||||||
|
: "流程中心不可达:" + (e?.message || e),
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
flowActing.value = false;
|
flowActing.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 查看流程图:flow-center 示意图深链(绑流程时;Notice 指定到人场景用人员视图) */
|
/* 流程图弹窗(2026-09-17:后端同源出图 /flow/Diagram,img 免 token 免跨域,不再深链 flow-center) */
|
||||||
|
const diagramVisible = ref(false);
|
||||||
function openFlowDiagram() {
|
function openFlowDiagram() {
|
||||||
if (!detail.value?.flowGuid || !config.flowHost) return;
|
if (!detail.value?.flowGuid || !detail.value?.flowInstanceId) return;
|
||||||
window.open(`${config.flowHost}/#/diagram?flowGuid=${detail.value.flowGuid}&mode=user`, "_blank");
|
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 readGroups = ref<ReadGroup[]>([]);
|
||||||
const showRead = ref(false);
|
const showRead = ref(false);
|
||||||
@@ -264,8 +288,26 @@ function openPreview(item: { name?: string; filename?: string; fileid?: number;
|
|||||||
办理意见:{{ flowTrace.flowResult.opinion }}
|
办理意见:{{ flowTrace.flowResult.opinion }}
|
||||||
<template v-if="flowTrace.flowResult.rejectNode">({{ flowTrace.flowResult.rejectNode }})</template>
|
<template v-if="flowTrace.flowResult.rejectNode">({{ flowTrace.flowResult.rejectNode }})</template>
|
||||||
</div>
|
</div>
|
||||||
<!-- 节点时间线(traceJson 解析) -->
|
<!-- 结构化步骤时间线(2026-09-17 接入 SDK progress;steps[0] 固定"发起申请",同节点多任务每人一行) -->
|
||||||
<div v-if="flowTrace.trace && flowTrace.trace.length" class="flow-timeline">
|
<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">
|
<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-node">{{ t.nodeName || t.node || t.taskName || `节点${i + 1}` }}</span>
|
||||||
<span class="flow-step-user">{{ t.userName || t.assigneeName || t.handlerName || "" }}</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>
|
||||||
</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">
|
<div v-if="viewType !== 0" class="meta">
|
||||||
<span>发文单位:{{ detail.DeptName || "—" }}</span>
|
<span>发文单位:{{ detail.DeptName || "—" }}</span>
|
||||||
<span>发布人:{{ detail.TeaName || "—" }}</span>
|
<span>发布人:{{ detail.TeaName || "—" }}</span>
|
||||||
@@ -410,6 +459,25 @@ function openPreview(item: { name?: string; filename?: string; fileid?: number;
|
|||||||
.flow-step-op {
|
.flow-step-op {
|
||||||
color: #ed4014;
|
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 {
|
.meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user