@veltra/desktop 1.8.3 → 1.8.4

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 (197) hide show
  1. package/dist/components/action/action-group.js.map +1 -1
  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/auto-complete/auto-complete.js.map +1 -1
  5. package/dist/components/badge/badge.js.map +1 -1
  6. package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
  7. package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
  8. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  9. package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
  10. package/dist/components/button/button-group.js.map +1 -1
  11. package/dist/components/button/button.js.map +1 -1
  12. package/dist/components/calendar/calendar.js.map +1 -1
  13. package/dist/components/card/card-action.js.map +1 -1
  14. package/dist/components/card/card-content.js.map +1 -1
  15. package/dist/components/card/card-cover.js.map +1 -1
  16. package/dist/components/card/card-header.js.map +1 -1
  17. package/dist/components/card/card.js.map +1 -1
  18. package/dist/components/cascade/cascade-panel-item.js.map +1 -1
  19. package/dist/components/cascade/cascade.js +1 -0
  20. package/dist/components/cascade/cascade.js.map +1 -1
  21. package/dist/components/cascade/use-select.js +6 -2
  22. package/dist/components/cascade/use-select.js.map +1 -1
  23. package/dist/components/check-tag/check-tag.js.map +1 -1
  24. package/dist/components/checkbox/checkbox-button.js.map +1 -1
  25. package/dist/components/checkbox/checkbox.js.map +1 -1
  26. package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
  27. package/dist/components/code-editor/code-editor.js.map +1 -1
  28. package/dist/components/collapse/collapse-item.js.map +1 -1
  29. package/dist/components/collapse/collapse.js.map +1 -1
  30. package/dist/components/condition-editor/components/condition-group.js.map +1 -1
  31. package/dist/components/condition-editor/components/condition-row.js.map +1 -1
  32. package/dist/components/condition-editor/condition-editor.js.map +1 -1
  33. package/dist/components/contextmenu/contextmenu-item.js.map +1 -1
  34. package/dist/components/contextmenu/contextmenu-panel.js.map +1 -1
  35. package/dist/components/contextmenu/contextmenu-sub.js.map +1 -1
  36. package/dist/components/contextmenu/contextmenu.js.map +1 -1
  37. package/dist/components/date-panel/date-panel.js.map +1 -1
  38. package/dist/components/date-panel/headers/day.js.map +1 -1
  39. package/dist/components/date-panel/headers/month.js.map +1 -1
  40. package/dist/components/date-panel/headers/year.js.map +1 -1
  41. package/dist/components/date-panel/panels/day.js.map +1 -1
  42. package/dist/components/date-panel/panels/month.js.map +1 -1
  43. package/dist/components/date-panel/panels/year.js.map +1 -1
  44. package/dist/components/date-picker/date-picker.js.map +1 -1
  45. package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
  46. package/dist/components/dialog/dialog.js.map +1 -1
  47. package/dist/components/drawer/drawer.js.map +1 -1
  48. package/dist/components/dropdown/dropdown.js.map +1 -1
  49. package/dist/components/dual-nav/dual-nav-app.js.map +1 -1
  50. package/dist/components/dual-nav/dual-nav.js.map +1 -1
  51. package/dist/components/empty/empty.js.map +1 -1
  52. package/dist/components/expression-editor/components/path-preview.js.map +1 -1
  53. package/dist/components/expression-editor/components/variable-picker.js.map +1 -1
  54. package/dist/components/expression-editor/expression-editor.js.map +1 -1
  55. package/dist/components/file-picker/file-picker.js.map +1 -1
  56. package/dist/components/file-viewer/file-viewer.js.map +1 -1
  57. package/dist/components/file-viewer/previewers/docx-previewer.js.map +1 -1
  58. package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -1
  59. package/dist/components/file-viewer/previewers/ofd-previewer.js.map +1 -1
  60. package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -1
  61. package/dist/components/file-viewer/previewers/pdf-viewport-scroll.js.map +1 -1
  62. package/dist/components/file-viewer/previewers/pdf-zoom-bridge.js.map +1 -1
  63. package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -1
  64. package/dist/components/file-viewer/previewers/text-previewer.js.map +1 -1
  65. package/dist/components/file-viewer/previewers/video-previewer.js.map +1 -1
  66. package/dist/components/float-button/float-button.js.map +1 -1
  67. package/dist/components/form/form.js.map +1 -1
  68. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
  69. package/dist/components/form-item/form-item.js.map +1 -1
  70. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js.map +1 -1
  71. package/dist/components/gantt-chart/gantt-chart.js.map +1 -1
  72. package/dist/components/grid/grid-item.js.map +1 -1
  73. package/dist/components/grid/grid.js.map +1 -1
  74. package/dist/components/grid-input/grid-input.js.map +1 -1
  75. package/dist/components/group-input/group-input.js.map +1 -1
  76. package/dist/components/group-nav/group-nav-item.js.map +1 -1
  77. package/dist/components/group-nav/group-nav.js.map +1 -1
  78. package/dist/components/icon/icon.js.map +1 -1
  79. package/dist/components/image-cropper/image-cropper.js.map +1 -1
  80. package/dist/components/input/input.js.map +1 -1
  81. package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js.map +1 -1
  82. package/dist/components/kanban/kanban-column.js.map +1 -1
  83. package/dist/components/kanban/kanban.js.map +1 -1
  84. package/dist/components/kbd/kbd.js.map +1 -1
  85. package/dist/components/layout/layout-resizer.js.map +1 -1
  86. package/dist/components/layout/layout.js.map +1 -1
  87. package/dist/components/list/list-item.js.map +1 -1
  88. package/dist/components/list/list.js.map +1 -1
  89. package/dist/components/loading/loading.js.map +1 -1
  90. package/dist/components/message/message-box.js.map +1 -1
  91. package/dist/components/message/message.js.map +1 -1
  92. package/dist/components/message-confirm/message-confirm-box.js.map +1 -1
  93. package/dist/components/message-confirm/message-confirm.js.map +1 -1
  94. package/dist/components/multi-select/multi-select-option.js.map +1 -1
  95. package/dist/components/multi-select/multi-select.js.map +1 -1
  96. package/dist/components/multi-tree-select/multi-tree-select.js.map +1 -1
  97. package/dist/components/nav/nav-icon.js.map +1 -1
  98. package/dist/components/nav/nav-item-collapsed.js.map +1 -1
  99. package/dist/components/nav/nav-item.js.map +1 -1
  100. package/dist/components/nav/nav-sub-collapsed.js.map +1 -1
  101. package/dist/components/nav/nav-sub.js.map +1 -1
  102. package/dist/components/nav/nav.js.map +1 -1
  103. package/dist/components/notification/notification-box.js.map +1 -1
  104. package/dist/components/notification/notification.js.map +1 -1
  105. package/dist/components/number/number.js.map +1 -1
  106. package/dist/components/number-input/number-input.js.map +1 -1
  107. package/dist/components/number-range-input/number-range-input.js.map +1 -1
  108. package/dist/components/paginator/paginator.js.map +1 -1
  109. package/dist/components/palette/palette-alpha.js.map +1 -1
  110. package/dist/components/palette/palette-color-switch.js.map +1 -1
  111. package/dist/components/palette/palette-hue.js.map +1 -1
  112. package/dist/components/palette/palette-sv.js.map +1 -1
  113. package/dist/components/palette/palette.js.map +1 -1
  114. package/dist/components/password-input/password-input.js.map +1 -1
  115. package/dist/components/pop-confirm/pop-confirm.js.map +1 -1
  116. package/dist/components/progress/progress.js.map +1 -1
  117. package/dist/components/progress-nodes/progress-nodes.js.map +1 -1
  118. package/dist/components/radio/radio.js.map +1 -1
  119. package/dist/components/radio-group/radio-group.js.map +1 -1
  120. package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
  121. package/dist/components/rich-text-editor/toolbar.js.map +1 -1
  122. package/dist/components/scroll/scroll-bar.js.map +1 -1
  123. package/dist/components/scroll/scroll.js.map +1 -1
  124. package/dist/components/segment/segment.js.map +1 -1
  125. package/dist/components/select/select.js +9 -5
  126. package/dist/components/select/select.js.map +1 -1
  127. package/dist/components/slider/slider-thumb.js.map +1 -1
  128. package/dist/components/slider/slider.js.map +1 -1
  129. package/dist/components/steps/steps.js.map +1 -1
  130. package/dist/components/switch/switch.js.map +1 -1
  131. package/dist/components/table/table-body.js.map +1 -1
  132. package/dist/components/table/table-cell.js.map +1 -1
  133. package/dist/components/table/table-foot.js.map +1 -1
  134. package/dist/components/table/table-head.js.map +1 -1
  135. package/dist/components/table/table-row.js.map +1 -1
  136. package/dist/components/table/table.js.map +1 -1
  137. package/dist/components/table-editor/table-editor.js.map +1 -1
  138. package/dist/components/tabs/tabs-horizontal.js.map +1 -1
  139. package/dist/components/tabs/tabs-vertical.js.map +1 -1
  140. package/dist/components/tabs/tabs.js.map +1 -1
  141. package/dist/components/tag/tag.js.map +1 -1
  142. package/dist/components/text/text.js.map +1 -1
  143. package/dist/components/textarea/textarea.js.map +1 -1
  144. package/dist/components/theme/theme.js.map +1 -1
  145. package/dist/components/tip/tip.js.map +1 -1
  146. package/dist/components/tree/tree-node.js.map +1 -1
  147. package/dist/components/tree/tree.js.map +1 -1
  148. package/dist/components/tree-select/tree-select.js +19 -10
  149. package/dist/components/tree-select/tree-select.js.map +1 -1
  150. package/dist/components/watermark/watermark.js.map +1 -1
  151. package/dist/types/cascade.d.ts +5 -0
  152. package/dist/types/select.d.ts +8 -2
  153. package/dist/types/tree-select.d.ts +8 -2
  154. package/package.json +18 -18
  155. package/src/components/batch-edit/__test__/batch-edit.test.ts +1 -1
  156. package/src/components/button/__test__/button.test.ts +1 -1
  157. package/src/components/cascade/__test__/cascade.test.ts +26 -1
  158. package/src/components/cascade/use-select.ts +5 -5
  159. package/src/components/collapse/__test__/collapse.test.ts +1 -1
  160. package/src/components/condition-editor/__test__/condition-editor.test.ts +1 -1
  161. package/src/components/contextmenu/__test__/contextmenu.test.ts +1 -1
  162. package/src/components/date-picker/__test__/date-picker.test.ts +1 -1
  163. package/src/components/date-range-picker/__test__/date-range-picker.test.ts +1 -1
  164. package/src/components/drawer/__test__/drawer.test.ts +1 -1
  165. package/src/components/expression-editor/__test__/chip.test.ts +1 -1
  166. package/src/components/expression-editor/__test__/editor.test.ts +1 -1
  167. package/src/components/expression-editor/__test__/expression-editor.test.ts +1 -1
  168. package/src/components/expression-editor/__test__/mention.test.ts +1 -1
  169. package/src/components/expression-editor/__test__/model.test.ts +1 -1
  170. package/src/components/file-viewer/__test__/helper.test.ts +1 -1
  171. package/src/components/form/__test__/form.test.ts +1 -1
  172. package/src/components/form/__test__/is-field-modified.test.ts +1 -1
  173. package/src/components/form-item/__test__/form-item.test.ts +1 -1
  174. package/src/components/image-cropper/__test__/draw-crop.test.ts +1 -1
  175. package/src/components/image-cropper/__test__/image-cropper.test.ts +1 -1
  176. package/src/components/image-cropper/__test__/use-transform.test.ts +1 -1
  177. package/src/components/kanban/__test__/kanban.test.ts +1 -1
  178. package/src/components/message-confirm/__test__/message-confirm.test.ts +1 -1
  179. package/src/components/multi-tree-select/__test__/multi-tree-select.test.ts +1 -1
  180. package/src/components/number-input/__test__/number-input.test.ts +1 -1
  181. package/src/components/number-range-input/__test__/number-range-input.test.ts +1 -1
  182. package/src/components/palette/__test__/color-transform.test.ts +1 -1
  183. package/src/components/palette/__test__/palette.test.ts +1 -1
  184. package/src/components/password-input/__test__/password-input.test.ts +1 -1
  185. package/src/components/radio-group/__test__/radio-group.test.ts +1 -1
  186. package/src/components/rich-text-editor/__test__/image-node.test.ts +1 -1
  187. package/src/components/segment/__test__/segment.test.ts +1 -1
  188. package/src/components/select/__test__/select.test.ts +68 -1
  189. package/src/components/select/select.vue +15 -5
  190. package/src/components/table/__test__/col-width.test.ts +1 -1
  191. package/src/components/table/__test__/column-style.test.ts +1 -1
  192. package/src/components/table-editor/__test__/table-editor.test.ts +1 -1
  193. package/src/components/tree-select/__test__/tree-select.test.ts +50 -1
  194. package/src/components/tree-select/tree-select.vue +28 -11
  195. package/src/types/cascade.ts +5 -0
  196. package/src/types/select.ts +8 -2
  197. package/src/types/tree-select.ts +9 -2
@@ -1 +1 @@
1
- {"version":3,"file":"tree-select.js","names":["$attrs","$slots"],"sources":["../../../src/components/tree-select/tree-select.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n v-bind=\"$attrs\"\n :class=\"[cls.b, bem.is('disabled', disabled)]\"\n trigger=\"click\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size), contentClass]\"\n :content-style=\"contentStyle\"\n ref=\"dropdownRef\"\n v-model:visible=\"dropdownVisible\"\n :min-width=\"minWidth\"\n :width=\"width\"\n :disabled=\"disabled\"\n @update:visible=\"handleDropdownVisible\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n >\n <template #trigger>\n <u-input\n ref=\"inputRef\"\n :size=\"size\"\n :disabled=\"disabled\"\n :placeholder=\"inputPlaceholder\"\n :clearable=\"false\"\n :model-value=\"inputValue\"\n @update:model-value=\"handleQueryInput\"\n :native-readonly=\"!filterable || !querying\"\n @click.capture=\"handleTriggerClickCapture\"\n >\n <template #prefix v-if=\"$slots.prefix\">\n <slot name=\"prefix\" />\n </template>\n <template #suffix>\n <transition name=\"zoom-in\" mode=\"out-in\">\n <u-icon\n v-if=\"showClear\"\n :class=\"cls.e('clear')\"\n title=\"清除\"\n key=\"clear\"\n @click.stop=\"handleClear\"\n >\n <Close />\n </u-icon>\n <u-icon v-else :class=\"cls.e('arrow')\" key=\"arrow\"><ArrowDown /></u-icon>\n </transition>\n </template>\n </u-input>\n </template>\n <template #content>\n <!-- 菜单列表 -->\n\n <div v-if=\"remoteLoading\" :class=\"cls.e('loading')\">\n <ULoading type=\"dual-ring\" />\n </div>\n <u-tree\n v-else\n v-bind=\"treeProps\"\n :data=\"treeData\"\n :selected=\"model\"\n @update:selected=\"handleSelect\"\n ref=\"treeRef\"\n selectable\n :class=\"cls.e('content-tree')\"\n :slots=\"slots\"\n scroll-to-view\n />\n </template>\n </u-dropdown>\n\n <template v-else>\n {{ label || FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { debounce, dfs, o } from '@cat-kit/core'\nimport { useFormFallbackProps, useUserAction } from '@veltra/compositions'\nimport { ArrowDown, Close } from '@veltra/icons/normal'\nimport { bem, fieldKey, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, nextTick, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { TreeSelectProps, TreeSelectEmits, TreeExposed, InputExposed } from '../../types'\nimport { UDropdown } from '../dropdown'\nimport { UIcon } from '../icon'\nimport { UInput } from '../input'\nimport { ULoading } from '../loading'\nimport { UTree } from '../tree'\nimport type { TreeSlotsScope } from '../tree/di'\n\ndefineOptions({ name: 'UTreeSelect', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<TreeSelectProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n placeholder: '请选择',\n expandAll: false,\n clearable: true,\n disabled: undefined,\n readonly: undefined,\n filterable: false,\n minWidth: '280px'\n})\n\nconst emit = defineEmits<TreeSelectEmits>()\n\nconst slots = defineSlots<{\n /** 默认插槽 */\n default?: (props: TreeSlotsScope) => any\n /** 前缀插槽 */\n prefix?: () => any\n}>()\n\nconst treeProps = computed(() => {\n return o(props as Record<string, any>).omit([\n 'tips',\n 'field',\n 'placeholder',\n 'disabled',\n 'label',\n 'readonly',\n 'data',\n 'contentClass',\n 'contentStyle',\n 'minWidth',\n 'width'\n ])\n})\n\nconst cls = bem('tree-select')\n\nconst labelKey = computed(() => fieldKey(props.labelKey, 'label'))\nconst valueKey = computed(() => fieldKey(props.valueKey, 'value'))\n\n/** 是否可搜索:显式声明或数据源为远程函数 */\nconst filterable = computed(() => props.filterable || typeof props.data === 'function')\n\n/** 过滤 */\nconst qs = shallowRef('')\n\nconst treeRef = shallowRef<TreeExposed>()\n\n/** 远程搜索返回的树数据 */\nconst remoteData = shallowRef<Record<string, any>[]>()\n\n/** 面板渲染的树数据:data 为函数时来自远程搜索,否则为静态数据 */\nconst treeData = computed(() => (typeof props.data === 'function' ? remoteData.value : props.data))\n\nconst remoteLoading = shallowRef(false)\n/** 远程请求序号;响应返回时序号不一致说明已有更新的请求,结果作废 */\nlet remoteSeq = 0\n\nconst debouncedRemoteSearch = debounce(\n async (\n query: string,\n dataFn: (qs: string) => Promise<Record<string, any>[]> | Record<string, any>[]\n ) => {\n const seq = ++remoteSeq\n remoteLoading.value = true\n try {\n const data = await dataFn(query)\n // 响应到达时查询词可能已变化或已有更新的请求,过期结果直接丢弃\n if (seq !== remoteSeq || query !== qs.value) return\n remoteData.value = data ?? []\n // 搜索结果展示完整命中路径,与本地过滤自动展开祖先的行为对齐\n if (query) nextTick(() => treeRef.value?.expandAll())\n } finally {\n if (seq === remoteSeq) remoteLoading.value = false\n }\n },\n 200\n)\n\nwatch(\n [qs, () => props.data],\n ([query, data]) => {\n if (typeof data === 'function') {\n debouncedRemoteSearch(query, data)\n return\n }\n treeRef.value?.filter(query)\n },\n { immediate: true }\n)\n\nconst model = defineModel<string | number>()\n\n/** 内部展示文案,仅由 data 推导;通过 update:text 单向通知父级 */\nconst label = shallowRef<string>()\n\nconst dropdownVisible = shallowRef(false)\n\n/**\n * 是否处于查询态:决定触发输入框显示查询串还是选中标签。\n * 与面板可见状态解耦 —— 选择后立即退出查询态,\n * 不等面板关闭动画结束(否则显示值会延迟一个动画时长才恢复)。\n */\nconst querying = shallowRef(false)\n\nconst inputRef = useTemplateRef<InputExposed>('inputRef')\n\n/** 更新内部文案;值变化时单向 emit update:text */\nfunction setLabel(next?: string) {\n if (label.value === next) return\n label.value = next\n emit('update:text', next)\n}\n\n/** 触发输入框的值:查询态下承载查询串,否则展示选中标签 */\nconst inputValue = computed(() => {\n if (filterable.value && querying.value) return qs.value\n return model.value || model.value === 0 ? label.value : undefined\n})\n\n/** 查询态下已选标签降级为占位提示 */\nconst inputPlaceholder = computed(() => {\n const display = model.value || model.value === 0 ? label.value : undefined\n if (filterable.value && querying.value && display) {\n return display\n }\n return props.placeholder\n})\n\nfunction handleQueryInput(value: string) {\n if (!filterable.value) return\n qs.value = value\n}\n\nconst hovered = shallowRef(false)\n\n/** 悬停且存在选中值时展示清除按钮(替代下拉箭头) */\nconst showClear = computed(() => {\n if (!props.clearable || disabled.value || !hovered.value) return false\n return !!(model.value || model.value === 0 ? label.value : undefined)\n})\n\n/**\n * 过滤模式下拦截输入区域的点击:\n * 阻止 dropdown 的 trigger 开合切换,保持面板展开以不中断输入。\n * 非输入区域(箭头、留白)放行,维持原开合行为。\n */\nfunction handleTriggerClickCapture(e: MouseEvent) {\n if (!filterable.value || disabled.value) return\n if (!(e.target instanceof HTMLInputElement)) return\n\n e.stopPropagation()\n if (!dropdownVisible.value) dropdownRef.value?.open()\n}\n\nwatch(dropdownVisible, (visible) => {\n if (visible && filterable.value) {\n // 面板展开后进入查询态并聚焦输入框,可以立即输入查询\n querying.value = true\n nextTick(() => inputRef.value?.el?.focus())\n } else if (!visible) {\n querying.value = false\n }\n})\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst dropdownRef = shallowRef<InstanceType<typeof UDropdown>>()\n\nconst { userAction, isUserActive } = useUserAction()\n\n/** 清空 */\nconst handleClear = userAction(() => {\n model.value = ''\n setLabel(undefined)\n emit('clear')\n emit('change', undefined)\n})\n\n/** 外部回显:按 data 查找 label(O(n));用户动作期内跳过 */\nwatch(\n [treeData, model],\n ([data, modelVal]) => {\n if (isUserActive()) return\n if (!data?.length || modelVal === undefined || modelVal === null || modelVal === '') {\n setLabel(undefined)\n return\n }\n\n let nextLabel: string | undefined\n const childrenKey = props.childrenKey ?? 'children'\n data.some((item) => {\n let founded = false\n dfs(\n item,\n (v) => {\n if (v[valueKey.value] === modelVal) {\n nextLabel = v[labelKey.value]\n founded = true\n return true\n }\n },\n childrenKey\n )\n\n return founded\n })\n setLabel(nextLabel)\n },\n { immediate: true }\n)\n\n/** 用户选择:O(1) 写入值与文案,跳过 data 回显查找 */\nconst handleSelect = userAction(\n (selected?: string | number, selectedData?: Record<string, any>) => {\n model.value = selected ?? ''\n\n if (selectedData) {\n setLabel(o(selectedData).get(labelKey.value))\n } else {\n setLabel(undefined)\n }\n\n emit('change', selectedData)\n // 立即退出查询态,输入框同步恢复显示选中标签\n querying.value = false\n qs.value = ''\n dropdownRef.value?.close()\n }\n)\nconst handleDropdownVisible = (visible: boolean) => {\n if (!visible) {\n qs.value = ''\n }\n}\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree-select.js","names":["$attrs","$slots","_useSlots","_useModel","_unref","_openBlock","_createBlock","UDropdown","_mergeProps","_withCtx","_createVNode","UInput","_createSlots","_Transition","UIcon","_normalizeClass","_withModifiers","_renderSlot","_createCommentVNode","_createElementBlock","ULoading","UTree","_Fragment","_createTextVNode","_toDisplayString"],"sources":["../../../src/components/tree-select/tree-select.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n v-bind=\"$attrs\"\n :class=\"[cls.b, bem.is('disabled', disabled)]\"\n trigger=\"click\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size), contentClass]\"\n :content-style=\"contentStyle\"\n ref=\"dropdownRef\"\n v-model:visible=\"dropdownVisible\"\n :min-width=\"minWidth\"\n :width=\"width\"\n :disabled=\"disabled\"\n @update:visible=\"handleDropdownVisible\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n >\n <template #trigger>\n <u-input\n ref=\"inputRef\"\n :size=\"size\"\n :disabled=\"disabled\"\n :placeholder=\"inputPlaceholder\"\n :clearable=\"false\"\n :model-value=\"inputValue\"\n @update:model-value=\"handleQueryInput\"\n :native-readonly=\"!filterable || !querying\"\n @click.capture=\"handleTriggerClickCapture\"\n >\n <template #prefix v-if=\"$slots.prefix\">\n <slot name=\"prefix\" />\n </template>\n <template #suffix>\n <transition name=\"zoom-in\" mode=\"out-in\">\n <u-icon\n v-if=\"showClear\"\n :class=\"cls.e('clear')\"\n title=\"清除\"\n key=\"clear\"\n @click.stop=\"handleClear\"\n >\n <Close />\n </u-icon>\n <u-icon v-else :class=\"cls.e('arrow')\" key=\"arrow\"><ArrowDown /></u-icon>\n </transition>\n </template>\n </u-input>\n </template>\n <template #content>\n <!-- 菜单列表 -->\n\n <div v-if=\"remoteLoading\" :class=\"cls.e('loading')\">\n <ULoading type=\"dual-ring\" />\n </div>\n <u-tree\n v-else\n v-bind=\"treeProps\"\n :data=\"treeData\"\n :selected=\"model\"\n @update:selected=\"handleSelect\"\n ref=\"treeRef\"\n selectable\n :class=\"cls.e('content-tree')\"\n :slots=\"slots\"\n scroll-to-view\n />\n </template>\n </u-dropdown>\n\n <template v-else>\n {{ displayText || FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { debounce, dfs, o } from '@cat-kit/core'\nimport { useFormFallbackProps, useUserAction } from '@veltra/compositions'\nimport { ArrowDown, Close } from '@veltra/icons/normal'\nimport { bem, fieldKey, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, nextTick, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { TreeSelectProps, TreeSelectEmits, TreeExposed, InputExposed } from '../../types'\nimport { UDropdown } from '../dropdown'\nimport { UIcon } from '../icon'\nimport { UInput } from '../input'\nimport { ULoading } from '../loading'\nimport { UTree } from '../tree'\nimport type { TreeSlotsScope } from '../tree/di'\n\ndefineOptions({ name: 'UTreeSelect', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<TreeSelectProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n placeholder: '请选择',\n expandAll: false,\n clearable: true,\n disabled: undefined,\n readonly: undefined,\n filterable: false,\n minWidth: '280px'\n})\n\nconst emit = defineEmits<TreeSelectEmits>()\n\nconst slots = defineSlots<{\n /** 默认插槽 */\n default?: (props: TreeSlotsScope) => any\n /** 前缀插槽 */\n prefix?: () => any\n}>()\n\nconst treeProps = computed(() => {\n return o(props as Record<string, any>).omit([\n 'tips',\n 'field',\n 'placeholder',\n 'disabled',\n 'label',\n 'text',\n 'readonly',\n 'data',\n 'contentClass',\n 'contentStyle',\n 'minWidth',\n 'width'\n ])\n})\n\nconst cls = bem('tree-select')\n\nconst labelKey = computed(() => fieldKey(props.labelKey, 'label'))\nconst valueKey = computed(() => fieldKey(props.valueKey, 'value'))\n\n/** 是否可搜索:显式声明或数据源为远程函数 */\nconst filterable = computed(() => props.filterable || typeof props.data === 'function')\n\n/** 过滤 */\nconst qs = shallowRef('')\n\nconst treeRef = shallowRef<TreeExposed>()\n\n/** 远程搜索返回的树数据 */\nconst remoteData = shallowRef<Record<string, any>[]>()\n\n/** 面板渲染的树数据:data 为函数时来自远程搜索,否则为静态数据 */\nconst treeData = computed(() => (typeof props.data === 'function' ? remoteData.value : props.data))\n\nconst remoteLoading = shallowRef(false)\n/** 远程请求序号;响应返回时序号不一致说明已有更新的请求,结果作废 */\nlet remoteSeq = 0\n\nconst debouncedRemoteSearch = debounce(\n async (\n query: string,\n dataFn: (qs: string) => Promise<Record<string, any>[]> | Record<string, any>[]\n ) => {\n const seq = ++remoteSeq\n remoteLoading.value = true\n try {\n const data = await dataFn(query)\n // 响应到达时查询词可能已变化或已有更新的请求,过期结果直接丢弃\n if (seq !== remoteSeq || query !== qs.value) return\n remoteData.value = data ?? []\n // 搜索结果展示完整命中路径,与本地过滤自动展开祖先的行为对齐\n if (query) nextTick(() => treeRef.value?.expandAll())\n } finally {\n if (seq === remoteSeq) remoteLoading.value = false\n }\n },\n 200\n)\n\nwatch(\n [qs, () => props.data],\n ([query, data]) => {\n if (typeof data === 'function') {\n debouncedRemoteSearch(query, data)\n return\n }\n treeRef.value?.filter(query)\n },\n { immediate: true }\n)\n\nconst model = defineModel<string | number>()\n\n/** 内部展示文案,仅由 data 推导(未命中时展示 text 兜底);经 update:text 通知父级 */\nconst label = shallowRef<string>()\n\n/** 展示文案:data 推导优先,未命中时回退 text 兜底 */\nconst displayText = computed(() => {\n if (!(model.value || model.value === 0)) return undefined\n return label.value ?? props.text\n})\n\nconst dropdownVisible = shallowRef(false)\n\n/**\n * 是否处于查询态:决定触发输入框显示查询串还是选中标签。\n * 与面板可见状态解耦 —— 选择后立即退出查询态,\n * 不等面板关闭动画结束(否则显示值会延迟一个动画时长才恢复)。\n */\nconst querying = shallowRef(false)\n\nconst inputRef = useTemplateRef<InputExposed>('inputRef')\n\n/** 更新内部文案;值变化时 emit update:text(readonly 纯展示,不通知父级) */\nfunction setLabel(next?: string) {\n if (label.value === next) return\n label.value = next\n if (!readonly.value) emit('update:text', next)\n}\n\n/** 触发输入框的值:查询态下承载查询串,否则展示选中标签 */\nconst inputValue = computed(() => {\n if (filterable.value && querying.value) return qs.value\n return displayText.value\n})\n\n/** 查询态下已选标签降级为占位提示 */\nconst inputPlaceholder = computed(() => {\n if (filterable.value && querying.value && displayText.value) {\n return displayText.value\n }\n return props.placeholder\n})\n\nfunction handleQueryInput(value: string) {\n if (!filterable.value) return\n qs.value = value\n}\n\nconst hovered = shallowRef(false)\n\n/** 悬停且存在选中值时展示清除按钮(替代下拉箭头) */\nconst showClear = computed(() => {\n if (!props.clearable || disabled.value || !hovered.value) return false\n return !!displayText.value\n})\n\n/**\n * 过滤模式下拦截输入区域的点击:\n * 阻止 dropdown 的 trigger 开合切换,保持面板展开以不中断输入。\n * 非输入区域(箭头、留白)放行,维持原开合行为。\n */\nfunction handleTriggerClickCapture(e: MouseEvent) {\n if (!filterable.value || disabled.value) return\n if (!(e.target instanceof HTMLInputElement)) return\n\n e.stopPropagation()\n if (!dropdownVisible.value) dropdownRef.value?.open()\n}\n\nwatch(dropdownVisible, (visible) => {\n if (visible && filterable.value) {\n // 面板展开后进入查询态并聚焦输入框,可以立即输入查询\n querying.value = true\n nextTick(() => inputRef.value?.el?.focus())\n } else if (!visible) {\n querying.value = false\n }\n})\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst dropdownRef = shallowRef<InstanceType<typeof UDropdown>>()\n\nconst { userAction, isUserActive } = useUserAction()\n\n/** 清空 */\nconst handleClear = userAction(() => {\n model.value = ''\n setLabel(undefined)\n emit('clear')\n emit('change', undefined)\n})\n\n/** 外部回显:按 data 查找 label(O(n));用户动作期内跳过 */\nwatch(\n [treeData, model],\n ([data, modelVal]) => {\n if (isUserActive()) return\n if (modelVal === undefined || modelVal === null || modelVal === '') {\n setLabel(undefined)\n return\n }\n\n // 数据未就绪(远程加载等):保留现有文案与父级 text 兜底,避免中途被清空\n if (!data?.length) return\n\n let nextLabel: string | undefined\n const childrenKey = props.childrenKey ?? 'children'\n data.some((item) => {\n let founded = false\n dfs(\n item,\n (v) => {\n if (v[valueKey.value] === modelVal) {\n nextLabel = v[labelKey.value]\n founded = true\n return true\n }\n },\n childrenKey\n )\n\n return founded\n })\n if (nextLabel !== undefined) {\n setLabel(nextLabel)\n } else if (props.text) {\n // 未命中但有 text 兜底:文案以父级为准,不回发\n label.value = undefined\n } else {\n // 未命中且无兜底:如实通知父级当前没有可展示文案\n setLabel(undefined)\n }\n },\n { immediate: true }\n)\n\n/** 用户选择:O(1) 写入值与文案,跳过 data 回显查找 */\nconst handleSelect = userAction(\n (selected?: string | number, selectedData?: Record<string, any>) => {\n model.value = selected ?? ''\n\n if (selectedData) {\n setLabel(o(selectedData).get(labelKey.value))\n } else {\n setLabel(undefined)\n }\n\n emit('change', selectedData)\n // 立即退出查询态,输入框同步恢复显示选中标签\n querying.value = false\n qs.value = ''\n dropdownRef.value?.close()\n }\n)\nconst handleDropdownVisible = (visible: boolean) => {\n if (!visible) {\n qs.value = ''\n }\n}\n</script>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"watermark.js","names":[],"sources":["../../../src/components/watermark/watermark.vue"],"sourcesContent":["<template>\n <Teleport v-if=\"appendToBody\" to=\"body\">\n <div :class=\"cls.b\" ref=\"watermark\" :style=\"{ zIndex: zIndex() }\"></div>\n </Teleport>\n\n <div v-else :class=\"cls.b\" ref=\"watermark\" :style=\"{ zIndex: zIndex() }\">\n <slot />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { debounce } from '@cat-kit/core'\nimport { bem, setStyles, zIndex } from '@veltra/utils'\nimport { onBeforeUnmount, onMounted, reactive, useTemplateRef } from 'vue'\n\nimport type { WatermarkProps, WatermarkEmits } from '../../types'\n\ndefineOptions({ name: 'UWatermark' })\nconst cls = bem('watermark')\nconst props = withDefaults(defineProps<WatermarkProps>(), { route: -30, fontSize: 60 })\ndefineEmits<WatermarkEmits>()\n\nconst watermarkRef = useTemplateRef('watermark')\n\nconst styles = reactive({ fontColor: 'rgba(0,0,0,.1)', fontFamily: 'Arial', image: props.image })\n\nconst setWatermark = debounce(async () => {\n const str = props.text\n const container = watermarkRef.value\n\n if (!container || !str) return\n\n // 创建canvas\n let canvas: HTMLCanvasElement | null = document.createElement('canvas')\n\n // 创建canvs画布\n let ctx = canvas.getContext('2d')!\n // 字体\n ctx.font = `${props.fontSize}px ${styles.fontFamily}`\n\n const textWidth = ctx.measureText(str).width\n canvas = document.createElement('canvas')\n canvas.width = textWidth\n canvas.height = textWidth\n ctx = canvas.getContext('2d')!\n // 字体\n ctx.font = `${props.fontSize}px ${styles.fontFamily}`\n ctx = canvas.getContext('2d')!\n // 字体颜色\n ctx.fillStyle = styles.fontColor\n // 对齐方式\n ctx.textAlign = 'left'\n // 文本基线\n ctx.textBaseline = 'top'\n\n // 逆时旋转\n ctx.translate(textWidth / 2, textWidth / 2)\n ctx.rotate((props.route * Math.PI) / 180)\n ctx.translate(-textWidth / 2, -textWidth / 2)\n // 编制文字\n ctx.fillText(str, 0, (textWidth - props.fontSize) / 2)\n\n setStyles(container, { background: `url(${canvas.toDataURL('image/png')}) repeat` })\n\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n canvas = null\n}, 150)\n\nwindow.addEventListener('resize', setWatermark)\n\nonBeforeUnmount(() => {\n window.removeEventListener('resize', setWatermark)\n})\n\nonMounted(() => {\n setWatermark()\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;;;EAkBA,MAAM,MAAM,IAAI,WAAW;EAC3B,MAAM,QAAQ;EAGd,MAAM,eAAe,eAAe,WAAW;EAE/C,MAAM,SAAS,SAAS;GAAE,WAAW;GAAkB,YAAY;GAAS,OAAO,MAAM;EAAM,CAAC;EAEhG,MAAM,eAAe,SAAS,YAAY;GACxC,MAAM,MAAM,MAAM;GAClB,MAAM,YAAY,aAAa;GAE/B,IAAI,CAAC,aAAa,CAAC,KAAK;GAGxB,IAAI,SAAmC,SAAS,cAAc,QAAQ;GAGtE,IAAI,MAAM,OAAO,WAAW,IAAI;GAEhC,IAAI,OAAO,GAAG,MAAM,SAAS,KAAK,OAAO;GAEzC,MAAM,YAAY,IAAI,YAAY,GAAG,CAAC,CAAC;GACvC,SAAS,SAAS,cAAc,QAAQ;GACxC,OAAO,QAAQ;GACf,OAAO,SAAS;GAChB,MAAM,OAAO,WAAW,IAAI;GAE5B,IAAI,OAAO,GAAG,MAAM,SAAS,KAAK,OAAO;GACzC,MAAM,OAAO,WAAW,IAAI;GAE5B,IAAI,YAAY,OAAO;GAEvB,IAAI,YAAY;GAEhB,IAAI,eAAe;GAGnB,IAAI,UAAU,YAAY,GAAG,YAAY,CAAC;GAC1C,IAAI,OAAQ,MAAM,QAAQ,KAAK,KAAM,GAAG;GACxC,IAAI,UAAU,CAAC,YAAY,GAAG,CAAC,YAAY,CAAC;GAE5C,IAAI,SAAS,KAAK,IAAI,YAAY,MAAM,YAAY,CAAC;GAErD,UAAU,WAAW,EAAE,YAAY,OAAO,OAAO,UAAU,WAAW,EAAE,UAAU,CAAC;GAEnF,IAAI,UAAU,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;GAC/C,SAAS;EACX,GAAG,GAAG;EAEN,OAAO,iBAAiB,UAAU,YAAY;EAE9C,sBAAsB;GACpB,OAAO,oBAAoB,UAAU,YAAY;EACnD,CAAC;EAED,gBAAgB;GACd,aAAa;EACf,CAAC;;GA3EiB,OAAA,QAAA,gBAAhB,UAAA,GAAA,YAEW,UAAA;;IAFmB,IAAG;GAC/B,GAAA,CAAA,mBAAwE,OAAA;IAAlE,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,CAAC;IAAE,KAAI;IAAa,OAAK,eAAA,EAAA,QAAY,MAAA,MAAA,CAAM,CAAA,EAAA,CAAA;GAG9D,GAAA,MAAA,CAAA,CAAA,CAAA,MAAA,UAAA,GAAA,mBAEM,OAAA;;IAFO,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,CAAC;IAAE,KAAI;IAAa,OAAK,eAAA,EAAA,QAAY,MAAA,MAAA,CAAM,CAAA,EAAA,CAAA;GACjE,GAAA,CAAA,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"watermark.js","names":["_openBlock","_createBlock","_Teleport","_createElementVNode","_normalizeClass","_unref","_normalizeStyle","_createElementBlock","_renderSlot"],"sources":["../../../src/components/watermark/watermark.vue"],"sourcesContent":["<template>\n <Teleport v-if=\"appendToBody\" to=\"body\">\n <div :class=\"cls.b\" ref=\"watermark\" :style=\"{ zIndex: zIndex() }\"></div>\n </Teleport>\n\n <div v-else :class=\"cls.b\" ref=\"watermark\" :style=\"{ zIndex: zIndex() }\">\n <slot />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { debounce } from '@cat-kit/core'\nimport { bem, setStyles, zIndex } from '@veltra/utils'\nimport { onBeforeUnmount, onMounted, reactive, useTemplateRef } from 'vue'\n\nimport type { WatermarkProps, WatermarkEmits } from '../../types'\n\ndefineOptions({ name: 'UWatermark' })\nconst cls = bem('watermark')\nconst props = withDefaults(defineProps<WatermarkProps>(), { route: -30, fontSize: 60 })\ndefineEmits<WatermarkEmits>()\n\nconst watermarkRef = useTemplateRef('watermark')\n\nconst styles = reactive({ fontColor: 'rgba(0,0,0,.1)', fontFamily: 'Arial', image: props.image })\n\nconst setWatermark = debounce(async () => {\n const str = props.text\n const container = watermarkRef.value\n\n if (!container || !str) return\n\n // 创建canvas\n let canvas: HTMLCanvasElement | null = document.createElement('canvas')\n\n // 创建canvs画布\n let ctx = canvas.getContext('2d')!\n // 字体\n ctx.font = `${props.fontSize}px ${styles.fontFamily}`\n\n const textWidth = ctx.measureText(str).width\n canvas = document.createElement('canvas')\n canvas.width = textWidth\n canvas.height = textWidth\n ctx = canvas.getContext('2d')!\n // 字体\n ctx.font = `${props.fontSize}px ${styles.fontFamily}`\n ctx = canvas.getContext('2d')!\n // 字体颜色\n ctx.fillStyle = styles.fontColor\n // 对齐方式\n ctx.textAlign = 'left'\n // 文本基线\n ctx.textBaseline = 'top'\n\n // 逆时旋转\n ctx.translate(textWidth / 2, textWidth / 2)\n ctx.rotate((props.route * Math.PI) / 180)\n ctx.translate(-textWidth / 2, -textWidth / 2)\n // 编制文字\n ctx.fillText(str, 0, (textWidth - props.fontSize) / 2)\n\n setStyles(container, { background: `url(${canvas.toDataURL('image/png')}) repeat` })\n\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n canvas = null\n}, 150)\n\nwindow.addEventListener('resize', setWatermark)\n\nonBeforeUnmount(() => {\n window.removeEventListener('resize', setWatermark)\n})\n\nonMounted(() => {\n setWatermark()\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;;;EAkBA,MAAM,MAAM,IAAI,WAAW;EAC3B,MAAM,QAAQ;EAGd,MAAM,eAAe,eAAe,WAAW;EAE/C,MAAM,SAAS,SAAS;GAAE,WAAW;GAAkB,YAAY;GAAS,OAAO,MAAM;EAAM,CAAC;EAEhG,MAAM,eAAe,SAAS,YAAY;GACxC,MAAM,MAAM,MAAM;GAClB,MAAM,YAAY,aAAa;GAE/B,IAAI,CAAC,aAAa,CAAC,KAAK;GAGxB,IAAI,SAAmC,SAAS,cAAc,QAAQ;GAGtE,IAAI,MAAM,OAAO,WAAW,IAAI;GAEhC,IAAI,OAAO,GAAG,MAAM,SAAS,KAAK,OAAO;GAEzC,MAAM,YAAY,IAAI,YAAY,GAAG,CAAC,CAAC;GACvC,SAAS,SAAS,cAAc,QAAQ;GACxC,OAAO,QAAQ;GACf,OAAO,SAAS;GAChB,MAAM,OAAO,WAAW,IAAI;GAE5B,IAAI,OAAO,GAAG,MAAM,SAAS,KAAK,OAAO;GACzC,MAAM,OAAO,WAAW,IAAI;GAE5B,IAAI,YAAY,OAAO;GAEvB,IAAI,YAAY;GAEhB,IAAI,eAAe;GAGnB,IAAI,UAAU,YAAY,GAAG,YAAY,CAAC;GAC1C,IAAI,OAAQ,MAAM,QAAQ,KAAK,KAAM,GAAG;GACxC,IAAI,UAAU,CAAC,YAAY,GAAG,CAAC,YAAY,CAAC;GAE5C,IAAI,SAAS,KAAK,IAAI,YAAY,MAAM,YAAY,CAAC;GAErD,UAAU,WAAW,EAAE,YAAY,OAAO,OAAO,UAAU,WAAW,EAAE,UAAU,CAAC;GAEnF,IAAI,UAAU,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;GAC/C,SAAS;EACX,GAAG,GAAG;EAEN,OAAO,iBAAiB,UAAU,YAAY;EAE9C,sBAAsB;GACpB,OAAO,oBAAoB,UAAU,YAAY;EACnD,CAAC;EAED,gBAAgB;GACd,aAAa;EACf,CAAC;;GA3EiB,OAAA,QAAA,gBAAhBA,UAAA,GAAAC,YAEWC,UAAA;;IAFmB,IAAG;GAC/B,GAAA,CAAAC,mBAAwE,OAAA;IAAlE,OAAKC,eAAEC,MAAA,GAAA,CAAG,CAAC,CAAC;IAAE,KAAI;IAAa,OAAKC,eAAA,EAAA,QAAYD,MAAA,MAAA,CAAM,CAAA,EAAA,CAAA;GAG9D,GAAA,MAAA,CAAA,CAAA,CAAA,MAAAL,UAAA,GAAAO,mBAEM,OAAA;;IAFO,OAAKH,eAAEC,MAAA,GAAA,CAAG,CAAC,CAAC;IAAE,KAAI;IAAa,OAAKC,eAAA,EAAA,QAAYD,MAAA,MAAA,CAAM,CAAA,EAAA,CAAA;GACjE,GAAA,CAAAG,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA"}
@@ -17,6 +17,11 @@ export interface CascadeProps extends FormComponentProps {
17
17
  modelValue?: string[] | string;
18
18
  /** 级联数据项的标签字段 */
19
19
  labelKey?: string;
20
+ /**
21
+ * 兜底展示文案
22
+ * @description 单选 modelValue 未命中数据时展示 text(如回显路径已不在选项中),命中时展示节点 label 路径
23
+ */
24
+ text?: string;
20
25
  /** 级联数据项的值字段 */
21
26
  valueKey?: string;
22
27
  /** 占位符 */
@@ -14,6 +14,11 @@ export interface SelectProps extends FormComponentProps {
14
14
  valueKey?: string;
15
15
  /** 标签字段 */
16
16
  labelKey?: string;
17
+ /**
18
+ * 兜底展示文案
19
+ * @description modelValue 未命中选项时展示 text(如回显数据已不在选项中),命中时展示选项 label
20
+ */
21
+ text?: string;
17
22
  /** 是否可清除 */
18
23
  clearable?: boolean;
19
24
  /** 占位符 */
@@ -53,8 +58,9 @@ export interface SelectProps extends FormComponentProps {
53
58
  }
54
59
  export interface SelectEmits {
55
60
  /**
56
- * 选中项文案变化(单向通知,用于同步父级冗余字段)
57
- * @description 展示始终由 options 推导,请用 `@update:text` 而非 `v-model:text`
61
+ * 选中项文案变化(用于同步父级冗余字段)
62
+ * @description 命中选项时发出 label,清空时发出 undefined;未命中选项时,
63
+ * 传了 text 兜底则不发出(父级文案已是事实来源),未传 text 时发出 undefined;readonly 下不发出
58
64
  */
59
65
  (e: 'update:text', text?: string): void;
60
66
  (e: 'update:modelValue', modelValue?: any): void;
@@ -5,6 +5,11 @@ import { DeconstructValue, FormComponentProps } from "@veltra/utils";
5
5
  /** 树形选择器组件属性 */
6
6
  export interface TreeSelectProps extends FormComponentProps, Omit<TreeProps, 'selected' | 'checked' | 'selectable' | 'checkable' | 'data'> {
7
7
  modelValue?: string | number;
8
+ /**
9
+ * 兜底展示文案
10
+ * @description modelValue 未命中树节点时展示 text(如回显数据已不在选项中),命中时展示节点 label
11
+ */
12
+ text?: string;
8
13
  /**
9
14
  * 树数据
10
15
  * @description 如果传入一个函数,那么filterable会被强制启用;
@@ -42,8 +47,9 @@ export interface TreeSelectEmits {
42
47
  (e: 'update:modelValue', value?: string | number): void;
43
48
  (e: 'change', selectedData?: Record<string, any>): void;
44
49
  /**
45
- * 选中项文案变化(单向通知,用于同步父级冗余字段)
46
- * @description 展示始终由 data 推导,请用 `@update:text` 而非 `v-model:text`
50
+ * 选中项文案变化(用于同步父级冗余字段)
51
+ * @description 命中节点时发出 label,清空时发出 undefined;未命中节点时,
52
+ * 传了 text 兜底则不发出(父级文案已是事实来源),未传 text 时发出 undefined;readonly 下不发出
47
53
  */
48
54
  (e: 'update:text', text?: string): void;
49
55
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veltra/desktop",
3
- "version": "1.8.3",
3
+ "version": "1.8.4",
4
4
  "homepage": "https://github.com/cabinet-fe/ultra-ui#readme",
5
5
  "bugs": {
6
6
  "url": "https://github.com/cabinet-fe/ultra-ui/issues"
@@ -44,22 +44,22 @@
44
44
  }
45
45
  },
46
46
  "dependencies": {
47
- "@embedpdf/core": "^2.15.0",
48
- "@embedpdf/engines": "^2.15.0",
49
- "@embedpdf/plugin-document-manager": "^2.15.0",
50
- "@embedpdf/plugin-render": "^2.15.0",
51
- "@embedpdf/plugin-scroll": "^2.15.0",
52
- "@embedpdf/plugin-viewport": "^2.15.0",
53
- "@embedpdf/plugin-zoom": "^2.15.0",
54
- "@lexical/history": "^0.50.0",
55
- "@lexical/html": "^0.50.0",
56
- "@lexical/link": "^0.50.0",
57
- "@lexical/list": "^0.50.0",
58
- "@lexical/rich-text": "^0.50.0",
59
- "@lexical/selection": "^0.50.0",
60
- "@lexical/utils": "^0.50.0",
61
- "docx-preview": "^0.4.0",
62
- "lexical": "^0.50.0"
47
+ "@embedpdf/core": "^2.15.1",
48
+ "@embedpdf/engines": "^2.15.1",
49
+ "@embedpdf/plugin-document-manager": "^2.15.1",
50
+ "@embedpdf/plugin-render": "^2.15.1",
51
+ "@embedpdf/plugin-scroll": "^2.15.1",
52
+ "@embedpdf/plugin-viewport": "^2.15.1",
53
+ "@embedpdf/plugin-zoom": "^2.15.1",
54
+ "@lexical/history": "^0.51.0",
55
+ "@lexical/html": "^0.51.0",
56
+ "@lexical/link": "^0.51.0",
57
+ "@lexical/list": "^0.51.0",
58
+ "@lexical/rich-text": "^0.51.0",
59
+ "@lexical/selection": "^0.51.0",
60
+ "@lexical/utils": "^0.51.0",
61
+ "docx-preview": "^0.4.1",
62
+ "lexical": "^0.51.0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@codemirror/autocomplete": "6.20.3",
@@ -87,7 +87,7 @@
87
87
  "@veltra/sheet-core": "^2.5.7",
88
88
  "@veltra/styles": "^1.7.14",
89
89
  "@veltra/utils": "^1.7.14",
90
- "vue": ">=3.5.42"
90
+ "vue": ">=3.5.43"
91
91
  },
92
92
  "peerDependenciesMeta": {
93
93
  "@veltra/sheet-core": {
@@ -1,4 +1,4 @@
1
- import { describe, expect, it, vi } from 'vitest'
1
+ import { describe, expect, it, vi } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, reactive, ref } from 'vue'
3
3
 
4
4
  import { UInput } from '../../input'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h } from 'vue'
3
3
 
4
4
  import UButton from '../button.vue'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import UCascade from '../cascade.vue'
@@ -101,3 +101,28 @@ describe('UCascade change event fullLabel', () => {
101
101
  host.remove()
102
102
  })
103
103
  })
104
+
105
+ describe('UCascade text fallback', () => {
106
+ it('falls back to text when modelValue matches no node', async () => {
107
+ const host = document.createElement('div')
108
+ document.body.appendChild(host)
109
+
110
+ const app = createApp({
111
+ render() {
112
+ return h(UCascade, {
113
+ data: cascadeData,
114
+ modelValue: 'zhejiang/removed',
115
+ text: '已删除的路径'
116
+ })
117
+ }
118
+ })
119
+
120
+ app.mount(host)
121
+ await nextTick()
122
+
123
+ expect(host.querySelector('input')!.value).toBe('已删除的路径')
124
+
125
+ app.unmount()
126
+ host.remove()
127
+ })
128
+ })
@@ -68,12 +68,12 @@ export function useSelect(options: SelectOptions): UseSelectReturned {
68
68
  if (!modelValue || typeof modelValue !== 'string') return ''
69
69
 
70
70
  if (showFullPath) {
71
- return modelValue
72
- .split(separator!)
73
- .map((v) => dataMap.value.get(v)?.label ?? v)
74
- .join(separator)
71
+ const keys = modelValue.split(separator!)
72
+ // 末级未命中视为整条路径无效,回退 text 兜底,避免露出不可读的编码
73
+ if (!dataMap.value.has(keys[keys.length - 1]!)) return props.text ?? modelValue
74
+ return keys.map((v) => dataMap.value.get(v)?.label ?? v).join(separator)
75
75
  }
76
- return dataMap.value.get(modelValue)?.label ?? modelValue
76
+ return dataMap.value.get(modelValue)?.label ?? props.text ?? modelValue
77
77
  })
78
78
 
79
79
  function getPanelItemList(data?: CascadeNode[]) {
@@ -1,4 +1,4 @@
1
- import { describe, expect, it, vi } from 'vitest'
1
+ import { describe, expect, it, vi } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import UCollapseItem from '../collapse-item.vue'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, defineComponent, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import { UForm } from '../../form'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it, vi } from 'vitest'
1
+ import { describe, expect, it, vi } from 'vite-plus/test'
2
2
  import { createApp, defineComponent, h, inject, nextTick } from 'vue'
3
3
 
4
4
  import type { ContextmenuItem } from '../../../types'
@@ -1,5 +1,5 @@
1
1
  import { date } from '@cat-kit/core'
2
- import { describe, expect, it } from 'vitest'
2
+ import { describe, expect, it } from 'vite-plus/test'
3
3
  import { createApp, h, nextTick, ref } from 'vue'
4
4
 
5
5
  import UDatePicker from '../date-picker.vue'
@@ -1,5 +1,5 @@
1
1
  import { date } from '@cat-kit/core'
2
- import { describe, expect, it } from 'vitest'
2
+ import { describe, expect, it } from 'vite-plus/test'
3
3
  import { createApp, h, nextTick, ref } from 'vue'
4
4
 
5
5
  import UDateRangePicker from '../date-range-picker.vue'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it, vi } from 'vitest'
1
+ import { describe, expect, it, vi } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import UDrawer from '../drawer.vue'
@@ -1,5 +1,5 @@
1
1
  // @vitest-environment happy-dom
2
- import { describe, expect, it, vi } from 'vitest'
2
+ import { describe, expect, it, vi } from 'vite-plus/test'
3
3
 
4
4
  import { ChipAttrs, createChip, isChipElement, readChipValue, setChipFocused } from '../core/chip'
5
5
 
@@ -1,5 +1,5 @@
1
1
  // @vitest-environment happy-dom
2
- import { afterEach, describe, expect, it, vi } from 'vitest'
2
+ import { afterEach, describe, expect, it, vi } from 'vite-plus/test'
3
3
 
4
4
  import { createEditor } from '../core/editor'
5
5
  import { parse } from '../core/model'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, defineComponent, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import { UForm } from '../../form'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
 
3
3
  import { createMention } from '../core/mention'
4
4
  import { parse, type Doc } from '../core/model'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
 
3
3
  import { normalize, parse, serialize, splitAt, type Doc } from '../core/model'
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
 
3
3
  import { FILE_VIEWER_KIND_LABEL, inferKind } from '../helper'
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, defineComponent, h, nextTick, reactive, ref } from 'vue'
3
3
 
4
4
  import { UInput } from '../../input'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
 
3
3
  import { isFieldModified } from '../is-field-modified'
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, reactive, ref } from 'vue'
3
3
 
4
4
  import { UForm } from '../../form'
@@ -1,4 +1,4 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest'
1
+ import { afterEach, describe, expect, it, vi } from 'vite-plus/test'
2
2
 
3
3
  import { cropToResult, drawCropToCanvas } from '../draw-crop'
4
4
 
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref, shallowRef } from 'vue'
3
3
 
4
4
  import type { ImageCropperChangePayload, ImageCropperExposed } from '../../../types'
@@ -1,4 +1,4 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest'
1
+ import { afterEach, describe, expect, it, vi } from 'vite-plus/test'
2
2
  import { createApp, shallowRef } from 'vue'
3
3
 
4
4
  import { useTransform } from '../use-transform'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import type { KanbanColumnItem } from '../../types'
@@ -1,5 +1,5 @@
1
1
  import { zIndex } from '@veltra/utils'
2
- import { afterEach, describe, expect, it } from 'vitest'
2
+ import { afterEach, describe, expect, it } from 'vite-plus/test'
3
3
  import { nextTick } from 'vue'
4
4
 
5
5
  import { messageConfirm } from '../message-confirm'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref, type Ref } from 'vue'
3
3
 
4
4
  import UMultiTreeSelect from '../multi-tree-select.vue'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import UNumberInput from '../number-input.vue'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import type { NumberRangeTuple } from '../../../types'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
 
3
3
  import { HEX2RGBA } from '../color-transform'
4
4
 
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import UPalette from '../palette.vue'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import UPasswordInput from '../password-input.vue'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import URadioGroup from '../radio-group.vue'
@@ -1,5 +1,5 @@
1
1
  import { createEditor, type LexicalEditor } from 'lexical'
2
- import { afterAll, beforeAll, describe, expect, it } from 'vitest'
2
+ import { afterAll, beforeAll, describe, expect, it } from 'vite-plus/test'
3
3
 
4
4
  import { $createImageNode, $isImageNode, ImageNode } from '../image-node'
5
5
 
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref } from 'vue'
3
3
 
4
4
  import USegment from '../segment.vue'
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from 'vite-plus/test'
2
2
  import { createApp, h, nextTick, ref, type Ref } from 'vue'
3
3
 
4
4
  import USelect from '../select.vue'
@@ -171,6 +171,73 @@ describe('USelect', () => {
171
171
  }
172
172
  })
173
173
 
174
+ it('falls back to text when modelValue matches no option', async () => {
175
+ const { host, texts, unmount } = mountSelect({
176
+ modelValue: 'removed',
177
+ text: '已删除的选项',
178
+ options: [
179
+ { label: '北京', value: 'beijing' },
180
+ { label: '上海', value: 'shanghai' }
181
+ ]
182
+ })
183
+
184
+ try {
185
+ await nextTick()
186
+ await nextTick()
187
+ expect(host.querySelector('input')!.value).toBe('已删除的选项')
188
+
189
+ // 未命中且传了 text 兜底:不发送 update:text,父级 text 即事实来源
190
+ expect(texts).toHaveLength(0)
191
+ } finally {
192
+ unmount()
193
+ }
194
+ })
195
+
196
+ it('emits update:text undefined when unmatched echo has no text fallback', async () => {
197
+ const { host, model, texts, unmount } = mountSelect({
198
+ modelValue: 'beijing',
199
+ options: [
200
+ { label: '北京', value: 'beijing' },
201
+ { label: '上海', value: 'shanghai' }
202
+ ]
203
+ })
204
+
205
+ try {
206
+ await nextTick()
207
+ expect(texts.at(-1)).toBe('北京')
208
+
209
+ // 值改为不在选项中的值且无 text 兜底:如实发出 undefined
210
+ model.value = 'removed'
211
+ await nextTick()
212
+ await nextTick()
213
+ expect(texts.at(-1)).toBeUndefined()
214
+ expect(host.querySelector('input')!.value).toBe('removed')
215
+ } finally {
216
+ unmount()
217
+ }
218
+ })
219
+
220
+ it('does not emit update:text in readonly', async () => {
221
+ const { host, texts, unmount } = mountSelect({
222
+ modelValue: 'beijing',
223
+ readonly: true,
224
+ options: [
225
+ { label: '北京', value: 'beijing' },
226
+ { label: '上海', value: 'shanghai' }
227
+ ]
228
+ })
229
+
230
+ try {
231
+ await nextTick()
232
+ await nextTick()
233
+ // readonly 纯展示:不触发 update:text,避免下游回写
234
+ expect(texts).toHaveLength(0)
235
+ expect(host.textContent).toContain('北京')
236
+ } finally {
237
+ unmount()
238
+ }
239
+ })
240
+
174
241
  it('emits update:text on user select and clear', async () => {
175
242
  const { host, model, texts, unmount } = mountSelect({
176
243
  filterable: true,