@veltra/desktop 1.2.26 → 1.2.28
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/action/action-group.vue.d.ts +1 -1
- package/dist/components/action/action.vue.d.ts +1 -1
- package/dist/components/batch-edit/batch-edit-form.js +10 -5
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/use-edit-state.js +1 -0
- package/dist/components/batch-edit/use-edit-state.js.map +1 -1
- package/dist/components/batch-edit/use-handlers.js +3 -0
- package/dist/components/batch-edit/use-handlers.js.map +1 -1
- package/dist/components/batch-edit/use-shortcut-key.js +2 -0
- package/dist/components/batch-edit/use-shortcut-key.js.map +1 -1
- package/dist/components/cascade/cascade.vue.d.ts +2 -2
- package/dist/components/grid-input/grid-input.js +18 -12
- package/dist/components/grid-input/grid-input.js.map +1 -1
- package/dist/components/grid-input/grid-input.vue.d.ts +1 -1
- package/dist/components/input/input.vue.d.ts +2 -2
- package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +2 -2
- package/dist/components/number/number.vue.d.ts +1 -1
- package/dist/components/number-input/number-input.vue.d.ts +2 -2
- package/dist/components/number-range-input/number-range-input.js +23 -16
- package/dist/components/number-range-input/number-range-input.js.map +1 -1
- package/dist/components/textarea/textarea.vue.d.ts +2 -2
- package/dist/components/tip/tip.vue.d.ts +1 -1
- package/dist/components/tree-select/tree-select.vue.d.ts +2 -2
- package/dist/components/watermark/watermark.vue.d.ts +1 -1
- package/dist/types/grid-input.d.ts +12 -5
- package/package.json +6 -6
- package/src/components/batch-edit/batch-edit-form.vue +11 -5
- package/src/components/batch-edit/use-edit-state.ts +3 -0
- package/src/components/batch-edit/use-handlers.ts +5 -0
- package/src/components/batch-edit/use-shortcut-key.ts +2 -0
- package/src/components/grid-input/grid-input.vue +21 -17
- package/src/components/number-range-input/__test__/number-range-input.test.ts +100 -0
- package/src/components/number-range-input/number-range-input.vue +28 -16
- package/src/types/grid-input.ts +12 -5
|
@@ -8,9 +8,9 @@ type __VLS_Slots = {
|
|
|
8
8
|
declare const __VLS_base: import("vue").DefineComponent<ActionGroupProps, _ActionGroupExposed, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ActionGroupProps> & Readonly<{}>, {
|
|
9
9
|
type: import("@veltra/utils").ColorType;
|
|
10
10
|
size: "small" | "default" | "large";
|
|
11
|
-
text: boolean;
|
|
12
11
|
circle: boolean;
|
|
13
12
|
max: number;
|
|
13
|
+
text: boolean;
|
|
14
14
|
loading: boolean;
|
|
15
15
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
16
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -14,8 +14,8 @@ declare const __VLS_base: import("vue").DefineComponent<ActionProps, {}, {}, {},
|
|
|
14
14
|
}>, {
|
|
15
15
|
type: ButtonType;
|
|
16
16
|
size: import("@veltra/utils").ComponentSize;
|
|
17
|
-
text: boolean;
|
|
18
17
|
circle: boolean;
|
|
18
|
+
text: boolean;
|
|
19
19
|
loading: boolean;
|
|
20
20
|
inDropdown: boolean;
|
|
21
21
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -7,7 +7,7 @@ import { BatchEditDIKey } from "./di.js";
|
|
|
7
7
|
import { FORM_ACTION_HEADER_MAP } from "./form-action-header.js";
|
|
8
8
|
import { Fragment, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, guardReactiveProps, inject, normalizeClass, normalizeProps, openBlock, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, toRef, unref, withCtx } from "vue";
|
|
9
9
|
import { bem } from "@veltra/utils";
|
|
10
|
-
import { Close } from "@veltra/icons/normal";
|
|
10
|
+
import { Close, Save } from "@veltra/icons/normal";
|
|
11
11
|
import { o } from "@cat-kit/core";
|
|
12
12
|
//#region src/components/batch-edit/batch-edit-form.vue
|
|
13
13
|
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
@@ -119,6 +119,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
119
119
|
}),
|
|
120
120
|
_cache[3] || (_cache[3] = createTextVNode(" 关闭 ", -1))
|
|
121
121
|
], 2)], 2), createElementVNode("div", { class: normalizeClass(unref(cls).e("form-actions")) }, [createVNode(unref(_sfc_main$3), {
|
|
122
|
+
size: "small",
|
|
122
123
|
text: "",
|
|
123
124
|
loading: unref(state).loading,
|
|
124
125
|
onClick: unref(handleClose)
|
|
@@ -128,12 +129,16 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
128
129
|
}, 8, ["loading", "onClick"]), showSaveBtn.value ? (openBlock(), createBlock(unref(_sfc_main$3), {
|
|
129
130
|
key: 0,
|
|
130
131
|
type: "primary",
|
|
132
|
+
size: "small",
|
|
133
|
+
title: "保存",
|
|
134
|
+
icon: unref(Save),
|
|
131
135
|
loading: unref(state).loading,
|
|
132
136
|
onClick: unref(handleSave)
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
}, null, 8, [
|
|
138
|
+
"icon",
|
|
139
|
+
"loading",
|
|
140
|
+
"onClick"
|
|
141
|
+
])) : createCommentVNode("v-if", true)], 2)], 2)
|
|
137
142
|
], 2)) : createCommentVNode("v-if", true);
|
|
138
143
|
};
|
|
139
144
|
}
|
|
@@ -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.formVisible && !!props.model\">\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'), bem.is(state.formActionType)]\">\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 </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 :label-width=\"props.labelWidth\"\n @field:change=\"handleFieldChange\"\n >\n <slot\n v-bind=\"{\n row: state.row,\n depth: state.depth,\n indexes: state.indexPath,\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')\">\n <template v-if=\"props.readonly\"> 只读模式 </template>\n\n <span :class=\"{ [bem.is('concealed')]: !focused }\">\n <template v-if=\"!(state.formActionType === 'update' && props.quickEdit)\">\n <u-kbd>Ctrl + S</u-kbd> 保存 ·\n </template>\n <u-kbd>Esc</u-kbd> 关闭\n </span>\n </span>\n\n <div :class=\"cls.e('form-actions')\">\n <u-button text :loading=\"state.loading\" @click=\"handleClose\"> 取消 </u-button>\n <u-button
|
|
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.formVisible && !!props.model\">\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'), bem.is(state.formActionType)]\">\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 </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 :label-width=\"props.labelWidth\"\n @field:change=\"handleFieldChange\"\n >\n <slot\n v-bind=\"{\n row: state.row,\n depth: state.depth,\n indexes: state.indexPath,\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')\">\n <template v-if=\"props.readonly\"> 只读模式 </template>\n\n <span :class=\"{ [bem.is('concealed')]: !focused }\">\n <template v-if=\"!(state.formActionType === 'update' && props.quickEdit)\">\n <u-kbd>Ctrl + S</u-kbd> 保存 ·\n </template>\n <u-kbd>Esc</u-kbd> 关闭\n </span>\n </span>\n\n <div :class=\"cls.e('form-actions')\">\n <u-button size=\"small\" text :loading=\"state.loading\" @click=\"handleClose\"> 取消 </u-button>\n <u-button\n v-if=\"showSaveBtn\"\n type=\"primary\"\n size=\"small\"\n title=\"保存\"\n :icon=\"Save\"\n :loading=\"state.loading\"\n @click=\"handleSave\"\n />\n </div>\n </footer>\n </aside>\n</template>\n\n<script lang=\"ts\" setup>\nimport { o } from '@cat-kit/core'\nimport { Close, Save } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, shallowRef, toRef } 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'\nimport { FORM_ACTION_HEADER_MAP } from './form-action-header'\n\ndefineOptions({ name: 'UBatchEditForm' })\n\nconst batchEditCtx = inject(BatchEditDIKey)!\n\nconst { cls, props, state, handleClose, handleSave, staticFeatures, dynamicFeatures } = batchEditCtx\n\nconst focused = toRef(batchEditCtx, 'focused')\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\nfunction handleFieldChange(field: string, value: any) {\n if (state.row && props.quickEdit) {\n o(state.row.data).set(field, value)\n }\n}\n\nconst creatable = computed(() => {\n if (state.formActionType !== 'create') return false\n return staticFeatures.value.has('create') || dynamicFeatures.value.create?.(state.row)\n})\n\nconst creatableChild = computed(() => {\n if (state.formActionType !== 'createChild') return false\n return staticFeatures.value.has('createChild') || dynamicFeatures.value.createChild?.(state.row)\n})\n\nconst updatable = computed(() => {\n if (state.formActionType !== 'update') return false\n return staticFeatures.value.has('update') || dynamicFeatures.value.update?.(state.row)\n})\n\nconst showSaveBtn = computed(() => {\n if (props.readonly) return false\n if (props.quickEdit && state.formActionType === 'update') return false\n return creatable.value || updatable.value || creatableChild.value\n})\n\nconst headerInfo = computed(() => FORM_ACTION_HEADER_MAP[state.formActionType])\n\n/** 通过 row 切换 / 类型切换驱动表单内容淡出淡入 */\nconst bodyKey = computed(() => {\n return `${state.formActionType}-${state.row?.uid ?? 'create'}-${state.parentRow?.uid ?? 'root'}`\n})\n</script>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-edit-state.js","names":[],"sources":["../../../src/components/batch-edit/use-edit-state.ts"],"sourcesContent":["import { o } from '@cat-kit/core'\nimport { nextTick, shallowReactive, watch, type ShallowRef } from 'vue'\n\nimport type { BatchEditProps, BatchEditStates, FormExposed } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n formRef: ShallowRef<FormExposed | null>\n}\n\nexport function useEditState(options: Options) {\n const { props, formRef } = options\n\n const defaultState: BatchEditStates = {\n depth: -1,\n formVisible: false,\n formActionType: 'create',\n loading: false,\n indexPath: []\n }\n\n const state = shallowReactive({ ...defaultState })\n\n function resetState() {\n if (state.row) {\n state.row.isCurrent = false\n }\n\n Object.keys(state).forEach((key) => {\n delete state[key]\n })\n\n Object.assign(state, defaultState)\n }\n\n watch(\n () => state.row,\n (row) => {\n formRef.value?.reset()\n\n if (row) {\n /** 延迟设置 model,防止表单初始状态丢失 */\n nextTick(() => {\n if (props.model) {\n o(props.model).deepExtend(row.data)\n }\n })\n state.formActionType = props.readonly ? 'view' : 'update'\n state.formVisible = true\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n\n return\n }\n\n resetState()\n }\n )\n\n return { state, resetState }\n}\n"],"mappings":";;;AAUA,SAAgB,aAAa,SAAkB;CAC7C,MAAM,EAAE,OAAO,YAAY;CAE3B,MAAM,eAAgC;EACpC,OAAO;EACP,aAAa;EACb,gBAAgB;EAChB,SAAS;EACT,WAAW,CAAC;CACd;CAEA,MAAM,QAAQ,gBAAgB,EAAE,GAAG,aAAa,CAAC;CAEjD,SAAS,aAAa;
|
|
1
|
+
{"version":3,"file":"use-edit-state.js","names":[],"sources":["../../../src/components/batch-edit/use-edit-state.ts"],"sourcesContent":["import { o } from '@cat-kit/core'\nimport { nextTick, shallowReactive, watch, type ShallowRef } from 'vue'\n\nimport type { BatchEditProps, BatchEditStates, FormExposed } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n formRef: ShallowRef<FormExposed | null>\n}\n\nexport function useEditState(options: Options) {\n const { props, formRef } = options\n\n const defaultState: BatchEditStates = {\n depth: -1,\n formVisible: false,\n formActionType: 'create',\n loading: false,\n indexPath: []\n }\n\n const state = shallowReactive({ ...defaultState })\n\n function resetState() {\n // 销毁表单前先重置,避免下次 v-if 重挂载时 Form 拍到脏 model\n formRef.value?.reset()\n\n if (state.row) {\n state.row.isCurrent = false\n }\n\n Object.keys(state).forEach((key) => {\n delete state[key]\n })\n\n Object.assign(state, defaultState)\n }\n\n watch(\n () => state.row,\n (row) => {\n formRef.value?.reset()\n\n if (row) {\n /** 延迟设置 model,防止表单初始状态丢失 */\n nextTick(() => {\n if (props.model) {\n o(props.model).deepExtend(row.data)\n }\n })\n state.formActionType = props.readonly ? 'view' : 'update'\n state.formVisible = true\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n\n return\n }\n\n resetState()\n }\n )\n\n return { state, resetState }\n}\n"],"mappings":";;;AAUA,SAAgB,aAAa,SAAkB;CAC7C,MAAM,EAAE,OAAO,YAAY;CAE3B,MAAM,eAAgC;EACpC,OAAO;EACP,aAAa;EACb,gBAAgB;EAChB,SAAS;EACT,WAAW,CAAC;CACd;CAEA,MAAM,QAAQ,gBAAgB,EAAE,GAAG,aAAa,CAAC;CAEjD,SAAS,aAAa;EAEpB,QAAQ,OAAO,MAAM;EAErB,IAAI,MAAM,KACR,MAAM,IAAI,YAAY;EAGxB,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,QAAQ;GAClC,OAAO,MAAM;EACf,CAAC;EAED,OAAO,OAAO,OAAO,YAAY;CACnC;CAEA,YACQ,MAAM,MACX,QAAQ;EACP,QAAQ,OAAO,MAAM;EAErB,IAAI,KAAK;;GAEP,eAAe;IACb,IAAI,MAAM,OACR,EAAE,MAAM,KAAK,CAAC,CAAC,WAAW,IAAI,IAAI;GAEtC,CAAC;GACD,MAAM,iBAAiB,MAAM,WAAW,SAAS;GACjD,MAAM,cAAc;GACpB,MAAM,QAAQ,IAAI;GAClB,MAAM,YAAY,CAAC,GAAG,IAAI,OAAO;GAEjC;EACF;EAEA,WAAW;CACb,CACF;CAEA,OAAO;EAAE;EAAO;CAAW;AAC7B"}
|
|
@@ -103,6 +103,9 @@ function useHandlers(options) {
|
|
|
103
103
|
if (result) item = result;
|
|
104
104
|
}
|
|
105
105
|
insert(item);
|
|
106
|
+
const next = last(state.indexPath) + 1;
|
|
107
|
+
state.indexPath = [...state.indexPath.slice(0, -1), next];
|
|
108
|
+
formRef.value?.reset();
|
|
106
109
|
return;
|
|
107
110
|
}
|
|
108
111
|
if (saveMethod) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-handlers.js","names":[],"sources":["../../../src/components/batch-edit/use-handlers.ts"],"sourcesContent":["import { last, o } from '@cat-kit/core'\nimport { computed, nextTick, type ShallowRef } from 'vue'\n\nimport type {\n TableRow,\n BatchEditEmits,\n BatchEditProps,\n BatchEditStates,\n FormExposed\n} 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 state: BatchEditStates\n formRef: ShallowRef<FormExposed | null>\n resetState: () => void\n}\n\nexport interface EditReturned {\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => 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 useHandlers(options: Options): EditReturned {\n const { props, emit, state, resetState, formRef } = options\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n function getInsertData(): Record<string, any> {\n return o(props.model ?? {}).copy()\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(data ?? [], state.indexPath.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(state.indexPath), 0, item)\n }\n } else {\n data.splice(last(state.indexPath), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n /**\n * 点击新增按钮\n */\n function handleCreate() {\n const { data } = props\n\n resetState()\n\n nextTick(() => {\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = 1\n state.indexPath = [data?.length ?? 0]\n })\n }\n\n function handleInsertToPrev(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n }\n\n function handleInsertToNext(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = row.depth\n state.indexPath = [...row.indexes.slice(0, -1), row.index + 1]\n }\n\n function handleInsertChild(row: TableRow) {\n resetState()\n state.formActionType = 'createChild'\n state.formVisible = true\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n state.indexPath = [...row.indexes, row.children?.length ?? 0]\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 const valid = await formRef.value?.validate()\n if (!model || !valid) return\n\n let item = getInsertData()\n\n // 新增\n if (state.formActionType === 'create' || state.formActionType === 'createChild') {\n await props.beforeCreate?.(item, state.parentRow?.data)\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n return\n }\n\n // 普通模式下的编辑\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n\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 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 resetState()\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n resetState()\n }\n\n return {\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"use-handlers.js","names":[],"sources":["../../../src/components/batch-edit/use-handlers.ts"],"sourcesContent":["import { last, o } from '@cat-kit/core'\nimport { computed, nextTick, type ShallowRef } from 'vue'\n\nimport type {\n TableRow,\n BatchEditEmits,\n BatchEditProps,\n BatchEditStates,\n FormExposed\n} 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 state: BatchEditStates\n formRef: ShallowRef<FormExposed | null>\n resetState: () => void\n}\n\nexport interface EditReturned {\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => 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 useHandlers(options: Options): EditReturned {\n const { props, emit, state, resetState, formRef } = options\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n function getInsertData(): Record<string, any> {\n return o(props.model ?? {}).copy()\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(data ?? [], state.indexPath.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(state.indexPath), 0, item)\n }\n } else {\n data.splice(last(state.indexPath), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n /**\n * 点击新增按钮\n */\n function handleCreate() {\n const { data } = props\n\n resetState()\n\n nextTick(() => {\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = 1\n state.indexPath = [data?.length ?? 0]\n })\n }\n\n function handleInsertToPrev(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n }\n\n function handleInsertToNext(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = row.depth\n state.indexPath = [...row.indexes.slice(0, -1), row.index + 1]\n }\n\n function handleInsertChild(row: TableRow) {\n resetState()\n state.formActionType = 'createChild'\n state.formVisible = true\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n state.indexPath = [...row.indexes, row.children?.length ?? 0]\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 const valid = await formRef.value?.validate()\n if (!model || !valid) return\n\n let item = getInsertData()\n\n // 新增\n if (state.formActionType === 'create' || state.formActionType === 'createChild') {\n await props.beforeCreate?.(item, state.parentRow?.data)\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n\n // 推进插入点,便于连续新增;并重置表单到初始默认值\n const next = last(state.indexPath) + 1\n state.indexPath = [...state.indexPath.slice(0, -1), next]\n formRef.value?.reset()\n return\n }\n\n // 普通模式下的编辑\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n\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 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 resetState()\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n resetState()\n }\n\n return {\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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"}
|
|
@@ -10,7 +10,9 @@ function useShortcutKey(options) {
|
|
|
10
10
|
if (!e.currentTarget.contains(e.relatedTarget)) focused.value = false;
|
|
11
11
|
}
|
|
12
12
|
function runEscape(e) {
|
|
13
|
+
if (!state.formVisible) return;
|
|
13
14
|
e.preventDefault();
|
|
15
|
+
e.stopPropagation();
|
|
14
16
|
onClose();
|
|
15
17
|
}
|
|
16
18
|
function runSave(e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-shortcut-key.js","names":[],"sources":["../../../src/components/batch-edit/use-shortcut-key.ts"],"sourcesContent":["import { shallowRef } from 'vue'\n\nimport type { BatchEditProps, BatchEditStates } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n onSave: () => void\n onClose: () => void\n state: BatchEditStates\n}\nexport function useShortcutKey(options: Options) {\n const { props, onClose, onSave, state } = options\n const focused = shallowRef(false)\n\n function handleFocusIn() {\n focused.value = true\n }\n\n function handleFocusOut(e: FocusEvent) {\n const root = e.currentTarget as HTMLElement\n if (!root.contains(e.relatedTarget as Node | null)) {\n focused.value = false\n }\n }\n\n function runEscape(e: KeyboardEvent) {\n e.preventDefault()\n onClose()\n }\n\n function runSave(e: KeyboardEvent) {\n if (!state.formVisible) return\n if (props.quickEdit && state.formActionType === 'update') return\n e.preventDefault()\n onSave()\n }\n\n /**\n * 键盘快捷键(仅组件获焦时生效):\n * - Esc 关闭表单\n * - ⌘/Ctrl + S 保存(快速编辑模式下编辑行时除外)\n */\n function handleKeydown(e: KeyboardEvent) {\n if (!focused.value) return\n if (props.readonly && e.key !== 'Escape') return\n\n if (e.key === 'Escape') return runEscape(e)\n\n const meta = e.metaKey || e.ctrlKey\n if (!meta) return\n\n const key = e.key.toLowerCase()\n\n if (key === 's') return runSave(e)\n }\n\n return { focused, handleFocusIn, handleFocusOut, handleKeydown }\n}\n"],"mappings":";;AAUA,SAAgB,eAAe,SAAkB;CAC/C,MAAM,EAAE,OAAO,SAAS,QAAQ,UAAU;CAC1C,MAAM,UAAU,WAAW,KAAK;CAEhC,SAAS,gBAAgB;EACvB,QAAQ,QAAQ;CAClB;CAEA,SAAS,eAAe,GAAe;EAErC,IAAI,CADS,EAAE,cACL,SAAS,EAAE,aAA4B,GAC/C,QAAQ,QAAQ;CAEpB;CAEA,SAAS,UAAU,GAAkB;EACnC,EAAE,eAAe;EACjB,QAAQ;CACV;CAEA,SAAS,QAAQ,GAAkB;EACjC,IAAI,CAAC,MAAM,aAAa;EACxB,IAAI,MAAM,aAAa,MAAM,mBAAmB,UAAU;EAC1D,EAAE,eAAe;EACjB,OAAO;CACT;;;;;;CAOA,SAAS,cAAc,GAAkB;EACvC,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,MAAM,YAAY,EAAE,QAAQ,UAAU;EAE1C,IAAI,EAAE,QAAQ,UAAU,OAAO,UAAU,CAAC;EAG1C,IAAI,EADS,EAAE,WAAW,EAAE,UACjB;EAIX,IAFY,EAAE,IAAI,YAEZ,MAAM,KAAK,OAAO,QAAQ,CAAC;CACnC;CAEA,OAAO;EAAE;EAAS;EAAe;EAAgB;CAAc;AACjE"}
|
|
1
|
+
{"version":3,"file":"use-shortcut-key.js","names":[],"sources":["../../../src/components/batch-edit/use-shortcut-key.ts"],"sourcesContent":["import { shallowRef } from 'vue'\n\nimport type { BatchEditProps, BatchEditStates } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n onSave: () => void\n onClose: () => void\n state: BatchEditStates\n}\nexport function useShortcutKey(options: Options) {\n const { props, onClose, onSave, state } = options\n const focused = shallowRef(false)\n\n function handleFocusIn() {\n focused.value = true\n }\n\n function handleFocusOut(e: FocusEvent) {\n const root = e.currentTarget as HTMLElement\n if (!root.contains(e.relatedTarget as Node | null)) {\n focused.value = false\n }\n }\n\n function runEscape(e: KeyboardEvent) {\n if (!state.formVisible) return\n e.preventDefault()\n e.stopPropagation()\n onClose()\n }\n\n function runSave(e: KeyboardEvent) {\n if (!state.formVisible) return\n if (props.quickEdit && state.formActionType === 'update') return\n e.preventDefault()\n onSave()\n }\n\n /**\n * 键盘快捷键(仅组件获焦时生效):\n * - Esc 关闭表单\n * - ⌘/Ctrl + S 保存(快速编辑模式下编辑行时除外)\n */\n function handleKeydown(e: KeyboardEvent) {\n if (!focused.value) return\n if (props.readonly && e.key !== 'Escape') return\n\n if (e.key === 'Escape') return runEscape(e)\n\n const meta = e.metaKey || e.ctrlKey\n if (!meta) return\n\n const key = e.key.toLowerCase()\n\n if (key === 's') return runSave(e)\n }\n\n return { focused, handleFocusIn, handleFocusOut, handleKeydown }\n}\n"],"mappings":";;AAUA,SAAgB,eAAe,SAAkB;CAC/C,MAAM,EAAE,OAAO,SAAS,QAAQ,UAAU;CAC1C,MAAM,UAAU,WAAW,KAAK;CAEhC,SAAS,gBAAgB;EACvB,QAAQ,QAAQ;CAClB;CAEA,SAAS,eAAe,GAAe;EAErC,IAAI,CADS,EAAE,cACL,SAAS,EAAE,aAA4B,GAC/C,QAAQ,QAAQ;CAEpB;CAEA,SAAS,UAAU,GAAkB;EACnC,IAAI,CAAC,MAAM,aAAa;EACxB,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAClB,QAAQ;CACV;CAEA,SAAS,QAAQ,GAAkB;EACjC,IAAI,CAAC,MAAM,aAAa;EACxB,IAAI,MAAM,aAAa,MAAM,mBAAmB,UAAU;EAC1D,EAAE,eAAe;EACjB,OAAO;CACT;;;;;;CAOA,SAAS,cAAc,GAAkB;EACvC,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,MAAM,YAAY,EAAE,QAAQ,UAAU;EAE1C,IAAI,EAAE,QAAQ,UAAU,OAAO,UAAU,CAAC;EAG1C,IAAI,EADS,EAAE,WAAW,EAAE,UACjB;EAIX,IAFY,EAAE,IAAI,YAEZ,MAAM,KAAK,OAAO,QAAQ,CAAC;CACnC;CAEA,OAAO;EAAE;EAAS;EAAe;EAAgB;CAAc;AACjE"}
|
|
@@ -2,13 +2,13 @@ import { CascadeProps } from "../../types/cascade.js";
|
|
|
2
2
|
//#region src/components/cascade/cascade.vue.d.ts
|
|
3
3
|
declare const __VLS_export: import("vue").DefineComponent<CascadeProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
4
4
|
"update:modelValue": (value?: string | string[] | undefined) => any;
|
|
5
|
-
clear: () => any;
|
|
6
5
|
change: (...args: [item?: Record<string, any> | undefined] | [items: Record<string, any>[]]) => any;
|
|
6
|
+
clear: () => any;
|
|
7
7
|
"update:label": (label?: string | string[] | undefined) => any;
|
|
8
8
|
}, string, import("vue").PublicProps, Readonly<CascadeProps> & Readonly<{
|
|
9
9
|
"onUpdate:modelValue"?: ((value?: string | string[] | undefined) => any) | undefined;
|
|
10
|
-
onClear?: (() => any) | undefined;
|
|
11
10
|
onChange?: ((...args: [item?: Record<string, any> | undefined] | [items: Record<string, any>[]]) => any) | undefined;
|
|
11
|
+
onClear?: (() => any) | undefined;
|
|
12
12
|
"onUpdate:label"?: ((label?: string | string[] | undefined) => any) | undefined;
|
|
13
13
|
}>, {
|
|
14
14
|
labelKey: string;
|
|
@@ -25,11 +25,16 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
25
25
|
const props = __props;
|
|
26
26
|
const { size } = useFallbackProps([props], { size: "default" });
|
|
27
27
|
const cls = bem("grid-input");
|
|
28
|
-
const
|
|
28
|
+
const numberReg = computed(() => props.zero ? /^[0-9]$/ : /^[1-9]$/);
|
|
29
29
|
const valueArray = ref([]);
|
|
30
30
|
const position = ref(-1);
|
|
31
31
|
const blur = ref(false);
|
|
32
32
|
const instance = getCurrentInstance();
|
|
33
|
+
const emitValue = () => {
|
|
34
|
+
const value = valueArray.value.join(props.separator);
|
|
35
|
+
emit("input", value);
|
|
36
|
+
emit("update:modelValue", value);
|
|
37
|
+
};
|
|
33
38
|
const focus = async (index) => {
|
|
34
39
|
if (index === void 0) {
|
|
35
40
|
focus(position.value);
|
|
@@ -42,38 +47,39 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
42
47
|
};
|
|
43
48
|
const changeValue = (value, index) => {
|
|
44
49
|
if (position.value === props.length) return;
|
|
45
|
-
if (valueArray.value
|
|
50
|
+
if (index < valueArray.value.length) valueArray.value.splice(index, 1, value);
|
|
46
51
|
else if (index === valueArray.value.length) valueArray.value.push(value);
|
|
47
52
|
else return;
|
|
48
53
|
position.value++;
|
|
49
54
|
focus();
|
|
50
|
-
|
|
55
|
+
emitValue();
|
|
51
56
|
};
|
|
52
57
|
const baseOperation = {
|
|
53
|
-
Backspace: (
|
|
54
|
-
if (value) valueArray.value.splice(index, 1);
|
|
58
|
+
Backspace: (_value, index) => {
|
|
59
|
+
if (index < valueArray.value.length) valueArray.value.splice(index, 1);
|
|
55
60
|
else if (index - 1 >= 0) valueArray.value.splice(index - 1, 1);
|
|
56
61
|
if (index !== 0) focus(index - 1);
|
|
57
|
-
|
|
62
|
+
emitValue();
|
|
58
63
|
},
|
|
59
|
-
ArrowLeft: (
|
|
64
|
+
ArrowLeft: (_value, index) => {
|
|
60
65
|
if (index === 0) return;
|
|
61
66
|
focus(index - 1);
|
|
62
67
|
},
|
|
63
|
-
ArrowRight: (
|
|
68
|
+
ArrowRight: (_value, index) => {
|
|
64
69
|
if (index === valueArray.value.length) return;
|
|
65
70
|
focus(index + 1);
|
|
66
71
|
}
|
|
67
72
|
};
|
|
68
73
|
const onKeydown = (e, value, index) => {
|
|
69
|
-
if (
|
|
74
|
+
if (numberReg.value.test(e.key)) {
|
|
70
75
|
changeValue(e.key, index);
|
|
71
76
|
return;
|
|
72
77
|
}
|
|
73
|
-
baseOperation[e.key](value, index);
|
|
78
|
+
baseOperation[e.key]?.(value, index);
|
|
74
79
|
};
|
|
75
80
|
const clear = () => {
|
|
76
|
-
|
|
81
|
+
valueArray.value = [];
|
|
82
|
+
position.value = -1;
|
|
77
83
|
};
|
|
78
84
|
__expose({ clear });
|
|
79
85
|
return (_ctx, _cache) => {
|
|
@@ -87,7 +93,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
87
93
|
ref_for: true,
|
|
88
94
|
ref: "items",
|
|
89
95
|
class: normalizeClass([unref(cls).e("item"), unref(bem).is("focus", index === position.value && !blur.value)])
|
|
90
|
-
}, [valueArray.value
|
|
96
|
+
}, [index < valueArray.value.length ? (openBlock(), createElementBlock("span", {
|
|
91
97
|
key: 0,
|
|
92
98
|
class: normalizeClass(unref(cls).em("item", "text"))
|
|
93
99
|
}, toDisplayString(valueArray.value[index]), 3)) : index === position.value ? (openBlock(), createElementBlock("span", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid-input.js","names":[],"sources":["../../../src/components/grid-input/grid-input.vue"],"sourcesContent":["<template>\n <ul :class=\"[cls.b, cls.m(size)]\">\n <li\n v-for=\"(_, index) in length\"\n :key=\"index\"\n tabindex=\"0\"\n @keydown=\"onKeydown($event, valueArray[index]!, index)\"\n @focus=\"focus(index)\"\n @blur=\"index === position && (blur = true)\"\n ref=\"items\"\n :class=\"[cls.e('item'), bem.is('focus', index === position && !blur)]\"\n >\n <span :class=\"cls.em('item', 'text')\" v-if=\"valueArray
|
|
1
|
+
{"version":3,"file":"grid-input.js","names":[],"sources":["../../../src/components/grid-input/grid-input.vue"],"sourcesContent":["<template>\n <ul :class=\"[cls.b, cls.m(size)]\">\n <li\n v-for=\"(_, index) in length\"\n :key=\"index\"\n tabindex=\"0\"\n @keydown=\"onKeydown($event, valueArray[index]!, index)\"\n @focus=\"focus(index)\"\n @blur=\"index === position && (blur = true)\"\n ref=\"items\"\n :class=\"[cls.e('item'), bem.is('focus', index === position && !blur)]\"\n >\n <span :class=\"cls.em('item', 'text')\" v-if=\"index < valueArray.length\">\n {{ valueArray[index] }}\n </span>\n\n <span :class=\"cls.em('item', 'cursor')\" v-else-if=\"index === position\"></span>\n </li>\n </ul>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFallbackProps } from '@veltra/compositions'\nimport { bem } from '@veltra/utils'\nimport { computed, ref, getCurrentInstance } from 'vue'\n\nimport type { GridInputProps, GridInputEmits, GridInputExposed } from '../../types'\n\ndefineOptions({ name: 'UGridInput' })\n\nconst emit = defineEmits<GridInputEmits>()\n\nconst props = withDefaults(defineProps<GridInputProps>(), {\n length: 6,\n zero: false,\n separator: '-'\n})\n\nconst { size } = useFallbackProps([props], { size: 'default' })\n\nconst cls = bem('grid-input')\n\nconst numberReg = computed(() => (props.zero ? /^[0-9]$/ : /^[1-9]$/))\n\nconst valueArray = ref<string[]>([])\n\nconst position = ref<number>(-1)\n\nconst blur = ref<boolean>(false)\n\nconst instance = getCurrentInstance()\n\nconst emitValue = () => {\n const value = valueArray.value.join(props.separator)\n emit('input', value)\n emit('update:modelValue', value)\n}\n\nconst focus = async (index?: number) => {\n if (index === undefined) {\n focus(position.value)\n return\n }\n if (index !== 0 && index > valueArray.value.length) {\n index = valueArray.value.length\n }\n position.value = index\n const items = (instance?.refs as { items?: unknown })?.items as any\n let dom = items?.[index]\n dom?.focus()\n blur.value = false\n}\n\nconst changeValue = (value: string, index: number) => {\n if (position.value === props.length) return\n\n if (index < valueArray.value.length) {\n valueArray.value.splice(index, 1, value)\n } else if (index === valueArray.value.length) {\n valueArray.value.push(value)\n } else {\n return\n }\n position.value++\n focus()\n\n emitValue()\n}\n\nconst baseOperation: Record<string, (value: string, index: number) => void> = {\n Backspace: (_value: string, index: number) => {\n if (index < valueArray.value.length) {\n valueArray.value.splice(index, 1)\n } else if (index - 1 >= 0) {\n valueArray.value.splice(index - 1, 1)\n }\n if (index !== 0) {\n focus(index - 1)\n }\n emitValue()\n },\n ArrowLeft: (_value: string, index: number) => {\n if (index === 0) return\n focus(index - 1)\n },\n ArrowRight: (_value: string, index: number) => {\n if (index === valueArray.value.length) return\n focus(index + 1)\n }\n}\n\nconst onKeydown = (e: KeyboardEvent, value: string, index: number) => {\n if (numberReg.value.test(e.key)) {\n changeValue(e.key, index)\n return\n }\n baseOperation[e.key]?.(value, index)\n}\n\nconst clear = () => {\n valueArray.value = []\n position.value = -1\n}\n\ndefineExpose<GridInputExposed>({ clear })\n</script>\n"],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ declare const __VLS_export: import("vue").DefineComponent<GridInputProps, import
|
|
|
9
9
|
}>, {
|
|
10
10
|
length: number;
|
|
11
11
|
separator: string;
|
|
12
|
-
zero:
|
|
12
|
+
zero: boolean;
|
|
13
13
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
14
|
declare const _default: typeof __VLS_export;
|
|
15
15
|
//#endregion
|
|
@@ -15,20 +15,20 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, _Inpu
|
|
|
15
15
|
"update:modelValue": (value: string | undefined) => any;
|
|
16
16
|
} & {
|
|
17
17
|
"update:modelValue": (value: string) => any;
|
|
18
|
-
clear: () => any;
|
|
19
18
|
change: (value: string) => any;
|
|
20
19
|
"suffix:click": (value?: string | undefined) => any;
|
|
21
20
|
"prefix:click": (value?: string | undefined) => any;
|
|
22
21
|
focus: (value?: string | undefined) => any;
|
|
22
|
+
clear: () => any;
|
|
23
23
|
blur: (value?: string | undefined) => any;
|
|
24
24
|
"native:input": (ev: Event) => any;
|
|
25
25
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
26
26
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
27
|
-
onClear?: (() => any) | undefined;
|
|
28
27
|
onChange?: ((value: string) => any) | undefined;
|
|
29
28
|
"onSuffix:click"?: ((value?: string | undefined) => any) | undefined;
|
|
30
29
|
"onPrefix:click"?: ((value?: string | undefined) => any) | undefined;
|
|
31
30
|
onFocus?: ((value?: string | undefined) => any) | undefined;
|
|
31
|
+
onClear?: (() => any) | undefined;
|
|
32
32
|
onBlur?: ((value?: string | undefined) => any) | undefined;
|
|
33
33
|
"onNative:input"?: ((ev: Event) => any) | undefined;
|
|
34
34
|
}>, {
|
|
@@ -14,12 +14,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
14
14
|
"update:modelValue": (value: (string | number)[]) => any;
|
|
15
15
|
} & {
|
|
16
16
|
"update:modelValue": (value: any[]) => any;
|
|
17
|
-
clear: () => any;
|
|
18
17
|
change: (checked: Record<string, any>[]) => any;
|
|
18
|
+
clear: () => any;
|
|
19
19
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
20
|
"onUpdate:modelValue"?: ((value: any[]) => any) | undefined;
|
|
21
|
-
onClear?: (() => any) | undefined;
|
|
22
21
|
onChange?: ((checked: Record<string, any>[]) => any) | undefined;
|
|
22
|
+
onClear?: (() => any) | undefined;
|
|
23
23
|
}>, {
|
|
24
24
|
expandAll: boolean;
|
|
25
25
|
labelKey: string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { NumberProps } from "../../types/number.js";
|
|
2
2
|
//#region src/components/number/number.vue.d.ts
|
|
3
3
|
declare const __VLS_export: import("vue").DefineComponent<NumberProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NumberProps> & Readonly<{}>, {
|
|
4
|
-
format: "currency" | "percent" | "decimal";
|
|
5
4
|
duration: number;
|
|
5
|
+
format: "currency" | "percent" | "decimal";
|
|
6
6
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
7
7
|
declare const _default: typeof __VLS_export;
|
|
8
8
|
//#endregion
|
|
@@ -13,12 +13,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
13
13
|
"update:modelValue": (value: number | undefined) => any;
|
|
14
14
|
} & {
|
|
15
15
|
"update:modelValue": (value?: number | undefined) => any;
|
|
16
|
-
clear: () => any;
|
|
17
16
|
change: (value?: number | undefined) => any;
|
|
17
|
+
clear: () => any;
|
|
18
18
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
19
19
|
"onUpdate:modelValue"?: ((value?: number | undefined) => any) | undefined;
|
|
20
|
-
onClear?: (() => any) | undefined;
|
|
21
20
|
onChange?: ((value?: number | undefined) => any) | undefined;
|
|
21
|
+
onClear?: (() => any) | undefined;
|
|
22
22
|
}>, {
|
|
23
23
|
disabled: boolean;
|
|
24
24
|
readonly: boolean;
|
|
@@ -87,10 +87,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
87
87
|
const endRef = useModel(__props, "end");
|
|
88
88
|
let syncGuard = false;
|
|
89
89
|
function normalizeFromSplit(s, e) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (nextS !== void 0 && nextE !== void 0 && nextS > nextE) nextE = nextS;
|
|
93
|
-
return [nextS, nextE];
|
|
90
|
+
if (s !== void 0 && e !== void 0 && s > e) return [s, s];
|
|
91
|
+
return [s, e];
|
|
94
92
|
}
|
|
95
93
|
watch(model, (t) => {
|
|
96
94
|
if (syncGuard) return;
|
|
@@ -145,10 +143,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
145
143
|
return model.value?.[0];
|
|
146
144
|
},
|
|
147
145
|
set(v) {
|
|
148
|
-
|
|
149
|
-
let nextEnd = end;
|
|
150
|
-
if (v !== void 0 && end !== void 0 && v > end) nextEnd = v;
|
|
151
|
-
model.value = [v, nextEnd];
|
|
146
|
+
model.value = [v, (model.value ?? [void 0, void 0])[1]];
|
|
152
147
|
}
|
|
153
148
|
});
|
|
154
149
|
const endModel = computed({
|
|
@@ -156,10 +151,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
156
151
|
return model.value?.[1];
|
|
157
152
|
},
|
|
158
153
|
set(v) {
|
|
159
|
-
|
|
160
|
-
let nextStart = start;
|
|
161
|
-
if (v !== void 0 && start !== void 0 && v < start) nextStart = v;
|
|
162
|
-
model.value = [nextStart, v];
|
|
154
|
+
model.value = [(model.value ?? [void 0, void 0])[0], v];
|
|
163
155
|
}
|
|
164
156
|
});
|
|
165
157
|
function formatNumberPart(num) {
|
|
@@ -182,8 +174,23 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
182
174
|
const sep = props.separator ?? "~";
|
|
183
175
|
return `${p}${s === void 0 ? "—" : formatNumberPart(s)} ${sep} ${e === void 0 ? "—" : formatNumberPart(e)}${sfx}`;
|
|
184
176
|
});
|
|
185
|
-
function
|
|
186
|
-
|
|
177
|
+
function handleStartChange() {
|
|
178
|
+
const [start, end] = model.value ?? [void 0, void 0];
|
|
179
|
+
let next = [start, end];
|
|
180
|
+
if (start !== void 0 && end !== void 0 && start > end) {
|
|
181
|
+
next = [end, end];
|
|
182
|
+
model.value = next;
|
|
183
|
+
}
|
|
184
|
+
emit("change", next);
|
|
185
|
+
}
|
|
186
|
+
function handleEndChange() {
|
|
187
|
+
const [start, end] = model.value ?? [void 0, void 0];
|
|
188
|
+
let next = [start, end];
|
|
189
|
+
if (start !== void 0 && end !== void 0 && end < start) {
|
|
190
|
+
next = [start, start];
|
|
191
|
+
model.value = next;
|
|
192
|
+
}
|
|
193
|
+
emit("change", next);
|
|
187
194
|
}
|
|
188
195
|
return (_ctx, _cache) => {
|
|
189
196
|
return !unref(readonly) ? (openBlock(), createElementBlock("div", mergeProps({ key: 0 }, _ctx.$attrs, { class: className.value }), [
|
|
@@ -194,7 +201,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
194
201
|
disabled: unref(disabled),
|
|
195
202
|
readonly: unref(readonly),
|
|
196
203
|
size: unref(size)
|
|
197
|
-
}, numberInputBind.value, { onChange:
|
|
204
|
+
}, numberInputBind.value, { onChange: handleStartChange }), null, 16, [
|
|
198
205
|
"modelValue",
|
|
199
206
|
"placeholder",
|
|
200
207
|
"disabled",
|
|
@@ -209,7 +216,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
209
216
|
disabled: unref(disabled),
|
|
210
217
|
readonly: unref(readonly),
|
|
211
218
|
size: unref(size)
|
|
212
|
-
}, numberInputBind.value, { onChange:
|
|
219
|
+
}, numberInputBind.value, { onChange: handleEndChange }), null, 16, [
|
|
213
220
|
"modelValue",
|
|
214
221
|
"placeholder",
|
|
215
222
|
"disabled",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-range-input.js","names":["$attrs"],"sources":["../../../src/components/number-range-input/number-range-input.vue"],"sourcesContent":["<template>\n <div v-if=\"!readonly\" v-bind=\"$attrs\" :class=\"className\">\n <u-number-input\n v-model=\"startModel\"\n :placeholder=\"startPlaceholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :size=\"size\"\n v-bind=\"numberInputBind\"\n @change=\"emitChange\"\n />\n <span :class=\"cls.e('separator')\">{{ separator }}</span>\n <u-number-input\n v-model=\"endModel\"\n :placeholder=\"endPlaceholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :size=\"size\"\n v-bind=\"numberInputBind\"\n @change=\"emitChange\"\n />\n </div>\n\n <template v-else>\n {{ readonlyText || FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { n, $n, o } from '@cat-kit/core'\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { bem, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, getCurrentInstance, nextTick, onMounted, watch } from 'vue'\n\nimport type { NumberRangeInputEmits, NumberRangeInputProps, NumberRangeTuple } from '../../types'\nimport { UNumberInput } from '../number-input'\n\ndefineOptions({ name: 'UNumberRangeInput', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<NumberRangeInputProps>(), {\n startPlaceholder: '请输入',\n endPlaceholder: '请输入',\n separator: '~',\n clearable: true,\n disabled: undefined,\n readonly: undefined\n})\n\nconst emit = defineEmits<NumberRangeInputEmits>()\n\nconst inst = getCurrentInstance()\n\nfunction splitBound(): boolean {\n const p = inst?.vnode.props\n if (!p) return false\n return 'start' in p || 'onUpdate:start' in p || 'end' in p || 'onUpdate:end' in p\n}\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {\n size: 'default',\n disabled: false,\n readonly: false\n})\n\nconst cls = bem('number-range-input')\n\nconst className = computed(() => {\n return [cls.b, cls.m(size.value)]\n})\n\nconst model = defineModel<NumberRangeTuple>({ default: () => [undefined, undefined] })\n\nconst startRef = defineModel<number | undefined>('start')\nconst endRef = defineModel<number | undefined>('end')\n\nlet syncGuard = false\n\nfunction normalizeFromSplit(s: number | undefined, e: number | undefined): NumberRangeTuple {\n let nextS = s\n let nextE = e\n if (nextS !== undefined && nextE !== undefined && nextS > nextE) nextE = nextS\n return [nextS, nextE]\n}\n\nwatch(\n model,\n (t) => {\n if (syncGuard) return\n syncGuard = true\n const tuple = t ?? [undefined, undefined]\n if (startRef.value !== tuple[0]) startRef.value = tuple[0]\n if (endRef.value !== tuple[1]) endRef.value = tuple[1]\n nextTick(() => {\n syncGuard = false\n })\n },\n { deep: true }\n)\n\nwatch(\n [startRef, endRef],\n () => {\n if (!splitBound() || syncGuard) return\n syncGuard = true\n const normalized = normalizeFromSplit(startRef.value, endRef.value)\n const cur = model.value ?? [undefined, undefined]\n if (cur[0] !== normalized[0] || cur[1] !== normalized[1]) {\n model.value = normalized\n }\n nextTick(() => {\n syncGuard = false\n })\n },\n { deep: true }\n)\n\nonMounted(() => {\n if (!splitBound()) return\n const cur = model.value ?? [undefined, undefined]\n const hasModel = cur[0] !== undefined || cur[1] !== undefined\n if (hasModel) return\n const normalized = normalizeFromSplit(startRef.value, endRef.value)\n if (cur[0] !== normalized[0] || cur[1] !== normalized[1]) {\n syncGuard = true\n model.value = normalized\n nextTick(() => {\n syncGuard = false\n })\n }\n})\n\nconst numberInputBind = computed(() => {\n return o(props).pick([\n 'clearable',\n 'prefix',\n 'suffix',\n 'step',\n 'min',\n 'max',\n 'currency',\n 'precision',\n 'minPrecision',\n 'maxPrecision',\n 'multiple'\n ])\n})\n\nconst startModel = computed({\n get(): number | undefined {\n return model.value?.[0]\n },\n set(v: number | undefined) {\n const cur = model.value ?? [undefined, undefined]\n const end = cur[1]\n let nextEnd = end\n if (v !== undefined && end !== undefined && v > end) nextEnd = v\n model.value = [v, nextEnd]\n }\n})\n\nconst endModel = computed({\n get(): number | undefined {\n return model.value?.[1]\n },\n set(v: number | undefined) {\n const cur = model.value ?? [undefined, undefined]\n const start = cur[0]\n let nextStart = start\n if (v !== undefined && start !== undefined && v < start) nextStart = v\n model.value = [nextStart, v]\n }\n})\n\nfunction formatNumberPart(num: number): string {\n const { currency, precision, minPrecision, maxPrecision, multiple } = props\n\n const displayValue = multiple ? $n.div(num, multiple) : num\n\n return currency\n ? n(displayValue).currency('CNY', { precision, minPrecision, maxPrecision })\n : n(displayValue).fixed(precision ?? { minPrecision, maxPrecision })\n}\n\nconst readonlyText = computed(() => {\n const [s, e] = model.value ?? [undefined, undefined]\n if (s === undefined && e === undefined) return ''\n const p = props.prefix ?? ''\n const sfx = props.suffix ?? ''\n const sep = props.separator ?? '~'\n const a = s === undefined ? '—' : formatNumberPart(s)\n const b = e === undefined ? '—' : formatNumberPart(e)\n return `${p}${a} ${sep} ${b}${sfx}`\n})\n\nfunction emitChange(): void {\n emit('change', model.value ?? [undefined, undefined])\n}\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"number-range-input.js","names":["$attrs"],"sources":["../../../src/components/number-range-input/number-range-input.vue"],"sourcesContent":["<template>\n <div v-if=\"!readonly\" v-bind=\"$attrs\" :class=\"className\">\n <u-number-input\n v-model=\"startModel\"\n :placeholder=\"startPlaceholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :size=\"size\"\n v-bind=\"numberInputBind\"\n @change=\"handleStartChange\"\n />\n <span :class=\"cls.e('separator')\">{{ separator }}</span>\n <u-number-input\n v-model=\"endModel\"\n :placeholder=\"endPlaceholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :size=\"size\"\n v-bind=\"numberInputBind\"\n @change=\"handleEndChange\"\n />\n </div>\n\n <template v-else>\n {{ readonlyText || FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { n, $n, o } from '@cat-kit/core'\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { bem, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, getCurrentInstance, nextTick, onMounted, watch } from 'vue'\n\nimport type { NumberRangeInputEmits, NumberRangeInputProps, NumberRangeTuple } from '../../types'\nimport { UNumberInput } from '../number-input'\n\ndefineOptions({ name: 'UNumberRangeInput', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<NumberRangeInputProps>(), {\n startPlaceholder: '请输入',\n endPlaceholder: '请输入',\n separator: '~',\n clearable: true,\n disabled: undefined,\n readonly: undefined\n})\n\nconst emit = defineEmits<NumberRangeInputEmits>()\n\nconst inst = getCurrentInstance()\n\nfunction splitBound(): boolean {\n const p = inst?.vnode.props\n if (!p) return false\n return 'start' in p || 'onUpdate:start' in p || 'end' in p || 'onUpdate:end' in p\n}\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {\n size: 'default',\n disabled: false,\n readonly: false\n})\n\nconst cls = bem('number-range-input')\n\nconst className = computed(() => {\n return [cls.b, cls.m(size.value)]\n})\n\nconst model = defineModel<NumberRangeTuple>({ default: () => [undefined, undefined] })\n\nconst startRef = defineModel<number | undefined>('start')\nconst endRef = defineModel<number | undefined>('end')\n\nlet syncGuard = false\n\nfunction normalizeFromSplit(s: number | undefined, e: number | undefined): NumberRangeTuple {\n // 外部 split 写入无法区分哪一侧后改,统一将越界的 end 抬到 start\n if (s !== undefined && e !== undefined && s > e) return [s, s]\n return [s, e]\n}\n\nwatch(\n model,\n (t) => {\n if (syncGuard) return\n syncGuard = true\n const tuple = t ?? [undefined, undefined]\n if (startRef.value !== tuple[0]) startRef.value = tuple[0]\n if (endRef.value !== tuple[1]) endRef.value = tuple[1]\n nextTick(() => {\n syncGuard = false\n })\n },\n { deep: true }\n)\n\nwatch(\n [startRef, endRef],\n () => {\n if (!splitBound() || syncGuard) return\n syncGuard = true\n const normalized = normalizeFromSplit(startRef.value, endRef.value)\n const cur = model.value ?? [undefined, undefined]\n if (cur[0] !== normalized[0] || cur[1] !== normalized[1]) {\n model.value = normalized\n }\n nextTick(() => {\n syncGuard = false\n })\n },\n { deep: true }\n)\n\nonMounted(() => {\n if (!splitBound()) return\n const cur = model.value ?? [undefined, undefined]\n const hasModel = cur[0] !== undefined || cur[1] !== undefined\n if (hasModel) return\n const normalized = normalizeFromSplit(startRef.value, endRef.value)\n if (cur[0] !== normalized[0] || cur[1] !== normalized[1]) {\n syncGuard = true\n model.value = normalized\n nextTick(() => {\n syncGuard = false\n })\n }\n})\n\nconst numberInputBind = computed(() => {\n return o(props).pick([\n 'clearable',\n 'prefix',\n 'suffix',\n 'step',\n 'min',\n 'max',\n 'currency',\n 'precision',\n 'minPrecision',\n 'maxPrecision',\n 'multiple'\n ])\n})\n\nconst startModel = computed({\n get(): number | undefined {\n return model.value?.[0]\n },\n set(v: number | undefined) {\n // 输入过程只更新单侧,交叉约束放到 change(失焦)时处理\n const cur = model.value ?? [undefined, undefined]\n model.value = [v, cur[1]]\n }\n})\n\nconst endModel = computed({\n get(): number | undefined {\n return model.value?.[1]\n },\n set(v: number | undefined) {\n const cur = model.value ?? [undefined, undefined]\n model.value = [cur[0], v]\n }\n})\n\nfunction formatNumberPart(num: number): string {\n const { currency, precision, minPrecision, maxPrecision, multiple } = props\n\n const displayValue = multiple ? $n.div(num, multiple) : num\n\n return currency\n ? n(displayValue).currency('CNY', { precision, minPrecision, maxPrecision })\n : n(displayValue).fixed(precision ?? { minPrecision, maxPrecision })\n}\n\nconst readonlyText = computed(() => {\n const [s, e] = model.value ?? [undefined, undefined]\n if (s === undefined && e === undefined) return ''\n const p = props.prefix ?? ''\n const sfx = props.suffix ?? ''\n const sep = props.separator ?? '~'\n const a = s === undefined ? '—' : formatNumberPart(s)\n const b = e === undefined ? '—' : formatNumberPart(e)\n return `${p}${a} ${sep} ${b}${sfx}`\n})\n\nfunction handleStartChange(): void {\n const [start, end] = model.value ?? [undefined, undefined]\n // 失焦时只校正刚改的一侧:start > end 时把 start 压回 end\n let next: NumberRangeTuple = [start, end]\n if (start !== undefined && end !== undefined && start > end) {\n next = [end, end]\n model.value = next\n }\n emit('change', next)\n}\n\nfunction handleEndChange(): void {\n const [start, end] = model.value ?? [undefined, undefined]\n // 失焦时只校正刚改的一侧:end < start 时把 end 抬回 start\n let next: NumberRangeTuple = [start, end]\n if (start !== undefined && end !== undefined && end < start) {\n next = [start, start]\n model.value = next\n }\n emit('change', next)\n}\n</script>\n"],"mappings":"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"}
|
|
@@ -9,15 +9,15 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
9
9
|
"update:modelValue": (value: string | undefined) => any;
|
|
10
10
|
} & {
|
|
11
11
|
"update:modelValue": (value: string) => any;
|
|
12
|
-
clear: () => any;
|
|
13
12
|
change: (value: string) => any;
|
|
14
13
|
focus: () => any;
|
|
14
|
+
clear: () => any;
|
|
15
15
|
blur: () => any;
|
|
16
16
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
17
17
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
18
|
-
onClear?: (() => any) | undefined;
|
|
19
18
|
onChange?: ((value: string) => any) | undefined;
|
|
20
19
|
onFocus?: (() => any) | undefined;
|
|
20
|
+
onClear?: (() => any) | undefined;
|
|
21
21
|
onBlur?: (() => any) | undefined;
|
|
22
22
|
}>, {
|
|
23
23
|
disabled: boolean;
|
|
@@ -13,8 +13,8 @@ declare const __VLS_base: import("vue").DefineComponent<TipProps, {}, {}, {}, {}
|
|
|
13
13
|
contentTag: string;
|
|
14
14
|
visible: boolean;
|
|
15
15
|
direction: TipDirection;
|
|
16
|
-
content: string;
|
|
17
16
|
alignment: TipAlign;
|
|
17
|
+
content: string;
|
|
18
18
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
19
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
20
20
|
declare const _default: typeof __VLS_export;
|
|
@@ -15,13 +15,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
15
15
|
"update:modelValue": (value: string | number | undefined) => any;
|
|
16
16
|
} & {
|
|
17
17
|
"update:modelValue": (value?: string | number | undefined) => any;
|
|
18
|
-
clear: () => any;
|
|
19
18
|
change: (selectedData?: Record<string, any> | undefined) => any;
|
|
19
|
+
clear: () => any;
|
|
20
20
|
"update:text": (text?: string | undefined) => any;
|
|
21
21
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
22
22
|
"onUpdate:modelValue"?: ((value?: string | number | undefined) => any) | undefined;
|
|
23
|
-
onClear?: (() => any) | undefined;
|
|
24
23
|
onChange?: ((selectedData?: Record<string, any> | undefined) => any) | undefined;
|
|
24
|
+
onClear?: (() => any) | undefined;
|
|
25
25
|
"onUpdate:text"?: ((text?: string | undefined) => any) | undefined;
|
|
26
26
|
}>, {
|
|
27
27
|
expandAll: boolean;
|
|
@@ -5,8 +5,8 @@ type __VLS_Slots = {} & {
|
|
|
5
5
|
default?: (props: typeof __VLS_7) => any;
|
|
6
6
|
};
|
|
7
7
|
declare const __VLS_base: import("vue").DefineComponent<WatermarkProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<WatermarkProps> & Readonly<{}>, {
|
|
8
|
-
route: number;
|
|
9
8
|
fontSize: number;
|
|
9
|
+
route: number;
|
|
10
10
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
11
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
12
12
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
import { DeconstructValue } from "@veltra/utils";
|
|
2
2
|
|
|
3
3
|
//#region src/types/grid-input.d.ts
|
|
4
|
-
/**
|
|
4
|
+
/** 网格输入框组件属性 */
|
|
5
5
|
interface GridInputProps {
|
|
6
6
|
modelValue?: string;
|
|
7
|
+
/** 格子数量 */
|
|
7
8
|
length?: number;
|
|
8
|
-
|
|
9
|
+
/**
|
|
10
|
+
* 是否允许输入 0
|
|
11
|
+
* @description 验证码场景通常开启;组织编码结构等场景关闭(如 3-3-2)
|
|
12
|
+
* @default false
|
|
13
|
+
*/
|
|
14
|
+
zero?: boolean;
|
|
15
|
+
/** 格子之间的分隔符 */
|
|
9
16
|
separator?: string;
|
|
10
17
|
}
|
|
11
|
-
/**
|
|
18
|
+
/** 网格输入框组件定义的事件 */
|
|
12
19
|
interface GridInputEmits {
|
|
13
20
|
(e: 'update:modelValue', value: string): void;
|
|
14
21
|
(e: 'input', value: string): void;
|
|
15
22
|
}
|
|
16
|
-
/**
|
|
23
|
+
/** 网格输入框组件暴露的属性和方法(组件内部使用) */
|
|
17
24
|
interface _GridInputExposed {
|
|
18
25
|
clear: () => void;
|
|
19
26
|
}
|
|
20
|
-
/**
|
|
27
|
+
/** 网格输入框组件暴露的属性和方法(组件外部使用, 引用的值会被自动解构) */
|
|
21
28
|
type GridInputExposed = DeconstructValue<_GridInputExposed>;
|
|
22
29
|
//#endregion
|
|
23
30
|
export { GridInputEmits, GridInputExposed, GridInputProps, _GridInputExposed };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veltra/desktop",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.28",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist",
|
|
6
6
|
"src"
|
|
@@ -57,11 +57,11 @@
|
|
|
57
57
|
"@cat-kit/core": ">=1.1.8",
|
|
58
58
|
"@cat-kit/excel": ">=1.0.0",
|
|
59
59
|
"@cat-kit/fe": "^1.1.8",
|
|
60
|
-
"@veltra/compositions": "1.2.
|
|
61
|
-
"@veltra/directives": "1.2.
|
|
62
|
-
"@veltra/icons": "1.2.
|
|
63
|
-
"@veltra/styles": "1.2.
|
|
64
|
-
"@veltra/utils": "1.2.
|
|
60
|
+
"@veltra/compositions": "1.2.28",
|
|
61
|
+
"@veltra/directives": "1.2.28",
|
|
62
|
+
"@veltra/icons": "1.2.28",
|
|
63
|
+
"@veltra/styles": "1.2.28",
|
|
64
|
+
"@veltra/utils": "1.2.28",
|
|
65
65
|
"vue": ">=3.5.39"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
@@ -54,10 +54,16 @@
|
|
|
54
54
|
</span>
|
|
55
55
|
|
|
56
56
|
<div :class="cls.e('form-actions')">
|
|
57
|
-
<u-button text :loading="state.loading" @click="handleClose"> 取消 </u-button>
|
|
58
|
-
<u-button
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
<u-button size="small" text :loading="state.loading" @click="handleClose"> 取消 </u-button>
|
|
58
|
+
<u-button
|
|
59
|
+
v-if="showSaveBtn"
|
|
60
|
+
type="primary"
|
|
61
|
+
size="small"
|
|
62
|
+
title="保存"
|
|
63
|
+
:icon="Save"
|
|
64
|
+
:loading="state.loading"
|
|
65
|
+
@click="handleSave"
|
|
66
|
+
/>
|
|
61
67
|
</div>
|
|
62
68
|
</footer>
|
|
63
69
|
</aside>
|
|
@@ -65,7 +71,7 @@
|
|
|
65
71
|
|
|
66
72
|
<script lang="ts" setup>
|
|
67
73
|
import { o } from '@cat-kit/core'
|
|
68
|
-
import { Close } from '@veltra/icons/normal'
|
|
74
|
+
import { Close, Save } from '@veltra/icons/normal'
|
|
69
75
|
import { bem } from '@veltra/utils'
|
|
70
76
|
import { computed, inject, shallowRef, toRef } from 'vue'
|
|
71
77
|
|
|
@@ -22,6 +22,9 @@ export function useEditState(options: Options) {
|
|
|
22
22
|
const state = shallowReactive({ ...defaultState })
|
|
23
23
|
|
|
24
24
|
function resetState() {
|
|
25
|
+
// 销毁表单前先重置,避免下次 v-if 重挂载时 Form 拍到脏 model
|
|
26
|
+
formRef.value?.reset()
|
|
27
|
+
|
|
25
28
|
if (state.row) {
|
|
26
29
|
state.row.isCurrent = false
|
|
27
30
|
}
|
|
@@ -163,6 +163,11 @@ export function useHandlers(options: Options): EditReturned {
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
insert(item)
|
|
166
|
+
|
|
167
|
+
// 推进插入点,便于连续新增;并重置表单到初始默认值
|
|
168
|
+
const next = last(state.indexPath) + 1
|
|
169
|
+
state.indexPath = [...state.indexPath.slice(0, -1), next]
|
|
170
|
+
formRef.value?.reset()
|
|
166
171
|
return
|
|
167
172
|
}
|
|
168
173
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
ref="items"
|
|
11
11
|
:class="[cls.e('item'), bem.is('focus', index === position && !blur)]"
|
|
12
12
|
>
|
|
13
|
-
<span :class="cls.em('item', 'text')" v-if="valueArray
|
|
13
|
+
<span :class="cls.em('item', 'text')" v-if="index < valueArray.length">
|
|
14
14
|
{{ valueArray[index] }}
|
|
15
15
|
</span>
|
|
16
16
|
|
|
@@ -40,7 +40,7 @@ const { size } = useFallbackProps([props], { size: 'default' })
|
|
|
40
40
|
|
|
41
41
|
const cls = bem('grid-input')
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const numberReg = computed(() => (props.zero ? /^[0-9]$/ : /^[1-9]$/))
|
|
44
44
|
|
|
45
45
|
const valueArray = ref<string[]>([])
|
|
46
46
|
|
|
@@ -50,6 +50,12 @@ const blur = ref<boolean>(false)
|
|
|
50
50
|
|
|
51
51
|
const instance = getCurrentInstance()
|
|
52
52
|
|
|
53
|
+
const emitValue = () => {
|
|
54
|
+
const value = valueArray.value.join(props.separator)
|
|
55
|
+
emit('input', value)
|
|
56
|
+
emit('update:modelValue', value)
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
const focus = async (index?: number) => {
|
|
54
60
|
if (index === undefined) {
|
|
55
61
|
focus(position.value)
|
|
@@ -67,9 +73,8 @@ const focus = async (index?: number) => {
|
|
|
67
73
|
|
|
68
74
|
const changeValue = (value: string, index: number) => {
|
|
69
75
|
if (position.value === props.length) return
|
|
70
|
-
const currentValue = valueArray.value[index]
|
|
71
76
|
|
|
72
|
-
if (
|
|
77
|
+
if (index < valueArray.value.length) {
|
|
73
78
|
valueArray.value.splice(index, 1, value)
|
|
74
79
|
} else if (index === valueArray.value.length) {
|
|
75
80
|
valueArray.value.push(value)
|
|
@@ -79,12 +84,12 @@ const changeValue = (value: string, index: number) => {
|
|
|
79
84
|
position.value++
|
|
80
85
|
focus()
|
|
81
86
|
|
|
82
|
-
|
|
87
|
+
emitValue()
|
|
83
88
|
}
|
|
84
89
|
|
|
85
|
-
const baseOperation = {
|
|
86
|
-
Backspace: (
|
|
87
|
-
if (value) {
|
|
90
|
+
const baseOperation: Record<string, (value: string, index: number) => void> = {
|
|
91
|
+
Backspace: (_value: string, index: number) => {
|
|
92
|
+
if (index < valueArray.value.length) {
|
|
88
93
|
valueArray.value.splice(index, 1)
|
|
89
94
|
} else if (index - 1 >= 0) {
|
|
90
95
|
valueArray.value.splice(index - 1, 1)
|
|
@@ -92,30 +97,29 @@ const baseOperation = {
|
|
|
92
97
|
if (index !== 0) {
|
|
93
98
|
focus(index - 1)
|
|
94
99
|
}
|
|
95
|
-
|
|
100
|
+
emitValue()
|
|
96
101
|
},
|
|
97
|
-
ArrowLeft: (
|
|
102
|
+
ArrowLeft: (_value: string, index: number) => {
|
|
98
103
|
if (index === 0) return
|
|
99
104
|
focus(index - 1)
|
|
100
105
|
},
|
|
101
|
-
ArrowRight: (
|
|
106
|
+
ArrowRight: (_value: string, index: number) => {
|
|
102
107
|
if (index === valueArray.value.length) return
|
|
103
108
|
focus(index + 1)
|
|
104
109
|
}
|
|
105
110
|
}
|
|
106
111
|
|
|
107
|
-
const onKeydown = (e:
|
|
108
|
-
if (
|
|
112
|
+
const onKeydown = (e: KeyboardEvent, value: string, index: number) => {
|
|
113
|
+
if (numberReg.value.test(e.key)) {
|
|
109
114
|
changeValue(e.key, index)
|
|
110
115
|
return
|
|
111
116
|
}
|
|
112
|
-
baseOperation[e.key](value, index)
|
|
117
|
+
baseOperation[e.key]?.(value, index)
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
const clear = () => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
121
|
+
valueArray.value = []
|
|
122
|
+
position.value = -1
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
defineExpose<GridInputExposed>({ clear })
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { createApp, h, nextTick, ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
import type { NumberRangeTuple } from '../../../types'
|
|
5
|
+
import UNumberRangeInput from '../number-range-input.vue'
|
|
6
|
+
|
|
7
|
+
function mountNumberRangeInput(initial: NumberRangeTuple) {
|
|
8
|
+
const host = document.createElement('div')
|
|
9
|
+
document.body.appendChild(host)
|
|
10
|
+
|
|
11
|
+
const model = ref<NumberRangeTuple>([...initial])
|
|
12
|
+
const changes: NumberRangeTuple[] = []
|
|
13
|
+
|
|
14
|
+
const app = createApp({
|
|
15
|
+
render() {
|
|
16
|
+
return h(UNumberRangeInput, {
|
|
17
|
+
modelValue: model.value,
|
|
18
|
+
'onUpdate:modelValue': (value: NumberRangeTuple) => {
|
|
19
|
+
model.value = value
|
|
20
|
+
},
|
|
21
|
+
onChange: (value: NumberRangeTuple) => {
|
|
22
|
+
changes.push(value)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
app.mount(host)
|
|
29
|
+
|
|
30
|
+
const inputs = () => host.querySelectorAll<HTMLInputElement>('input')
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
host,
|
|
34
|
+
model,
|
|
35
|
+
changes,
|
|
36
|
+
inputs,
|
|
37
|
+
async setInputValue(index: 0 | 1, value: string) {
|
|
38
|
+
const input = inputs()[index]
|
|
39
|
+
if (!input) throw new Error(`input[${index}] not found`)
|
|
40
|
+
input.value = value
|
|
41
|
+
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
42
|
+
await nextTick()
|
|
43
|
+
},
|
|
44
|
+
async blurInput(index: 0 | 1) {
|
|
45
|
+
const input = inputs()[index]
|
|
46
|
+
if (!input) throw new Error(`input[${index}] not found`)
|
|
47
|
+
input.dispatchEvent(new Event('change', { bubbles: true }))
|
|
48
|
+
input.dispatchEvent(new FocusEvent('blur', { bubbles: true }))
|
|
49
|
+
await nextTick()
|
|
50
|
+
},
|
|
51
|
+
unmount() {
|
|
52
|
+
app.unmount()
|
|
53
|
+
host.remove()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe('NumberRangeInput', () => {
|
|
59
|
+
it('does not rewrite the other side while typing an intermediate value', async () => {
|
|
60
|
+
const { model, setInputValue, unmount } = mountNumberRangeInput([50, 80])
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// 结束框键入 2(意图输入 20),输入过程中 start 不应被改写
|
|
64
|
+
await setInputValue(1, '2')
|
|
65
|
+
expect(model.value).toEqual([50, 2])
|
|
66
|
+
} finally {
|
|
67
|
+
unmount()
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('clamps the edited end back to start on change when end < start', async () => {
|
|
72
|
+
const { model, changes, setInputValue, blurInput, unmount } = mountNumberRangeInput([80, 100])
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await setInputValue(1, '10')
|
|
76
|
+
expect(model.value).toEqual([80, 10])
|
|
77
|
+
|
|
78
|
+
await blurInput(1)
|
|
79
|
+
expect(model.value).toEqual([80, 80])
|
|
80
|
+
expect(changes.at(-1)).toEqual([80, 80])
|
|
81
|
+
} finally {
|
|
82
|
+
unmount()
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('clamps the edited start back to end on change when start > end', async () => {
|
|
87
|
+
const { model, changes, setInputValue, blurInput, unmount } = mountNumberRangeInput([50, 80])
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
await setInputValue(0, '90')
|
|
91
|
+
expect(model.value).toEqual([90, 80])
|
|
92
|
+
|
|
93
|
+
await blurInput(0)
|
|
94
|
+
expect(model.value).toEqual([80, 80])
|
|
95
|
+
expect(changes.at(-1)).toEqual([80, 80])
|
|
96
|
+
} finally {
|
|
97
|
+
unmount()
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
})
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
:readonly="readonly"
|
|
8
8
|
:size="size"
|
|
9
9
|
v-bind="numberInputBind"
|
|
10
|
-
@change="
|
|
10
|
+
@change="handleStartChange"
|
|
11
11
|
/>
|
|
12
12
|
<span :class="cls.e('separator')">{{ separator }}</span>
|
|
13
13
|
<u-number-input
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
:readonly="readonly"
|
|
18
18
|
:size="size"
|
|
19
19
|
v-bind="numberInputBind"
|
|
20
|
-
@change="
|
|
20
|
+
@change="handleEndChange"
|
|
21
21
|
/>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
@@ -79,10 +79,9 @@ const endRef = defineModel<number | undefined>('end')
|
|
|
79
79
|
let syncGuard = false
|
|
80
80
|
|
|
81
81
|
function normalizeFromSplit(s: number | undefined, e: number | undefined): NumberRangeTuple {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return [nextS, nextE]
|
|
82
|
+
// 外部 split 写入无法区分哪一侧后改,统一将越界的 end 抬到 start
|
|
83
|
+
if (s !== undefined && e !== undefined && s > e) return [s, s]
|
|
84
|
+
return [s, e]
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
watch(
|
|
@@ -153,11 +152,9 @@ const startModel = computed({
|
|
|
153
152
|
return model.value?.[0]
|
|
154
153
|
},
|
|
155
154
|
set(v: number | undefined) {
|
|
155
|
+
// 输入过程只更新单侧,交叉约束放到 change(失焦)时处理
|
|
156
156
|
const cur = model.value ?? [undefined, undefined]
|
|
157
|
-
|
|
158
|
-
let nextEnd = end
|
|
159
|
-
if (v !== undefined && end !== undefined && v > end) nextEnd = v
|
|
160
|
-
model.value = [v, nextEnd]
|
|
157
|
+
model.value = [v, cur[1]]
|
|
161
158
|
}
|
|
162
159
|
})
|
|
163
160
|
|
|
@@ -167,10 +164,7 @@ const endModel = computed({
|
|
|
167
164
|
},
|
|
168
165
|
set(v: number | undefined) {
|
|
169
166
|
const cur = model.value ?? [undefined, undefined]
|
|
170
|
-
|
|
171
|
-
let nextStart = start
|
|
172
|
-
if (v !== undefined && start !== undefined && v < start) nextStart = v
|
|
173
|
-
model.value = [nextStart, v]
|
|
167
|
+
model.value = [cur[0], v]
|
|
174
168
|
}
|
|
175
169
|
})
|
|
176
170
|
|
|
@@ -195,7 +189,25 @@ const readonlyText = computed(() => {
|
|
|
195
189
|
return `${p}${a} ${sep} ${b}${sfx}`
|
|
196
190
|
})
|
|
197
191
|
|
|
198
|
-
function
|
|
199
|
-
|
|
192
|
+
function handleStartChange(): void {
|
|
193
|
+
const [start, end] = model.value ?? [undefined, undefined]
|
|
194
|
+
// 失焦时只校正刚改的一侧:start > end 时把 start 压回 end
|
|
195
|
+
let next: NumberRangeTuple = [start, end]
|
|
196
|
+
if (start !== undefined && end !== undefined && start > end) {
|
|
197
|
+
next = [end, end]
|
|
198
|
+
model.value = next
|
|
199
|
+
}
|
|
200
|
+
emit('change', next)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function handleEndChange(): void {
|
|
204
|
+
const [start, end] = model.value ?? [undefined, undefined]
|
|
205
|
+
// 失焦时只校正刚改的一侧:end < start 时把 end 抬回 start
|
|
206
|
+
let next: NumberRangeTuple = [start, end]
|
|
207
|
+
if (start !== undefined && end !== undefined && end < start) {
|
|
208
|
+
next = [start, start]
|
|
209
|
+
model.value = next
|
|
210
|
+
}
|
|
211
|
+
emit('change', next)
|
|
200
212
|
}
|
|
201
213
|
</script>
|
package/src/types/grid-input.ts
CHANGED
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
import type { DeconstructValue } from '@veltra/utils'
|
|
2
2
|
|
|
3
|
-
/**
|
|
3
|
+
/** 网格输入框组件属性 */
|
|
4
4
|
export interface GridInputProps {
|
|
5
5
|
modelValue?: string
|
|
6
|
+
/** 格子数量 */
|
|
6
7
|
length?: number
|
|
7
|
-
|
|
8
|
+
/**
|
|
9
|
+
* 是否允许输入 0
|
|
10
|
+
* @description 验证码场景通常开启;组织编码结构等场景关闭(如 3-3-2)
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
zero?: boolean
|
|
14
|
+
/** 格子之间的分隔符 */
|
|
8
15
|
separator?: string
|
|
9
16
|
}
|
|
10
17
|
|
|
11
|
-
/**
|
|
18
|
+
/** 网格输入框组件定义的事件 */
|
|
12
19
|
export interface GridInputEmits {
|
|
13
20
|
(e: 'update:modelValue', value: string): void
|
|
14
21
|
(e: 'input', value: string): void
|
|
15
22
|
}
|
|
16
23
|
|
|
17
|
-
/**
|
|
24
|
+
/** 网格输入框组件暴露的属性和方法(组件内部使用) */
|
|
18
25
|
export interface _GridInputExposed {
|
|
19
26
|
clear: () => void
|
|
20
27
|
}
|
|
21
28
|
|
|
22
|
-
/**
|
|
29
|
+
/** 网格输入框组件暴露的属性和方法(组件外部使用, 引用的值会被自动解构) */
|
|
23
30
|
export type GridInputExposed = DeconstructValue<_GridInputExposed>
|