@kq_npm/client3d_webgl_vue 4.5.55 → 4.5.57

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.
Files changed (82) hide show
  1. package/adddata/index.js +189 -21
  2. package/airspacegridoccupancyquery/index.js +1977 -0
  3. package/airspacegridoccupancyquery/style/airspacegridoccupancyquery.css +1 -0
  4. package/airspacegridoccupancyquery/style/index.js +3 -0
  5. package/airspaceprofileanalysis/index.js +1870 -0
  6. package/airspaceprofileanalysis/style/airspaceprofileanalysis.css +1 -0
  7. package/airspaceprofileanalysis/style/index.js +3 -0
  8. package/aspectanalysis/index.js +25 -7
  9. package/baseterraingallery/index.js +16 -4
  10. package/boxclip/index.js +58 -16
  11. package/buildpointmodel/index.js +3207 -230
  12. package/buildpointmodel/style/buildpointmodel.css +1 -1
  13. package/buildpolygonmodel/index.js +205 -81
  14. package/buildpolylinemodel/index.js +346 -70
  15. package/clientPrint/index.js +32440 -2337
  16. package/comparemap/index.js +132 -60
  17. package/compass/index.js +16 -6
  18. package/excavatefillanalysis/index.js +51 -7
  19. package/fixedzoomin/index.js +24 -7
  20. package/fixedzoomout/index.js +25 -7
  21. package/flight/index.js +113 -26
  22. package/floodanalysis/index.js +79 -14
  23. package/geologicalbodyanalysis/index.js +41 -5
  24. package/gpuspatialquery/index.js +127 -19
  25. package/gridoccupancyquery/index.js +627 -0
  26. package/gridoccupancyquery/style/gridoccupancyquery.css +1 -0
  27. package/gridoccupancyquery/style/index.js +3 -0
  28. package/hawkeye/index.js +20 -2
  29. package/headertemp/index.js +7 -2
  30. package/heatmap3d/index.js +282 -158
  31. package/index.js +32440 -2337
  32. package/isolineanalysis/index.js +113 -38
  33. package/light/index.js +80 -22
  34. package/limitheightanalysis/index.js +30 -10
  35. package/lowaltitudefeature/index.js +5027 -0
  36. package/lowaltitudefeature/style/index.js +3 -0
  37. package/lowaltitudefeature/style/lowaltitudefeature.css +1 -0
  38. package/measure/index.js +60 -19
  39. package/modelFlat/index.js +48 -8
  40. package/modeledit/index.js +38 -4
  41. package/modelexcavate/index.js +48 -7
  42. package/modelfilter/index.js +51 -8
  43. package/modelmaterialedit/index.js +127 -25
  44. package/modelprofileanalysis/index.js +51 -14
  45. package/modelselect/index.js +34 -3
  46. package/modelstyleedit/index.js +39 -3
  47. package/modeltransform/index.js +79 -14
  48. package/package.json +1 -1
  49. package/particleeffect/index.js +83 -17
  50. package/planeclip/index.js +66 -17
  51. package/pointcloudrender/index.js +134 -15
  52. package/radarscananalysis/index.js +35 -3
  53. package/resetview/index.js +14 -6
  54. package/roller/index.js +55 -18
  55. package/scaneffect/index.js +98 -29
  56. package/sceneadvancedtoimage/index.js +32 -6
  57. package/sceneapp/index.js +32440 -2337
  58. package/sceneset/index.js +141 -71
  59. package/scenetohdimage/index.js +23 -3
  60. package/sceneview/index.js +32440 -2337
  61. package/sceneview/style/sceneview.css +1 -1
  62. package/screenshot/index.js +44 -11
  63. package/shadowanalysis/index.js +79 -19
  64. package/sightlineanalysis/index.js +66 -15
  65. package/skylineanalysis/index.js +20 -4
  66. package/slopeanalysis/index.js +75 -16
  67. package/slopeaspectanalysis/index.js +128 -26
  68. package/statusbar/index.js +80 -67
  69. package/style.css +1 -1
  70. package/terrainoperation/index.js +39 -7
  71. package/terrainprofileanalysis/index.js +43 -5
  72. package/toolbarapp/index.js +32440 -2337
  73. package/toolboxapp/index.js +32440 -2337
  74. package/typhoontrac/index.js +134 -16
  75. package/underground/index.js +8 -2
  76. package/videofusion/index.js +164 -79
  77. package/videoproject/index.js +77 -23
  78. package/viewshedanalysis/index.js +61 -14
  79. package/weathereffect/index.js +73 -18
  80. package/webgl.es.js +866 -16
  81. package/windyslicing/index.js +258 -54
  82. package/wireframesketch/index.js +25 -8
@@ -12,6 +12,22 @@ return /******/ (function() { // webpackBootstrap
12
12
  /******/ "use strict";
13
13
  /******/ var __webpack_modules__ = ({
14
14
 
15
+ /***/ 1006:
16
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
17
+
18
+ /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(76314);
19
+ /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);
20
+ // Imports
21
+
22
+ var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()(function(i){return i[1]});
23
+ // Module
24
+ ___CSS_LOADER_EXPORT___.push([module.id, "\n.simple-filter-select[data-v-011f2cca] {\r\n width: 100%;\n}\n.option-content[data-v-011f2cca] {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n width: 100%;\r\n padding: 0 4px;\n}\n.option-text[data-v-011f2cca] {\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\n}\n.icon-class[data-v-011f2cca] {\r\n font-size: 14px;\r\n padding: 4px;\n}\n.icon-class[data-v-011f2cca]:hover {\r\n color: var(--kq-color-danger);\n}\n[data-v-011f2cca] .kq-option:hover .delete-btn {\r\n opacity: 1;\n}\n[data-v-011f2cca] .custom-select-popper {\r\n --kq-select-dropdown-item-padding: 4px 8px;\n}\n[data-v-011f2cca] .kq-option {\r\n padding: 0 !important;\n}\r\n", ""]);
25
+ // Exports
26
+ /* harmony default export */ __webpack_exports__.A = (___CSS_LOADER_EXPORT___);
27
+
28
+
29
+ /***/ }),
30
+
15
31
  /***/ 4822:
16
32
  /***/ (function(module) {
17
33
 
@@ -58,13 +74,13 @@ var _default = exports.A = {
58
74
  t,
59
75
  lang,
60
76
  locale
61
- } = (0, _useGlobalConfig.useLocale)();
62
- const selectRef = (0, _vue.ref)(null);
77
+ } = (0, _useGlobalConfig.useLocale)(); // 国际化相关方法
78
+ const selectRef = (0, _vue.ref)(null); // 下拉选择组件引用
63
79
  const props = __props;
64
- const selectedCondition = (0, _vue.ref)("");
65
- const filterConditions = (0, _vue.ref)([...props.initialConditions]);
66
- const selectKey = (0, _vue.ref)(0);
67
- const emit = __emit;
80
+ const selectedCondition = (0, _vue.ref)(""); // 当前选中的过滤条件
81
+ const filterConditions = (0, _vue.ref)([...props.initialConditions]); // 可选过滤条件列表
82
+ const selectKey = (0, _vue.ref)(0); // 下拉组件 key,用于强制刷新
83
+ const emit = __emit; // 对外事件定义
68
84
 
69
85
  // 监听初始条件变化
70
86
  (0, _vue.watch)(() => props.initialConditions, async newVal => {
@@ -76,7 +92,11 @@ var _default = exports.A = {
76
92
  immediate: true
77
93
  });
78
94
 
79
- // 处理选中/新增逻辑
95
+ /**
96
+ * @description 处理选中/新增逻辑
97
+ * @param {string} value 选中的条件字符串
98
+ * @returns {Promise<void>}
99
+ */
80
100
  const handleConditionChange = async value => {
81
101
  if (!value) return;
82
102
  const isExist = filterConditions.value.includes(value);
@@ -86,12 +106,22 @@ var _default = exports.A = {
86
106
  }
87
107
  emit("condition-change", value);
88
108
  };
109
+
110
+ /**
111
+ * @description 处理新增自定义条件
112
+ * @param {string} item 新创建的条件字符串
113
+ * @returns {Promise<void>}
114
+ */
89
115
  const handleCreateCondition = async item => {
90
116
  if (!item) return;
91
117
  await handleConditionChange(item);
92
118
  selectedCondition.value = item;
93
119
  };
94
- //
120
+ /**
121
+ * @description 删除指定条件选项
122
+ * @param {string} condition 待删除的条件字符串
123
+ * @returns {Promise<void>}
124
+ */
95
125
  const handleDeleteOption = async condition => {
96
126
  filterConditions.value = filterConditions.value.filter(item => item !== condition);
97
127
  if (selectedCondition.value === condition) {
@@ -103,7 +133,10 @@ var _default = exports.A = {
103
133
  emit("option-delete", condition);
104
134
  };
105
135
 
106
- // 实时输入监听
136
+ /**
137
+ * @description 实时输入监听
138
+ * @param {string} val 当前输入值
139
+ */
107
140
  const handleInput = val => {};
108
141
 
109
142
  // 清空选中
@@ -113,11 +146,17 @@ var _default = exports.A = {
113
146
 
114
147
  // 供父组件调用
115
148
  __expose({
149
+ // 刷新下拉组件
116
150
  refreshConditions: () => {
117
151
  selectKey.value++;
118
152
  },
119
153
  clearSelection,
154
+ // 获取当前条件列表副本
120
155
  getConditions: () => [...filterConditions.value],
156
+ /**
157
+ * @description 添加条件
158
+ * @param {string} condition 待添加的条件字符串
159
+ */
121
160
  addCondition: condition => {
122
161
  if (condition && !filterConditions.value.includes(condition)) {
123
162
  filterConditions.value.push(condition);
@@ -172,6 +211,504 @@ var _default = exports.A = {
172
211
 
173
212
  /***/ }),
174
213
 
214
+ /***/ 11790:
215
+ /***/ (function(__unused_webpack_module, exports) {
216
+
217
+
218
+
219
+ Object.defineProperty(exports, "__esModule", ({
220
+ value: true
221
+ }));
222
+ exports["default"] = void 0;
223
+ /**
224
+ * BuildPointModel 内部 API 工具类
225
+ * 用于复杂几何符号模板的服务器交互(上传/下载/删除)
226
+ * 通过组件的 props(geometryServerUrl, geometryServerToken)配置,不依赖全局 store
227
+ */
228
+ class BuildPointModelApi {
229
+ /**
230
+ * @param {string} serverUrl - 服务器地址(如 http://xxx.com)
231
+ * @param {string} token - 认证 token
232
+ */
233
+ constructor(serverUrl, token) {
234
+ this._serverUrl = serverUrl || '';
235
+ this._token = token || '';
236
+ this._resourceDirectory = null;
237
+ }
238
+
239
+ /**
240
+ * @description 统一的请求方法(基于原生 fetch)
241
+ * @param {string} method HTTP 请求方法(GET/POST/DELETE 等)
242
+ * @param {string} path 接口路径(拼接到 /server-manager/network/disk 之后)
243
+ * @param {Object} [data={}] 请求参数或请求体
244
+ * @param {Object} [config={}] 额外配置(headers、timeout 等)
245
+ * @returns {Promise<Object|null>} 接口返回的数据体,失败返回 null
246
+ */
247
+ async _request(method, path, data = {}, config = {}) {
248
+ const baseUrl = this._serverUrl.replace(/\/+$/, '');
249
+ let url = `${baseUrl}/server-manager/network/disk${path}`;
250
+ const headers = {
251
+ ...config.headers
252
+ };
253
+ const isFormData = data instanceof FormData;
254
+
255
+ // 超时控制
256
+ const controller = new AbortController();
257
+ const timeout = config.timeout || 30000;
258
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
259
+ const fetchOptions = {
260
+ method: method.toUpperCase(),
261
+ headers,
262
+ signal: controller.signal,
263
+ redirect: "follow"
264
+ };
265
+ if (method.toLowerCase() === 'get') {
266
+ // GET 请求:将 data 拼接为 query string
267
+ const params = new URLSearchParams(data);
268
+ if (this._token) {
269
+ params.append('ua_token', this._token);
270
+ }
271
+ if (params.toString()) {
272
+ url += (url.includes('?') ? '&' : '?') + params.toString();
273
+ }
274
+ } else {
275
+ // 非 GET 请求:token 拼接到 URL
276
+ if (this._token) {
277
+ url += (url.includes('?') ? '&' : '?') + 'ua_token=' + encodeURIComponent(this._token);
278
+ }
279
+ if (isFormData) {
280
+ // FormData:移除 Content-Type 让浏览器自动设置 boundary
281
+ delete headers['Content-Type'];
282
+ fetchOptions.body = data;
283
+ } else {
284
+ // 其他请求:JSON body
285
+ headers['Content-Type'] = 'application/json';
286
+ fetchOptions.body = JSON.stringify(data);
287
+ }
288
+ }
289
+ try {
290
+ const response = await fetch(url, fetchOptions);
291
+ clearTimeout(timeoutId);
292
+ const resData = await response.json();
293
+ if (resData && resData.data && resData.data.code === 200) {
294
+ return resData.data;
295
+ } else if (resData && resData.code === 200) {
296
+ return resData;
297
+ }
298
+ return null;
299
+ } catch (error) {
300
+ clearTimeout(timeoutId);
301
+ if (error.name === 'AbortError') {
302
+ throw new Error('请求超时');
303
+ }
304
+ throw new Error(error.message || '请求失败');
305
+ }
306
+ }
307
+
308
+ // ============ 目录内容相关接口 ============
309
+
310
+ /**
311
+ * 获取当前层级目录状态(不递归)
312
+ * @param {string} [filePath] - 目录路径,不传则返回根目录
313
+ */
314
+ async getDirContents(filePath) {
315
+ const query = filePath ? `?filePath=${encodeURIComponent(filePath)}&includeSuffix=&filterFile=false` : '?includeSuffix=&filterFile=false';
316
+ const response = await this._request('GET', `/directoryByRoot${query}`);
317
+ return response ? response.data : {
318
+ fileList: [],
319
+ filePath: filePath || ''
320
+ };
321
+ }
322
+
323
+ /**
324
+ * 初始化:通过 getDirContents 遍历磁盘,发现 mapRoot 目录并存储为 _resourceDirectory
325
+ * 后续 getAllContents(isFirst=true) 会自动拼接 _resourceDirectory 作为根路径
326
+ * @returns {Promise<string|null>} 发现的 mapRoot 路径,未找到返回 null
327
+ */
328
+ async init() {
329
+ if (this._resourceDirectory) return this._resourceDirectory;
330
+
331
+ // 1. 获取根目录(返回各磁盘)
332
+ const rootData = await this.getDirContents();
333
+ if (!rootData?.fileList?.length) {
334
+ console.error('[BuildPointModelApi] 获取根目录失败,无法初始化 resourceDirectory');
335
+ return null;
336
+ }
337
+
338
+ // 2. 遍历每个磁盘,查找 mapRoot 目录
339
+ for (const disk of rootData.fileList) {
340
+ if (disk.fileType !== "File Folder") continue;
341
+ const diskContents = await this.getDirContents(disk.dirPath);
342
+ if (!diskContents?.fileList?.length) continue;
343
+ const mapRootDir = diskContents.fileList.find(item => item.dirName === 'mapRoot' && item.fileType === "File Folder");
344
+ if (mapRootDir) {
345
+ this._resourceDirectory = mapRootDir.dirPath;
346
+ return this._resourceDirectory;
347
+ }
348
+ }
349
+ console.error('[BuildPointModelApi] 未找到 mapRoot 目录');
350
+ return null;
351
+ }
352
+
353
+ /**
354
+ * 递归获取目录树结构
355
+ * @param {string} filePath - 目标路径
356
+ * @param {boolean} [isFirst=false] - 是否首次调用,首次调用时需拼接 resourceDirectory 根路径
357
+ */
358
+ async getAllContents(filePath, isFirst = false) {
359
+ if (isFirst) {
360
+ filePath = this._resourceDirectory + (filePath.startsWith('/') ? filePath : '/' + filePath);
361
+ }
362
+ const response = await this.getDirContents(filePath);
363
+ if (!response || !response.fileList || !Array.isArray(response.fileList)) return [];
364
+ let result = [...response.fileList];
365
+ for (let i = 0; i < result.length; i++) {
366
+ const item = result[i];
367
+ if (item.fileType === "File Folder" && item.dirPath) {
368
+ const subContents = await this.getAllContents(item.dirPath);
369
+ item.children = subContents;
370
+ }
371
+ }
372
+ return result;
373
+ }
374
+
375
+ // ============ 文件操作接口 ============
376
+
377
+ /**
378
+ * @description 检查文件/目录是否存在
379
+ * @param {string} filePath 文件或目录的绝对路径
380
+ * @returns {Promise<boolean>} 存在返回 true,否则返回 false
381
+ */
382
+ async checkFilePath(filePath) {
383
+ const response = await this._request('GET', `/checkFilePath?filePath=${encodeURIComponent(filePath)}`);
384
+ return response?.data?.resultBool === true;
385
+ }
386
+
387
+ /**
388
+ * @description 删除文件或目录
389
+ * @param {string} filePath 文件或目录的绝对路径
390
+ * @returns {Promise<boolean>} 删除成功返回 true,否则返回 false
391
+ */
392
+ async deleteFile(filePath) {
393
+ const response = await this._request('DELETE', `/delete?filePath=${encodeURIComponent(filePath)}`);
394
+ return response?.data === true;
395
+ }
396
+
397
+ /**
398
+ * @description 创建目录
399
+ * @param {string} filePath 父级目录路径
400
+ * @param {string} folderName 新建目录名称
401
+ * @returns {Promise<Object|null>} 创建结果,失败返回 null
402
+ */
403
+ async createDirectory(filePath, folderName) {
404
+ const response = await this._request('POST', `/mkdirs?filePath=${encodeURIComponent(filePath)}&folderName=${folderName}`);
405
+ return response?.data || null;
406
+ }
407
+
408
+ /**
409
+ * @description 上传单个文件
410
+ * @param {Object} fileData 文件数据对象(含 file、filePath、name 等字段)
411
+ * @returns {Promise<Object|null>} 上传结果,失败返回 null
412
+ */
413
+ async uploadFile(fileData) {
414
+ try {
415
+ const formData = new FormData();
416
+ formData.append('file', fileData.file);
417
+ const params = {
418
+ filePath: fileData.filePath,
419
+ name: fileData.name,
420
+ origSize: fileData.origSize || fileData.file.size,
421
+ chunkSize: fileData.chunkSize || fileData.file.size,
422
+ chunks: fileData.chunks || 1,
423
+ chunk: fileData.chunk || 0
424
+ };
425
+ Object.keys(params).forEach(key => {
426
+ formData.append(key, params[key]);
427
+ });
428
+ const response = await this._request('POST', '/uploadFile', formData, {
429
+ headers: {
430
+ 'Content-Type': 'multipart/form-data'
431
+ }
432
+ });
433
+ return response?.data || null;
434
+ } catch (error) {
435
+ throw new Error(error);
436
+ }
437
+ }
438
+
439
+ // ============ 业务接口 ============
440
+
441
+ /**
442
+ * @description 上传点符号素材(创建目录 + 上传图片 + 上传模型)
443
+ * @param {Object} params 上传参数(含 filePath、name、img、path)
444
+ * @returns {Promise<Object|null>} 上传成功返回 { success, dirPath },失败返回 null
445
+ */
446
+ async uploadPointMaterial(params) {
447
+ const {
448
+ filePath,
449
+ name,
450
+ img,
451
+ path
452
+ } = params;
453
+ if (!filePath || !name) return null;
454
+
455
+ // 拼接 _resourceDirectory 得到绝对路径(相对路径兜底时)
456
+ const fullPath = this._resourceDirectory && !/^[A-Za-z]:/.test(filePath) ? this._resourceDirectory + (filePath.startsWith('/') ? filePath : '/' + filePath) : filePath;
457
+ const targetDirPath = `${fullPath}/${name}`;
458
+ try {
459
+ // 检查并删除已存在目录(删除失败不阻断流程,继续尝试创建)
460
+ const exists = await this.checkFilePath(targetDirPath);
461
+ if (exists) {
462
+ try {
463
+ await this.deleteFile(targetDirPath);
464
+ } catch (delErr) {
465
+ console.warn('[BuildPointModelApi] 删除已存在目录失败,继续尝试创建:', delErr);
466
+ }
467
+ }
468
+
469
+ // 创建目录
470
+ const createdPath = await this.createDirectory(fullPath, name);
471
+ if (!createdPath) return null;
472
+
473
+ // 上传图片
474
+ if (img) {
475
+ const actualImg = img.raw || img;
476
+ await this.uploadFile({
477
+ file: actualImg,
478
+ filePath: targetDirPath,
479
+ name: actualImg.name
480
+ });
481
+ }
482
+
483
+ // 上传模型
484
+ if (path) {
485
+ const actualPath = path.raw || path;
486
+ await this.uploadFile({
487
+ file: actualPath,
488
+ filePath: targetDirPath,
489
+ name: actualPath.name
490
+ });
491
+ }
492
+ return {
493
+ success: true,
494
+ dirPath: createdPath
495
+ };
496
+ } catch (error) {
497
+ return null;
498
+ }
499
+ }
500
+
501
+ /**
502
+ * @description 上传JSON数据到服务器(用于复杂几何模板保存);方案2:按模板名称分别存储为独立 JSON 文件
503
+ * @param {Object} params 上传参数(含 filePath、fileName、jsonData)
504
+ * @returns {Promise<Object|null>} 上传结果,失败返回 null
505
+ */
506
+ async uploadJsonData(params) {
507
+ try {
508
+ const {
509
+ filePath,
510
+ fileName,
511
+ jsonData
512
+ } = params;
513
+
514
+ // 拼接 _resourceDirectory 得到绝对路径
515
+ const fullPath = this._resourceDirectory ? this._resourceDirectory + (filePath.startsWith('/') ? filePath : '/' + filePath) : filePath;
516
+ const formattedFileName = fileName.endsWith('.json') ? fileName : `${fileName}.json`;
517
+
518
+ // 将JSON对象转换为Blob
519
+ const jsonBlob = new Blob([JSON.stringify(jsonData, null, 2)], {
520
+ type: 'application/json'
521
+ });
522
+ const jsonFile = new File([jsonBlob], formattedFileName, {
523
+ type: 'application/json'
524
+ });
525
+
526
+ // 检查目标目录是否存在
527
+ const dirExists = await this.checkFilePath(fullPath);
528
+ if (!dirExists) {
529
+ console.error(`[BuildPointModelApi] 目标目录不存在: ${fullPath}`);
530
+ throw new Error(`目标目录 "${fullPath}" 不存在,无法上传`);
531
+ }
532
+ const targetFile = `${fullPath}/${formattedFileName}`;
533
+ const fileExists = await this.checkFilePath(targetFile);
534
+ if (fileExists) {
535
+ await this.deleteFile(targetFile);
536
+ }
537
+ const result = await this.uploadFile({
538
+ file: jsonFile,
539
+ filePath: fullPath,
540
+ name: formattedFileName
541
+ });
542
+ return result?.uploaded ? result : null;
543
+ } catch (error) {
544
+ console.error('[BuildPointModelApi] uploadJsonData 失败:', error);
545
+ return null;
546
+ }
547
+ }
548
+
549
+ // ============ 辅助方法 ============
550
+
551
+ /**
552
+ * 从目录树数据构建分类列表(仅名称,不加载 base64)
553
+ * 保留原始文件列表在 _children 中,供 loadCategorySymbols 按需加载
554
+ * @param {Array} data - 目录树数据
555
+ * @returns {Array} 分类列表 [{ name, _dirPath, _children, children: [] }]
556
+ */
557
+ buildCategoryList(data) {
558
+ const result = [];
559
+ for (const parentDir of data) {
560
+ if (parentDir.fileType !== "File Folder") continue;
561
+ result.push({
562
+ name: parentDir.dirName,
563
+ _dirPath: parentDir.dirPath,
564
+ _children: parentDir.children || [],
565
+ children: [] // 选中分类后按需加载
566
+ });
567
+ }
568
+ return result;
569
+ }
570
+
571
+ /**
572
+ * 按需加载指定分类的符号数据(获取 base64)
573
+ * 按文件基础名分组,每组对应一个符号
574
+ * @param {Object} categoryItem - buildCategoryList 返回的分类项(含 _children)
575
+ * @returns {Promise<Array>} 加载完成的 children 数组
576
+ */
577
+ async loadCategorySymbols(categoryItem) {
578
+ if (!categoryItem._children?.length) return categoryItem.children;
579
+
580
+ // 已加载过则直接返回
581
+ if (categoryItem.children?.length) return categoryItem.children;
582
+ const fileGroups = new Map();
583
+ for (const file of categoryItem._children) {
584
+ if (file.fileType === "File Folder") continue;
585
+ const baseName = file.dirName.replace(/\.[^.]+$/, '');
586
+ if (!fileGroups.has(baseName)) {
587
+ fileGroups.set(baseName, {});
588
+ }
589
+ const group = fileGroups.get(baseName);
590
+ if (file.dirName.endsWith('.glb')) {
591
+ group.glb = file;
592
+ } else if (file.dirName.endsWith('.png')) {
593
+ group.png = file;
594
+ }
595
+ }
596
+
597
+ // 并行请求所有文件的 base64
598
+ const childrenData = [];
599
+ for (const [baseName, files] of fileGroups) {
600
+ if (files.glb) {
601
+ try {
602
+ const [glbBase64, pngBase64] = await Promise.all([this.getFileBase64(files.glb.dirPath), files.png ? this.getFileBase64(files.png.dirPath) : Promise.resolve(null)]);
603
+ childrenData.push({
604
+ name: baseName,
605
+ img: pngBase64 ? `data:image/png;base64,${pngBase64}` : '',
606
+ path: glbBase64 ? `data:model/gltf-binary;base64,${glbBase64}` : ''
607
+ });
608
+ } catch (err) {
609
+ console.error(`[BuildPointModelApi] 加载符号 "${baseName}" 失败:`, err);
610
+ }
611
+ }
612
+ }
613
+
614
+ // 直接修改 categoryItem.children(Vue 响应式会追踪)
615
+ categoryItem.children.splice(0, categoryItem.children.length, ...childrenData);
616
+ return categoryItem.children;
617
+ }
618
+
619
+ /**
620
+ * 获取文件的 base64 内容
621
+ * 通过 downloadFile 接口获取原始二进制数据,客户端侧转为 base64
622
+ * 避免 /base64 接口将二进制文件当文本读取导致数据损坏的问题
623
+ * @param {string} filePath - 文件路径
624
+ * @returns {Promise<string|null>} base64 字符串
625
+ */
626
+ async getFileBase64(filePath) {
627
+ try {
628
+ const baseUrl = this._serverUrl.replace(/\/+$/, '');
629
+ const params = new URLSearchParams({
630
+ filePath
631
+ });
632
+ if (this._token) {
633
+ params.append('ua_token', this._token);
634
+ }
635
+ const url = `${baseUrl}/server-manager/network/disk/downloadFile?${params.toString()}`;
636
+ const controller = new AbortController();
637
+ const timeoutId = setTimeout(() => controller.abort(), 30000);
638
+ const response = await fetch(url, {
639
+ method: 'GET',
640
+ signal: controller.signal
641
+ });
642
+ clearTimeout(timeoutId);
643
+ if (!response.ok) {
644
+ throw new Error(`下载文件失败: ${response.status}`);
645
+ }
646
+
647
+ // 获取二进制数据,客户端侧转为 base64(分块处理避免大文件栈溢出)
648
+ const arrayBuffer = await response.arrayBuffer();
649
+ const bytes = new Uint8Array(arrayBuffer);
650
+ const chunkSize = 8192;
651
+ let base64 = '';
652
+ for (let i = 0; i < bytes.length; i += chunkSize) {
653
+ const chunk = bytes.slice(i, i + chunkSize);
654
+ base64 += String.fromCharCode.apply(null, chunk);
655
+ }
656
+ return btoa(base64);
657
+ } catch (error) {
658
+ console.error(`[BuildPointModelApi] getFileBase64 失败:`, error);
659
+ return null;
660
+ }
661
+ }
662
+
663
+ /**
664
+ * 获取文件的文本内容(通过 base64 接口获取文件二进制数据,解码为文本)
665
+ * 用于读取 JSON 等文本文件
666
+ * 相比 downloadFile 接口,base64 接口走统一 _request 方法,鉴权/超时/错误处理一致
667
+ * @param {string} filePath - 文件绝对路径
668
+ * @returns {Promise<string|null>} 文件文本内容
669
+ */
670
+ async getFileText(filePath) {
671
+ try {
672
+ const response = await this._request('GET', `/base64?filePath=${encodeURIComponent(filePath)}`);
673
+ if (!response?.data) return null;
674
+ // base64 解码还原为原始文本
675
+ return atob(response.data);
676
+ } catch (error) {
677
+ console.error(`[BuildPointModelApi] getFileText 失败:`, error);
678
+ return null;
679
+ }
680
+ }
681
+
682
+ /**
683
+ * 通过 fetch 读取 JSON 文件(用于读取服务器上的模板 JSON)
684
+ * @deprecated 请使用 getFileText 替代,此方法依赖静态文件服务,可能不可用
685
+ */
686
+ async readJsonByFetch(jsonPath) {
687
+ try {
688
+ const baseUrl = this._serverUrl.replace(/\/+$/, '');
689
+ let url = `${baseUrl}${jsonPath}`;
690
+ if (this._token) {
691
+ url += (url.includes('?') ? '&' : '?') + 'ua_token=' + encodeURIComponent(this._token);
692
+ }
693
+ const response = await fetch(url, {
694
+ headers: {
695
+ Accept: 'application/json'
696
+ },
697
+ method: 'GET'
698
+ });
699
+ if (!response.ok) {
700
+ return null;
701
+ }
702
+ return await response.json();
703
+ } catch (err) {
704
+ return null;
705
+ }
706
+ }
707
+ }
708
+ exports["default"] = BuildPointModelApi;
709
+
710
+ /***/ }),
711
+
175
712
  /***/ 20064:
176
713
  /***/ (function(module) {
177
714
 
@@ -214,6 +751,92 @@ module.exports = require("@babel/runtime/helpers/interopRequireDefault");
214
751
 
215
752
  /***/ }),
216
753
 
754
+ /***/ 39745:
755
+ /***/ (function(__unused_webpack_module, exports) {
756
+
757
+
758
+
759
+ Object.defineProperty(exports, "__esModule", ({
760
+ value: true
761
+ }));
762
+ exports["default"] = void 0;
763
+ /**
764
+ * BSP 操作工具类
765
+ * 提取 _operationModels 和 _buildComplexModel 中共用的 BSP 操作逻辑
766
+ */
767
+ class BSPOperationUtil {
768
+ /**
769
+ * 将简单几何模型转换为 BSP 模型
770
+ * @param {Object} model - 简单几何模型实例(PMCube/PMSphere等)
771
+ * @param {Cesium.PMKq3dBSPUtility} bspUtility - BSP 工具实例
772
+ * @returns {Object|null} BSP 模型,失败返回 null
773
+ */
774
+ static convertModelToBSP(model, bspUtility) {
775
+ if (!model || !bspUtility) return null;
776
+ const bspes = [];
777
+ bspUtility.getBSPes(model, model, bspes);
778
+ return bspes[0] || null;
779
+ }
780
+
781
+ /**
782
+ * 安全保存 BSP 结果并解析为对象
783
+ * @param {Cesium.PMKq3dBSPUtility} bspUtility - BSP 工具实例
784
+ * @param {Object} bspResult - BSP 运算结果
785
+ * @returns {Object|null} 解析后的 bspGeometry 对象
786
+ */
787
+ static saveBSPResult(bspUtility, bspResult) {
788
+ if (!bspUtility || !bspResult) return null;
789
+ let savedBsp = bspUtility.save(bspResult);
790
+ if (!savedBsp) return null;
791
+ console.log('[Z-OFFSET-DEBUG] saveBSPResult - BSP保存结果:', {
792
+ savedBspType: typeof savedBsp,
793
+ savedBspPreview: typeof savedBsp === 'string' ? savedBsp.substring(0, 200) : JSON.stringify(savedBsp).substring(0, 200),
794
+ bspUtilityCenter: bspUtility._center ? {
795
+ x: bspUtility._center.x,
796
+ y: bspUtility._center.y,
797
+ z: bspUtility._center.z
798
+ } : bspUtility.center ? {
799
+ x: bspUtility.center.x,
800
+ y: bspUtility.center.y,
801
+ z: bspUtility.center.z
802
+ } : 'unknown'
803
+ });
804
+ let bspGeometry;
805
+ if (typeof savedBsp === 'string') {
806
+ try {
807
+ bspGeometry = JSON.parse(savedBsp);
808
+ } catch (e) {
809
+ console.error('解析 bspGeometry 失败:', e);
810
+ return null;
811
+ }
812
+ } else {
813
+ bspGeometry = savedBsp;
814
+ }
815
+ if (!bspGeometry || typeof bspGeometry === 'object' && !bspGeometry.polygons) {
816
+ console.warn('bspGeometry 结构无效:', bspGeometry);
817
+ return null;
818
+ }
819
+ return bspGeometry;
820
+ }
821
+
822
+ /**
823
+ * 获取 BSP 模型(无论是简单模型还是已确认 BSP 组合)
824
+ * @param {Object} modelData - { pointModels, isBsp, bspItems }
825
+ * @param {Object} rawModel - 原始模型实例
826
+ * @param {Cesium.PMKq3dBSPUtility} bspUtility - BSP 工具实例
827
+ * @returns {Object|null} BSP 模型
828
+ */
829
+ static getBSPModel(modelData, rawModel, bspUtility) {
830
+ if (modelData.isBsp) {
831
+ return rawModel.bspResult || rawModel;
832
+ }
833
+ return BSPOperationUtil.convertModelToBSP(rawModel, bspUtility);
834
+ }
835
+ }
836
+ exports["default"] = BSPOperationUtil;
837
+
838
+ /***/ }),
839
+
217
840
  /***/ 42975:
218
841
  /***/ (function(module) {
219
842
 
@@ -234,7 +857,8 @@ exports["default"] = exports.MODEL_TYPES = exports.GEOMETRY_DEFAULT_CONFIG = exp
234
857
  const MODEL_TYPES = exports.MODEL_TYPES = Object.freeze({
235
858
  DYNAMIC: "dynamicSymbol",
236
859
  GEOMETRY: "geometrySymbol",
237
- CUSTOM_POINT: "customPointSymbol"
860
+ CUSTOM_POINT: "customPointSymbol",
861
+ COMPLEX_GEOMETRY: "complexGeometrySymbol"
238
862
  });
239
863
  const EXCLUDED_PROPERTY_FIELDS = exports.EXCLUDED_PROPERTY_FIELDS = Object.freeze(["oid", "kid", "id", "fid", "objectid", "smid", "sid"]);
240
864
  const GEOMETRY_DEFAULT_CONFIG = exports.GEOMETRY_DEFAULT_CONFIG = Object.freeze({
@@ -449,69 +1073,17 @@ module.exports = require("element-plus/dist/index.full.js");
449
1073
 
450
1074
  /***/ }),
451
1075
 
452
- /***/ 64546:
453
- /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
454
-
455
- // ESM COMPAT FLAG
456
- __webpack_require__.r(__webpack_exports__);
1076
+ /***/ 65698:
1077
+ /***/ (function(module) {
457
1078
 
458
- // EXPORTS
459
- __webpack_require__.d(__webpack_exports__, {
460
- __esModule: function() { return /* reexport */ filterConditionSelectvue_type_script_setup_true_lang_js/* __esModule */.B; },
461
- "default": function() { return /* binding */ filterConditionSelect; }
462
- });
1079
+ module.exports = require("@kq_npm/client_icons_vue");
463
1080
 
464
- // EXTERNAL MODULE: ./node_modules/babel-loader/lib/index.js??clonedRuleSet-1.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=script&setup=true&lang=js
465
- var filterConditionSelectvue_type_script_setup_true_lang_js = __webpack_require__(10993);
466
- ;// ./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=script&setup=true&lang=js
467
-
468
- // EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js
469
- var injectStylesIntoStyleTag = __webpack_require__(85072);
470
- var injectStylesIntoStyleTag_default = /*#__PURE__*/__webpack_require__.n(injectStylesIntoStyleTag);
471
- // EXTERNAL MODULE: ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=style&index=0&id=7e7a85c7&scoped=true&lang=css
472
- var filterConditionSelectvue_type_style_index_0_id_7e7a85c7_scoped_true_lang_css = __webpack_require__(66328);
473
- ;// ./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=style&index=0&id=7e7a85c7&scoped=true&lang=css
1081
+ /***/ }),
474
1082
 
475
-
1083
+ /***/ 66262:
1084
+ /***/ (function(__unused_webpack_module, exports) {
476
1085
 
477
- var options = {};
478
-
479
- options.insert = "head";
480
- options.singleton = false;
481
-
482
- var update = injectStylesIntoStyleTag_default()(filterConditionSelectvue_type_style_index_0_id_7e7a85c7_scoped_true_lang_css/* default */.A, options);
483
-
484
-
485
-
486
- /* harmony default export */ var buildpointmodel_filterConditionSelectvue_type_style_index_0_id_7e7a85c7_scoped_true_lang_css = (filterConditionSelectvue_type_style_index_0_id_7e7a85c7_scoped_true_lang_css/* default */.A.locals || {});
487
- ;// ./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=style&index=0&id=7e7a85c7&scoped=true&lang=css
488
-
489
- // EXTERNAL MODULE: ./node_modules/vue-loader/dist/exportHelper.js
490
- var exportHelper = __webpack_require__(66262);
491
- ;// ./src/webgl/buildpointmodel/filterConditionSelect.vue
492
-
493
-
494
-
495
- ;
496
-
497
-
498
- const __exports__ = /*#__PURE__*/(0,exportHelper/* default */.A)(filterConditionSelectvue_type_script_setup_true_lang_js/* default */.A, [['__scopeId',"data-v-7e7a85c7"]])
499
-
500
- /* harmony default export */ var filterConditionSelect = (__exports__);
501
-
502
- /***/ }),
503
-
504
- /***/ 65698:
505
- /***/ (function(module) {
506
-
507
- module.exports = require("@kq_npm/client_icons_vue");
508
-
509
- /***/ }),
510
-
511
- /***/ 66262:
512
- /***/ (function(__unused_webpack_module, exports) {
513
-
514
- var __webpack_unused_export__;
1086
+ var __webpack_unused_export__;
515
1087
 
516
1088
  __webpack_unused_export__ = ({ value: true });
517
1089
  // runtime helper for setting properties on components
@@ -525,22 +1097,6 @@ exports.A = (sfc, props) => {
525
1097
  };
526
1098
 
527
1099
 
528
- /***/ }),
529
-
530
- /***/ 66328:
531
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
532
-
533
- /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(76314);
534
- /* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);
535
- // Imports
536
-
537
- var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()(function(i){return i[1]});
538
- // Module
539
- ___CSS_LOADER_EXPORT___.push([module.id, "\n.simple-filter-select[data-v-7e7a85c7] {\r\n width: 100%;\n}\n.option-content[data-v-7e7a85c7] {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n width: 100%;\r\n padding: 0 4px;\n}\n.option-text[data-v-7e7a85c7] {\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\n}\n.icon-class[data-v-7e7a85c7] {\r\n font-size: 14px;\r\n padding: 4px;\n}\n.icon-class[data-v-7e7a85c7]:hover {\r\n color: var(--kq-color-danger);\n}\n[data-v-7e7a85c7] .kq-option:hover .delete-btn {\r\n opacity: 1;\n}\n[data-v-7e7a85c7] .custom-select-popper {\r\n --kq-select-dropdown-item-padding: 4px 8px;\n}\n[data-v-7e7a85c7] .kq-option {\r\n padding: 0 !important;\n}\r\n", ""]);
540
- // Exports
541
- /* harmony default export */ __webpack_exports__.A = (___CSS_LOADER_EXPORT___);
542
-
543
-
544
1100
  /***/ }),
545
1101
 
546
1102
  /***/ 67434:
@@ -596,6 +1152,58 @@ _KqGIS.kq_npm_client_common_vue.KqMessage = _indexFull.ElMessage;
596
1152
 
597
1153
  /***/ }),
598
1154
 
1155
+ /***/ 74317:
1156
+ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1157
+
1158
+ // ESM COMPAT FLAG
1159
+ __webpack_require__.r(__webpack_exports__);
1160
+
1161
+ // EXPORTS
1162
+ __webpack_require__.d(__webpack_exports__, {
1163
+ __esModule: function() { return /* reexport */ filterConditionSelectvue_type_script_setup_true_lang_js/* __esModule */.B; },
1164
+ "default": function() { return /* binding */ filterConditionSelect; }
1165
+ });
1166
+
1167
+ // EXTERNAL MODULE: ./node_modules/babel-loader/lib/index.js??clonedRuleSet-1.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=script&setup=true&lang=js
1168
+ var filterConditionSelectvue_type_script_setup_true_lang_js = __webpack_require__(10993);
1169
+ ;// ./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=script&setup=true&lang=js
1170
+
1171
+ // EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js
1172
+ var injectStylesIntoStyleTag = __webpack_require__(85072);
1173
+ var injectStylesIntoStyleTag_default = /*#__PURE__*/__webpack_require__.n(injectStylesIntoStyleTag);
1174
+ // EXTERNAL MODULE: ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=style&index=0&id=011f2cca&scoped=true&lang=css
1175
+ var filterConditionSelectvue_type_style_index_0_id_011f2cca_scoped_true_lang_css = __webpack_require__(1006);
1176
+ ;// ./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=style&index=0&id=011f2cca&scoped=true&lang=css
1177
+
1178
+
1179
+
1180
+ var options = {};
1181
+
1182
+ options.insert = "head";
1183
+ options.singleton = false;
1184
+
1185
+ var update = injectStylesIntoStyleTag_default()(filterConditionSelectvue_type_style_index_0_id_011f2cca_scoped_true_lang_css/* default */.A, options);
1186
+
1187
+
1188
+
1189
+ /* harmony default export */ var buildpointmodel_filterConditionSelectvue_type_style_index_0_id_011f2cca_scoped_true_lang_css = (filterConditionSelectvue_type_style_index_0_id_011f2cca_scoped_true_lang_css/* default */.A.locals || {});
1190
+ ;// ./src/webgl/buildpointmodel/filterConditionSelect.vue?vue&type=style&index=0&id=011f2cca&scoped=true&lang=css
1191
+
1192
+ // EXTERNAL MODULE: ./node_modules/vue-loader/dist/exportHelper.js
1193
+ var exportHelper = __webpack_require__(66262);
1194
+ ;// ./src/webgl/buildpointmodel/filterConditionSelect.vue
1195
+
1196
+
1197
+
1198
+ ;
1199
+
1200
+
1201
+ const __exports__ = /*#__PURE__*/(0,exportHelper/* default */.A)(filterConditionSelectvue_type_script_setup_true_lang_js/* default */.A, [['__scopeId',"data-v-011f2cca"]])
1202
+
1203
+ /* harmony default export */ var filterConditionSelect = (__exports__);
1204
+
1205
+ /***/ }),
1206
+
599
1207
  /***/ 74844:
600
1208
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
601
1209
 
@@ -610,8 +1218,11 @@ var _util = __webpack_require__(42975);
610
1218
  var _message = _interopRequireDefault(__webpack_require__(71323));
611
1219
  var _useGlobalConfig = __webpack_require__(22686);
612
1220
  var _BuildPointModelUtil = _interopRequireWildcard(__webpack_require__(46312));
1221
+ var _BSPOperationUtil = _interopRequireDefault(__webpack_require__(39745));
1222
+ var _vue = __webpack_require__(50154);
613
1223
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
614
1224
  class BuildPointModelViewModel {
1225
+ // { templateIndex: [PMBSPPrimitive] }
615
1226
  /**
616
1227
  * 构造函数
617
1228
  * @param {Cesium.SceneView} sceneView - Cesium 场景视图实例
@@ -620,17 +1231,39 @@ class BuildPointModelViewModel {
620
1231
  constructor(sceneView, formItem) {
621
1232
  // 私有属性:恢复_前缀命名规范
622
1233
  this._options = {};
1234
+ // 表单配置项(与视图层 formItem 双向同步)
623
1235
  this._sceneView = null;
1236
+ // Cesium 场景视图实例
624
1237
  this._layerData = null;
1238
+ // 当前图层 GeoJSON 数据
625
1239
  this._pointModel = null;
1240
+ // 当前编辑中的点模型实例
626
1241
  this._pointModels = [];
1242
+ // 生成的点模型 JSON 列表
627
1243
  this._currentItem = null;
1244
+ // 当前选中的动态符号项
628
1245
  this._currentItemGeometry = {
629
1246
  value: "PMCube",
630
1247
  name: "立方体"
631
1248
  };
1249
+ // 当前选中的几何符号项
632
1250
  this._language = null;
1251
+ // 国际化语言资源
633
1252
  this._customAxis = null;
1253
+ // 自定义坐标轴实例(编辑模式)
1254
+ this._groupShapes = [];
1255
+ // 简单几何与模板模型列表(组合基础/运算对象来源)
1256
+ this._previewBspResults = [];
1257
+ // 预览态 BSP 结果(临时)
1258
+ this._confirmedBspResults = {};
1259
+ // 已确认 BSP 结果(keyed by id)
1260
+ this._previewComplexModels = [];
1261
+ // 最终复杂模型预览(PMBSPPrimitive 实例)
1262
+ this._drawManager = null;
1263
+ // 绘制管理器实例
1264
+ this._selectedTemplateIndices = new Set();
1265
+ // 当前选中的模板索引集合(支持多选)
1266
+ this._selectedTemplateModelsMap = new Map();
634
1267
  this._sceneView = sceneView;
635
1268
  this._options = formItem;
636
1269
  this._sceneView._viewer.scene.globe.depthTestAgainstTerrain = true;
@@ -638,6 +1271,65 @@ class BuildPointModelViewModel {
638
1271
  locale
639
1272
  } = (0, _useGlobalConfig.useLocale)();
640
1273
  this._language = locale;
1274
+ this._drawManager = sceneView._drawManager;
1275
+ // let that = this;
1276
+ // this._drawManager.startDraw("marker", { image: null }, (feature, { shape }) => {
1277
+ // if (!shape.groupName || shape.groupName !== "BuildPointModelDraw") return;
1278
+ // that._drawManager.clearDrawGroup("BuildPointModelDraw");
1279
+ // const screenPosition = that._sceneView._viewer.scene.cartesianToCanvasCoordinates(shape._position);
1280
+ // if (Cesium.defined(screenPosition)) {
1281
+ // let pickedObject = that._sceneView._viewer.scene.pick(screenPosition);
1282
+ // console.log(pickedObject);
1283
+ // }
1284
+ // },"BuildPointModelDraw")
1285
+ }
1286
+
1287
+ /**
1288
+ * 获取校验后的 features(聚合数据校验/过滤/处理逻辑)
1289
+ * @returns {Array|null} features 数组,校验失败返回 null
1290
+ */
1291
+ _getValidatedFeatures() {
1292
+ if (!this._layerData) {
1293
+ (0, _message.default)({
1294
+ message: this._language.value.webgl.noGeoJSONData,
1295
+ type: "warning"
1296
+ });
1297
+ return null;
1298
+ }
1299
+ const filteredData = _BuildPointModelUtil.default.filterGeoJSONData(this._layerData, this._options.selectModelId);
1300
+ const features = _BuildPointModelUtil.default.processGeoJSON(filteredData);
1301
+ if (!features?.length) {
1302
+ (0, _message.default)({
1303
+ message: this._language.value.webgl.noGeoJSONData,
1304
+ type: "warning"
1305
+ });
1306
+ return null;
1307
+ }
1308
+ return features;
1309
+ }
1310
+
1311
+ /**
1312
+ * @description 安全回调调用
1313
+ * @param {Function} cb 回调函数
1314
+ * @param {...*} args 透传给回调的参数
1315
+ */
1316
+ _safeCallback(cb, ...args) {
1317
+ typeof cb === "function" && cb(...args);
1318
+ }
1319
+
1320
+ /**
1321
+ * 获取简化后的 groupShapes 数据(仅含 value/name/icon)
1322
+ * @returns {Array}
1323
+ */
1324
+ _getSimplifiedGroupShapes() {
1325
+ return this._groupShapes.map(item => ({
1326
+ value: item.value,
1327
+ name: item.name,
1328
+ // 模板加载的运算模型在下拉列表中只显示名称,不显示图标
1329
+ icon: item._isTemplate ? null : item.icon,
1330
+ // 标记来源:模板加载的项用于保存按钮禁用判断
1331
+ _isTemplate: !!item._isTemplate
1332
+ }));
641
1333
  }
642
1334
 
643
1335
  /**
@@ -663,24 +1355,9 @@ class BuildPointModelViewModel {
663
1355
  */
664
1356
  generated(type, cb) {
665
1357
  this._pointModels = [];
666
- if (!this._layerData) {
667
- (0, _message.default)({
668
- message: this._language.value.webgl.noGeoJSONData,
669
- type: "warning"
670
- });
671
- return;
672
- }
1358
+ const features = this._getValidatedFeatures();
1359
+ if (!features) return;
673
1360
  try {
674
- // 复用工具类方法,简化主逻辑
675
- const filteredData = _BuildPointModelUtil.default.filterGeoJSONData(this._layerData, this._options.selectModelId);
676
- const features = _BuildPointModelUtil.default.processGeoJSON(filteredData);
677
- if (!features?.length) {
678
- (0, _message.default)({
679
- message: this._language.value.webgl.noGeoJSONData,
680
- type: "warning"
681
- });
682
- return;
683
- }
684
1361
  features.forEach((feature, index) => {
685
1362
  const {
686
1363
  geometry,
@@ -695,12 +1372,454 @@ class BuildPointModelViewModel {
695
1372
  this._pointModels.push(point3D.toJSON());
696
1373
  }
697
1374
  });
698
- typeof cb === "function" && cb(this._pointModels);
1375
+ this._safeCallback(cb, this._pointModels);
1376
+ } catch (error) {
1377
+ console.error("处理GeoJSON数据生成模型失败:", error);
1378
+ this._safeCallback(cb, null, error);
1379
+ }
1380
+ }
1381
+ /**
1382
+ * 生成3D点模型(加载文件)
1383
+ * @param {Function} [cb] - 回调函数,返回生成的模型列表或错误信息
1384
+ */
1385
+ generated_loadFiles(cb) {
1386
+ const features = this._getValidatedFeatures();
1387
+ if (!features) return;
1388
+ try {
1389
+ const pointModels = [];
1390
+ const featurePositions = [];
1391
+ const pointModelConfigs = [];
1392
+ features.forEach((feature, index) => {
1393
+ const {
1394
+ geometry,
1395
+ properties
1396
+ } = feature;
1397
+ if (!geometry?.coordinates) return;
1398
+ const position = _BuildPointModelUtil.default.extractPosition(geometry.coordinates);
1399
+ featurePositions.push({
1400
+ ...position
1401
+ });
1402
+ const modelConfig = this._generateModelConfig(_BuildPointModelUtil.MODEL_TYPES.GEOMETRY, feature, position, index);
1403
+ if (modelConfig) {
1404
+ const point3D = this._createModelInstance(_BuildPointModelUtil.MODEL_TYPES.GEOMETRY, modelConfig);
1405
+ this._sceneView._viewer.scene.primitives.add(point3D);
1406
+ point3D.show = this._options?.showOperationModel ?? true;
1407
+ pointModels.push(point3D);
1408
+ // 存储原始 config,用于后续组合列表创建独立模型(保持与模板逻辑一致)
1409
+ pointModelConfigs.push(modelConfig);
1410
+ }
1411
+ });
1412
+ this._groupShapes.push({
1413
+ ...this._currentItemGeometry,
1414
+ pointModels: pointModels,
1415
+ _featurePositions: featurePositions,
1416
+ _pointModelConfigs: pointModelConfigs
1417
+ });
1418
+ this._safeCallback(cb, this._getSimplifiedGroupShapes());
699
1419
  } catch (error) {
700
1420
  console.error("处理GeoJSON数据生成模型失败:", error);
701
- typeof cb === "function" && cb(null, error);
1421
+ this._safeCallback(cb, null, error);
1422
+ }
1423
+ }
1424
+
1425
+ /**
1426
+ * 相机定位到数据点坐标(高度 500m,使用 setView 瞬间定位)
1427
+ */
1428
+ _zoomToDataPoint() {
1429
+ const features = this._getValidatedFeatures();
1430
+ if (!features?.length) return;
1431
+ const firstFeature = features[0];
1432
+ if (!firstFeature?.geometry?.coordinates) return;
1433
+ const position = _BuildPointModelUtil.default.extractPosition(firstFeature.geometry.coordinates);
1434
+ const viewer = this._sceneView?._viewer;
1435
+ if (!viewer) return;
1436
+ viewer.scene.camera.setView({
1437
+ destination: Cesium.Cartesian3.fromDegrees(position.x, position.y, 500),
1438
+ orientation: {
1439
+ heading: Cesium.Math.toRadians(0.0),
1440
+ roll: Cesium.Math.toRadians(0.0)
1441
+ }
1442
+ });
1443
+ }
1444
+
1445
+ /**
1446
+ * 通过 key(value)查找模型数据
1447
+ * @param {string} key - 模型标识(_groupShapes 的 value 或 _confirmedBspResults 的 id)
1448
+ * @returns {{ pointModels: Array, isBsp: boolean, bspItems: Array }|null}
1449
+ */
1450
+ _getModelsByKey(key) {
1451
+ // 先查 _groupShapes(简单几何模型)
1452
+ const shape = this._groupShapes.find(item => item.value === key);
1453
+ if (shape) {
1454
+ return {
1455
+ pointModels: shape.pointModels,
1456
+ isBsp: false,
1457
+ bspItems: null,
1458
+ featurePositions: shape._featurePositions,
1459
+ pointModelConfigs: shape._pointModelConfigs
1460
+ };
1461
+ }
1462
+ // 再查 _confirmedBspResults(已确认 BSP 组合)
1463
+ const bspItems = this._confirmedBspResults[key];
1464
+ if (bspItems?.length) {
1465
+ return {
1466
+ pointModels: null,
1467
+ isBsp: true,
1468
+ bspItems
1469
+ };
1470
+ }
1471
+ return null;
1472
+ }
1473
+
1474
+ /**
1475
+ * 生成/预览 BSP 运算模型
1476
+ * @param {Object} operationObj - { baseModel, operationModel, operationMethod }
1477
+ * @param {boolean} isPreview - 是否预览模式(true 存入 _previewBspResults,false 存入 _confirmedBspResults)
1478
+ * @param {string} [confirmId] - 确认时传入的组合 ID
1479
+ * @returns {Array} 生成的 BSP 结果列表
1480
+ */
1481
+ _operationModels(operationObj, isPreview = true, confirmId = null) {
1482
+ // 先清除之前的预览
1483
+ if (isPreview) {
1484
+ this._clearPreviewBsp();
1485
+ }
1486
+ if (!operationObj?.baseModel) return [];
1487
+ const {
1488
+ baseModel,
1489
+ operationModel,
1490
+ operationMethod = 0
1491
+ } = operationObj;
1492
+
1493
+ // 通过 key 查找基础模型数据
1494
+ const baseModelData = this._getModelsByKey(baseModel.value);
1495
+ const baseModels = baseModelData?.pointModels || baseModelData?.bspItems;
1496
+ if (!baseModels?.length) return [];
1497
+ const results = [];
1498
+ if (operationModel) {
1499
+ // 复杂组合:BSP 布尔运算
1500
+ const operationModelData = this._getModelsByKey(operationModel.value);
1501
+ const operationModels = operationModelData?.pointModels || operationModelData?.bspItems;
1502
+ if (!operationModels?.length) return [];
1503
+ const loopLength = Math.min(baseModels.length, operationModels.length);
1504
+ if (loopLength === 0) return [];
1505
+ const ZERO_CARTESIAN = Cesium.Cartesian3.ZERO;
1506
+ const BLUE_COLOR = Cesium.Color.BLUE;
1507
+ for (let i = 0; i < loopLength; i++) {
1508
+ const rawBase = baseModels[i];
1509
+ const rawOperate = operationModels[i];
1510
+ if (!rawBase || !rawOperate) continue;
1511
+
1512
+ // 获取基础模型的位置信息(优先使用 feature 原始坐标)
1513
+ let x, y, z;
1514
+ if (baseModelData?.featurePositions?.[i]) {
1515
+ // 来自 _groupShapes:使用 feature 原始坐标
1516
+ ({
1517
+ x,
1518
+ y,
1519
+ z
1520
+ } = baseModelData.featurePositions[i]);
1521
+ } else if (rawBase._centerDegrees) {
1522
+ // 来自 _confirmedBspResults:使用已存储的 _centerDegrees
1523
+ ({
1524
+ x,
1525
+ y,
1526
+ z
1527
+ } = rawBase._centerDegrees);
1528
+ } else {
1529
+ // 回退:使用模型 toJSON 位置
1530
+ const rawBaseJson = rawBase?.toJSON?.();
1531
+ ({
1532
+ x,
1533
+ y,
1534
+ z
1535
+ } = rawBaseJson?.geometry?.position ?? {
1536
+ x: 0,
1537
+ y: 0,
1538
+ z: 0
1539
+ });
1540
+ }
1541
+ const centerPos = Cesium.Cartesian3.fromDegrees(x, y, z);
1542
+ console.log('[Z-OFFSET-DEBUG] _operationModels 复杂组合 - BSPUtility中心:', {
1543
+ degrees: {
1544
+ x,
1545
+ y,
1546
+ z
1547
+ },
1548
+ ecef: {
1549
+ x: centerPos.x,
1550
+ y: centerPos.y,
1551
+ z: centerPos.z
1552
+ },
1553
+ source: baseModelData?.featurePositions?.[i] ? 'featurePositions' : rawBase._centerDegrees ? '_centerDegrees' : 'modelToJSON',
1554
+ modelKey: rawBase?.toJSON?.()?.key || rawBase?.key
1555
+ });
1556
+ const bspUtility = new Cesium.PMKq3dBSPUtility(this._sceneView._viewer, centerPos);
1557
+
1558
+ // 将基础模型转换为 BSP
1559
+ const bspA = _BSPOperationUtil.default.convertModelToBSP(rawBase, bspUtility);
1560
+ if (!bspA) continue;
1561
+
1562
+ // 获取运算模型的 BSP
1563
+ const bspB = _BSPOperationUtil.default.getBSPModel(operationModelData, rawOperate, bspUtility);
1564
+ if (!bspB) continue;
1565
+ const bspResult = bspUtility.computeBSP(bspA, bspB, operationMethod);
1566
+ const distForMove = Cesium.Cartesian3.multiplyByScalar(ZERO_CARTESIAN, 4.0, new Cesium.Cartesian3());
1567
+
1568
+ // 记录 addToScene 前的 primitives 数量,以便追踪新添加的 primitive
1569
+ const primitivesBefore = this._sceneView._viewer.scene.primitives.length;
1570
+ bspUtility.addToScene(bspResult, distForMove, BLUE_COLOR);
1571
+ const primitivesAfter = this._sceneView._viewer.scene.primitives.length;
1572
+ const addedPrimitives = [];
1573
+ for (let p = primitivesBefore; p < primitivesAfter; p++) {
1574
+ addedPrimitives.push(this._sceneView._viewer.scene.primitives.get(p));
1575
+ }
1576
+ const resultItem = {
1577
+ key: rawBase?.toJSON?.()?.key || rawBase?.key || (0, _util.guid)(),
1578
+ base: rawBase,
1579
+ operate: rawOperate,
1580
+ bspResult,
1581
+ bspUtility,
1582
+ bspA,
1583
+ bspB,
1584
+ operationMethod,
1585
+ isSimple: false,
1586
+ _centerDegrees: {
1587
+ x,
1588
+ y,
1589
+ z
1590
+ },
1591
+ _addedPrimitives: addedPrimitives,
1592
+ _visible: true
1593
+ };
1594
+ if (isPreview) {
1595
+ this._previewBspResults.push(resultItem);
1596
+ } else if (confirmId) {
1597
+ if (!this._confirmedBspResults[confirmId]) {
1598
+ this._confirmedBspResults[confirmId] = [];
1599
+ }
1600
+ this._confirmedBspResults[confirmId].push(resultItem);
1601
+ }
1602
+ results.push(resultItem);
1603
+ }
1604
+ } else {
1605
+ // 简单组合:仅基础模型,不进行 BSP 运算
1606
+ // 关键修复:基于原始 config 创建独立模型,避免直接引用模板/简单几何原模型
1607
+ // 不能用 toJSON 克隆:PMBSPPrimitive 的 toJSON 不含 bspGeometry,会导致 getBSPes/save 失败
1608
+ const featurePositions = baseModelData?.featurePositions;
1609
+ const baseConfigs = baseModelData?.pointModelConfigs;
1610
+ baseModels.forEach((model, i) => {
1611
+ // 使用 feature 原始坐标(featurePositions),回退到模型 toJSON 位置
1612
+ const modelJson = model?.toJSON?.();
1613
+ const pos = featurePositions?.[i] || modelJson?.geometry?.position;
1614
+ const {
1615
+ x,
1616
+ y,
1617
+ z
1618
+ } = pos ?? {
1619
+ x: 0,
1620
+ y: 0,
1621
+ z: 0
1622
+ };
1623
+ const centerPos = Cesium.Cartesian3.fromDegrees(x, y, z);
1624
+ console.log('[Z-OFFSET-DEBUG] _operationModels 简单组合 - BSPUtility中心:', {
1625
+ degrees: {
1626
+ x,
1627
+ y,
1628
+ z
1629
+ },
1630
+ ecef: {
1631
+ x: centerPos.x,
1632
+ y: centerPos.y,
1633
+ z: centerPos.z
1634
+ },
1635
+ source: featurePositions?.[i] ? 'featurePositions' : 'modelToJSON',
1636
+ modelKey: modelJson?.key,
1637
+ featureIndex: i
1638
+ });
1639
+ const bspUtility = new Cesium.PMKq3dBSPUtility(this._sceneView._viewer, centerPos);
1640
+
1641
+ // 基于原始 config 深拷贝创建独立模型,保留完整的 bspGeometry 等数据
1642
+ let independentModel = null;
1643
+ const addedPrimitives = [];
1644
+ // 预存 bspGeometry:PMBSPPrimitive 的 config 中包含 bspGeometry,
1645
+ // 单个简单组合预览/生成时可直接使用,跳过 getBSPes+save(save 不接受 getBSPes 的原始结果)
1646
+ let savedBspGeometry = null;
1647
+ if (baseConfigs?.[i]) {
1648
+ try {
1649
+ const config = JSON.parse(JSON.stringify(baseConfigs[i]));
1650
+ const newKey = (0, _util.guid)();
1651
+ config.key = newKey;
1652
+ if (config.featureID !== undefined) config.featureID = newKey;
1653
+ // 提取预存 bspGeometry(PMBSPPrimitive 才有)
1654
+ savedBspGeometry = config.geometry?.bspGeometry || null;
1655
+ // 用原模型的 constructor 创建同类型实例(PMBSPPrimitive/PMCube 等)
1656
+ const Constructor = model.constructor;
1657
+ if (Constructor) {
1658
+ independentModel = new Constructor(config);
1659
+ this._sceneView._viewer.scene.primitives.add(independentModel);
1660
+ addedPrimitives.push(independentModel);
1661
+ }
1662
+ } catch (e) {
1663
+ console.error('[BuildPointModelViewModel] 基于config创建独立模型失败:', e);
1664
+ }
1665
+ }
1666
+ const resultItem = {
1667
+ key: independentModel?._key || modelJson?.key || (0, _util.guid)(),
1668
+ base: independentModel || model,
1669
+ // 创建失败时回退到原模型引用
1670
+ operate: null,
1671
+ bspResult: null,
1672
+ bspUtility: bspUtility,
1673
+ bspA: null,
1674
+ bspB: null,
1675
+ operationMethod: 0,
1676
+ isSimple: true,
1677
+ _centerDegrees: {
1678
+ x,
1679
+ y,
1680
+ z
1681
+ },
1682
+ _addedPrimitives: addedPrimitives,
1683
+ _visible: true,
1684
+ savedBspGeometry: savedBspGeometry
1685
+ };
1686
+ if (isPreview) {
1687
+ this._previewBspResults.push(resultItem);
1688
+ } else if (confirmId) {
1689
+ if (!this._confirmedBspResults[confirmId]) {
1690
+ this._confirmedBspResults[confirmId] = [];
1691
+ }
1692
+ this._confirmedBspResults[confirmId].push(resultItem);
1693
+ }
1694
+ results.push(resultItem);
1695
+ });
1696
+ }
1697
+ return results;
1698
+ }
1699
+
1700
+ /**
1701
+ * 确认组合:将预览结果转为已确认(若无预览则重新生成)
1702
+ * @param {Object} operationObj - 组合操作对象
1703
+ * @param {string} confirmId - 组合唯一 ID
1704
+ */
1705
+ _confirmOperationModel(operationObj, confirmId) {
1706
+ if (this._previewBspResults.length) {
1707
+ // 已有预览,直接移入已确认
1708
+ if (!this._confirmedBspResults[confirmId]) {
1709
+ this._confirmedBspResults[confirmId] = [];
1710
+ }
1711
+ this._confirmedBspResults[confirmId].push(...this._previewBspResults);
1712
+ this._previewBspResults = [];
1713
+ } else {
1714
+ // 无预览,重新生成
1715
+ this._operationModels(operationObj, false, confirmId);
1716
+ }
1717
+ }
1718
+
1719
+ /**
1720
+ * 清除预览 BSP 模型(从场景中移除)
1721
+ */
1722
+ _clearPreviewBsp() {
1723
+ const primitives = this._sceneView?._viewer?.scene?.primitives;
1724
+ this._previewBspResults.forEach(item => {
1725
+ // 移除新增的 primitive(简单组合的克隆模型、复杂组合的 BSP 结果)
1726
+ item._addedPrimitives?.forEach(p => primitives?.remove(p));
1727
+ if (item.bspUtility) {
1728
+ item.bspUtility?.destroy?.();
1729
+ }
1730
+ });
1731
+ this._previewBspResults = [];
1732
+ }
1733
+
1734
+ /**
1735
+ * 删除指定组合的已确认 BSP 模型
1736
+ * @param {string} confirmId - 组合 ID
1737
+ */
1738
+ _removeConfirmedBsp(confirmId) {
1739
+ const items = this._confirmedBspResults[confirmId];
1740
+ if (items?.length) {
1741
+ const primitives = this._sceneView?._viewer?.scene?.primitives;
1742
+ items.forEach(item => {
1743
+ // 移除该组合新增的 primitive(简单组合的克隆模型等)
1744
+ item._addedPrimitives?.forEach(p => primitives?.remove(p));
1745
+ item.bspUtility?.destroy?.();
1746
+ });
1747
+ delete this._confirmedBspResults[confirmId];
702
1748
  }
703
1749
  }
1750
+ /**
1751
+ * @description 通用:处理组内模型(移除 / 显隐)
1752
+ * @param {string} action 操作类型('remove' 移除 / 'show' 显隐)
1753
+ * @param {boolean} [val=false] 显隐值(action='show' 时生效)
1754
+ */
1755
+ _handleGroupShapes(action, val = false) {
1756
+ if (!this._groupShapes?.length) return;
1757
+ const primitives = this._sceneView?._viewer?.scene?.primitives;
1758
+ this._groupShapes.forEach(el => {
1759
+ el.pointModels?.forEach(item => {
1760
+ // 根据动作执行不同逻辑
1761
+ action === 'remove' ? primitives?.remove(item) : item.show = val;
1762
+ });
1763
+ });
1764
+
1765
+ // 清空逻辑只在移除时执行
1766
+ if (action === 'remove') this._groupShapes = [];
1767
+ }
1768
+
1769
+ /**
1770
+ * @description 清空简单几何模型(仅清除 _groupShapes,不影响组合列表和已确认 BSP)
1771
+ * @param {Function} cb 回调函数,返回简化后的组合列表
1772
+ */
1773
+ clearSimpleGeometryModels(cb) {
1774
+ this._handleGroupShapes('remove');
1775
+ this._safeCallback(cb, this._getSimplifiedGroupShapes());
1776
+ }
1777
+
1778
+ /**
1779
+ * @description 清空组图形(包括简单几何模型和已确认 BSP 组合)
1780
+ * @param {Function} cb 回调函数,返回简化后的组合列表
1781
+ */
1782
+ clearGroupShapes(cb) {
1783
+ this._handleGroupShapes('remove');
1784
+ this._clearAllConfirmedBsp();
1785
+ this._safeCallback(cb, this._getSimplifiedGroupShapes());
1786
+ }
1787
+
1788
+ /**
1789
+ * @description 显示/隐藏组图形
1790
+ * @param {boolean} val 是否可见
1791
+ * @param {Function} cb 回调函数,返回简化后的组合列表
1792
+ */
1793
+ showGroupShapes(val, cb) {
1794
+ this._options.showOperationModel = val;
1795
+ this._handleGroupShapes('show', val);
1796
+ this._safeCallback(cb, this._getSimplifiedGroupShapes());
1797
+ }
1798
+ /**
1799
+ * @description 设置编辑模型显隐状态
1800
+ * @param {boolean} val 是否显示编辑模型
1801
+ */
1802
+ showEditModel(val) {
1803
+ this._options.showEditModel = val;
1804
+ }
1805
+
1806
+ /**
1807
+ * 控制所有已确认 BSP 组合模型的显隐(预览/生成时隐藏,避免与最终模型重叠)
1808
+ * @param {boolean} visible - 是否可见
1809
+ */
1810
+ _setConfirmedBspVisible(visible) {
1811
+ Object.values(this._confirmedBspResults).forEach(items => {
1812
+ items?.forEach(item => {
1813
+ if (item.isSimple) {
1814
+ if (item.base) item.base.show = visible;
1815
+ } else {
1816
+ item._addedPrimitives?.forEach(p => {
1817
+ if (p && p.show !== undefined) p.show = visible;
1818
+ });
1819
+ }
1820
+ });
1821
+ });
1822
+ }
704
1823
 
705
1824
  /**
706
1825
  * 生成模型配置项
@@ -723,7 +1842,7 @@ class BuildPointModelViewModel {
723
1842
  params = this._generateDynamicModelParams(properties, position);
724
1843
  } else if (type === _BuildPointModelUtil.MODEL_TYPES.GEOMETRY) {
725
1844
  selectItem = this._currentItemGeometry;
726
- params = this._generateGeometryModelParams(properties, position);
1845
+ params = this._generateGeometryModelParams(selectItem.value, properties, position);
727
1846
  } else if (type === _BuildPointModelUtil.MODEL_TYPES.CUSTOM_POINT) {
728
1847
  selectItem = {
729
1848
  name: "自定义点符号"
@@ -734,10 +1853,12 @@ class BuildPointModelViewModel {
734
1853
  return null;
735
1854
  }
736
1855
  return {
1856
+ fieldNames: properties ? Object.keys(properties) : [],
1857
+ fieldValues: properties ? Object.values(properties) : [],
737
1858
  label: _BuildPointModelUtil.default.getStringValue(properties, this._options, "ofModelNameFields", "ofModelName", selectItem?.name || `point_label${index + 1}`),
738
1859
  rename: selectItem?.name || `point_label${index + 1}`,
739
1860
  key,
740
- type: "model",
1861
+ type: selectItem?.value || "model",
741
1862
  modelingType: type,
742
1863
  show: true,
743
1864
  featureID: key,
@@ -791,7 +1912,7 @@ class BuildPointModelViewModel {
791
1912
  return {
792
1913
  geometry: {
793
1914
  clampToGround: this._options.clampToGround ?? false,
794
- type: "CUSTOM_POINT3D",
1915
+ type: "POINT3D",
795
1916
  position,
796
1917
  rotate: this._options.rotate ?? false,
797
1918
  offset: {
@@ -812,15 +1933,16 @@ class BuildPointModelViewModel {
812
1933
  };
813
1934
  }
814
1935
  /**
815
- * 生成几何模型参数
1936
+ * @description 生成几何模型参数
816
1937
  * @private
817
- * @param {Object} properties - 要素属性
818
- * @param {Object} position - 位置坐标
1938
+ * @param {string} val 几何类型(PMCube/PMCylinder 等)
1939
+ * @param {Object} properties 要素属性
1940
+ * @param {Object} position 位置坐标
819
1941
  * @returns {Object} 几何模型参数
820
1942
  */
821
- _generateGeometryModelParams(properties, position) {
1943
+ _generateGeometryModelParams(val, properties, position) {
822
1944
  return {
823
- geometry: this.getGeometry(this._currentItemGeometry.value, position, properties),
1945
+ geometry: this.getGeometry(val, position, properties),
824
1946
  style: {
825
1947
  color: _BuildPointModelUtil.default.getStringValue(properties, this._options, "colorFields", "color", "#FFFFFF")
826
1948
  }
@@ -839,7 +1961,7 @@ class BuildPointModelViewModel {
839
1961
  const util = _BuildPointModelUtil.default;
840
1962
  const baseConfig = {
841
1963
  clampToGround: this._options.clampToGround ?? false,
842
- type: this._currentItemGeometry.value ?? "POINT3D",
1964
+ type: "POINT3D",
843
1965
  position,
844
1966
  rotate: this._options.rotate ?? false,
845
1967
  offset: {
@@ -980,45 +2102,310 @@ class BuildPointModelViewModel {
980
2102
  }
981
2103
 
982
2104
  /**
983
- * 模型参数变更处理
984
- * @param {string} key - 变更的参数键
985
- * @param {Object} mode - 操作模式(add/edit)
2105
+ * @description 构建复杂几何模型(共享方法:预览和最终生成共用)
2106
+ * @param {Array} features GeoJSON Feature 数组
2107
+ * @param {Array} groupShapes 组合列表 [{ id, operationMethod, ... }]
2108
+ * @param {string} type 模型类型
2109
+ * @param {boolean} isPreview 是否预览模式
2110
+ * @param {boolean} [addToScene=true] 是否将结果添加到场景
2111
+ * @returns {Array} 生成的 PMBSPPrimitive 配置数组
986
2112
  */
987
- paramsChanged(key, mode) {
988
- if (mode.value === "add") return;
989
- if (!this._pointModel) {
990
- (0, _message.default)({
991
- message: this._language.value.webgl.noEditModelData,
992
- type: "warning"
2113
+ _buildComplexModel(features, groupShapes, type, isPreview, addToScene = true) {
2114
+ const results = [];
2115
+
2116
+ // 按 feature 维度收集所有 BSP 结果和简单模型
2117
+ const featureModelMap = {}; // { featureIndex: [{ bspResult, isSimple, bspUtility }] }
2118
+ const featureUtilityMap = {};
2119
+ groupShapes.forEach(shape => {
2120
+ const items = this._confirmedBspResults[shape.id];
2121
+ if (items?.length) {
2122
+ items.forEach((item, featureIndex) => {
2123
+ if (!featureModelMap[featureIndex]) {
2124
+ featureModelMap[featureIndex] = [];
2125
+ }
2126
+ if (item.bspResult) {
2127
+ featureModelMap[featureIndex].push({
2128
+ model: item.bspResult,
2129
+ isSimple: false,
2130
+ bspUtility: item.bspUtility
2131
+ });
2132
+ featureUtilityMap[featureIndex] = item.bspUtility;
2133
+ } else if (item.isSimple && item.base) {
2134
+ featureModelMap[featureIndex].push({
2135
+ model: item.base,
2136
+ isSimple: true,
2137
+ bspUtility: item.bspUtility,
2138
+ savedBspGeometry: item.savedBspGeometry
2139
+ });
2140
+ if (!featureUtilityMap[featureIndex]) {
2141
+ featureUtilityMap[featureIndex] = item.bspUtility;
2142
+ }
2143
+ }
2144
+ });
2145
+ }
2146
+ });
2147
+ if (!Object.keys(featureModelMap).length) return results;
2148
+
2149
+ // 每个 feature 独立计算自己的 bspGeometry
2150
+ const featureIndices = Object.keys(featureModelMap).map(Number);
2151
+ const featureCount = Math.min(features.length, Math.max(...featureIndices) + 1);
2152
+ for (let fi = 0; fi < featureCount; fi++) {
2153
+ const feature = features[fi];
2154
+ if (!feature) continue;
2155
+ const models = featureModelMap[fi];
2156
+ const bspUtility = featureUtilityMap[fi];
2157
+ if (!models?.length || !bspUtility) continue;
2158
+ console.log('[Z-OFFSET-DEBUG] _buildComplexModel - featureIndex:', fi, {
2159
+ bspUtilityCenter: bspUtility._center ? {
2160
+ x: bspUtility._center.x,
2161
+ y: bspUtility._center.y,
2162
+ z: bspUtility._center.z
2163
+ } : bspUtility.center ? {
2164
+ x: bspUtility.center.x,
2165
+ y: bspUtility.center.y,
2166
+ z: bspUtility.center.z
2167
+ } : 'unknown',
2168
+ featurePosition: feature?.geometry?.coordinates,
2169
+ modelsCount: models.length,
2170
+ modelsDetail: models.map(m => ({
2171
+ isSimple: m.isSimple,
2172
+ hasBspResult: !!m.bspResult
2173
+ }))
993
2174
  });
994
- return;
2175
+ let finalResult = null;
2176
+ // 单个简单组合且有预存 bspGeometry 时,直接使用,跳过 getBSPes+save
2177
+ // 原因:bspUtility.save 不接受 getBSPes 的原始结果(缺少运算后的内部状态)
2178
+ let directBspGeometry = null;
2179
+ for (let i = 0; i < models.length; i++) {
2180
+ const {
2181
+ model,
2182
+ isSimple,
2183
+ savedBspGeometry
2184
+ } = models[i];
2185
+ // 单个简单组合 + 预存 bspGeometry:直接使用,不走 getBSPes+save
2186
+ if (isSimple && savedBspGeometry && models.length === 1) {
2187
+ directBspGeometry = savedBspGeometry;
2188
+ break;
2189
+ }
2190
+ let currentBsp = isSimple ? _BSPOperationUtil.default.convertModelToBSP(model, bspUtility) : model;
2191
+ if (!currentBsp) continue;
2192
+ finalResult = !finalResult ? currentBsp : bspUtility.computeBSP(finalResult, currentBsp, 1);
2193
+ }
2194
+
2195
+ // 优先使用直接提取的 bspGeometry(单个简单组合),否则通过 save 序列化运算结果
2196
+ let bspGeometry;
2197
+ if (directBspGeometry) {
2198
+ bspGeometry = directBspGeometry;
2199
+ } else {
2200
+ if (!finalResult) continue;
2201
+ bspGeometry = _BSPOperationUtil.default.saveBSPResult(bspUtility, finalResult);
2202
+ }
2203
+ if (!bspGeometry) continue;
2204
+ const config = this._buildPMBSPConfig(feature, bspGeometry, type);
2205
+ if (!config) continue;
2206
+ if (addToScene) {
2207
+ const bspPrimitive = new Cesium.PMBSPPrimitive(config);
2208
+ this._sceneView._viewer.scene.primitives.add(bspPrimitive);
2209
+ if (isPreview) {
2210
+ this._previewComplexModels.push(bspPrimitive);
2211
+ }
2212
+ }
2213
+ results.push(config);
995
2214
  }
996
- const paramUpdater = {
2215
+ return results;
2216
+ }
2217
+
2218
+ /**
2219
+ * 构建 PMBSPPrimitive 配置对象
2220
+ * @param {Object} feature - GeoJSON Feature
2221
+ * @param {Object} bspGeometry - BSP 几何数据
2222
+ * @param {string} type - 模型类型
2223
+ * @returns {Object} PMBSPPrimitive 配置
2224
+ */
2225
+ _buildPMBSPConfig(feature, bspGeometry, type) {
2226
+ const {
2227
+ geometry,
2228
+ properties
2229
+ } = feature;
2230
+ if (!geometry?.coordinates) return null;
2231
+ const position = _BuildPointModelUtil.default.extractPosition(geometry.coordinates);
2232
+ const key = properties?.key || (0, _util.guid)();
2233
+ const fieldNames = properties ? Object.keys(properties) : [];
2234
+ const fieldValues = properties ? Object.values(properties) : [];
2235
+ console.log('[Z-OFFSET-DEBUG] _buildPMBSPConfig - PMBSPPrimitive配置:', {
2236
+ position: {
2237
+ x: position.x,
2238
+ y: position.y,
2239
+ z: position.z
2240
+ },
2241
+ featureCoordinates: geometry?.coordinates,
2242
+ bspGeometryType: typeof bspGeometry,
2243
+ bspGeometryHasPolygons: !!bspGeometry?.polygons
2244
+ });
2245
+ return {
2246
+ fieldNames,
2247
+ fieldValues,
2248
+ label: _BuildPointModelUtil.default.getStringValue(properties, this._options, "ofModelNameFields", "ofModelName", `PMBSPPrimitive_label`),
2249
+ rename: properties?.name || `PMBSPPrimitive_label`,
2250
+ key,
2251
+ type: "PMBSPPrimitive",
2252
+ modelingType: type,
2253
+ show: true,
2254
+ featureID: key,
2255
+ geometry: {
2256
+ clampToGround: this._options.clampToGround ?? false,
2257
+ type: "POINT3D",
2258
+ position: {
2259
+ x: position.x,
2260
+ y: position.y,
2261
+ z: position.z
2262
+ },
2263
+ offset: {
2264
+ x: this._options.offsetX ?? 0,
2265
+ y: this._options.offsetY ?? 0,
2266
+ z: this._options.offsetZ ?? 0
2267
+ },
2268
+ heading: this._options.heading ?? 0,
2269
+ pitch: this._options.pitch ?? 0,
2270
+ roll: this._options.roll ?? 0,
2271
+ bspGeometry: bspGeometry
2272
+ },
2273
+ style: {
2274
+ color: this._options.color || "rgb(255,255,255)"
2275
+ }
2276
+ };
2277
+ }
2278
+
2279
+ /**
2280
+ * 预览最终复杂几何模型(将组合列表融合生成预览到场景)
2281
+ * @param {Array} groupShapes - 组合列表
2282
+ * @param {string} type - 模型类型
2283
+ */
2284
+ _previewComplexModel(groupShapes, type) {
2285
+ this._clearComplexPreview();
2286
+ const allFeatures = this._getValidatedFeatures();
2287
+ if (!allFeatures) return;
2288
+ try {
2289
+ this._buildComplexModel(allFeatures, groupShapes, type, true);
2290
+ } catch (error) {
2291
+ console.error("预览复杂几何模型失败:", error);
2292
+ }
2293
+ }
2294
+
2295
+ /**
2296
+ * 清除预览的最终复杂模型
2297
+ */
2298
+ _clearComplexPreview() {
2299
+ const primitives = this._sceneView?._viewer?.scene?.primitives;
2300
+ this._previewComplexModels.forEach(model => {
2301
+ primitives?.remove(model);
2302
+ });
2303
+ this._previewComplexModels = [];
2304
+ }
2305
+
2306
+ /**
2307
+ * 生成复杂几何符号最终结果
2308
+ * 若已预览则直接获取预览结果,否则先构建复杂模型
2309
+ * @param {Array} groupShapes - 组合列表 [{ id, operationMethod, ... }]
2310
+ * @param {string} type - 模型类型
2311
+ * @param {Function} [cb] - 回调函数
2312
+ */
2313
+ _generateComplexGeometry(groupShapes, type, cb) {
2314
+ this._pointModels = [];
2315
+ const features = this._getValidatedFeatures();
2316
+ if (!features) return;
2317
+ try {
2318
+ // 清除预览(预览只有 1 个模型,不能复用;生成时需处理所有 feature)
2319
+ this._clearComplexPreview();
2320
+ const results = this._buildComplexModel(features, groupShapes, type, false);
2321
+ if (results?.length) {
2322
+ this._pointModels.push(...results);
2323
+ }
2324
+ this._safeCallback(cb, this._pointModels);
2325
+ } catch (error) {
2326
+ console.error("处理复杂几何生成失败:", error);
2327
+ this._safeCallback(cb, null, error);
2328
+ }
2329
+ }
2330
+
2331
+ /**
2332
+ * 模型参数变更处理
2333
+ * @param {string} key - 变更的参数键
2334
+ * @param {Object} mode - 操作模式(add/edit)
2335
+ */
2336
+ paramsChanged(key, mode) {
2337
+ // 编辑模式下允许更新 _groupShapes 中的模型,不受 mode 限制
2338
+ if (mode.value === "add" && !this._options.showEditModel) return;
2339
+
2340
+ // mode=add 下,朝向角/俯仰角/翻转角仅更新表单数据,不进入编辑模型属性更新逻辑
2341
+ if (mode.value === "add" && ['heading', 'pitch', 'roll'].includes(key)) return;
2342
+ const isEditMode = this._options.showEditModel;
2343
+
2344
+ // 编辑模式下允许无 _pointModel(通过 _groupShapes 更新)
2345
+ if (!isEditMode && !this._pointModel) {
2346
+ (0, _message.default)({
2347
+ message: this._language.value.webgl.noEditModelData,
2348
+ type: "warning"
2349
+ });
2350
+ return;
2351
+ }
2352
+
2353
+ // 参数更新器工厂:生成针对特定模型的更新函数
2354
+ const createUpdater = model => ({
997
2355
  scale: () => {
998
- this._pointModel.scale = {
2356
+ model.scale = {
999
2357
  x: this._options.scaleX,
1000
2358
  y: this._options.scaleY,
1001
2359
  z: this._options.scaleZ
1002
2360
  };
1003
2361
  },
1004
2362
  offset: () => {
1005
- this._pointModel.offset = {
2363
+ model.offset = {
1006
2364
  x: this._options.offsetX,
1007
2365
  y: this._options.offsetY,
1008
2366
  z: this._options.offsetZ
1009
2367
  };
1010
2368
  },
1011
2369
  setImage: () => {
1012
- this._pointModel.url = this._currentItem?.path || "";
2370
+ model.url = this._currentItem?.path || "";
1013
2371
  },
1014
2372
  ofModelName: () => {
1015
- this._pointModel.label = this._options.ofModelName || this._pointModel.label;
2373
+ model.label = this._options.ofModelName || model.label;
1016
2374
  },
1017
2375
  default: () => {
1018
- this._pointModel[key] = this._options[key];
2376
+ model[key] = this._options[key];
1019
2377
  }
2378
+ });
2379
+ const applyUpdate = model => {
2380
+ const updater = createUpdater(model);
2381
+ (updater[key] || updater.default)();
1020
2382
  };
1021
- (paramUpdater[key] || paramUpdater.default)();
2383
+
2384
+ // 更新当前选中模型
2385
+ if (this._pointModel) {
2386
+ applyUpdate(this._pointModel);
2387
+ }
2388
+
2389
+ // 编辑模式:同步更新 _groupShapes 中与当前选中几何类型匹配的模型
2390
+ if (isEditMode) {
2391
+ const targetValue = this._currentItemGeometry?.value;
2392
+ this._groupShapes.forEach(shape => {
2393
+ if (shape.value === targetValue) {
2394
+ shape.pointModels?.forEach(model => {
2395
+ applyUpdate(model);
2396
+ });
2397
+ }
2398
+ });
2399
+ }
2400
+
2401
+ // 编辑模式:heading/pitch/roll 同步更新预览的复杂模型(仅 mode=edit 时生效)
2402
+ if (mode.value === "edit" && ['heading', 'pitch', 'roll'].includes(key)) {
2403
+ this._previewComplexModels.forEach(model => {
2404
+ if (model[key] !== undefined) {
2405
+ model[key] = this._options[key];
2406
+ }
2407
+ });
2408
+ }
1022
2409
  }
1023
2410
 
1024
2411
  /**
@@ -1053,25 +2440,208 @@ class BuildPointModelViewModel {
1053
2440
  hide() {
1054
2441
  this._customAxis?.showOff?.();
1055
2442
  }
2443
+
2444
+ // 启用缩放轴
1056
2445
  zoomBtn() {
1057
2446
  this._customAxis?.addZoomAxis?.();
1058
2447
  }
2448
+
2449
+ // 启用旋转轴
1059
2450
  rotate() {
1060
2451
  this._customAxis?.addRotateAxis?.();
1061
2452
  }
2453
+
2454
+ // 启用平移轴
1062
2455
  pan() {
1063
2456
  this._customAxis?.addTranslationAxis?.();
1064
2457
  }
2458
+
2459
+ /**
2460
+ * 保存模板数据:生成最终复杂模型配置的 JSON 字符串
2461
+ * @param {string} templateName - 模板名称
2462
+ * @param {Array} groupShapes - 组合列表
2463
+ * @returns {string|null} 模板 groupJson 字符串
2464
+ */
2465
+ saveTemplateData(templateName, groupShapes) {
2466
+ const features = this._getValidatedFeatures();
2467
+ if (!features) return null;
2468
+ const results = this._buildComplexModel(features, groupShapes, 'complexGeometrySymbol', false, false);
2469
+ if (results?.length) {
2470
+ return JSON.stringify(results[0]);
2471
+ }
2472
+ return null;
2473
+ }
2474
+
2475
+ /**
2476
+ * 模板加载/卸载 toggle(支持多个模板同时显示)
2477
+ * 选中已加载的模板 → 卸载该模板;选中未加载的模板 → 加载(不影响其他已加载模板)
2478
+ * @param {number} templateIndex - 模板索引
2479
+ * @param {Object} templateItem - 模板数据 { name, icon, groupJson }
2480
+ * @returns {{ action: string, simplified?: Array }}
2481
+ */
2482
+ loadTemplateSymbol(templateIndex, templateItem) {
2483
+ // 已选中该模板 → 卸载
2484
+ if (this._selectedTemplateIndices.has(templateIndex)) {
2485
+ this._unloadTemplateSymbol(templateIndex);
2486
+ return {
2487
+ action: 'unloaded',
2488
+ simplified: this._getSimplifiedGroupShapes()
2489
+ };
2490
+ }
2491
+ const features = this._getValidatedFeatures();
2492
+ if (!features) return {
2493
+ action: 'unloaded'
2494
+ };
2495
+ try {
2496
+ // 解析模板 groupJson(兼容字符串和对象)
2497
+ let templateConfig;
2498
+ if (typeof templateItem.groupJson === 'string') {
2499
+ try {
2500
+ templateConfig = JSON.parse(templateItem.groupJson);
2501
+ } catch (e) {
2502
+ console.error('解析模板 groupJson 失败:', e);
2503
+ return {
2504
+ action: 'unloaded'
2505
+ };
2506
+ }
2507
+ } else {
2508
+ templateConfig = templateItem.groupJson;
2509
+ }
2510
+ if (!templateConfig) return {
2511
+ action: 'unloaded'
2512
+ };
2513
+ const pointModels = [];
2514
+ const featurePositions = [];
2515
+ const pointModelConfigs = [];
2516
+
2517
+ // 处理所有 feature(与 generated_loadFiles 逻辑保持一致)
2518
+ // 确保多 feature 场景下,模板作为 base 时能为每个 feature 生成独立的克隆模型
2519
+ features.forEach((feature, index) => {
2520
+ const {
2521
+ geometry,
2522
+ properties
2523
+ } = feature;
2524
+ if (!geometry?.coordinates) return;
2525
+ const position = _BuildPointModelUtil.default.extractPosition(geometry.coordinates);
2526
+ featurePositions.push({
2527
+ ...position
2528
+ });
2529
+ const newKey = (0, _util.guid)();
2530
+
2531
+ // 深拷贝模板配置,替换坐标、guid、属性
2532
+ const config = JSON.parse(JSON.stringify(templateConfig));
2533
+
2534
+ // 替换 position
2535
+ if (config.geometry) {
2536
+ config.geometry.position = {
2537
+ x: position.x,
2538
+ y: position.y,
2539
+ z: position.z
2540
+ };
2541
+ }
2542
+
2543
+ // 替换 key / featureID
2544
+ config.key = newKey;
2545
+ config.featureID = newKey;
2546
+
2547
+ // 替换 fieldNames / fieldValues
2548
+ if (properties) {
2549
+ config.fieldNames = Object.keys(properties);
2550
+ config.fieldValues = Object.values(properties);
2551
+ }
2552
+
2553
+ // 替换 label
2554
+ config.label = _BuildPointModelUtil.default.getStringValue(properties, this._options, "ofModelNameFields", "ofModelName", `${templateItem.name}_label${index + 1}`);
2555
+ const bspPrimitive = new Cesium.PMBSPPrimitive(config);
2556
+ this._sceneView._viewer.scene.primitives.add(bspPrimitive);
2557
+ pointModels.push(bspPrimitive);
2558
+ // 存储原始 config,用于后续组合列表创建独立模型(避免 toJSON 丢失 bspGeometry)
2559
+ pointModelConfigs.push(config);
2560
+ });
2561
+
2562
+ // 添加到 _groupShapes
2563
+ this._groupShapes.push({
2564
+ value: `template_${templateIndex}`,
2565
+ name: templateItem.name,
2566
+ icon: templateItem.icon,
2567
+ pointModels: pointModels,
2568
+ _featurePositions: featurePositions,
2569
+ _pointModelConfigs: pointModelConfigs,
2570
+ _isTemplate: true,
2571
+ _templateIndex: templateIndex
2572
+ });
2573
+ this._selectedTemplateIndices.add(templateIndex);
2574
+ this._selectedTemplateModelsMap.set(templateIndex, pointModels);
2575
+ return {
2576
+ action: 'loaded',
2577
+ simplified: this._getSimplifiedGroupShapes()
2578
+ };
2579
+ } catch (error) {
2580
+ console.error("加载组合模板失败:", error);
2581
+ return {
2582
+ action: 'unloaded'
2583
+ };
2584
+ }
2585
+ }
2586
+
2587
+ /**
2588
+ * 卸载模板:从场景移除指定模板(或全部模板)的模型
2589
+ * @param {number} [templateIndex] - 指定模板索引,不传则卸载全部
2590
+ */
2591
+ _unloadTemplateSymbol(templateIndex) {
2592
+ const primitives = this._sceneView?._viewer?.scene?.primitives;
2593
+ if (templateIndex !== undefined) {
2594
+ // 卸载指定模板
2595
+ const models = this._selectedTemplateModelsMap.get(templateIndex);
2596
+ if (models) {
2597
+ models.forEach(model => primitives?.remove(model));
2598
+ this._selectedTemplateModelsMap.delete(templateIndex);
2599
+ }
2600
+ this._selectedTemplateIndices.delete(templateIndex);
2601
+ this._groupShapes = this._groupShapes.filter(item => !(item._isTemplate && item._templateIndex === templateIndex));
2602
+ } else {
2603
+ // 卸载全部模板
2604
+ this._selectedTemplateModelsMap.forEach(models => {
2605
+ models.forEach(model => primitives?.remove(model));
2606
+ });
2607
+ this._selectedTemplateModelsMap.clear();
2608
+ this._selectedTemplateIndices.clear();
2609
+ this._groupShapes = this._groupShapes.filter(item => !item._isTemplate);
2610
+ }
2611
+ }
2612
+
2613
+ // 清空所有状态与场景模型(图层、点模型、预览、已确认 BSP、模板)
1065
2614
  clear() {
1066
2615
  this._layerData = null;
1067
2616
  this._pointModels = [];
1068
2617
  this._pointModel = null;
1069
2618
  this._customAxis?.destroy?.();
1070
2619
  this._customAxis = null;
2620
+ this._clearPreviewBsp();
2621
+ this._clearComplexPreview();
2622
+ this._clearAllConfirmedBsp();
2623
+ this._unloadTemplateSymbol();
2624
+ }
2625
+
2626
+ /**
2627
+ * 清除所有已确认的 BSP 模型
2628
+ */
2629
+ _clearAllConfirmedBsp() {
2630
+ Object.keys(this._confirmedBspResults).forEach(id => {
2631
+ this._removeConfirmedBsp(id);
2632
+ });
2633
+ this._confirmedBspResults = {};
1071
2634
  }
2635
+
2636
+ // 导出当前生成的点模型 JSON 列表
1072
2637
  exportModels() {
1073
2638
  return this._pointModels;
1074
2639
  }
2640
+
2641
+ /**
2642
+ * @description 导入模型 JSON 列表并添加到场景
2643
+ * @param {Array} jsons 模型 JSON 数组
2644
+ */
1075
2645
  importModels(jsons) {
1076
2646
  if (!Array.isArray(jsons)) return;
1077
2647
  jsons.forEach(jsonData => {
@@ -1079,6 +2649,8 @@ class BuildPointModelViewModel {
1079
2649
  this._sceneView._viewer.scene.primitives.add(model);
1080
2650
  });
1081
2651
  }
2652
+
2653
+ // 销毁视图模型,清空状态并释放场景引用
1082
2654
  destroy() {
1083
2655
  this.clear();
1084
2656
  this._sceneView = null;
@@ -1182,7 +2754,8 @@ var _BuildPointModelViewModel = _interopRequireDefault(__webpack_require__(74844
1182
2754
  var _util = __webpack_require__(42975);
1183
2755
  var _useGlobalConfig = __webpack_require__(22686);
1184
2756
  var _constImage = __webpack_require__(4822);
1185
- var _filterConditionSelect = _interopRequireDefault(__webpack_require__(64546));
2757
+ var _filterConditionSelect = _interopRequireDefault(__webpack_require__(74317));
2758
+ var _BuildPointModelApi = _interopRequireDefault(__webpack_require__(11790));
1186
2759
  const _hoisted_1 = {
1187
2760
  class: "spanTile"
1188
2761
  };
@@ -1279,59 +2852,129 @@ const _hoisted_25 = {
1279
2852
  key: 0,
1280
2853
  class: "spanTile"
1281
2854
  };
1282
- const _hoisted_26 = {
2855
+ const _hoisted_26 = ["title", "onClick"];
2856
+ const _hoisted_27 = ["src"];
2857
+ const _hoisted_28 = {
2858
+ style: {
2859
+ "line-height": "30px",
2860
+ "text-align": "left",
2861
+ "display": "flex",
2862
+ "align-items": "center"
2863
+ }
2864
+ };
2865
+ const _hoisted_29 = {
2866
+ class: "render-list-container"
2867
+ };
2868
+ const _hoisted_30 = {
2869
+ class: "render-item-row"
2870
+ };
2871
+ const _hoisted_31 = {
2872
+ class: "render-item-row-icon"
2873
+ };
2874
+ const _hoisted_32 = {
1283
2875
  class: "kq3d-build-point-model-footer"
1284
2876
  };
1285
- const _hoisted_27 = {
2877
+ const _hoisted_33 = {
1286
2878
  class: "kq-add-model"
1287
2879
  };
1288
- const _hoisted_28 = {
2880
+ const _hoisted_34 = {
1289
2881
  class: "thumbnail-upload-wrapper"
1290
2882
  };
1291
- const _hoisted_29 = {
2883
+ const _hoisted_35 = {
1292
2884
  class: "avatar-uploader-trigger"
1293
2885
  };
1294
- const _hoisted_30 = {
2886
+ const _hoisted_36 = {
1295
2887
  key: 0,
1296
2888
  class: "avatar-preview"
1297
2889
  };
1298
- const _hoisted_31 = ["src"];
1299
- const _hoisted_32 = {
2890
+ const _hoisted_37 = ["src"];
2891
+ const _hoisted_38 = {
1300
2892
  class: "avatar-overlay"
1301
2893
  };
1302
- const _hoisted_33 = {
2894
+ const _hoisted_39 = {
1303
2895
  class: "overlay-text"
1304
2896
  };
1305
- const _hoisted_34 = {
2897
+ const _hoisted_40 = {
1306
2898
  key: 1,
1307
2899
  class: "avatar-uploader-empty"
1308
2900
  };
1309
- const _hoisted_35 = {
2901
+ const _hoisted_41 = {
1310
2902
  class: "upload-text"
1311
2903
  };
1312
- const _hoisted_36 = {
2904
+ const _hoisted_42 = {
1313
2905
  class: "upload-hint"
1314
2906
  };
1315
- const _hoisted_37 = {
2907
+ const _hoisted_43 = {
1316
2908
  class: "model-upload-wrapper"
1317
2909
  };
1318
- const _hoisted_38 = {
2910
+ const _hoisted_44 = {
1319
2911
  class: "upload-tip"
1320
2912
  };
1321
- const _hoisted_39 = {
2913
+ const _hoisted_45 = {
1322
2914
  class: "model-file-info"
1323
2915
  };
1324
- const _hoisted_40 = {
2916
+ const _hoisted_46 = {
1325
2917
  key: 0,
1326
2918
  class: "file-details"
1327
2919
  };
1328
- const _hoisted_41 = {
2920
+ const _hoisted_47 = {
1329
2921
  class: "file-name"
1330
2922
  };
1331
- const _hoisted_42 = {
2923
+ const _hoisted_48 = {
1332
2924
  class: "file-size"
1333
2925
  };
1334
- const _hoisted_43 = {
2926
+ const _hoisted_49 = {
2927
+ style: {
2928
+ "text-align": "center",
2929
+ "padding-top": "8px"
2930
+ }
2931
+ };
2932
+ const _hoisted_50 = {
2933
+ class: "kq-add-model"
2934
+ };
2935
+ const _hoisted_51 = {
2936
+ class: "option-content"
2937
+ };
2938
+ const _hoisted_52 = {
2939
+ class: "option-content"
2940
+ };
2941
+ const _hoisted_53 = {
2942
+ style: {
2943
+ "text-align": "right",
2944
+ "padding-top": "8px"
2945
+ }
2946
+ };
2947
+ const _hoisted_54 = {
2948
+ class: "kq-add-model"
2949
+ };
2950
+ const _hoisted_55 = {
2951
+ class: "thumbnail-upload-wrapper"
2952
+ };
2953
+ const _hoisted_56 = {
2954
+ class: "avatar-uploader-trigger"
2955
+ };
2956
+ const _hoisted_57 = {
2957
+ key: 0,
2958
+ class: "avatar-preview"
2959
+ };
2960
+ const _hoisted_58 = ["src"];
2961
+ const _hoisted_59 = {
2962
+ class: "avatar-overlay"
2963
+ };
2964
+ const _hoisted_60 = {
2965
+ class: "overlay-text"
2966
+ };
2967
+ const _hoisted_61 = {
2968
+ key: 1,
2969
+ class: "avatar-uploader-empty"
2970
+ };
2971
+ const _hoisted_62 = {
2972
+ class: "upload-text"
2973
+ };
2974
+ const _hoisted_63 = {
2975
+ class: "upload-hint"
2976
+ };
2977
+ const _hoisted_64 = {
1335
2978
  style: {
1336
2979
  "text-align": "center",
1337
2980
  "padding-top": "8px"
@@ -1392,7 +3035,9 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1392
3035
  default: []
1393
3036
  }
1394
3037
  },
1395
- emits: ["generatedEnd", "changeModelName", "uploadPointSymbol", "deletePointSymbol"],
3038
+ emits: [
3039
+ // 对外事件定义
3040
+ "generatedEnd", "changeModelName", "uploadPointSymbol", "deletePointSymbol", "uploadComplexGeometryTemplate"],
1396
3041
  setup(__props, {
1397
3042
  expose: __expose,
1398
3043
  emit: __emit
@@ -1403,7 +3048,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1403
3048
  locale
1404
3049
  } = (0, _useGlobalConfig.useLocale)();
1405
3050
  const props = __props;
1406
- const mode = (0, _vue.computed)(() => props?.settingParams?.mode ?? "add");
3051
+ const mode = (0, _vue.computed)(() => props?.settingParams?.mode ?? "add"); // 当前模式(add 新增 / edit 编辑)
1407
3052
  let formItem = (0, _vue.reactive)({
1408
3053
  collapseValue: props?.settingParams?.collapseValue ?? "general",
1409
3054
  // 默认展开属性设置
@@ -1550,14 +3195,28 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1550
3195
  // 自定义点符号
1551
3196
  coordinates: props?.settingParams?.coordinates ?? "",
1552
3197
  // 自定义范围
1553
- stretchHeight: props?.settingParams?.stretchHeight ?? 20 // 拉伸高度
3198
+ stretchHeight: props?.settingParams?.stretchHeight ?? 20,
3199
+ // 拉伸高度
3200
+ isComplexGeometry: props?.settingParams?.isComplexGeometry ?? false,
3201
+ // 拉伸高度
3202
+ // 复杂几何
3203
+ modelName: props?.settingParams?.modelName ?? "",
3204
+ showOperationModel: true,
3205
+ showEditModel: false,
3206
+ // 外部数据配置
3207
+ geometryServerUrl: props?.settingParams?.geometryServerUrl ?? '',
3208
+ geometryServerToken: props?.settingParams?.geometryServerToken ?? '',
3209
+ isUseServer: props?.settingParams?.isUseServer ?? false
1554
3210
  });
1555
3211
  // 2. 初始化 symbolTypes
1556
3212
  const symbolTypes = (0, _vue.reactive)({
1557
3213
  ...props?.symbolData
1558
3214
  });
1559
- let modelingTypes = (0, _vue.ref)(null);
1560
- let geometrySymbols = (0, _vue.ref)([{
3215
+ let modelingTypes = (0, _vue.ref)(null); // 当前模型类型(动态符号/几何符号/自定义点/复杂几何)
3216
+
3217
+ let geometrySymbols = (0, _vue.ref)([
3218
+ // 几何符号类型列表(立方体、圆柱、圆锥等)
3219
+ {
1561
3220
  // 立方体
1562
3221
  value: "PMCube",
1563
3222
  name: locale.value.webgl.cube,
@@ -1635,34 +3294,82 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1635
3294
  name: locale.value.webgl.PMCustomPointModel,
1636
3295
  icon: (0, _vue.markRaw)(_client_icons_vue.IconStretchedBody)
1637
3296
  }]);
3297
+ const groupShapesArr = (0, _vue.ref)([]); // 当前可用作组合基础/运算对象的简单几何与模板项列表
3298
+ // 组合模板数据
3299
+ const groupSymbols = (0, _vue.ref)([]);
3300
+ const groupShapes = (0, _vue.ref)([]); // 已确认的组合列表
3301
+ const groupShapesObj = (0, _vue.reactive)({
3302
+ // 当前正在编辑的组合表单对象
3303
+ name: '',
3304
+ operationName: "",
3305
+ baseModel: null,
3306
+ operationModel: null,
3307
+ operationMethod: 0
3308
+ });
3309
+ // 第一个下拉框:排除掉第二个下拉框已经选中的值,并加入已确认的运算模型组合
3310
+ const groupShapeList1 = (0, _vue.computed)(() => {
3311
+ const baseList = groupShapesArr.value.filter(item => item.name !== groupShapesObj.operationName);
3312
+ // 追加已确认的运算模型组合
3313
+ const confirmedCombos = groupShapes.value.filter(item => item.operationName).map(item => ({
3314
+ value: item.id,
3315
+ name: `${item.groupType}${item.index}`,
3316
+ icon: null
3317
+ }));
3318
+ return [...baseList, ...confirmedCombos];
3319
+ });
3320
+
3321
+ // 第二个下拉框:排除掉第一个下拉框已经选中的值,并加入已确认的运算模型组合
3322
+ const groupShapeList2 = (0, _vue.computed)(() => {
3323
+ const baseList = groupShapesArr.value.filter(item => item.name !== groupShapesObj.name);
3324
+ // 追加已确认的运算模型组合(只有 operationName 不为空的才是运算模型)
3325
+ const confirmedCombos = groupShapes.value.filter(item => item.operationName).map(item => ({
3326
+ value: item.id,
3327
+ name: `${item.groupType}${item.index}`,
3328
+ icon: null
3329
+ }));
3330
+ return [...baseList, ...confirmedCombos];
3331
+ });
3332
+ let selectedIndex_group = (0, _vue.ref)([]); // 已选中的模板索引列表
3333
+ let isShowSaveTemplate = (0, _vue.ref)(false); // 是否显示保存模板弹框
3334
+ const templateSaveData = (0, _vue.reactive)({
3335
+ // 保存模板弹框的表单数据
3336
+ name: '',
3337
+ img: ''
3338
+ });
1638
3339
  const emit = __emit;
1639
3340
  // 组件容器Ref
1640
3341
  let boxRef = (0, _vue.ref)(null);
1641
3342
  // 生成组件默认header
1642
3343
  let headerTemp = (0, _vue.ref)();
1643
- let headerTempRef = (0, _vue.ref)();
1644
- let viewModel = null;
1645
- let propertyFieldsDef = (0, _vue.ref)([]);
1646
- let isShowAddModel = (0, _vue.ref)(false);
3344
+ let headerTempRef = (0, _vue.ref)(); // header 模板引用
3345
+ let viewModel = null; // 视图模型实例(业务逻辑层)
3346
+ let _api = null; // 服务端 API 实例(服务端模式)
3347
+ let propertyFieldsDef = (0, _vue.ref)([]); // 数据属性字段定义列表
3348
+ let isShowAddModel = (0, _vue.ref)(false); // 是否显示添加模型弹框
3349
+ let isShowAddGroup = (0, _vue.ref)(false); // 是否显示添加组合弹框
1647
3350
  let modelEditData = (0, _vue.reactive)({
3351
+ // 模型编辑表单数据
1648
3352
  name: "",
1649
3353
  img: "",
1650
3354
  path: ""
1651
3355
  });
3356
+
1652
3357
  // 类型选中
1653
3358
  let currentData = (0, _vue.ref)({});
1654
- let selectedIndex = (0, _vue.ref)(null);
1655
- let selectedIndex_jh = (0, _vue.ref)(null);
1656
- let currentItemGeometry = (0, _vue.ref)(null);
1657
- let currentItem = (0, _vue.ref)(null);
1658
- let isDelete = (0, _vue.ref)(false);
1659
- const maxHeight = (0, _vue.computed)(() => props?.maxHeight ?? 605);
3359
+ let selectedIndex = (0, _vue.ref)(null); // 当前选中的符号索引
3360
+ let selectedIndex_jh = (0, _vue.ref)(null); // 当前选中的几何符号索引
3361
+
3362
+ let currentItemGeometry = (0, _vue.ref)(null); // 当前选中的几何符号项
3363
+ let currentItem = (0, _vue.ref)(null); // 当前选中的符号项
3364
+ let isDelete = (0, _vue.ref)(false); // 是否处于删除模式
3365
+
3366
+ const maxHeight = (0, _vue.computed)(() => props?.maxHeight ?? 605); // 内容区最大高度
1660
3367
  // 控制是否加滚动样式
1661
3368
  const needScroll = (0, _vue.ref)(false);
1662
3369
  // DOM 引用
1663
3370
  const scrollBox = (0, _vue.ref)(null);
1664
3371
  // 监听元素尺寸变化(内容变化自动触发)
1665
- let resizeObserver = null;
3372
+ let resizeObserver = null; // 尺寸观察器实例
1666
3373
  (0, _vue.watch)((0, _vue.toRef)(props, "symbolData"),
1667
3374
  // 精准监听 props 中的 symbolData 属性,避免解构丢失响应式
1668
3375
  newData => {
@@ -1702,29 +3409,48 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1702
3409
  setPointSymbol();
1703
3410
  }
1704
3411
  });
3412
+ // 服务端模式:初始化 API 实例并获取远程数据
3413
+ if (formItem.isUseServer && formItem.geometryServerUrl) {
3414
+ _api = new _BuildPointModelApi.default(formItem.geometryServerUrl, formItem.geometryServerToken);
3415
+ _api.init().then(() => {
3416
+ getFileDirectory();
3417
+ getComplexGeometryTemplates();
3418
+ });
3419
+ }
1705
3420
  initScroll();
1706
3421
  });
1707
3422
  // 计算属性
3423
+ // 编辑模式下的复杂几何符号:仅显示朝向角/俯仰角/翻转角
3424
+ const isEditComplexGeometry = (0, _vue.computed)(() => mode.value === 'edit' && modelingTypes.value === 'complexGeometrySymbol');
1708
3425
  const isDisabled = (0, _vue.computed)(() => {
1709
- // 1. 基础判断:没有 geometry 直接禁用
3426
+ // 复杂几何符号:需要至少一个组合
3427
+ if (formItem.isComplexGeometry) {
3428
+ return !groupShapes.value.length;
3429
+ }
3430
+
3431
+ // 基础判断:没有 geometry 直接禁用
1710
3432
  if (!currentItemGeometry.value) return true;
1711
3433
  const type = currentItemGeometry.value?.value;
1712
3434
 
1713
- // 2. 圆柱体类型:需要高度 + 半径
3435
+ // 圆柱体类型:需要高度 + 半径
1714
3436
  if (type === 'PMExtrudedCylinder') {
1715
3437
  return !(formItem.heights && formItem.radii && safelyParse(formItem.heights) && safelyParse(formItem.radii));
1716
3438
  }
1717
3439
 
1718
- // 3. 自定义点模型:需要坐标
3440
+ // 自定义点模型:需要坐标
1719
3441
  if (type === 'PMCustomPointModel') {
1720
3442
  return !(formItem.coordinates && safelyParse(formItem.coordinates));
1721
3443
  }
1722
3444
 
1723
- // 4. 其他类型:不禁用
3445
+ // 其他类型:不禁用
1724
3446
  return false;
1725
3447
  });
1726
3448
 
1727
- // 工具函数:安全解析 JSON,防止报错
3449
+ /**
3450
+ * @description 工具函数:安全解析 JSON,防止报错
3451
+ * @param {string} str 待解析的 JSON 字符串
3452
+ * @returns {*} 解析后的对象,失败返回 null
3453
+ */
1728
3454
  function safelyParse(str) {
1729
3455
  try {
1730
3456
  return JSON.parse(str);
@@ -1732,6 +3458,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1732
3458
  return null;
1733
3459
  }
1734
3460
  }
3461
+ // 初始化滚动监听,观察内容区尺寸变化以决定是否显示滚动条
1735
3462
  function initScroll() {
1736
3463
  const el = scrollBox.value;
1737
3464
  if (!el) return;
@@ -1753,6 +3480,98 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1753
3480
  // 内容实际高度 > 最大高度 → 显示滚动条
1754
3481
  needScroll.value = el.scrollHeight > maxHeight.value;
1755
3482
  }
3483
+ // 获取点符号文件目录(服务端模式)
3484
+ async function getFileDirectory() {
3485
+ if (!_api) return;
3486
+ try {
3487
+ const res = await _api.getAllContents('/sceneView/buildModel/pointSymbol', true);
3488
+ if (res?.length) {
3489
+ const categories = _api.buildCategoryList(res);
3490
+ if (categories?.length) {
3491
+ Object.keys(symbolTypes).forEach(key => delete symbolTypes[key]);
3492
+ Object.assign(symbolTypes, categories);
3493
+ setPointSymbol();
3494
+ // 预加载第一个分类的符号数据(传 reactive proxy 确保响应式更新)
3495
+ if (symbolTypes[0]) {
3496
+ _api.loadCategorySymbols(symbolTypes[0]).then(() => {
3497
+ updateCurrentItem();
3498
+ });
3499
+ }
3500
+ }
3501
+ }
3502
+ } catch (error) {
3503
+ console.error('获取点符号文件目录失败:', error);
3504
+ }
3505
+ }
3506
+ // 获取复杂几何符号模板(服务端模式)
3507
+ async function getComplexGeometryTemplates() {
3508
+ if (!_api) return;
3509
+ try {
3510
+ const res = await _api.getAllContents('/sceneView/buildModel/complexGeometryTemplate', true);
3511
+ if (!res?.length) return;
3512
+ const addedNames = new Set();
3513
+
3514
+ // 辅助函数:添加模板到列表(去重)
3515
+ function addTemplate(name, icon, groupJson) {
3516
+ if (addedNames.has(name)) return;
3517
+ addedNames.add(name);
3518
+ groupSymbols.value.push({
3519
+ name,
3520
+ icon: icon || (0, _vue.markRaw)(_client_icons_vue.PrintImage),
3521
+ groupJson
3522
+ });
3523
+ }
3524
+
3525
+ // 1. 处理子目录中的模板(每个模板一个子目录,包含 JSON 和 PNG 文件)
3526
+ for (const dir of res) {
3527
+ if (dir.fileType !== "File Folder" || !dir.children) continue;
3528
+ for (const child of dir.children) {
3529
+ if (child.fileType !== "File Folder" && child.dirName.endsWith('.json')) {
3530
+ try {
3531
+ const textContent = await _api.getFileText(child.dirPath);
3532
+ if (textContent) {
3533
+ const groupJson = JSON.parse(textContent);
3534
+ const pngFile = dir.children.find(c => c.fileType !== "File Folder" && c.dirName.endsWith('.png'));
3535
+ let icon = null;
3536
+ if (pngFile) {
3537
+ const pngBase64 = await _api.getFileBase64(pngFile.dirPath);
3538
+ icon = pngBase64 ? `data:image/png;base64,${pngBase64}` : null;
3539
+ }
3540
+ addTemplate(dir.dirName, icon, groupJson);
3541
+ }
3542
+ } catch (err) {
3543
+ console.error('读取模板文件失败:', child.dirName, err);
3544
+ }
3545
+ }
3546
+ }
3547
+ }
3548
+
3549
+ // 2. 处理直接放在目录中的 JSON 文件(uploadJsonData 上传的扁平模板)
3550
+ for (const file of res) {
3551
+ if (file.fileType === "File Folder" || !file.dirName.endsWith('.json')) continue;
3552
+ try {
3553
+ const textContent = await _api.getFileText(file.dirPath);
3554
+ if (textContent) {
3555
+ const groupJson = JSON.parse(textContent);
3556
+ const templateName = file.dirName.replace(/\.json$/i, '');
3557
+ // 查找同名的 PNG 缩略图
3558
+ const pngFile = res.find(f => f.fileType !== "File Folder" && f.dirName === templateName + '.png');
3559
+ let icon = null;
3560
+ if (pngFile) {
3561
+ const pngBase64 = await _api.getFileBase64(pngFile.dirPath);
3562
+ icon = pngBase64 ? `data:image/png;base64,${pngBase64}` : null;
3563
+ }
3564
+ addTemplate(templateName, icon, groupJson);
3565
+ }
3566
+ } catch (err) {
3567
+ console.error('读取模板文件失败:', file.dirName, err);
3568
+ }
3569
+ }
3570
+ } catch (error) {
3571
+ console.error('获取复杂几何模板失败:', error);
3572
+ }
3573
+ }
3574
+ // 设置默认点符号与几何符号的选中项
1756
3575
  function setPointSymbol() {
1757
3576
  formItem.symbolType = symbolTypes?.[0]?.name;
1758
3577
  currentData.value = symbolTypes?.[0];
@@ -1774,6 +3593,10 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1774
3593
  headerTemp.value = (0, _util.createHeaderTemp)(boxRef.value, (0, _vue.toRefs)(props), headerTempRef, "webgl.buildPointModel");
1775
3594
  }
1776
3595
  };
3596
+ /**
3597
+ * @description 接收外部数据并下发到视图模型(字符串走服务端拉取,对象直接使用)
3598
+ * @param {string|Object} data 数据源,字符串表示服务端数据地址,对象表示直接的图层数据
3599
+ */
1777
3600
  function setData(data) {
1778
3601
  if (data) {
1779
3602
  if (!viewModel) return;
@@ -1801,10 +3624,14 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1801
3624
  label,
1802
3625
  modelingType,
1803
3626
  geometry,
1804
- style
3627
+ style,
3628
+ type
1805
3629
  } = item?.toJSON?.() ?? {};
1806
3630
  const {
1807
3631
  hpr,
3632
+ heading,
3633
+ pitch,
3634
+ roll,
1808
3635
  scale,
1809
3636
  color,
1810
3637
  clampToGround,
@@ -1815,7 +3642,6 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1815
3642
  slices,
1816
3643
  topRadius,
1817
3644
  bottomRadius,
1818
- type,
1819
3645
  radius,
1820
3646
  slicePartitions,
1821
3647
  stackPartitions,
@@ -1856,16 +3682,21 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1856
3682
  topCenterOffsetX,
1857
3683
  topCenterOffsetY,
1858
3684
  stretchHeight,
1859
- coordinates
3685
+ coordinates,
3686
+ offset
1860
3687
  } = Object.assign({}, parameter || {}, geometry || {}, style || {});
1861
3688
  modelingTypes.value = modelingType ?? null;
1862
3689
  Object.assign(formItem, {
1863
- heading: hpr?.heading ?? formItem.heading,
1864
- pitch: hpr?.pitch ?? formItem.pitch,
1865
- roll: hpr?.roll ?? formItem.roll,
3690
+ isComplexGeometry: modelingType === 'complexGeometrySymbol',
3691
+ heading: hpr?.heading ?? heading ?? formItem.heading,
3692
+ pitch: hpr?.pitch ?? pitch ?? formItem.pitch,
3693
+ roll: hpr?.roll ?? roll ?? formItem.roll,
1866
3694
  scaleX: scale?.x ?? formItem.scaleX,
1867
3695
  scaleY: scale?.y ?? formItem.scaleY,
1868
3696
  scaleZ: scale?.z ?? formItem.scaleZ,
3697
+ offsetX: offset?.x ?? formItem.offsetX,
3698
+ offsetY: offset?.y ?? formItem.offsetY,
3699
+ offsetZ: offset?.z ?? formItem.offsetZ,
1869
3700
  color: color ?? formItem.color,
1870
3701
  clampToGround: clampToGround ?? formItem.clampToGround,
1871
3702
  ofModelName: label ?? formItem.ofModelName,
@@ -1927,7 +3758,10 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1927
3758
  };
1928
3759
  }
1929
3760
  }
1930
- // 参数切换
3761
+ /**
3762
+ * @description 参数切换,同步表单到视图模型并通知视图层处理
3763
+ * @param {string} key 变化的参数键名(特殊键:ofModelName/setImage/setGeometrySymbol)
3764
+ */
1931
3765
  function paramsChanged(key) {
1932
3766
  if (!viewModel) return;
1933
3767
  Object.assign(viewModel._options, formItem);
@@ -1942,9 +3776,19 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1942
3776
  const isFormValid = (0, _vue.computed)(() => {
1943
3777
  return modelEditData.name && modelEditData.path;
1944
3778
  });
3779
+ // 保存模板按钮可用性判断
3780
+ // 仅当组合列表只有1条且是"仅来自模板的简单组合"时禁用(数据同源,保存无意义)
3781
+ // 简单几何(可能调整参数)或运算模型(已是新模型)单条时允许保存
3782
+ const canSaveTemplate = (0, _vue.computed)(() => {
3783
+ if (!groupShapes.value.length) return false;
3784
+ if (groupShapes.value.length === 1) {
3785
+ return !groupShapes.value[0]._isFromTemplateOnly;
3786
+ }
3787
+ return true;
3788
+ });
1945
3789
 
1946
3790
  // 保存模型
1947
- function saveModelData() {
3791
+ async function saveModelData() {
1948
3792
  try {
1949
3793
  // 准备保存的数据
1950
3794
  const saveData = {
@@ -1955,12 +3799,34 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1955
3799
  if (currentData?.value?.children) {
1956
3800
  currentData.value.children.push(saveData);
1957
3801
  }
1958
- // 发出上传事件
1959
- emit("uploadPointSymbol", {
1960
- ...uploadFile.value,
1961
- name: saveData.name,
1962
- parentNode: currentData.value
1963
- });
3802
+ // 服务端模式:通过 API 内部上传
3803
+ if (formItem.isUseServer && _api) {
3804
+ const res = await _api.uploadPointMaterial({
3805
+ filePath: currentData?.value?._dirPath || '/sceneView/buildModel/pointSymbol',
3806
+ name: saveData.name,
3807
+ img: uploadFile.value.img,
3808
+ path: uploadFile.value.path
3809
+ });
3810
+ if (res && res.success) {
3811
+ (0, _message.default)({
3812
+ message: locale.value.webgl.uploadSuccess || '文件上传成功!',
3813
+ type: 'success'
3814
+ });
3815
+ getFileDirectory();
3816
+ } else {
3817
+ (0, _message.default)({
3818
+ message: locale.value.webgl.uploadFail || '文件上传失败!',
3819
+ type: 'error'
3820
+ });
3821
+ }
3822
+ } else {
3823
+ // 非服务端模式:发出上传事件,由父组件处理
3824
+ emit("uploadPointSymbol", {
3825
+ ...uploadFile.value,
3826
+ name: saveData.name,
3827
+ parentNode: currentData.value
3828
+ });
3829
+ }
1964
3830
  // 重置表单数据
1965
3831
  modelEditData.name = "";
1966
3832
  modelEditData.img = "";
@@ -1973,7 +3839,11 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1973
3839
  console.error("模型添加失败:", error);
1974
3840
  }
1975
3841
  }
1976
- // 处理GLB文件上传
3842
+ /**
3843
+ * @description 处理 GLB 模型文件上传,校验大小并写入表单
3844
+ * @param {Object} file 上传的文件对象
3845
+ * @param {Array} fileList 文件列表
3846
+ */
1977
3847
  function handleGlbSuccess(file, fileList) {
1978
3848
  if (file.size > 5 * 1024 * 1024) {
1979
3849
  _message.default.error(locale.value.webgl.modelSizeLimit);
@@ -1982,7 +3852,10 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1982
3852
  uploadFile.value.path = file;
1983
3853
  modelEditData.path = URL.createObjectURL(file.raw);
1984
3854
  }
1985
- // 处理缩略图上传
3855
+ /**
3856
+ * @description 处理缩略图上传,读取为 base64 写入表单
3857
+ * @param {Object} file 上传的图片文件对象
3858
+ */
1986
3859
  const handleAvatarSuccess = file => {
1987
3860
  uploadFile.value.img = file;
1988
3861
  const reader = new FileReader();
@@ -1991,11 +3864,19 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
1991
3864
  };
1992
3865
  reader.readAsDataURL(file.raw);
1993
3866
  };
1994
- // 获取文件名(不含扩展名)
3867
+ /**
3868
+ * @description 获取文件名(不含扩展名)
3869
+ * @param {string} fullName 完整文件名
3870
+ * @returns {string} 去除扩展名后的文件名
3871
+ */
1995
3872
  function getFileName(fullName) {
1996
3873
  return fullName.replace(/\.[^/.]+$/, "");
1997
3874
  }
1998
- // 获取文件大小格式化显示
3875
+ /**
3876
+ * @description 获取文件大小格式化显示
3877
+ * @param {number} bytes 文件字节数
3878
+ * @returns {string} 带单位(Bytes/KB/MB/GB)的大小字符串
3879
+ */
1999
3880
  function getFileSize(bytes) {
2000
3881
  if (bytes === 0) return "0 Bytes";
2001
3882
  const k = 1024;
@@ -2011,40 +3892,100 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2011
3892
  function addContents() {
2012
3893
  isShowAddModel.value = true;
2013
3894
  }
3895
+ // 切换删除模式显隐
2014
3896
  function showDelete() {
2015
3897
  isDelete.value = !isDelete.value;
2016
3898
  }
3899
+ /**
3900
+ * @description 删除指定符号,弹框确认后从列表与服务端移除
3901
+ * @param {Object} image 待删除的符号对象
3902
+ * @param {number} image 在列表中的索引
3903
+ */
2017
3904
  function deleteImage(image, index) {
2018
3905
  _messagebox.default.confirm(`${locale.value.webgl.confirmDelete}"${image.name}"?`, locale.value.webgl.deleteConfirm, {
2019
3906
  confirmButtonText: locale.value.common.confirm,
2020
3907
  cancelButtonText: locale.value.common.cancel,
2021
3908
  type: "warning"
2022
- }).then(() => {
3909
+ }).then(async () => {
2023
3910
  if (currentData?.value?.children) {
2024
3911
  currentData.value.children.splice(index, 1);
2025
3912
  }
2026
- emit("deletePointSymbol", image);
3913
+ // 服务端模式:通过 API 内部删除
3914
+ if (formItem.isUseServer && _api && image.dirPath) {
3915
+ const deleted = await _api.deleteFile(image.dirPath);
3916
+ if (deleted) {
3917
+ (0, _message.default)({
3918
+ message: '文件删除成功!',
3919
+ type: 'success'
3920
+ });
3921
+ getFileDirectory();
3922
+ } else {
3923
+ (0, _message.default)({
3924
+ message: '文件删除失败!',
3925
+ type: 'error'
3926
+ });
3927
+ }
3928
+ } else {
3929
+ // 非服务端模式:发出删除事件,由父组件处理
3930
+ emit("deletePointSymbol", image);
3931
+ }
2027
3932
  }).catch(() => {
2028
3933
  // 用户取消删除,不做任何操作
2029
3934
  });
2030
3935
  }
2031
- // 生成
3936
+ /**
3937
+ * @description 生成模型;复杂几何走合并逻辑,其他走视图模型常规生成
3938
+ * @param {string} key 模型类型键(如 complexGeometrySymbol)
3939
+ */
2032
3940
  function generated(key) {
2033
- viewModel?.generated(key, function (data) {
2034
- emit("generatedEnd", data);
2035
- });
3941
+ if (key === "complexGeometrySymbol" && formItem.isComplexGeometry) {
3942
+ // 生成时隐藏所有辅助内容,只显示生成结果
3943
+ hideAllAuxiliaryForPreview();
3944
+ // 复杂几何符号:合并所有已确认组合的 BSP 结果
3945
+ viewModel?._generateComplexGeometry(groupShapes.value, key, function (data) {
3946
+ emit("generatedEnd", data);
3947
+ });
3948
+ } else {
3949
+ viewModel?.generated(key, function (data) {
3950
+ emit("generatedEnd", data);
3951
+ });
3952
+ }
2036
3953
  }
2037
- // 切换类型
3954
+ /**
3955
+ * @description 切换符号分类,按需加载该分类下的符号 base64
3956
+ * @param {Object} item 选中的分类项
3957
+ * @param {number} index 分类索引
3958
+ */
2038
3959
  function changeType(item, index) {
2039
3960
  currentData.value = item;
2040
3961
  selectedIndex.value = 0;
3962
+ // 按需加载:分类未加载过则先请求 base64
3963
+ if (_api && item._children && !item.children?.length) {
3964
+ _api.loadCategorySymbols(item).then(() => {
3965
+ updateCurrentItem();
3966
+ });
3967
+ } else {
3968
+ updateCurrentItem();
3969
+ }
3970
+ }
3971
+ // 根据当前选中分类与索引同步视图模型的当前项
3972
+ function updateCurrentItem() {
2041
3973
  if (!viewModel) return;
2042
3974
  viewModel._currentItem = currentData?.value?.children?.[selectedIndex?.value];
2043
3975
  currentItem.value = viewModel?._currentItem ?? null;
2044
3976
  }
3977
+ /**
3978
+ * @description 处理过滤条件变化
3979
+ * @param {string} condition 选中的过滤条件字符串
3980
+ */
2045
3981
  const handleFilterChange = condition => {
2046
3982
  formItem.selectModelId = condition;
2047
3983
  };
3984
+ /**
3985
+ * @description 选中某个符号图片
3986
+ * @param {number} index 符号在列表中的索引
3987
+ * @param {Object} item 符号对象
3988
+ */
2048
3989
  function selectImage(index, item) {
2049
3990
  if (isDelete.value) return;
2050
3991
  selectedIndex.value = index;
@@ -2069,11 +4010,26 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2069
4010
  function pan() {
2070
4011
  viewModel && viewModel.pan();
2071
4012
  }
4013
+ // 清空视图模型与所有组合状态,重置弹框与表单
2072
4014
  function clear() {
2073
4015
  viewModel?.clear();
4016
+ groupShapesArr.value = [];
4017
+ selectedIndex_group.value = [];
4018
+ groupShapes.value = [];
4019
+ // 补充重置:避免弹框残留、表单数据残留
4020
+ resetGroupShapesObj();
4021
+ isShowAddGroup.value = false;
4022
+ isShowSaveTemplate.value = false;
4023
+ templateSaveData.name = '';
4024
+ templateSaveData.img = '';
2074
4025
  }
2075
4026
 
2076
4027
  //--------------几何符号---------------------------------------------------------------
4028
+ /**
4029
+ * @description 选中某个几何符号
4030
+ * @param {number} index 几何符号索引
4031
+ * @param {Object} item 几何符号对象
4032
+ */
2077
4033
  function selectGeometrySymbol(index, item) {
2078
4034
  selectedIndex_jh.value = index;
2079
4035
  if (!viewModel) return;
@@ -2081,13 +4037,285 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2081
4037
  currentItemGeometry.value = item;
2082
4038
  viewModel.paramsChanged("setGeometrySymbol", mode);
2083
4039
  }
4040
+ /**
4041
+ * @description 选中/取消选中某个组合模板,加载或卸载对应模板符号
4042
+ * @param {number} index 模板索引
4043
+ * @param {Object} item 模板对象
4044
+ */
4045
+ function selectGroupSymbol(index, item) {
4046
+ if (!viewModel) return;
4047
+ const result = viewModel.loadTemplateSymbol(index, item);
4048
+ if (result?.simplified !== undefined) {
4049
+ groupShapesArr.value = result.simplified;
4050
+ }
4051
+ if (result?.action === 'loaded') {
4052
+ if (!selectedIndex_group.value.includes(index)) {
4053
+ selectedIndex_group.value.push(index);
4054
+ }
4055
+ } else {
4056
+ selectedIndex_group.value = selectedIndex_group.value.filter(i => i !== index);
4057
+ }
4058
+ }
4059
+ // 添加图形
4060
+ function addGroupShape() {
4061
+ // 重置表单对象
4062
+ resetGroupShapesObj();
4063
+ isShowAddGroup.value = true;
4064
+ }
4065
+ // 重置组合表单对象
4066
+ function resetGroupShapesObj() {
4067
+ groupShapesObj.name = '';
4068
+ groupShapesObj.operationName = '';
4069
+ groupShapesObj.baseModel = null;
4070
+ groupShapesObj.operationModel = null;
4071
+ groupShapesObj.operationMethod = 0;
4072
+ // 清除预览
4073
+ viewModel?._clearPreviewBsp();
4074
+ }
4075
+ // 取消添加组合:清除数据并关闭弹框
4076
+ function handleCancelAddGroup() {
4077
+ resetGroupShapesObj();
4078
+ isShowAddGroup.value = false;
4079
+ }
4080
+ /**
4081
+ * @description 组合操作统一入口,按 key 分发到加载/清除/显隐/预览/确认等逻辑
4082
+ * @param {string} key 操作键(loadFiles/clearGroupShapes/showOperationModel/showEditModel/preview/confirm/clear/base/operation)
4083
+ * @param {*} [val] 操作附带值(base/operation 时为模型对象)
4084
+ */
4085
+ function addGroupShapeBtn(key, val) {
4086
+ switch (key) {
4087
+ case 'loadFiles':
4088
+ if (!viewModel) return;
4089
+ // 复杂几何编辑阶段:只生成第一个 feature + 缩放,节省性能
4090
+ viewModel.generated_loadFiles((data, message) => {
4091
+ if (data?.length) {
4092
+ groupShapesArr.value = data;
4093
+ }
4094
+ }, formItem.isComplexGeometry);
4095
+ break;
4096
+ case 'clearGroupShapes':
4097
+ viewModel.clearSimpleGeometryModels(data => {
4098
+ groupShapesArr.value = data;
4099
+ });
4100
+ break;
4101
+ case 'showOperationModel':
4102
+ viewModel.showGroupShapes(formItem.showOperationModel, data => {
4103
+ groupShapesArr.value = data;
4104
+ });
4105
+ break;
4106
+ case 'showEditModel':
4107
+ viewModel.showEditModel(formItem.showEditModel);
4108
+ break;
4109
+ case 'preview':
4110
+ viewModel._operationModels(groupShapesObj, true, null);
4111
+ break;
4112
+ case 'confirm':
4113
+ {
4114
+ // 生成唯一 ID
4115
+ const confirmId = (0, _util.guid)();
4116
+ const type = groupShapesObj.operationName ? locale.value.webgl.group : locale.value.webgl.shape;
4117
+ const sameType = groupShapes.value.filter(i => i.groupType === type);
4118
+ const newIndex = sameType.length ? Math.max(...sameType.map(i => i.index)) + 1 : 1;
4119
+
4120
+ // 确认组合:生成/移动 BSP 结果到已确认
4121
+ viewModel._confirmOperationModel(groupShapesObj, confirmId);
4122
+
4123
+ // 判断是否为"仅来自模板的简单组合"(无运算 + base 来自模板)
4124
+ // 这种组合保存模板时数据同源,无意义
4125
+ const isFromTemplateOnly = !groupShapesObj.operationName && !!groupShapesObj.baseModel?._isTemplate;
4126
+ groupShapes.value.push({
4127
+ id: confirmId,
4128
+ index: newIndex,
4129
+ groupType: type,
4130
+ name: groupShapesObj.name,
4131
+ operationName: groupShapesObj.operationName,
4132
+ operationMethod: groupShapesObj.operationMethod,
4133
+ _show: true,
4134
+ _isFromTemplateOnly: isFromTemplateOnly
4135
+ });
4136
+ // 清除预览的运算模型
4137
+ viewModel._clearPreviewBsp();
4138
+ isShowAddGroup.value = false;
4139
+ }
4140
+ break;
4141
+ case 'clear':
4142
+ // 清除预览的运算模型(原始简单几何模型不动)
4143
+ viewModel._clearPreviewBsp();
4144
+ break;
4145
+ case 'base':
4146
+ groupShapesObj.baseModel = val;
4147
+ break;
4148
+ case 'operation':
4149
+ groupShapesObj.operationModel = val;
4150
+ break;
4151
+ default:
4152
+ break;
4153
+ }
4154
+ }
4155
+ /**
4156
+ * @description 删除组合(同步删除对应布尔运算模型)
4157
+ * @param {number} index 组合在列表中的索引
4158
+ */
4159
+ function handleDeleteGroupShape(index) {
4160
+ const item = groupShapes.value[index];
4161
+ if (item?.id) {
4162
+ viewModel?._removeConfirmedBsp(item.id);
4163
+ }
4164
+ groupShapes.value.splice(index, 1);
4165
+ }
4166
+
4167
+ /**
4168
+ * @description 切换组合显隐
4169
+ * @param {Object} item 组合对象(含 id 与 _show 状态)
4170
+ * @param {number} index 组合索引
4171
+ */
4172
+ function handleViewGroupShape(item, index) {
4173
+ if (!item?.id || !viewModel) return;
4174
+ const bspItems = viewModel._confirmedBspResults[item.id];
4175
+ if (!bspItems?.length) return;
4176
+ const newShow = item._show === false ? true : false;
4177
+ item._show = newShow;
4178
+ bspItems.forEach(bspItem => {
4179
+ bspItem._visible = newShow;
4180
+ if (bspItem.isSimple) {
4181
+ // 简单组合:直接控制 base 模型的 show
4182
+ if (bspItem.base) {
4183
+ bspItem.base.show = newShow;
4184
+ }
4185
+ } else {
4186
+ // 运算组合:通过 _addedPrimitives 控制显隐
4187
+ bspItem._addedPrimitives?.forEach(primitive => {
4188
+ if (primitive && primitive.show !== undefined) {
4189
+ primitive.show = newShow;
4190
+ }
4191
+ });
4192
+ }
4193
+ });
4194
+ }
4195
+
4196
+ // 定位到数据点
4197
+ function zoomToDataPoint() {
4198
+ viewModel?._zoomToDataPoint();
4199
+ }
4200
+
4201
+ // 预览/生成时隐藏所有辅助内容(场景模型 + UI 状态同步),只显示最终模型
4202
+ function hideAllAuxiliaryForPreview() {
4203
+ if (!viewModel) return;
4204
+ // 1. 简单几何模型隐藏 + checkbox 取消选中(同步 UI)
4205
+ formItem.showOperationModel = false;
4206
+ addGroupShapeBtn('showOperationModel');
4207
+ // 2. confirmed 模型隐藏 + 组合列表显隐图标样式同步
4208
+ viewModel._setConfirmedBspVisible(false);
4209
+ groupShapes.value.forEach(item => {
4210
+ item._show = false;
4211
+ });
4212
+ // 3. 模板卸载(从场景移除)+ 模板列表取消选中 + 同步下拉列表
4213
+ viewModel._unloadTemplateSymbol();
4214
+ selectedIndex_group.value = [];
4215
+ viewModel._selectedTemplateIndices?.clear();
4216
+ viewModel._selectedTemplateModelsMap?.clear();
4217
+ groupShapesArr.value = viewModel._getSimplifiedGroupShapes();
4218
+ }
4219
+
4220
+ // 预览最终复杂模型
4221
+ function handlePreviewComplexModel() {
4222
+ if (!viewModel || !groupShapes.value.length) return;
4223
+ // 隐藏所有辅助内容,只显示预览结果
4224
+ hideAllAuxiliaryForPreview();
4225
+ // 预览
4226
+ viewModel._previewComplexModel(groupShapes.value, 'complexGeometrySymbol');
4227
+ }
4228
+
4229
+ // 清除预览及组合列表
4230
+ function handleClearPreview() {
4231
+ // 清除预览的最终复杂模型
4232
+ viewModel?._clearComplexPreview();
4233
+ // 清除所有已确认的 BSP 组合模型
4234
+ viewModel?._clearAllConfirmedBsp();
4235
+ // 清除组合列表
4236
+ groupShapes.value = [];
4237
+ // 清除模板选中状态
4238
+ selectedIndex_group.value = [];
4239
+ viewModel?._selectedTemplateIndices?.clear();
4240
+ viewModel?._selectedTemplateModelsMap?.clear();
4241
+ viewModel?._unloadTemplateSymbol();
4242
+ // 同步更新 groupShapesArr,移除已卸载的模板项(保留 loadFiles 加载的简单几何项)
4243
+ // 避免下拉列表残留已失效的模板项导致后续组合失败
4244
+ if (viewModel) {
4245
+ groupShapesArr.value = viewModel._getSimplifiedGroupShapes();
4246
+ }
4247
+ }
4248
+
4249
+ // 打开保存模板弹框
4250
+ function handleSaveTemplate() {
4251
+ templateSaveData.name = '';
4252
+ templateSaveData.img = '';
4253
+ isShowSaveTemplate.value = true;
4254
+ }
4255
+
4256
+ // 保存模板数据
4257
+ async function saveTemplateData() {
4258
+ if (!templateSaveData.name || !viewModel) return;
4259
+ try {
4260
+ const groupJson = viewModel.saveTemplateData(templateSaveData.name, groupShapes.value);
4261
+ if (groupJson) {
4262
+ const templateItem = {
4263
+ name: templateSaveData.name,
4264
+ icon: templateSaveData.img ? (0, _vue.markRaw)({
4265
+ template: templateSaveData.img
4266
+ }) : (0, _vue.markRaw)(_client_icons_vue.PrintImage),
4267
+ groupJson: groupJson
4268
+ };
4269
+ groupSymbols.value.push(templateItem);
4270
+ // 服务端模式:上传模板到服务器
4271
+ if (formItem.isUseServer && _api) {
4272
+ const uploadRes = await _api.uploadJsonData({
4273
+ filePath: '/sceneView/buildModel/complexGeometryTemplate',
4274
+ fileName: templateSaveData.name,
4275
+ jsonData: groupJson
4276
+ });
4277
+ if (uploadRes) {
4278
+ (0, _message.default)({
4279
+ message: '模板上传成功!',
4280
+ type: 'success'
4281
+ });
4282
+ }
4283
+ } else {
4284
+ // 非服务端模式:发出上传事件,由父组件处理
4285
+ emit("uploadComplexGeometryTemplate", templateItem);
4286
+ }
4287
+ }
4288
+ isShowSaveTemplate.value = false;
4289
+ } catch (error) {
4290
+ console.error("保存模板失败:", error);
4291
+ }
4292
+ }
4293
+
4294
+ /**
4295
+ * @description 模板缩略图上传,读取为 base64 写入表单
4296
+ * @param {Object} file 上传的图片文件对象
4297
+ */
4298
+ function handleTemplateAvatarSuccess(file) {
4299
+ const reader = new FileReader();
4300
+ reader.onload = function (e) {
4301
+ templateSaveData.img = e.target.result;
4302
+ };
4303
+ reader.readAsDataURL(file.raw);
4304
+ }
4305
+
2084
4306
  // 销毁
2085
4307
  (0, _vue.onBeforeUnmount)(() => {
2086
4308
  clear();
2087
4309
  });
4310
+ // 导出当前所有模型数据
2088
4311
  function exportModels() {
2089
4312
  return viewModel.exportModels();
2090
4313
  }
4314
+ /**
4315
+ * @description 导入模型数据
4316
+ * @param {Array} jsons 模型 JSON 数组
4317
+ * @returns {*} 导入结果
4318
+ */
2091
4319
  function importModels(jsons) {
2092
4320
  return viewModel.importModels(jsons);
2093
4321
  }
@@ -2111,6 +4339,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2111
4339
  const _component_kq_button = (0, _vue.resolveComponent)("kq-button");
2112
4340
  const _component_kq_scrollbar = (0, _vue.resolveComponent)("kq-scrollbar");
2113
4341
  const _component_kq_slider = (0, _vue.resolveComponent)("kq-slider");
4342
+ const _component_kq_checkbox = (0, _vue.resolveComponent)("kq-checkbox");
2114
4343
  const _component_kq_collapse = (0, _vue.resolveComponent)("kq-collapse");
2115
4344
  const _component_kq_form = (0, _vue.resolveComponent)("kq-form");
2116
4345
  const _component_kq_upload = (0, _vue.resolveComponent)("kq-upload");
@@ -2202,7 +4431,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2202
4431
  _: 1 /* STABLE */
2203
4432
  }, 8 /* PROPS */, ["label"]), (0, _vue.createVNode)(_component_kq_collapse, {
2204
4433
  modelValue: (0, _vue.unref)(formItem).collapseValue,
2205
- "onUpdate:modelValue": _cache[224] || (_cache[224] = $event => (0, _vue.unref)(formItem).collapseValue = $event),
4434
+ "onUpdate:modelValue": _cache[245] || (_cache[245] = $event => (0, _vue.unref)(formItem).collapseValue = $event),
2206
4435
  accordion: ""
2207
4436
  }, {
2208
4437
  default: (0, _vue.withCtx)(() => [(0, _vue.createCommentVNode)(" 通用 "), (0, _vue.createVNode)(_component_kq_collapse_item, {
@@ -2221,7 +4450,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2221
4450
  default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
2222
4451
  span: 8
2223
4452
  }, {
2224
- default: (0, _vue.withCtx)(() => [_cache[228] || (_cache[228] = (0, _vue.createElementVNode)("span", {
4453
+ default: (0, _vue.withCtx)(() => [_cache[260] || (_cache[260] = (0, _vue.createElementVNode)("span", {
2225
4454
  class: "spanTile"
2226
4455
  }, "X:", -1 /* CACHED */)), (0, _vue.createVNode)(_component_kq_input_number, {
2227
4456
  modelValue: (0, _vue.unref)(formItem).offsetX,
@@ -2233,11 +4462,11 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2233
4462
  onChange: _cache[4] || (_cache[4] = $event => paramsChanged('offset'))
2234
4463
  }, null, 8 /* PROPS */, ["modelValue", "min", "max", "step"])]),
2235
4464
  _: 1 /* STABLE */,
2236
- __: [228]
4465
+ __: [260]
2237
4466
  }), (0, _vue.createVNode)(_component_kq_col, {
2238
4467
  span: 8
2239
4468
  }, {
2240
- default: (0, _vue.withCtx)(() => [_cache[229] || (_cache[229] = (0, _vue.createElementVNode)("span", {
4469
+ default: (0, _vue.withCtx)(() => [_cache[261] || (_cache[261] = (0, _vue.createElementVNode)("span", {
2241
4470
  class: "spanTile"
2242
4471
  }, "Y:", -1 /* CACHED */)), (0, _vue.createVNode)(_component_kq_input_number, {
2243
4472
  modelValue: (0, _vue.unref)(formItem).offsetY,
@@ -2249,11 +4478,11 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2249
4478
  onChange: _cache[6] || (_cache[6] = $event => paramsChanged('offset'))
2250
4479
  }, null, 8 /* PROPS */, ["modelValue", "min", "max", "step"])]),
2251
4480
  _: 1 /* STABLE */,
2252
- __: [229]
4481
+ __: [261]
2253
4482
  }), (0, _vue.createVNode)(_component_kq_col, {
2254
4483
  span: 8
2255
4484
  }, {
2256
- default: (0, _vue.withCtx)(() => [_cache[230] || (_cache[230] = (0, _vue.createElementVNode)("span", {
4485
+ default: (0, _vue.withCtx)(() => [_cache[262] || (_cache[262] = (0, _vue.createElementVNode)("span", {
2257
4486
  class: "spanTile"
2258
4487
  }, "Z:", -1 /* CACHED */)), (0, _vue.createVNode)(_component_kq_input_number, {
2259
4488
  modelValue: (0, _vue.unref)(formItem).offsetZ,
@@ -2265,7 +4494,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2265
4494
  onChange: _cache[8] || (_cache[8] = $event => paramsChanged('offset'))
2266
4495
  }, null, 8 /* PROPS */, ["modelValue", "min", "max", "step"])]),
2267
4496
  _: 1 /* STABLE */,
2268
- __: [230]
4497
+ __: [262]
2269
4498
  })]),
2270
4499
  _: 1 /* STABLE */
2271
4500
  })]),
@@ -2709,7 +4938,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2709
4938
  key: 1,
2710
4939
  span: 8
2711
4940
  }, {
2712
- default: (0, _vue.withCtx)(() => [_cache[231] || (_cache[231] = (0, _vue.createElementVNode)("span", {
4941
+ default: (0, _vue.withCtx)(() => [_cache[263] || (_cache[263] = (0, _vue.createElementVNode)("span", {
2713
4942
  class: "spanTile"
2714
4943
  }, "Y:", -1 /* CACHED */)), (0, _vue.createVNode)(_component_kq_input_number, {
2715
4944
  modelValue: (0, _vue.unref)(formItem).scaleY,
@@ -2721,12 +4950,12 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2721
4950
  onChange: _cache[36] || (_cache[36] = $event => paramsChanged('scale'))
2722
4951
  }, null, 8 /* PROPS */, ["modelValue", "min", "max", "step"])]),
2723
4952
  _: 1 /* STABLE */,
2724
- __: [231]
4953
+ __: [263]
2725
4954
  })) : (0, _vue.createCommentVNode)("v-if", true), mode.value == 'edit' ? ((0, _vue.openBlock)(), (0, _vue.createBlock)(_component_kq_col, {
2726
4955
  key: 2,
2727
4956
  span: 8
2728
4957
  }, {
2729
- default: (0, _vue.withCtx)(() => [_cache[232] || (_cache[232] = (0, _vue.createElementVNode)("span", {
4958
+ default: (0, _vue.withCtx)(() => [_cache[264] || (_cache[264] = (0, _vue.createElementVNode)("span", {
2730
4959
  class: "spanTile"
2731
4960
  }, "Z:", -1 /* CACHED */)), (0, _vue.createVNode)(_component_kq_input_number, {
2732
4961
  modelValue: (0, _vue.unref)(formItem).scaleZ,
@@ -2738,7 +4967,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2738
4967
  onChange: _cache[38] || (_cache[38] = $event => paramsChanged('scale'))
2739
4968
  }, null, 8 /* PROPS */, ["modelValue", "min", "max", "step"])]),
2740
4969
  _: 1 /* STABLE */,
2741
- __: [232]
4970
+ __: [264]
2742
4971
  })) : (0, _vue.createCommentVNode)("v-if", true)]),
2743
4972
  _: 1 /* STABLE */
2744
4973
  })]),
@@ -2804,7 +5033,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2804
5033
  }, 8 /* PROPS */, ["title", "style"]), [[_vue.vShow, !(0, _vue.unref)(modelingTypes) || (0, _vue.unref)(modelingTypes) == 'dynamicSymbol']]), (0, _vue.createCommentVNode)(" 几何符号 "), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_collapse_item, {
2805
5034
  title: (0, _vue.unref)(locale).webgl.geometrySymbol,
2806
5035
  name: "geometrySymbol",
2807
- style: (0, _vue.normalizeStyle)((0, _vue.unref)(modelingTypes) == 'geometrySymbol' ? 'margin-bottom: 0px' : '')
5036
+ style: (0, _vue.normalizeStyle)((0, _vue.unref)(modelingTypes) == 'geometrySymbol' || (0, _vue.unref)(modelingTypes) == 'complexGeometrySymbol' ? 'margin-bottom: 0px' : '')
2808
5037
  }, {
2809
5038
  default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
2810
5039
  default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
@@ -2842,7 +5071,9 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
2842
5071
  _: 1 /* STABLE */
2843
5072
  }, 8 /* PROPS */, ["label"])]),
2844
5073
  _: 1 /* STABLE */
2845
- }, 512 /* NEED_PATCH */), [[_vue.vShow, mode.value == 'add']]), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
5074
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, mode.value == 'add']]), (0, _vue.createCommentVNode)(" 简单几何参数:编辑模式下的复杂几何符号隐藏 "), !isEditComplexGeometry.value ? ((0, _vue.openBlock)(), (0, _vue.createElementBlock)(_vue.Fragment, {
5075
+ key: 0
5076
+ }, [(0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
2846
5077
  default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
2847
5078
  label: (0, _vue.unref)(locale).webgl.width + '(m)'
2848
5079
  }, {
@@ -4642,7 +6873,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
4642
6873
  style: {
4643
6874
  "width": "100%"
4644
6875
  },
4645
- placeholder: "[{x: 0, y: -10},{x: 2.469, y: -3.399},{x: 9.511, y: -3.090},{x: 3.995, y: 1.298}]"
6876
+ placeholder: "[{\"x\": 0, \"y\": -10},{\"x\": 2.469, \"y\": -3.399},{\"x\": 9.511, \"y\": -3.090},{\"x\": 3.995, \"y\": 1.298}]"
4646
6877
  }, null, 8 /* PROPS */, ["modelValue"])]),
4647
6878
  _: 1 /* STABLE */
4648
6879
  })]),
@@ -4769,7 +7000,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
4769
7000
  _: 1 /* STABLE */
4770
7001
  }, 8 /* PROPS */, ["label"])]),
4771
7002
  _: 1 /* STABLE */
4772
- }, 512 /* NEED_PATCH */), [[_vue.vShow, ['PMCustomPointModel'].includes((0, _vue.unref)(currentItemGeometry).value)]]), (0, _vue.createVNode)(_component_kq_row, null, {
7003
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, ['PMCustomPointModel'].includes((0, _vue.unref)(currentItemGeometry).value)]]), (0, _vue.createCommentVNode)(" 旋转 "), (0, _vue.createVNode)(_component_kq_row, null, {
4773
7004
  default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
4774
7005
  label: (0, _vue.unref)(locale).webgl.rotate + '(°)'
4775
7006
  }, {
@@ -4809,8 +7040,469 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
4809
7040
  _: 1 /* STABLE */
4810
7041
  }, 8 /* PROPS */, ["label"])]),
4811
7042
  _: 1 /* STABLE */
4812
- }), (0, _vue.withDirectives)((0, _vue.createElementVNode)("div", _hoisted_26, [(0, _vue.createVNode)(_component_kq_button, {
4813
- onClick: _cache[223] || (_cache[223] = (0, _vue.withModifiers)($event => generated('geometrySymbol'), ["stop"])),
7043
+ })], 64 /* STABLE_FRAGMENT */)) : (0, _vue.createCommentVNode)("v-if", true), (0, _vue.createCommentVNode)(" 复杂几何符号参数 "), mode.value == 'add' ? ((0, _vue.openBlock)(), (0, _vue.createBlock)(_component_kq_row, {
7044
+ key: 1,
7045
+ style: {
7046
+ "margin-bottom": "8px"
7047
+ }
7048
+ }, {
7049
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, {
7050
+ style: {
7051
+ "display": "flex"
7052
+ }
7053
+ }, {
7054
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7055
+ span: 7
7056
+ }, {
7057
+ default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_checkbox, {
7058
+ modelValue: (0, _vue.unref)(formItem).isComplexGeometry,
7059
+ "onUpdate:modelValue": _cache[223] || (_cache[223] = $event => (0, _vue.unref)(formItem).isComplexGeometry = $event),
7060
+ onChange: _cache[224] || (_cache[224] = $event => paramsChanged('isComplexGeometry'))
7061
+ }, {
7062
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.isComplexGeometry), 1 /* TEXT */)]),
7063
+ _: 1 /* STABLE */
7064
+ }, 8 /* PROPS */, ["modelValue"]), [[_vue.vShow, mode.value == 'add']])]),
7065
+ _: 1 /* STABLE */
7066
+ }), (0, _vue.createVNode)(_component_kq_col, {
7067
+ span: 3,
7068
+ style: {
7069
+ "text-align": "right"
7070
+ }
7071
+ }, {
7072
+ default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_checkbox, {
7073
+ modelValue: (0, _vue.unref)(formItem).showEditModel,
7074
+ "onUpdate:modelValue": _cache[225] || (_cache[225] = $event => (0, _vue.unref)(formItem).showEditModel = $event),
7075
+ onChange: _cache[226] || (_cache[226] = $event => addGroupShapeBtn('showEditModel'))
7076
+ }, {
7077
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.editType), 1 /* TEXT */)]),
7078
+ _: 1 /* STABLE */
7079
+ }, 8 /* PROPS */, ["modelValue"]), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry]])]),
7080
+ _: 1 /* STABLE */
7081
+ }), (0, _vue.createVNode)(_component_kq_col, {
7082
+ span: 5,
7083
+ style: {
7084
+ "text-align": "right"
7085
+ }
7086
+ }, {
7087
+ default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_checkbox, {
7088
+ modelValue: (0, _vue.unref)(formItem).showOperationModel,
7089
+ "onUpdate:modelValue": _cache[227] || (_cache[227] = $event => (0, _vue.unref)(formItem).showOperationModel = $event),
7090
+ onChange: _cache[228] || (_cache[228] = $event => addGroupShapeBtn('showOperationModel'))
7091
+ }, {
7092
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.showOperationModel), 1 /* TEXT */)]),
7093
+ _: 1 /* STABLE */
7094
+ }, 8 /* PROPS */, ["modelValue"]), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry]])]),
7095
+ _: 1 /* STABLE */
7096
+ }), (0, _vue.createVNode)(_component_kq_col, {
7097
+ span: 9,
7098
+ style: {
7099
+ "text-align": "right"
7100
+ }
7101
+ }, {
7102
+ default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_button, {
7103
+ onClick: _cache[229] || (_cache[229] = (0, _vue.withModifiers)($event => addGroupShapeBtn('loadFiles'), ["stop"])),
7104
+ title: (0, _vue.unref)(locale).webgl.loadFiles,
7105
+ type: "primary",
7106
+ size: "small"
7107
+ }, {
7108
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.loadFiles), 1 /* TEXT */)]),
7109
+ _: 1 /* STABLE */
7110
+ }, 8 /* PROPS */, ["title"]), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry]]), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_button, {
7111
+ onClick: _cache[230] || (_cache[230] = $event => addGroupShapeBtn('clearGroupShapes')),
7112
+ title: (0, _vue.unref)(locale).common.clear,
7113
+ size: "small"
7114
+ }, {
7115
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(locale).common.clear), 1 /* TEXT */)]),
7116
+ _: 1 /* STABLE */
7117
+ }, 8 /* PROPS */, ["title"]), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry]])]),
7118
+ _: 1 /* STABLE */
7119
+ })]),
7120
+ _: 1 /* STABLE */
7121
+ })]),
7122
+ _: 1 /* STABLE */
7123
+ })) : (0, _vue.createCommentVNode)("v-if", true), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
7124
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
7125
+ label: (0, _vue.unref)(locale).webgl.groupTemplate
7126
+ }, {
7127
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, {
7128
+ style: {
7129
+ "display": "flex"
7130
+ }
7131
+ }, {
7132
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7133
+ span: 24
7134
+ }, {
7135
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_scrollbar, null, {
7136
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", {
7137
+ class: "scrollbar-flex-content",
7138
+ style: (0, _vue.normalizeStyle)(0 < groupSymbols.value?.length > 5 ? 'margin-bottom: 8px' : '')
7139
+ }, [((0, _vue.openBlock)(true), (0, _vue.createElementBlock)(_vue.Fragment, null, (0, _vue.renderList)(groupSymbols.value, (image, index) => {
7140
+ return (0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", {
7141
+ key: index,
7142
+ title: image.name,
7143
+ onClick: $event => selectGroupSymbol(index, image),
7144
+ style: (0, _vue.normalizeStyle)({
7145
+ margin: '0 2px 0 4px',
7146
+ cursor: 'pointer',
7147
+ display: 'inline-flex',
7148
+ alignItems: 'center',
7149
+ justifyContent: 'center',
7150
+ width: '28px',
7151
+ height: '28px',
7152
+ border: (0, _vue.unref)(selectedIndex_group).includes(index) ? '1px solid ' + 'var(--kq-color-primary, #409eff)' : '1px solid #d9d9d9',
7153
+ borderRadius: '4px',
7154
+ backgroundColor: (0, _vue.unref)(selectedIndex_group).includes(index) ? 'var(--kq-color-primary-light-9, #ecf5ff)' : '#fff',
7155
+ transition: 'all 0.2s'
7156
+ })
7157
+ }, [image.icon?.template ? ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("img", {
7158
+ key: 0,
7159
+ src: image.icon.template,
7160
+ style: {
7161
+ "width": "16px",
7162
+ "height": "16px",
7163
+ "object-fit": "contain"
7164
+ }
7165
+ }, null, 8 /* PROPS */, _hoisted_27)) : ((0, _vue.openBlock)(), (0, _vue.createBlock)(_component_kq_icon, {
7166
+ key: 1,
7167
+ size: 16
7168
+ }, {
7169
+ default: (0, _vue.withCtx)(() => [((0, _vue.openBlock)(), (0, _vue.createBlock)((0, _vue.resolveDynamicComponent)(image.icon)))]),
7170
+ _: 2 /* DYNAMIC */
7171
+ }, 1024 /* DYNAMIC_SLOTS */))], 12 /* STYLE, PROPS */, _hoisted_26);
7172
+ }), 128 /* KEYED_FRAGMENT */))], 4 /* STYLE */)]),
7173
+ _: 1 /* STABLE */
7174
+ })]),
7175
+ _: 1 /* STABLE */
7176
+ })]),
7177
+ _: 1 /* STABLE */
7178
+ })]),
7179
+ _: 1 /* STABLE */
7180
+ }, 8 /* PROPS */, ["label"])]),
7181
+ _: 1 /* STABLE */
7182
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry && !isEditComplexGeometry.value]]), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
7183
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
7184
+ label: (0, _vue.unref)(locale).webgl.groupList
7185
+ }, {
7186
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, {
7187
+ style: {
7188
+ "display": "flex"
7189
+ }
7190
+ }, {
7191
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7192
+ span: 24
7193
+ }, {
7194
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_28, [(0, _vue.createVNode)(_component_kq_icon, {
7195
+ size: 18,
7196
+ style: {
7197
+ "color": "#67C23A"
7198
+ },
7199
+ title: (0, _vue.unref)(locale).webgl.addGroupShape,
7200
+ class: "addGroup",
7201
+ onClick: _cache[231] || (_cache[231] = $event => addGroupShape())
7202
+ }, {
7203
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconAmplify))]),
7204
+ _: 1 /* STABLE */
7205
+ }, 8 /* PROPS */, ["title"])])]),
7206
+ _: 1 /* STABLE */
7207
+ })]),
7208
+ _: 1 /* STABLE */
7209
+ })]),
7210
+ _: 1 /* STABLE */
7211
+ }, 8 /* PROPS */, ["label"])]),
7212
+ _: 1 /* STABLE */
7213
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry && !isEditComplexGeometry.value]]), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
7214
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_scrollbar, {
7215
+ "max-height": "170px",
7216
+ ref: "scrollcar_ref",
7217
+ style: {
7218
+ "width": "100%"
7219
+ }
7220
+ }, {
7221
+ default: (0, _vue.withCtx)(() => [(0, _vue.createCommentVNode)(" 添加关键容器:强制内部使用栅格布局 "), (0, _vue.createElementVNode)("div", _hoisted_29, [((0, _vue.openBlock)(true), (0, _vue.createElementBlock)(_vue.Fragment, null, (0, _vue.renderList)(groupShapes.value, (item, index) => {
7222
+ return (0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", {
7223
+ key: index,
7224
+ class: "render-item"
7225
+ }, [(0, _vue.createVNode)(_component_kq_row, {
7226
+ justify: "space-between",
7227
+ align: "middle"
7228
+ }, {
7229
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7230
+ span: 19
7231
+ }, {
7232
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_30, [(0, _vue.createVNode)(_component_kq_col, {
7233
+ span: 5
7234
+ }, {
7235
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_31, (0, _vue.toDisplayString)(`${item.groupType}${item.index}`), 1 /* TEXT */)]),
7236
+ _: 2 /* DYNAMIC */
7237
+ }, 1024 /* DYNAMIC_SLOTS */), (0, _vue.createVNode)(_component_kq_col, {
7238
+ span: 7,
7239
+ class: "colClass"
7240
+ }, {
7241
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("span", null, (0, _vue.toDisplayString)(item.name), 1 /* TEXT */)]),
7242
+ _: 2 /* DYNAMIC */
7243
+ }, 1024 /* DYNAMIC_SLOTS */), (0, _vue.createVNode)(_component_kq_col, {
7244
+ span: 1,
7245
+ class: "colClass"
7246
+ }, {
7247
+ default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_icon, {
7248
+ size: "18",
7249
+ style: {
7250
+ "display": "inline-block"
7251
+ }
7252
+ }, {
7253
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconArrow))]),
7254
+ _: 2 /* DYNAMIC */
7255
+ }, 1536 /* NEED_PATCH, DYNAMIC_SLOTS */), [[_vue.vShow, item.operationName]])]),
7256
+ _: 2 /* DYNAMIC */
7257
+ }, 1024 /* DYNAMIC_SLOTS */), (0, _vue.createVNode)(_component_kq_col, {
7258
+ span: 7,
7259
+ class: "colClass"
7260
+ }, {
7261
+ default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createElementVNode)("span", null, (0, _vue.toDisplayString)(item.operationName), 513 /* TEXT, NEED_PATCH */), [[_vue.vShow, item.operationName]])]),
7262
+ _: 2 /* DYNAMIC */
7263
+ }, 1024 /* DYNAMIC_SLOTS */), (0, _vue.createVNode)(_component_kq_col, {
7264
+ span: 3,
7265
+ class: "colClass"
7266
+ }, {
7267
+ default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_button, {
7268
+ class: "build-model-btn-add isActive",
7269
+ style: {
7270
+ "margin": "0 2px 0 4px",
7271
+ "cursor": "default"
7272
+ }
7273
+ }, {
7274
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_icon, {
7275
+ size: 16
7276
+ }, {
7277
+ default: (0, _vue.withCtx)(() => [(0, _vue.withDirectives)((0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconIntersect), null, null, 512 /* NEED_PATCH */), [[_vue.vShow, item.operationMethod == 0]]), (0, _vue.withDirectives)((0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconMerge), null, null, 512 /* NEED_PATCH */), [[_vue.vShow, item.operationMethod == 1]]), (0, _vue.withDirectives)((0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconDifference), null, null, 512 /* NEED_PATCH */), [[_vue.vShow, item.operationMethod == 2]])]),
7278
+ _: 2 /* DYNAMIC */
7279
+ }, 1024 /* DYNAMIC_SLOTS */)]),
7280
+ _: 2 /* DYNAMIC */
7281
+ }, 1536 /* NEED_PATCH, DYNAMIC_SLOTS */), [[_vue.vShow, item.operationName]])]),
7282
+ _: 2 /* DYNAMIC */
7283
+ }, 1024 /* DYNAMIC_SLOTS */)])]),
7284
+ _: 2 /* DYNAMIC */
7285
+ }, 1024 /* DYNAMIC_SLOTS */), (0, _vue.createVNode)(_component_kq_col, {
7286
+ span: 3,
7287
+ class: (0, _vue.normalizeClass)(["render-item-btn", item._show !== false ? 'isSetting' : ''])
7288
+ }, {
7289
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_icon, {
7290
+ size: "16",
7291
+ class: "kq-row-icon",
7292
+ onClick: $event => handleViewGroupShape(item, index),
7293
+ title: (0, _vue.unref)(t)('webgl.visibility')
7294
+ }, {
7295
+ default: (0, _vue.withCtx)(() => [item._show !== false ? ((0, _vue.openBlock)(), (0, _vue.createBlock)((0, _vue.unref)(_iconsVue.View), {
7296
+ key: 0
7297
+ })) : ((0, _vue.openBlock)(), (0, _vue.createBlock)((0, _vue.unref)(_iconsVue.Hide), {
7298
+ key: 1
7299
+ }))]),
7300
+ _: 2 /* DYNAMIC */
7301
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["onClick", "title"])]),
7302
+ _: 2 /* DYNAMIC */
7303
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["class"]), (0, _vue.createCommentVNode)(" <kq-col :span=\"1\" class=\"render-item-btn\">\r\n <kq-icon size=\"16\" class=\"kq-row-icon\" @click=\"handleSettingGroupShape(item)\" :title=\"t('webgl.settingTilte')\">\r\n <IconSetting />\r\n </kq-icon>\r\n </kq-col> "), (0, _vue.createVNode)(_component_kq_col, {
7304
+ span: 2,
7305
+ class: "render-item-btn isDelete"
7306
+ }, {
7307
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_icon, {
7308
+ size: "16",
7309
+ class: "kq-row-icon",
7310
+ onClick: $event => handleDeleteGroupShape(index),
7311
+ title: (0, _vue.unref)(t)('webgl.deleteRow')
7312
+ }, {
7313
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_iconsVue.Remove))]),
7314
+ _: 2 /* DYNAMIC */
7315
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["onClick", "title"])]),
7316
+ _: 2 /* DYNAMIC */
7317
+ }, 1024 /* DYNAMIC_SLOTS */)]),
7318
+ _: 2 /* DYNAMIC */
7319
+ }, 1024 /* DYNAMIC_SLOTS */)]);
7320
+ }), 128 /* KEYED_FRAGMENT */))])]),
7321
+ _: 1 /* STABLE */
7322
+ }, 512 /* NEED_PATCH */)]),
7323
+ _: 1 /* STABLE */
7324
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry && !isEditComplexGeometry.value]]), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, {
7325
+ style: {
7326
+ "display": "flex",
7327
+ "margin-bottom": "8px"
7328
+ }
7329
+ }, {
7330
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7331
+ style: {
7332
+ "text-align": "left"
7333
+ },
7334
+ span: 4
7335
+ }, {
7336
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_icon, {
7337
+ size: 18,
7338
+ title: (0, _vue.unref)(locale).webgl.zoomBtn,
7339
+ style: {
7340
+ "cursor": "pointer"
7341
+ },
7342
+ onClick: zoomToDataPoint
7343
+ }, {
7344
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconHome))]),
7345
+ _: 1 /* STABLE */
7346
+ }, 8 /* PROPS */, ["title"])]),
7347
+ _: 1 /* STABLE */
7348
+ }), (0, _vue.createVNode)(_component_kq_col, {
7349
+ style: {
7350
+ "text-align": "right"
7351
+ },
7352
+ span: 20
7353
+ }, {
7354
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_button, {
7355
+ title: (0, _vue.unref)(locale).webgl.preview,
7356
+ type: "primary",
7357
+ size: "small",
7358
+ disabled: !groupShapes.value.length,
7359
+ onClick: handlePreviewComplexModel
7360
+ }, {
7361
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.preview), 1 /* TEXT */)]),
7362
+ _: 1 /* STABLE */
7363
+ }, 8 /* PROPS */, ["title", "disabled"]), (0, _vue.createVNode)(_component_kq_button, {
7364
+ title: (0, _vue.unref)(locale).webgl.save,
7365
+ type: "primary",
7366
+ size: "small",
7367
+ disabled: !canSaveTemplate.value,
7368
+ onClick: handleSaveTemplate
7369
+ }, {
7370
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.save), 1 /* TEXT */)]),
7371
+ _: 1 /* STABLE */
7372
+ }, 8 /* PROPS */, ["title", "disabled"]), (0, _vue.createVNode)(_component_kq_button, {
7373
+ title: (0, _vue.unref)(locale).common.clear,
7374
+ size: "small",
7375
+ disabled: !groupShapes.value.length && !(0, _vue.unref)(selectedIndex_group).length,
7376
+ onClick: handleClearPreview
7377
+ }, {
7378
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(locale).common.clear), 1 /* TEXT */)]),
7379
+ _: 1 /* STABLE */
7380
+ }, 8 /* PROPS */, ["title", "disabled"])]),
7381
+ _: 1 /* STABLE */
7382
+ })]),
7383
+ _: 1 /* STABLE */
7384
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry && !isEditComplexGeometry.value]]), (0, _vue.createCommentVNode)(" 复杂几何旋转参数 "), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
7385
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
7386
+ label: (0, _vue.unref)(locale).webgl.heading
7387
+ }, {
7388
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, {
7389
+ style: {
7390
+ "display": "flex"
7391
+ }
7392
+ }, {
7393
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7394
+ span: 16
7395
+ }, {
7396
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_slider, {
7397
+ modelValue: (0, _vue.unref)(formItem).heading,
7398
+ "onUpdate:modelValue": _cache[232] || (_cache[232] = $event => (0, _vue.unref)(formItem).heading = $event),
7399
+ min: 0,
7400
+ max: 360,
7401
+ step: 1,
7402
+ onChange: _cache[233] || (_cache[233] = $event => paramsChanged('heading'))
7403
+ }, null, 8 /* PROPS */, ["modelValue"])]),
7404
+ _: 1 /* STABLE */
7405
+ }), (0, _vue.createVNode)(_component_kq_col, {
7406
+ span: 8
7407
+ }, {
7408
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_input_number, {
7409
+ modelValue: (0, _vue.unref)(formItem).heading,
7410
+ "onUpdate:modelValue": _cache[234] || (_cache[234] = $event => (0, _vue.unref)(formItem).heading = $event),
7411
+ min: 0,
7412
+ max: 360,
7413
+ step: 1,
7414
+ "controls-position": "right",
7415
+ onChange: _cache[235] || (_cache[235] = $event => paramsChanged('heading'))
7416
+ }, null, 8 /* PROPS */, ["modelValue"])]),
7417
+ _: 1 /* STABLE */
7418
+ })]),
7419
+ _: 1 /* STABLE */
7420
+ })]),
7421
+ _: 1 /* STABLE */
7422
+ }, 8 /* PROPS */, ["label"])]),
7423
+ _: 1 /* STABLE */
7424
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry]]), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
7425
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
7426
+ label: (0, _vue.unref)(locale).webgl.pitch
7427
+ }, {
7428
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, {
7429
+ style: {
7430
+ "display": "flex"
7431
+ }
7432
+ }, {
7433
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7434
+ span: 16
7435
+ }, {
7436
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_slider, {
7437
+ modelValue: (0, _vue.unref)(formItem).pitch,
7438
+ "onUpdate:modelValue": _cache[236] || (_cache[236] = $event => (0, _vue.unref)(formItem).pitch = $event),
7439
+ min: 0,
7440
+ max: 360,
7441
+ step: 1,
7442
+ onChange: _cache[237] || (_cache[237] = $event => paramsChanged('pitch'))
7443
+ }, null, 8 /* PROPS */, ["modelValue"])]),
7444
+ _: 1 /* STABLE */
7445
+ }), (0, _vue.createVNode)(_component_kq_col, {
7446
+ span: 8
7447
+ }, {
7448
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_input_number, {
7449
+ modelValue: (0, _vue.unref)(formItem).pitch,
7450
+ "onUpdate:modelValue": _cache[238] || (_cache[238] = $event => (0, _vue.unref)(formItem).pitch = $event),
7451
+ min: 0,
7452
+ max: 360,
7453
+ step: 1,
7454
+ "controls-position": "right",
7455
+ onChange: _cache[239] || (_cache[239] = $event => paramsChanged('pitch'))
7456
+ }, null, 8 /* PROPS */, ["modelValue"])]),
7457
+ _: 1 /* STABLE */
7458
+ })]),
7459
+ _: 1 /* STABLE */
7460
+ })]),
7461
+ _: 1 /* STABLE */
7462
+ }, 8 /* PROPS */, ["label"])]),
7463
+ _: 1 /* STABLE */
7464
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry]]), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
7465
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
7466
+ label: (0, _vue.unref)(locale).webgl.roll
7467
+ }, {
7468
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, {
7469
+ style: {
7470
+ "display": "flex"
7471
+ }
7472
+ }, {
7473
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7474
+ span: 16
7475
+ }, {
7476
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_slider, {
7477
+ modelValue: (0, _vue.unref)(formItem).roll,
7478
+ "onUpdate:modelValue": _cache[240] || (_cache[240] = $event => (0, _vue.unref)(formItem).roll = $event),
7479
+ min: 0,
7480
+ max: 360,
7481
+ step: 1,
7482
+ onChange: _cache[241] || (_cache[241] = $event => paramsChanged('roll'))
7483
+ }, null, 8 /* PROPS */, ["modelValue"])]),
7484
+ _: 1 /* STABLE */
7485
+ }), (0, _vue.createVNode)(_component_kq_col, {
7486
+ span: 8
7487
+ }, {
7488
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_input_number, {
7489
+ modelValue: (0, _vue.unref)(formItem).roll,
7490
+ "onUpdate:modelValue": _cache[242] || (_cache[242] = $event => (0, _vue.unref)(formItem).roll = $event),
7491
+ min: 0,
7492
+ max: 360,
7493
+ step: 1,
7494
+ "controls-position": "right",
7495
+ onChange: _cache[243] || (_cache[243] = $event => paramsChanged('roll'))
7496
+ }, null, 8 /* PROPS */, ["modelValue"])]),
7497
+ _: 1 /* STABLE */
7498
+ })]),
7499
+ _: 1 /* STABLE */
7500
+ })]),
7501
+ _: 1 /* STABLE */
7502
+ }, 8 /* PROPS */, ["label"])]),
7503
+ _: 1 /* STABLE */
7504
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, (0, _vue.unref)(formItem).isComplexGeometry]]), (0, _vue.withDirectives)((0, _vue.createElementVNode)("div", _hoisted_32, [(0, _vue.createVNode)(_component_kq_button, {
7505
+ onClick: _cache[244] || (_cache[244] = (0, _vue.withModifiers)($event => generated((0, _vue.unref)(formItem).isComplexGeometry ? 'complexGeometrySymbol' : 'geometrySymbol'), ["stop"])),
4814
7506
  title: (0, _vue.unref)(locale).webgl.generated,
4815
7507
  type: "primary",
4816
7508
  disabled: isDisabled.value
@@ -4819,21 +7511,21 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
4819
7511
  _: 1 /* STABLE */
4820
7512
  }, 8 /* PROPS */, ["title", "disabled"])], 512 /* NEED_PATCH */), [[_vue.vShow, mode.value == 'add']])]),
4821
7513
  _: 1 /* STABLE */
4822
- }, 8 /* PROPS */, ["title", "style"]), [[_vue.vShow, !(0, _vue.unref)(modelingTypes) || (0, _vue.unref)(modelingTypes) == 'geometrySymbol']]), (0, _vue.createCommentVNode)(" 复杂几何符号 "), (0, _vue.createCommentVNode)(" <kq-collapse-item\r\n :title=\"locale.webgl.complexGeometrySymbol\"\r\n name=\"complexGeometrySymbol\"\r\n v-show=\"!modelingTypes || modelingTypes == 'complexGeometrySymbol'\"\r\n :style=\" modelingTypes == 'complexGeometrySymbol' ? 'margin-bottom: 0px' : '' \">\r\n </kq-collapse-item> ")]),
7514
+ }, 8 /* PROPS */, ["title", "style"]), [[_vue.vShow, !(0, _vue.unref)(modelingTypes) || (0, _vue.unref)(modelingTypes) == 'geometrySymbol' || (0, _vue.unref)(modelingTypes) == 'complexGeometrySymbol']])]),
4823
7515
  _: 1 /* STABLE */
4824
7516
  }, 8 /* PROPS */, ["modelValue"])]),
4825
7517
  _: 1 /* STABLE */
4826
7518
  }, 8 /* PROPS */, ["label-width"])], 6 /* CLASS, STYLE */), (0, _vue.unref)(isShowAddModel) ? ((0, _vue.openBlock)(), (0, _vue.createBlock)((0, _vue.unref)(_basewindow.default), {
4827
7519
  key: 1,
4828
7520
  modelValue: (0, _vue.unref)(isShowAddModel),
4829
- "onUpdate:modelValue": _cache[227] || (_cache[227] = $event => (0, _vue.isRef)(isShowAddModel) ? isShowAddModel.value = $event : isShowAddModel = $event),
7521
+ "onUpdate:modelValue": _cache[248] || (_cache[248] = $event => (0, _vue.isRef)(isShowAddModel) ? isShowAddModel.value = $event : isShowAddModel = $event),
4830
7522
  title: (0, _vue.unref)(locale).webgl.newModel,
4831
7523
  titleIcon: (0, _vue.unref)(_client_icons_vue.IconAddData),
4832
7524
  id: "kq-add-model",
4833
7525
  zIndex: 2000,
4834
7526
  coexist: ""
4835
7527
  }, {
4836
- default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_27, [(0, _vue.createVNode)(_component_kq_form, {
7528
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_33, [(0, _vue.createVNode)(_component_kq_form, {
4837
7529
  "label-width": (0, _vue.unref)(lang) === 'zh' ? '100px' : '120px',
4838
7530
  "label-position": "left"
4839
7531
  }, {
@@ -4846,7 +7538,7 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
4846
7538
  }, {
4847
7539
  default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_input, {
4848
7540
  modelValue: (0, _vue.unref)(modelEditData).name,
4849
- "onUpdate:modelValue": _cache[225] || (_cache[225] = $event => (0, _vue.unref)(modelEditData).name = $event),
7541
+ "onUpdate:modelValue": _cache[246] || (_cache[246] = $event => (0, _vue.unref)(modelEditData).name = $event),
4850
7542
  placeholder: (0, _vue.unref)(t)('webgl.enterNameHint'),
4851
7543
  clearable: ""
4852
7544
  }, null, 8 /* PROPS */, ["modelValue", "placeholder"])]),
@@ -4866,35 +7558,35 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
4866
7558
  "text-align": "center"
4867
7559
  }
4868
7560
  }, {
4869
- default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_28, [(0, _vue.createVNode)(_component_kq_upload, {
7561
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_34, [(0, _vue.createVNode)(_component_kq_upload, {
4870
7562
  "show-file-list": false,
4871
7563
  action: "#",
4872
7564
  "auto-upload": false,
4873
7565
  "on-change": handleAvatarSuccess,
4874
7566
  accept: ".jpg,.png"
4875
7567
  }, {
4876
- default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_29, [(0, _vue.unref)(modelEditData).img ? ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", _hoisted_30, [(0, _vue.createElementVNode)("img", {
7568
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_35, [(0, _vue.unref)(modelEditData).img ? ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", _hoisted_36, [(0, _vue.createElementVNode)("img", {
4877
7569
  src: (0, _vue.unref)(modelEditData).img,
4878
7570
  class: "avatar"
4879
- }, null, 8 /* PROPS */, _hoisted_31), (0, _vue.createElementVNode)("div", _hoisted_32, [(0, _vue.createVNode)(_component_kq_icon, {
7571
+ }, null, 8 /* PROPS */, _hoisted_37), (0, _vue.createElementVNode)("div", _hoisted_38, [(0, _vue.createVNode)(_component_kq_icon, {
4880
7572
  size: 24
4881
7573
  }, {
4882
7574
  default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_iconsVue.Edit))]),
4883
7575
  _: 1 /* STABLE */
4884
- }), (0, _vue.createElementVNode)("div", _hoisted_33, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.changeImage), 1 /* TEXT */)])])) : ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", _hoisted_34, [(0, _vue.createVNode)(_component_kq_icon, {
7576
+ }), (0, _vue.createElementVNode)("div", _hoisted_39, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.changeImage), 1 /* TEXT */)])])) : ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", _hoisted_40, [(0, _vue.createVNode)(_component_kq_icon, {
4885
7577
  size: 48,
4886
7578
  class: "upload-icon"
4887
7579
  }, {
4888
7580
  default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_iconsVue.Plus))]),
4889
7581
  _: 1 /* STABLE */
4890
- }), (0, _vue.createElementVNode)("div", _hoisted_35, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.uploadThumbnail), 1 /* TEXT */), (0, _vue.createElementVNode)("div", _hoisted_36, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.supportImageFormats), 1 /* TEXT */)]))])]),
7582
+ }), (0, _vue.createElementVNode)("div", _hoisted_41, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.uploadThumbnail), 1 /* TEXT */), (0, _vue.createElementVNode)("div", _hoisted_42, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.supportImageFormats), 1 /* TEXT */)]))])]),
4891
7583
  _: 1 /* STABLE */
4892
7584
  })])]),
4893
7585
  _: 1 /* STABLE */
4894
7586
  }), (0, _vue.createVNode)(_component_kq_col, {
4895
7587
  span: 12
4896
7588
  }, {
4897
- default: (0, _vue.withCtx)(() => [(0, _vue.createCommentVNode)(" 上传模型文件 "), (0, _vue.createElementVNode)("div", _hoisted_37, [(0, _vue.createVNode)(_component_kq_upload, {
7589
+ default: (0, _vue.withCtx)(() => [(0, _vue.createCommentVNode)(" 上传模型文件 "), (0, _vue.createElementVNode)("div", _hoisted_43, [(0, _vue.createVNode)(_component_kq_upload, {
4898
7590
  action: "#",
4899
7591
  "auto-upload": false,
4900
7592
  accept: ".glb,.gltf",
@@ -4911,21 +7603,21 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
4911
7603
  }), (0, _vue.createTextVNode)(" " + (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.uploadModelFile), 1 /* TEXT */)]),
4912
7604
  _: 1 /* STABLE */
4913
7605
  })]),
4914
- tip: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_38, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.supportGLB), 1 /* TEXT */)]),
7606
+ tip: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_44, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.supportGLB), 1 /* TEXT */)]),
4915
7607
  _: 1 /* STABLE */
4916
- }), (0, _vue.createCommentVNode)(" 模型文件信息展示 "), (0, _vue.createElementVNode)("div", _hoisted_39, [(0, _vue.createVNode)(_component_kq_icon, {
7608
+ }), (0, _vue.createCommentVNode)(" 模型文件信息展示 "), (0, _vue.createElementVNode)("div", _hoisted_45, [(0, _vue.createVNode)(_component_kq_icon, {
4917
7609
  size: 20,
4918
7610
  class: "file-icon"
4919
7611
  }, {
4920
7612
  default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_iconsVue.Document))]),
4921
7613
  _: 1 /* STABLE */
4922
- }), (0, _vue.unref)(uploadFile).path ? ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", _hoisted_40, [(0, _vue.createElementVNode)("div", _hoisted_41, (0, _vue.toDisplayString)(getFileName((0, _vue.unref)(uploadFile).path.name)), 1 /* TEXT */), (0, _vue.createElementVNode)("div", _hoisted_42, (0, _vue.toDisplayString)(getFileSize((0, _vue.unref)(uploadFile).path.size)), 1 /* TEXT */)])) : (0, _vue.createCommentVNode)("v-if", true)])])]),
7614
+ }), (0, _vue.unref)(uploadFile).path ? ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", _hoisted_46, [(0, _vue.createElementVNode)("div", _hoisted_47, (0, _vue.toDisplayString)(getFileName((0, _vue.unref)(uploadFile).path.name)), 1 /* TEXT */), (0, _vue.createElementVNode)("div", _hoisted_48, (0, _vue.toDisplayString)(getFileSize((0, _vue.unref)(uploadFile).path.size)), 1 /* TEXT */)])) : (0, _vue.createCommentVNode)("v-if", true)])])]),
4923
7615
  _: 1 /* STABLE */
4924
7616
  })]),
4925
7617
  _: 1 /* STABLE */
4926
7618
  })]),
4927
7619
  _: 1 /* STABLE */
4928
- }, 8 /* PROPS */, ["label-width"]), (0, _vue.createElementVNode)("div", _hoisted_43, [(0, _vue.createVNode)(_component_kq_button, {
7620
+ }, 8 /* PROPS */, ["label-width"]), (0, _vue.createElementVNode)("div", _hoisted_49, [(0, _vue.createVNode)(_component_kq_button, {
4929
7621
  type: "primary",
4930
7622
  onClick: saveModelData,
4931
7623
  disabled: !isFormValid.value
@@ -4933,7 +7625,292 @@ var _default = exports.A = /*@__PURE__*/Object.assign(__default__, {
4933
7625
  default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(t)("common.confirm")), 1 /* TEXT */)]),
4934
7626
  _: 1 /* STABLE */
4935
7627
  }, 8 /* PROPS */, ["disabled"]), (0, _vue.createVNode)(_component_kq_button, {
4936
- onClick: _cache[226] || (_cache[226] = $event => (0, _vue.isRef)(isShowAddModel) ? isShowAddModel.value = !(0, _vue.unref)(isShowAddModel) : isShowAddModel = !(0, _vue.unref)(isShowAddModel))
7628
+ onClick: _cache[247] || (_cache[247] = $event => (0, _vue.isRef)(isShowAddModel) ? isShowAddModel.value = !(0, _vue.unref)(isShowAddModel) : isShowAddModel = !(0, _vue.unref)(isShowAddModel))
7629
+ }, {
7630
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(t)("common.cancel")), 1 /* TEXT */)]),
7631
+ _: 1 /* STABLE */
7632
+ })])])]),
7633
+ _: 1 /* STABLE */
7634
+ }, 8 /* PROPS */, ["modelValue", "title", "titleIcon"])) : (0, _vue.createCommentVNode)("v-if", true), (0, _vue.unref)(isShowAddGroup) ? ((0, _vue.openBlock)(), (0, _vue.createBlock)((0, _vue.unref)(_basewindow.default), {
7635
+ key: 2,
7636
+ modelValue: (0, _vue.unref)(isShowAddGroup),
7637
+ "onUpdate:modelValue": _cache[256] || (_cache[256] = $event => (0, _vue.isRef)(isShowAddGroup) ? isShowAddGroup.value = $event : isShowAddGroup = $event),
7638
+ title: (0, _vue.unref)(locale).webgl.addGroupShape,
7639
+ titleIcon: (0, _vue.unref)(_client_icons_vue.IconAddData),
7640
+ id: "kq-add-model",
7641
+ zIndex: 2000,
7642
+ coexist: "",
7643
+ onClose: handleCancelAddGroup
7644
+ }, {
7645
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_50, [(0, _vue.createVNode)(_component_kq_form, {
7646
+ "label-width": (0, _vue.unref)(lang) === 'zh' ? '100px' : '120px',
7647
+ "label-position": "left"
7648
+ }, {
7649
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, null, {
7650
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
7651
+ label: (0, _vue.unref)(locale).webgl.operationModel
7652
+ }, {
7653
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, {
7654
+ style: {
7655
+ "display": "flex"
7656
+ }
7657
+ }, {
7658
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7659
+ span: 11
7660
+ }, {
7661
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_select, {
7662
+ modelValue: groupShapesObj.name,
7663
+ "onUpdate:modelValue": _cache[249] || (_cache[249] = $event => groupShapesObj.name = $event),
7664
+ style: {
7665
+ "width": "100%"
7666
+ }
7667
+ }, {
7668
+ default: (0, _vue.withCtx)(() => [((0, _vue.openBlock)(true), (0, _vue.createElementBlock)(_vue.Fragment, null, (0, _vue.renderList)(groupShapeList1.value, (item, index) => {
7669
+ return (0, _vue.openBlock)(), (0, _vue.createBlock)(_component_kq_option, {
7670
+ key: index,
7671
+ value: item.name,
7672
+ onClick: $event => addGroupShapeBtn('base', item)
7673
+ }, {
7674
+ default: (0, _vue.withCtx)(() => [(0, _vue.createCommentVNode)(" 给图标+文字套一层 flex 容器,实现垂直居中 "), (0, _vue.createElementVNode)("div", _hoisted_51, [item.icon ? ((0, _vue.openBlock)(), (0, _vue.createBlock)(_component_kq_icon, {
7675
+ key: 0,
7676
+ class: "option-icon"
7677
+ }, {
7678
+ default: (0, _vue.withCtx)(() => [((0, _vue.openBlock)(), (0, _vue.createBlock)((0, _vue.resolveDynamicComponent)(item.icon)))]),
7679
+ _: 2 /* DYNAMIC */
7680
+ }, 1024 /* DYNAMIC_SLOTS */)) : (0, _vue.createCommentVNode)("v-if", true), (0, _vue.createElementVNode)("span", null, (0, _vue.toDisplayString)(item.name), 1 /* TEXT */)])]),
7681
+ _: 2 /* DYNAMIC */
7682
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["value", "onClick"]);
7683
+ }), 128 /* KEYED_FRAGMENT */))]),
7684
+ _: 1 /* STABLE */
7685
+ }, 8 /* PROPS */, ["modelValue"])]),
7686
+ _: 1 /* STABLE */
7687
+ }), (0, _vue.createVNode)(_component_kq_col, {
7688
+ span: 2,
7689
+ style: {
7690
+ "text-align": "center",
7691
+ "line-height": "33px"
7692
+ }
7693
+ }, {
7694
+ default: (0, _vue.withCtx)(() => _cache[265] || (_cache[265] = [(0, _vue.createTextVNode)(" -> ")])),
7695
+ _: 1 /* STABLE */,
7696
+ __: [265]
7697
+ }), (0, _vue.createVNode)(_component_kq_col, {
7698
+ span: 11
7699
+ }, {
7700
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_select, {
7701
+ modelValue: groupShapesObj.operationName,
7702
+ "onUpdate:modelValue": _cache[250] || (_cache[250] = $event => groupShapesObj.operationName = $event),
7703
+ style: {
7704
+ "width": "100%"
7705
+ },
7706
+ clearable: ""
7707
+ }, {
7708
+ default: (0, _vue.withCtx)(() => [((0, _vue.openBlock)(true), (0, _vue.createElementBlock)(_vue.Fragment, null, (0, _vue.renderList)(groupShapeList2.value, (item, index) => {
7709
+ return (0, _vue.openBlock)(), (0, _vue.createBlock)(_component_kq_option, {
7710
+ key: index,
7711
+ value: item.name,
7712
+ onClick: $event => addGroupShapeBtn('operation', item)
7713
+ }, {
7714
+ default: (0, _vue.withCtx)(() => [(0, _vue.createCommentVNode)(" 给图标+文字套一层 flex 容器,实现垂直居中 "), (0, _vue.createElementVNode)("div", _hoisted_52, [item.icon ? ((0, _vue.openBlock)(), (0, _vue.createBlock)(_component_kq_icon, {
7715
+ key: 0,
7716
+ class: "option-icon"
7717
+ }, {
7718
+ default: (0, _vue.withCtx)(() => [((0, _vue.openBlock)(), (0, _vue.createBlock)((0, _vue.resolveDynamicComponent)(item.icon)))]),
7719
+ _: 2 /* DYNAMIC */
7720
+ }, 1024 /* DYNAMIC_SLOTS */)) : (0, _vue.createCommentVNode)("v-if", true), (0, _vue.createElementVNode)("span", null, (0, _vue.toDisplayString)(item.name), 1 /* TEXT */)])]),
7721
+ _: 2 /* DYNAMIC */
7722
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["value", "onClick"]);
7723
+ }), 128 /* KEYED_FRAGMENT */))]),
7724
+ _: 1 /* STABLE */
7725
+ }, 8 /* PROPS */, ["modelValue"])]),
7726
+ _: 1 /* STABLE */
7727
+ })]),
7728
+ _: 1 /* STABLE */
7729
+ })]),
7730
+ _: 1 /* STABLE */
7731
+ }, 8 /* PROPS */, ["label"])]),
7732
+ _: 1 /* STABLE */
7733
+ }), (0, _vue.withDirectives)((0, _vue.createVNode)(_component_kq_row, null, {
7734
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
7735
+ label: (0, _vue.unref)(locale).webgl.operationMethod
7736
+ }, {
7737
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, {
7738
+ style: {
7739
+ "display": "flex"
7740
+ }
7741
+ }, {
7742
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7743
+ span: 24,
7744
+ style: {
7745
+ "text-align": "left"
7746
+ }
7747
+ }, {
7748
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_button, {
7749
+ class: (0, _vue.normalizeClass)(["build-model-btn-add", groupShapesObj.operationMethod == 0 ? 'isActive' : '']),
7750
+ style: {
7751
+ "margin": "0 2px 0 4px"
7752
+ },
7753
+ onClick: _cache[251] || (_cache[251] = $event => groupShapesObj.operationMethod = 0),
7754
+ title: (0, _vue.unref)(locale).webgl.intersection
7755
+ }, {
7756
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_icon, {
7757
+ size: 16
7758
+ }, {
7759
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconIntersect))]),
7760
+ _: 1 /* STABLE */
7761
+ })]),
7762
+ _: 1 /* STABLE */
7763
+ }, 8 /* PROPS */, ["class", "title"]), (0, _vue.createVNode)(_component_kq_button, {
7764
+ class: (0, _vue.normalizeClass)(["build-model-btn-add", groupShapesObj.operationMethod == 1 ? 'isActive' : '']),
7765
+ style: {
7766
+ "margin": "0 2px 0 4px"
7767
+ },
7768
+ onClick: _cache[252] || (_cache[252] = $event => groupShapesObj.operationMethod = 1),
7769
+ title: (0, _vue.unref)(locale).webgl.union
7770
+ }, {
7771
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_icon, {
7772
+ size: 16
7773
+ }, {
7774
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconMerge))]),
7775
+ _: 1 /* STABLE */
7776
+ })]),
7777
+ _: 1 /* STABLE */
7778
+ }, 8 /* PROPS */, ["class", "title"]), (0, _vue.createVNode)(_component_kq_button, {
7779
+ class: (0, _vue.normalizeClass)(["build-model-btn-add", groupShapesObj.operationMethod == 2 ? 'isActive' : '']),
7780
+ style: {
7781
+ "margin": "0 2px 0 4px"
7782
+ },
7783
+ onClick: _cache[253] || (_cache[253] = $event => groupShapesObj.operationMethod = 2),
7784
+ title: (0, _vue.unref)(locale).webgl.difference
7785
+ }, {
7786
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_icon, {
7787
+ size: 16
7788
+ }, {
7789
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_client_icons_vue.IconDifference))]),
7790
+ _: 1 /* STABLE */
7791
+ })]),
7792
+ _: 1 /* STABLE */
7793
+ }, 8 /* PROPS */, ["class", "title"])]),
7794
+ _: 1 /* STABLE */
7795
+ })]),
7796
+ _: 1 /* STABLE */
7797
+ })]),
7798
+ _: 1 /* STABLE */
7799
+ }, 8 /* PROPS */, ["label"])]),
7800
+ _: 1 /* STABLE */
7801
+ }, 512 /* NEED_PATCH */), [[_vue.vShow, groupShapesObj.operationName]])]),
7802
+ _: 1 /* STABLE */
7803
+ }, 8 /* PROPS */, ["label-width"]), (0, _vue.createElementVNode)("div", _hoisted_53, [(0, _vue.createVNode)(_component_kq_button, {
7804
+ type: "primary",
7805
+ onClick: _cache[254] || (_cache[254] = $event => addGroupShapeBtn('preview')),
7806
+ disabled: !groupShapesObj.baseModel || !groupShapesObj.operationModel,
7807
+ size: "small"
7808
+ }, {
7809
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(t)("webgl.preview")), 1 /* TEXT */)]),
7810
+ _: 1 /* STABLE */
7811
+ }, 8 /* PROPS */, ["disabled"]), (0, _vue.createVNode)(_component_kq_button, {
7812
+ type: "primary",
7813
+ onClick: _cache[255] || (_cache[255] = $event => addGroupShapeBtn('confirm')),
7814
+ disabled: !groupShapesObj.baseModel,
7815
+ size: "small"
7816
+ }, {
7817
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(t)("common.confirm")), 1 /* TEXT */)]),
7818
+ _: 1 /* STABLE */
7819
+ }, 8 /* PROPS */, ["disabled"]), (0, _vue.createVNode)(_component_kq_button, {
7820
+ onClick: resetGroupShapesObj,
7821
+ size: "small"
7822
+ }, {
7823
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(t)("common.clear")), 1 /* TEXT */)]),
7824
+ _: 1 /* STABLE */
7825
+ }), (0, _vue.createVNode)(_component_kq_button, {
7826
+ onClick: handleCancelAddGroup,
7827
+ size: "small"
7828
+ }, {
7829
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(t)("common.cancel")), 1 /* TEXT */)]),
7830
+ _: 1 /* STABLE */
7831
+ })])])]),
7832
+ _: 1 /* STABLE */
7833
+ }, 8 /* PROPS */, ["modelValue", "title", "titleIcon"])) : (0, _vue.createCommentVNode)("v-if", true), (0, _vue.unref)(isShowSaveTemplate) ? ((0, _vue.openBlock)(), (0, _vue.createBlock)((0, _vue.unref)(_basewindow.default), {
7834
+ key: 3,
7835
+ modelValue: (0, _vue.unref)(isShowSaveTemplate),
7836
+ "onUpdate:modelValue": _cache[259] || (_cache[259] = $event => (0, _vue.isRef)(isShowSaveTemplate) ? isShowSaveTemplate.value = $event : isShowSaveTemplate = $event),
7837
+ title: (0, _vue.unref)(locale).webgl.saveGroupTemplate,
7838
+ titleIcon: (0, _vue.unref)(_client_icons_vue.IconAddData),
7839
+ id: "kq-save-template",
7840
+ zIndex: 2000,
7841
+ coexist: ""
7842
+ }, {
7843
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_54, [(0, _vue.createVNode)(_component_kq_form, {
7844
+ "label-width": (0, _vue.unref)(lang) === 'zh' ? '100px' : '120px',
7845
+ "label-position": "left"
7846
+ }, {
7847
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_form_item, {
7848
+ label: (0, _vue.unref)(t)('webgl.modelName')
7849
+ }, {
7850
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_row, null, {
7851
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7852
+ span: 24
7853
+ }, {
7854
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_input, {
7855
+ modelValue: templateSaveData.name,
7856
+ "onUpdate:modelValue": _cache[257] || (_cache[257] = $event => templateSaveData.name = $event),
7857
+ placeholder: (0, _vue.unref)(t)('webgl.enterNameHint'),
7858
+ clearable: ""
7859
+ }, null, 8 /* PROPS */, ["modelValue", "placeholder"])]),
7860
+ _: 1 /* STABLE */
7861
+ })]),
7862
+ _: 1 /* STABLE */
7863
+ })]),
7864
+ _: 1 /* STABLE */
7865
+ }, 8 /* PROPS */, ["label"]), (0, _vue.createVNode)(_component_kq_row, {
7866
+ style: {
7867
+ "display": "flex"
7868
+ }
7869
+ }, {
7870
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)(_component_kq_col, {
7871
+ span: 24,
7872
+ style: {
7873
+ "text-align": "center"
7874
+ }
7875
+ }, {
7876
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_55, [(0, _vue.createVNode)(_component_kq_upload, {
7877
+ "show-file-list": false,
7878
+ action: "#",
7879
+ "auto-upload": false,
7880
+ "on-change": handleTemplateAvatarSuccess,
7881
+ accept: ".jpg,.png"
7882
+ }, {
7883
+ default: (0, _vue.withCtx)(() => [(0, _vue.createElementVNode)("div", _hoisted_56, [templateSaveData.img ? ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", _hoisted_57, [(0, _vue.createElementVNode)("img", {
7884
+ src: templateSaveData.img,
7885
+ class: "avatar"
7886
+ }, null, 8 /* PROPS */, _hoisted_58), (0, _vue.createElementVNode)("div", _hoisted_59, [(0, _vue.createVNode)(_component_kq_icon, {
7887
+ size: 24
7888
+ }, {
7889
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_iconsVue.Edit))]),
7890
+ _: 1 /* STABLE */
7891
+ }), (0, _vue.createElementVNode)("div", _hoisted_60, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.changeImage), 1 /* TEXT */)])])) : ((0, _vue.openBlock)(), (0, _vue.createElementBlock)("div", _hoisted_61, [(0, _vue.createVNode)(_component_kq_icon, {
7892
+ size: 48,
7893
+ class: "upload-icon"
7894
+ }, {
7895
+ default: (0, _vue.withCtx)(() => [(0, _vue.createVNode)((0, _vue.unref)(_iconsVue.Plus))]),
7896
+ _: 1 /* STABLE */
7897
+ }), (0, _vue.createElementVNode)("div", _hoisted_62, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.uploadThumbnail), 1 /* TEXT */), (0, _vue.createElementVNode)("div", _hoisted_63, (0, _vue.toDisplayString)((0, _vue.unref)(locale).webgl.supportImageFormats), 1 /* TEXT */)]))])]),
7898
+ _: 1 /* STABLE */
7899
+ })])]),
7900
+ _: 1 /* STABLE */
7901
+ })]),
7902
+ _: 1 /* STABLE */
7903
+ })]),
7904
+ _: 1 /* STABLE */
7905
+ }, 8 /* PROPS */, ["label-width"]), (0, _vue.createElementVNode)("div", _hoisted_64, [(0, _vue.createVNode)(_component_kq_button, {
7906
+ type: "primary",
7907
+ onClick: saveTemplateData,
7908
+ disabled: !templateSaveData.name
7909
+ }, {
7910
+ default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(t)("common.confirm")), 1 /* TEXT */)]),
7911
+ _: 1 /* STABLE */
7912
+ }, 8 /* PROPS */, ["disabled"]), (0, _vue.createVNode)(_component_kq_button, {
7913
+ onClick: _cache[258] || (_cache[258] = $event => (0, _vue.isRef)(isShowSaveTemplate) ? isShowSaveTemplate.value = !(0, _vue.unref)(isShowSaveTemplate) : isShowSaveTemplate = !(0, _vue.unref)(isShowSaveTemplate))
4937
7914
  }, {
4938
7915
  default: (0, _vue.withCtx)(() => [(0, _vue.createTextVNode)((0, _vue.toDisplayString)((0, _vue.unref)(t)("common.cancel")), 1 /* TEXT */)]),
4939
7916
  _: 1 /* STABLE */
@@ -5264,11 +8241,11 @@ Object.defineProperty(exports, "__esModule", ({
5264
8241
  value: true
5265
8242
  }));
5266
8243
  exports.kq_npm_client_leaflet_vue = exports.kq_npm_client_common_vue = exports.kq_npm_client3d_webgl_vue = void 0;
5267
- let kq_npm_client_common_vue = exports.kq_npm_client_common_vue = window.kq_npm_client_common_vue = window.kq_npm_client_common_vue || {};
8244
+ const kq_npm_client_common_vue = exports.kq_npm_client_common_vue = window.kq_npm_client_common_vue = window.kq_npm_client_common_vue || {};
5268
8245
  __webpack_require__.g.kq_npm_client_common_vue = kq_npm_client_common_vue;
5269
- let kq_npm_client_leaflet_vue = exports.kq_npm_client_leaflet_vue = window.kq_npm_client_leaflet_vue = window.kq_npm_client_leaflet_vue || {};
8246
+ const kq_npm_client_leaflet_vue = exports.kq_npm_client_leaflet_vue = window.kq_npm_client_leaflet_vue = window.kq_npm_client_leaflet_vue || {};
5270
8247
  __webpack_require__.g.kq_npm_client_leaflet_vue = kq_npm_client_leaflet_vue;
5271
- let kq_npm_client3d_webgl_vue = exports.kq_npm_client3d_webgl_vue = window.kq_npm_client3d_webgl_vue = window.kq_npm_client3d_webgl_vue || {};
8248
+ const kq_npm_client3d_webgl_vue = exports.kq_npm_client3d_webgl_vue = window.kq_npm_client3d_webgl_vue = window.kq_npm_client3d_webgl_vue || {};
5272
8249
  __webpack_require__.g.kq_npm_client3d_webgl_vue = kq_npm_client3d_webgl_vue;
5273
8250
 
5274
8251
  /***/ })