fix(diagram): 嵌入页补滚动容器(裸渲染页被全局 body overflow:hidden 裁剪无滚动条)+ 流程图 PNG 按逻辑尺寸显示(SCALE=2 图按自然尺寸渲染整体放大一倍,四处 PNG 消费点统一走 fitDiagram)
build / build (push) Successful in 3m46s
build / build (push) Successful in 3m46s
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* 流程示意图 PNG 显示口径(2026-10-10 用户反馈:嵌入页图过大):服务端 DiagramImageService
|
||||||
|
* 按 SCALE=2 出图(视网膜清晰度),页面若按自然尺寸渲染等于整体放大一倍。
|
||||||
|
* 须按逻辑尺寸(自然宽一半)显示;>3 分支等超宽长图再收缩到容器宽。
|
||||||
|
* 用法:<img ref="diagramEl" :src="..." @load="onDiagramLoad">,onMounted 里对 complete 的图补调一次。
|
||||||
|
*/
|
||||||
|
export function fitDiagram(el: HTMLImageElement | null | undefined): void {
|
||||||
|
if (!el || !el.naturalWidth) return;
|
||||||
|
const want = el.naturalWidth / 2;
|
||||||
|
const cap = (el.parentElement?.clientWidth || 0) - 8; // Card body 左右衬
|
||||||
|
el.style.width = Math.round(Math.min(want, cap > 120 ? cap : want)) + "px";
|
||||||
|
}
|
||||||
@@ -3,11 +3,12 @@
|
|||||||
// 展示"进度 + 流程示意图",零样式复制、单点维护。全程零 CAS 交互——数据走 /open/flow/embed/data
|
// 展示"进度 + 流程示意图",零样式复制、单点维护。全程零 CAS 交互——数据走 /open/flow/embed/data
|
||||||
// 免签端点(只认 token),示意图 token 两用(/open/flow/diagram/img 同一 token 出图)。
|
// 免签端点(只认 token),示意图 token 两用(/open/flow/diagram/img 同一 token 出图)。
|
||||||
// 本页只读(方案 §9):不做任何审批动作;办理入口仍是待办站内信 → /task/:taskId 既有链路。
|
// 本页只读(方案 §9):不做任何审批动作;办理入口仍是待办站内信 → /task/:taskId 既有链路。
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted, nextTick } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { Tag } from "view-ui-plus";
|
import { Tag } from "view-ui-plus";
|
||||||
import { INSTANCE_STATUS, INSTANCE_STATUS_COLOR, TASK_STATUS } from "@/api/module/flow";
|
import { INSTANCE_STATUS, INSTANCE_STATUS_COLOR, TASK_STATUS } from "@/api/module/flow";
|
||||||
import TraceTimeline from "@/views/flow/components/TraceTimeline.vue";
|
import TraceTimeline from "@/views/flow/components/TraceTimeline.vue";
|
||||||
|
import { fitDiagram } from "@/utils/diagramImg";
|
||||||
import config from "@/assets/config/host.config";
|
import config from "@/assets/config/host.config";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -29,6 +30,10 @@ const token = computed(() => String(route.query.token || ""));
|
|||||||
const diagramSrc = computed(
|
const diagramSrc = computed(
|
||||||
() => `${config.serviceHost}/open/flow/diagram/img?token=${token.value}`,
|
() => `${config.serviceHost}/open/flow/diagram/img?token=${token.value}`,
|
||||||
);
|
);
|
||||||
|
const diagramEl = ref<HTMLImageElement | null>(null);
|
||||||
|
function onDiagramLoad() {
|
||||||
|
fitDiagram(diagramEl.value);
|
||||||
|
}
|
||||||
|
|
||||||
const snapshotRows = computed(() => {
|
const snapshotRows = computed(() => {
|
||||||
const raw = detail.value?.bizSnapshot;
|
const raw = detail.value?.bizSnapshot;
|
||||||
@@ -186,6 +191,11 @@ onMounted(async () => {
|
|||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
// 缓存命中的图可能在监听器挂上之前就 complete,补一次适配
|
||||||
|
await nextTick();
|
||||||
|
if (diagramEl.value?.complete) {
|
||||||
|
fitDiagram(diagramEl.value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -217,7 +227,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<Card class="block" :bordered="false" dis-hover>
|
<Card class="block" :bordered="false" dis-hover>
|
||||||
<template #title>流程示意图</template>
|
<template #title>流程示意图</template>
|
||||||
<img class="diagram-img" :src="diagramSrc" alt="流程示意图" />
|
<img class="diagram-img" ref="diagramEl" :src="diagramSrc" alt="流程示意图" @load="onDiagramLoad" />
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card class="block" :bordered="false" dis-hover>
|
<Card class="block" :bordered="false" dis-hover>
|
||||||
@@ -255,7 +265,9 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 根类不用 .page:UnoCSS 原子类同名会以更高优先级盖掉 scoped 的 padding(裸渲染无 layout 壳时暴露) */
|
/* 根类不用 .page:UnoCSS 原子类同名会以更高优先级盖掉 scoped 的 padding(裸渲染无 layout 壳时暴露) */
|
||||||
.embed-page { padding: 12px 16px; }
|
/* 嵌入页自身即滚动容器:全局 html/body overflow:hidden(App.vue 壳用),裸渲染页无 layout 滚动壳,
|
||||||
|
不在此定高滚动的话内容超一屏被裁且无滚动条(2026-10-10 用户反馈) */
|
||||||
|
.embed-page { height: 100vh; overflow-y: auto; padding: 12px 16px; box-sizing: border-box; }
|
||||||
.head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
|
.head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
|
||||||
.title { font-size: 16px; font-weight: 600; }
|
.title { font-size: 16px; font-weight: 600; }
|
||||||
.block { margin-bottom: 12px; }
|
.block { margin-bottom: 12px; }
|
||||||
@@ -264,7 +276,7 @@ onMounted(async () => {
|
|||||||
.v { white-space: pre-wrap; word-break: break-all; }
|
.v { white-space: pre-wrap; word-break: break-all; }
|
||||||
.muted { color: #999; }
|
.muted { color: #999; }
|
||||||
.expired { padding: 48px 16px; text-align: center; }
|
.expired { padding: 48px 16px; text-align: center; }
|
||||||
.diagram-img { max-width: 100%; }
|
.diagram-img { max-width: 100%; height: auto; display: block; margin: 0 auto; }
|
||||||
.trace-mode { float: right; font-weight: normal; margin-right: 16px; }
|
.trace-mode { float: right; font-weight: normal; margin-right: 16px; }
|
||||||
/* 类名带 record- 前缀:防 UnoCSS 原子类撞名(嵌入页裸渲染无 layout 壳,撞名实测会盖样式) */
|
/* 类名带 record- 前缀:防 UnoCSS 原子类撞名(嵌入页裸渲染无 layout 壳,撞名实测会盖样式) */
|
||||||
.record-tip {
|
.record-tip {
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
// 办件详情:状态 + 业务摘要 + 流程轨迹时间线 + 分支会签进度(概览 §9.4 进度图数据源)
|
// 办件详情:状态 + 业务摘要 + 流程轨迹时间线 + 分支会签进度(概览 §9.4 进度图数据源)
|
||||||
// 轨迹两档显示(2026-09-18):mode=user(人员,缺省)|dept(科室),写进 query 便于分享/刷新保持,
|
// 轨迹两档显示(2026-09-18):mode=user(人员,缺省)|dept(科室),写进 query 便于分享/刷新保持,
|
||||||
// 并随"流程示意图"跳转带给图示页(两边口径一致)。
|
// 并随"流程示意图"跳转带给图示页(两边口径一致)。
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted, nextTick } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { flowApi, INSTANCE_STATUS } from "@/api/module/flow";
|
import { flowApi, INSTANCE_STATUS } from "@/api/module/flow";
|
||||||
import TraceTimeline from "@/views/flow/components/TraceTimeline.vue";
|
import TraceTimeline from "@/views/flow/components/TraceTimeline.vue";
|
||||||
|
import { fitDiagram } from "@/utils/diagramImg";
|
||||||
import config from "@/assets/config/host.config";
|
import config from "@/assets/config/host.config";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -72,6 +73,12 @@ const diagramSrc = computed(
|
|||||||
() => `${config.serviceHost}/api/flow/diagram.png?instanceId=${route.params.instanceId}&mode=${mode.value}`,
|
() => `${config.serviceHost}/api/flow/diagram.png?instanceId=${route.params.instanceId}&mode=${mode.value}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** PNG 按 SCALE=2 出图:显示逻辑尺寸(自然宽一半),超宽收缩到容器(src 随口径切换会重新 load) */
|
||||||
|
const diagramEl = ref<HTMLImageElement | null>(null);
|
||||||
|
function onDiagramLoad() {
|
||||||
|
fitDiagram(diagramEl.value);
|
||||||
|
}
|
||||||
|
|
||||||
/** 跳流程图时带上当前口径(图示页读 mode,缺省人员) */
|
/** 跳流程图时带上当前口径(图示页读 mode,缺省人员) */
|
||||||
function toDiagram() {
|
function toDiagram() {
|
||||||
router.push({ path: "/diagram", query: { instanceId: String(route.params.instanceId), mode: mode.value } });
|
router.push({ path: "/diagram", query: { instanceId: String(route.params.instanceId), mode: mode.value } });
|
||||||
@@ -92,6 +99,10 @@ onMounted(async () => {
|
|||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
await nextTick();
|
||||||
|
if (diagramEl.value?.complete) {
|
||||||
|
fitDiagram(diagramEl.value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -139,7 +150,7 @@ onMounted(async () => {
|
|||||||
流程示意图
|
流程示意图
|
||||||
<a class="diagram-more" @click="toDiagram()">查看大图</a>
|
<a class="diagram-more" @click="toDiagram()">查看大图</a>
|
||||||
</template>
|
</template>
|
||||||
<img class="diagram-img" :src="diagramSrc" alt="流程示意图" />
|
<img class="diagram-img" ref="diagramEl" :src="diagramSrc" alt="流程示意图" @load="onDiagramLoad" />
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card class="block" :bordered="false" dis-hover>
|
<Card class="block" :bordered="false" dis-hover>
|
||||||
|
|||||||
Reference in New Issue
Block a user