diff --git a/track-uniapp/src/pages/scan/components/TreeCanvas.vue b/track-uniapp/src/pages/scan/components/TreeCanvas.vue
index 5b0db70..c8fb0ae 100644
--- a/track-uniapp/src/pages/scan/components/TreeCanvas.vue
+++ b/track-uniapp/src/pages/scan/components/TreeCanvas.vue
@@ -3,16 +3,10 @@
← 返回
-
- 🌳 流转蓝图
- 双指缩放 · 单指拖拽
-
+ 🌳 流转蓝图
📇 卡片
- -
- {{ Math.round(mvScale * 100) }}%
- +
⊡ 全览
@@ -24,10 +18,9 @@
+ @change="onChange">
@@ -67,16 +60,13 @@ export default {
emits: ["viewRecords", "back", "swipe"],
data() {
return {
- mvX: 0, mvY: 0, mvScale: 1,
+ mvX: 0, mvY: 0,
viewportW: 375, viewportH: 600,
areaHeight: 500,
- _scalePending: false,
- _pendingScale: 1,
};
},
mounted() {
try { const info = uni.getSystemInfoSync(); this.viewportW = info.windowWidth || 375; this.viewportH = info.windowHeight || 600; } catch {}
- // 🚀 给 movable-area 明确像素高度,避免 flex:1 导致触摸区域计算不准
this.areaHeight = Math.max(this.viewportH - 100, 400);
this.$nextTick(() => this.fitAll());
},
@@ -208,33 +198,13 @@ export default {
// ============================================================
canvasWidth() { const ns = this.treeNodes; if (!ns.length) return 400; return Math.max(...ns.map(n => n.x)) + 200; },
canvasHeight() { const ns = this.treeNodes; if (!ns.length) return 400; return Math.max(...ns.map(n => n.y)) + 200; },
- fitScale() {
- if (!this.treeNodes.length) return 1;
- return Math.max(0.1, Math.min((this.viewportW - 32) / this.canvasWidth, (this.areaHeight - 16) / this.canvasHeight, 1));
- }
},
methods: {
- // 🚀 缩放事件节流:用 rAF 限频,避免每帧触发 Vue 响应式更新导致卡顿
- onScale(e) {
- const s = e?.detail?.scale;
- if (!s) return;
- this._pendingScale = s;
- if (!this._scalePending) {
- this._scalePending = true;
- // uni-app 环境优先用定时器(兼容小程序),H5 用 rAF
- const schedule = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : (fn) => setTimeout(fn, 16);
- schedule(() => {
- this.mvScale = this._pendingScale;
- this._scalePending = false;
- });
- }
- },
- // 🚀 手势结束后同步位置(仅记录,不回绑 :x/:y 避免干扰原生拖拽)
+ // 🚀 手势结束后同步位置
onChange(e) {
if (e?.detail?.x !== undefined) this.mvX = e.detail.x;
if (e?.detail?.y !== undefined) this.mvY = e.detail.y;
},
- zoomIn() { this.mvScale = Math.min(5, +(this.mvScale + 0.2).toFixed(1)); },
handleNodeTap(node) {
if (node.records && node.records.length > 0) {
this.$emit('viewRecords', node);
@@ -242,18 +212,14 @@ export default {
uni.showToast({ title: '当前节点暂无流转记录', icon: 'none' });
}
},
- zoomOut() { this.mvScale = Math.max(0.1, +(this.mvScale - 0.2).toFixed(1)); },
- // 🚀 全览居中:缩放至适配 + 主分支水平居中 + 垂直起始位置
+ // 🚀 全览居中:固定 100% 比例,内容整体在视口中居中
fitAll() {
- const scale = this.fitScale;
const canvasW = this.canvasWidth;
const canvasH = this.canvasHeight;
const viewW = this.viewportW;
const viewH = this.areaHeight;
- // 内容整体在视口中居中
- this.mvScale = scale;
- this.mvX = (viewW - canvasW * scale) / 2;
- this.mvY = (viewH - canvasH * scale) / 2;
+ this.mvX = (viewW - canvasW) / 2;
+ this.mvY = (viewH - canvasH) / 2;
},
fmtDate(d) { if (!d) return ""; const dt = new Date(d); return (dt.getMonth() + 1) + '/' + dt.getDate(); },
statusLabel(s) { const m = { PENDING: "待接收", WIP: "进行中", COMPLETED: "已完成", REJECTED: "已驳回", ARCHIVED: "已入库", CANCELED: "已撤回" }; return m[s] || s; },