warehouse-map-sdk 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,177 @@
1
- # Temporary Holding Version
1
+ # warehouse-map-sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 仓库地图 SDK(Vue 2 组件):Canvas 渲染、沿道路 A* 路径导航、点击货位联动库存、**内置绘制工具面板**的可视化编辑(画货位/装卸口/墙体/边界/道路、批量选货位、撤销重做、导入导出 JSON)。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install warehouse-map-sdk
9
+ # 或
10
+ pnpm add warehouse-map-sdk
11
+ ```
12
+
13
+ 要求宿主 Vue 2.6 / 2.7。
14
+
15
+ ## 一体化编辑器(推荐)
16
+
17
+ > 布局通常是异步拉取的:`layout` 尚为 `null` 时组件会用内置空模型兜底(不报错),
18
+ > 布局到达后自动应用。若不希望布局到达前出现短暂空白地图,可加 `v-if="layout"`。
19
+ >
20
+ > ⚠️ 示例中的 `http` 需换成你项目里**实际的请求实例**(如 `import http from '@/utils/request'`
21
+ > 或 `axios`);Vue 原型上没有 `$http` 时直接写 `this.$http` 会报错。
22
+
23
+ ```vue
24
+ <template>
25
+ <WarehouseMapEditor
26
+ ref="editor"
27
+ v-if="layout"
28
+ :layout="layout"
29
+ :api="mapApi"
30
+ @model-change="onModelChange"
31
+ />
32
+ </template>
33
+
34
+ <script>
35
+ import http from '@/utils/request'; // ← 换成你项目的 axios 实例
36
+
37
+ export default {
38
+ data() {
39
+ return {
40
+ layout: null,
41
+ latestJson: null
42
+ };
43
+ },
44
+ computed: {
45
+ // 用 computed 而不是 data:data 里的箭头函数拿不到 this
46
+ mapApi() {
47
+ const self = this;
48
+ return {
49
+ // 批量选货位/批量选装卸口的清单服务(不传则对应工具按钮自动隐藏)
50
+ // 返回 [{ code, name, row, col }]
51
+ fetchBizSlots: () => http.get('/api/warehouse/biz-slots').then(r => r.data),
52
+ // 返回 [{ code, name }]
53
+ fetchBizDocks: () => http.get('/api/warehouse/biz-docks').then(r => r.data)
54
+ };
55
+ }
56
+ },
57
+ async created() {
58
+ const res = await http.get('/api/warehouse/layout');
59
+ this.layout = res.data;
60
+ },
61
+ methods: {
62
+ // 任何编辑(画/改/删/撤销/导入)后抛完整契约 JSON → 先暂存,「保存」按钮入库
63
+ onModelChange(json) { this.latestJson = json; },
64
+ async save() {
65
+ const json = this.latestJson || this.$refs.editor.exportJSON();
66
+ await http.put('/api/warehouse/layout', JSON.parse(json));
67
+ this.$message && this.$message.success('已保存');
68
+ }
69
+ }
70
+ };
71
+ </script>
72
+ ```
73
+
74
+ 全局注册方式(可选):
75
+
76
+ ```js
77
+ import WarehouseMapSdk from 'warehouse-map-sdk';
78
+ Vue.use(WarehouseMapSdk); // 注册 <WarehouseMap> 与 <WarehouseMapEditor>
79
+ ```
80
+
81
+ ## 只读地图(导航 + 库存联动)
82
+
83
+ ```vue
84
+ <template>
85
+ <div>
86
+ <WarehouseMap
87
+ :layout="layout"
88
+ :slot-status="slotStatus"
89
+ :path="pathPoints"
90
+ :night="night"
91
+ @shape-click="onShapeClick"
92
+ />
93
+ <!-- 库存弹窗等 UI 由业务自己渲染 -->
94
+ </div>
95
+ </template>
96
+
97
+ <script>
98
+ export default {
99
+ data() {
100
+ return { layout: null, slotStatus: {}, pathPoints: [], night: false };
101
+ },
102
+ methods: {
103
+ onShapeClick(shape) {
104
+ // shape.type: 'slot' | 'dock' | 'node';shape.id 即货位编码
105
+ if (shape.type === 'slot') this.$emit('query-inventory', shape.id);
106
+ }
107
+ }
108
+ };
109
+ </script>
110
+ ```
111
+
112
+ ## 组件 API
113
+
114
+ ### `<WarehouseMapEditor>`
115
+
116
+ | Prop | 类型 | 说明 |
117
+ | --- | --- | --- |
118
+ | `layout` | Object | 布局契约 JSON(必传,创建时读取) |
119
+ | `api` | Object | `{ fetchBizSlots?, fetchBizDocks? }`,返回 `Promise<[{code, name, row?, col?}]>` |
120
+ | `night` | Boolean | 夜间主题 |
121
+ | `tools` | Array | 工具白名单(value 数组),缺省全部 |
122
+ | `showPanel` | Boolean | 是否显示右侧面板,默认 `true` |
123
+ | `gridSnap` / `roadSnap` / `roadFillStep` | Number | 初始吸附参数(米),默认 0.1 / 0.8 / 5 |
124
+
125
+ **Events**
126
+
127
+ | 事件 | 参数 | 说明 |
128
+ | --- | --- | --- |
129
+ | `model-change` | `json` | 任何模型变更后抛完整契约 JSON |
130
+ | `selection-change` | `{kind,id}` \| null | 选中变化 |
131
+ | `tool-change` | `tool` | 绘制工具切换 |
132
+ | `notice` | `{text,level}` | 面板内 toast 同时抛出(level: info/success/warning/error) |
133
+
134
+ **Methods**(`this.$refs.editor.xxx`)
135
+
136
+ | 方法 | 说明 |
137
+ | --- | --- |
138
+ | `exportJSON()` | 返回契约 JSON 字符串 |
139
+ | `importJSON(text)` | 粘贴 JSON 整体替换布局(可撤销) |
140
+
141
+ ### `<WarehouseMap>`
142
+
143
+ | Prop | 类型 | 说明 |
144
+ | --- | --- | --- |
145
+ | `layout` | Object | 布局契约 JSON |
146
+ | `slotStatus` | Object | `{ [slotId]: { state: 'empty'\|'partial'\|'full', qty, capacity } }` 着色 |
147
+ | `path` / `selectedId` | — | 导航路径点、选中元素 |
148
+ | `night` | Boolean | 夜间主题 |
149
+ | `mode` | String | `view`(点击抛事件)\| `select`(点选/拖动)等,编辑器组件内部管理 |
150
+
151
+ **Events**:`shape-click`(点击货位/装卸口,`payload.type`/`payload.id`)。
152
+
153
+ **方法**:通过 ref 调用 `findPath(fromId, toId)` 返回 `{ok, points, length}`。
154
+
155
+ ## 数据契约
156
+
157
+ ```jsonc
158
+ // 布局(GET /api/warehouse/layout,导出 JSON 同结构)
159
+ {
160
+ "size": { "width": 60, "height": 40 },
161
+ "slots": [{ "id": "0001", "name": "D1·1", "points": [[10,2],[13,2],[13,6.5],[10,6.5]], "entry": { "x": 11.5, "y": 6.5 } }],
162
+ "docks": [{ "id": "DOCK-01", "name": "1号装卸口", "points": [[8,36],[14,36],[14,40],[8,40]], "entry": { "x": 11, "y": 36 } }],
163
+ "walls": [{ "id": "W1", "label": "设备区", "points": [[56,12],[60,12],[60,20],[56,20]] }],
164
+ "roadNodes": [{ "id": "P1", "x": 6, "y": 8 }],
165
+ "roadEdges": [{ "from": "P1", "to": "P2" }],
166
+ "roadWidth": 4
167
+ }
168
+
169
+ // 货位着色概览(GET /api/inventory/summary,须返回全部货位,含 qty=0)
170
+ { "capacity": 250, "slots": [{ "slotCode": "0001", "qty": 118 }] }
171
+ ```
172
+
173
+ 坐标单位为**米**,原点在仓库左下角、x 向右、y 向上。
174
+
175
+ ## License
176
+
177
+ MIT
@@ -0,0 +1 @@
1
+ function t(t){if(t.__esModule)return t;var e=Object.defineProperty({},"__esModule",{value:!0});return Object.keys(t).forEach(function(i){var n=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,n.get?n:{enumerable:!0,get:function(){return t[i]}})}),e}var e=function(t){var e=t.canvasWidth,i=t.canvasHeight,n=t.worldWidth,o=t.worldHeight,a=void 0===t.padding?20:t.padding,r=Math.min((e-2*a)/n,(i-2*a)/o),s=r,l=(e-n*r)/2,d=(i-o*r)/2;function h(t,e){return{x:(t-l)/s,y:o-(e-d)/s}}return{toScreen:function(t,e){return{x:l+t*s,y:d+(o-e)*s}},screenToWorld:h,zoomAt:function(t,e,i){var n=h(t,e);s*=i,l=t-n.x*s,d=e-(o-n.y)*s},pan:function(t,e){l+=t,d+=e},reset:function(){s=r,l=(e-n*r)/2,d=(i-o*r)/2},fitBounds:function(t,n,a,r,h){var u=void 0===h?20:h,c=Math.max(a-t,1e-6),f=Math.max(r-n,1e-6);s=Math.min((e-2*u)/c,(i-2*u)/f),l=(e-c*s)/2-t*s,d=(i-f*s)/2-(o-r)*s},getScale:function(){return s},getFitScale:function(){return r},signature:function(){return s+","+l+","+d}}};function i(t,e,i,n,o,a){var r=o-i,s=a-n,l=r*r+s*s,d=0===l?0:((t-i)*r+(e-n)*s)/l,h=i+(d=Math.max(0,Math.min(1,d)))*r,u=n+d*s;return{x:h,y:u,t:d,dist:Math.hypot(t-h,e-u)}}function n(t,e,i,n,o,a){return(i-t)*(a-e)-(n-e)*(o-t)}function o(t,e,i,o,a,r,s){return Math.abs(n(i,o,a,r,t,e))<=s&&t>=Math.min(i,a)-s&&t<=Math.max(i,a)+s&&e>=Math.min(o,r)-s&&e<=Math.max(o,r)+s}var a={dist:function(t,e,i,n){return Math.hypot(i-t,n-e)},pointSegProjection:i,pointOnSegment:function(t,e,n,o,a,r,s){s=void 0===s?1e-4:s;var l=i(t,e,n,o,a,r);return l.dist<=s&&l.t>1e-6&&l.t<.999999},pointInPolygon:function(t,e,i){for(var n=!1,o=0,a=i.length-1;o<i.length;a=o++){var r=i[o][0],s=i[o][1],l=i[a][0],d=i[a][1];s>e!=d>e&&t<(l-r)*(e-s)/(d-s)+r&&(n=!n)}return n},polygonArea:function(t){for(var e=0,i=0,n=t.length-1;i<t.length;n=i++)e+=t[n][0]*t[i][1]-t[i][0]*t[n][1];return Math.abs(e)/2},polygonBounds:function(t){var e=1/0,i=1/0,n=-1/0,o=-1/0;return t.forEach(function(t){t[0]<e&&(e=t[0]),t[0]>n&&(n=t[0]),t[1]<i&&(i=t[1]),t[1]>o&&(o=t[1])}),{x1:e,y1:i,x2:n,y2:o,width:n-e,height:o-i}},segSegIntersect:function(t,e,i,a,r,s,l,d){var h=1e-9,u=n(r,s,l,d,t,e),c=n(r,s,l,d,i,a),f=n(t,e,i,a,r,s),p=n(t,e,i,a,l,d);return(u>h&&c<-h||u<-h&&c>h)&&(f>h&&p<-h||f<-h&&p>h)||!!(o(t,e,r,s,l,d,h)||o(i,a,r,s,l,d,h)||o(r,s,t,e,i,a,h)||o(l,d,t,e,i,a,h))},projectPointOnPolygonBoundary:function(t,e,n){for(var o=null,a=0;a<n.length;a++){var r=n[a],s=n[(a+1)%n.length],l=i(t,e,r[0],r[1],s[0],s[1]);(!o||l.dist<o.dist)&&(o=l)}return o?{x:o.x,y:o.y,dist:o.dist}:{x:t,y:e,dist:0}}};function r(t){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r(t)}var s=a,l=1.5;function d(t){return JSON.parse(JSON.stringify(t))}function h(t,e){var i=Math.pow(10,void 0===e?3:e);return Math.round(t*i)/i}function u(t,e){var i=null==e?.5:e;return h(i?Math.round(t/i)*i:t,3)}function c(t,e){return{x:u(t.x,e),y:u(t.y,e)}}function f(t){return!Array.isArray(t)||t.length<3?null:t.map(function(t){return[h(t[0]),h(t[1])]})}function p(t){if(t.boundary&&t.boundary.length>=3)return t.boundary;var e=null;return(t.walls||[]).forEach(function(t){!1!==t.fill||e||(e=t)}),e?e.points:null}function y(t,e){var i=Math.min(t.x,e.x),n=Math.min(t.y,e.y),o=Math.max(t.x,e.x),a=Math.max(t.y,e.y);return{x1:h(i),y1:h(n),x2:h(o),y2:h(a),width:h(o-i),height:h(a-n)}}function g(t){return[[t.x1,t.y1],[t.x2,t.y1],[t.x2,t.y2],[t.x1,t.y2]]}function x(t){if(!t||4!==t.length)return null;var e=s.polygonBounds(t),i=s.polygonArea(t);return Math.abs(i-e.width*e.height)>1e-6?null:{x1:e.x1,y1:e.y1,x2:e.x2,y2:e.y2,width:e.width,height:e.height}}function m(t,e){return"slot"===e?t.slots:"dock"===e?t.docks:"wall"===e?t.walls:"node"===e?t.roadNodes:null}function v(t,e,i){var n=m(t,e);if(!n)return null;for(var o=0;o<n.length;o++)if(n[o].id===i)return n[o];return null}function b(t,e,i){var n=void 0===i?.8:i,o=null,a=1/0;return t.roadNodes.forEach(function(t){var i=Math.hypot(t.x-e.x,t.y-e.y);i<=n&&i<a&&(o=t,a=i)}),o}function w(t,e){var i=null;return t.roadEdges.forEach(function(n,o){var a=v(t,"node",n.from),r=v(t,"node",n.to);if(a&&r){var l=s.pointSegProjection(e.x,e.y,a.x,a.y,r.x,r.y);(!i||l.dist<i.dist)&&(i={dist:l.dist,x:l.x,y:l.y,edgeIndex:o})}}),i}function k(t,e){if(!e.roadEdges||0===e.roadEdges.length){var i=s.polygonBounds(t);return{x:h((i.x1+i.x2)/2),y:h(i.y1)}}for(var n=null,o=0;o<t.length;o++){var a=t[o],r=t[(o+1)%t.length],l=w(e,{x:(a[0]+r[0])/2,y:(a[1]+r[1])/2});if(l){var d=s.pointSegProjection(l.x,l.y,a[0],a[1],r[0],r[1]),u=Math.hypot(l.x-d.x,l.y-d.y);(!n||u<n.dist)&&(n={x:d.x,y:d.y,dist:u})}}if(!n){var c=s.polygonBounds(t);return{x:h((c.x1+c.x2)/2),y:h(c.y1)}}return{x:h(n.x),y:h(n.y)}}function S(t){for(var e=/^([A-Za-z]+\d+):(\d+)$/,i=t.slots.length-1;i>=0;i--){var n=e.exec(String(t.slots[i].id));if(n){var o=n[1]+":"+(parseInt(n[2],10)+1);if(!v(t,"slot",o))return o}}for(var a=1;v(t,"slot","A1:"+a);)a++;return"A1:"+a}function E(t){for(var e=t.docks.length+1;v(t,"dock","DOCK-"+String(e).padStart(2,"0"));)e++;return"DOCK-"+String(e).padStart(2,"0")}function M(t){for(var e=1;v(t,"wall","WALL-"+String(e).padStart(2,"0"));)e++;return"WALL-"+String(e).padStart(2,"0")}function D(t){for(var e=1;v(t,"node","N"+e);)e++;return"N"+e}function T(t,e,i){return t.roadEdges.some(function(t){return t.from===e&&t.to===i||t.from===i&&t.to===e})}function P(t,e,i){var n=i||{},o={id:n.id||M(t),points:e.map(function(t){return[h(t[0]),h(t[1])]})};return n.name&&(o.name=n.name),!1===n.fill&&(o.fill=!1),t.walls.push(o),o}function L(t,e,i){var n=void 0===i?.8:i,o=b(t,e,n);if(o)return o.id;if(n>0){var a=function(t,e){var i=null;return t.roadEdges.forEach(function(n,o){var a=v(t,"node",n.from),r=v(t,"node",n.to);if(a&&r){var l=s.pointSegProjection(e.x,e.y,a.x,a.y,r.x,r.y);(!i||l.dist<i.dist)&&(i={dist:l.dist,x:l.x,y:l.y,t:l.t,edgeIndex:o})}}),i}(t,e);if(a&&a.dist<=n&&a.t>.01&&a.t<.99){var r=t.roadEdges[a.edgeIndex],l={id:D(t),x:h(a.x),y:h(a.y)};return t.roadNodes.push(l),t.roadEdges.splice(a.edgeIndex,1),t.roadEdges.push({from:r.from,to:l.id}),t.roadEdges.push({from:l.id,to:r.to}),l.id}}var d={id:D(t),x:h(e.x),y:h(e.y)};return t.roadNodes.push(d),d.id}function I(t,e,i){if(!e||!i||e===i)return null;if(!v(t,"node",e)||!v(t,"node",i))return null;if(T(t,e,i))return null;var n={from:e,to:i};return t.roadEdges.push(n),n}function O(t){if(!t||!t.entry||!t.points)return t;var e=s.projectPointOnPolygonBoundary(t.entry.x,t.entry.y,t.points);return t.entry={x:h(e.x),y:h(e.y)},t}function R(t){return!(!t||4!==t.length)&&t[0][1]===t[1][1]&&t[1][0]===t[2][0]&&t[2][1]===t[3][1]&&t[3][0]===t[0][0]}function z(t){var e={name:t.name,size:{width:t.size.width,height:t.size.height},walls:d(t.walls),docks:d(t.docks),slots:d(t.slots),roadNodes:d(t.roadNodes),roadEdges:t.roadEdges.map(function(t){return{from:t.from,to:t.to}}),roadWidth:t.roadWidth||l};return t.boundary&&t.boundary.length>=3&&(e.boundary=d(t.boundary)),e}var N={GRID_DEFAULT:.5,ROAD_SNAP_TOLERANCE:.8,ROAD_FILL_STEP_DEFAULT:5,ROAD_WIDTH_DEFAULT:l,MAX_ENTRY_ROAD_DISTANCE:10,MIN_ELEMENT_SIZE:.1,clone:d,round:h,snapValue:u,snapPoint:c,rectFromPoints:y,rectToPolygon:g,polygonToRect:x,polygonCenter:function(t){var e=s.polygonBounds(t);return{x:h((e.x1+e.x2)/2),y:h((e.y1+e.y2)/2)}},findElement:v,findNodeNear:b,nearestRoad:w,suggestEntry:k,nextSlotCode:S,nextDockId:E,nextNodeId:D,edgeExists:T,normalizeBoundary:f,orthoElbow:function(t,e){var i=e.x-t.x,n=e.y-t.y;return Math.abs(i)<1e-9||Math.abs(n)<1e-9?null:Math.abs(i)>=Math.abs(n)?{x:h(e.x),y:h(t.y)}:{x:h(t.x),y:h(e.y)}},boundaryPolygon:p,addSlot:function(t,e,i){var n={id:i||S(t),type:"slot",points:e.map(function(t){return[h(t[0]),h(t[1])]}),entry:k(e,t)};return t.slots.push(n),n},generateSlots:function(t,e,i){var n=i||{},o=h(n.width),a=h(n.depth),r=n.entryDir||"bottom",s=[],l=[];return(e||[]).forEach(function(e){if(v(t,"slot",e.code))l.push(e.code);else{var i,n=h(e.x),d=h(e.y),u=h(n+o/2),c=h(d+a/2);i="top"===r?{x:u,y:h(d+a)}:"left"===r?{x:n,y:c}:"right"===r?{x:h(n+o),y:c}:{x:u,y:d};var f={id:e.code,type:"slot",points:[[n,d],[h(n+o),d],[h(n+o),h(d+a)],[n,h(d+a)]],entry:i};e.name&&(f.name=e.name),t.slots.push(f),s.push(f)}}),{created:s,skipped:l}},generateDocks:function(t,e,i){var n=i||{},o=h(n.width),a=h(n.depth),r=n.entryDir||"bottom",s=[],l=[];return(e||[]).forEach(function(e){if(v(t,"dock",e.code))l.push(e.code);else{var i,n=h(e.x),d=h(e.y),u=h(n+o/2),c=h(d+a/2);i="top"===r?{x:u,y:h(d+a)}:"left"===r?{x:n,y:c}:"right"===r?{x:h(n+o),y:c}:{x:u,y:d};var f={id:e.code,name:e.name||t.docks.length+1+"号装卸口",type:"dock",points:[[n,d],[h(n+o),d],[h(n+o),h(d+a)],[n,h(d+a)]],entry:i};t.docks.push(f),s.push(f)}}),{created:s,skipped:l}},addDock:function(t,e,i){var n={id:E(t),name:i||t.docks.length+1+"号装卸口",type:"dock",points:e.map(function(t){return[h(t[0]),h(t[1])]}),entry:k(e,t)};return t.docks.push(n),n},addWall:P,addRoadNode:L,addRoadSegment:I,fillRoadBetween:function(t,e,i,n,o){var a=o||{},r=v(t,"node",e),s=v(t,"node",i);if(!r||!s)return null;var l=Math.hypot(s.x-r.x,s.y-r.y),d="number"==typeof n?n:5,u=1;d>0&&l>d&&(u=Math.ceil(l/d));for(var f=[],p=e,y=1;y<u;y++){var g=y/u,x={x:r.x+(s.x-r.x)*g,y:r.y+(s.y-r.y)*g};a.grid&&(x=c(x,a.grid));var m=L(t,x={x:h(x.x),y:h(x.y)},a.tolerance);m&&m!==p&&m!==i&&f.indexOf(m)<0&&f.push(m),I(t,p,m),p=m}return I(t,p,i),{nodeIds:f,segCount:u,filled:u>1}},removeElement:function(t,e,i){var n=m(t,e);if(!n)return!1;for(var o=-1,a=0;a<n.length;a++)if(n[a].id===i){o=a;break}return!(o<0||(n.splice(o,1),"node"===e&&(t.roadEdges=t.roadEdges.filter(function(t){return t.from!==i&&t.to!==i})),0))},applyElementGeometry:function(t,e,i,n,o){var a=v(t,e,i);return a?(n&&(a.points=n.map(function(t){return[h(t[0]),h(t[1])]})),o&&(a.entry={x:h(o.x),y:h(o.y)}),a):null},translateElement:function(t,e,i,n,o){var a=v(t,e,i);return a?(a.points&&(a.points=a.points.map(function(t){return[h(t[0]+n),h(t[1]+o)]})),a.entry&&(a.entry={x:h(a.entry.x+n),y:h(a.entry.y+o)}),a):null},resizeRectElement:function(t,e,i,n,o,a,r){var s=v(t,e,i);if(!s)return null;var l="number"==typeof r?r:.1,d={x:h(n.x),y:h(n.y)},u=c(o,a);return Math.abs(u.x-d.x)<l&&(u.x=d.x+(u.x>=d.x?l:-l)),Math.abs(u.y-d.y)<l&&(u.y=d.y+(u.y>=d.y?l:-l)),s.points=g(y(d,u)),O(s)},movePolygonVertex:function(t,e,i,n,o,a){var r=v(t,e,i);if(!r||!r.points||n<0||n>=r.points.length)return null;var s=c(o,a);return r.points.splice(n,1,[h(s.x),h(s.y)]),O(r)},isRectPolygon:R,resizeWallEdge:function(t,e,i,n,o,a){var r=v(t,"wall",e);if(!r||!R(r.points))return null;var s="number"==typeof a?a:.1,l=c(n,o),d=r.points.map(function(t){return t[0]}),h=r.points.map(function(t){return t[1]}),u=Math.min.apply(null,d),f=Math.max.apply(null,d),p=Math.min.apply(null,h),x=Math.max.apply(null,h);if(0===i)u=Math.min(l.x,f-s);else if(1===i)f=Math.max(l.x,u+s);else if(2===i)p=Math.min(l.y,x-s);else{if(3!==i)return null;x=Math.max(l.y,p+s)}return r.points=g(y({x:u,y:p},{x:f,y:x})),r},duplicateWall:function(t,e,i,n){var o=v(t,"wall",e);if(!o)return null;var a="number"==typeof i?i:1,r="number"==typeof n?n:1;return P(t,o.points.map(function(t){return[h(t[0]+a),h(t[1]+r)]}),{name:o.name})},WALL_MIN_SIZE:.1,slotsInRect:function(t,e){var i=[];return t.slots.forEach(function(t){var n=s.polygonBounds(t.points);!(n.x2<e.x1-1e-9||n.x1>e.x2+1e-9||n.y2<e.y1-1e-9||n.y1>e.y2+1e-9)&&i.push(t.id)}),i},shapesInRect:function(t,e){var i=[];return[["slots","slot"],["docks","dock"]].forEach(function(n){t[n[0]].forEach(function(t){if(t.points){var o=s.polygonBounds(t.points);!(o.x2<e.x1-1e-9||o.x1>e.x2+1e-9||o.y2<e.y1-1e-9||o.y1>e.y2+1e-9)&&i.push({kind:n[1],id:t.id})}})}),i},worldToBgPixel:function(t,e,i,n,o){return{x:(o.x-t.x)/t.w*i,y:e?(o.y-t.y)/t.h*n:(t.y+t.h-o.y)/t.h*n}},calibrateBgRect:function(t,e,i,n){var o=n.px.x-i.px.x,a=n.px.y-i.px.y;if(Math.abs(o)<1e-9||Math.abs(a)<1e-9)return{error:"两个参考点在图片上横向或纵向位置相同,无法确定比例,请沿对角线方向另选两点"};var r=(n.u.x-i.u.x)/o;if(r<=0)return{error:"两个参考点的 X 实际坐标与图片左右方向相反(横向为负),请检查是否把两点的 X 填反了(图片不支持左右镜像)"};var s=(n.u.y-i.u.y)/a;if(Math.abs(s)<1e-9)return{error:"两个参考点的 Y 实际坐标相同,无法确定纵向比例,请另选一个纵向位置不同的点"};var l,d=s>0,u=e*Math.abs(s);if(d)l={x:h(i.u.x-r*i.px.x),y:h(i.u.y-s*i.px.y),w:h(t*r),h:h(u)};else{var c=-s;l={x:h(i.u.x-r*i.px.x),y:h(i.u.y+c*i.px.y-u),w:h(t*r),h:h(u)}}return{rect:l,flipY:d}},setNodePosition:function(t,e,i){var n=v(t,"node",e);return n?(n.x=h(i.x),n.y=h(i.y),n):null},setEntry:function(t,e,i,n){var o=v(t,e,i);if(!o||!o.points)return null;var a=s.projectPointOnPolygonBoundary(n.x,n.y,o.points);return o.entry={x:h(a.x),y:h(a.y)},o},renameSlot:function(t,e,i){var n=String(i||"").trim();if(!n)return{ok:!1,message:"编码不能为空"};if(n===e)return{ok:!0};if(v(t,"slot",n))return{ok:!1,message:"编码 "+n+" 已存在"};var o=v(t,"slot",e);return o?(o.id=n,{ok:!0}):{ok:!1,message:"货位不存在"}},computeStats:function(t){var e=null;t.walls.forEach(function(t){!1!==t.fill||e||(e=t)});var i=p(t),n=i?s.polygonArea(i):t.size?t.size.width*t.size.height:0,o=0;t.slots.forEach(function(t){o+=s.polygonArea(t.points)});var a=t.roadWidth||l,r=0,d=0;return t.roadEdges.forEach(function(e){var i=v(t,"node",e.from),n=v(t,"node",e.to);if(i&&n){var o=Math.hypot(n.x-i.x,n.y-i.y);r+=o,d+=o*a}}),{warehouseArea:h(n,1),slotCount:t.slots.length,slotArea:h(o,1),dockCount:t.docks.length,wallCount:t.walls.length,roadNodeCount:t.roadNodes.length,roadEdgeCount:t.roadEdges.length,roadLength:h(r,1),roadArea:h(d,1),slotRatio:n?h(o/n*100,1):0,roadRatio:n?h(d/n*100,1):0}},validateModel:function(t){var e=[];[["slot","货位"],["dock","装卸口"]].forEach(function(i){var n=i[0],o=i[1],a={};m(t,n).forEach(function(t){a[t.id]&&e.push({level:"error",message:o+"编码重复:"+t.id,target:{kind:n,id:t.id}}),a[t.id]=!0})});var i=null;t.walls.forEach(function(t){!1!==t.fill||i||(i=t)});var n=i?s.polygonBounds(i.points):null,o=t.boundary&&t.boundary.length>=3?t.boundary:null;t.slots.forEach(function(t){x(t.points)||e.push({level:"error",message:"货位 "+t.id+" 不是矩形(货位需为长方形、单端进出)",target:{kind:"slot",id:t.id}})}),["slot","dock"].forEach(function(i){var a="slot"===i?"货位":"装卸口";m(t,i).forEach(function(r){var l=a+" "+r.id;if(o)r.points.some(function(t){if(s.pointInPolygon(t[0],t[1],o))return!1;var e=s.projectPointOnPolygonBoundary(t[0],t[1],o);return!(e&&s.dist(t[0],t[1],e.x,e.y)<=.05)})&&e.push({level:"warn",message:l+" 超出仓库边界范围",target:{kind:i,id:r.id}});else if(n){var d=s.polygonBounds(r.points);(d.x1<n.x1-1e-6||d.y1<n.y1-1e-6||d.x2>n.x2+1e-6||d.y2>n.y2+1e-6)&&e.push({level:"warn",message:l+" 超出外墙范围",target:{kind:i,id:r.id}})}if(r.entry){var u=w(t,r.entry);u?u.dist>10&&e.push({level:"warn",message:a+" "+r.id+" 入口距道路 "+h(u.dist,1)+" 米,超过 10 米将无法接驳",target:{kind:i,id:r.id}}):e.push({level:"warn",message:a+" "+r.id+" 尚未接驳道路(当前没有任何道路)",target:{kind:i,id:r.id}})}else e.push({level:"error",message:a+" "+r.id+" 缺少入口点",target:{kind:i,id:r.id}})})});var a={};t.roadNodes.forEach(function(t){a[t.id]=!0});var r={};if(t.roadEdges.forEach(function(t){a[t.from]&&a[t.to]?(r[t.from]=!0,r[t.to]=!0):e.push({level:"error",message:"道路边 "+t.from+" → "+t.to+" 引用了不存在的节点"})}),t.roadNodes.forEach(function(t){r[t.id]||e.push({level:"warn",message:"道路节点 "+t.id+" 是孤立节点(没有连接任何道路)",target:{kind:"node",id:t.id}})}),t.roadEdges.length>0){var l={};t.roadEdges.forEach(function(t){(l[t.from]=l[t.from]||[]).push(t.to),(l[t.to]=l[t.to]||[]).push(t.from)});var d={},u=0;Object.keys(l).forEach(function(t){if(!d[t]){u++;var e=[t];for(d[t]=!0;e.length;){var i=e.shift();(l[i]||[]).forEach(function(t){d[t]||(d[t]=!0,e.push(t))})}}}),u>1&&e.push({level:"warn",message:"道路网被分成 "+u+" 个互不连通的部分(新画道路两端需点在已有节点吸附半径内,或压在已有道路上自动拆边接入),跨部分导航会失败"})}if(t.roadEdges.forEach(function(i){var n=v(t,"node",i.from),o=v(t,"node",i.to);n&&o&&t.slots.forEach(function(t){for(var a=!1,r=0;r<t.points.length&&!a;r++){var l=t.points[r],d=t.points[(r+1)%t.points.length];s.segSegIntersect(n.x,n.y,o.x,o.y,l[0],l[1],d[0],d[1])&&(a=!0)}!a&&s.pointInPolygon(n.x,n.y,t.points)&&s.pointInPolygon(o.x,o.y,t.points)&&(a=!0),a&&e.push({level:"warn",message:"道路 "+i.from+" → "+i.to+" 穿过货位 "+t.id,target:{kind:"slot",id:t.id}})})}),o)for(var c=0;c<o.length;c++){var f=o[c],p=o[(c+1)%o.length];Math.abs(f[0]-p[0])>1e-6&&Math.abs(f[1]-p[1])>1e-6&&e.push({level:"warn",message:"仓库边界第 "+(c+1)+" 段是斜线(绘制时会自动横平竖直,建议重画边界)"})}return e},createHistory:function(t){var e=[],i=-1,n=t||100;return{push:function(t){var o=JSON.stringify(t);return!(i>=0&&e[i]===o||((e=e.slice(0,i+1)).push(o),e.length>n&&e.shift(),i=e.length-1,0))},undo:function(){return i<=0?null:(i--,JSON.parse(e[i]))},redo:function(){return i>=e.length-1?null:(i++,JSON.parse(e[i]))},canUndo:function(){return i>0},canRedo:function(){return i<e.length-1},size:function(){return e.length},reset:function(t){e=[JSON.stringify(t)],i=0}}},exportLayout:z,parseLayout:function(t){var e="string"==typeof t?JSON.parse(t):t;if(!e||"object"!==r(e))throw new Error("不是合法的 JSON 对象");if(["walls","docks","slots","roadNodes","roadEdges"].forEach(function(t){if(!Array.isArray(e[t]))throw new Error("缺少数组字段:"+t)}),!e.size||"number"!=typeof e.size.width||"number"!=typeof e.size.height)throw new Error("缺少 size.width / size.height");if(void 0!==e.boundary&&!Array.isArray(e.boundary))throw new Error("boundary 必须是坐标数组");if(e.boundary&&e.boundary.length<3)throw new Error("boundary 至少需要 3 个点");return z({name:e.name,size:e.size,boundary:e.boundary?f(e.boundary):void 0,walls:e.walls,docks:e.docks,slots:e.slots,roadNodes:e.roadNodes,roadEdges:e.roadEdges.map(function(t){return{from:t.from,to:t.to}}),roadWidth:"number"==typeof e.roadWidth?e.roadWidth:e.roadWidths&&(e.roadWidths.branch||e.roadWidths.main)||l})}},A=e,W=a,B=W.pointInPolygon,C=N,j={floor:"#f8fafc",grid:"rgba(15, 23, 42, 0.18)",gridFine:"rgba(15, 23, 42, 0.07)",gridLabel:"rgba(15, 23, 42, 0.28)",road:"#dcd8d1",wallFill:"#d4d9e0",wallStroke:"#7c8592",outerWall:"#545964",slot:"rgba(96, 165, 250, 0.30)",slotHover:"#bfdbfe",slotSelected:"#93c5fd",slotStroke:"#3b82f6",slotEmpty:"rgba(74, 222, 128, 0.34)",slotEmptyStroke:"#22c55e",slotPartial:"rgba(251, 191, 36, 0.38)",slotPartialStroke:"#f59e0b",slotFull:"rgba(239, 68, 68, 0.38)",slotFullStroke:"#dc2626",slotHoverStroke:"#2563eb",slotSelectedStroke:"#1d4ed8",slotText:"#ffffff",slotTextHalo:"rgba(15, 23, 42, 0.45)",dock:"#ffedd5",dockStroke:"#ea580c",dockText:"#9a3412",entry:"#ef4444",path:"#ef4444",pathHalo:"rgba(239, 68, 68, 0.18)",pathStart:"#2563eb",node:"#1f2937",selection:"#2563eb",selectionHalo:"rgba(37, 99, 235, 0.28)",draft:"#7c3aed",axisLabel:"#475569",axisLabelHalo:"rgba(255, 255, 255, 0.9)"},_={floor:"#111827",grid:"rgba(148, 163, 184, 0.20)",gridFine:"rgba(148, 163, 184, 0.08)",gridLabel:"rgba(148, 163, 184, 0.45)",road:"#374151",wallFill:"#1f2937",wallStroke:"#9ca3af",outerWall:"#e5e7eb",slot:"rgba(59, 130, 246, 0.30)",slotHover:"#1d4ed8",slotSelected:"#2563eb",slotStroke:"#60a5fa",slotEmpty:"rgba(34, 197, 94, 0.30)",slotEmptyStroke:"#4ade80",slotPartial:"rgba(245, 158, 11, 0.34)",slotPartialStroke:"#fbbf24",slotFull:"rgba(239, 68, 68, 0.36)",slotFullStroke:"#f87171",slotHoverStroke:"#60a5fa",slotSelectedStroke:"#93c5fd",slotText:"#ffffff",slotTextHalo:"rgba(0, 0, 0, 0.65)",dock:"#7c2d12",dockStroke:"#fb923c",dockText:"#fed7aa",entry:"#f87171",path:"#f87171",pathHalo:"rgba(248, 113, 113, 0.22)",pathStart:"#60a5fa",node:"#e5e7eb",selection:"#3b82f6",selectionHalo:"rgba(59, 130, 246, 0.35)",draft:"#a78bfa",axisLabel:"#cbd5e1",axisLabelHalo:"rgba(0, 0, 0, 0.6)"},F={name:"WarehouseMap",props:{layout:{type:Object,default:null},path:{type:Array,default:function(){return[]}},selectedId:{type:String,default:""},mode:{type:String,default:"view"},draft:{type:Object,default:null},selection:{type:Object,default:null},gridSnap:{type:Number,default:0},roadSnap:{type:Number,default:C.ROAD_SNAP_TOLERANCE},slotStatus:{type:Object,default:function(){return{}}},multiIds:{type:Array,default:function(){return[]}},bgImage:{type:Object,default:null},bgRect:{type:Object,default:null},bgOpacity:{type:Number,default:.5},bgFlipY:{type:Boolean,default:!1},minRect:{type:Number,default:.5},showEditLayer:{type:Boolean,default:!1},night:{type:Boolean,default:!1}},data:function(){return{canvasWidth:1e3,canvasHeight:680,hoverId:"",cursorWorld:null,localMulti:[],selfMulti:null}},computed:{tipText:function(){if(!this.layout)return"";var t=[];if(this.hoverId){var e=this.findShape(this.hoverId);e&&t.push(e.id+(e.name?" · "+e.name:""))}if(this.cursorWorld){var i=this.cursorWorld.x,n=this.cursorWorld.y;this.gridSnap>0&&(i=Math.round(i/this.gridSnap)*this.gridSnap,n=Math.round(n/this.gridSnap)*this.gridSnap),t.push("x "+i.toFixed(1)+", y "+n.toFixed(1)+" m")}return t.join(" ")}},watch:{layout:{handler:function(){this.staticDirty=!0,this.refreshNodeIndex(),this.scheduleDraw()},deep:!0},path:function(){this.syncPathAnim(),this.scheduleDraw()},selectedId:function(){this.scheduleDraw()},hoverId:function(){this.scheduleDraw()},mode:function(){this.rectDraft=null,this.multiDraft=null,this.dragging=null,this.panState=null,this.alignLines=null,this.alignTargets=null,this.alignOrig=null,this.scheduleDraw()},draft:function(){this.scheduleDraw()},selection:function(){this.scheduleDraw()},gridSnap:function(){this.staticDirty=!0,this.scheduleDraw()},night:function(){this.staticDirty=!0,this.scheduleDraw()},multiIds:function(t){t!==this.selfMulti&&(this.localMulti=(t||[]).slice(),this.selfMulti=null),this.scheduleDraw()},bgImage:function(){this.staticDirty=!0,this.scheduleDraw()},bgRect:function(){this.staticDirty=!0,this.scheduleDraw()},bgOpacity:function(){this.staticDirty=!0,this.scheduleDraw()},bgFlipY:function(){this.staticDirty=!0,this.scheduleDraw()},showEditLayer:function(){this.staticDirty=!0,this.scheduleDraw()},slotStatus:function(){this.staticDirty=!0,this.scheduleDraw()}},mounted:function(){this.view=null,this.panState=null,this.dragging=null,this.mouseDown=null,this.movedPx=0,this.rectDraft=null,this.multiDraft=null,this.nodeById={},this.animRaf=null,this.animOffset=0,this.staticCanvas=null,this.staticSig="",this.staticDirty=!0,this.drawScheduled=!1,this.hoverBgEdge=-1,this.alignLines=null,this.alignTargets=null,this.alignOrig=null,this.refreshNodeIndex(),this.updateCanvasSize(),this.draw();var t=this;"function"==typeof ResizeObserver?(this.ro=new ResizeObserver(function(){t.updateCanvasSize()}),this.ro.observe(this.$refs.wrap)):(this.onWinResize=function(){t.updateCanvasSize()},window.addEventListener("resize",this.onWinResize))},beforeDestroy:function(){this.stopPathAnim(),this.ro&&this.ro.disconnect(),this.onWinResize&&window.removeEventListener("resize",this.onWinResize),this.view=null,this.staticCanvas=null},methods:{updateCanvasSize:function(){var t=this.$refs.wrap;if(t){var e=t.clientWidth||1e3,i=t.clientHeight||680;e=Math.round(e),i=Math.round(i),e===this.canvasWidth&&i===this.canvasHeight||(this.canvasWidth=e,this.canvasHeight=i,this.view=null,this.ensureView(),this.scheduleDraw())}},refreshNodeIndex:function(){var t=this;this.nodeById={},this.layout&&this.layout.roadNodes.forEach(function(e){t.nodeById[e.id]=e})},syncPathAnim:function(){this.path&&this.path.length>1?this.startPathAnim():this.stopPathAnim()},startPathAnim:function(){if(!this.animRaf&&"function"==typeof window.requestAnimationFrame){var t=this,e=Date.now();!function i(){t.animOffset=(Date.now()-e)/30,t.draw(),t.animRaf=window.requestAnimationFrame(i)}()}},stopPathAnim:function(){this.animRaf&&"function"==typeof window.cancelAnimationFrame&&window.cancelAnimationFrame(this.animRaf),this.animRaf=null,this.animOffset=0},ensureView:function(){!this.view&&this.layout&&(this.view=A({canvasWidth:this.canvasWidth,canvasHeight:this.canvasHeight,worldWidth:this.layout.size.width,worldHeight:this.layout.size.height,padding:20}),this.applyBoundaryFit())},applyBoundaryFit:function(){if(this.view&&this.layout){var t=this.layout.boundary&&this.layout.boundary.length>=3?W.polygonBounds(this.layout.boundary):{x1:0,y1:0,x2:this.layout.size.width,y2:this.layout.size.height};this.view.fitBounds(t.x1,t.y1,t.x2,t.y2,20)}},fitBoundary:function(){this.ensureView(),this.applyBoundaryFit(),this.scheduleDraw()},resetView:function(){this.view&&(this.view.reset(),this.scheduleDraw())},eventToCanvas:function(t){var e=this.$refs.canvas,i=e.getBoundingClientRect(),n=i.width>0?e.width/i.width:1,o=i.height>0?e.height/i.height:1;return{px:(t.clientX-i.left)*n,py:(t.clientY-i.top)*o}},worldAt:function(t){var e=this.eventToCanvas(t);return this.view.screenToWorld(e.px,e.py)},snapWorld:function(t){var e=this.worldAt(t);if("view"===this.mode)return{point:e,nodeId:null};var i=C.snapPoint(e,this.gridSnap||0),n=null;if("road"===this.mode&&this.layout){var o=C.findNodeNear(this.layout,i,this.roadSnap);o&&(n=o.id)}return{point:i,nodeId:n}},toleranceMeters:function(t){return this.view?Math.max(.25,t/this.view.getScale()):.5},findShape:function(t){if(!this.layout)return null;for(var e=this.layout.slots.concat(this.layout.docks),i=0;i<e.length;i++)if(e[i].id===t)return e[i];return null},hitShape:function(t){if(!this.layout)return null;for(var e=["slots","docks","walls"],i=0;i<e.length;i++)for(var n=this.layout[e[i]],o=n.length-1;o>=0;o--)if(n[o].points&&B(t.x,t.y,n[o].points))return{kind:"slots"===e[i]?"slot":"docks"===e[i]?"dock":"wall",id:n[o].id,shape:n[o]};return null},hitNode:function(t){if(!this.layout||!this.showEditLayer)return null;var e=this.toleranceMeters(7),i=null;return this.layout.roadNodes.forEach(function(n){var o=Math.hypot(n.x-t.x,n.y-t.y);o<=e&&(!i||o<i.d)&&(i={node:n,d:o})}),i?{kind:"node",id:i.node.id}:null},hitEntry:function(t){if(!this.layout||!this.showEditLayer)return null;var e=this.toleranceMeters(8),i=null,n=this;return["slot","dock"].forEach(function(o){("slot"===o?n.layout.slots:n.layout.docks).forEach(function(n){if(n.entry){var a=Math.hypot(n.entry.x-t.x,n.entry.y-t.y);a<=e&&(!i||a<i.d)&&(i={kind:o,id:n.id,d:a})}})}),i?{kind:i.kind,id:i.id,part:"entry"}:null},selectionHandles:function(){var t=this.findSelShape();if(!t||!t.points||t.points.length<2)return[];if("wall"===this.selection.kind){if(C.isRectPolygon(t.points)){var e=W.polygonBounds(t.points),i=(e.y1+e.y2)/2,n=(e.x1+e.x2)/2;return[{x:e.x1,y:e.y1,index:0,rect:!0},{x:e.x2,y:e.y1,index:1,rect:!0},{x:e.x2,y:e.y2,index:2,rect:!0},{x:e.x1,y:e.y2,index:3,rect:!0},{x:e.x1,y:i,index:0,edge:!0,rect:!0},{x:e.x2,y:i,index:1,edge:!0,rect:!0},{x:n,y:e.y1,index:2,edge:!0,rect:!0},{x:n,y:e.y2,index:3,edge:!0,rect:!0}]}return t.points.map(function(t,e){return{x:t[0],y:t[1],index:e}})}if(4!==t.points.length)return[];var o=W.polygonBounds(t.points);return[{x:o.x1,y:o.y1,index:0},{x:o.x2,y:o.y1,index:1},{x:o.x2,y:o.y2,index:2},{x:o.x1,y:o.y2,index:3}]},hitHandle:function(t){if(!this.layout||!this.showEditLayer||"select"!==this.mode)return null;if(!this.selection||"node"===this.selection.kind)return null;var e,i=this.toleranceMeters(9),n=null;return this.selectionHandles().forEach(function(e){var o=Math.hypot(e.x-t.x,e.y-t.y);o<=i&&(!n||o<n.d)&&(n={h:e,d:o})}),n?(e="wall"===this.selection.kind?n.h.rect?n.h.edge?"edge-resize":"resize":"vertex":"resize",{kind:this.selection.kind,id:this.selection.id,part:e,index:n.h.index,edge:n.h.edge?n.h.index:void 0}):null},onMouseDown:function(t){if(this.ensureView(),this.view){var e=this.eventToCanvas(t);if(this.mouseDown={px:e.px,py:e.py},this.movedPx=0,1===t.button)return this.panState={px:e.px,py:e.py},void(this.$refs.canvas.style.cursor="grabbing");if(0===t.button){var i=this.worldAt(t),n=this.snapWorld(t);if("view"!==this.mode){if("rect"===this.mode)return this.rectDraft={x1:n.point.x,y1:n.point.y,x2:n.point.x,y2:n.point.y},void this.scheduleDraw();if("bg-adjust"!==this.mode){if("multi"===this.mode){var o=this.hitShape(i);if(o&&("slot"===o.kind||"dock"===o.kind)){if(t.ctrlKey||t.metaKey){var a=this.multiHas(o.kind,o.id),r=this.localMulti.filter(function(t){return!(t.kind===o.kind&&t.id===o.id)});return a||(r=r.concat([{kind:o.kind,id:o.id}])),void this.setMulti(r)}return this.multiHas(o.kind,o.id)||this.setMulti([{kind:o.kind,id:o.id}]),void this.startDrag({kind:o.kind,id:o.id,part:"group"},i)}if(t.ctrlKey||t.metaKey)return;return this.multiDraft={x1:i.x,y1:i.y,x2:i.x,y2:i.y},void this.scheduleDraw()}if("select"===this.mode){var s=this;function p(){s.localMulti.length&&s.setMulti([])}var l=this.hitShape(i);if((t.ctrlKey||t.metaKey)&&l&&("slot"===l.kind||"dock"===l.kind))return a=this.multiHas(l.kind,l.id),r=this.localMulti.filter(function(t){return!(t.kind===l.kind&&t.id===l.id)}),a||(r=r.concat([{kind:l.kind,id:l.id}])),this.setMulti(r),void this.startDrag({kind:l.kind,id:l.id,part:"group"},i);var d=this.localMulti.length>1;if(!d){var h=this.hitHandle(i);if(h)return p(),this.$emit("select-change",{kind:h.kind,id:h.id}),void this.startDrag(h,i);var u=this.hitEntry(i);if(u)return p(),this.$emit("select-change",{kind:u.kind,id:u.id}),void this.startDrag({kind:u.kind,id:u.id,part:"entry"},i)}if(l)return d&&this.multiHas(l.kind,l.id)?void this.startDrag({kind:l.kind,id:l.id,part:"group"},i):(p(),this.$emit("select-change",{kind:l.kind,id:l.id}),"slot"!==l.kind&&"dock"!==l.kind||this.setMulti([{kind:l.kind,id:l.id}]),void this.startDrag({kind:l.kind,id:l.id,part:"body"},i));if(!d){var c=this.hitNode(i);if(c)return p(),this.$emit("select-change",{kind:"node",id:c.id}),void this.startDrag({kind:"node",id:c.id,part:"body"},i)}p(),this.$emit("select-change",null)}}else{var f=this.hitBgEdge(i);f>=0?this.dragging={target:{kind:"bg",part:"edge",edge:f},point:i,bgOrig:{x:this.bgRect.x,y:this.bgRect.y,w:this.bgRect.w,h:this.bgRect.h}}:this.pointInBgRect(i)&&(this.dragging={target:{kind:"bg",part:"body"},point:i,bgOrig:{x:this.bgRect.x,y:this.bgRect.y,w:this.bgRect.w,h:this.bgRect.h}})}}else this.panState={px:e.px,py:e.py}}}},startDrag:function(t,e){if(this.dragging={target:t,point:e},this.alignLines=null,this.alignTargets=null,this.alignOrig=null,"body"===t.part||"group"===t.part){var i="group"===t.part?this.localMulti.slice():[{kind:t.kind,id:t.id}];this.alignOrig=this.bboxOfIds(i),this.alignTargets=this.collectAlignTargets(i)}this.$emit("drag-start",{target:t,point:e})},bboxOfIds:function(t){var e=this,i=null;return t.forEach(function(t){var n=C.findElement(e.layout,t.kind,t.id);if(n&&n.points){var o=W.polygonBounds(n.points);i=i?{x1:Math.min(i.x1,o.x1),y1:Math.min(i.y1,o.y1),x2:Math.max(i.x2,o.x2),y2:Math.max(i.y2,o.y2)}:o}}),i},multiHas:function(t,e){return this.localMulti.some(function(i){return i.kind===t&&i.id===e})},setMulti:function(t){this.selfMulti=t,this.localMulti=t.slice(),this.$emit("area-select",{ids:t}),this.scheduleDraw()},collectAlignTargets:function(t){var e=[],i=[],n=this.layout;if(!n)return{xs:e,ys:i};var o={};(t||[]).forEach(function(t){o[t.kind+":"+t.id]=1}),["slots","docks","walls"].forEach(function(t){var a="slots"===t?"slot":"docks"===t?"dock":"wall";n[t].forEach(function(t){if(!o[a+":"+t.id]&&t.points&&!(t.points.length<3)){var n=W.polygonBounds(t.points);e.push(n.x1,(n.x1+n.x2)/2,n.x2),i.push(n.y1,(n.y1+n.y2)/2,n.y2)}})});var a=n.boundary&&n.boundary.length>=3?W.polygonBounds(n.boundary):{x1:0,y1:0,x2:n.size.width,y2:n.size.height};return e.push(a.x1,a.x2,0,n.size.width),i.push(a.y1,a.y2,0,n.size.height),n.roadNodes.forEach(function(t){e.push(t.x),i.push(t.y)}),e.sort(function(t,e){return t-e}),i.sort(function(t,e){return t-e}),{xs:e,ys:i}},alignmentSnap:function(t,e){var i=this.alignOrig,n=this.alignTargets,o={dx:0,dy:0,xs:[],ys:[]};if(!i||!n)return o;var a=Math.max(.05,5/this.view.getScale()),r=this.gridSnap||0;function s(t){return r>0?C.snapValue(t,r):t}function l(t,e){for(var i=null,n=0;n<t.length;n++){var o=Math.abs(t[n]-e);o<=a&&(!i||o<i.d)&&(i={t:t[n],d:o})}return i}var d=null;[i.x1+t,(i.x1+i.x2)/2+t,i.x2+t].forEach(function(t){var e=l(n.xs,t);e&&(!d||e.d<d.d)&&(d={t:e.t,c:t,d:e.d})}),d&&(o.dx=s(d.t-d.c),o.xs=[d.t]);var h=null;return[i.y1+e,(i.y1+i.y2)/2+e,i.y2+e].forEach(function(t){var e=l(n.ys,t);e&&(!h||e.d<h.d)&&(h={t:e.t,c:t,d:e.d})}),h&&(o.dy=s(h.t-h.c),o.ys=[h.t]),o},onMouseMove:function(t){if(this.view){var e=this.$refs.canvas;if(e){var i=this.eventToCanvas(t),n=this.worldAt(t);if(this.cursorWorld=n,this.panState){var o=i.px-this.panState.px,a=i.py-this.panState.py;return this.movedPx+=Math.abs(o)+Math.abs(a),this.view.pan(o,a),this.panState={px:i.px,py:i.py},void this.scheduleDraw()}if(this.mouseDown&&(this.movedPx+=Math.abs(i.px-this.mouseDown.px)+Math.abs(i.py-this.mouseDown.py),this.mouseDown={px:i.px,py:i.py}),this.dragging&&"bg"===this.dragging.target.kind){var r=this.applyBgDrag(n,t.shiftKey);r&&this.$emit("bg-rect-change",r)}else{if(this.dragging){var s=n;if(this.alignOrig&&this.alignTargets&&("body"===this.dragging.target.part||"group"===this.dragging.target.part)){var l=this.alignmentSnap(n.x-this.dragging.point.x,n.y-this.dragging.point.y);(l.dx||l.dy)&&(s={x:n.x+l.dx,y:n.y+l.dy}),this.alignLines={xs:l.xs,ys:l.ys}}else this.alignLines=null;return this.$emit("drag-move",{target:this.dragging.target,point:s}),void this.scheduleDraw()}if(this.rectDraft){var d=this.snapWorld(t);return this.rectDraft.x2=d.point.x,this.rectDraft.y2=d.point.y,void this.scheduleDraw()}if(this.multiDraft)return this.multiDraft.x2=n.x,this.multiDraft.y2=n.y,void this.scheduleDraw();if("bg-adjust"===this.mode){var h=this.hitBgEdge(n);return h!==this.hoverBgEdge&&(this.hoverBgEdge=h,this.scheduleDraw()),void(e.style.cursor=0===h||1===h?"ew-resize":2===h||3===h?"ns-resize":this.pointInBgRect(n)?"move":"default")}var u=this.hitShape(n),c=u?u.id:"";c!==this.hoverId&&(this.hoverId=c),"view"===this.mode||"select"===this.mode?e.style.cursor="select"===this.mode&&this.hitHandle(n)?"crosshair":u?"pointer":"default":e.style.cursor="crosshair","polygon"!==this.mode&&"road"!==this.mode||this.scheduleDraw()}}}},onMouseUp:function(t){if(this.view)if(this.panState){if(this.panState=null,this.$refs.canvas.style.cursor="view"===this.mode||"select"===this.mode?"default":"crosshair","view"===this.mode&&this.movedPx<5){var e=this.hitShape(this.worldAt(t));e&&this.$emit("shape-click",Object.assign({},e.shape,{type:e.kind}))}}else{if(this.dragging){var i=this.dragging.target;return this.dragging=null,this.alignLines=null,this.alignTargets=null,this.alignOrig=null,this.$emit("drag-end",{target:i}),void this.scheduleDraw()}if(this.rectDraft){var n=C.rectFromPoints({x:this.rectDraft.x1,y:this.rectDraft.y1},{x:this.rectDraft.x2,y:this.rectDraft.y2});return this.rectDraft=null,n.width>=this.minRect&&n.height>=this.minRect&&this.$emit("rect-drawn",{rect:n}),void this.scheduleDraw()}if(this.multiDraft){var o=C.rectFromPoints({x:this.multiDraft.x1,y:this.multiDraft.y1},{x:this.multiDraft.x2,y:this.multiDraft.y2});this.multiDraft=null;var a=o.width>=.2||o.height>=.2?C.shapesInRect(this.layout,o):[];this.setMulti(a)}else if(!(this.movedPx>=5))if("view"!==this.mode){if("polygon"===this.mode||"road"===this.mode||"pick"===this.mode){var r=this.snapWorld(t);this.$emit("canvas-click",{point:r.point,nodeId:r.nodeId})}}else{var s=this.hitShape(this.worldAt(t));s&&this.$emit("shape-click",Object.assign({},s.shape,{type:s.kind}))}}else this.mouseDown=null},onMouseLeave:function(){this.panState=null,this.dragging=null,this.mouseDown=null,this.cursorWorld=null,this.multiDraft=null,this.hoverId="",this.alignLines=null,this.alignTargets=null,this.alignOrig=null},onDblClick:function(t){"polygon"!==this.mode&&"road"!==this.mode||this.$emit("canvas-dblclick",{point:this.worldAt(t)})},onWheel:function(t){if(this.ensureView(),this.view){var e=this.eventToCanvas(t),i=t.deltaY<0?1.15:1/1.15;this.view.zoomAt(e.px,e.py,i),this.scheduleDraw()}},scheduleDraw:function(){if(!this.drawScheduled){this.drawScheduled=!0;var t=this;"function"==typeof window.requestAnimationFrame?window.requestAnimationFrame(function(){t.drawScheduled=!1,t.draw()}):(this.drawScheduled=!1,this.draw())}},draw:function(){this.ensureView();var t=this.$refs.canvas;if(t){var e=t.getContext&&t.getContext("2d");if(e&&this.view&&this.layout){var i=this,n=this.view.getScale(),o=function(t,e){return i.view.toScreen(t,e)},a=this.view.signature();if(this.staticDirty||a!==this.staticSig||!this.staticCanvas||this.staticCanvas.width!==t.width||this.staticCanvas.height!==t.height){var r=null;if("undefined"!=typeof document&&document.createElement&&(this.staticCanvas&&this.staticCanvas.width===t.width&&this.staticCanvas.height===t.height||(this.staticCanvas=document.createElement("canvas"),this.staticCanvas.width=t.width,this.staticCanvas.height=t.height),r=this.staticCanvas.getContext&&this.staticCanvas.getContext("2d")),this.staticSig=a,this.staticDirty=!1,!r)return e.clearRect(0,0,t.width,t.height),this.drawStatic(e,o,n),void this.drawOverlay(e,o,n);r.clearRect(0,0,this.staticCanvas.width,this.staticCanvas.height),this.drawStatic(r,o,n),e.clearRect(0,0,t.width,t.height),e.drawImage(this.staticCanvas,0,0)}else e.clearRect(0,0,t.width,t.height),e.drawImage(this.staticCanvas,0,0);this.drawOverlay(e,o,n)}}},drawStatic:function(t,e,i){var n=this,o=this.night?_:j,a=this.layout,r=a.boundary&&a.boundary.length>=3?a.boundary:null,s=r||[[0,0],[a.size.width,0],[a.size.width,a.size.height],[0,a.size.height]];function l(){t.beginPath(),s.forEach(function(i,n){var o=e(i[0],i[1]);0===n?t.moveTo(o.x,o.y):t.lineTo(o.x,o.y)}),t.closePath()}if(t.save(),l(),t.clip(),l(),t.fillStyle=o.floor,t.fill(),this.showEditLayer&&this.bgImage&&this.bgRect&&this.bgImage.el){var d=this.bgRect,h=e(d.x,d.y+d.h),u=d.w*i,c=d.h*i;t.save(),t.globalAlpha=this.bgOpacity,this.bgFlipY?(t.translate(h.x,h.y+c),t.scale(1,-1),t.drawImage(this.bgImage.el,0,0,u,c)):t.drawImage(this.bgImage.el,h.x,h.y,u,c),t.restore()}t.restore(),this.showEditLayer&&this.gridSnap>0&&this.drawGrid(t,e),r&&(l(),t.strokeStyle=o.outerWall,t.lineWidth=Math.min(3,Math.max(1.2,.08*i)),t.stroke()),this.showEditLayer&&this.gridSnap>0&&this.drawAxisLabels(t,e);var f=a.roadWidth||4;t.strokeStyle=o.road,t.lineCap="round",t.lineJoin="round",a.roadEdges.forEach(function(o){var a=n.nodeById[o.from],r=n.nodeById[o.to];if(a&&r){var s=e(a.x,a.y),l=e(r.x,r.y);t.lineWidth=f*i,t.beginPath(),t.moveTo(s.x,s.y),t.lineTo(l.x,l.y),t.stroke()}}),a.walls.forEach(function(a){if(a.points&&!(a.points.length<2)&&(t.beginPath(),a.points.forEach(function(i,n){var o=e(i[0],i[1]);0===n?t.moveTo(o.x,o.y):t.lineTo(o.x,o.y)}),t.closePath(),!1!==a.fill&&(t.fillStyle=o.wallFill,t.fill()),t.strokeStyle=!1===a.fill?o.outerWall:o.wallStroke,t.lineWidth=!1===a.fill?4:1.5,t.stroke(),a.name&&!1!==a.fill)){var r=W.polygonBounds(a.points),s=e((r.x1+r.x2)/2,(r.y1+r.y2)/2);t.fillStyle=o.dockText,t.font=n.textScale(12)+"px sans-serif",t.textAlign="center",t.textBaseline="middle",t.fillText(n.fitText(t,a.name,(r.x2-r.x1)*i-4),s.x,s.y)}}),a.slots.forEach(function(a){var r=o.slot,s=o.slotStroke,l=n.slotStatus?n.slotStatus[a.id]:null;l&&"empty"===l.state?(r=o.slotEmpty,s=o.slotEmptyStroke):l&&"full"===l.state?(r=o.slotFull,s=o.slotFullStroke):l&&(r=o.slotPartial,s=o.slotPartialStroke),n.drawPolygon(t,a.points,e,r,s,n.lineScale(1.4));var d=W.polygonBounds(a.points),h=e((d.x1+d.x2)/2,(d.y1+d.y2)/2);if(n.drawSlotLabel(t,a.name||a.id,d,h,i),a.entry&&n.showEditLayer){var u=e(a.entry.x,a.entry.y);n.drawDot(t,u.x,u.y,3,o.entry)}}),a.docks.forEach(function(a){n.drawPolygon(t,a.points,e,o.dock,o.dockStroke,n.lineScale(1.4));var r=W.polygonBounds(a.points),s=e((r.x1+r.x2)/2,(r.y1+r.y2)/2);t.fillStyle=o.dockText,t.textAlign="center",t.textBaseline="middle";var l=n.textScale(11),d=(r.y2-r.y1)*i;if(d>=1.4*l){t.font=l+"px sans-serif";var h=(r.x2-r.x1)*i-4;t.fillText(n.fitText(t,a.id,h),s.x,s.y-.6*l)}if(d>=3*l&&a.name&&(t.font=Math.max(2,l-1)+"px sans-serif",t.fillText(n.fitText(t,a.name,(r.x2-r.x1)*i-4),s.x,s.y+.6*l)),a.entry&&n.showEditLayer){var u=e(a.entry.x,a.entry.y);n.drawDot(t,u.x,u.y,3.5,o.entry)}})},drawOverlay:function(t,e,i){var n=this,o=this.night?_:j,a=this.layout;if(a.slots.forEach(function(a){if(a.id===n.hoverId||a.id===n.selectedId){var r=a.id===n.selectedId?o.slotSelected:o.slotHover,s=a.id===n.selectedId?o.slotSelectedStroke:o.slotHoverStroke;n.drawPolygon(t,a.points,e,r,s,n.lineScale(2));var l=W.polygonBounds(a.points),d=e((l.x1+l.x2)/2,(l.y1+l.y2)/2);n.drawSlotLabel(t,a.name||a.id,l,d,i)}}),this.localMulti&&this.localMulti.length){var r=function(i){t.strokeStyle=o.selection,t.lineWidth=n.lineScale(2),n.strokePolygon(t,i.points,e)};a.slots.forEach(function(t){n.multiHas("slot",t.id)&&r(t)}),a.docks.forEach(function(t){n.multiHas("dock",t.id)&&r(t)})}if("bg-adjust"===this.mode&&this.bgRect){var s=this.bgRect,l=e(s.x,s.y),d=e(s.x+s.w,s.y+s.h),h=Math.min(l.x,d.x),u=Math.min(l.y,d.y),c=Math.abs(d.x-l.x),f=Math.abs(d.y-l.y);t.save(),t.setLineDash([6,4]),t.strokeStyle=o.draft,t.lineWidth=1.5,t.strokeRect(h,u,c,f),t.restore(),this.hoverBgEdge>=0&&(t.save(),t.strokeStyle=o.draft,t.lineWidth=4,t.beginPath(),0===this.hoverBgEdge?(t.moveTo(h,u),t.lineTo(h,u+f)):1===this.hoverBgEdge?(t.moveTo(h+c,u),t.lineTo(h+c,u+f)):2===this.hoverBgEdge?(t.moveTo(h,u+f),t.lineTo(h+c,u+f)):(t.moveTo(h,u),t.lineTo(h+c,u)),t.stroke(),t.restore())}if(this.path&&this.path.length>1){var p=this.lineScale(1),y=this.path.map(function(t){return e(t.x,t.y)});t.lineCap="round",t.lineJoin="round",t.strokeStyle=o.pathHalo,t.lineWidth=Math.max(5,10*p),t.beginPath(),t.moveTo(y[0].x,y[0].y),y.forEach(function(e,i){i>0&&t.lineTo(e.x,e.y)}),t.stroke(),t.strokeStyle=o.path,t.lineWidth=Math.max(1.5,3.5*p),t.setLineDash([Math.max(6,14*p),Math.max(4,9*p)]),t.lineDashOffset=-(this.animOffset||0),t.stroke(),t.setLineDash([]),t.lineDashOffset=0;for(var g=Math.max(14,30*p),x=Math.max(8,16*p),m=Math.max(2,5.5*p),v=[],b=0,w=0;w<y.length-1;w++){var k=y[w],S=(d=y[w+1]).x-k.x,E=d.y-k.y,M=Math.hypot(S,E);M<1||(v.push({start:b,len:M,ax:k.x,ay:k.y,ux:S/M,uy:E/M,ang:Math.atan2(E,S)}),b+=M)}var D=b;t.fillStyle=o.path;for(var T=g;T<=D-x;T+=g){for(var P=v[0],L=0;L<v.length;L++)if(T<=v[L].start+v[L].len){P=v[L];break}var I=T-P.start;t.save(),t.translate(P.ax+P.ux*I,P.ay+P.uy*I),t.rotate(P.ang),t.beginPath(),t.moveTo(m,0),t.lineTo(.7*-m,.7*-m),t.lineTo(.7*-m,.7*m),t.closePath(),t.fill(),t.restore()}var O=Math.max(2.5,5.5*p);this.drawDot(t,y[0].x,y[0].y,O,o.pathStart),this.drawDot(t,y[y.length-1].x,y[y.length-1].y,O,o.path)}if(this.showEditLayer&&a.roadNodes.forEach(function(i){var a=e(i.x,i.y),r=n.selection&&"node"===n.selection.kind&&n.selection.id===i.id;t.beginPath(),t.arc(a.x,a.y,r?6:4,0,2*Math.PI),t.fillStyle=r?o.selection:o.node,t.fill(),t.strokeStyle="#ffffff",t.lineWidth=1.5,t.stroke()}),this.selection&&this.showEditLayer&&"node"!==this.selection.kind){var R=this.findSelShape();if(R&&R.points){if(t.strokeStyle=o.selectionHalo,t.lineWidth=8,this.strokePolygon(t,R.points,e),t.strokeStyle=o.selection,t.lineWidth=n.lineScale(2),this.strokePolygon(t,R.points,e),R.entry&&"entry"===this.selection.part){var z=e(R.entry.x,R.entry.y);t.beginPath(),t.arc(z.x,z.y,8,0,2*Math.PI),t.fillStyle=o.selection,t.fill(),t.strokeStyle="#ffffff",t.lineWidth=2,t.stroke()}this.selectionHandles().forEach(function(i){var n=e(i.x,i.y);"wall"===this.selection.kind?this.drawDot(t,n.x,n.y,4.5,o.selection):(t.fillStyle="#ffffff",t.strokeStyle=o.selection,t.lineWidth=2,t.beginPath(),t.rect(n.x-4,n.y-4,8,8),t.fill(),t.stroke())},this)}}if(this.draft&&this.draft.points&&this.draft.points.length>0){var N=this.draft.points.map(function(t){return e(t.x,t.y)}),A=this.cursorWorld?e(this.cursorWorld.x,this.cursorWorld.y):null;t.save(),t.setLineDash([6,4]),t.strokeStyle=o.draft,t.lineWidth=2,t.beginPath(),t.moveTo(N[0].x,N[0].y);for(var B=1;B<N.length;B++)t.lineTo(N[B].x,N[B].y);A&&t.lineTo(A.x,A.y),t.stroke(),"polygon"===this.draft.kind&&A&&N.length>=2&&(t.beginPath(),t.moveTo(A.x,A.y),t.lineTo(N[0].x,N[0].y),t.stroke()),t.restore(),N.forEach(function(e){n.drawDot(t,e.x,e.y,4,o.draft)})}if(this.multiDraft){var C=e(this.multiDraft.x1,this.multiDraft.y1),F=e(this.multiDraft.x2,this.multiDraft.y2);t.save(),t.fillStyle="rgba(37, 99, 235, 0.08)",t.strokeStyle=o.selection,t.lineWidth=1.5,t.setLineDash([6,4]),t.fillRect(Math.min(C.x,F.x),Math.min(C.y,F.y),Math.abs(F.x-C.x),Math.abs(F.y-C.y)),t.strokeRect(Math.min(C.x,F.x),Math.min(C.y,F.y),Math.abs(F.x-C.x),Math.abs(F.y-C.y)),t.restore()}if(this.rectDraft){k=e(this.rectDraft.x1,this.rectDraft.y1);var H=e(this.rectDraft.x2,this.rectDraft.y2),$=Math.min(k.x,H.x),V=Math.min(k.y,H.y),J=Math.abs(H.x-k.x),K=Math.abs(H.y-k.y);t.save(),t.setLineDash([6,4]),t.strokeStyle=o.draft,t.lineWidth=2,t.strokeRect($,V,J,K),t.restore(),t.fillStyle=o.draft,t.font="12px sans-serif",t.textAlign="left",t.textBaseline="bottom",t.fillText(Math.abs(this.rectDraft.x2-this.rectDraft.x1).toFixed(1)+" × "+Math.abs(this.rectDraft.y2-this.rectDraft.y1).toFixed(1)+" m",$,V-4)}this.alignLines&&(this.alignLines.xs.length||this.alignLines.ys.length)&&(t.save(),t.strokeStyle="#d946ef",t.lineWidth=1,t.setLineDash([5,4]),this.alignLines.xs.forEach(function(i){var n=e(i,0).x;t.beginPath(),t.moveTo(n,0),t.lineTo(n,t.canvas.height),t.stroke()}),this.alignLines.ys.forEach(function(i){var n=e(0,i).y;t.beginPath(),t.moveTo(0,n),t.lineTo(t.canvas.width,n),t.stroke()}),t.restore())},findSelShape:function(){return this.selection&&this.layout?C.findElement(this.layout,this.selection.kind,this.selection.id):null},hitBgEdge:function(t){var e=this.bgRect;if(!e)return-1;var i=this.toleranceMeters(8),n=[];return Math.abs(t.x-e.x)<=i&&t.y>=e.y-i&&t.y<=e.y+e.h+i&&n.push({i:0,d:Math.abs(t.x-e.x)}),Math.abs(t.x-(e.x+e.w))<=i&&t.y>=e.y-i&&t.y<=e.y+e.h+i&&n.push({i:1,d:Math.abs(t.x-(e.x+e.w))}),Math.abs(t.y-e.y)<=i&&t.x>=e.x-i&&t.x<=e.x+e.w+i&&n.push({i:2,d:Math.abs(t.y-e.y)}),Math.abs(t.y-(e.y+e.h))<=i&&t.x>=e.x-i&&t.x<=e.x+e.w+i&&n.push({i:3,d:Math.abs(t.y-(e.y+e.h))}),n.length?(n.sort(function(t,e){return t.d-e.d}),n[0].i):-1},pointInBgRect:function(t){var e=this.bgRect;return!!e&&t.x>=e.x&&t.x<=e.x+e.w&&t.y>=e.y&&t.y<=e.y+e.h},applyBgDrag:function(t,e){var i=this.dragging;if(!i||!this.bgRect)return null;var n=this.gridSnap>0?C.snapPoint(t,this.gridSnap):{x:t.x,y:t.y},o=i.bgOrig;if("body"===i.target.part)return{x:o.x+(n.x-i.point.x),y:o.y+(n.y-i.point.y),w:o.w,h:o.h};var a=.2,r=i.target.edge;if(e){var s;s=0===r?Math.max(o.w-(n.x-i.point.x),a)/o.w:1===r?Math.max(o.w+(n.x-i.point.x),a)/o.w:2===r?Math.max(o.h-(n.y-i.point.y),a)/o.h:Math.max(o.h+(n.y-i.point.y),a)/o.h;var l,d,h=o.w*s,u=o.h*s;return l=0===r?o.x+o.w:1===r?o.x:o.x+o.w/2,d=2===r?o.y+o.h:3===r?o.y:o.y+o.h/2,{x:0===r?l-h:1===r?l:l-h/2,y:3===r?d-u:2===r?d:d-u/2,w:h,h:u}}if(0===r){var c=Math.min(o.x+(n.x-i.point.x),o.x+o.w-a);return{x:c,y:o.y,w:o.x+o.w-c,h:o.h}}if(1===r)return{x:o.x,y:o.y,w:Math.max(o.w+(n.x-i.point.x),a),h:o.h};if(2===r){var f=Math.min(o.y+(n.y-i.point.y),o.y+o.h-a);return{x:o.x,y:f,w:o.w,h:o.y+o.h-f}}return{x:o.x,y:o.y,w:o.w,h:Math.max(o.h+(n.y-i.point.y),a)}},drawGrid:function(t,e){var i=this.night?_:j,n=this.view?this.view.getScale():10,o=this.view.screenToWorld(0,0),a=this.view.screenToWorld(this.canvasWidth,this.canvasHeight),r=Math.min(o.x,a.x),s=Math.max(o.x,a.x),l=Math.min(o.y,a.y),d=Math.max(o.y,a.y);function h(i,o){if(!(i*n<7)){var a=Math.floor((s-r)/i),h=Math.floor((d-l)/i);if(!(a+h>600)){var u=Math.ceil(r/i)*i,c=Math.ceil(l/i)*i;t.strokeStyle=o,t.lineWidth=1;for(var f=0;f<=a;f++){var p=u+f*i,y=e(p,l),g=e(p,d);t.beginPath(),t.moveTo(y.x,y.y),t.lineTo(g.x,g.y),t.stroke()}for(var x=0;x<=h;x++){var m=c+x*i,v=e(r,m),b=e(s,m);t.beginPath(),t.moveTo(v.x,v.y),t.lineTo(b.x,b.y),t.stroke()}}}}t.save(),h(this.gridSnap>0?this.gridSnap:.1,i.gridFine),h(.5,i.gridFine),h(5,i.grid),h(50,i.grid),h(500,i.grid),t.restore()},drawAxisLabels:function(t,e){for(var i=this.night?_:j,n=this.view.getScale(),o=this.view.screenToWorld(0,0),a=this.view.screenToWorld(this.canvasWidth,this.canvasHeight),r=Math.min(o.x,a.x),s=Math.max(o.x,a.x),l=Math.min(o.y,a.y),d=Math.max(o.y,a.y),h=[1,2,5,10,20,50,100,200,500,1e3],u=h[h.length-1],c=0;c<h.length;c++)if(h[c]*n>=60){u=h[c];break}t.save(),t.font="10px sans-serif",t.lineWidth=3,t.lineJoin="round",t.strokeStyle=i.axisLabelHalo,t.fillStyle=i.axisLabel,t.textAlign="center",t.textBaseline="bottom";for(var f=Math.ceil(r/u)*u,p=Math.floor((s-f)/u+1e-9),y=0;y<=p;y++){var g=Math.round(10*(f+y*u))/10,x=e(g,l);t.strokeText(g+"m",x.x,this.canvasHeight-4),t.fillText(g+"m",x.x,this.canvasHeight-4)}t.textAlign="left",t.textBaseline="middle";for(var m=Math.ceil(l/u)*u,v=Math.floor((d-m)/u+1e-9),b=0;b<=v;b++){var w=Math.round(10*(m+b*u))/10,k=e(r,w);t.strokeText(w+"m",6,k.y),t.fillText(w+"m",6,k.y)}t.restore()},tracePolygon:function(t,e,i){t.beginPath(),e.forEach(function(e,n){var o=i(e[0],e[1]);0===n?t.moveTo(o.x,o.y):t.lineTo(o.x,o.y)}),t.closePath()},textScale:function(t){var e=this.view?this.view.getFitScale():10,i=this.view?this.view.getScale():e;return Math.max(2,t*i/e)},lineScale:function(t){var e=this.view?this.view.getFitScale():10,i=this.view?this.view.getScale():e;return Math.max(.6,Math.min(3,t*i/e))},fitText:function(t,e,i){if(!e)return e;if(t.measureText(e).width<=i)return e;for(var n=e;n.length>1&&t.measureText(n+"…").width>i;)n=n.slice(0,-1);return 1===n.length&&t.measureText(n+"…").width>i?"":n+"…"},drawSlotLabel:function(t,e,i,n,o){var a=this.night?_:j,r=(i.x2-i.x1)*o,s=(i.y2-i.y1)*o,l=Math.max(1.2,Math.min(this.textScale(11),r/1.45,s/1.45));if(t.fillStyle=a.slotText,t.strokeStyle=a.slotTextHalo,t.lineWidth=Math.max(1,.18*l),t.lineJoin="round",t.font=l+"px sans-serif",t.textAlign="center",t.textBaseline="middle",e){var d=Math.max(1,Math.min(4,.15*r)),h=Math.max(1,Math.min(4,.15*s)),u=s>=1.4*l?this.fitText(t,e,r-d):"";if(u===e&&u)return t.strokeText(u,n.x,n.y),void t.fillText(u,n.x,n.y);if(r>=1.4*l&&s>=r){var c=this.fitText(t,e,s-h);if(c)return t.save(),t.translate(n.x,n.y),t.rotate(Math.PI/2),t.strokeText(c,0,0),t.fillText(c,0,0),void t.restore()}u&&(t.strokeText(u,n.x,n.y),t.fillText(u,n.x,n.y))}},strokePolygon:function(t,e,i){this.tracePolygon(t,e,i),t.stroke()},drawPolygon:function(t,e,i,n,o,a){this.tracePolygon(t,e,i),t.fillStyle=n,t.fill(),t.strokeStyle=o,t.lineWidth=a,t.stroke()},drawDot:function(t,e,i,n,o){t.beginPath(),t.arc(e,i,n,0,2*Math.PI),t.fillStyle=o,t.fill(),t.strokeStyle="#ffffff",t.lineWidth=1.2,t.stroke()}},render:function(t){var e=this,i=[t("canvas",{ref:"canvas",class:"warehouse-canvas",attrs:{width:this.canvasWidth,height:this.canvasHeight},on:{mousedown:e.onMouseDown,mousemove:e.onMouseMove,mouseup:e.onMouseUp,mouseleave:e.onMouseLeave,dblclick:e.onDblClick,contextmenu:function(t){t.preventDefault()},wheel:e.onWheel}})];return this.tipText&&i.push(t("div",{class:"map-tip"},this.tipText)),i.push(t("div",{class:{"map-reset":!0,night:this.night},attrs:{title:"复位视图"},on:{click:e.resetView}},"复位视图")),t("div",{class:{"warehouse-map-wrap":!0,night:this.night},ref:"wrap"},i)}},H="warehouse-map-sdk-styles";F._injectStyles=function(){if("undefined"!=typeof document&&!document.getElementById(H)){var t=document.createElement("style");t.id=H,t.textContent="\n.warehouse-map-wrap {\n position: relative;\n display: block;\n width: 100%;\n height: 100%;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n background: #fff;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);\n}\n.warehouse-map-wrap.night {\n background: #0b1220;\n border-color: #1f2937;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);\n}\n.warehouse-map-wrap .warehouse-canvas {\n display: block;\n width: 100%;\n height: 100%;\n border-radius: 6px;\n}\n.warehouse-map-wrap .map-tip {\n position: absolute;\n top: 10px;\n left: 10px;\n background: rgba(17, 24, 39, 0.85);\n color: #fff;\n font-size: 12px;\n padding: 4px 10px;\n border-radius: 4px;\n pointer-events: none;\n}\n.warehouse-map-wrap .map-reset {\n position: absolute;\n right: 10px;\n bottom: 10px;\n background: #fff;\n border: 1px solid #d1d5db;\n color: #4b5563;\n font-size: 12px;\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n user-select: none;\n}\n.warehouse-map-wrap .map-reset:hover {\n border-color: #3b82f6;\n color: #3b82f6;\n}\n.warehouse-map-wrap .map-reset.night {\n background: #1f2937;\n border-color: #374151;\n color: #d1d5db;\n}\n.warehouse-map-wrap .map-reset.night:hover {\n border-color: #60a5fa;\n color: #60a5fa;\n}\n",document.head.appendChild(t)}},F.mounted=F.mounted?F.mounted:function(){},F.created=F.created?F.created:function(){},F._injectStyles();var $=t(Object.freeze({__proto__:null,default:F})),V=a.dist,J=a.pointSegProjection,K=a.pointOnSegment;function Y(t,e){return Math.round(1e3*t)+"@"+Math.round(1e3*e)}var U=function(t,e,i,n){var o=n||{},a=void 0===o.maxSnapDistance?10:o.maxSnapDistance,r=new Map;t.forEach(function(t){r.set(t.id,t)});var s=new Map;function l(t,e){var i=Y(t,e);return s.has(i)||s.set(i,{x:t,y:e}),i}t.forEach(function(t){l(t.x,t.y)});var d=[];(i||[]).forEach(function(t){var i=null;e.forEach(function(e,n){var o=r.get(e.from),s=r.get(e.to);if(o&&s){var l=J(t.x,t.y,o.x,o.y,s.x,s.y);l.dist<=a&&(null===i||l.dist<i.proj.dist)&&(i={proj:l,edgeIndex:n})}}),i&&d.push({anchor:t,proj:i.proj,edgeIndex:i.edgeIndex})});var h=e.map(function(){return[]});d.forEach(function(t){h[t.edgeIndex].push({x:t.proj.x,y:t.proj.y,t:t.proj.t})}),t.forEach(function(t){e.forEach(function(e,i){var n=r.get(e.from),o=r.get(e.to);if(n&&o&&K(t.x,t.y,n.x,n.y,o.x,o.y,.005)){var a=J(t.x,t.y,n.x,n.y,o.x,o.y);h[i].push({x:t.x,y:t.y,t:a.t})}})}),h.forEach(function(t){var e=new Map;t.forEach(function(t){var i=Y(t.x,t.y);e.has(i)||e.set(i,t)});var i=Array.from(e.values());i.sort(function(t,e){return t.t-e.t}),t.length=0,i.forEach(function(e){t.push(e)})});var u=new Map,c=new Set;function f(t,e){if(t!==e){var i=t<e?t+"|"+e:e+"|"+t;if(!c.has(i)){c.add(i);var n=s.get(t),o=s.get(e),a=V(n.x,n.y,o.x,o.y);u.has(t)||u.set(t,[]),u.has(e)||u.set(e,[]),u.get(t).push({key:e,w:a}),u.get(e).push({key:t,w:a})}}}e.forEach(function(t,e){var i=r.get(t.from),n=r.get(t.to);if(i&&n)for(var o=[{x:i.x,y:i.y,t:0}].concat(h[e],[{x:n.x,y:n.y,t:1}]),a=0;a<o.length-1;a++)f(l(o[a].x,o[a].y),l(o[a+1].x,o[a+1].y))});var p=new Map,y=new Map;return d.forEach(function(t){var e=l(t.anchor.x,t.anchor.y),i=l(t.proj.x,t.proj.y);f(e,i),p.set(t.anchor.id,e),y.set(t.anchor.id,i)}),{points:s,adj:u,anchorKeys:p,anchorProjKeys:y}},X=U,G=function(t,e,i){var n=t.points,o=t.adj;if(!n.has(e)||!n.has(i))return null;if(e===i)return[e];n.get(e);var a=n.get(i);function r(t){var e=n.get(t);return Math.hypot(e.x-a.x,e.y-a.y)}var s=[];function l(t){s.push(t);for(var e=s.length-1;e>0;){var i=e-1>>1;if(s[i].f<=s[e].f)break;var n=s[i];s[i]=s[e],s[e]=n,e=i}}function d(){var t=s[0],e=s.pop();if(s.length>0){s[0]=e;for(var i=0;;){var n=2*i+1,o=n+1,a=i;if(n<s.length&&s[n].f<s[a].f&&(a=n),o<s.length&&s[o].f<s[a].f&&(a=o),a===i)break;var r=s[a];s[a]=s[i],s[i]=r,i=a}}return t}var h=new Map([[e,0]]),u=new Map,c=new Set;for(l({key:e,f:r(e)});s.length>0;){var f=d();if(f.key===i){for(var p=[i],y=i;u.has(y);)y=u.get(y),p.unshift(y);return p}if(!c.has(f.key)){c.add(f.key);for(var g=o.get(f.key)||[],x=h.get(f.key),m=0;m<g.length;m++){var v=g[m],b=x+v.w;b<(h.has(v.key)?h.get(v.key):1/0)&&(h.set(v.key,b),u.set(v.key,f.key),l({key:v.key,f:b+r(v.key)}))}}}return null},Z=new WeakMap;function q(t,e){return t.docks.find(function(t){return t.id===e})||t.slots.find(function(t){return t.id===e})||null}function Q(t){for(var e=0,i=1;i<t.length;i++)e+=Math.hypot(t[i].x-t[i-1].x,t[i].y-t[i-1].y);return e}function tt(t,e){for(var i=new Set([e]),n=[e];n.length;){var o=n.shift();(t.adj.get(o)||[]).forEach(function(t){i.has(t.key)||(i.add(t.key),n.push(t.key))})}return i}var et={findPath:function(t,e,i){if(e===i)return{ok:!1,reason:"same",message:"起点和终点相同"};if(!q(t,e)||!q(t,i))return{ok:!1,reason:"unknown-id",message:"起点或终点不存在"};var n=function(t){if(!Z.has(t)){var e=[].concat(t.docks.map(function(t){return{id:t.id,x:t.entry.x,y:t.entry.y}}),t.slots.map(function(t){return{id:t.id,x:t.entry.x,y:t.entry.y}}));Z.set(t,X(t.roadNodes,t.roadEdges,e))}return Z.get(t)}(t),o=n.anchorKeys.get(e),a=n.anchorKeys.get(i);if(!o||!a)return{ok:!1,reason:"not-snapped",message:"起点或终点无法接入任何道路(距离超过 10 米)"};var r=n.anchorProjKeys.get(e),s=n.anchorProjKeys.get(i);if(r&&r===s){var l=[n.points.get(o),n.points.get(r),n.points.get(a)];return{ok:!0,points:l,length:Q(l)}}var d=G(n,o,a);if(!d){var h="道路网中不存在可达路径";return!tt(n,o).has(a)&&function(t){var e=new Set,i=0;return t.adj.forEach(function(n,o){e.has(o)||(i++,tt(t,o).forEach(function(t){e.add(t)}))}),i}(n)>1&&(h+=':起点与终点分属互不连通的路网部分——常见原因是新画的道路没有接入已有路网。排查:① 新路两端要点在已有道路节点的吸附半径内(默认 0.8m,画的时候节点会高亮复用而不是新建);② 或让新路压在已有道路上(会自动拆边接入);③ 编辑面板「校验」里会提示"道路网被分成 N 个互不连通的部分",点击出问题的节点可定位'),{ok:!1,reason:"no-path",message:h}}var u=d.map(function(t){var e=n.points.get(t);return{x:e.x,y:e.y}});return{ok:!0,points:u,length:Q(u)}},invalidateLayout:function(t){t&&Z.delete(t)},polylineLength:Q},it=N,nt=et,ot=function(t,e){var i=e||{},n=t?it.parseLayout(JSON.stringify(it.exportLayout(t))):it.parseLayout({name:"未命名仓库",size:{width:60,height:40},walls:[],docks:[],slots:[],roadNodes:[],roadEdges:[],roadWidth:1.5}),o=it.createHistory(i.maxHistory||120);o.push(it.exportLayout(n));var a=[];function r(){nt.invalidateLayout(n);var t=it.exportLayout(n);o.push(t);for(var e=0;e<a.length;e++)try{a[e](t,n)}catch(t){}return t}function s(t){n=it.parseLayout(JSON.stringify(t)),nt.invalidateLayout(n);for(var e=0;e<a.length;e++)try{a[e](it.exportLayout(n),n)}catch(t){}return n}return{getModel:function(){return n},getJSON:function(){return n?it.exportLayout(n):null},onChange:function(t){return a.push(t),function(){var e=a.indexOf(t);e>=0&&a.splice(e,1)}},setModel:function(t){n=it.parseLayout("string"==typeof t?t:JSON.stringify(t)),(o=it.createHistory(i.maxHistory||120)).push(it.exportLayout(n)),nt.invalidateLayout(n);for(var e=0;e<a.length;e++)try{a[e](it.exportLayout(n),n)}catch(t){}return n},apply:function(t){if(!n)return null;var e=Array.prototype.slice.call(arguments,1);e.unshift(n);var i=t.apply(null,e);return r(),i},applySilent:function(t){if(!n)return null;var e=Array.prototype.slice.call(arguments,1);e.unshift(n);var i=t.apply(null,e);return nt.invalidateLayout(n),i},snapshot:function(){return n?r():null},invalidate:function(){n&&nt.invalidateLayout(n)},addSlot:function(t,e){return this.apply(it.addSlot,t,e)},addDock:function(t,e){return this.apply(it.addDock,t,e)},addWall:function(t,e){return this.apply(it.addWall,t,e)},addRoadNode:function(t,e){return this.apply(it.addRoadNode,t,e)},addRoadSegment:function(t,e){return this.apply(it.addRoadSegment,t,e)},fillRoadBetween:function(t,e,i,n){return this.apply(it.fillRoadBetween,t,e,i,n)},generateSlots:function(t,e){return this.apply(it.generateSlots,t,e)},generateDocks:function(t,e){return this.apply(it.generateDocks,t,e)},removeElement:function(t,e){return this.apply(it.removeElement,t,e)},translateElement:function(t,e,i,n){return this.apply(it.translateElement,t,e,i,n)},applyElementGeometry:function(t,e,i,n){return this.apply(it.applyElementGeometry,t,e,i,n)},duplicateWall:function(t,e,i){return this.apply(it.duplicateWall,t,e,i)},renameSlot:function(t,e){if(!n)return{ok:!1,message:"模型为空"};var i=it.renameSlot(n,t,e);return i.ok&&r(),i},setLabel:function(t,e,i){var o=it.findElement(n,t,e);if(!o)return{ok:!1,message:"元素不存在"};var a=String(i||"").trim();return(o.name||"")===a?{ok:!0,message:"无变化"}:(a?o.name=a:delete o.name,r(),{ok:!0,message:"已更新"})},setBoundary:function(t){var e=it.normalizeBoundary(t);return e?(n.boundary=e,r(),{ok:!0,boundary:e}):{ok:!1,message:"边界多边形不合法"}},clearBoundary:function(){return delete n.boundary,r(),{ok:!0}},undo:function(){var t=o.undo();return!!t&&(s(t),!0)},redo:function(){var t=o.redo();return!!t&&(s(t),!0)},canUndo:function(){return o.canUndo()},canRedo:function(){return o.canRedo()},validate:function(){return n?it.validateModel(n):[]},stats:function(){return n?it.computeStats(n):null},exportJSON:function(){return n?JSON.stringify(it.exportLayout(n)):null},importJSON:function(t){return this.setModel(t)},findPath:function(t,e){return n?nt.findPath(n,t,e):{ok:!1,reason:"empty",message:"模型为空"}},history:o}},at=N,rt=$,st=rt.default||rt,lt="warehouse-map-sdk-editor-styles",dt=[".wme-editor { display: flex; gap: 12px; height: 100%; min-height: 420px; position: relative; font-family: Helvetica, PingFang SC, Microsoft YaHei, sans-serif; font-size: 13px; color: #374151; }",".wme-map-col { flex: 1; min-width: 0; }",".wme-panel { width: 300px; flex: 0 0 300px; overflow-y: auto; background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 6px; padding: 10px; box-sizing: border-box; }",".wme-panel-block { background: #fff; border: 1px solid #e5e7eb; border-radius: 6px; padding: 10px; margin-bottom: 10px; }",".wme-panel-title { font-weight: 500; font-size: 13px; color: #111827; margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }",".wme-badge { font-size: 11px; font-weight: 400; color: #6b7280; background: #f3f4f6; border-radius: 8px; padding: 1px 7px; }",".wme-badge.ok { color: #15803d; background: #dcfce7; }",".wme-badge.warn { color: #b45309; background: #fef3c7; }",".wme-tool-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }",".wme-tool-btn { border: 1px solid #d1d5db; background: #fff; border-radius: 4px; padding: 5px 4px; font-size: 12px; cursor: pointer; color: #374151; }",".wme-tool-btn:hover { border-color: #3b82f6; color: #3b82f6; }",".wme-tool-btn.active { background: #2563eb; border-color: #2563eb; color: #fff; }",".wme-row { display: flex; align-items: center; gap: 6px; margin-top: 8px; flex-wrap: wrap; }",".wme-row-label { flex: 0 0 56px; color: #6b7280; font-size: 12px; }",".wme-row-hint { color: #9ca3af; font-size: 11px; flex: 1; min-width: 100%; }",".wme-btn { border: 1px solid #d1d5db; background: #fff; border-radius: 4px; padding: 3px 10px; font-size: 12px; cursor: pointer; color: #374151; }",".wme-btn:hover:not(:disabled) { border-color: #3b82f6; color: #3b82f6; }",".wme-btn:disabled { opacity: 0.45; cursor: not-allowed; }",".wme-btn.primary { background: #2563eb; border-color: #2563eb; color: #fff; }",".wme-btn.primary:hover:not(:disabled) { background: #1d4ed8; color: #fff; }",".wme-btn.danger:hover:not(:disabled) { border-color: #dc2626; color: #dc2626; }",".wme-input, .wme-select { border: 1px solid #d1d5db; border-radius: 4px; padding: 3px 6px; font-size: 12px; color: #374151; background: #fff; box-sizing: border-box; }",".wme-input:focus, .wme-select:focus { outline: none; border-color: #3b82f6; }",".wme-input.w-60 { width: 60px; } .wme-input.w-80 { width: 80px; } .wme-select { width: 88px; }",".wme-hint { color: #9ca3af; font-size: 11px; margin-top: 8px; line-height: 1.5; }",".wme-stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 10px; }",".wme-stat { display: flex; align-items: baseline; gap: 4px; font-size: 12px; }",".wme-stat span { color: #6b7280; } .wme-stat b { color: #111827; } .wme-stat i { font-style: normal; color: #9ca3af; font-size: 11px; }",".wme-issue-list { list-style: none; margin: 0; padding: 0; max-height: 140px; overflow-y: auto; }",".wme-issue-list li { display: flex; align-items: baseline; gap: 6px; padding: 3px 0; font-size: 12px; cursor: pointer; color: #4b5563; }",".wme-issue-list li:hover { color: #2563eb; }",".wme-issue-list li .dot { width: 6px; height: 6px; border-radius: 50%; flex: 0 0 6px; }",".wme-issue-list li.error .dot { background: #dc2626; } .wme-issue-list li.warn .dot { background: #f59e0b; }",".wme-tabs { display: flex; gap: 6px; margin-bottom: 6px; }",".wme-tab-btn { border: 1px solid #d1d5db; background: #fff; border-radius: 4px; padding: 2px 10px; font-size: 12px; cursor: pointer; color: #6b7280; }",".wme-tab-btn.active { background: #2563eb; border-color: #2563eb; color: #fff; }",".wme-list-scroll { max-height: 260px; overflow-y: auto; }",".wme-list-row { display: flex; align-items: center; gap: 6px; padding: 3px 4px; border-radius: 4px; cursor: pointer; }",".wme-list-row:hover { background: #f3f4f6; }",".wme-list-row.active { background: #dbeafe; }",".wme-list-row .wme-code-input { flex: 1; min-width: 0; }",".wme-list-row .wme-slot-name { font-style: normal; color: #6b7280; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 80px; }",".wme-list-row .wme-row-id { color: #6b7280; font-size: 12px; flex: 0 0 auto; }",".wme-del-btn { border: none; background: none; color: #9ca3af; cursor: pointer; font-size: 12px; padding: 2px 4px; }",".wme-del-btn:hover { color: #dc2626; }",".wme-overlay { position: absolute; left: 0; top: 0; right: 0; bottom: 0; background: rgba(15, 23, 42, 0.45); display: flex; align-items: center; justify-content: center; z-index: 30; }",".wme-modal { background: #fff; border-radius: 8px; width: 520px; max-width: 92%; max-height: 86%; display: flex; flex-direction: column; padding: 14px; box-sizing: border-box; }",".wme-modal.wide { width: 640px; }",".wme-modal-title { font-weight: 500; font-size: 14px; color: #111827; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; }",".wme-modal-body { overflow-y: auto; flex: 1; min-height: 0; }",".wme-modal-footer { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }",".wme-biz-toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; flex-wrap: wrap; }",".wme-biz-list { border: 1px solid #e5e7eb; border-radius: 4px; max-height: 240px; overflow-y: auto; }",".wme-biz-row { display: flex; align-items: center; gap: 8px; padding: 4px 8px; font-size: 12px; cursor: pointer; border-bottom: 1px solid #f3f4f6; }",".wme-biz-row:hover { background: #f8fafc; }",".wme-biz-row .code { color: #111827; } .wme-biz-row .name { color: #6b7280; } .wme-biz-row .rc { color: #9ca3af; font-size: 11px; margin-left: auto; }",".wme-params-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 12px; margin-top: 10px; }",".wme-params-grid .wme-row-label { flex: 0 0 auto; }",".wme-textarea { width: 100%; box-sizing: border-box; border: 1px solid #d1d5db; border-radius: 4px; font-family: monospace; font-size: 12px; padding: 8px; resize: vertical; }",".wme-toast { position: absolute; top: 12px; left: 50%; transform: translateX(-50%); background: rgba(17, 24, 39, 0.88); color: #fff; font-size: 12px; padding: 6px 14px; border-radius: 4px; z-index: 40; pointer-events: none; max-width: 70%; }",".wme-toast.success { background: rgba(21, 128, 61, 0.92); }",".wme-toast.warning { background: rgba(180, 83, 9, 0.92); }",".wme-toast.error { background: rgba(153, 27, 27, 0.92); }"].join("\n"),ht=[{value:"select",label:"选择/移动",mode:"select",hint:"点选元素,拖动移动;拖角调整大小;拖红点改入口方向;Ctrl+单击 多选"},{value:"multi-move",label:"框选移动",mode:"multi",hint:"拖出矩形批量选中货位,拖动任意选中货位整组平移;点空白/Esc 取消;Delete 批量删除"},{value:"slot",label:"画货位",mode:"rect",hint:"空白处拖拽出矩形即成货位:自动编码 + 自动推断入口朝向"},{value:"dock",label:"画装卸口",mode:"rect",hint:"拖拽生成装卸口,自动编号 DOCK-N 与入口"},{value:"wall-rect",label:"画墙体(矩形)",mode:"rect",hint:"拖拽生成矩形墙体,适合设备区等"},{value:"wall-poly",label:"画墙体(多边形)",mode:"polygon",hint:"连续单击加点,双击结束(至少 3 个点)"},{value:"boundary",label:"画边界",mode:"polygon",hint:"连续单击勾出仓库轮廓,自动横平竖直,双击结束(至少 3 个点)"},{value:"road",label:"画道路",mode:"road",hint:"沿通道连续单击,自动生成节点并连边;靠近已有节点自动吸附;双击结束"},{value:"batch-slot",label:"批量选货位",mode:"rect",hint:"从系统货位清单弹窗勾选 → 按排/列或框选片区批量生成"},{value:"batch-dock",label:"批量选装卸口",mode:"rect",hint:"从月台清单弹窗勾选 → 批量生成"}],ut={name:"WarehouseMapEditor",props:{layout:{type:Object,default:null},controller:{type:Object,default:null},api:{type:Object,default:null},night:{type:Boolean,default:!1},tools:{type:Array,default:null},showPanel:{type:Boolean,default:!0},gridSnap:{type:Number,default:.1},roadSnap:{type:Number,default:.8},roadFillStep:{type:Number,default:5}},data:function(){var t=this.layout&&this.layout.slots?this.layout:null;this._userLayoutApplied=!!t;var e=this.controller||ot(t);return this.ctrl=e,e.onChange(this.onCtrlChange.bind(this)),{model:e.getModel(),tool:"select",draft:null,roadDraftFrom:null,selection:null,multiIds:[],dragOrigin:null,gridSnapOn:this.gridSnap>0,roadSnapValue:this.roadSnap,roadFillStepValue:this.roadFillStep,stats:at.computeStats(e.getModel()),issues:[],histVersion:0,group:"slot",renameBuf:{},notice:{text:"",level:"info"},noticeTimer:null,batch:{visible:!1,type:"slot",loading:!1,keyword:"",rows:[],rect:null,params:{w:3,d:5,gapX:0,gapY:0,mode:"table",entryDir:"bottom",originX:1,originY:1}},jsonDialog:{visible:!1,mode:"export",text:""}}},computed:{toolDefs:function(){var t=this.api||{},e=this.tools;return ht.filter(function(i){return!(e&&e.indexOf(i.value)<0||"batch-slot"===i.value&&"function"!=typeof t.fetchBizSlots||"batch-dock"===i.value&&"function"!=typeof t.fetchBizDocks)})},mapMode:function(){for(var t=0;t<ht.length;t++)if(ht[t].value===this.tool)return ht[t].mode;return"select"},toolHint:function(){for(var t=0;t<ht.length;t++)if(ht[t].value===this.tool)return ht[t].hint;return""},canUndo:function(){return this.histVersion,this.ctrl.canUndo()},canRedo:function(){return this.histVersion,this.ctrl.canRedo()},bizFilteredRows:function(){var t=(this.batch.keyword||"").trim().toLowerCase();return t?this.batch.rows.filter(function(e){return(e.code+" "+(e.name||"")).toLowerCase().indexOf(t)>=0}):this.batch.rows},bizSelectedRows:function(){return this.batch.rows.filter(function(t){return t._checked})}},watch:{layout:function(t){t&&t.slots&&!this._userLayoutApplied&&(this._userLayoutApplied=!0,this.ctrl.setModel(t))}},mounted:function(){!function(){if("undefined"!=typeof document&&!document.getElementById(lt)){var t=document.createElement("style");t.id=lt,t.textContent=dt,document.head.appendChild(t)}}(),this.refreshMeta(),window.addEventListener("keydown",this.onKeydown)},beforeDestroy:function(){window.removeEventListener("keydown",this.onKeydown)},methods:{toast:function(t,e){var i=this;this.notice={text:t,level:e||"info"},this.noticeTimer&&clearTimeout(this.noticeTimer),this.noticeTimer=setTimeout(function(){i.notice={text:"",level:"info"}},2600),this.$emit("notice",{text:t,level:e||"info"})},onCtrlChange:function(t,e){this.histVersion++,this.model!==e&&(this.model=e),this.refreshMeta(),this.refreshSelectionValidity(),this.$emit("model-change",t)},refreshMeta:function(){this.stats=at.computeStats(this.model),this.issues=at.validateModel(this.model)},refreshSelectionValidity:function(){this.selection&&(at.findElement(this.model,this.selection.kind,this.selection.id)||(this.selection=null,this.$emit("selection-change",null)))},onToolClick:function(t){"batch-slot"!==t.value&&"batch-dock"!==t.value?(this.tool=t.value,this.draft=null,this.roadDraftFrom=null,this.$emit("tool-change",t.value)):this.openBatchModal("batch-dock"===t.value?"dock":"slot")},onRectDrawn:function(t){var e=this.tool;if("batch-slot"===e||"batch-dock"===e)return this.batch.rect=t.rect,this.batch.visible=!0,void this.toast("已框选片区 "+t.rect.width+" × "+t.rect.height+" 米","success");var i=at.rectToPolygon(t.rect),n=null,o=null;"slot"===e?(n=this.ctrl.apply(at.addSlot,i),o="slot"):"dock"===e?(n=this.ctrl.apply(at.addDock,i),o="dock"):"wall-rect"===e&&(n=this.ctrl.apply(at.addWall,i,{name:"新墙体"}),o="wall"),n&&(this.selection={kind:o,id:n.id},this.$emit("selection-change",this.selection),this.toast("已新增 "+n.id+",可拖角调整大小","success"))},onCanvasClick:function(t){var e=t.point;if("wall-poly"===this.tool||"boundary"===this.tool){var i=this.draft&&"polygon"===this.draft.kind?this.draft.points.slice():[],n=i[i.length-1];if(n&&Math.hypot(n.x-e.x,n.y-e.y)<.3)return;if("boundary"===this.tool&&n){var o=at.orthoElbow(n,e);o&&i.push(o)}return i.push({x:e.x,y:e.y}),void(this.draft={kind:"polygon",points:i})}if("road"===this.tool){var a=this.roadDraftFrom;if(a&&Math.hypot(a.x-e.x,a.y-e.y)<.3)return;var r=t.nodeId||this.ctrl.apply(at.addRoadNode,e,this.roadSnapValue);if(a&&a.nodeId!==r){var s=this.ctrl.applySilent(at.fillRoadBetween,a.nodeId,r,this.roadFillStepValue,{tolerance:this.roadSnapValue,grid:this.gridSnapOn?.1:0});s&&s.filled&&this.toast("已自动补 "+s.nodeIds.length+" 个中间节点,分 "+s.segCount+" 段","success")}var l=at.findElement(this.model,"node",r);this.roadDraftFrom={nodeId:r,x:l.x,y:l.y},this.draft={kind:"road",points:[{x:l.x,y:l.y}]},this.selection={kind:"node",id:r},this.$emit("selection-change",this.selection),this.ctrl.snapshot()}},onCanvasDblClick:function(){if("wall-poly"!==this.tool)if("boundary"!==this.tool)this.draft=null,this.roadDraftFrom=null;else{if(this.draft&&this.draft.points&&this.draft.points.length>=3){var t=this.draft.points,e=at.orthoElbow(t[t.length-1],t[0]),i=e?t.concat([e]):t.slice(),n=at.normalizeBoundary(i.map(function(t){return[t.x,t.y]}));n&&(this.model.boundary=n,this.ctrl.snapshot(),this.toast("仓库边界已更新("+n.length+" 个顶点,横平竖直)","success"))}else this.toast("边界至少需要 3 个点","warning");this.draft=null}else{if(this.draft&&this.draft.points&&this.draft.points.length>=3){var o=this.draft.points.map(function(t){return[t.x,t.y]}),a=this.ctrl.apply(at.addWall,o,{name:"新墙体"});this.selection={kind:"wall",id:a.id},this.$emit("selection-change",this.selection),this.toast("新增墙体 "+a.id,"success")}else this.toast("多边形墙体至少需要 3 个点","warning");this.draft=null}},onSelectChange:function(t){this.selection=t,this.$emit("selection-change",t)},onAreaSelect:function(t){this.multiIds=t&&t.ids||[]},onDragStart:function(t){var e=t.target,i=at.findElement(this.model,e.kind,e.id);if(i){if("group"===e.part){var n=this.multiIds.some(function(t){return t.kind===e.kind&&t.id===e.id})?this.multiIds.slice():this.multiIds.concat([{kind:e.kind,id:e.id}]),o=[];return n.forEach(function(t){var e=at.findElement(this.model,t.kind,t.id);e&&e.points&&o.push({kind:t.kind,id:t.id,points:at.clone(e.points),entry:e.entry?{x:e.entry.x,y:e.entry.y}:null})},this),void(this.dragOrigin={target:e,point:{x:t.point.x,y:t.point.y},snapshot:o})}this.dragOrigin={target:e,point:{x:t.point.x,y:t.point.y},snapshot:"node"===e.kind?{x:i.x,y:i.y}:{points:at.clone(i.points),entry:i.entry?{x:i.entry.x,y:i.entry.y}:null}}}},onDragMove:function(t){var e=this.dragOrigin;if(e){var i=e.target,n=t.point,o=this.gridSnapOn?.1:0;if("entry"===i.part)this.ctrl.applySilent(at.setEntry,i.kind,i.id,at.snapPoint(n,o));else if("resize"===i.part){var a=e.snapshot.points[(i.index+2)%4];this.ctrl.applySilent(at.resizeRectElement,i.kind,i.id,{x:a[0],y:a[1]},n,o,"wall"===i.kind?at.WALL_MIN_SIZE:void 0)}else if("edge-resize"===i.part)this.ctrl.applySilent(at.resizeWallEdge,i.id,i.edge,n,o,at.WALL_MIN_SIZE);else if("vertex"===i.part)this.ctrl.applySilent(at.movePolygonVertex,i.kind,i.id,i.index,n,o);else if("group"===i.part){var r=at.snapValue(n.x-e.point.x,o),s=at.snapValue(n.y-e.point.y,o);e.snapshot.forEach(function(t){var e=t.points.map(function(t){return[t[0]+r,t[1]+s]}),i=t.entry?{x:t.entry.x+r,y:t.entry.y+s}:null;at.applyElementGeometry(this.model,t.kind,t.id,e,i)},this),this.ctrl.invalidate()}else if("node"===i.kind)this.ctrl.applySilent(at.setNodePosition,i.id,at.snapPoint(n,o));else{var l=at.snapValue(n.x-e.point.x,o),d=at.snapValue(n.y-e.point.y,o),h=e.snapshot.points.map(function(t){return[t[0]+l,t[1]+d]}),u=e.snapshot.entry?{x:e.snapshot.entry.x+l,y:e.snapshot.entry.y+d}:null;this.ctrl.applySilent(at.applyElementGeometry,i.kind,i.id,h,u)}this.refreshMeta()}},onDragEnd:function(t){this.dragOrigin=null,t&&t.target&&"bg"===t.target.kind||this.ctrl.snapshot()},deleteSelection:function(){if(this.multiIds.length>1)return this.multiIds.forEach(function(t){this.ctrl.removeElement(t.kind,t.id)},this),this.multiIds=[],void this.toast("已删除批量选中元素","success");if(this.selection){var t=at.findElement(this.model,this.selection.kind,this.selection.id);"wall"===this.selection.kind&&t&&!1===t.fill?this.toast("外围墙不可删除","warning"):(this.ctrl.removeElement(this.selection.kind,this.selection.id),this.selection=null,this.$emit("selection-change",null))}},duplicateWall:function(){if(this.selection&&"wall"===this.selection.kind){var t=this.ctrl.duplicateWall(this.selection.id,1,1);t&&(this.selection={kind:"wall",id:t.id},this.toast("已复制为 "+t.id,"success"))}else this.toast("请先选中一段墙体","warning")},undo:function(){this.ctrl.undo()||this.toast("没有可撤销的操作")},redo:function(){this.ctrl.redo()||this.toast("没有可重做的操作")},onRoadWidth:function(t){var e=Number(t);e>0&&this.model.roadWidth!==e&&(this.model.roadWidth=e,this.ctrl.snapshot())},isSelected:function(t,e){return!!this.selection&&this.selection.kind===t&&this.selection.id===e},bufKey:function(t,e){return t+":"+e},bufValue:function(t,e,i){var n=this.bufKey(t,e);return void 0!==this.renameBuf[n]?this.renameBuf[n]:i||""},onBufInput:function(t,e,i){this.renameBuf[this.bufKey(t,e)]=i.target.value},commitBuf:function(t,e){var i=this.bufKey(t,e);if(void 0!==this.renameBuf[i]){var n=String(this.renameBuf[i]).trim();if(delete this.renameBuf[i],"slot"===t){var o=this.ctrl.renameSlot(e,n);this.toast(o.ok?"货位已改名为 "+n:o.message,o.ok?"success":"warning"),o.ok&&this.selection&&this.selection.id===e&&(this.selection={kind:"slot",id:n})}else this.ctrl.setLabel(t,e,n)}},openBatchModal:function(t){var e=this,i=this.api||{},n="dock"===t?i.fetchBizDocks:i.fetchBizSlots;"function"==typeof n?(this.batch.type=t,this.batch.loading=!0,this.batch.keyword="",this.batch.visible=!0,"dock"===t?(this.batch.params.w=6,this.batch.params.d=4):(this.batch.params.w=3,this.batch.params.d=5),this.batch.rows=[],Promise.resolve(n()).then(function(i){var n={};("dock"===t?e.model.docks:e.model.slots).forEach(function(t){n[t.id]=!0}),e.batch.rows=(i||[]).filter(function(t){return!n[t.code]}).map(function(t){return{code:t.code,name:t.name,row:t.row,col:t.col,_checked:!1}}),e.batch.loading=!1}).catch(function(t){e.batch.loading=!1,e.toast("清单加载失败:"+(t&&t.message),"error")})):this.toast("未提供批量清单 api","warning")},gotoRectSelect:function(){this.batch.visible=!1,this.batch.rect=null,this.toast("在画布上拖出一个矩形片区,松开即回到本弹窗")},toggleAllBiz:function(t){var e=t.target.checked;this.bizFilteredRows.forEach(function(t){t._checked=e})},confirmBatchGenerate:function(){var t=this.bizSelectedRows;if(t.length){var e=this.batch.params,i="dock"===this.batch.type,n=[],o=0;if("rect"===e.mode){if(!this.batch.rect)return void this.toast("请先在画布上框选片区矩形","warning");var a=this.batch.rect,r=Math.max(1,Math.floor((a.width+e.gapX)/(e.w+e.gapX))),s=r*Math.max(1,Math.floor((a.height+e.gapY)/(e.d+e.gapY)));t.slice().sort(function(t,e){return t.code<e.code?-1:1}).forEach(function(t,i){if(i>=s)o++;else{var l=Math.floor(i/r);n.push({code:t.code,name:t.name,x:a.x1+i%r*(e.w+e.gapX),y:a.y2-(l+1)*e.d-l*e.gapY})}})}else{var l=[],d=[];t.forEach(function(t){null!=t.row&&null!=t.col?l.push(t):d.push(t)}),l.forEach(function(t){n.push({code:t.code,name:t.name,x:e.originX+(t.col-1)*(e.w+e.gapX),y:e.originY+(t.row-1)*(e.d+e.gapY)})}),d.forEach(function(t,i){n.push({code:t.code,name:t.name,x:e.originX+i*(e.w+e.gapX),y:e.originY})})}var h=this.ctrl.applySilent(i?at.generateDocks:at.generateSlots,n,{width:e.w,depth:e.d,entryDir:e.entryDir});this.ctrl.snapshot(),this.batch.visible=!1,this.batch.rect=null;var u=i?"装卸口":"货位",c="已生成 "+h.created.length+" 个"+u;h.skipped.length&&(c+=",跳过已存在 "+h.skipped.length+" 个"),o&&(c+=",片区容量不足跳过 "+o+" 个"),this.toast(c,"success")}else this.toast("请先勾选要生成的条目","warning")},exportJSON:function(){return this.ctrl?this.ctrl.exportJSON():null},importJSON:function(t){return this.ctrl?this.ctrl.importJSON(t):null},openExport:function(){this.jsonDialog={visible:!0,mode:"export",text:this.ctrl.exportJSON()}},openImport:function(){this.jsonDialog={visible:!0,mode:"import",text:""}},copyJSON:function(){var t=this,e=this.jsonDialog.text,i=function(){t.toast("已复制到剪贴板","success")},n=function(){var e=t.$refs.jsonTa;e&&(e.select(),t.toast("已全选文本,请按 Ctrl+C 复制"))};if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(e).then(i,n);else{var o=this.$refs.jsonTa;o?(o.select(),document.execCommand("copy")?i():n()):n()}},downloadJSON:function(){var t=new Blob([this.jsonDialog.text],{type:"application/json"}),e=document.createElement("a");e.href=URL.createObjectURL(t),e.download="warehouse-layout.json",e.click(),URL.revokeObjectURL(e.href),this.toast("已下载 warehouse-layout.json,可交由业务存入业务表","success")},applyImport:function(){try{this.ctrl.importJSON(this.jsonDialog.text),this.jsonDialog.visible=!1,this.toast("导入成功(可 Ctrl+Z 撤销)","success")}catch(t){this.toast("导入失败:"+(t&&t.message),"error")}},onKeydown:function(t){var e=t.target;if(!e||!/^(INPUT|TEXTAREA|SELECT)$/.test(e.tagName))if("Escape"===t.key){if(this.batch.visible||this.jsonDialog.visible)return this.batch.visible=!1,void(this.jsonDialog.visible=!1);this.draft=null,this.roadDraftFrom=null,this.multiIds.length?this.multiIds=[]:this.selection&&(this.selection=null,this.$emit("selection-change",null))}else"Delete"===t.key||"Backspace"===t.key?(this.selection||this.multiIds.length)&&(this.deleteSelection(),t.preventDefault()):!t.ctrlKey&&!t.metaKey||t.shiftKey||"z"!==t.key.toLowerCase()?((t.ctrlKey||t.metaKey)&&t.shiftKey&&"z"===t.key.toLowerCase()||(t.ctrlKey||t.metaKey)&&"y"===t.key.toLowerCase())&&(this.redo(),t.preventDefault()):(this.undo(),t.preventDefault())}},render:function(t){var e=this,i="wme-";function n(e,n){return t("button",{class:[i+"btn",(n=n||{}).cls],attrs:{disabled:!!n.disabled,title:n.title||""},on:{click:n.click}},e)}function o(e,n,o){var a=[t("span",{class:i+"row-label"},e)].concat(n);return o&&a.push(t("span",{class:i+"row-hint"},o)),t("div",{class:i+"row"},a)}function a(e,n,o){return t("select",{class:i+"select",on:{change:function(t){o(t.target.value)}}},n.map(function(i){return t("option",{attrs:{value:i.value},domProps:{selected:String(i.value)===String(e)}},i.label)}))}var r=[t("div",{class:i+"tool-grid"},this.toolDefs.map(function(n){return t("button",{key:n.value,class:[i+"tool-btn",{active:e.tool===n.value}],attrs:{title:n.hint},on:{click:function(){e.onToolClick(n)}}},n.label)}))];"road"===this.tool&&(r.push(o("节点吸附",[a(this.roadSnapValue,[{value:0,label:"关闭"},{value:.3,label:"0.3m"},{value:.5,label:"0.5m"},{value:.8,label:"0.8m"},{value:1.5,label:"1.5m"},{value:3,label:"3m"}],function(t){e.roadSnapValue=Number(t)})],"落点在此半径内复用已有节点")),r.push(o("自动补点",[a(this.roadFillStepValue,[{value:0,label:"关闭"},{value:2,label:"2m"},{value:5,label:"5m"},{value:10,label:"10m"},{value:20,label:"20m"}],function(t){e.roadFillStepValue=Number(t)})],"两点间距超过此值时等距补点"))),r.push(o("道路宽度",[t("input",{class:[i+"input","w-60"],attrs:{type:"number",min:.5,max:10,step:.5,value:this.model.roadWidth},on:{change:function(t){e.onRoadWidth(t.target.value)}}}),t("span",{class:i+"row-hint",style:{minWidth:"auto",flex:"none"}},"米")])),r.push(o("网格吸附",[t("input",{attrs:{type:"checkbox",checked:this.gridSnapOn},on:{change:function(t){e.gridSnapOn=t.target.checked}}}),t("span",{class:i+"row-hint",style:{minWidth:"auto",flex:"none"}},"0.1m")])),r.push(o("操作",[n("撤销",{disabled:!this.canUndo,click:this.undo}),n("重做",{disabled:!this.canRedo,click:this.redo}),n("删除选中",{disabled:!this.selection&&!this.multiIds.length,click:this.deleteSelection}),n("复制墙体",{disabled:!this.selection||"wall"!==this.selection.kind,click:this.duplicateWall})]));var s=[];if(this.showPanel){s.push(t("div",{class:i+"panel-block"},[t("div",{class:i+"panel-title"},"绘制工具"),t("div",{class:i+"tool-grid-wrap"},r),t("div",{class:i+"hint"},this.toolHint)]));var l=this.stats;function k(e,n,o){return t("div",{class:i+"stat"},[t("span",e),t("b",String(n)),t("i",o||"")])}s.push(t("div",{class:i+"panel-block"},[t("div",{class:i+"panel-title"},"统计"),t("div",{class:i+"stat-grid"},[k("仓库面积",l.warehouseArea,"m²"),k("货位数",l.slotCount,"个"),k("货位面积",l.slotArea,"m²"),k("货位占比",l.slotRatio,"%"),k("装卸口",l.dockCount,"个"),k("墙体",l.wallCount,"段"),k("道路总长",l.roadLength,"m"),k("道路面积",l.roadArea,"m²"),k("道路占比",l.roadRatio,"%"),k("节点/边",l.roadNodeCount+"/"+l.roadEdgeCount,"")])]));var d=[];0===this.issues.length?d.push(t("div",{class:i+"hint"},"未发现问题")):d.push(t("ul",{class:i+"issue-list"},this.issues.map(function(i,n){return t("li",{key:n,class:i.level||"warn",on:{click:function(){i.target&&(e.selection=i.target,e.$emit("selection-change",i.target))}}},[t("i",{class:"dot"}),i.message])}))),s.push(t("div",{class:i+"panel-block"},[t("div",{class:i+"panel-title"},["校验",t("span",{class:[i+"badge",0===this.issues.length?"ok":"warn"]},0===this.issues.length?"通过":this.issues.length+" 项")]),t("div",null,d)]));var h=[t("div",{class:i+"tabs"},[{value:"slot",label:"货位"},{value:"dock",label:"装卸口"},{value:"wall",label:"墙体"}].map(function(n){return t("button",{key:n.value,class:[i+"tab-btn",{active:e.group===n.value}],on:{click:function(){e.group=n.value}}},n.label)}))],u=[];"slot"===this.group?this.model.slots.forEach(function(n){u.push(t("div",{key:n.id,class:[i+"list-row",{active:e.isSelected("slot",n.id)}],on:{click:function(){e.selection={kind:"slot",id:n.id},e.$emit("selection-change",e.selection)}}},[t("input",{class:[i+"input",i+"code-input"],attrs:{value:e.bufValue("slot",n.id,n.id),title:n.id},on:{input:function(t){e.onBufInput("slot",n.id,t)},blur:function(){e.commitBuf("slot",n.id)},keydown:function(t){"Enter"===t.key&&t.target.blur()}}}),n.name?t("em",{class:i+"slot-name",attrs:{title:n.id+" · "+n.name}},n.name):null,t("button",{class:i+"del-btn",attrs:{title:"删除"},on:{click:function(t){t.stopPropagation(),e.ctrl.removeElement("slot",n.id)}}},"✕")]))}):"dock"===this.group?this.model.docks.forEach(function(n){u.push(t("div",{key:n.id,class:[i+"list-row",{active:e.isSelected("dock",n.id)}],on:{click:function(){e.selection={kind:"dock",id:n.id},e.$emit("selection-change",e.selection)}}},[t("span",{class:i+"row-id"},n.id),t("input",{class:[i+"input",i+"code-input"],attrs:{value:e.bufValue("dock",n.id,n.name||""),placeholder:"名称"},on:{input:function(t){e.onBufInput("dock",n.id,t)},blur:function(){e.commitBuf("dock",n.id)},keydown:function(t){"Enter"===t.key&&t.target.blur()}}}),t("button",{class:i+"del-btn",attrs:{title:"删除"},on:{click:function(t){t.stopPropagation(),e.ctrl.removeElement("dock",n.id)}}},"✕")]))}):this.model.walls.forEach(function(n){u.push(t("div",{key:n.id,class:[i+"list-row",{active:e.isSelected("wall",n.id)}],on:{click:function(){e.selection={kind:"wall",id:n.id},e.$emit("selection-change",e.selection)}}},[t("span",{class:i+"row-id"},[n.id,!1===n.fill?t("em"," 外墙"):null]),t("input",{class:[i+"input",i+"code-input"],attrs:{value:e.bufValue("wall",n.id,n.name||""),placeholder:"标签(可空)"},on:{input:function(t){e.onBufInput("wall",n.id,t)},blur:function(){e.commitBuf("wall",n.id)},keydown:function(t){"Enter"===t.key&&t.target.blur()}}}),t("button",{class:i+"del-btn",attrs:{title:"删除"},on:{click:function(t){t.stopPropagation(),e.ctrl.removeElement("wall",n.id)}}},"✕")]))}),h.push(t("div",{class:i+"list-scroll"},u)),s.push(t("div",{class:i+"panel-block"},[t("div",{class:i+"panel-title"},["元素",t("span",{class:i+"badge"},this.model.slots.length+" 货位 / "+this.model.docks.length+" 口")]),t("div",null,h)])),s.push(t("div",{class:i+"panel-block"},[t("div",{class:i+"panel-title"},"数据"),t("div",{class:i+"row"},[n("导出 JSON",{click:this.openExport}),n("导入 JSON",{click:this.openImport})]),t("div",{class:i+"hint"},"导出的 JSON 即后端契约结构,可手工存储到业务表;导入会整体替换当前布局(可撤销)")]))}var c=t(st,{props:{layout:this.model,mode:this.mapMode,draft:this.draft,selection:this.selection,multiIds:this.multiIds,gridSnap:this.gridSnapOn?.1:0,roadSnap:this.roadSnapValue,minRect:.1,showEditLayer:!0,night:this.night},on:{"rect-drawn":this.onRectDrawn,"canvas-click":this.onCanvasClick,"canvas-dblclick":this.onCanvasDblClick,"select-change":this.onSelectChange,"area-select":this.onAreaSelect,"drag-start":this.onDragStart,"drag-move":this.onDragMove,"drag-end":this.onDragEnd}}),f=[t("div",{class:i+"map-col"},[c])];if(this.showPanel&&f.push(t("div",{class:i+"panel"},s)),this.batch.visible){var p=this.batch,y=this.bizFilteredRows.map(function(e){return t("div",{key:e.code,class:i+"biz-row",on:{click:function(){e._checked=!e._checked}}},[t("input",{attrs:{type:"checkbox",checked:e._checked},on:{click:function(t){t.stopPropagation()},change:function(t){e._checked=t.target.checked}}}),t("span",{class:"code"},e.code),t("span",{class:"name"},e.name||""),t("span",{class:"rc"},null!=e.row?"排"+e.row+" 列"+e.col:"")])}),g=p.params,x=function(e,n){return t("div",{class:i+"row",style:{marginTop:"4px"}},[t("span",{class:i+"row-label",style:{flex:"none",width:"auto"}},e),n])},m=t("div",{class:i+"params-grid"},[x("宽(米)",t("input",{class:[i+"input","w-60"],attrs:{type:"number",min:.5,step:.1,value:g.w},on:{input:function(t){g.w=Number(t.target.value)||g.w}}})),x("深(米)",t("input",{class:[i+"input","w-60"],attrs:{type:"number",min:.5,step:.1,value:g.d},on:{input:function(t){g.d=Number(t.target.value)||g.d}}})),x("横向间距",t("input",{class:[i+"input","w-60"],attrs:{type:"number",min:0,step:.1,value:g.gapX},on:{input:function(t){g.gapX=Number(t.target.value)||0}}})),x("纵向间距",t("input",{class:[i+"input","w-60"],attrs:{type:"number",min:0,step:.1,value:g.gapY},on:{input:function(t){g.gapY=Number(t.target.value)||0}}})),x("入口朝向",a(g.entryDir,[{value:"bottom",label:"朝下"},{value:"top",label:"朝上"},{value:"left",label:"朝左"},{value:"right",label:"朝右"}],function(t){g.entryDir=t})),x("铺排方式",a(g.mode,[{value:"table",label:"按排/列推算"},{value:"rect",label:"框选片区"}],function(t){g.mode=t}))].concat("table"===g.mode?[x("起点 x",t("input",{class:[i+"input","w-60"],attrs:{type:"number",step:.5,value:g.originX},on:{input:function(t){g.originX=Number(t.target.value)||1}}})),x("起点 y",t("input",{class:[i+"input","w-60"],attrs:{type:"number",step:.5,value:g.originY},on:{input:function(t){g.originY=Number(t.target.value)||1}}}))]:[x("片区",p.rect?t("span",{class:i+"row-hint",style:{flex:"none"}},p.rect.width+" × "+p.rect.height+" 米"):n("去画布框选",{click:e.gotoRectSelect}))]));f.push(t("div",{class:i+"overlay",on:{mousedown:function(t){t.target===t.currentTarget&&(p.visible=!1)}}},[t("div",{class:[i+"modal","wide"]},[t("div",{class:i+"modal-title"},[("dock"===p.type?"批量选装卸口":"批量选货位")+"(已勾选 "+this.bizSelectedRows.length+" / "+p.rows.length+")",t("button",{class:i+"del-btn",on:{click:function(){p.visible=!1}}},"✕")]),t("div",{class:i+"modal-body"},[t("div",{class:i+"biz-toolbar"},[t("input",{class:[i+"input","w-80"],attrs:{placeholder:"搜索编码/名称",value:p.keyword},on:{input:function(t){p.keyword=t.target.value}}}),t("label",{style:{fontSize:"12px",display:"flex",alignItems:"center",gap:"4px"}},[t("input",{attrs:{type:"checkbox"},on:{change:e.toggleAllBiz}}),"全选(筛选结果内)"]),p.loading?t("span",{class:i+"row-hint",style:{flex:"none"}},"清单加载中…"):null]),t("div",{class:i+"biz-list"},y),m]),t("div",{class:i+"modal-footer"},[n("取消",{click:function(){p.visible=!1}}),n("生成",{cls:"primary",click:e.confirmBatchGenerate})])])]))}if(this.jsonDialog.visible){var v="export"===this.jsonDialog.mode,b=[t("textarea",{ref:"jsonTa",class:i+"textarea",attrs:{rows:v?14:12,readonly:v,placeholder:v?"":"粘贴 warehouse-layout JSON 内容"},domProps:{value:this.jsonDialog.text},on:v?{}:{input:function(t){e.jsonDialog.text=t.target.value}}})],w=v?[n("复制",{click:this.copyJSON}),n("下载文件",{click:this.downloadJSON}),n("关闭",{click:function(){e.jsonDialog.visible=!1}})]:[n("取消",{click:function(){e.jsonDialog.visible=!1}}),n("应用",{cls:"primary",click:this.applyImport})];f.push(t("div",{class:i+"overlay",on:{mousedown:function(t){t.target===t.currentTarget&&(e.jsonDialog.visible=!1)}}},[t("div",{class:[i+"modal","wide"]},[t("div",{class:i+"modal-title"},[v?"导出布局 JSON(契约结构,可手工存储到业务表)":"导入布局 JSON",t("button",{class:i+"del-btn",on:{click:function(){e.jsonDialog.visible=!1}}},"✕")]),t("div",{class:i+"modal-body"},b),t("div",{class:i+"modal-footer"},w)])]))}return this.notice.text&&f.push(t("div",{class:[i+"toast",this.notice.level]},this.notice.text)),t("div",{class:i+"editor"},f)}},ct="0.2.1",ft={install:function(t){t.component("WarehouseMap",F),t.component("WarehouseMapEditor",ut)},version:ct},pt=N.GRID_DEFAULT,yt=N.MAX_ENTRY_ROAD_DISTANCE,gt=N.MIN_ELEMENT_SIZE,xt=N.ROAD_FILL_STEP_DEFAULT,mt=N.ROAD_SNAP_TOLERANCE,vt=N.ROAD_WIDTH_DEFAULT,bt=N.WALL_MIN_SIZE,wt=N.boundaryPolygon,kt=U,St=N.clone,Et=N.computeStats,Mt=N.createHistory,Dt=e,Tt=ot,Pt=a.dist,Lt=N.exportLayout,It=N.findElement,Ot=et.findPath,Rt=et.invalidateLayout,zt=N.normalizeBoundary,Nt=N.orthoElbow,At=N.parseLayout,Wt=a.pointInPolygon,Bt=a.pointOnSegment,Ct=a.pointSegProjection,jt=a.polygonArea,_t=a.polygonBounds,Ft=N.polygonToRect,Ht=et.polylineLength,$t=a.projectPointOnPolygonBoundary,Vt=N.rectFromPoints,Jt=N.rectToPolygon,Kt=a.segSegIntersect,Yt=N.snapPoint,Ut=N.snapValue,Xt=N.validateModel;export{pt as GRID_DEFAULT,yt as MAX_ENTRY_ROAD_DISTANCE,gt as MIN_ELEMENT_SIZE,xt as ROAD_FILL_STEP_DEFAULT,mt as ROAD_SNAP_TOLERANCE,vt as ROAD_WIDTH_DEFAULT,bt as WALL_MIN_SIZE,F as WarehouseMap,ut as WarehouseMapEditor,wt as boundaryPolygon,kt as buildRoadGraph,St as clone,Et as computeStats,Mt as createHistory,Dt as createView,Tt as createWarehouseController,ft as default,Pt as dist,Lt as exportLayout,It as findElement,Ot as findPath,Rt as invalidateLayout,zt as normalizeBoundary,Nt as orthoElbow,At as parseLayout,Wt as pointInPolygon,Bt as pointOnSegment,Ct as pointSegProjection,jt as polygonArea,_t as polygonBounds,Ft as polygonToRect,Ht as polylineLength,$t as projectPointOnPolygonBoundary,Vt as rectFromPoints,Jt as rectToPolygon,Kt as segSegIntersect,Yt as snapPoint,Ut as snapValue,Xt as validateModel,ct as version};
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "warehouse-map-sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.1",
4
+ "description": "仓库地图 SDK:Canvas 渲染 + 沿道路 A* 路径导航 + 可视化编辑内核(Vue 2 组件,框架无关内核)",
5
+ "main": "dist/warehouse-map-sdk.esm.js",
6
+ "module": "dist/warehouse-map-sdk.esm.js",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
11
+ "keywords": [
12
+ "warehouse",
13
+ "map",
14
+ "canvas",
15
+ "vue2",
16
+ "astar",
17
+ "pathfinding",
18
+ "wms"
19
+ ],
20
+ "author": "",
21
+ "license": "MIT",
22
+ "peerDependencies": {
23
+ "vue": "^2.6.0 || ^2.7.0"
24
+ },
25
+ "devDependencies": {
26
+ "@babel/core": "^7.24.0",
27
+ "@babel/preset-env": "^7.24.0",
28
+ "@rollup/plugin-babel": "^5.3.1",
29
+ "@rollup/plugin-commonjs": "^21.1.0",
30
+ "@rollup/plugin-node-resolve": "^13.3.0",
31
+ "jsdom": "^24.1.3",
32
+ "rollup": "^2.79.1",
33
+ "rollup-plugin-terser": "7.0.2",
34
+ "rollup-plugin-vue": "^5.1.9",
35
+ "vue": "2.6.14",
36
+ "vue-template-compiler": "2.6.14"
37
+ },
38
+ "scripts": {
39
+ "build": "node scripts/build.js",
40
+ "test": "node test/smoke.js"
41
+ }
6
42
  }