@veltra/desktop 1.1.36 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/auto-complete/auto-complete.js +1 -0
- package/dist/components/auto-complete/auto-complete.js.map +1 -1
- package/dist/components/batch-edit/batch-edit-form.js +12 -5
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/batch-edit.js +8 -3
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/batch-edit.vue.d.ts +40 -35
- package/dist/components/batch-edit/di.js.map +1 -1
- package/dist/components/batch-edit/use-edit.js +41 -23
- package/dist/components/batch-edit/use-edit.js.map +1 -1
- package/dist/components/cascade/cascade.js +1 -0
- package/dist/components/cascade/cascade.js.map +1 -1
- package/dist/components/checkbox/checkbox-button.js +1 -0
- package/dist/components/checkbox/checkbox-button.js.map +1 -1
- package/dist/components/checkbox/checkbox.js +1 -0
- package/dist/components/checkbox/checkbox.js.map +1 -1
- package/dist/components/checkbox-group/checkbox-group.js +1 -0
- package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
- package/dist/components/code-editor/code-editor.js +2 -1
- package/dist/components/code-editor/code-editor.js.map +1 -1
- package/dist/components/condition-editor/core/evaluator.js +3 -3
- package/dist/components/condition-editor/core/evaluator.js.map +1 -1
- package/dist/components/date-picker/date-picker.js +1 -0
- package/dist/components/date-picker/date-picker.js.map +1 -1
- package/dist/components/date-range-picker/date-range-picker.js +2 -0
- package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.js +1 -0
- package/dist/components/expression-editor/expression-editor.js.map +1 -1
- package/dist/components/file-picker/file-picker.js +1 -0
- package/dist/components/file-picker/file-picker.js.map +1 -1
- package/dist/components/form/form.js.map +1 -1
- package/dist/components/form/form.vue.d.ts +11 -19
- package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js +24 -26
- package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form/index.d.ts +0 -3
- package/dist/components/form/use-form-fields.js +88 -0
- package/dist/components/form/use-form-fields.js.map +1 -0
- package/dist/components/form/use-node-interceptor.js +19 -30
- package/dist/components/form/use-node-interceptor.js.map +1 -1
- package/dist/components/form-item/form-item.js.map +1 -1
- package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js +44 -18
- package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form-item/helper.js +4 -1
- package/dist/components/form-item/helper.js.map +1 -1
- package/dist/components/form-item/validate.js +97 -0
- package/dist/components/form-item/validate.js.map +1 -0
- package/dist/components/group-input/group-input.js +1 -0
- package/dist/components/group-input/group-input.js.map +1 -1
- package/dist/components/index.d.ts +0 -3
- package/dist/components/index.js +0 -7
- package/dist/components/input/input.vue.d.ts +4 -4
- package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/multi-select/multi-select.js +1 -0
- package/dist/components/multi-select/multi-select.js.map +1 -1
- package/dist/components/multi-tree-select/multi-tree-select.js +1 -0
- package/dist/components/multi-tree-select/multi-tree-select.js.map +1 -1
- package/dist/components/number-input/number-input.js +1 -0
- package/dist/components/number-input/number-input.js.map +1 -1
- package/dist/components/number-range-input/number-range-input.js +1 -0
- package/dist/components/number-range-input/number-range-input.js.map +1 -1
- package/dist/components/number-range-input/number-range-input.vue.d.ts +1 -1
- package/dist/components/palette/palette.js +1 -0
- package/dist/components/palette/palette.js.map +1 -1
- package/dist/components/password-input/password-input.js +1 -0
- package/dist/components/password-input/password-input.js.map +1 -1
- package/dist/components/radio/radio.js +1 -0
- package/dist/components/radio/radio.js.map +1 -1
- package/dist/components/radio-group/radio-group.js +1 -0
- package/dist/components/radio-group/radio-group.js.map +1 -1
- package/dist/components/rich-text-editor/rich-text-editor.js +3 -2
- package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
- package/dist/components/rich-text-editor/toolbar.js +10 -7
- package/dist/components/rich-text-editor/toolbar.js.map +1 -1
- package/dist/components/select/select.js +6 -3
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/slider/slider.js +15 -2
- package/dist/components/slider/slider.js.map +1 -1
- package/dist/components/switch/switch.js +1 -0
- package/dist/components/switch/switch.js.map +1 -1
- package/dist/components/tabs/tabs-horizontal.vue.d.ts +2 -2
- package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
- package/dist/components/tabs/tabs.vue.d.ts +2 -2
- package/dist/components/textarea/textarea.js +1 -0
- package/dist/components/textarea/textarea.js.map +1 -1
- package/dist/components/tip/tip.vue.d.ts +3 -3
- package/dist/components/tree-select/tree-select.js +1 -0
- package/dist/components/tree-select/tree-select.js.map +1 -1
- package/dist/index.d.ts +3 -6
- package/dist/index.js +1 -4
- package/dist/types/batch-edit.d.ts +4 -5
- package/dist/types/form.d.ts +9 -48
- package/dist/types/index.d.ts +2 -2
- package/package.json +6 -6
- package/src/components/batch-edit/batch-edit-form.vue +20 -13
- package/src/components/batch-edit/batch-edit.vue +7 -8
- package/src/components/batch-edit/di.ts +1 -2
- package/src/components/batch-edit/use-edit.ts +58 -36
- package/src/components/date-range-picker/date-range-picker.vue +2 -0
- package/src/components/form/form.vue +22 -38
- package/src/components/form/index.ts +0 -6
- package/src/components/form/use-form-fields.ts +126 -0
- package/src/components/form/use-node-interceptor.ts +27 -56
- package/src/components/form-item/form-item.vue +69 -18
- package/src/components/form-item/helper.ts +5 -1
- package/src/components/form-item/validate.ts +131 -0
- package/src/components/rich-text-editor/rich-text-editor.vue +28 -25
- package/src/components/rich-text-editor/toolbar.vue +23 -19
- package/src/components/select/select.vue +6 -4
- package/src/components/slider/slider.vue +12 -2
- package/src/types/auto-complete.ts +1 -1
- package/src/types/batch-edit.ts +4 -5
- package/src/types/form.ts +9 -82
- package/src/types/radio-group.ts +1 -0
- package/src/types/radio.ts +1 -0
- package/src/types/tree-select.ts +1 -1
- package/dist/components/form/dynamic-form-model.d.ts +0 -73
- package/dist/components/form/dynamic-form-model.js +0 -184
- package/dist/components/form/dynamic-form-model.js.map +0 -1
- package/dist/components/form/form-model.d.ts +0 -73
- package/dist/components/form/form-model.js +0 -179
- package/dist/components/form/form-model.js.map +0 -1
- package/dist/components/form/helper.d.ts +0 -16
- package/dist/components/form/helper.js +0 -20
- package/dist/components/form/helper.js.map +0 -1
- package/src/components/form/__test__/form-model.test.ts +0 -190
- package/src/components/form/dynamic-form-model.ts +0 -258
- package/src/components/form/form-model.ts +0 -255
- package/src/components/form/helper.ts +0 -23
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-complete.js","names":[],"sources":["../../../src/components/auto-complete/auto-complete.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n trigger=\"click\"\n :class=\"[cls.b, cls.m(size), bem.is('disabled', disabled)]\"\n ref=\"dropdownRef\"\n v-model:visible=\"dropdownVisible\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size)]\"\n :disabled=\"disabled\"\n >\n <!-- 触发 -->\n <template #trigger>\n <!-- 单选 -->\n <u-input\n :size=\"size\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :clearable=\"clearable\"\n v-model=\"model\"\n @keydown=\"handleInputKeydown\"\n >\n <template #suffix v-if=\"slots.suffix\">\n <slot name=\"suffix\" />\n </template>\n\n <template #prefix v-if=\"slots.prefix\">\n <slot name=\"prefix\" />\n </template>\n </u-input>\n </template>\n\n <!-- 下拉内容 -->\n <template #content>\n <u-scroll tag=\"ul\" :class=\"cls.e('options')\" ref=\"scrollRef\">\n <li\n v-if=\"cachedSuggestion\"\n :class=\"[optionClass, bem.is('active', isCachedActive)]\"\n @click=\"handleSelectCachedOption(cachedSuggestion)\"\n v-ripple=\"cls.e('ripple')\"\n :data-key=\"cachedSuggestion\"\n :key=\"cachedSuggestion\"\n >\n <slot v-bind=\"{ option: cachedSuggestion, index: -1 }\">\n {{ cachedSuggestion }}\n </slot>\n </li>\n\n <li\n v-for=\"(option, index) of suggestions\"\n :class=\"[\n optionClass,\n bem.is('selected', option === model),\n bem.is('active', isActiveOption(index))\n ]\"\n @click=\"handleSelect(option)\"\n v-ripple=\"cls.e('ripple')\"\n :data-key=\"option\"\n :key=\"option\"\n >\n <slot v-bind=\"{ option, index }\">\n {{ option }}\n </slot>\n </li>\n </u-scroll>\n </template>\n </u-dropdown>\n\n <template v-else>\n {{ model || FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { vRipple } from '@veltra/directives'\nimport { bem, FORM_EMPTY_CONTENT, scrollIntoContainerView } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, shallowRef, watch } from 'vue'\n\nimport type { AutoCompleteEmits, AutoCompleteProps, _AutoCompleteExposed } from '../../types'\nimport type { DropdownExposed, ScrollExposed } from '../../types'\nimport { UDropdown } from '../dropdown'\nimport { UInput } from '../input'\nimport { UScroll } from '../scroll'\nimport { useKeyboard } from './use-keyboard'\nimport { useSuggestions } from './use-suggestions'\n\ndefineOptions({ name: 'AutoComplete', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<AutoCompleteProps>(), {\n placeholder: '请输入',\n clearable: true,\n disabled: undefined,\n readonly: undefined\n})\n\nconst emit = defineEmits<AutoCompleteEmits>()\n\nconst slots = defineSlots<{\n default?: (props: { option: string; index: number }) => any\n suffix?: () => any\n prefix?: () => any\n}>()\n\n// 当前输入框的值\nconst model = defineModel<string>()\n\nconst cls = bem('auto-complete')\n\nconst optionClass = cls.e('option')\n\nconst { formProps } = injectFormContext()\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {\n size: 'default',\n disabled: false,\n readonly: false\n})\n\nconst dropdownRef = shallowRef<DropdownExposed>()\nconst dropdownVisible = shallowRef(false)\nconst scrollRef = shallowRef<ScrollExposed>()\n\nwatch(scrollRef, (scroll) => {\n if (scroll && model.value !== undefined) {\n const li = scroll.contentRef!.querySelector(`li[data-key=\"${model.value}\"]`) as HTMLElement\n li && scrollIntoContainerView(li, scroll.containerRef ?? null)\n }\n})\n\nconst { suggestions, appendedSuggestions, cachedSuggestion } = useSuggestions({ props, model })\n\nconst keyboardOptions = computed(() => {\n const currentSuggestions = suggestions.value\n return cachedSuggestion.value\n ? [cachedSuggestion.value, ...currentSuggestions]\n : currentSuggestions\n})\n\nconst { point, handleKeydown } = useKeyboard({\n options: keyboardOptions,\n dropdownVisible,\n getDefaultIndex: (options) => {\n if (!options.length) return -1\n if (model.value) {\n const matchIndex = options.indexOf(model.value)\n if (matchIndex > -1) return matchIndex\n }\n return 0\n },\n onSelect: (option, index) => {\n if (cachedSuggestion.value && index === 0) {\n handleSelectCachedOption(option)\n return\n }\n handleSelect(option)\n }\n})\n\nconst isCachedActive = computed(() => !!cachedSuggestion.value && point.value === 0)\n\nconst isActiveOption = (index: number) => {\n const offset = cachedSuggestion.value ? 1 : 0\n return point.value === index + offset\n}\n\nconst handleInputKeydown = (event: KeyboardEvent) => {\n if (!dropdownVisible.value && event.key === 'Enter' && cachedSuggestion.value) {\n event.preventDefault()\n event.stopPropagation()\n handleSelectCachedOption(cachedSuggestion.value)\n return\n }\n handleKeydown(event)\n}\n\nwatch([point, keyboardOptions], ([currentPoint, options]) => {\n if (!scrollRef.value || currentPoint < 0) return\n const currentOption = options[currentPoint]\n if (!currentOption) return\n const target = scrollRef.value.contentRef?.querySelector(\n `li[data-key=\"${currentOption}\"]`\n ) as HTMLElement | null\n if (target) {\n scrollIntoContainerView(target, scrollRef.value.containerRef ?? null)\n }\n})\n\n/** 选中选项 */\nconst handleSelect = (option: string) => {\n model.value = option\n dropdownRef.value?.close()\n saveCache()\n emit('select', option)\n}\n\nfunction saveCache() {\n if (!model.value) return\n appendedSuggestions.value = [...appendedSuggestions.value, model.value]\n}\n\nconst handleSelectCachedOption = (cachedOption: string) => {\n appendedSuggestions.value = [...appendedSuggestions.value, cachedOption]\n dropdownRef.value?.close()\n}\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auto-complete.js","names":[],"sources":["../../../src/components/auto-complete/auto-complete.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n trigger=\"click\"\n :class=\"[cls.b, cls.m(size), bem.is('disabled', disabled)]\"\n ref=\"dropdownRef\"\n v-model:visible=\"dropdownVisible\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size)]\"\n :disabled=\"disabled\"\n >\n <!-- 触发 -->\n <template #trigger>\n <!-- 单选 -->\n <u-input\n :size=\"size\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :clearable=\"clearable\"\n v-model=\"model\"\n @keydown=\"handleInputKeydown\"\n >\n <template #suffix v-if=\"slots.suffix\">\n <slot name=\"suffix\" />\n </template>\n\n <template #prefix v-if=\"slots.prefix\">\n <slot name=\"prefix\" />\n </template>\n </u-input>\n </template>\n\n <!-- 下拉内容 -->\n <template #content>\n <u-scroll tag=\"ul\" :class=\"cls.e('options')\" ref=\"scrollRef\">\n <li\n v-if=\"cachedSuggestion\"\n :class=\"[optionClass, bem.is('active', isCachedActive)]\"\n @click=\"handleSelectCachedOption(cachedSuggestion)\"\n v-ripple=\"cls.e('ripple')\"\n :data-key=\"cachedSuggestion\"\n :key=\"cachedSuggestion\"\n >\n <slot v-bind=\"{ option: cachedSuggestion, index: -1 }\">\n {{ cachedSuggestion }}\n </slot>\n </li>\n\n <li\n v-for=\"(option, index) of suggestions\"\n :class=\"[\n optionClass,\n bem.is('selected', option === model),\n bem.is('active', isActiveOption(index))\n ]\"\n @click=\"handleSelect(option)\"\n v-ripple=\"cls.e('ripple')\"\n :data-key=\"option\"\n :key=\"option\"\n >\n <slot v-bind=\"{ option, index }\">\n {{ option }}\n </slot>\n </li>\n </u-scroll>\n </template>\n </u-dropdown>\n\n <template v-else>\n {{ model || FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { vRipple } from '@veltra/directives'\nimport { bem, FORM_EMPTY_CONTENT, scrollIntoContainerView } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, shallowRef, watch } from 'vue'\n\nimport type { AutoCompleteEmits, AutoCompleteProps, _AutoCompleteExposed } from '../../types'\nimport type { DropdownExposed, ScrollExposed } from '../../types'\nimport { UDropdown } from '../dropdown'\nimport { UInput } from '../input'\nimport { UScroll } from '../scroll'\nimport { useKeyboard } from './use-keyboard'\nimport { useSuggestions } from './use-suggestions'\n\ndefineOptions({ name: 'AutoComplete', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<AutoCompleteProps>(), {\n placeholder: '请输入',\n clearable: true,\n disabled: undefined,\n readonly: undefined\n})\n\nconst emit = defineEmits<AutoCompleteEmits>()\n\nconst slots = defineSlots<{\n default?: (props: { option: string; index: number }) => any\n suffix?: () => any\n prefix?: () => any\n}>()\n\n// 当前输入框的值\nconst model = defineModel<string>()\n\nconst cls = bem('auto-complete')\n\nconst optionClass = cls.e('option')\n\nconst { formProps } = injectFormContext()\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {\n size: 'default',\n disabled: false,\n readonly: false\n})\n\nconst dropdownRef = shallowRef<DropdownExposed>()\nconst dropdownVisible = shallowRef(false)\nconst scrollRef = shallowRef<ScrollExposed>()\n\nwatch(scrollRef, (scroll) => {\n if (scroll && model.value !== undefined) {\n const li = scroll.contentRef!.querySelector(`li[data-key=\"${model.value}\"]`) as HTMLElement\n li && scrollIntoContainerView(li, scroll.containerRef ?? null)\n }\n})\n\nconst { suggestions, appendedSuggestions, cachedSuggestion } = useSuggestions({ props, model })\n\nconst keyboardOptions = computed(() => {\n const currentSuggestions = suggestions.value\n return cachedSuggestion.value\n ? [cachedSuggestion.value, ...currentSuggestions]\n : currentSuggestions\n})\n\nconst { point, handleKeydown } = useKeyboard({\n options: keyboardOptions,\n dropdownVisible,\n getDefaultIndex: (options) => {\n if (!options.length) return -1\n if (model.value) {\n const matchIndex = options.indexOf(model.value)\n if (matchIndex > -1) return matchIndex\n }\n return 0\n },\n onSelect: (option, index) => {\n if (cachedSuggestion.value && index === 0) {\n handleSelectCachedOption(option)\n return\n }\n handleSelect(option)\n }\n})\n\nconst isCachedActive = computed(() => !!cachedSuggestion.value && point.value === 0)\n\nconst isActiveOption = (index: number) => {\n const offset = cachedSuggestion.value ? 1 : 0\n return point.value === index + offset\n}\n\nconst handleInputKeydown = (event: KeyboardEvent) => {\n if (!dropdownVisible.value && event.key === 'Enter' && cachedSuggestion.value) {\n event.preventDefault()\n event.stopPropagation()\n handleSelectCachedOption(cachedSuggestion.value)\n return\n }\n handleKeydown(event)\n}\n\nwatch([point, keyboardOptions], ([currentPoint, options]) => {\n if (!scrollRef.value || currentPoint < 0) return\n const currentOption = options[currentPoint]\n if (!currentOption) return\n const target = scrollRef.value.contentRef?.querySelector(\n `li[data-key=\"${currentOption}\"]`\n ) as HTMLElement | null\n if (target) {\n scrollIntoContainerView(target, scrollRef.value.containerRef ?? null)\n }\n})\n\n/** 选中选项 */\nconst handleSelect = (option: string) => {\n model.value = option\n dropdownRef.value?.close()\n saveCache()\n emit('select', option)\n}\n\nfunction saveCache() {\n if (!model.value) return\n appendedSuggestions.value = [...appendedSuggestions.value, model.value]\n}\n\nconst handleSelectCachedOption = (cachedOption: string) => {\n appendedSuggestions.value = [...appendedSuggestions.value, cachedOption]\n dropdownRef.value?.close()\n}\n</script>\n"],"mappings":"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"}
|
|
@@ -4,15 +4,22 @@ import form_default from "../form/form.js";
|
|
|
4
4
|
import _sfc_main$3 from "../button/button.js";
|
|
5
5
|
import _sfc_main$4 from "../kbd/kbd.js";
|
|
6
6
|
import { BatchEditDIKey } from "./di.js";
|
|
7
|
-
import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, guardReactiveProps, inject, normalizeClass, normalizeProps, openBlock, renderSlot, resolveDynamicComponent, toDisplayString, unref, withCtx } from "vue";
|
|
7
|
+
import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, guardReactiveProps, inject, normalizeClass, normalizeProps, openBlock, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, toRef, unref, withCtx } from "vue";
|
|
8
8
|
import { bem } from "@veltra/utils";
|
|
9
9
|
import { AddChild, Close, EditPen, Plus, View } from "@veltra/icons/normal";
|
|
10
10
|
//#region src/components/batch-edit/batch-edit-form.vue
|
|
11
11
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
12
12
|
name: "BatchEditForm",
|
|
13
13
|
__name: "batch-edit-form",
|
|
14
|
-
setup(__props) {
|
|
14
|
+
setup(__props, { expose: __expose }) {
|
|
15
15
|
const { cls, props, state, insertIndexes, handleSave, handleClose, staticFeatures, dynamicFeatures } = inject(BatchEditDIKey);
|
|
16
|
+
const formComponentRef = shallowRef();
|
|
17
|
+
__expose({
|
|
18
|
+
el: toRef(() => formComponentRef.value?.el),
|
|
19
|
+
validate: () => formComponentRef.value?.validate() ?? Promise.resolve(true),
|
|
20
|
+
clearValidate: () => formComponentRef.value?.clearValidate(),
|
|
21
|
+
reset: () => formComponentRef.value?.reset()
|
|
22
|
+
});
|
|
16
23
|
const creatable = computed(() => {
|
|
17
24
|
return state.type === "create" && (staticFeatures.value.has("create") || dynamicFeatures.value.create?.(state.row));
|
|
18
25
|
});
|
|
@@ -93,14 +100,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
93
100
|
mode: "out-in"
|
|
94
101
|
}, {
|
|
95
102
|
default: withCtx(() => [createVNode(unref(form_default), {
|
|
103
|
+
ref_key: "formComponentRef",
|
|
104
|
+
ref: formComponentRef,
|
|
96
105
|
model: unref(props).model,
|
|
97
106
|
readonly: unref(props).readonly,
|
|
98
107
|
onKeydown: handleFormKeydown,
|
|
99
108
|
"label-width": unref(props).labelWidth
|
|
100
109
|
}, {
|
|
101
|
-
default: withCtx((
|
|
102
|
-
data,
|
|
103
|
-
model,
|
|
110
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps({
|
|
104
111
|
row: unref(state).row,
|
|
105
112
|
depth: unref(state).depth,
|
|
106
113
|
indexes: unref(insertIndexes),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-edit-form.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-form.vue"],"sourcesContent":["<template>\n <aside :class=\"cls.e('form')\" v-if=\"state.visible && !!props.model\">\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'), bem.is(headerInfo.tone)]\">\n <u-icon>\n <component :is=\"headerInfo.icon\" />\n </u-icon>\n </span>\n <div :class=\"cls.e('form-title')\">\n <h3 :class=\"cls.e('form-title-text')\">{{ headerInfo.title }}</h3>\n <span v-if=\"headerInfo.chip\" :class=\"cls.e('form-chip')\">\n {{ headerInfo.chip }}\n </span>\n </div>\n <u-button\n :class=\"cls.e('form-close')\"\n :icon=\"Close\"\n text\n circle\n size=\"small\"\n title=\"关闭\"\n @click=\"handleClose\"\n />\n </header>\n\n <u-scroll always :class=\"cls.e('form-body')\" :key=\"bodyKey\">\n <transition name=\"fade\" appear mode=\"out-in\">\n <u-form\n :model=\"props.model\"\n :readonly=\"props.readonly\"\n @keydown=\"handleFormKeydown\"\n :label-width=\"props.labelWidth\"\n >\n <
|
|
1
|
+
{"version":3,"file":"batch-edit-form.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-form.vue"],"sourcesContent":["<template>\n <aside :class=\"cls.e('form')\" v-if=\"state.visible && !!props.model\">\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'), bem.is(headerInfo.tone)]\">\n <u-icon>\n <component :is=\"headerInfo.icon\" />\n </u-icon>\n </span>\n <div :class=\"cls.e('form-title')\">\n <h3 :class=\"cls.e('form-title-text')\">{{ headerInfo.title }}</h3>\n <span v-if=\"headerInfo.chip\" :class=\"cls.e('form-chip')\">\n {{ headerInfo.chip }}\n </span>\n </div>\n <u-button\n :class=\"cls.e('form-close')\"\n :icon=\"Close\"\n text\n circle\n size=\"small\"\n title=\"关闭\"\n @click=\"handleClose\"\n />\n </header>\n\n <u-scroll always :class=\"cls.e('form-body')\" :key=\"bodyKey\">\n <transition name=\"fade\" appear mode=\"out-in\">\n <u-form\n ref=\"formComponentRef\"\n :model=\"props.model\"\n :readonly=\"props.readonly\"\n @keydown=\"handleFormKeydown\"\n :label-width=\"props.labelWidth\"\n >\n <slot\n v-bind=\"{\n row: state.row,\n depth: state.depth,\n indexes: insertIndexes,\n index: state.row?.index\n }\"\n />\n </u-form>\n </transition>\n </u-scroll>\n\n <footer :class=\"cls.e('form-footer')\">\n <span :class=\"cls.e('form-hint')\" v-if=\"!props.readonly && state.dataUpdated\">\n 有未保存改动\n </span>\n <span :class=\"cls.e('form-hint')\" v-else-if=\"!props.readonly\">\n <u-kbd>Ctrl + Enter</u-kbd> 保存 · <u-kbd>Esc</u-kbd> 关闭\n </span>\n <span :class=\"cls.e('form-hint')\" v-else>只读模式</span>\n\n <div :class=\"cls.e('form-actions')\">\n <u-button text :loading=\"state.loading\" @click=\"handleClose\"> 取消 </u-button>\n <u-button\n v-if=\"!props.readonly && (creatable || updatable)\"\n :type=\"state.type === 'create' ? 'success' : 'primary'\"\n :loading=\"state.loading\"\n :disabled=\"!state.dataUpdated\"\n @click=\"handleSave\"\n >\n 保存\n </u-button>\n </div>\n </footer>\n </aside>\n</template>\n\n<script lang=\"ts\" setup>\nimport { AddChild, Close, EditPen, Plus, View } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, shallowRef, toRef, type Component } from 'vue'\n\nimport type { _FormExposed, FormExposed } from '../../types/form'\nimport { UButton } from '../button'\nimport { UForm } from '../form'\nimport { UIcon } from '../icon'\nimport { UKbd } from '../kbd'\nimport { UScroll } from '../scroll'\nimport { BatchEditDIKey } from './di'\n\ndefineOptions({ name: 'BatchEditForm' })\n\nconst {\n cls,\n props,\n state,\n insertIndexes,\n handleSave,\n handleClose,\n staticFeatures,\n dynamicFeatures\n} = inject(BatchEditDIKey)!\n\nconst formComponentRef = shallowRef<FormExposed>()\n\ndefineExpose<_FormExposed>({\n el: toRef(() => formComponentRef.value?.el),\n validate: () => formComponentRef.value?.validate() ?? Promise.resolve(true),\n clearValidate: () => formComponentRef.value?.clearValidate(),\n reset: () => formComponentRef.value?.reset()\n})\n\nconst creatable = computed(() => {\n return (\n state.type === 'create' &&\n (staticFeatures.value.has('create') || dynamicFeatures.value.create?.(state.row))\n )\n})\n\nconst updatable = computed(() => {\n return (\n state.type === 'update' &&\n (staticFeatures.value.has('update') || dynamicFeatures.value.update?.(state.row))\n )\n})\n\ninterface HeaderInfo {\n icon: Component\n title: string\n chip?: string\n tone: 'create' | 'update' | 'view' | 'child'\n}\n\nconst headerInfo = computed<HeaderInfo>(() => {\n if (props.readonly) {\n return {\n icon: View,\n title: '查看详情',\n chip: state.row ? `第 ${state.row.index + 1} 行` : undefined,\n tone: 'view'\n }\n }\n if (state.parentRow) {\n return {\n icon: AddChild,\n title: '新增子级',\n chip: `归属于第 ${state.parentRow.index + 1} 行`,\n tone: 'child'\n }\n }\n if (state.type === 'create') {\n return { icon: Plus, title: '新增', tone: 'create' }\n }\n return {\n icon: EditPen,\n title: '编辑',\n chip: state.row ? `第 ${state.row.index + 1} 行` : undefined,\n tone: 'update'\n }\n})\n\n/** 通过 row 切换 / 类型切换驱动表单内容淡出淡入 */\nconst bodyKey = computed(() => {\n return `${state.type}-${state.row?.uid ?? 'create'}-${state.parentRow?.uid ?? 'root'}`\n})\n\nfunction handleFormKeydown(e: KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n e.preventDefault()\n handleSave()\n }\n}\n</script>\n"],"mappings":"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"}
|
|
@@ -84,10 +84,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
84
84
|
const slots = useSlots();
|
|
85
85
|
const cls = bem("batch-edit");
|
|
86
86
|
const tableRef = shallowRef();
|
|
87
|
+
const formRef = shallowRef();
|
|
87
88
|
const editCtx = useEdit({
|
|
88
89
|
props,
|
|
89
90
|
emit,
|
|
90
|
-
tableRef
|
|
91
|
+
tableRef,
|
|
92
|
+
formRef
|
|
91
93
|
});
|
|
92
94
|
const { state, handleClose, handleSave, handleDelete, handleCreate } = editCtx;
|
|
93
95
|
provide(BatchEditDIKey, {
|
|
@@ -153,10 +155,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
153
155
|
createCommentVNode(" 编辑列表 "),
|
|
154
156
|
createVNode(_sfc_main$3, { slots }),
|
|
155
157
|
createCommentVNode(" 编辑表单 "),
|
|
156
|
-
createVNode(_sfc_main$2,
|
|
158
|
+
createVNode(_sfc_main$2, {
|
|
159
|
+
ref_key: "formRef",
|
|
160
|
+
ref: formRef
|
|
161
|
+
}, {
|
|
157
162
|
default: withCtx((scoped) => [createCommentVNode(" @vue-ignore "), renderSlot(_ctx.$slots, "form", normalizeProps(guardReactiveProps(scoped)))]),
|
|
158
163
|
_: 3
|
|
159
|
-
})
|
|
164
|
+
}, 512)
|
|
160
165
|
]),
|
|
161
166
|
_: 3
|
|
162
167
|
}, 8, ["class", "cols"]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-edit.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit.vue"],"sourcesContent":["<template>\n <u-layout\n :class=\"cls.b\"\n :cols=\"cols\"\n rows=\"minmax(0, 1fr)\"\n gap=\"8px\"\n resizable\n @keydown=\"handleKeydown\"\n tabindex=\"-1\"\n >\n <!-- 编辑列表 -->\n <BatchEditList :slots=\"slots\" />\n\n <!-- 编辑表单 -->\n <BatchEditForm v-slot=\"scoped\">\n <!-- @vue-ignore -->\n <slot name=\"form\" v-bind=\"scoped\" />\n </BatchEditForm>\n </u-layout>\n</template>\n\n<script lang=\"ts\" setup
|
|
1
|
+
{"version":3,"file":"batch-edit.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit.vue"],"sourcesContent":["<template>\n <u-layout\n :class=\"cls.b\"\n :cols=\"cols\"\n rows=\"minmax(0, 1fr)\"\n gap=\"8px\"\n resizable\n @keydown=\"handleKeydown\"\n tabindex=\"-1\"\n >\n <!-- 编辑列表 -->\n <BatchEditList :slots=\"slots\" />\n\n <!-- 编辑表单 -->\n <BatchEditForm ref=\"formRef\" v-slot=\"scoped\">\n <!-- @vue-ignore -->\n <slot name=\"form\" v-bind=\"scoped\" />\n </BatchEditForm>\n </u-layout>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { computed, inject, provide, shallowRef, watch } from 'vue'\n\nimport type {\n BatchEditEmits,\n BatchEditFeature,\n BatchEditProps,\n TableColumnSlotsScope,\n TableExposed,\n TableRow\n} from '../../types'\nimport type { FormExposed } from '../../types/form'\nimport { DialogDIKey } from '../dialog/di'\nimport { ULayout } from '../layout'\nimport BatchEditForm from './batch-edit-form.vue'\nimport BatchEditList from './batch-edit-list.vue'\nimport { BatchEditDIKey } from './di'\nimport { useEdit } from './use-edit'\n\ndefineOptions({ name: 'BatchEdit' })\n\nconst props = withDefaults(defineProps<BatchEditProps>(), {\n cols: () => ['1fr', '420px'],\n mode: 'normal'\n})\n\nconst emit = defineEmits<BatchEditEmits>()\n\nconst staticFeatures = computed(() => {\n const { features } = props\n\n if (Array.isArray(features)) {\n return new Set(features)\n }\n\n const defaultFeatures = new Set<BatchEditFeature>(['create', 'delete', 'update', 'createChild'])\n\n if (!features) {\n return defaultFeatures\n }\n\n // 函数与 false 的特性视为关闭;显式 true 视为开启(即便不在默认集合内)\n Object.entries(features).forEach(([key, value]) => {\n const k = key as BatchEditFeature\n if (typeof value === 'function' || value === false) {\n defaultFeatures.delete(k)\n } else if (value === true) {\n defaultFeatures.add(k)\n }\n })\n return defaultFeatures\n})\n\nconst dynamicFeatures = computed<\n Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n>(() => {\n const { features } = props\n if (!Array.isArray(features) && typeof features === 'object') {\n const ret = Object.entries(features)\n .filter(([_, value]) => {\n return typeof value === 'function'\n })\n .reduce(\n (acc, [key, value]) => {\n acc[key] = value\n return acc\n },\n {} as Record<BatchEditFeature, (row?: TableRow) => boolean>\n )\n return ret\n }\n\n return {} as Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n})\n\nconst slots = defineSlots<\n {\n form?: (props: {\n /** 表单数据 */\n data: Record<string, any> | undefined\n /** 当前编辑的层级 */\n depth?: number\n /** 当前编辑的行 */\n row?: TableRow\n /** 当前编辑的行索引 */\n index?: number\n /** 操作的目标行索引路径 */\n indexes?: number[]\n }) => any\n\n header?: () => any\n } & Partial<{ [key: `column:${string}`]: (props: TableColumnSlotsScope) => any }>\n>()\n\nconst cls = bem('batch-edit')\n\nconst tableRef = shallowRef<TableExposed>()\nconst formRef = shallowRef<FormExposed>()\n\nconst editCtx = useEdit({ props, emit, tableRef, formRef })\n\nconst { state, handleClose, handleSave, handleDelete, handleCreate } = editCtx\n\nprovide(BatchEditDIKey, { cls, props, emit, tableRef, staticFeatures, dynamicFeatures, ...editCtx })\n\nconst dialogCtx = inject(DialogDIKey, undefined)\n\ndialogCtx &&\n watch(dialogCtx.visible, (visible) => {\n !visible && editCtx.handleClose()\n })\n\nconst cols = computed(() => {\n return !!state.row || state.visible ? props.cols : undefined\n})\n\n/**\n * 键盘快捷键:\n * - Esc 关闭表单\n * - ⌘/Ctrl + S 保存\n * - ⌘/Ctrl + Backspace 删除当前编辑行\n * - ⌘/Ctrl + N 新增(仅在不在表单中时)\n */\nfunction handleKeydown(e: KeyboardEvent) {\n if (props.readonly && e.key !== 'Escape') return\n\n if (e.key === 'Escape') {\n if (state.visible) {\n e.preventDefault()\n handleClose()\n }\n return\n }\n\n const meta = e.metaKey || e.ctrlKey\n if (!meta) return\n\n const key = e.key.toLowerCase()\n\n if (key === 's' && state.visible) {\n e.preventDefault()\n handleSave()\n return\n }\n\n if (e.key === 'Backspace' && state.row && state.type === 'update') {\n e.preventDefault()\n handleDelete(state.row)\n return\n }\n\n if (key === 'n' && !state.visible) {\n e.preventDefault()\n handleCreate()\n }\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2CA,MAAM,QAAQ;EAKd,MAAM,OAAO;EAEb,MAAM,iBAAiB,eAAe;GACpC,MAAM,EAAE,aAAa;GAErB,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,IAAI,IAAI,QAAQ;GAGzB,MAAM,kBAAkB,IAAI,IAAsB;IAAC;IAAU;IAAU;IAAU;GAAa,CAAC;GAE/F,IAAI,CAAC,UACH,OAAO;GAIT,OAAO,QAAQ,QAAQ,EAAE,SAAS,CAAC,KAAK,WAAW;IACjD,MAAM,IAAI;IACV,IAAI,OAAO,UAAU,cAAc,UAAU,OAC3C,gBAAgB,OAAO,CAAC;SACnB,IAAI,UAAU,MACnB,gBAAgB,IAAI,CAAC;GAEzB,CAAC;GACD,OAAO;EACT,CAAC;EAED,MAAM,kBAAkB,eAEhB;GACN,MAAM,EAAE,aAAa;GACrB,IAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,OAAO,aAAa,UAYlD,OAXY,OAAO,QAAQ,QAAQ,EAChC,QAAQ,CAAC,GAAG,WAAW;IACtB,OAAO,OAAO,UAAU;GAC1B,CAAC,EACA,QACE,KAAK,CAAC,KAAK,WAAW;IACrB,IAAI,OAAO;IACX,OAAO;GACT,GACA,CAAC,CAEE;GAGT,OAAO,CAAC;EACV,CAAC;EAED,MAAM,QAAQ,SAAA;EAmBd,MAAM,MAAM,IAAI,YAAY;EAE5B,MAAM,WAAW,WAAyB;EAC1C,MAAM,UAAU,WAAwB;EAExC,MAAM,UAAU,QAAQ;GAAE;GAAO;GAAM;GAAU;EAAQ,CAAC;EAE1D,MAAM,EAAE,OAAO,aAAa,YAAY,cAAc,iBAAiB;EAEvE,QAAQ,gBAAgB;GAAE;GAAK;GAAO;GAAM;GAAU;GAAgB;GAAiB,GAAG;EAAQ,CAAC;EAEnG,MAAM,YAAY,OAAO,aAAa,KAAA,CAAS;EAE/C,aACE,MAAM,UAAU,UAAU,YAAY;GACpC,CAAC,WAAW,QAAQ,YAAY;EAClC,CAAC;EAEH,MAAM,OAAO,eAAe;GAC1B,OAAO,CAAC,CAAC,MAAM,OAAO,MAAM,UAAU,MAAM,OAAO,KAAA;EACrD,CAAC;;;;;;;;EASD,SAAS,cAAc,GAAkB;GACvC,IAAI,MAAM,YAAY,EAAE,QAAQ,UAAU;GAE1C,IAAI,EAAE,QAAQ,UAAU;IACtB,IAAI,MAAM,SAAS;KACjB,EAAE,eAAe;KACjB,YAAY;IACd;IACA;GACF;GAGA,IAAI,EADS,EAAE,WAAW,EAAE,UACjB;GAEX,MAAM,MAAM,EAAE,IAAI,YAAY;GAE9B,IAAI,QAAQ,OAAO,MAAM,SAAS;IAChC,EAAE,eAAe;IACjB,WAAW;IACX;GACF;GAEA,IAAI,EAAE,QAAQ,eAAe,MAAM,OAAO,MAAM,SAAS,UAAU;IACjE,EAAE,eAAe;IACjB,aAAa,MAAM,GAAG;IACtB;GACF;GAEA,IAAI,QAAQ,OAAO,CAAC,MAAM,SAAS;IACjC,EAAE,eAAe;IACjB,aAAa;GACf;EACF;;uBAhLE,YAiBW,MAAA,WAAA,GAAA;IAhBR,OAAK,eAAE,MAAA,GAAA,EAAI,CAAC;IACZ,MAAM,KAAA;IACP,MAAK;IACL,KAAI;IACJ,WAAA;IACC,WAAS;IACV,UAAS;;2BAEI;KAAb,mBAAA,QAAA;KACA,YAAgC,aAAA,EAAT,MAAK,CAAA;KAE5B,mBAAA,QAAA;KACA,YAGgB,aAAA;eAHG;MAAJ,KAAI;;wBAAkB,WAAM,CACzC,mBAAA,eAAA,GACA,WAAoC,KAAA,QAAA,QAAA,eAAA,mBAAV,MAAM,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1,41 +1,46 @@
|
|
|
1
|
-
import { IFormModel } from "../../types/form.js";
|
|
2
1
|
import { TableColumn, TableColumnSlotsScope, TableRow } from "../../types/table.js";
|
|
3
|
-
import {
|
|
2
|
+
import { BatchEditProps } from "../../types/batch-edit.js";
|
|
4
3
|
//#region src/components/batch-edit/batch-edit.vue.d.ts
|
|
5
|
-
|
|
6
|
-
props:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
4
|
+
type __VLS_Slots = {
|
|
5
|
+
form?: (props: {
|
|
6
|
+
/** 表单数据 */data: Record<string, any> | undefined; /** 当前编辑的层级 */
|
|
7
|
+
depth?: number; /** 当前编辑的行 */
|
|
8
|
+
row?: TableRow; /** 当前编辑的行索引 */
|
|
9
|
+
index?: number; /** 操作的目标行索引路径 */
|
|
10
|
+
indexes?: number[];
|
|
11
|
+
}) => any;
|
|
12
|
+
header?: () => any;
|
|
13
|
+
} & Partial<{
|
|
14
|
+
[key: `column:${string}`]: (props: TableColumnSlotsScope) => any;
|
|
15
|
+
}>;
|
|
16
|
+
declare const __VLS_base: import("vue").DefineComponent<BatchEditProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
17
|
+
"update:selected": (value: Record<string, any> | undefined) => any;
|
|
18
|
+
"update:checked": (value: Record<string, any>[]) => any;
|
|
19
|
+
"update:current": (row?: TableRow | undefined) => any;
|
|
20
|
+
"update:data": (value: Record<string, any>[]) => any;
|
|
21
|
+
"update:rows": (rows: TableRow[]) => any;
|
|
22
|
+
"update:forest": (rows?: import("@cat-kit/core").Forest<Record<string, unknown>, any> | undefined) => any;
|
|
23
|
+
"cell-click": (row: TableRow, column: TableColumn, ev: MouseEvent) => any;
|
|
24
|
+
"row-click": (row: TableRow, ev: MouseEvent) => any;
|
|
25
|
+
}, string, import("vue").PublicProps, Readonly<BatchEditProps> & Readonly<{
|
|
26
|
+
"onUpdate:selected"?: ((value: Record<string, any> | undefined) => any) | undefined;
|
|
27
|
+
"onUpdate:checked"?: ((value: Record<string, any>[]) => any) | undefined;
|
|
28
|
+
"onUpdate:current"?: ((row?: TableRow | undefined) => any) | undefined;
|
|
29
|
+
"onUpdate:data"?: ((value: Record<string, any>[]) => any) | undefined;
|
|
30
|
+
"onUpdate:rows"?: ((rows: TableRow[]) => any) | undefined;
|
|
31
|
+
"onUpdate:forest"?: ((rows?: import("@cat-kit/core").Forest<Record<string, unknown>, any> | undefined) => any) | undefined;
|
|
32
|
+
"onCell-click"?: ((row: TableRow, column: TableColumn, ev: MouseEvent) => any) | undefined;
|
|
33
|
+
"onRow-click"?: ((row: TableRow, ev: MouseEvent) => any) | undefined;
|
|
34
|
+
}>, {
|
|
35
|
+
cols: string | [string, string];
|
|
36
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
37
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
37
38
|
declare const _default: typeof __VLS_export;
|
|
38
|
-
type
|
|
39
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
40
|
+
new (): {
|
|
41
|
+
$slots: S;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
39
44
|
//#endregion
|
|
40
45
|
export { _default };
|
|
41
46
|
//# sourceMappingURL=batch-edit.vue.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"di.js","names":[],"sources":["../../../src/components/batch-edit/di.ts"],"sourcesContent":["import type { BEM } from '@veltra/utils'\nimport type { ComputedRef, InjectionKey, ShallowRef } from 'vue'\n\nimport type {\n BatchEditEmits,\n BatchEditFeature,\n BatchEditProps,\n
|
|
1
|
+
{"version":3,"file":"di.js","names":[],"sources":["../../../src/components/batch-edit/di.ts"],"sourcesContent":["import type { BEM } from '@veltra/utils'\nimport type { ComputedRef, InjectionKey, ShallowRef } from 'vue'\n\nimport type {\n BatchEditEmits,\n BatchEditFeature,\n BatchEditProps,\n TableExposed,\n TableRow\n} from '../../types'\nimport type { EditReturned } from './use-edit'\nexport const BatchEditDIKey: InjectionKey<\n {\n cls: BEM<'batch-edit', 'u-'>\n props: BatchEditProps\n emit: BatchEditEmits\n tableRef: ShallowRef<TableExposed | undefined>\n staticFeatures: ComputedRef<Set<BatchEditFeature>>\n dynamicFeatures: ComputedRef<\n Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n >\n } & EditReturned\n> = Symbol('BatchEditDIKey')\n"],"mappings":";AAWA,MAAa,iBAWT,OAAO,gBAAgB"}
|
|
@@ -18,8 +18,15 @@ function visitDataByIndexPath(roots, indexPath, childrenKey) {
|
|
|
18
18
|
}
|
|
19
19
|
return node;
|
|
20
20
|
}
|
|
21
|
+
function snapshotData(data) {
|
|
22
|
+
return safeRun(() => JSON.parse(JSON.stringify(data ?? {})), {});
|
|
23
|
+
}
|
|
24
|
+
function replaceModelData(model, data) {
|
|
25
|
+
for (const key of Object.keys(model)) delete model[key];
|
|
26
|
+
Object.assign(model, data);
|
|
27
|
+
}
|
|
21
28
|
function useEdit(options) {
|
|
22
|
-
const { props, emit, tableRef } = options;
|
|
29
|
+
const { props, emit, tableRef, formRef } = options;
|
|
23
30
|
/** 组件状态 */
|
|
24
31
|
const state = shallowReactive({
|
|
25
32
|
depth: void 0,
|
|
@@ -39,25 +46,36 @@ function useEdit(options) {
|
|
|
39
46
|
* 阶段把规范化后的值再写回模型时被误判为「用户已修改」
|
|
40
47
|
*/
|
|
41
48
|
let baselineSnapshot;
|
|
49
|
+
let emptySnapshot;
|
|
42
50
|
function snapshotModelData() {
|
|
43
|
-
return
|
|
51
|
+
return snapshotData(props.model);
|
|
52
|
+
}
|
|
53
|
+
function resetFormData(data) {
|
|
54
|
+
if (!props.model) return;
|
|
55
|
+
replaceModelData(props.model, snapshotData(data ?? emptySnapshot));
|
|
56
|
+
formRef.value?.clearValidate();
|
|
44
57
|
}
|
|
58
|
+
function setFormData(formData) {
|
|
59
|
+
if (!props.model) return;
|
|
60
|
+
replaceModelData(props.model, snapshotData(formData));
|
|
61
|
+
}
|
|
62
|
+
watch(() => props.model, (model) => {
|
|
63
|
+
emptySnapshot = snapshotData(model);
|
|
64
|
+
}, { immediate: true });
|
|
45
65
|
watch(() => state.row, (row) => {
|
|
46
|
-
|
|
66
|
+
resetFormData();
|
|
47
67
|
if (row) {
|
|
48
68
|
state.type = "update";
|
|
49
69
|
state.visible = true;
|
|
50
|
-
|
|
70
|
+
setFormData(row.data);
|
|
51
71
|
} else state.visible = false;
|
|
52
72
|
baselineSnapshot = snapshotModelData();
|
|
53
73
|
state.dataUpdated = false;
|
|
54
74
|
}, { flush: "sync" });
|
|
55
|
-
|
|
56
|
-
if (baselineSnapshot)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
state.dataUpdated = true;
|
|
60
|
-
};
|
|
75
|
+
watch(() => props.model, () => {
|
|
76
|
+
if (!baselineSnapshot || !state.visible) return;
|
|
77
|
+
state.dataUpdated = !isSameValue(baselineSnapshot, snapshotModelData());
|
|
78
|
+
}, { deep: true });
|
|
61
79
|
function isSameValue(a, b) {
|
|
62
80
|
if (a === b) return true;
|
|
63
81
|
if (a == null && b == null) return true;
|
|
@@ -69,10 +87,6 @@ function useEdit(options) {
|
|
|
69
87
|
}
|
|
70
88
|
return false;
|
|
71
89
|
}
|
|
72
|
-
watch(() => props.model, (model, oldModel) => {
|
|
73
|
-
if (oldModel) oldModel.offChange(changeCb);
|
|
74
|
-
if (model) model.onChange(changeCb);
|
|
75
|
-
}, { immediate: true });
|
|
76
90
|
const childrenKey = computed(() => {
|
|
77
91
|
return typeof props.tree === "string" ? props.tree : "children";
|
|
78
92
|
});
|
|
@@ -92,17 +106,19 @@ function useEdit(options) {
|
|
|
92
106
|
return item;
|
|
93
107
|
}
|
|
94
108
|
function getInsertData() {
|
|
95
|
-
return
|
|
109
|
+
return snapshotModelData();
|
|
96
110
|
}
|
|
97
111
|
async function runCreate(cb) {
|
|
98
112
|
state.parentRow = void 0;
|
|
99
113
|
if (state.row) state.row.isCurrent = false;
|
|
100
114
|
state.row = void 0;
|
|
101
115
|
state.type = "create";
|
|
102
|
-
|
|
116
|
+
resetFormData();
|
|
103
117
|
cb();
|
|
104
118
|
await nextTick();
|
|
105
119
|
state.visible = true;
|
|
120
|
+
baselineSnapshot = snapshotModelData();
|
|
121
|
+
state.dataUpdated = false;
|
|
106
122
|
}
|
|
107
123
|
/**
|
|
108
124
|
* 点击新增按钮
|
|
@@ -144,8 +160,9 @@ function useEdit(options) {
|
|
|
144
160
|
runCreate(() => {
|
|
145
161
|
state.depth = row.depth;
|
|
146
162
|
insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1];
|
|
147
|
-
|
|
148
|
-
|
|
163
|
+
setFormData(row.data);
|
|
164
|
+
baselineSnapshot = snapshotModelData();
|
|
165
|
+
state.dataUpdated = false;
|
|
149
166
|
});
|
|
150
167
|
}
|
|
151
168
|
function runWithLoading(fn) {
|
|
@@ -165,8 +182,8 @@ function useEdit(options) {
|
|
|
165
182
|
const handleSave = runWithLoading(async () => {
|
|
166
183
|
const { model, saveMethod } = props;
|
|
167
184
|
if (!model) return;
|
|
168
|
-
|
|
169
|
-
if (!await
|
|
185
|
+
formRef.value?.clearValidate();
|
|
186
|
+
if (!await formRef.value?.validate()) return;
|
|
170
187
|
let item = getInsertData();
|
|
171
188
|
if (saveMethod) {
|
|
172
189
|
const result = await saveMethod(item, state.type, state.parentRow);
|
|
@@ -175,11 +192,12 @@ function useEdit(options) {
|
|
|
175
192
|
state.dataUpdated = false;
|
|
176
193
|
if (state.type === "create") {
|
|
177
194
|
insert(item);
|
|
178
|
-
|
|
195
|
+
resetFormData();
|
|
196
|
+
return;
|
|
179
197
|
}
|
|
180
198
|
if (state.type === "update") {
|
|
181
199
|
const { row } = state;
|
|
182
|
-
row &&
|
|
200
|
+
row && Object.keys(item).forEach((key) => {
|
|
183
201
|
o(row.data).set(key, o(item).get(key));
|
|
184
202
|
});
|
|
185
203
|
}
|
|
@@ -206,7 +224,7 @@ function useEdit(options) {
|
|
|
206
224
|
state.row = void 0;
|
|
207
225
|
state.parentRow = void 0;
|
|
208
226
|
state.depth = void 0;
|
|
209
|
-
|
|
227
|
+
resetFormData();
|
|
210
228
|
insertIndexes.value = [];
|
|
211
229
|
}
|
|
212
230
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-edit.js","names":[],"sources":["../../../src/components/batch-edit/use-edit.ts"],"sourcesContent":["import { last, o, safeRun } from '@cat-kit/core'\nimport { computed, nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'\n\nimport type { TableRow, BatchEditEmits, BatchEditProps, TableExposed } from '../../types'\n\n/** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */\nfunction visitDataByIndexPath<T extends Record<string, unknown>>(\n roots: T[],\n indexPath: number[],\n childrenKey: string\n): T | undefined {\n if (!indexPath.length) return undefined\n let currentList: T[] | undefined = roots\n let node: T | undefined\n for (let i = 0; i < indexPath.length; i++) {\n const idx = indexPath[i]!\n if (!currentList) return undefined\n node = currentList[idx]\n if (node === undefined) return undefined\n if (i < indexPath.length - 1) {\n const next = node[childrenKey]\n currentList = Array.isArray(next) ? (next as T[]) : undefined\n }\n }\n return node\n}\n\ninterface Options {\n props: BatchEditProps\n emit: BatchEditEmits\n tableRef: ShallowRef<TableExposed | undefined>\n}\n\nexport interface BatchEditStates {\n /** 层级 */\n depth?: number\n visible: boolean\n type: 'create' | 'update'\n loading: boolean\n row?: TableRow\n /** 父级,只在添加子级时会有值 */\n parentRow?: TableRow\n /** 数据是否已更新 */\n dataUpdated: boolean\n}\n\nexport interface EditReturned {\n state: BatchEditStates\n insertIndexes: ShallowRef<number[]>\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => void\n handleEdit: (row: TableRow) => void\n handleCopy: (row: TableRow) => void\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => void\n handleInsertToPrev: (row: TableRow) => void\n handleInsertChild: (row: TableRow) => void\n}\n\nexport function useEdit(options: Options): EditReturned {\n const { props, emit, tableRef } = options\n\n /** 组件状态 */\n const state = shallowReactive<BatchEditStates>({\n depth: undefined,\n visible: false,\n type: 'create',\n loading: false,\n dataUpdated: false\n })\n\n const insertIndexes = shallowRef<number[]>([])\n\n watch(\n () => state.visible,\n (v) => {\n if (!v) {\n state.dataUpdated = false\n }\n }\n )\n\n /**\n * 「打开行 / 切换 type」时记录的基线快照\n * @description\n * 用于 changeCb 内部比对 — 若新值与基线相等(深比较)视为无改动,避免某些组件在 mount\n * 阶段把规范化后的值再写回模型时被误判为「用户已修改」\n */\n let baselineSnapshot: Record<string, any> | undefined\n\n function snapshotModelData() {\n return safeRun(() => JSON.parse(JSON.stringify(props.model?.data ?? {})), {})\n }\n\n watch(\n () => state.row,\n (row) => {\n props.model?.resetData()\n if (row) {\n state.type = 'update'\n state.visible = true\n props.model?.setData(row.data)\n } else {\n state.visible = false\n }\n baselineSnapshot = snapshotModelData()\n state.dataUpdated = false\n },\n // sync 保证 setData 完成后立刻取快照,避免 mount 期间组件回写值时丢基线\n { flush: 'sync' }\n )\n\n const changeCb = (field: string, val: any) => {\n // 与基线比较 — 同值(如组件 mount 时把当前值再写一次)不算\"用户修改\"\n if (baselineSnapshot) {\n const baseVal = o(baselineSnapshot).get(field)\n if (isSameValue(baseVal, val)) {\n return\n }\n }\n state.dataUpdated = true\n }\n\n function isSameValue(a: any, b: any) {\n if (a === b) return true\n if (a == null && b == null) return true\n if (typeof a !== typeof b) return false\n if (typeof a === 'object') {\n try {\n return JSON.stringify(a) === JSON.stringify(b)\n } catch {\n return false\n }\n }\n return false\n }\n\n watch(\n () => props.model,\n (model, oldModel) => {\n if (oldModel) {\n oldModel.offChange(changeCb)\n }\n if (model) {\n model.onChange(changeCb)\n }\n },\n { immediate: true }\n )\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n /**\n * 插入数据\n * @param item 数据\n */\n function insert(item: Record<string, any>) {\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(\n data ?? [],\n insertIndexes.value.slice(0, -1),\n childrenKey.value\n )\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(insertIndexes.value), 0, item)\n }\n } else {\n data.splice(last(insertIndexes.value), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n function getInsertData(): Record<string, any> {\n return safeRun(() => JSON.parse(JSON.stringify(props.model?.data ?? {})), {})\n }\n\n async function runCreate(cb: () => void) {\n state.parentRow = undefined\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.type = 'create'\n props.model?.resetData()\n cb()\n\n let item: Record<string, any> | undefined = undefined\n\n await nextTick()\n\n state.visible = true\n\n if (item) {\n const row = tableRef.value?.getRowByData(item)\n if (row) {\n state.row = row\n }\n }\n }\n\n /**\n * 点击新增按钮\n */\n function handleCreate() {\n const { data } = props\n runCreate(() => {\n state.depth = 1\n insertIndexes.value = [data?.length ?? 0]\n })\n }\n\n function handleInsertToPrev(row: TableRow) {\n runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes]\n })\n }\n\n function handleInsertToNext(row: TableRow) {\n runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n })\n }\n\n function handleInsertChild(row: TableRow) {\n runCreate(() => {\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n\n insertIndexes.value = [...row.indexes, row.children?.length ?? 0]\n })\n }\n\n /** 编辑指定行(等同于点击行) */\n function handleEdit(row: TableRow) {\n state.row = row\n state.depth = row.depth\n }\n\n /** 复制指定行:在其下方以 create 模式打开表单,并预填副本数据 */\n function handleCopy(row: TableRow) {\n runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n const cloned = safeRun(() => JSON.parse(JSON.stringify(row.data ?? {})), {})\n props.model?.setData(cloned)\n })\n }\n\n function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {\n return async (...args: Arg) => {\n state.loading = true\n if (state.row) {\n state.row.operating = true\n }\n try {\n await fn.apply(null, args)\n } catch (error) {\n console.error(error)\n }\n state.loading = false\n if (state.row) {\n state.row.operating = false\n }\n }\n }\n\n /** 保存 */\n const handleSave = runWithLoading(async () => {\n const { model, saveMethod } = props\n\n if (!model) return\n\n model.clearValidate()\n const valid = await model.validate()\n\n if (!valid) return\n\n let item = getInsertData()\n if (saveMethod) {\n const result = await saveMethod(item, state.type, state.parentRow)\n if (result) {\n item = result\n }\n }\n\n state.dataUpdated = false\n\n // 新增\n if (state.type === 'create') {\n insert(item)\n\n return model?.resetData()\n }\n // 更新\n if (state.type === 'update') {\n const { row } = state\n row &&\n model.allKeys.forEach((key) => {\n o(row.data).set(key, o(item).get(key))\n })\n }\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n await deleteMethod([row.data])\n }\n\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (children) {\n children.splice(row.index, 1)\n } else {\n console.error('行路径不正确')\n }\n } else {\n data.splice(row.index, 1)\n }\n\n if (state.row === row) {\n state.row = undefined\n state.depth = undefined\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n state.visible = false\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.parentRow = undefined\n state.depth = undefined\n props.model?.resetData()\n insertIndexes.value = []\n }\n\n return {\n state,\n insertIndexes,\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleEdit,\n handleCopy,\n handleClose,\n handleSave\n }\n}\n"],"mappings":";;;;AAMA,SAAS,qBACP,OACA,WACA,aACe;CACf,IAAI,CAAC,UAAU,QAAQ,OAAO,KAAA;CAC9B,IAAI,cAA+B;CACnC,IAAI;CACJ,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;EACzC,MAAM,MAAM,UAAU;EACtB,IAAI,CAAC,aAAa,OAAO,KAAA;EACzB,OAAO,YAAY;EACnB,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;EAC/B,IAAI,IAAI,UAAU,SAAS,GAAG;GAC5B,MAAM,OAAO,KAAK;GAClB,cAAc,MAAM,QAAQ,IAAI,IAAK,OAAe,KAAA;EACtD;CACF;CACA,OAAO;AACT;AAmCA,SAAgB,QAAQ,SAAgC;CACtD,MAAM,EAAE,OAAO,MAAM,aAAa;;CAGlC,MAAM,QAAQ,gBAAiC;EAC7C,OAAO,KAAA;EACP,SAAS;EACT,MAAM;EACN,SAAS;EACT,aAAa;CACf,CAAC;CAED,MAAM,gBAAgB,WAAqB,CAAC,CAAC;CAE7C,YACQ,MAAM,UACX,MAAM;EACL,IAAI,CAAC,GACH,MAAM,cAAc;CAExB,CACF;;;;;;;CAQA,IAAI;CAEJ,SAAS,oBAAoB;EAC3B,OAAO,cAAc,KAAK,MAAM,KAAK,UAAU,MAAM,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;CAC9E;CAEA,YACQ,MAAM,MACX,QAAQ;EACP,MAAM,OAAO,UAAU;EACvB,IAAI,KAAK;GACP,MAAM,OAAO;GACb,MAAM,UAAU;GAChB,MAAM,OAAO,QAAQ,IAAI,IAAI;EAC/B,OACE,MAAM,UAAU;EAElB,mBAAmB,kBAAkB;EACrC,MAAM,cAAc;CACtB,GAEA,EAAE,OAAO,OAAO,CAClB;CAEA,MAAM,YAAY,OAAe,QAAa;EAE5C,IAAI;OAEE,YADY,EAAE,gBAAgB,EAAE,IAAI,KAClB,GAAG,GAAG,GAC1B;EAAA;EAGJ,MAAM,cAAc;CACtB;CAEA,SAAS,YAAY,GAAQ,GAAQ;EACnC,IAAI,MAAM,GAAG,OAAO;EACpB,IAAI,KAAK,QAAQ,KAAK,MAAM,OAAO;EACnC,IAAI,OAAO,MAAM,OAAO,GAAG,OAAO;EAClC,IAAI,OAAO,MAAM,UACf,IAAI;GACF,OAAO,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;EAC/C,QAAQ;GACN,OAAO;EACT;EAEF,OAAO;CACT;CAEA,YACQ,MAAM,QACX,OAAO,aAAa;EACnB,IAAI,UACF,SAAS,UAAU,QAAQ;EAE7B,IAAI,OACF,MAAM,SAAS,QAAQ;CAE3B,GACA,EAAE,WAAW,KAAK,CACpB;CAEA,MAAM,cAAc,eAAe;EACjC,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;CACvD,CAAC;;;;;CAMD,SAAS,OAAO,MAA2B;EACzC,MAAM,OAAO,CAAC,GAAI,MAAM,QAAQ,CAAC,CAAE;EAEnC,MAAM,SAAS,qBACb,QAAQ,CAAC,GACT,cAAc,MAAM,MAAM,GAAG,EAAE,GAC/B,YAAY,KACd;EAEA,IAAI,QAAQ;GACV,MAAM,WAAW,OAAO,YAAY;GACpC,IAAI,CAAC,UACH,OAAO,YAAY,SAAS,CAAC,IAAI;QAEjC,SAAS,OAAO,KAAK,cAAc,KAAK,GAAG,GAAG,IAAI;EAEtD,OACE,KAAK,OAAO,KAAK,cAAc,KAAK,GAAG,GAAG,IAAI;EAGhD,KAAK,eAAe,IAAI;EAExB,OAAO;CACT;CAEA,SAAS,gBAAqC;EAC5C,OAAO,cAAc,KAAK,MAAM,KAAK,UAAU,MAAM,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;CAC9E;CAEA,eAAe,UAAU,IAAgB;EACvC,MAAM,YAAY,KAAA;EAClB,IAAI,MAAM,KACR,MAAM,IAAI,YAAY;EAExB,MAAM,MAAM,KAAA;EACZ,MAAM,OAAO;EACb,MAAM,OAAO,UAAU;EACvB,GAAG;EAIH,MAAM,SAAS;EAEf,MAAM,UAAU;CAQlB;;;;CAKA,SAAS,eAAe;EACtB,MAAM,EAAE,SAAS;EACjB,gBAAgB;GACd,MAAM,QAAQ;GACd,cAAc,QAAQ,CAAC,MAAM,UAAU,CAAC;EAC1C,CAAC;CACH;CAEA,SAAS,mBAAmB,KAAe;EACzC,gBAAgB;GACd,MAAM,QAAQ,IAAI;GAClB,cAAc,QAAQ,CAAC,GAAG,IAAI,OAAO;EACvC,CAAC;CACH;CAEA,SAAS,mBAAmB,KAAe;EACzC,gBAAgB;GACd,MAAM,QAAQ,IAAI;GAClB,cAAc,QAAQ,CAAC,GAAG,IAAI,QAAQ,MAAM,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC;EACnE,CAAC;CACH;CAEA,SAAS,kBAAkB,KAAe;EACxC,gBAAgB;GACd,MAAM,YAAY;GAClB,MAAM,QAAQ,IAAI,QAAQ;GAC1B,IAAI,WAAW;GAEf,cAAc,QAAQ,CAAC,GAAG,IAAI,SAAS,IAAI,UAAU,UAAU,CAAC;EAClE,CAAC;CACH;;CAGA,SAAS,WAAW,KAAe;EACjC,MAAM,MAAM;EACZ,MAAM,QAAQ,IAAI;CACpB;;CAGA,SAAS,WAAW,KAAe;EACjC,gBAAgB;GACd,MAAM,QAAQ,IAAI;GAClB,cAAc,QAAQ,CAAC,GAAG,IAAI,QAAQ,MAAM,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC;GACjE,MAAM,SAAS,cAAc,KAAK,MAAM,KAAK,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;GAC3E,MAAM,OAAO,QAAQ,MAAM;EAC7B,CAAC;CACH;CAEA,SAAS,eAAkC,IAA4C;EACrF,OAAO,OAAO,GAAG,SAAc;GAC7B,MAAM,UAAU;GAChB,IAAI,MAAM,KACR,MAAM,IAAI,YAAY;GAExB,IAAI;IACF,MAAM,GAAG,MAAM,MAAM,IAAI;GAC3B,SAAS,OAAO;IACd,QAAQ,MAAM,KAAK;GACrB;GACA,MAAM,UAAU;GAChB,IAAI,MAAM,KACR,MAAM,IAAI,YAAY;EAE1B;CACF;;CAGA,MAAM,aAAa,eAAe,YAAY;EAC5C,MAAM,EAAE,OAAO,eAAe;EAE9B,IAAI,CAAC,OAAO;EAEZ,MAAM,cAAc;EAGpB,IAAI,CAAC,MAFe,MAAM,SAAS,GAEvB;EAEZ,IAAI,OAAO,cAAc;EACzB,IAAI,YAAY;GACd,MAAM,SAAS,MAAM,WAAW,MAAM,MAAM,MAAM,MAAM,SAAS;GACjE,IAAI,QACF,OAAO;EAEX;EAEA,MAAM,cAAc;EAGpB,IAAI,MAAM,SAAS,UAAU;GAC3B,OAAO,IAAI;GAEX,OAAO,OAAO,UAAU;EAC1B;EAEA,IAAI,MAAM,SAAS,UAAU;GAC3B,MAAM,EAAE,QAAQ;GAChB,OACE,MAAM,QAAQ,SAAS,QAAQ;IAC7B,EAAE,IAAI,IAAI,EAAE,IAAI,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC;GACvC,CAAC;EACL;CACF,CAAC;CAED,MAAM,eAAe,eAAe,OAAO,QAAkB;EAC3D,MAAM,EAAE,iBAAiB;EAEzB,IAAI,cACF,MAAM,aAAa,CAAC,IAAI,IAAI,CAAC;EAG/B,MAAM,OAAO,CAAC,GAAI,MAAM,QAAQ,CAAC,CAAE;EAEnC,MAAM,SAAS,qBAAqB,MAAM,IAAI,QAAQ,MAAM,GAAG,EAAE,GAAG,YAAY,KAAK;EAErF,IAAI,QAAQ;GACV,MAAM,WAAW,OAAO,YAAY;GACpC,IAAI,UACF,SAAS,OAAO,IAAI,OAAO,CAAC;QAE5B,QAAQ,MAAM,QAAQ;EAE1B,OACE,KAAK,OAAO,IAAI,OAAO,CAAC;EAG1B,IAAI,MAAM,QAAQ,KAAK;GACrB,MAAM,MAAM,KAAA;GACZ,MAAM,QAAQ,KAAA;EAChB;EAEA,KAAK,eAAe,IAAI;CAC1B,CAAC;CAED,SAAS,cAAc;EACrB,MAAM,UAAU;EAChB,IAAI,MAAM,KACR,MAAM,IAAI,YAAY;EAExB,MAAM,MAAM,KAAA;EACZ,MAAM,YAAY,KAAA;EAClB,MAAM,QAAQ,KAAA;EACd,MAAM,OAAO,UAAU;EACvB,cAAc,QAAQ,CAAC;CACzB;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"use-edit.js","names":[],"sources":["../../../src/components/batch-edit/use-edit.ts"],"sourcesContent":["import { last, o, safeRun } from '@cat-kit/core'\nimport { computed, nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'\n\nimport type { TableRow, BatchEditEmits, BatchEditProps, TableExposed } from '../../types'\nimport type { FormExposed } from '../../types/form'\n\n/** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */\nfunction visitDataByIndexPath<T extends Record<string, unknown>>(\n roots: T[],\n indexPath: number[],\n childrenKey: string\n): T | undefined {\n if (!indexPath.length) return undefined\n let currentList: T[] | undefined = roots\n let node: T | undefined\n for (let i = 0; i < indexPath.length; i++) {\n const idx = indexPath[i]!\n if (!currentList) return undefined\n node = currentList[idx]\n if (node === undefined) return undefined\n if (i < indexPath.length - 1) {\n const next = node[childrenKey]\n currentList = Array.isArray(next) ? (next as T[]) : undefined\n }\n }\n return node\n}\n\ninterface Options {\n props: BatchEditProps\n emit: BatchEditEmits\n tableRef: ShallowRef<TableExposed | undefined>\n formRef: ShallowRef<FormExposed | undefined>\n}\n\nexport interface BatchEditStates {\n /** 层级 */\n depth?: number\n visible: boolean\n type: 'create' | 'update'\n loading: boolean\n row?: TableRow\n /** 父级,只在添加子级时会有值 */\n parentRow?: TableRow\n /** 数据是否已更新 */\n dataUpdated: boolean\n}\n\nexport interface EditReturned {\n state: BatchEditStates\n insertIndexes: ShallowRef<number[]>\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => void\n handleEdit: (row: TableRow) => void\n handleCopy: (row: TableRow) => void\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => void\n handleInsertToPrev: (row: TableRow) => void\n handleInsertChild: (row: TableRow) => void\n}\n\nfunction snapshotData(data?: Record<string, any>) {\n return safeRun(() => JSON.parse(JSON.stringify(data ?? {})), {})\n}\n\nfunction replaceModelData(model: Record<string, any>, data: Record<string, any>) {\n for (const key of Object.keys(model)) {\n delete model[key]\n }\n Object.assign(model, data)\n}\n\nexport function useEdit(options: Options): EditReturned {\n const { props, emit, tableRef, formRef } = options\n\n /** 组件状态 */\n const state = shallowReactive<BatchEditStates>({\n depth: undefined,\n visible: false,\n type: 'create',\n loading: false,\n dataUpdated: false\n })\n\n const insertIndexes = shallowRef<number[]>([])\n\n watch(\n () => state.visible,\n (v) => {\n if (!v) {\n state.dataUpdated = false\n }\n }\n )\n\n /**\n * 「打开行 / 切换 type」时记录的基线快照\n * @description\n * 用于 changeCb 内部比对 — 若新值与基线相等(深比较)视为无改动,避免某些组件在 mount\n * 阶段把规范化后的值再写回模型时被误判为「用户已修改」\n */\n let baselineSnapshot: Record<string, any> | undefined\n let emptySnapshot: Record<string, any> | undefined\n\n function snapshotModelData() {\n return snapshotData(props.model)\n }\n\n function resetFormData(data?: Record<string, any>) {\n if (!props.model) return\n replaceModelData(props.model, snapshotData(data ?? emptySnapshot))\n formRef.value?.clearValidate()\n }\n\n function setFormData(formData: Record<string, any>) {\n if (!props.model) return\n replaceModelData(props.model, snapshotData(formData))\n }\n\n watch(\n () => props.model,\n (model) => {\n emptySnapshot = snapshotData(model)\n },\n { immediate: true }\n )\n\n watch(\n () => state.row,\n (row) => {\n resetFormData()\n if (row) {\n state.type = 'update'\n state.visible = true\n setFormData(row.data)\n } else {\n state.visible = false\n }\n baselineSnapshot = snapshotModelData()\n state.dataUpdated = false\n },\n // sync 保证 setData 完成后立刻取快照,避免 mount 期间组件回写值时丢基线\n { flush: 'sync' }\n )\n\n watch(\n () => props.model,\n () => {\n if (!baselineSnapshot || !state.visible) return\n state.dataUpdated = !isSameValue(baselineSnapshot, snapshotModelData())\n },\n { deep: true }\n )\n\n function isSameValue(a: any, b: any) {\n if (a === b) return true\n if (a == null && b == null) return true\n if (typeof a !== typeof b) return false\n if (typeof a === 'object') {\n try {\n return JSON.stringify(a) === JSON.stringify(b)\n } catch {\n return false\n }\n }\n return false\n }\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n /**\n * 插入数据\n * @param item 数据\n */\n function insert(item: Record<string, any>) {\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(\n data ?? [],\n insertIndexes.value.slice(0, -1),\n childrenKey.value\n )\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(insertIndexes.value), 0, item)\n }\n } else {\n data.splice(last(insertIndexes.value), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n function getInsertData(): Record<string, any> {\n return snapshotModelData()\n }\n\n async function runCreate(cb: () => void) {\n state.parentRow = undefined\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.type = 'create'\n resetFormData()\n cb()\n\n let item: Record<string, any> | undefined = undefined\n\n await nextTick()\n\n state.visible = true\n baselineSnapshot = snapshotModelData()\n state.dataUpdated = false\n\n if (item) {\n const row = tableRef.value?.getRowByData(item)\n if (row) {\n state.row = row\n }\n }\n }\n\n /**\n * 点击新增按钮\n */\n function handleCreate() {\n const { data } = props\n runCreate(() => {\n state.depth = 1\n insertIndexes.value = [data?.length ?? 0]\n })\n }\n\n function handleInsertToPrev(row: TableRow) {\n runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes]\n })\n }\n\n function handleInsertToNext(row: TableRow) {\n runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n })\n }\n\n function handleInsertChild(row: TableRow) {\n runCreate(() => {\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n\n insertIndexes.value = [...row.indexes, row.children?.length ?? 0]\n })\n }\n\n /** 编辑指定行(等同于点击行) */\n function handleEdit(row: TableRow) {\n state.row = row\n state.depth = row.depth\n }\n\n /** 复制指定行:在其下方以 create 模式打开表单,并预填副本数据 */\n function handleCopy(row: TableRow) {\n runCreate(() => {\n state.depth = row.depth\n insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]\n setFormData(row.data)\n baselineSnapshot = snapshotModelData()\n state.dataUpdated = false\n })\n }\n\n function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {\n return async (...args: Arg) => {\n state.loading = true\n if (state.row) {\n state.row.operating = true\n }\n try {\n await fn.apply(null, args)\n } catch (error) {\n console.error(error)\n }\n state.loading = false\n if (state.row) {\n state.row.operating = false\n }\n }\n }\n\n /** 保存 */\n const handleSave = runWithLoading(async () => {\n const { model, saveMethod } = props\n\n if (!model) return\n\n formRef.value?.clearValidate()\n const valid = await formRef.value?.validate()\n\n if (!valid) return\n\n let item = getInsertData()\n if (saveMethod) {\n const result = await saveMethod(item, state.type, state.parentRow)\n if (result) {\n item = result\n }\n }\n\n state.dataUpdated = false\n\n // 新增\n if (state.type === 'create') {\n insert(item)\n\n resetFormData()\n return\n }\n // 更新\n if (state.type === 'update') {\n const { row } = state\n row &&\n Object.keys(item).forEach((key) => {\n o(row.data).set(key, o(item).get(key))\n })\n }\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n await deleteMethod([row.data])\n }\n\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (children) {\n children.splice(row.index, 1)\n } else {\n console.error('行路径不正确')\n }\n } else {\n data.splice(row.index, 1)\n }\n\n if (state.row === row) {\n state.row = undefined\n state.depth = undefined\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n state.visible = false\n if (state.row) {\n state.row.isCurrent = false\n }\n state.row = undefined\n state.parentRow = undefined\n state.depth = undefined\n resetFormData()\n insertIndexes.value = []\n }\n\n return {\n state,\n insertIndexes,\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleEdit,\n handleCopy,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cascade.js","names":[],"sources":["../../../src/components/cascade/cascade.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n :class=\"[cls.b, bem.is('disabled', disabled), bem.is('multiple', multiple), cls.m(size)]\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size)]\"\n trigger=\"click\"\n ref=\"dropdownRef\"\n :disabled=\"disabled\"\n width=\"auto\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n @update:visible=\"!$event && (qs = '')\"\n >\n <template #trigger>\n <!-- 单选展示 -->\n <u-input\n v-if=\"!multiple\"\n :size=\"size\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :clearable=\"clearable\"\n native-readonly\n :model-value=\"displayedValue\"\n @clear=\"handleClear\"\n >\n <template #suffix>\n <u-icon :class=\"cls.e('arrow')\"><ArrowDown /></u-icon>\n </template>\n </u-input>\n\n <!-- 多选展示 -->\n <template v-if=\"multiple\">\n <span :class=\"cls.e('placeholder')\" v-show=\"!modelValue?.length\">\n {{ placeholder }}\n </span>\n\n <div v-if=\"modelValue?.length\" :class=\"cls.e('tags')\">\n <u-tag\n v-for=\"tag of tags\"\n :key=\"tag.value\"\n :closable=\"!disabled\"\n @close=\"handleCloseTag(tag)\"\n >\n {{ tag.label }}\n </u-tag>\n <u-tag v-if=\"restTag\"> {{ restTag }}+ </u-tag>\n </div>\n\n <transition name=\"zoom-in\" mode=\"out-in\">\n <u-icon\n v-if=\"clearable && modelValue?.length && hovered && !disabled\"\n :class=\"cls.e('clear')\"\n @click.stop=\"handleClear\"\n >\n <Close />\n </u-icon>\n\n <u-icon :class=\"cls.e('arrow')\" v-else><ArrowDown /></u-icon>\n </transition>\n </template>\n </template>\n\n <template #content>\n <!-- 过滤 -->\n <div v-if=\"filterable\" :class=\"cls.e('panel-filter')\">\n <u-input placeholder=\"输入关键字进行过滤\" v-model=\"qs\" :size=\"size\" clearable>\n <template #suffix>\n <u-icon><Search /></u-icon>\n </template>\n </u-input>\n </div>\n\n <div :class=\"cls.e('content')\" v-if=\"panelItemList.length\">\n <UCascadePanelItem\n v-for=\"({ nodes, key }, index) of panelItemList\"\n :data=\"nodes\"\n :key=\"key\"\n :panel-index=\"index\"\n :value=\"selectedNodeKeys[index]\"\n @click=\"handleClick\"\n @check=\"handleCheck\"\n />\n </div>\n\n <div :class=\"cls.e('empty')\" v-else>\n <UEmpty />\n </div>\n </template>\n </u-dropdown>\n\n <!-- 只读 -->\n <template v-else>\n <div :class=\"[cls.m(size)]\" v-if=\"multiple\">\n <div :class=\"cls.e('tags')\">\n <u-tag v-for=\"tag of tags\" :key=\"tag.value\">\n {{ tag.label }}\n </u-tag>\n </div>\n </div>\n <template v-else>\n {{ displayedValue || FORM_EMPTY_CONTENT }}\n </template>\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Forest, o } from '@cat-kit/core'\nimport { useFormFallbackProps, useUserAction } from '@veltra/compositions'\nimport { ArrowDown, Close, Search } from '@veltra/icons/normal'\nimport { bem, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, provide, shallowRef, triggerRef, watch } from 'vue'\n\nimport type { CascadeProps, CascadeEmits, DropdownExposed } from '../../types'\nimport { UDropdown } from '../dropdown'\nimport { UEmpty } from '../empty'\nimport { UIcon } from '../icon'\nimport { UInput } from '../input'\nimport { UTag } from '../tag'\nimport UCascadePanelItem from './cascade-panel-item.vue'\nimport { CascadeDIKey } from './di'\nimport { CascadeNode } from './node'\nimport { useCheck } from './use-check'\nimport { useDataMap } from './use-data-map'\nimport { useSelect } from './use-select'\n\ndefineOptions({ name: 'Cascade' })\n\nconst props = withDefaults(defineProps<CascadeProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n placeholder: '请选择',\n separator: '/',\n clearable: true,\n disabled: undefined,\n readonly: undefined,\n childrenKey: 'children',\n filterable: false,\n data: () => [],\n visibilityLimit: 3\n})\n\nconst emit = defineEmits<CascadeEmits>()\n\nconst cls = bem('cascade')\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {\n size: 'default',\n disabled: false,\n readonly: false\n})\n\nconst dropdownRef = shallowRef<DropdownExposed>()\n\nconst forest = computed(() => {\n return new Forest<Record<string, unknown>, any>({\n data: (props.data ?? []) as Record<string, unknown>[],\n childrenKey: props.childrenKey,\n createNode: (data, index, depth, _forest, parent) => {\n if (!data) {\n return new CascadeNode({ data, index, depth, value: '', label: '', parent })\n }\n\n return new CascadeNode({\n data,\n index,\n depth,\n value: o(data).get(props.valueKey) ?? '',\n label: o(data).get(props.labelKey) ?? '',\n parent\n })\n }\n })\n})\n\nconst { dataMap } = useDataMap({ props, forest })\n\nconst { userAction, isUserActive } = useUserAction()\n\nconst {\n displayedValue,\n selectItem,\n updateSingleValue,\n panelItemList,\n getPanelItemList,\n createPanelItem,\n selectedNodeKeys\n} = useSelect({ props, emit, dataMap, forest, isUserActive, dropdownRef })\n\nconst { hovered, tags, restTag, updateMultipleValue, handleCloseTag, checkItem, checkedSet } =\n useCheck({ props, forest, getPanelItemList, emit, dataMap, isUserActive, disabled, readonly })\n\nconst commitSingleSelect = userAction((item: CascadeNode) => {\n if (!props.strict) {\n updateSingleValue()\n } else if (!item.children?.length) {\n updateSingleValue()\n }\n})\n\nfunction handleClick(panelIndex: number, item: CascadeNode) {\n selectItem(panelIndex, item)\n\n if (!props.multiple) {\n commitSingleSelect(item)\n }\n}\n\nconst handleCheck = userAction((item: CascadeNode, checked: boolean) => {\n checkItem(item, checked)\n})\n\nfunction handleClear() {\n if (props.multiple) {\n checkedSet.value.clear()\n triggerRef(checkedSet)\n updateMultipleValue()\n } else {\n selectedNodeKeys.value = []\n updateSingleValue()\n }\n\n emit('clear')\n}\n\n// 过滤\nconst qs = shallowRef<string>('')\n\nwatch([qs, forest], ([qs, forest]) => {\n const { filterable } = props\n if (!filterable || !qs) {\n forest.dfs((node) => {\n node.visible = true\n })\n getPanelItemList(forest.roots)\n return\n }\n\n const cache = new Set<CascadeNode>()\n\n forest.dfs((node) => {\n if (node.label?.toLowerCase().includes(qs.toLowerCase())) {\n node.visible = true\n let parent = node.parent\n while (parent && !cache.has(parent)) {\n parent.visible = true\n cache.add(parent)\n parent = parent.parent\n }\n } else {\n node.visible = false\n }\n })\n\n panelItemList.value = [createPanelItem(forest.roots)]\n})\n\nprovide(CascadeDIKey, { cls, size, disabled, readonly, cascadeProps: props, checkedSet })\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cascade.js","names":[],"sources":["../../../src/components/cascade/cascade.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n :class=\"[cls.b, bem.is('disabled', disabled), bem.is('multiple', multiple), cls.m(size)]\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size)]\"\n trigger=\"click\"\n ref=\"dropdownRef\"\n :disabled=\"disabled\"\n width=\"auto\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n @update:visible=\"!$event && (qs = '')\"\n >\n <template #trigger>\n <!-- 单选展示 -->\n <u-input\n v-if=\"!multiple\"\n :size=\"size\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :clearable=\"clearable\"\n native-readonly\n :model-value=\"displayedValue\"\n @clear=\"handleClear\"\n >\n <template #suffix>\n <u-icon :class=\"cls.e('arrow')\"><ArrowDown /></u-icon>\n </template>\n </u-input>\n\n <!-- 多选展示 -->\n <template v-if=\"multiple\">\n <span :class=\"cls.e('placeholder')\" v-show=\"!modelValue?.length\">\n {{ placeholder }}\n </span>\n\n <div v-if=\"modelValue?.length\" :class=\"cls.e('tags')\">\n <u-tag\n v-for=\"tag of tags\"\n :key=\"tag.value\"\n :closable=\"!disabled\"\n @close=\"handleCloseTag(tag)\"\n >\n {{ tag.label }}\n </u-tag>\n <u-tag v-if=\"restTag\"> {{ restTag }}+ </u-tag>\n </div>\n\n <transition name=\"zoom-in\" mode=\"out-in\">\n <u-icon\n v-if=\"clearable && modelValue?.length && hovered && !disabled\"\n :class=\"cls.e('clear')\"\n @click.stop=\"handleClear\"\n >\n <Close />\n </u-icon>\n\n <u-icon :class=\"cls.e('arrow')\" v-else><ArrowDown /></u-icon>\n </transition>\n </template>\n </template>\n\n <template #content>\n <!-- 过滤 -->\n <div v-if=\"filterable\" :class=\"cls.e('panel-filter')\">\n <u-input placeholder=\"输入关键字进行过滤\" v-model=\"qs\" :size=\"size\" clearable>\n <template #suffix>\n <u-icon><Search /></u-icon>\n </template>\n </u-input>\n </div>\n\n <div :class=\"cls.e('content')\" v-if=\"panelItemList.length\">\n <UCascadePanelItem\n v-for=\"({ nodes, key }, index) of panelItemList\"\n :data=\"nodes\"\n :key=\"key\"\n :panel-index=\"index\"\n :value=\"selectedNodeKeys[index]\"\n @click=\"handleClick\"\n @check=\"handleCheck\"\n />\n </div>\n\n <div :class=\"cls.e('empty')\" v-else>\n <UEmpty />\n </div>\n </template>\n </u-dropdown>\n\n <!-- 只读 -->\n <template v-else>\n <div :class=\"[cls.m(size)]\" v-if=\"multiple\">\n <div :class=\"cls.e('tags')\">\n <u-tag v-for=\"tag of tags\" :key=\"tag.value\">\n {{ tag.label }}\n </u-tag>\n </div>\n </div>\n <template v-else>\n {{ displayedValue || FORM_EMPTY_CONTENT }}\n </template>\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Forest, o } from '@cat-kit/core'\nimport { useFormFallbackProps, useUserAction } from '@veltra/compositions'\nimport { ArrowDown, Close, Search } from '@veltra/icons/normal'\nimport { bem, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, provide, shallowRef, triggerRef, watch } from 'vue'\n\nimport type { CascadeProps, CascadeEmits, DropdownExposed } from '../../types'\nimport { UDropdown } from '../dropdown'\nimport { UEmpty } from '../empty'\nimport { UIcon } from '../icon'\nimport { UInput } from '../input'\nimport { UTag } from '../tag'\nimport UCascadePanelItem from './cascade-panel-item.vue'\nimport { CascadeDIKey } from './di'\nimport { CascadeNode } from './node'\nimport { useCheck } from './use-check'\nimport { useDataMap } from './use-data-map'\nimport { useSelect } from './use-select'\n\ndefineOptions({ name: 'Cascade' })\n\nconst props = withDefaults(defineProps<CascadeProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n placeholder: '请选择',\n separator: '/',\n clearable: true,\n disabled: undefined,\n readonly: undefined,\n childrenKey: 'children',\n filterable: false,\n data: () => [],\n visibilityLimit: 3\n})\n\nconst emit = defineEmits<CascadeEmits>()\n\nconst cls = bem('cascade')\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {\n size: 'default',\n disabled: false,\n readonly: false\n})\n\nconst dropdownRef = shallowRef<DropdownExposed>()\n\nconst forest = computed(() => {\n return new Forest<Record<string, unknown>, any>({\n data: (props.data ?? []) as Record<string, unknown>[],\n childrenKey: props.childrenKey,\n createNode: (data, index, depth, _forest, parent) => {\n if (!data) {\n return new CascadeNode({ data, index, depth, value: '', label: '', parent })\n }\n\n return new CascadeNode({\n data,\n index,\n depth,\n value: o(data).get(props.valueKey) ?? '',\n label: o(data).get(props.labelKey) ?? '',\n parent\n })\n }\n })\n})\n\nconst { dataMap } = useDataMap({ props, forest })\n\nconst { userAction, isUserActive } = useUserAction()\n\nconst {\n displayedValue,\n selectItem,\n updateSingleValue,\n panelItemList,\n getPanelItemList,\n createPanelItem,\n selectedNodeKeys\n} = useSelect({ props, emit, dataMap, forest, isUserActive, dropdownRef })\n\nconst { hovered, tags, restTag, updateMultipleValue, handleCloseTag, checkItem, checkedSet } =\n useCheck({ props, forest, getPanelItemList, emit, dataMap, isUserActive, disabled, readonly })\n\nconst commitSingleSelect = userAction((item: CascadeNode) => {\n if (!props.strict) {\n updateSingleValue()\n } else if (!item.children?.length) {\n updateSingleValue()\n }\n})\n\nfunction handleClick(panelIndex: number, item: CascadeNode) {\n selectItem(panelIndex, item)\n\n if (!props.multiple) {\n commitSingleSelect(item)\n }\n}\n\nconst handleCheck = userAction((item: CascadeNode, checked: boolean) => {\n checkItem(item, checked)\n})\n\nfunction handleClear() {\n if (props.multiple) {\n checkedSet.value.clear()\n triggerRef(checkedSet)\n updateMultipleValue()\n } else {\n selectedNodeKeys.value = []\n updateSingleValue()\n }\n\n emit('clear')\n}\n\n// 过滤\nconst qs = shallowRef<string>('')\n\nwatch([qs, forest], ([qs, forest]) => {\n const { filterable } = props\n if (!filterable || !qs) {\n forest.dfs((node) => {\n node.visible = true\n })\n getPanelItemList(forest.roots)\n return\n }\n\n const cache = new Set<CascadeNode>()\n\n forest.dfs((node) => {\n if (node.label?.toLowerCase().includes(qs.toLowerCase())) {\n node.visible = true\n let parent = node.parent\n while (parent && !cache.has(parent)) {\n parent.visible = true\n cache.add(parent)\n parent = parent.parent\n }\n } else {\n node.visible = false\n }\n })\n\n panelItemList.value = [createPanelItem(forest.roots)]\n})\n\nprovide(CascadeDIKey, { cls, size, disabled, readonly, cascadeProps: props, checkedSet })\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgIA,MAAM,QAAQ;EAcd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,SAAS;EAEzB,MAAM,EAAE,cAAc,kBAAkB;EAExC,MAAM,EAAE,MAAM,UAAU,aAAa,qBAAqB,CAAC,aAAa,CAAC,GAAG,KAAK,GAAG;GAClF,MAAM;GACN,UAAU;GACV,UAAU;EACZ,CAAC;EAED,MAAM,cAAc,WAA4B;EAEhD,MAAM,SAAS,eAAe;GAC5B,OAAO,IAAI,OAAqC;IAC9C,MAAO,MAAM,QAAQ,CAAC;IACtB,aAAa,MAAM;IACnB,aAAa,MAAM,OAAO,OAAO,SAAS,WAAW;KACnD,IAAI,CAAC,MACH,OAAO,IAAI,YAAY;MAAE;MAAM;MAAO;MAAO,OAAO;MAAI,OAAO;MAAI;KAAO,CAAC;KAG7E,OAAO,IAAI,YAAY;MACrB;MACA;MACA;MACA,OAAO,EAAE,IAAI,EAAE,IAAI,MAAM,QAAQ,KAAK;MACtC,OAAO,EAAE,IAAI,EAAE,IAAI,MAAM,QAAQ,KAAK;MACtC;KACF,CAAC;IACH;GACF,CAAC;EACH,CAAC;EAED,MAAM,EAAE,YAAY,WAAW;GAAE;GAAO;EAAO,CAAC;EAEhD,MAAM,EAAE,YAAY,iBAAiB,cAAc;EAEnD,MAAM,EACJ,gBACA,YACA,mBACA,eACA,kBACA,iBACA,qBACE,UAAU;GAAE;GAAO;GAAM;GAAS;GAAQ;GAAc;EAAY,CAAC;EAEzE,MAAM,EAAE,SAAS,MAAM,SAAS,qBAAqB,gBAAgB,WAAW,eAC9E,SAAS;GAAE;GAAO;GAAQ;GAAkB;GAAM;GAAS;GAAc;GAAU;EAAS,CAAC;EAE/F,MAAM,qBAAqB,YAAY,SAAsB;GAC3D,IAAI,CAAC,MAAM,QACT,kBAAkB;QACb,IAAI,CAAC,KAAK,UAAU,QACzB,kBAAkB;EAEtB,CAAC;EAED,SAAS,YAAY,YAAoB,MAAmB;GAC1D,WAAW,YAAY,IAAI;GAE3B,IAAI,CAAC,MAAM,UACT,mBAAmB,IAAI;EAE3B;EAEA,MAAM,cAAc,YAAY,MAAmB,YAAqB;GACtE,UAAU,MAAM,OAAO;EACzB,CAAC;EAED,SAAS,cAAc;GACrB,IAAI,MAAM,UAAU;IAClB,WAAW,MAAM,MAAM;IACvB,WAAW,UAAU;IACrB,oBAAoB;GACtB,OAAO;IACL,iBAAiB,QAAQ,CAAC;IAC1B,kBAAkB;GACpB;GAEA,KAAK,OAAO;EACd;EAGA,MAAM,KAAK,WAAmB,EAAE;EAEhC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,YAAY;GACpC,MAAM,EAAE,eAAe;GACvB,IAAI,CAAC,cAAc,CAAC,IAAI;IACtB,OAAO,KAAK,SAAS;KACnB,KAAK,UAAU;IACjB,CAAC;IACD,iBAAiB,OAAO,KAAK;IAC7B;GACF;GAEA,MAAM,wBAAQ,IAAI,IAAiB;GAEnC,OAAO,KAAK,SAAS;IACnB,IAAI,KAAK,OAAO,YAAY,EAAE,SAAS,GAAG,YAAY,CAAC,GAAG;KACxD,KAAK,UAAU;KACf,IAAI,SAAS,KAAK;KAClB,OAAO,UAAU,CAAC,MAAM,IAAI,MAAM,GAAG;MACnC,OAAO,UAAU;MACjB,MAAM,IAAI,MAAM;MAChB,SAAS,OAAO;KAClB;IACF,OACE,KAAK,UAAU;GAEnB,CAAC;GAED,cAAc,QAAQ,CAAC,gBAAgB,OAAO,KAAK,CAAC;EACtD,CAAC;EAED,QAAQ,cAAc;GAAE;GAAK;GAAM;GAAU;GAAU,cAAc;GAAO;EAAW,CAAC;;WAjQ7E,MAAA,QAAA,KAAA,UAAA,GADT,YAuFa,MAAA,WAAA,GAAA;;IArFV,OAAK,eAAA;KAAG,MAAA,GAAA,EAAI;KAAG,MAAA,GAAA,EAAI,GAAE,YAAa,MAAA,QAAA,CAAQ;KAAG,MAAA,GAAA,EAAI,GAAE,YAAa,QAAA,QAAQ;KAAG,MAAA,GAAA,EAAI,EAAE,MAAA,IAAA,CAAI;IAAA,CAAA;IACrF,iBAAa,CAAG,MAAA,GAAA,EAAI,EAAC,OAAA,GAAW,MAAA,GAAA,EAAI,GAAE,SAAU,MAAA,IAAA,CAAI,CAAA;IACrD,SAAQ;aACJ;IAAJ,KAAI;IACH,UAAU,MAAA,QAAA;IACX,OAAM;IACL,cAAU,OAAA,OAAA,OAAA,MAAA,WAAE,QAAA,QAAO;IACnB,cAAU,OAAA,OAAA,OAAA,MAAA,WAAE,QAAA,QAAO;IACnB,oBAAc,OAAA,OAAA,OAAA,MAAA,WAAA,CAAG,WAAW,GAAA,QAAE;;IAEpB,SAAO,cACH;KAAb,mBAAA,QAAA;MAES,QAAA,YAAA,UAAA,GADT,YAaU,MAAA,aAAA,GAAA;;MAXP,MAAM,MAAA,IAAA;MACN,UAAU,MAAA,QAAA;MACV,aAAa,QAAA;MACb,WAAW,QAAA;MACZ,mBAAA;MACC,eAAa,MAAA,cAAA;MACb,SAAO;;MAEG,QAAM,cACuC,CAAtD,YAAsD,MAAA,WAAA,GAAA,EAA7C,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,OAAA,CAAA,EAAA,GAAA;8BAAwB,CAAb,YAAa,MAAA,SAAA,CAAA,CAAA,CAAA;;;;;;;;;;;KAIjD,mBAAA,QAAA;KACgB,QAAA,YAAA,UAAA,GAAhB,mBA4BW,UAAA,EAAA,KAAA,EAAA,GAAA;qBA3BT,mBAEO,QAAA,EAFA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,aAAA,CAAA,EAAA,GAAA,gBACd,QAAA,WAAW,GAAA,CAAA,GAAA,CAAA,CAAA,OAAA,CAD6B,QAAA,YAAY,MAAM,CAAA,CAAA;MAIpD,QAAA,YAAY,UAAA,UAAA,GAAvB,mBAUM,OAAA;;OAV0B,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,MAAA,CAAA;4BAC1C,mBAOQ,UAAA,MAAA,WANQ,MAAA,IAAA,IAAP,QAAG;2BADZ,YAOQ,MAAA,WAAA,GAAA;QALL,KAAK,IAAI;QACT,UAAQ,CAAG,MAAA,QAAA;QACX,UAAK,WAAE,MAAA,cAAA,EAAe,GAAG;;+BAEX,CAAA,gBAAA,gBAAZ,IAAI,KAAK,GAAA,CAAA,CAAA,CAAA;;;iBAED,MAAA,OAAA,KAAA,UAAA,GAAb,YAA8C,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,GAAA;8BAAV,CAAA,gBAAA,gBAAV,MAAA,OAAA,CAAO,IAAG,MAAE,CAAA,CAAA,CAAA;;;MAGxC,YAUa,YAAA;OAVD,MAAK;OAAU,MAAK;;8BAOrB,CALD,QAAA,aAAa,QAAA,YAAY,UAAU,MAAA,OAAA,KAAO,CAAK,MAAA,QAAA,KAAA,UAAA,GADvD,YAMS,MAAA,WAAA,GAAA;;QAJN,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,OAAA,CAAA;QACZ,SAAK,cAAO,aAAW,CAAA,MAAA,CAAA;;+BAEf,CAAT,YAAS,MAAA,KAAA,CAAA,CAAA,CAAA;;yCAGX,YAA6D,MAAA,WAAA,GAAA;;QAApD,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,OAAA,CAAA;;+BAA+B,CAAb,YAAa,MAAA,SAAA,CAAA,CAAA,CAAA;;;;;;;IAK/C,SAAO,cACL;KAAX,mBAAA,MAAA;KACW,QAAA,cAAA,UAAA,GAAX,mBAMM,OAAA;;MANkB,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,cAAA,CAAA;SAClC,YAIU,MAAA,aAAA,GAAA;MAJD,aAAY;kBAAqB,GAAA;mEAAA,GAAE,QAAA;MAAG,MAAM,MAAA,IAAA;MAAM,WAAA;;MAC9C,QAAM,cACY,CAA3B,YAA2B,MAAA,WAAA,GAAA,MAAA;8BAAT,CAAV,YAAU,MAAA,MAAA,CAAA,CAAA,CAAA;;;;;KAKa,MAAA,aAAA,EAAc,UAAA,UAAA,GAAnD,mBAUM,OAAA;;MAVA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,SAAA,CAAA;2BAChB,mBAQE,UAAA,MAAA,WAPkC,MAAA,aAAA,IAAa,EAArC,OAAO,OAAO,UAAK;0BAD/B,YAQE,aAAA;OANC,MAAM;OACD;OACL,eAAa;OACb,OAAO,MAAA,gBAAA,EAAiB;OACxB,SAAO;OACP,SAAO,MAAA,WAAA;;;;;;;qCAIZ,mBAEM,OAAA;;MAFA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,OAAA,CAAA;SAChB,YAAU,MAAA,WAAA,CAAA,CAAA,GAAA,CAAA;;;;;;;uBAMhB,mBAWW,UAAA,EAAA,KAAA,EAAA,GAAA,CAZX,mBAAA,MAAA,GAEoC,QAAA,YAAA,UAAA,GAAlC,mBAMM,OAAA;;IANA,OAAK,eAAA,CAAG,MAAA,GAAA,EAAI,EAAE,MAAA,IAAA,CAAI,CAAA,CAAA;OACtB,mBAIM,OAAA,EAJA,OAAK,eAAE,MAAA,GAAA,EAAI,EAAC,MAAA,CAAA,EAAA,GAAA,EAAA,UAAA,IAAA,GAChB,mBAEQ,UAAA,MAAA,WAFa,MAAA,IAAA,IAAP,QAAG;wBAAjB,YAEQ,MAAA,WAAA,GAAA,EAFoB,KAAK,IAAI,MAAA,GAAA;4BACpB,CAAA,gBAAA,gBAAZ,IAAI,KAAK,GAAA,CAAA,CAAA,CAAA;;;wCAIlB,mBAEW,UAAA,EAAA,KAAA,EAAA,GAAA,CAAA,gBAAA,gBADN,MAAA,cAAA,KAAkB,MAAA,kBAAA,CAAkB,GAAA,CAAA,CAAA,GAAA,EAAA,EAAA,GAAA,EAAA"}
|