@veltra/desktop 1.1.15 → 1.1.18

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 (284) hide show
  1. package/dist/components/action/action-group.vue.d.ts +2 -2
  2. package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js.map +1 -1
  3. package/dist/components/action/action.js.map +1 -1
  4. package/dist/components/action/action.vue.d.ts +2 -2
  5. package/dist/components/action/style2.css +0 -4
  6. package/dist/components/auto-complete/auto-complete.js.map +1 -1
  7. package/dist/components/auto-complete/style.js +1 -1
  8. package/dist/components/auto-complete/use-keyboard.js.map +1 -1
  9. package/dist/components/auto-complete/use-suggestions.js.map +1 -1
  10. package/dist/components/badge/badge.js +1 -1
  11. package/dist/components/badge/badge.js.map +1 -1
  12. package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
  13. package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
  14. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  15. package/dist/components/batch-edit/helper.js.map +1 -1
  16. package/dist/components/batch-edit/style.js +1 -1
  17. package/dist/components/batch-edit/use-edit.js.map +1 -1
  18. package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
  19. package/dist/components/button/button-group.js.map +1 -1
  20. package/dist/components/button/button.js.map +1 -1
  21. package/dist/components/calendar/calendar.js.map +1 -1
  22. package/dist/components/calendar/utils.js.map +1 -1
  23. package/dist/components/card/card-action.js.map +1 -1
  24. package/dist/components/card/card-content.js.map +1 -1
  25. package/dist/components/card/card-cover.js.map +1 -1
  26. package/dist/components/card/card-header.js.map +1 -1
  27. package/dist/components/card/card.js.map +1 -1
  28. package/dist/components/cascade/cascade-panel-item.js.map +1 -1
  29. package/dist/components/cascade/cascade.js.map +1 -1
  30. package/dist/components/cascade/cascade.vue.d.ts +6 -6
  31. package/dist/components/cascade/node.js.map +1 -1
  32. package/dist/components/cascade/use-check.js.map +1 -1
  33. package/dist/components/cascade/use-data-map.js.map +1 -1
  34. package/dist/components/cascade/use-select.js +1 -1
  35. package/dist/components/cascade/use-select.js.map +1 -1
  36. package/dist/components/check-tag/check-tag.js.map +1 -1
  37. package/dist/components/checkbox/checkbox-button.js.map +1 -1
  38. package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
  39. package/dist/components/checkbox/checkbox.js.map +1 -1
  40. package/dist/components/checkbox/style.js +1 -1
  41. package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
  42. package/dist/components/code-editor/code-editor.js.map +1 -1
  43. package/dist/components/collapse/collapse-item.js.map +1 -1
  44. package/dist/components/collapse/collapse.js.map +1 -1
  45. package/dist/components/condition-editor/components/condition-group.js +138 -103
  46. package/dist/components/condition-editor/components/condition-group.js.map +1 -1
  47. package/dist/components/condition-editor/components/condition-row.js +146 -95
  48. package/dist/components/condition-editor/components/condition-row.js.map +1 -1
  49. package/dist/components/condition-editor/condition-editor.js +18 -40
  50. package/dist/components/condition-editor/condition-editor.js.map +1 -1
  51. package/dist/components/condition-editor/condition-editor.vue.d.ts +0 -2
  52. package/dist/components/condition-editor/core/evaluator.d.ts +22 -0
  53. package/dist/components/condition-editor/core/evaluator.js +111 -50
  54. package/dist/components/condition-editor/core/evaluator.js.map +1 -1
  55. package/dist/components/condition-editor/core/operators.js.map +1 -1
  56. package/dist/components/condition-editor/index.d.ts +2 -1
  57. package/dist/components/condition-editor/style2.css +159 -82
  58. package/dist/components/context-menu/api.js.map +1 -1
  59. package/dist/components/context-menu/context-menu-item.js.map +1 -1
  60. package/dist/components/context-menu/context-menu.js.map +1 -1
  61. package/dist/components/context-menu/style.js +1 -1
  62. package/dist/components/date-panel/date-panel.js.map +1 -1
  63. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  64. package/dist/components/date-panel/headers/day.js.map +1 -1
  65. package/dist/components/date-panel/headers/month.js.map +1 -1
  66. package/dist/components/date-panel/headers/year.js.map +1 -1
  67. package/dist/components/date-panel/panels/day.js.map +1 -1
  68. package/dist/components/date-panel/panels/month.js.map +1 -1
  69. package/dist/components/date-panel/panels/year.js.map +1 -1
  70. package/dist/components/date-panel/use-date-select.js.map +1 -1
  71. package/dist/components/date-panel/use-panel-date.js.map +1 -1
  72. package/dist/components/date-panel/use-panel.js.map +1 -1
  73. package/dist/components/date-picker/date-picker.js.map +1 -1
  74. package/dist/components/date-picker/date-picker.vue.d.ts +1 -1
  75. package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
  76. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
  77. package/dist/components/dialog/dialog.js.map +1 -1
  78. package/dist/components/dialog/style.js +2 -2
  79. package/dist/components/dialog/use-maximum.js.map +1 -1
  80. package/dist/components/drawer/drawer.js.map +1 -1
  81. package/dist/components/drawer/style.js +1 -1
  82. package/dist/components/dropdown/dropdown.js +1 -0
  83. package/dist/components/dropdown/dropdown.js.map +1 -1
  84. package/dist/components/dropdown/style.js +1 -1
  85. package/dist/components/empty/empty.js.map +1 -1
  86. package/dist/components/expression-editor/components/path-preview.js.map +1 -1
  87. package/dist/components/expression-editor/components/variable-picker.js.map +1 -1
  88. package/dist/components/expression-editor/core/chip.js.map +1 -1
  89. package/dist/components/expression-editor/core/editor.js.map +1 -1
  90. package/dist/components/expression-editor/core/mention.js.map +1 -1
  91. package/dist/components/expression-editor/core/model.js.map +1 -1
  92. package/dist/components/expression-editor/di.js.map +1 -1
  93. package/dist/components/expression-editor/expression-editor.js.map +1 -1
  94. package/dist/components/file-picker/file-picker.js.map +1 -1
  95. package/dist/components/file-picker/helper.js.map +1 -1
  96. package/dist/components/file-viewer/file-viewer.js.map +1 -1
  97. package/dist/components/file-viewer/helper.js.map +1 -1
  98. package/dist/components/file-viewer/previewers/docx-previewer.js.map +1 -1
  99. package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -1
  100. package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -1
  101. package/dist/components/file-viewer/previewers/pdf-viewport-scroll.js.map +1 -1
  102. package/dist/components/file-viewer/previewers/pdf-zoom-bridge.js.map +1 -1
  103. package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -1
  104. package/dist/components/file-viewer/previewers/text-previewer.js.map +1 -1
  105. package/dist/components/file-viewer/previewers/video-previewer.js.map +1 -1
  106. package/dist/components/float-button/float-button.js.map +1 -1
  107. package/dist/components/form/dynamic-form-model.js.map +1 -1
  108. package/dist/components/form/form-model.js.map +1 -1
  109. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
  110. package/dist/components/form/helper.js.map +1 -1
  111. package/dist/components/form/use-node-interceptor.js.map +1 -1
  112. package/dist/components/form-item/form-item.js.map +1 -1
  113. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js +2 -1
  114. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js.map +1 -1
  115. package/dist/components/gantt-chart/gantt-chart.js.map +1 -1
  116. package/dist/components/grid/breakpoint.js.map +1 -1
  117. package/dist/components/grid/grid-item.js.map +1 -1
  118. package/dist/components/grid/grid.js.map +1 -1
  119. package/dist/components/grid/use-responsive.js.map +1 -1
  120. package/dist/components/grid-input/grid-input.js.map +1 -1
  121. package/dist/components/group-input/group-input.js.map +1 -1
  122. package/dist/components/group-input/use-group-items.js.map +1 -1
  123. package/dist/components/icon/icon.js.map +1 -1
  124. package/dist/components/index.d.ts +1 -0
  125. package/dist/components/index.js +4 -0
  126. package/dist/components/input/input.vue.d.ts +2 -2
  127. package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js.map +1 -1
  128. package/dist/components/input/style.js +1 -1
  129. package/dist/components/kbd/kbd.js.map +1 -1
  130. package/dist/components/layout/layout-resizer.js.map +1 -1
  131. package/dist/components/layout/layout.js.map +1 -1
  132. package/dist/components/list/list-item.js.map +1 -1
  133. package/dist/components/list/list.js.map +1 -1
  134. package/dist/components/loading/directive.js.map +1 -1
  135. package/dist/components/loading/loading.js.map +1 -1
  136. package/dist/components/loading/style.js +1 -1
  137. package/dist/components/menu/helper.js.map +1 -1
  138. package/dist/components/menu/menu-item-collapsed.js.map +1 -1
  139. package/dist/components/menu/menu-item.js.map +1 -1
  140. package/dist/components/menu/menu-sub-collapsed.js.map +1 -1
  141. package/dist/components/menu/menu-sub.js.map +1 -1
  142. package/dist/components/menu/menu.js.map +1 -1
  143. package/dist/components/menu/use-menu-item.js.map +1 -1
  144. package/dist/components/menu/walk-menu-path.js.map +1 -1
  145. package/dist/components/message/helper.js.map +1 -1
  146. package/dist/components/message/message-box.js.map +1 -1
  147. package/dist/components/message/message.js.map +1 -1
  148. package/dist/components/message/message2.js.map +1 -1
  149. package/dist/components/message-confirm/message-confirm.js.map +1 -1
  150. package/dist/components/message-confirm/message-confirm2.js.map +1 -1
  151. package/dist/components/multi-select/multi-select-option.js.map +1 -1
  152. package/dist/components/multi-select/multi-select.js.map +1 -1
  153. package/dist/components/multi-select/multi-select.vue.d.ts +2 -2
  154. package/dist/components/multi-select/style.js +1 -1
  155. package/dist/components/multi-tree-select/multi-tree-select.js.map +1 -1
  156. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +5 -5
  157. package/dist/components/multi-tree-select/style.js +1 -1
  158. package/dist/components/node-render/node-render.js.map +1 -1
  159. package/dist/components/notification/index.js.map +1 -1
  160. package/dist/components/notification/notification.js.map +1 -1
  161. package/dist/components/notification/notification.vue.d.ts +1 -1
  162. package/dist/components/number/number.js.map +1 -1
  163. package/dist/components/number-input/number-input.js.map +1 -1
  164. package/dist/components/number-input/number-input.vue.d.ts +2 -2
  165. package/dist/components/number-range-input/number-range-input.js.map +1 -1
  166. package/dist/components/paginator/paginator.js.map +1 -1
  167. package/dist/components/palette/color-transform.js.map +1 -1
  168. package/dist/components/palette/palette-alpha.js.map +1 -1
  169. package/dist/components/palette/palette-color-switch.js.map +1 -1
  170. package/dist/components/palette/palette-hue.js.map +1 -1
  171. package/dist/components/palette/palette-sv.js.map +1 -1
  172. package/dist/components/palette/palette.js.map +1 -1
  173. package/dist/components/palette/use-hsv.js.map +1 -1
  174. package/dist/components/password-input/password-input.js.map +1 -1
  175. package/dist/components/pop-confirm/pop-confirm.js.map +1 -1
  176. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  177. package/dist/components/progress/progress.js.map +1 -1
  178. package/dist/components/progress-nodes/progress-nodes.js.map +1 -1
  179. package/dist/components/radio/radio.js.map +1 -1
  180. package/dist/components/radio/style.js +1 -1
  181. package/dist/components/radio-group/radio-group.js.map +1 -1
  182. package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
  183. package/dist/components/rich-text-editor/toolbar.js.map +1 -1
  184. package/dist/components/scroll/scroll-bar.js +2 -0
  185. package/dist/components/scroll/scroll-bar.js.map +1 -1
  186. package/dist/components/scroll/scroll.js.map +1 -1
  187. package/dist/components/select/select.js.map +1 -1
  188. package/dist/components/select/select.vue.d.ts +2 -2
  189. package/dist/components/select/use-keyboard.js.map +1 -1
  190. package/dist/components/select/use-options.js.map +1 -1
  191. package/dist/components/slider/slider-thumb.js.map +1 -1
  192. package/dist/components/slider/slider.js +1 -1
  193. package/dist/components/slider/slider.js.map +1 -1
  194. package/dist/components/slider/use-slider.js.map +1 -1
  195. package/dist/components/steps/steps.js.map +1 -1
  196. package/dist/components/steps/steps.vue.d.ts +3 -3
  197. package/dist/components/switch/switch.js.map +1 -1
  198. package/dist/components/table/di.js.map +1 -1
  199. package/dist/components/table/node/col.js.map +1 -1
  200. package/dist/components/table/node/row.js.map +1 -1
  201. package/dist/components/table/table-body.js.map +1 -1
  202. package/dist/components/table/table-cell.js.map +1 -1
  203. package/dist/components/table/table-foot.js.map +1 -1
  204. package/dist/components/table/table-head.js.map +1 -1
  205. package/dist/components/table/table-row.js.map +1 -1
  206. package/dist/components/table/table.js.map +1 -1
  207. package/dist/components/table/use-check.js.map +1 -1
  208. package/dist/components/table/use-col-resize.js.map +1 -1
  209. package/dist/components/table/use-columns.js.map +1 -1
  210. package/dist/components/table/use-fixed-columns.js.map +1 -1
  211. package/dist/components/table/use-rows.js.map +1 -1
  212. package/dist/components/table/use-table.js.map +1 -1
  213. package/dist/components/table-editor/table-editor.js.map +1 -1
  214. package/dist/components/tabs/style.js +1 -1
  215. package/dist/components/tabs/tabs-horizontal.js.map +1 -1
  216. package/dist/components/tabs/tabs-horizontal.vue.d.ts +1 -1
  217. package/dist/components/tabs/tabs-vertical.js.map +1 -1
  218. package/dist/components/tabs/tabs.js.map +1 -1
  219. package/dist/components/tabs/tabs.vue.d.ts +1 -1
  220. package/dist/components/tabs/use-tabs-bar.js.map +1 -1
  221. package/dist/components/tag/tag.js.map +1 -1
  222. package/dist/components/text/text.js.map +1 -1
  223. package/dist/components/textarea/style.js +1 -1
  224. package/dist/components/textarea/textarea.js.map +1 -1
  225. package/dist/components/textarea/textarea.vue.d.ts +2 -2
  226. package/dist/components/textarea/utils.js.map +1 -1
  227. package/dist/components/theme/schema.js.map +1 -1
  228. package/dist/components/theme/theme.js.map +1 -1
  229. package/dist/components/tip/tip.js.map +1 -1
  230. package/dist/components/tip/tip.vue.d.ts +1 -1
  231. package/dist/components/tip/use-nest.js.map +1 -1
  232. package/dist/components/tree/tree-node.js.map +1 -1
  233. package/dist/components/tree/tree-node2.js.map +1 -1
  234. package/dist/components/tree/tree.js.map +1 -1
  235. package/dist/components/tree/tree.vue.d.ts +1 -1
  236. package/dist/components/tree/use-check.js.map +1 -1
  237. package/dist/components/tree/use-filter.js.map +1 -1
  238. package/dist/components/tree/use-select.js.map +1 -1
  239. package/dist/components/tree/use-tree-nodes.js.map +1 -1
  240. package/dist/components/tree-select/tree-select.js.map +1 -1
  241. package/dist/components/tree-select/tree-select.vue.d.ts +5 -5
  242. package/dist/components/watermark/watermark.js.map +1 -1
  243. package/dist/index.d.ts +4 -3
  244. package/dist/index.js +2 -1
  245. package/dist/install.js.map +1 -1
  246. package/dist/types/batch-edit.d.ts +2 -2
  247. package/dist/types/condition-editor.d.ts +21 -9
  248. package/dist/types/index.d.ts +2 -2
  249. package/package.json +13 -16
  250. package/src/components/action/style.scss +0 -6
  251. package/src/components/auto-complete/style.scss +0 -1
  252. package/src/components/auto-complete/style.ts +1 -1
  253. package/src/components/badge/badge.vue +1 -1
  254. package/src/components/batch-edit/style.ts +1 -1
  255. package/src/components/button/style.scss +1 -1
  256. package/src/components/cascade/use-select.ts +8 -6
  257. package/src/components/checkbox/style.ts +1 -1
  258. package/src/components/collapse/__test__/collapse.test.ts +3 -3
  259. package/src/components/condition-editor/components/condition-group.vue +118 -87
  260. package/src/components/condition-editor/components/condition-row.vue +137 -89
  261. package/src/components/condition-editor/condition-editor.vue +19 -48
  262. package/src/components/condition-editor/core/evaluator.ts +143 -57
  263. package/src/components/condition-editor/index.ts +6 -0
  264. package/src/components/condition-editor/style.scss +189 -102
  265. package/src/components/context-menu/style.ts +1 -1
  266. package/src/components/dialog/style.ts +2 -2
  267. package/src/components/drawer/style.ts +1 -1
  268. package/src/components/dropdown/style.ts +1 -1
  269. package/src/components/expression-editor/style.scss +1 -1
  270. package/src/components/form-item/form-item.vue +4 -9
  271. package/src/components/input/style.ts +1 -1
  272. package/src/components/loading/style.ts +1 -1
  273. package/src/components/menu/style.scss +1 -1
  274. package/src/components/message/style.scss +1 -1
  275. package/src/components/multi-select/style.ts +1 -1
  276. package/src/components/multi-tree-select/style.ts +1 -1
  277. package/src/components/number-input/__test__/number-input.test.ts +1 -1
  278. package/src/components/radio/style.ts +1 -1
  279. package/src/components/slider/slider.vue +1 -1
  280. package/src/components/table/di.ts +1 -1
  281. package/src/components/tabs/style.ts +1 -1
  282. package/src/components/textarea/style.ts +1 -1
  283. package/src/types/batch-edit.ts +2 -2
  284. package/src/types/condition-editor.ts +22 -8
@@ -4,5 +4,5 @@ import '../input/style'
4
4
  import '../icon/style'
5
5
  import '@veltra/directives/ripple/style.js'
6
6
  import '../tag/style'
7
- import '@veltra/styles/anime/zoom-in.scss'
7
+ import '@veltra/styles/transitions/zoom-in.scss'
8
8
  import './style.scss'
@@ -50,7 +50,7 @@ const setPosition = () => {
50
50
  const { width, height } = supRef.value.getBoundingClientRect()
51
51
  setStyles(supRef.value, {
52
52
  transform: `translate(-${width / 2}px, -${height / 2}px)`,
53
- backgroundColor: props.color && props.color,
53
+ backgroundColor: props.color,
54
54
  zIndex: zIndex()
55
55
  })
56
56
  }
@@ -7,5 +7,5 @@ import '../scroll/style'
7
7
  import '../table/style'
8
8
  import '../kbd/style'
9
9
  import '@veltra/directives/ripple/style.js'
10
- import '@veltra/styles/anime/fade.scss'
10
+ import '@veltra/styles/transitions/fade.scss'
11
11
  import './style.scss'
@@ -1,7 +1,7 @@
1
1
  @use 'sass:map';
2
2
  @use 'pkg:@veltra/styles/mixins' as m;
3
- @use 'pkg:@veltra/styles/vars';
4
3
  @use 'pkg:@veltra/styles/functions' as fn;
4
+ @use 'pkg:@veltra/styles/vars';
5
5
 
6
6
  $root-name: button;
7
7
 
@@ -59,12 +59,14 @@ export function useSelect(options: SelectOptions): UseSelectReturned {
59
59
  const { modelValue, separator } = props
60
60
  const valueNodes =
61
61
  modelValue && typeof modelValue === 'string' ? modelValue.split(separator!) : undefined
62
- return valueNodes
63
- ?.map((v) => {
64
- const node = dataMap.value.get(v)
65
- return node?.label ?? v
66
- })
67
- .join(props.separator)
62
+ return (
63
+ valueNodes
64
+ ?.map((v) => {
65
+ const node = dataMap.value.get(v)
66
+ return node?.label ?? v
67
+ })
68
+ .join(props.separator) ?? ''
69
+ )
68
70
  })
69
71
 
70
72
  function getPanelItemList(data?: CascadeNode[]) {
@@ -1,3 +1,3 @@
1
- import '@veltra/styles/anime/zoom-in.scss'
1
+ import '@veltra/styles/transitions/zoom-in.scss'
2
2
  import '../tag/style'
3
3
  import './style.scss'
@@ -1,4 +1,4 @@
1
- // @vitest-environment happy-dom
1
+ import { describe, expect, it } from 'vitest'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import UCollapseItem from '../collapse-item.vue'
@@ -119,7 +119,7 @@ describe('Collapse', () => {
119
119
 
120
120
  const activeItems = host.querySelectorAll('.u-collapse__item.is-active')
121
121
  expect(activeItems.length).toBe(1)
122
- expect(activeItems[0].querySelector('.u-collapse__title')?.textContent).toBe('Title A')
122
+ expect(activeItems[0]?.querySelector('.u-collapse__title')?.textContent).toBe('Title A')
123
123
  } finally {
124
124
  unmount()
125
125
  }
@@ -135,7 +135,7 @@ describe('Collapse', () => {
135
135
 
136
136
  const activeItems = host.querySelectorAll('.u-collapse__item.is-active')
137
137
  expect(activeItems.length).toBe(1)
138
- expect(activeItems[0].querySelector('.u-collapse__title')?.textContent).toBe('Title A')
138
+ expect(activeItems[0]?.querySelector('.u-collapse__title')?.textContent).toBe('Title A')
139
139
  } finally {
140
140
  unmount()
141
141
  }
@@ -1,131 +1,162 @@
1
1
  <template>
2
- <div :class="cls.e('group')">
3
- <!-- AND/OR 标签 + 汇总结果 -->
4
- <div :class="cls.e('group-header')">
5
- <span :class="[cls.e('logic-tag'), cls.em('logic-tag', group.logic)]" @click="toggleLogic">
6
- {{ group.logic.toUpperCase() }} ▾
7
- </span>
8
- <span
9
- v-if="hasResult"
10
- :class="[cls.e('group-result'), cls.em('group-result', group._result ? 'pass' : 'fail')]"
11
- >
12
- {{ group._result ? '✓ 通过' : '✗ 不通过' }}
13
- </span>
14
- </div>
15
-
16
- <!-- 嵌套组容器 -->
17
- <div :class="cls.e('group-body')">
18
- <!-- 子条件 -->
19
- <ConditionRow
20
- v-for="(cond, idx) in group.conditions"
21
- :key="idx"
22
- :item="cond"
23
- :fields="fields"
24
- :size="size"
25
- :disabled="disabled"
26
- :readonly="readonly"
27
- @update:item="(item) => updateCondition(idx, item)"
28
- @delete="removeCondition(idx)"
29
- @mention="(p) => emit('mention', p)"
30
- />
31
-
32
- <!-- 子分组(递归) -->
33
- <ConditionGroup
34
- v-for="(sub, idx) in group.groups"
35
- :key="idx"
36
- :group="sub"
37
- :fields="fields"
38
- :size="size"
39
- :disabled="disabled"
40
- :readonly="readonly"
41
- @update:group="(g) => updateSubGroup(idx, g)"
42
- @remove="() => removeSubGroup(idx)"
43
- @mention="(p) => emit('mention', p)"
44
- />
45
-
46
- <!-- 空状态 + 添加按钮 -->
47
- <div :class="cls.e('group-actions')">
48
- <span v-if="!readonly" :class="cls.e('add-btn')" @click="addCondition">+ 添加条件</span>
49
- <span v-if="!readonly" :class="cls.e('add-btn')" @click="addGroup">+ 添加条件组</span>
2
+ <div :class="[cls.e('group'), depth > 0 ? cls.em('group', 'nested') : '']">
3
+ <template v-if="group.children.length === 0">
4
+ <div :class="cls.e('group-empty')">
5
+ <span :class="cls.e('group-empty-tip')">暂无条件</span>
50
6
  </div>
7
+ </template>
8
+
9
+ <ul :class="cls.e('group-list')">
10
+ <li v-for="(child, idx) in group.children" :key="idx" :class="cls.e('group-item')">
11
+ <span
12
+ v-if="idx > 0"
13
+ :class="[cls.e('connector'), cls.em('connector', connectorAt(idx - 1))]"
14
+ :tabindex="readonly || disabled ? -1 : 0"
15
+ role="button"
16
+ :aria-label="`切换连接符(当前 ${connectorAt(idx - 1).toUpperCase()})`"
17
+ @click="toggleConnector(idx - 1)"
18
+ @keydown.enter.prevent="toggleConnector(idx - 1)"
19
+ @keydown.space.prevent="toggleConnector(idx - 1)"
20
+ >{{ connectorAt(idx - 1).toUpperCase() }}</span
21
+ >
22
+ <span v-else :class="cls.e('connector-placeholder')">WHERE</span>
23
+
24
+ <div :class="cls.e('group-item-body')">
25
+ <ConditionRow
26
+ v-if="child.type === 'condition'"
27
+ :item="child"
28
+ :fields="fields"
29
+ :size="size"
30
+ :disabled="disabled"
31
+ :readonly="readonly"
32
+ @update:item="(it) => updateChild(idx, it)"
33
+ @delete="removeChild(idx)"
34
+ @mention="(p) => emit('mention', p)"
35
+ />
36
+ <ConditionGroup
37
+ v-else
38
+ :group="child"
39
+ :fields="fields"
40
+ :size="size"
41
+ :depth="depth + 1"
42
+ :disabled="disabled"
43
+ :readonly="readonly"
44
+ @update:group="(g) => updateChild(idx, g)"
45
+ @remove="removeChild(idx)"
46
+ @mention="(p) => emit('mention', p)"
47
+ />
48
+ </div>
49
+ </li>
50
+ </ul>
51
+
52
+ <div v-if="!readonly" :class="cls.e('group-actions')">
53
+ <button type="button" :class="cls.e('action-btn')" :disabled="disabled" @click="addCondition">
54
+ <u-icon><Plus /></u-icon>
55
+ <span>添加条件</span>
56
+ </button>
57
+ <button type="button" :class="cls.e('action-btn')" :disabled="disabled" @click="addGroup">
58
+ <u-icon><Plus /></u-icon>
59
+ <span>添加条件组</span>
60
+ </button>
61
+ <button
62
+ v-if="depth > 0"
63
+ type="button"
64
+ :class="[cls.e('action-btn'), cls.em('action-btn', 'danger')]"
65
+ :disabled="disabled"
66
+ @click="emit('remove')"
67
+ >
68
+ <u-icon><Delete /></u-icon>
69
+ <span>删除组</span>
70
+ </button>
51
71
  </div>
52
72
  </div>
53
73
  </template>
54
74
 
55
75
  <script lang="ts" setup>
76
+ import { Delete, Plus } from '@veltra/icons/normal'
56
77
  import { bem } from '@veltra/utils'
57
- import { computed } from 'vue'
58
78
 
59
- import type { ConditionField, ConditionGroup, ConditionItem } from '../../../types'
60
- import { createEmptyGroup, createEmptyItem } from '../core/evaluator'
79
+ import type {
80
+ ConditionConnector,
81
+ ConditionField,
82
+ ConditionGroup as ConditionGroupNode,
83
+ ConditionNode
84
+ } from '../../../types'
85
+ import { UIcon } from '../../icon'
86
+ import { createEmptyGroup, createEmptyLeaf } from '../core/evaluator'
61
87
  import ConditionRow, { type MentionPayload } from './condition-row.vue'
62
88
 
63
89
  defineOptions({ name: 'ConditionGroup' })
64
90
 
65
91
  const props = withDefaults(
66
92
  defineProps<{
67
- group: ConditionGroup
93
+ group: ConditionGroupNode
68
94
  fields?: ConditionField[]
69
95
  size?: 'small' | 'default' | 'large'
96
+ depth?: number
70
97
  disabled?: boolean
71
98
  readonly?: boolean
72
99
  }>(),
73
- { size: 'default' }
100
+ { size: 'default', depth: 0 }
74
101
  )
75
102
 
76
103
  const emit = defineEmits<{
77
- (e: 'update:group', group: ConditionGroup): void
104
+ (e: 'update:group', group: ConditionGroupNode): void
78
105
  (e: 'remove'): void
79
106
  (e: 'mention', payload: MentionPayload): void
80
107
  }>()
81
108
 
82
109
  const cls = bem('condition-editor')
83
110
 
84
- const hasResult = computed(() => props.group._result !== undefined)
85
-
86
- function toggleLogic() {
87
- if (props.disabled || props.readonly) return
88
- emit('update:group', {
89
- ...props.group,
90
- logic: props.group.logic === 'and' ? 'or' : 'and'
91
- })
111
+ function connectorAt(index: number): ConditionConnector {
112
+ return props.group.connectors[index] ?? 'and'
92
113
  }
93
114
 
94
- function addCondition() {
95
- emit('update:group', {
96
- ...props.group,
97
- conditions: [...props.group.conditions, createEmptyItem()]
98
- })
115
+ function emitUpdate(next: Partial<ConditionGroupNode>) {
116
+ emit('update:group', { ...props.group, ...next })
99
117
  }
100
118
 
101
- function removeCondition(idx: number) {
102
- const conditions = [...props.group.conditions]
103
- conditions.splice(idx, 1)
104
- emit('update:group', { ...props.group, conditions })
119
+ function toggleConnector(index: number) {
120
+ if (props.disabled || props.readonly) return
121
+ const next = props.group.connectors.slice()
122
+ next[index] = connectorAt(index) === 'and' ? 'or' : 'and'
123
+ emitUpdate({ connectors: next })
105
124
  }
106
125
 
107
- function updateCondition(idx: number, item: ConditionItem) {
108
- const conditions = [...props.group.conditions]
109
- conditions[idx] = item
110
- emit('update:group', { ...props.group, conditions })
126
+ function addCondition() {
127
+ appendChild(createEmptyLeaf())
111
128
  }
112
129
 
113
130
  function addGroup() {
114
- emit('update:group', {
115
- ...props.group,
116
- groups: [...props.group.groups, createEmptyGroup()]
117
- })
131
+ appendChild({ ...createEmptyGroup(), children: [createEmptyLeaf()], connectors: [] })
132
+ }
133
+
134
+ function appendChild(node: ConditionNode) {
135
+ const children = [...props.group.children, node]
136
+ const connectors =
137
+ props.group.children.length === 0
138
+ ? props.group.connectors
139
+ : [...props.group.connectors, 'and' as const]
140
+ emitUpdate({ children, connectors })
118
141
  }
119
142
 
120
- function removeSubGroup(idx: number) {
121
- const groups = [...props.group.groups]
122
- groups.splice(idx, 1)
123
- emit('update:group', { ...props.group, groups })
143
+ function updateChild(index: number, node: ConditionNode) {
144
+ const children = props.group.children.slice()
145
+ children[index] = node
146
+ emitUpdate({ children })
124
147
  }
125
148
 
126
- function updateSubGroup(idx: number, g: ConditionGroup) {
127
- const groups = [...props.group.groups]
128
- groups[idx] = g
129
- emit('update:group', { ...props.group, groups })
149
+ function removeChild(index: number) {
150
+ const children = props.group.children.slice()
151
+ children.splice(index, 1)
152
+ const connectors = props.group.connectors.slice()
153
+ // 移除第 index 项时,连接到该项的连接符也要移除
154
+ // connectors[i] 位于 children[i] 与 children[i+1] 之间
155
+ if (index === 0) {
156
+ if (connectors.length > 0) connectors.shift()
157
+ } else {
158
+ connectors.splice(index - 1, 1)
159
+ }
160
+ emitUpdate({ children, connectors })
130
161
  }
131
162
  </script>
@@ -1,6 +1,5 @@
1
1
  <template>
2
- <div :class="[cls.e('row'), bem.is('focused', focused)]">
3
- <!-- 字段选择 -->
2
+ <div :class="cls.e('row')">
4
3
  <u-select
5
4
  :class="cls.e('field')"
6
5
  :model-value="item.field"
@@ -11,10 +10,10 @@
11
10
  :size="size"
12
11
  :disabled="disabled || readonly"
13
12
  :clearable="false"
13
+ filterable
14
14
  @update:model-value="onFieldChange"
15
15
  />
16
16
 
17
- <!-- 运算符选择 -->
18
17
  <u-select
19
18
  :class="cls.e('operator')"
20
19
  :model-value="item.operator"
@@ -23,61 +22,95 @@
23
22
  label-key="label"
24
23
  placeholder="运算符"
25
24
  :size="size"
26
- :disabled="disabled || readonly"
25
+ :disabled="disabled || readonly || !currentField"
27
26
  :clearable="false"
28
27
  @update:model-value="onOperatorChange"
29
28
  />
30
29
 
31
- <!-- 值输入 -->
32
30
  <div :class="cls.e('value')">
33
- <template v-if="needValue">
31
+ <template v-if="!needValue">
32
+ <span :class="cls.e('value-empty')">—</span>
33
+ </template>
34
+
35
+ <template v-else-if="enumValueOptions">
36
+ <u-select
37
+ :model-value="constantValue"
38
+ :options="enumValueOptions"
39
+ value-key="value"
40
+ label-key="label"
41
+ placeholder="选择值"
42
+ :size="size"
43
+ :disabled="disabled || readonly"
44
+ :clearable="false"
45
+ @update:model-value="onConstantChange"
46
+ />
47
+ </template>
48
+
49
+ <template v-else-if="booleanValueOptions">
50
+ <u-select
51
+ :model-value="constantValue"
52
+ :options="booleanValueOptions"
53
+ value-key="value"
54
+ label-key="label"
55
+ placeholder="选择值"
56
+ :size="size"
57
+ :disabled="disabled || readonly"
58
+ :clearable="false"
59
+ @update:model-value="onConstantChange"
60
+ />
61
+ </template>
62
+
63
+ <template v-else-if="item.value.kind === 'variable'">
64
+ <span
65
+ ref="chipRef"
66
+ :class="cls.e('value-chip')"
67
+ tabindex="0"
68
+ :title="`变量:${item.value.name}`"
69
+ @click="onChipClick"
70
+ @keydown.delete="onChipDelete"
71
+ >
72
+ <span :class="cls.e('value-chip-label')">{{ item.value.name }}</span>
73
+ <span :class="cls.e('value-chip-close')" @click.stop="onChipDelete">
74
+ <u-icon><Close /></u-icon>
75
+ </span>
76
+ </span>
77
+ </template>
78
+
79
+ <template v-else>
34
80
  <input
35
- v-if="item.value.kind === 'constant'"
36
81
  ref="valueInputRef"
37
82
  :class="cls.e('value-input')"
38
- :value="item.value.value"
83
+ :type="inputType"
84
+ :value="constantValue"
39
85
  :placeholder="placeholder"
40
86
  :disabled="disabled"
41
87
  :readonly="readonly"
42
88
  @input="onValueInput"
43
89
  @keydown="onValueKeydown"
44
- @focus="focused = true"
45
- @blur="focused = false"
46
90
  />
47
- <span
48
- v-else
49
- :class="cls.e('value-chip')"
50
- tabindex="0"
51
- @click="onChipClick"
52
- @keydown.delete="onChipDelete"
53
- >
54
- <span :class="cls.e('value-chip-label')">{{ variableLabel }}</span>
55
- <span :class="cls.e('value-chip-close')" @click.stop="onChipDelete">×</span>
56
- </span>
57
91
  </template>
58
- <span v-else :class="cls.e('value-empty')">—</span>
59
92
  </div>
60
93
 
61
- <!-- 删除 -->
62
- <span v-if="!readonly" :class="cls.e('row-delete')" @click="emit('delete')">×</span>
63
-
64
- <!-- 结果指示 -->
65
- <span
66
- v-if="hasResult"
67
- :class="[cls.e('result'), cls.em('result', item._result ? 'pass' : 'fail')]"
94
+ <button
95
+ v-if="!readonly"
96
+ type="button"
97
+ :class="cls.e('row-delete')"
98
+ :disabled="disabled"
99
+ title="删除条件"
100
+ @click="emit('delete')"
68
101
  >
69
- {{ item._result ? '✓' : '✗' }}
70
- </span>
71
- <span v-else :class="[cls.e('result'), cls.em('result', 'none')]">—</span>
102
+ <u-icon><Delete /></u-icon>
103
+ </button>
72
104
  </div>
73
105
  </template>
74
106
 
75
107
  <script lang="ts" setup>
76
- import { useFormFallbackProps } from '@veltra/compositions'
77
- import { bem, injectFormContext } from '@veltra/utils'
78
- import { computed, ref, useTemplateRef } from 'vue'
108
+ import { Close, Delete } from '@veltra/icons/normal'
109
+ import { bem } from '@veltra/utils'
110
+ import { computed, useTemplateRef } from 'vue'
79
111
 
80
- import type { ConditionField, ConditionItem, ConditionValue } from '../../../types'
112
+ import type { ConditionField, ConditionLeaf, ConditionValue } from '../../../types'
113
+ import { UIcon } from '../../icon'
81
114
  import { USelect } from '../../select'
82
115
  import { getOperatorsByFieldType, type OperatorDef } from '../core/operators'
83
116
 
@@ -90,25 +123,17 @@ export interface MentionPayload {
90
123
 
91
124
  const props = withDefaults(
92
125
  defineProps<{
93
- item: ConditionItem
126
+ item: ConditionLeaf
94
127
  fields?: ConditionField[]
95
- size?: string
128
+ size?: 'small' | 'default' | 'large'
96
129
  disabled?: boolean
97
130
  readonly?: boolean
98
131
  }>(),
99
- {}
132
+ { size: 'default' }
100
133
  )
101
134
 
102
- const { formProps } = injectFormContext()
103
-
104
- const { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {
105
- size: 'default',
106
- disabled: false,
107
- readonly: false
108
- })
109
-
110
135
  const emit = defineEmits<{
111
- (e: 'update:item', item: ConditionItem): void
136
+ (e: 'update:item', item: ConditionLeaf): void
112
137
  (e: 'delete'): void
113
138
  (e: 'mention', payload: MentionPayload): void
114
139
  }>()
@@ -116,7 +141,7 @@ const emit = defineEmits<{
116
141
  const cls = bem('condition-editor')
117
142
 
118
143
  const valueInputRef = useTemplateRef<HTMLInputElement>('valueInputRef')
119
- const focused = ref(false)
144
+ const chipRef = useTemplateRef<HTMLElement>('chipRef')
120
145
 
121
146
  const fieldOptions = computed(() =>
122
147
  (props.fields ?? []).map((f) => ({ label: f.label, value: f.value }))
@@ -124,85 +149,108 @@ const fieldOptions = computed(() =>
124
149
 
125
150
  const currentField = computed(() => props.fields?.find((f) => f.value === props.item.field))
126
151
 
127
- const operatorOptions = computed(() => {
152
+ const operatorOptions = computed<OperatorDef[]>(() => {
128
153
  if (!currentField.value) {
129
- return props.item.operator ? [{ label: props.item.operator, value: props.item.operator }] : []
154
+ return props.item.operator
155
+ ? [{ label: props.item.operator, value: props.item.operator, needValue: true }]
156
+ : []
130
157
  }
131
158
  return getOperatorsByFieldType(currentField.value.type)
132
159
  })
133
160
 
134
- const needValue = computed(() => {
135
- const ops = operatorOptions.value as OperatorDef[]
136
- const op = ops.find((o) => o.value === props.item.operator)
137
- return op?.needValue ?? true
161
+ const currentOperator = computed(() =>
162
+ operatorOptions.value.find((o) => o.value === props.item.operator)
163
+ )
164
+
165
+ const needValue = computed(() => currentOperator.value?.needValue ?? true)
166
+
167
+ const constantValue = computed(() =>
168
+ props.item.value.kind === 'constant' ? props.item.value.value : ''
169
+ )
170
+
171
+ /** 枚举字段的可选值(仅在非 `in` 等多值运算符下展开为下拉) */
172
+ const enumValueOptions = computed(() => {
173
+ if (!currentField.value || currentField.value.type !== 'enum') return null
174
+ if (props.item.operator === 'in') return null
175
+ return currentField.value.enumOptions ?? []
138
176
  })
139
177
 
140
- const hasResult = computed(() => props.item._result !== undefined)
178
+ const booleanValueOptions = computed(() => {
179
+ if (!currentField.value || currentField.value.type !== 'boolean') return null
180
+ if (!needValue.value) return null
181
+ return [
182
+ { label: '是', value: 'true' },
183
+ { label: '否', value: 'false' }
184
+ ]
185
+ })
141
186
 
142
- const placeholder = computed(() => (props.fields?.length ? '输入值或 @ 引用变量' : ''))
187
+ const inputType = computed(() => {
188
+ const type = currentField.value?.type
189
+ if (type === 'number') return 'number'
190
+ if (type === 'date') return 'date'
191
+ return 'text'
192
+ })
143
193
 
144
- const variableLabel = computed(() => {
145
- if (props.item.value.kind !== 'variable') return ''
146
- return props.item.value.name
194
+ const placeholder = computed(() => {
195
+ if (props.item.operator === 'in') return '多个值用逗号分隔'
196
+ if (!props.fields?.length) return ''
197
+ return '输入值或 @ 引用变量'
147
198
  })
148
199
 
200
+ function emitUpdate(patch: Partial<ConditionLeaf>) {
201
+ emit('update:item', { ...props.item, ...patch })
202
+ }
203
+
149
204
  function onFieldChange(val: string) {
150
205
  const field = props.fields?.find((f) => f.value === val)
151
- const newItem: ConditionItem = {
206
+ const nextOps = field ? getOperatorsByFieldType(field.type) : []
207
+ const nextOp = nextOps[0]?.value ?? 'eq'
208
+ emit('update:item', {
152
209
  ...props.item,
153
210
  field: val,
154
- operator: field ? getOperatorsByFieldType(field.type)[0]!.value : 'eq',
211
+ operator: nextOp,
155
212
  value: { kind: 'constant', value: '' }
156
- }
157
- emit('update:item', newItem)
213
+ })
158
214
  }
159
215
 
160
216
  function onOperatorChange(val: string) {
161
- const newItem: ConditionItem = {
162
- ...props.item,
217
+ emitUpdate({
163
218
  operator: val,
164
219
  value: { kind: 'constant', value: '' }
165
- }
166
- emit('update:item', newItem)
220
+ })
167
221
  }
168
222
 
169
223
  function onValueInput(e: Event) {
170
- const val = (e.target as HTMLInputElement).value
171
- emit('update:item', {
172
- ...props.item,
173
- value: { kind: 'constant', value: val }
174
- })
224
+ emitUpdate({ value: { kind: 'constant', value: (e.target as HTMLInputElement).value } })
225
+ }
226
+
227
+ function onConstantChange(val: string) {
228
+ emitUpdate({ value: { kind: 'constant', value: val } })
175
229
  }
176
230
 
177
231
  function onValueKeydown(e: KeyboardEvent) {
178
- if (disabled.value || readonly.value) return
232
+ if (props.disabled || props.readonly) return
179
233
  if (e.key === '@' && valueInputRef.value) {
180
234
  e.preventDefault()
181
235
  emit('mention', {
182
236
  triggerDom: valueInputRef.value,
183
- setValue: (val: ConditionValue) => {
184
- emit('update:item', { ...props.item, value: val })
185
- }
237
+ setValue: (val) => emitUpdate({ value: val })
186
238
  })
187
239
  }
188
240
  }
189
241
 
190
242
  function onChipClick() {
191
- if (disabled.value || readonly.value) return
192
- if (valueInputRef.value) {
193
- emit('mention', {
194
- triggerDom: valueInputRef.value,
195
- setValue: (val: ConditionValue) => {
196
- emit('update:item', { ...props.item, value: val })
197
- }
198
- })
199
- }
243
+ if (props.disabled || props.readonly) return
244
+ const dom = chipRef.value
245
+ if (!dom) return
246
+ emit('mention', {
247
+ triggerDom: dom,
248
+ setValue: (val) => emitUpdate({ value: val })
249
+ })
200
250
  }
201
251
 
202
252
  function onChipDelete() {
203
- emit('update:item', {
204
- ...props.item,
205
- value: { kind: 'constant', value: '' }
206
- })
253
+ if (props.disabled || props.readonly) return
254
+ emitUpdate({ value: { kind: 'constant', value: '' } })
207
255
  }
208
256
  </script>