kd-lane-container 0.0.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -67,12 +67,88 @@ export default {
67
67
 
68
68
  ### 4.1 基本使用
69
69
 
70
+ #### 4.1.1 泳道宽度配置
71
+
72
+ 从版本 0.1.0 开始,支持通过 `width` 属性自定义泳道宽度。
73
+
74
+ **配置说明**:
75
+ - **自定义插槽泳道**:
76
+ - 如果泳道配置中包含 `width` 属性(数字类型),则动态设置 `style` 为 `width: ${width}px`。
77
+ - 如果未配置 `width`,则动态设置 `style` 为 `width: auto`,由插槽内容决定实际宽度(之前的默认逻辑)。
78
+ - **普通泳道**:
79
+ - 如果泳道配置中包含 `width` 属性(数字类型),则动态设置 `style` 为 `width: ${width}px`。
80
+ - 如果未配置 `width`,则动态设置 `style` 为 `flex: 1`,与其他未设置宽度的泳道平分剩余空间(之前的默认逻辑)。
81
+
82
+ **示例配置**:
83
+ ```javascript
84
+ lanes: [
85
+ { 其他属性..., width: 200 }, // 自定义宽度为 200px
86
+ { 其他属性..., } // 未设置宽度,使用默认逻辑
87
+ ]
88
+ ```
89
+
90
+ #### 4.1.2 泳道尺寸获取
91
+
92
+ 新增 `getGridSize` 方法,用于获取泳道的精确尺寸(包括泳道抬头部分)。
93
+
94
+ **注意事项**:
95
+ - 调用时机:需确保泳道容器的 `div` 已挂载并渲染完毕,否则可能返回空数组或错误数据。
96
+ - 返回值:返回泳道的 `x`、`y`、`width`、`height` 等尺寸信息,以及 `lane-id` 属性。
97
+
98
+ **示例代码**:
99
+ ```javascript
100
+ const gridSizes = this.$refs.laneContainer.getGridSize();
101
+ console.log(gridSizes); // 输出泳道尺寸信息
102
+ ```
103
+
70
104
  ```vue
71
- <KdLaneContainer class="container" :config="config" :customMenuList="customMenuList" @onCustomMenuClicked="onCustomMenuClicked">
72
- <!-- 自定义插槽内容 -->
105
+ <KdLaneContainer
106
+ class="container"
107
+ :config="config"
108
+ :customMenuList="customMenuList"
109
+ @onCustomMenuClicked="onCustomMenuClicked"
110
+ @template-change="templateChange"
111
+ @line-change="lineChange"
112
+ :themeName="themeName"
113
+ >
114
+ <!-- 动态slot,处理容器抬头自定义布局 -->
115
+ <template v-if="headerSlotName">
116
+ <div :slot="headerSlotName" class="header-slot">
117
+ {{ headerSlotName }}
118
+ </div>
119
+ </template>
120
+ <!-- 处理draw-slot中泳道div -->
121
+ <template v-if="lanes && lanes.length > 0" slot="draw-slot">
122
+ <div class="draw-slot">
123
+ <template v-for="lane in lanes">
124
+ <!-- 如果title定义了,需要和title保持一样宽度 -->
125
+ <div v-if="lane.laneKey == 'depth'" :key="lane.laneId" style="width: 80px; height: 100%; overflow: hidden">
126
+ {{ lane.laneKey }}
127
+ </div>
128
+ <!-- 平分的泳道布局 -->
129
+ <div v-else class="lane-div" :key="`lane-${lane.laneId}`">
130
+ {{ lane.laneId }}
131
+ </div>
132
+ </template>
133
+ </div>
134
+ </template>
73
135
  </KdLaneContainer>
74
136
  ```
75
137
 
138
+ #### 使用步骤说明
139
+
140
+ 1. **配置组件**:
141
+ - 通过 `config` 属性传入初始配置,包括数据源类型、案例ID、版本号等。
142
+ - 通过 `customMenuList` 属性传入自定义菜单列表。
143
+
144
+ 2. **监听事件动态渲染**:
145
+ - 监听 `template-change` 事件,获取最新的泳道数据(`lanes`),动态渲染自定义抬头和泳道布局。
146
+ - 监听 `line-change` 事件,处理线条配置的变化。
147
+
148
+ 3. **主题变化处理**:
149
+ - 主题变更是由外部触发的,组件仅负责根据 `themeName` 属性正确渲染标题。
150
+ - 模板和线条的变化需要自行处理,组件不会主动通知这些变化。
151
+
76
152
  ### 4.2 场景与版本控制
77
153
 
78
154
  #### 4.2.1 场景唯一标识规则
@@ -293,66 +369,75 @@ handleCustomMenuClick(event) {
293
369
  }
294
370
  ```
295
371
 
296
- ## 5. 组件 API
297
-
298
- ### 5.1 Props
299
-
300
- | 属性名 | 类型 | 默认值 | 说明 |
301
- | ---------------- | ------ | ------- | ------------------ |
302
- | config | Object | 必填 | 组件配置对象 |
303
- | headerPadding | Number | 4 | 泳道头部内边距 |
304
- | headerItemHeight | Number | 20 | 头部线条项高度 |
305
- | itemGap | Number | 2 | 线条项之间的间距 |
306
- | customMenuList | Array | [] | 自定义菜单列表 |
307
- | themeName | String | "white" | 当前使用的主题名称 |
308
-
309
- ### 5.2 事件
310
-
311
- | 事件名 | 参数 | 说明 |
312
- | ------------------- | -------- | ------------------ |
313
- | onCustomMenuClicked | event | 自定义菜单点击事件 |
314
- | line-change | line | 线条变化事件 |
315
- | template-change | template | 模板变化事件 |
316
-
317
- ### 5.3 方法
318
-
319
- **注:以下方法仅在使用 `custom` 模式时需要了解和实现,local 模式下不需要考虑。**
320
-
321
- 组件内部提供的方法主要用于模板和线条的管理:
322
-
323
- - upsertTemplate(data) - 新增或更新模板
324
-
325
- - 参数:`data` - 模板数据
326
- - 返回值:`Promise<Object>` - 插入或更新后的**完整**模板对象
327
-
328
- - delTemplate(data) - 删除模板
329
-
330
- - 参数:`data` - 模板数据(需包含`templateId`)
331
- - 返回值:`Promise<void>` - 操作成功或失败的 Promise
332
-
333
- - upsertLane(data) - 新增或更新泳道
334
-
335
- - 参数:`data` - 泳道数据
336
- - 返回值:`Promise<Object>` - 插入或更新后的**完整**泳道对象
337
-
338
- - delLane(lane) - 删除泳道
339
-
340
- - 参数:`lane` - 泳道数据(需包含`laneId`和`lines`数组)
341
- - 返回值:`Promise<void>` - 操作成功或失败的 Promise
342
-
343
- - upsertLine(data) - 新增或更新线条
344
-
345
- - 参数:`data` - 线条数据
346
- - 返回值:`Promise<Object>` - 插入或更新后的**完整线**条对象
347
-
348
- - delLine(data) - 删除线条
349
-
350
- - 参数:`data` - 线条数据(需包含`lineId`和`laneId`)
351
- - 返回值:`Promise<void>` - 操作成功或失败的 Promise
352
-
353
- - restoreSetting() - 恢复默认设置
354
- - 功能:将当前场景的数据重置为初始配置状态
355
- - 实现逻辑:使用构造函数传入的初始 dataSource 重新初始化数据
372
+ ## 5. 组件 API
373
+
374
+ ### 5.1 Props
375
+
376
+ | 属性名 | 类型 | 默认值 | 说明 |
377
+ | ---------------- | ------ | ------- | ------------------ |
378
+ | config | Object | 必填 | 组件配置对象 |
379
+ | headerPadding | Number | 4 | 泳道头部内边距 |
380
+ | headerItemHeight | Number | 20 | 头部线条项高度 |
381
+ | itemGap | Number | 2 | 线条项之间的间距 |
382
+ | customMenuList | Array | [] | 自定义菜单列表 |
383
+ | themeName | String | "white" | 当前使用的主题名称 |
384
+
385
+ ### 5.2 事件
386
+
387
+ | 事件名 | 参数 | 说明 |
388
+ | ------------------- | -------- | ------------------ |
389
+ | onCustomMenuClicked | event | 自定义菜单点击事件 |
390
+ | line-change | line | 线条变化事件 |
391
+ | template-change | template | 模板变化事件 |
392
+
393
+ ### 5.3 方法
394
+
395
+ #### 5.3.1 组件实例方法
396
+
397
+ | 方法名 | 作用描述 | 入参 |
398
+ |----------------|-------------------------------------------------------------------------|------|
399
+ | `getGridSize` | 获取泳道的精确尺寸(包括泳道抬头部分) | 无 |
400
+ | `restoreSetting` | 恢复组件的初始设置(如重置模板、泳道和线条配置到默认状态) | 无 |
401
+
402
+ #### 5.3.2 数据源方法(仅 custom 模式需要实现)
403
+
404
+ **注:以下方法仅在使用 `custom` 模式时需要了解和实现,local 模式下不需要考虑。**
405
+
406
+ 组件内部提供的方法主要用于模板和线条的管理:
407
+
408
+ - upsertTemplate(data) - 新增或更新模板
409
+
410
+ - 参数:`data` - 模板数据
411
+ - 返回值:`Promise<Object>` - 插入或更新后的**完整**模板对象
412
+
413
+ - delTemplate(data) - 删除模板
414
+
415
+ - 参数:`data` - 模板数据(需包含`templateId`)
416
+ - 返回值:`Promise<void>` - 操作成功或失败的 Promise
417
+
418
+ - upsertLane(data) - 新增或更新泳道
419
+
420
+ - 参数:`data` - 泳道数据
421
+ - 返回值:`Promise<Object>` - 插入或更新后的**完整**泳道对象
422
+
423
+ - delLane(lane) - 删除泳道
424
+
425
+ - 参数:`lane` - 泳道数据(需包含`laneId`和`lines`数组)
426
+ - 返回值:`Promise<void>` - 操作成功或失败的 Promise
427
+
428
+ - upsertLine(data) - 新增或更新线条
429
+
430
+ - 参数:`data` - 线条数据
431
+ - 返回值:`Promise<Object>` - 插入或更新后的**完整线**条对象
432
+
433
+ - delLine(data) - 删除线条
434
+
435
+ - 参数:`data` - 线条数据(需包含`lineId`和`laneId`)
436
+ - 返回值:`Promise<void>` - 操作成功或失败的 Promise
437
+
438
+ - restoreSetting() - 恢复默认设置
439
+ - 功能:将当前场景的数据重置为初始配置状态
440
+ - 实现逻辑:使用构造函数传入的初始 dataSource 重新初始化数据
356
441
  - 返回值:`Promise<void>` - 恢复默认设置的 Promise
357
442
 
358
443
  ## 6. 自定义插槽
package/dist/cjs/index.js CHANGED
@@ -898,6 +898,9 @@ class ConfigDBManager {
898
898
  }
899
899
  const dbHelper = new ConfigDBManager();
900
900
 
901
+ function isNumeric(val) {
902
+ return val != null && val !== "" && !Number.isNaN(Number(val));
903
+ }
901
904
  function pxToNumber(pxStr) {
902
905
  if (!pxStr || typeof pxStr !== "string") return 0;
903
906
  return parseFloat(pxStr.replace("px", "")) || 0;
@@ -2114,7 +2117,7 @@ __vue_render__$5._withStripped = true;
2114
2117
  //
2115
2118
 
2116
2119
  var script$4 = {
2117
- inject: ["upsertLine", "setTargetData", "setExpanded"],
2120
+ inject: ["upsertLine", "setTargetData", "setExpanded", "getThemeName"],
2118
2121
  props: {
2119
2122
  template: {
2120
2123
  type: Object,
@@ -2194,6 +2197,14 @@ var script$4 = {
2194
2197
  .validate()
2195
2198
  .then(() => {
2196
2199
  if (this.upsertLine instanceof Function) {
2200
+ // 检查是否有主题配置
2201
+ const themeName = this.getThemeName();
2202
+ const themeConfig = this.formData.themeConfig;
2203
+ if (themeName && themeConfig && themeConfig[themeName]) {
2204
+ const theme = themeConfig[themeName];
2205
+ theme.lineColor = this.formData.lineColor;
2206
+ }
2207
+ this.saving = true;
2197
2208
  const result = this.upsertLine(this.formData);
2198
2209
  if (result instanceof Promise) {
2199
2210
  result
@@ -2226,7 +2237,22 @@ var script$4 = {
2226
2237
  immediate: false,
2227
2238
  deep: true,
2228
2239
  handler(newD) {
2229
- this.formData = Object.assign({}, newD);
2240
+ // 检查是否有主题配置
2241
+ const themeName = this.getThemeName();
2242
+ const themeConfig = newD.themeConfig;
2243
+ let themeLineColor;
2244
+ if (themeName && themeConfig && themeConfig[themeName]) {
2245
+ const theme = themeConfig[themeName];
2246
+ const lineColor = theme.lineColor;
2247
+ if (lineColor) {
2248
+ themeLineColor = lineColor;
2249
+ }
2250
+ }
2251
+ if (themeLineColor) {
2252
+ this.formData = Object.assign({}, newD, { lineColor: themeLineColor });
2253
+ } else {
2254
+ this.formData = Object.assign({}, newD);
2255
+ }
2230
2256
  },
2231
2257
  },
2232
2258
  },
@@ -2511,10 +2537,6 @@ Vue__default["default"].use(vClickOutside__default["default"]);
2511
2537
  var script$3 = {
2512
2538
  name: "VueSimpleContextMenu",
2513
2539
  props: {
2514
- elementId: {
2515
- type: String,
2516
- required: true,
2517
- },
2518
2540
  options: {
2519
2541
  type: Array,
2520
2542
  required: true,
@@ -2531,7 +2553,7 @@ var script$3 = {
2531
2553
  showMenu(event, item) {
2532
2554
  this.item = item;
2533
2555
 
2534
- var menu = document.getElementById(this.elementId);
2556
+ const menu = this.$refs.refUl;
2535
2557
  if (!menu) {
2536
2558
  return;
2537
2559
  }
@@ -2555,11 +2577,10 @@ var script$3 = {
2555
2577
  } else {
2556
2578
  menu.style.top = event.pageY - 2 + "px";
2557
2579
  }
2558
-
2559
2580
  menu.classList.add("vue-simple-context-menu--active");
2560
2581
  },
2561
2582
  hideContextMenu() {
2562
- const element = document.getElementById(this.elementId);
2583
+ const element = this.$refs.refUl;
2563
2584
  if (element) {
2564
2585
  element.classList.remove("vue-simple-context-menu--active");
2565
2586
  this.$emit("menu-closed");
@@ -2611,8 +2632,8 @@ var __vue_render__$3 = function () {
2611
2632
  expression: "onClickOutside",
2612
2633
  },
2613
2634
  ],
2635
+ ref: "refUl",
2614
2636
  staticClass: "vue-simple-context-menu",
2615
- attrs: { id: _vm.elementId },
2616
2637
  },
2617
2638
  _vm._l(_vm.options, function (option, index) {
2618
2639
  return _c(
@@ -3201,10 +3222,7 @@ var __vue_render__$2 = function () {
3201
3222
  _vm._v(" "),
3202
3223
  _c("VueSimpleContextMenu", {
3203
3224
  ref: "vueSimpleContextMenu",
3204
- attrs: {
3205
- "element-id": "kd-lane-chart-context-menu-2",
3206
- options: _vm.contextMenuOptions,
3207
- },
3225
+ attrs: { options: _vm.contextMenuOptions },
3208
3226
  on: { "option-clicked": _vm.optionClicked },
3209
3227
  }),
3210
3228
  ],
@@ -3428,6 +3446,9 @@ var script = {
3428
3446
  delLane: this.delLane,
3429
3447
  upsertLine: this.upsertLine,
3430
3448
  delLine: this.delLine,
3449
+ getThemeName: () => {
3450
+ return this.themeName;
3451
+ },
3431
3452
  };
3432
3453
  },
3433
3454
  components: {
@@ -3486,6 +3507,26 @@ var script = {
3486
3507
  mounted() {},
3487
3508
 
3488
3509
  methods: {
3510
+ getGridSize() {
3511
+ if (!this.$refs.refLaneDiv) return [];
3512
+ const isArray = Array.isArray(this.$refs.refLaneDiv);
3513
+ if (isArray) {
3514
+ return this.$refs.refLaneDiv.map((item) => {
3515
+ const { x, y, width, height, top, right, bottom, left } = item.getBoundingClientRect();
3516
+ return { x, y, width, height, top, bottom, right, left, "lane-id": item.getAttribute("lane-id") };
3517
+ });
3518
+ } else {
3519
+ return [this.$refs.refLaneDiv.getBoundingClientRect()];
3520
+ }
3521
+ },
3522
+ laneContainerStyle(lane, type) {
3523
+ const isWidthNumeric = isNumeric(lane.width);
3524
+ if (type === "slot") {
3525
+ return isWidthNumeric ? { width: `${lane.width}px` } : { width: "auto" };
3526
+ } else {
3527
+ return isWidthNumeric ? { width: `${lane.width}px` } : { flex: "1" };
3528
+ }
3529
+ },
3489
3530
  setExpanded() {
3490
3531
  this.$refs.curveConfig.setExpanded();
3491
3532
  },
@@ -3813,7 +3854,7 @@ var script = {
3813
3854
  },
3814
3855
  };
3815
3856
 
3816
- var css_248z = ".kd-lane-chart-container {\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n border: 1px solid var(--kd-lane-container-border-color, #333);\n display: flex;\n}\n.kd-lane-chart-container .kd-lane-chart-lane-slot-container, .kd-lane-chart-container .kd-lane-chart-lane-container {\n height: 100%;\n min-width: 0;\n overflow: hidden;\n z-index: 1;\n}\n.kd-lane-chart-container .kd-lane-chart-lane-slot-container .kd-lane-chart-lane-header, .kd-lane-chart-container .kd-lane-chart-lane-container .kd-lane-chart-lane-header {\n max-height: 40%;\n border-bottom: 1px solid var(--kd-lane-container-border-color, #333);\n overflow: hidden;\n z-index: 2;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n.kd-lane-chart-container .kd-lane-chart-lane-container {\n flex: 1;\n}\n.kd-lane-chart-container .kd-lane-chart-lane-slot-container {\n width: auto;\n}\n.kd-lane-chart-container .border-left {\n border-left: 1px solid var(--kd-lane-container-border-color, #333);\n}\n.kd-lane-chart-container .kd-lane-chart-container-draw-area {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 3;\n border: none;\n}";
3857
+ var css_248z = ".kd-lane-chart-container {\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n border: 1px solid var(--kd-lane-container-border-color, #333);\n display: flex;\n}\n.kd-lane-chart-container .kd-lane-chart-lane-container,\n.kd-lane-chart-container .kd-lane-chart-lane-slot-container {\n height: 100%;\n min-width: 0;\n overflow: hidden;\n z-index: 1;\n}\n.kd-lane-chart-container .kd-lane-chart-lane-container .kd-lane-chart-lane-header,\n.kd-lane-chart-container .kd-lane-chart-lane-slot-container .kd-lane-chart-lane-header {\n max-height: 40%;\n border-bottom: 1px solid var(--kd-lane-container-border-color, #333);\n overflow: hidden;\n z-index: 2;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n.kd-lane-chart-container .border-left {\n border-left: 1px solid var(--kd-lane-container-border-color, #333);\n}\n.kd-lane-chart-container .kd-lane-chart-container-draw-area {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 3;\n border: none;\n}";
3817
3858
  styleInject(css_248z);
3818
3859
 
3819
3860
  /* script */
@@ -3849,8 +3890,12 @@ var __vue_render__ = function () {
3849
3890
  "div",
3850
3891
  {
3851
3892
  key: lane.laneId,
3893
+ ref: "refLaneDiv",
3894
+ refInFor: true,
3852
3895
  staticClass: "kd-lane-chart-lane-slot-container",
3853
3896
  class: { "border-left": index != 0 },
3897
+ style: _vm.laneContainerStyle(lane, "slot"),
3898
+ attrs: { "lane-id": lane.laneId },
3854
3899
  },
3855
3900
  [
3856
3901
  _c(
@@ -3869,8 +3914,12 @@ var __vue_render__ = function () {
3869
3914
  "div",
3870
3915
  {
3871
3916
  key: "" + lane.laneId,
3917
+ ref: "refLaneDiv",
3918
+ refInFor: true,
3872
3919
  staticClass: "kd-lane-chart-lane-slot-container",
3873
3920
  class: { "border-left": index != 0 },
3921
+ style: _vm.laneContainerStyle(lane, "slot"),
3922
+ attrs: { "lane-id": lane.laneId },
3874
3923
  },
3875
3924
  [
3876
3925
  _c(
@@ -3889,8 +3938,12 @@ var __vue_render__ = function () {
3889
3938
  "div",
3890
3939
  {
3891
3940
  key: lane.laneId,
3941
+ ref: "refLaneDiv",
3942
+ refInFor: true,
3892
3943
  staticClass: "kd-lane-chart-lane-container",
3893
3944
  class: { "border-left": index != 0 },
3945
+ style: _vm.laneContainerStyle(lane, "lane"),
3946
+ attrs: { "lane-id": lane.laneId },
3894
3947
  },
3895
3948
  [
3896
3949
  _c(
@@ -3932,18 +3985,25 @@ var __vue_render__ = function () {
3932
3985
  }),
3933
3986
  ]
3934
3987
  : [
3935
- _c("div", { staticClass: "kd-lane-chart-lane-container" }, [
3936
- _c("div", {
3937
- staticClass: "kd-lane-chart-lane-header",
3938
- style: _vm.headerStyle,
3939
- on: {
3940
- contextmenu: function ($event) {
3941
- $event.preventDefault();
3942
- return _vm.showContextMenu.apply(null, arguments)
3988
+ _c(
3989
+ "div",
3990
+ {
3991
+ ref: "refLaneDiv",
3992
+ staticClass: "kd-lane-chart-lane-container",
3993
+ },
3994
+ [
3995
+ _c("div", {
3996
+ staticClass: "kd-lane-chart-lane-header",
3997
+ style: _vm.headerStyle,
3998
+ on: {
3999
+ contextmenu: function ($event) {
4000
+ $event.preventDefault();
4001
+ return _vm.showContextMenu.apply(null, arguments)
4002
+ },
3943
4003
  },
3944
- },
3945
- }),
3946
- ]),
4004
+ }),
4005
+ ]
4006
+ ),
3947
4007
  ],
3948
4008
  _vm._v(" "),
3949
4009
  _c(
@@ -3958,10 +4018,7 @@ var __vue_render__ = function () {
3958
4018
  _vm._v(" "),
3959
4019
  _c("VueSimpleContextMenu", {
3960
4020
  ref: "vueSimpleContextMenu",
3961
- attrs: {
3962
- "element-id": "kd-lane-chart-context-menu",
3963
- options: _vm.contextMenuOptions,
3964
- },
4021
+ attrs: { options: _vm.contextMenuOptions },
3965
4022
  on: { "option-clicked": _vm.optionClicked },
3966
4023
  }),
3967
4024
  _vm._v(" "),