feat(flow): 落地 FL2.0 原型——部门选人抽屉 / 授权管理页 / 退回重提入口(基线 origin/main)
build / build (push) Successful in 1m31s
build / build (push) Successful in 1m31s
在 c93313c 之上增量落地原型与前端规范,保留既有流程图入口/失败提示/指派预览/线级停发:
- 审批/抄送抽屉按原型重构(422→1026 / 239→742 行):科室树+成员多选、SYSTEM/CUSTOM 分支、
CUSTOM 分类导航自动定位、跨节点导航重置、保存后重开回显
- 新增授权管理页 /admin/usage-grants(UsageGrants.vue,417 行):校域清单、按流程线筛选、
授予/撤销后回读,失败不宣称成功
- 路由与 API:新增 usage-grant(schoolList/summary/grant/revoke)、department(groups/options/resolve/members)、
instance/resubmit;TaskHandle 增加「退回待修改」入口(仅 status=50 显示)
- 错误处理沿用 flowError 统一出口,不透出后端原文
- 组件/契约测试:flow-error、flow2-contract、department-roundtrip、task-result
不含构建产物(dist-verify)与依赖目录
This commit is contained in:
@@ -41,9 +41,12 @@ const contextId = ref("");
|
||||
const frameEl = ref<HTMLIFrameElement | null>(null);
|
||||
/** 本次打开锁定的父↔子通道条件;非响应式:只在 open 时刷新 */
|
||||
let expectedOrigin = "";
|
||||
let expectedFlowGuid = "";
|
||||
let listening = false;
|
||||
/** 本次会话是否已经由 iframe 明确答复过(确认/取消),用于区分"宿主自己关框" */
|
||||
/** 本次会话是否已经收口(确认或取消各只允许一次),用于区分"宿主自己关框"与重复关闭 */
|
||||
let settled = false;
|
||||
/** 框是否处于本次打开的生命周期内:close/X/遮罩/程序关闭统一走同一 settle 路径 */
|
||||
let opened = false;
|
||||
|
||||
function newContextId(): string {
|
||||
return `c${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
||||
@@ -57,14 +60,17 @@ function closeListener(): void {
|
||||
}
|
||||
|
||||
function onMessage(ev: MessageEvent): void {
|
||||
if (!opened || settled || !listening) return;
|
||||
const msg: AssignEmbedMessage | null = isValidAssignMessage(
|
||||
ev,
|
||||
expectedOrigin,
|
||||
frameEl.value?.contentWindow ?? null,
|
||||
contextId.value,
|
||||
expectedFlowGuid,
|
||||
);
|
||||
if (!msg) return;
|
||||
settled = true;
|
||||
opened = false;
|
||||
closeListener();
|
||||
visible.value = false;
|
||||
if (msg.type === "assign-cancelled") {
|
||||
@@ -72,6 +78,7 @@ function onMessage(ev: MessageEvent): void {
|
||||
return;
|
||||
}
|
||||
emit("confirmed", {
|
||||
// buildMessage 已保证确认消息必带非空 flowGuid;兜底 props 只为满足类型,不是信任来源
|
||||
flowGuid: msg.flowGuid || props.flowGuid,
|
||||
defVersion: msg.defVersion,
|
||||
assigns: msg.assigns ?? [],
|
||||
@@ -83,6 +90,8 @@ function open(): void {
|
||||
// 重开:先摘掉上一轮监听,再换一个新的 contextId——旧 frame 的迟到消息按 context 失效
|
||||
closeListener();
|
||||
settled = false;
|
||||
expectedFlowGuid = props.flowGuid;
|
||||
opened = true;
|
||||
contextId.value = newContextId();
|
||||
const query = `flowGuid=${encodeURIComponent(props.flowGuid)}&contextId=${encodeURIComponent(contextId.value)}`;
|
||||
frameUrl.value = toAppHashUrl(`#/assign-preview?${query}`);
|
||||
@@ -92,25 +101,40 @@ function open(): void {
|
||||
listening = true;
|
||||
}
|
||||
|
||||
/** 宿主主动收起(等价于取消):同样摘监听,避免后续消息继续影响本页 */
|
||||
function close(): void {
|
||||
/**
|
||||
* 唯一收口路径(F07):宿主程序关闭、点 X、点遮罩都进这里。
|
||||
* 已确认/已取消的会话不再补发第二次;未答复过的关闭按"取消"通知宿主(不覆盖原有选择)。
|
||||
*/
|
||||
function settleAsCancel(): void {
|
||||
closeListener();
|
||||
if (visible.value && !settled) emit("cancelled");
|
||||
visible.value = false;
|
||||
if (opened && !settled) {
|
||||
settled = true;
|
||||
opened = false;
|
||||
emit("cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
// 点遮罩/X 关闭走这里;已 settled 的关闭由 iframe 自己回过话,不再补发 cancelled
|
||||
// v-model 把 X/遮罩置 false 时也会走这里;只保证监听被摘,emit 由 settleAsCancel 负责,避免双发
|
||||
watch(visible, (val) => {
|
||||
if (!val) closeListener();
|
||||
if (!val) settleAsCancel();
|
||||
});
|
||||
|
||||
onBeforeUnmount(closeListener);
|
||||
watch(() => props.flowGuid, settleAsCancel);
|
||||
onBeforeUnmount(settleAsCancel);
|
||||
|
||||
defineExpose({ open, close, contextId });
|
||||
defineExpose({ open, close: settleAsCancel, contextId });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal v-model="visible" :title="title || '选择办理人'" :width="760" :footer-hide="true" class="assign-embed-modal">
|
||||
<Modal
|
||||
v-model="visible"
|
||||
:title="title || '选择办理人'"
|
||||
:width="760"
|
||||
:footer-hide="true"
|
||||
class="assign-embed-modal"
|
||||
@on-cancel="settleAsCancel"
|
||||
>
|
||||
<iframe
|
||||
v-if="frameUrl"
|
||||
ref="frameEl"
|
||||
|
||||
Reference in New Issue
Block a user