@antsoo-lib/core 2.0.0 → 2.0.2
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/CHANGELOG.md +6 -0
- package/dist/core.css +1 -0
- package/dist/index.cjs +57 -0
- package/dist/index.js +4154 -0
- package/dist/types/BaseSearch/index.d.ts +59 -0
- package/dist/types/BaseTable/index.d.ts +204 -0
- package/dist/types/Form/CoreForm.d.ts +82 -0
- package/dist/types/Form/types.d.ts +57 -0
- package/dist/types/SSelectPage/index.d.ts +102 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/render/AreaCascader.d.ts +5 -0
- package/dist/types/render/AutoComplete.d.ts +4 -0
- package/dist/types/render/Button.d.ts +4 -0
- package/dist/types/render/Cascader.d.ts +5 -0
- package/dist/types/render/Checkbox.d.ts +4 -0
- package/dist/types/render/CheckboxGroup.d.ts +4 -0
- package/dist/types/render/Custom.d.ts +8 -0
- package/dist/types/render/DatePicker.d.ts +4 -0
- package/dist/types/render/Input.d.ts +4 -0
- package/dist/types/render/InputGroup.d.ts +5 -0
- package/dist/types/render/InputNumber.d.ts +4 -0
- package/dist/types/render/InputPassword.d.ts +4 -0
- package/dist/types/render/InputRange.d.ts +9 -0
- package/dist/types/render/RadioGroup.d.ts +4 -0
- package/dist/types/render/Select.d.ts +4 -0
- package/dist/types/render/SselectPage.d.ts +4 -0
- package/dist/types/render/Switch.d.ts +4 -0
- package/dist/types/render/Tree.d.ts +9 -0
- package/dist/types/render/TreeSelect.d.ts +4 -0
- package/dist/types/render/Upload.d.ts +4 -0
- package/dist/types/render/helper.d.ts +10 -0
- package/dist/types/render/index.d.ts +43 -0
- package/dist/types/render/registry.d.ts +9 -0
- package/dist/types/render/state.d.ts +19 -0
- package/dist/types/render/types.d.ts +435 -0
- package/dist/types/utils/attrMapping.d.ts +26 -0
- package/package.json +12 -15
- package/src/BaseSearch/index.vue +371 -0
- package/src/BaseTable/index.vue +48 -22
- package/src/Form/CoreForm.vue +782 -0
- package/src/Form/types.ts +86 -0
- package/src/SSelectPage/index.vue +607 -0
- package/src/index.ts +15 -1
- package/src/{BaseTable/renderers → render}/AreaCascader.tsx +3 -3
- package/src/{BaseTable/renderers → render}/AutoComplete.tsx +3 -3
- package/src/{BaseTable/renderers → render}/Button.tsx +2 -2
- package/src/{BaseTable/renderers → render}/Cascader.tsx +3 -3
- package/src/{BaseTable/renderers → render}/Checkbox.tsx +2 -2
- package/src/{BaseTable/renderers → render}/CheckboxGroup.tsx +2 -2
- package/src/render/Custom.tsx +19 -0
- package/src/{BaseTable/renderers → render}/DatePicker.tsx +2 -2
- package/src/{BaseTable/renderers → render}/Input.tsx +3 -3
- package/src/{BaseTable/renderers → render}/InputGroup.tsx +3 -3
- package/src/{BaseTable/renderers → render}/InputNumber.tsx +3 -3
- package/src/{BaseTable/renderers → render}/InputPassword.tsx +3 -3
- package/src/render/InputRange.tsx +154 -0
- package/src/{BaseTable/renderers → render}/RadioGroup.tsx +2 -2
- package/src/{BaseTable/renderers → render}/Select.tsx +2 -2
- package/src/{BaseTable/renderers → render}/SselectPage.tsx +3 -3
- package/src/{BaseTable/renderers → render}/Switch.tsx +2 -2
- package/src/render/Tree.tsx +136 -0
- package/src/{BaseTable/renderers → render}/TreeSelect.tsx +2 -2
- package/src/{BaseTable/renderers → render}/Upload.tsx +4 -5
- package/src/{BaseTable/utils.tsx → render/helper.tsx} +86 -9
- package/src/{BaseTable/renderers → render}/index.ts +45 -4
- package/src/{BaseTable → render}/types.ts +62 -2
- package/src/utils/attrMapping.ts +106 -0
- package/vite.config.ts +15 -2
- package/index.css +0 -2
- package/index.ts +0 -21
- package/src/BaseTable/helpers.tsx +0 -91
- /package/src/{BaseTable → render}/registry.ts +0 -0
- /package/src/{BaseTable → render}/state.ts +0 -0
|
@@ -4,9 +4,9 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
4
4
|
import { markRaw } from 'vue'
|
|
5
5
|
import type { VNode } from 'vue'
|
|
6
6
|
|
|
7
|
-
import { getRegisteredComponent } from '
|
|
8
|
-
import type { ToolbarState } from '
|
|
9
|
-
import type { AreaCascaderProps, AreaCascaderToolbarItem } from '
|
|
7
|
+
import { getRegisteredComponent } from './registry'
|
|
8
|
+
import type { ToolbarState } from './state'
|
|
9
|
+
import type { AreaCascaderProps, AreaCascaderToolbarItem } from './types'
|
|
10
10
|
|
|
11
11
|
// 渲染地区级联选择器
|
|
12
12
|
export function renderAreaCascader(
|
|
@@ -4,9 +4,9 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
4
4
|
import { computed, markRaw, nextTick } from 'vue'
|
|
5
5
|
import type { ComponentPublicInstance, VNode } from 'vue'
|
|
6
6
|
|
|
7
|
-
import { getRegisteredComponent } from '
|
|
8
|
-
import type { ToolbarState } from '
|
|
9
|
-
import type { AutoCompleteToolbarItem, ToolbarItem } from '
|
|
7
|
+
import { getRegisteredComponent } from './registry'
|
|
8
|
+
import type { ToolbarState } from './state'
|
|
9
|
+
import type { AutoCompleteToolbarItem, ToolbarItem } from './types'
|
|
10
10
|
|
|
11
11
|
export function renderAutoComplete(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
12
12
|
const { key, events = {} } = item
|
|
@@ -4,8 +4,8 @@ import type { VoidFunction } from '@antsoo-lib/shared'
|
|
|
4
4
|
import { reactive } from 'vue'
|
|
5
5
|
import type { VNode } from 'vue'
|
|
6
6
|
|
|
7
|
-
import type { ToolbarState } from '
|
|
8
|
-
import type { ButtonToolbarItem, ToolbarItem } from '
|
|
7
|
+
import type { ToolbarState } from './state'
|
|
8
|
+
import type { ButtonToolbarItem, ToolbarItem } from './types'
|
|
9
9
|
|
|
10
10
|
// 按钮渲染函数
|
|
11
11
|
export function renderButton(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -4,9 +4,9 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
4
4
|
import { markRaw } from 'vue'
|
|
5
5
|
import type { VNode } from 'vue'
|
|
6
6
|
|
|
7
|
-
import { getRegisteredComponent } from '
|
|
8
|
-
import type { ToolbarState } from '
|
|
9
|
-
import type { CascaderToolbarItem } from '
|
|
7
|
+
import { getRegisteredComponent } from './registry'
|
|
8
|
+
import type { ToolbarState } from './state'
|
|
9
|
+
import type { CascaderToolbarItem } from './types'
|
|
10
10
|
|
|
11
11
|
// 渲染级联选择器
|
|
12
12
|
export function renderCascader(
|
|
@@ -6,8 +6,8 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
6
6
|
import { markRaw } from 'vue'
|
|
7
7
|
import type { VNode } from 'vue'
|
|
8
8
|
|
|
9
|
-
import type { ToolbarState } from '
|
|
10
|
-
import type { CheckboxToolbarItem, ToolbarItem } from '
|
|
9
|
+
import type { ToolbarState } from './state'
|
|
10
|
+
import type { CheckboxToolbarItem, ToolbarItem } from './types'
|
|
11
11
|
|
|
12
12
|
// 复选框渲染函数
|
|
13
13
|
export function renderCheckbox(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -6,8 +6,8 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
6
6
|
import { markRaw } from 'vue'
|
|
7
7
|
import type { VNode } from 'vue'
|
|
8
8
|
|
|
9
|
-
import type { ToolbarState } from '
|
|
10
|
-
import type { CheckboxGroupToolbarItem, ToolbarItem } from '
|
|
9
|
+
import type { ToolbarState } from './state'
|
|
10
|
+
import type { CheckboxGroupToolbarItem, ToolbarItem } from './types'
|
|
11
11
|
|
|
12
12
|
// 复选框组渲染函数
|
|
13
13
|
export function renderCheckboxGroup(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { VNode } from 'vue'
|
|
2
|
+
|
|
3
|
+
import type { ToolbarState } from './state'
|
|
4
|
+
import type { BaseToolbarItem, ToolbarItem } from './types'
|
|
5
|
+
|
|
6
|
+
// 自定义工具栏项目
|
|
7
|
+
export interface CustomToolbarItem extends BaseToolbarItem {
|
|
8
|
+
type: 'custom'
|
|
9
|
+
render: (toolbarState: ToolbarState) => VNode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 自定义渲染函数
|
|
13
|
+
export function renderCustom(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
14
|
+
const customItem = item as CustomToolbarItem
|
|
15
|
+
if (typeof customItem.render === 'function') {
|
|
16
|
+
return customItem.render(toolbarState)
|
|
17
|
+
}
|
|
18
|
+
return <div key={item.key}>{item.label || item.key || '未命名'}</div>
|
|
19
|
+
}
|
|
@@ -7,8 +7,8 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
7
7
|
import { markRaw, nextTick } from 'vue'
|
|
8
8
|
import type { ComponentPublicInstance, VNode } from 'vue'
|
|
9
9
|
|
|
10
|
-
import type { ToolbarState } from '
|
|
11
|
-
import type { DatePickerToolbarItem, ToolbarItem } from '
|
|
10
|
+
import type { ToolbarState } from './state'
|
|
11
|
+
import type { DatePickerToolbarItem, ToolbarItem } from './types'
|
|
12
12
|
|
|
13
13
|
// 日期选择器渲染函数
|
|
14
14
|
export function renderDatePicker(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -6,9 +6,9 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
6
6
|
import { markRaw, nextTick } from 'vue'
|
|
7
7
|
import type { ComponentPublicInstance, VNode } from 'vue'
|
|
8
8
|
|
|
9
|
-
import { renderSlotContent } from '
|
|
10
|
-
import type { ToolbarState } from '
|
|
11
|
-
import type { InputToolbarItem, ToolbarItem } from '
|
|
9
|
+
import { renderSlotContent } from './helper'
|
|
10
|
+
import type { ToolbarState } from './state'
|
|
11
|
+
import type { InputToolbarItem, ToolbarItem } from './types'
|
|
12
12
|
|
|
13
13
|
// 输入框渲染函数
|
|
14
14
|
export function renderInput(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -5,9 +5,9 @@ import { markRaw } from 'vue'
|
|
|
5
5
|
import type { ExtractPropTypes, VNode } from 'vue'
|
|
6
6
|
|
|
7
7
|
import { rendererMap } from '.'
|
|
8
|
-
import { validateInputGroupConfig } from '
|
|
9
|
-
import type { ToolbarState } from '
|
|
10
|
-
import type { InputGroupPropsLike, InputGroupToolbarItem, ToolbarItem } from '
|
|
8
|
+
import { validateInputGroupConfig } from './helper'
|
|
9
|
+
import type { ToolbarState } from './state'
|
|
10
|
+
import type { InputGroupPropsLike, InputGroupToolbarItem, ToolbarItem } from './types'
|
|
11
11
|
|
|
12
12
|
// Input.Group 渲染函数
|
|
13
13
|
export function renderInputGroup(
|
|
@@ -6,9 +6,9 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
6
6
|
import { markRaw, nextTick } from 'vue'
|
|
7
7
|
import type { ComponentPublicInstance, VNode } from 'vue'
|
|
8
8
|
|
|
9
|
-
import { getInputNumberFocusState, renderSlotContent } from '
|
|
10
|
-
import type { ToolbarState } from '
|
|
11
|
-
import type { InputNumberToolbarItem, ToolbarItem } from '
|
|
9
|
+
import { getInputNumberFocusState, renderSlotContent } from './helper'
|
|
10
|
+
import type { ToolbarState } from './state'
|
|
11
|
+
import type { InputNumberToolbarItem, ToolbarItem } from './types'
|
|
12
12
|
|
|
13
13
|
// 数字输入框渲染函数
|
|
14
14
|
export function renderInputNumber(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -6,9 +6,9 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
6
6
|
import { markRaw } from 'vue'
|
|
7
7
|
import type { VNode } from 'vue'
|
|
8
8
|
|
|
9
|
-
import { renderSlotContent } from '
|
|
10
|
-
import type { ToolbarState } from '
|
|
11
|
-
import type { InputPasswordToolbarItem, ToolbarItem } from '
|
|
9
|
+
import { renderSlotContent } from './helper'
|
|
10
|
+
import type { ToolbarState } from './state'
|
|
11
|
+
import type { InputPasswordToolbarItem, ToolbarItem } from './types'
|
|
12
12
|
|
|
13
13
|
export function renderInputPassword(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
14
14
|
const inputItem = item as InputPasswordToolbarItem
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Form, Input } from '@antsoo-lib/components'
|
|
2
|
+
import type { AnyObject } from '@antsoo-lib/shared'
|
|
3
|
+
|
|
4
|
+
import { defineComponent, h, markRaw } from 'vue'
|
|
5
|
+
import type { VNode } from 'vue'
|
|
6
|
+
|
|
7
|
+
import type { ToolbarState } from './state'
|
|
8
|
+
import type { InputRangeToolbarItem, ToolbarItem } from './types'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* InputRange 业务包装组件
|
|
12
|
+
* @description 统一处理 CoreForm 下 key/attr 映射、事件回调与校验触发
|
|
13
|
+
*/
|
|
14
|
+
const InputRangeWrapper = defineComponent({
|
|
15
|
+
name: 'InputRangeWrapper',
|
|
16
|
+
props: {
|
|
17
|
+
item: {
|
|
18
|
+
type: Object,
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
toolbarState: {
|
|
22
|
+
type: Object,
|
|
23
|
+
required: true,
|
|
24
|
+
},
|
|
25
|
+
formValues: {
|
|
26
|
+
type: Object,
|
|
27
|
+
required: false,
|
|
28
|
+
default: undefined,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
setup(props) {
|
|
32
|
+
const formItemContext = Form.useInjectFormItemContext()
|
|
33
|
+
|
|
34
|
+
return (): VNode => {
|
|
35
|
+
const inputRangeItem = props.item as InputRangeToolbarItem
|
|
36
|
+
const toolbarState = props.toolbarState as ToolbarState
|
|
37
|
+
const formValues = props.formValues as AnyObject | undefined
|
|
38
|
+
const attr = (inputRangeItem as AnyObject).attr
|
|
39
|
+
const allowClear = Boolean((inputRangeItem.props as AnyObject)?.allowClear)
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 解析区间值
|
|
43
|
+
* @description attr 模式优先取 formValues,回退到 toolbarState
|
|
44
|
+
*/
|
|
45
|
+
const getRangeValue = (): [string, string] => {
|
|
46
|
+
if (formValues && Array.isArray(attr) && attr.length >= 2) {
|
|
47
|
+
const [startKey, endKey] = attr as [string, string]
|
|
48
|
+
const start = formValues[startKey]
|
|
49
|
+
const end = formValues[endKey]
|
|
50
|
+
return [start != null ? String(start) : '', end != null ? String(end) : '']
|
|
51
|
+
}
|
|
52
|
+
const stateValue = toolbarState.getValue(inputRangeItem.key || '')
|
|
53
|
+
if (Array.isArray(stateValue)) {
|
|
54
|
+
const [start, end] = stateValue
|
|
55
|
+
return [start != null ? String(start) : '', end != null ? String(end) : '']
|
|
56
|
+
}
|
|
57
|
+
return ['', '']
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 同步区间值并触发外部事件
|
|
62
|
+
*/
|
|
63
|
+
const handleRangeChange = (value: [string, string]) => {
|
|
64
|
+
if (!formValues || !Array.isArray(attr)) {
|
|
65
|
+
toolbarState.setValue(inputRangeItem.key || '', value)
|
|
66
|
+
}
|
|
67
|
+
const allValues = toolbarState.getAllValues()
|
|
68
|
+
inputRangeItem.events?.['onUpdate:value']?.(value, allValues, toolbarState)
|
|
69
|
+
inputRangeItem.events?.onChange?.(value, allValues, toolbarState)
|
|
70
|
+
formItemContext.onFieldChange()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const [startValue, endValue] = getRangeValue()
|
|
74
|
+
const Comp = markRaw(Input)
|
|
75
|
+
|
|
76
|
+
const startInput = (
|
|
77
|
+
<Comp
|
|
78
|
+
{...inputRangeItem.props?.startProps}
|
|
79
|
+
value={startValue}
|
|
80
|
+
allowClear={Boolean(
|
|
81
|
+
(inputRangeItem.props as AnyObject)?.startProps?.allowClear ?? allowClear,
|
|
82
|
+
)}
|
|
83
|
+
placeholder={inputRangeItem.props?.startPlaceholder || '起始值'}
|
|
84
|
+
onUpdate:value={(value: string) => {
|
|
85
|
+
const [, currentEnd] = getRangeValue()
|
|
86
|
+
handleRangeChange([value, currentEnd])
|
|
87
|
+
}}
|
|
88
|
+
onChange={(event: Event) => {
|
|
89
|
+
const target = event.target as HTMLInputElement
|
|
90
|
+
const [, currentEnd] = getRangeValue()
|
|
91
|
+
handleRangeChange([target.value, currentEnd])
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
const endInput = (
|
|
97
|
+
<Comp
|
|
98
|
+
{...inputRangeItem.props?.endProps}
|
|
99
|
+
value={endValue}
|
|
100
|
+
allowClear={Boolean(
|
|
101
|
+
(inputRangeItem.props as AnyObject)?.endProps?.allowClear ?? allowClear,
|
|
102
|
+
)}
|
|
103
|
+
placeholder={inputRangeItem.props?.endPlaceholder || '结束值'}
|
|
104
|
+
onUpdate:value={(value: string) => {
|
|
105
|
+
const [currentStart] = getRangeValue()
|
|
106
|
+
handleRangeChange([currentStart, value])
|
|
107
|
+
}}
|
|
108
|
+
onChange={(event: Event) => {
|
|
109
|
+
const target = event.target as HTMLInputElement
|
|
110
|
+
const [currentStart] = getRangeValue()
|
|
111
|
+
handleRangeChange([currentStart, target.value])
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
const content = (
|
|
117
|
+
<div
|
|
118
|
+
key={inputRangeItem.key}
|
|
119
|
+
style={{
|
|
120
|
+
display: 'flex',
|
|
121
|
+
alignItems: 'center',
|
|
122
|
+
...(inputRangeItem as AnyObject).containerStyle,
|
|
123
|
+
}}
|
|
124
|
+
>
|
|
125
|
+
{startInput}
|
|
126
|
+
<span style={{ margin: '0 8px', color: '#999' }}>
|
|
127
|
+
{inputRangeItem.props?.separator || '至'}
|
|
128
|
+
</span>
|
|
129
|
+
{endInput}
|
|
130
|
+
</div>
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
return h(Form.ItemRest, null, {
|
|
134
|
+
default: () => content,
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 渲染 InputRange
|
|
142
|
+
* @description 透传 toolbarState 与 formValues,供 CoreForm 统一状态管理
|
|
143
|
+
*/
|
|
144
|
+
export function renderInputRange(
|
|
145
|
+
item: ToolbarItem,
|
|
146
|
+
toolbarState: ToolbarState,
|
|
147
|
+
formValues?: AnyObject,
|
|
148
|
+
): VNode {
|
|
149
|
+
return h(InputRangeWrapper, {
|
|
150
|
+
item,
|
|
151
|
+
toolbarState,
|
|
152
|
+
formValues,
|
|
153
|
+
})
|
|
154
|
+
}
|
|
@@ -6,8 +6,8 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
6
6
|
import { markRaw } from 'vue'
|
|
7
7
|
import type { VNode } from 'vue'
|
|
8
8
|
|
|
9
|
-
import type { ToolbarState } from '
|
|
10
|
-
import type { RadioGroupToolbarItem, ToolbarItem } from '
|
|
9
|
+
import type { ToolbarState } from './state'
|
|
10
|
+
import type { RadioGroupToolbarItem, ToolbarItem } from './types'
|
|
11
11
|
|
|
12
12
|
// 单选框渲染函数
|
|
13
13
|
export function renderRadioGroup(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -6,8 +6,8 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
6
6
|
import { computed, markRaw } from 'vue'
|
|
7
7
|
import type { VNode } from 'vue'
|
|
8
8
|
|
|
9
|
-
import type { ToolbarState } from '
|
|
10
|
-
import type { SelectToolbarItem, ToolbarItem } from '
|
|
9
|
+
import type { ToolbarState } from './state'
|
|
10
|
+
import type { SelectToolbarItem, ToolbarItem } from './types'
|
|
11
11
|
|
|
12
12
|
// 选择框渲染函数
|
|
13
13
|
export function renderSelect(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -4,9 +4,9 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
4
4
|
import { computed, markRaw, nextTick } from 'vue'
|
|
5
5
|
import type { ComponentPublicInstance, VNode } from 'vue'
|
|
6
6
|
|
|
7
|
-
import { getRegisteredComponent } from '
|
|
8
|
-
import type { ToolbarState } from '
|
|
9
|
-
import type { SselectPageProps, SselectPageToolbarItem, ToolbarItem } from '
|
|
7
|
+
import { getRegisteredComponent } from './registry'
|
|
8
|
+
import type { ToolbarState } from './state'
|
|
9
|
+
import type { SselectPageProps, SselectPageToolbarItem, ToolbarItem } from './types'
|
|
10
10
|
|
|
11
11
|
export function renderSselectPage(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
12
12
|
const sselectPageItem = item as SselectPageToolbarItem
|
|
@@ -6,8 +6,8 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
6
6
|
import { markRaw } from 'vue'
|
|
7
7
|
import type { VNode } from 'vue'
|
|
8
8
|
|
|
9
|
-
import type { ToolbarState } from '
|
|
10
|
-
import type { SwitchToolbarItem, ToolbarItem } from '
|
|
9
|
+
import type { ToolbarState } from './state'
|
|
10
|
+
import type { SwitchToolbarItem, ToolbarItem } from './types'
|
|
11
11
|
|
|
12
12
|
// 开关渲染函数
|
|
13
13
|
export function renderSwitch(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { Tree } from '@antsoo-lib/components'
|
|
2
|
+
import type { AnyObject } from '@antsoo-lib/shared'
|
|
3
|
+
import { isFunction } from '@antsoo-lib/utils'
|
|
4
|
+
|
|
5
|
+
import { markRaw } from 'vue'
|
|
6
|
+
import type { VNode } from 'vue'
|
|
7
|
+
|
|
8
|
+
import type { ToolbarState } from './state'
|
|
9
|
+
import type { ToolbarItem, TreeToolbarItem } from './types'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 按工具栏项缓存树展开状态,避免表单重渲染后丢失展开态
|
|
13
|
+
*/
|
|
14
|
+
const treeExpandedKeysCache = new WeakMap<object, any[]>()
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 解析树组件选中值
|
|
18
|
+
* @description 优先级:formValues -> toolbarState -> props.checkedKeys
|
|
19
|
+
*/
|
|
20
|
+
function resolveTreeCheckedKeys(
|
|
21
|
+
key: string | undefined,
|
|
22
|
+
props: AnyObject,
|
|
23
|
+
toolbarState: ToolbarState,
|
|
24
|
+
formValues?: AnyObject,
|
|
25
|
+
): any[] {
|
|
26
|
+
if (key && formValues && formValues[key] !== undefined) {
|
|
27
|
+
return formValues[key] ?? []
|
|
28
|
+
}
|
|
29
|
+
if (key) {
|
|
30
|
+
const stateValue = toolbarState.getValue(key)
|
|
31
|
+
if (stateValue !== undefined) {
|
|
32
|
+
return stateValue ?? []
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const propValue = props?.checkedKeys
|
|
36
|
+
if (isFunction(propValue)) {
|
|
37
|
+
return propValue(toolbarState.getAllValues(), toolbarState) ?? []
|
|
38
|
+
}
|
|
39
|
+
return propValue ?? []
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 标准化树勾选值
|
|
44
|
+
* @description 兼容 strict 模式下 { checked, halfChecked } 结构
|
|
45
|
+
*/
|
|
46
|
+
function normalizeCheckedKeys(value: any): any {
|
|
47
|
+
if (Array.isArray(value)) return value
|
|
48
|
+
if (value && typeof value === 'object' && Array.isArray(value.checked)) return value.checked
|
|
49
|
+
return value
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 渲染树控件
|
|
54
|
+
* @description 提供 checkedKeys 与 expandedKeys 的同步能力,并桥接到 CoreForm 事件系统
|
|
55
|
+
*/
|
|
56
|
+
export function renderTree(
|
|
57
|
+
item: ToolbarItem,
|
|
58
|
+
toolbarState: ToolbarState,
|
|
59
|
+
formValues?: AnyObject,
|
|
60
|
+
): VNode {
|
|
61
|
+
const treeItem = item as TreeToolbarItem
|
|
62
|
+
const { key, events = {} } = treeItem
|
|
63
|
+
const { props = {}, disabled } = treeItem
|
|
64
|
+
const finalDisabled = isFunction(disabled)
|
|
65
|
+
? disabled(toolbarState.getAllValues(), toolbarState)
|
|
66
|
+
: disabled
|
|
67
|
+
|
|
68
|
+
const { treeData: originalTreeData, ...otherProps } = props as AnyObject
|
|
69
|
+
const treeData = (() => {
|
|
70
|
+
if (isFunction(originalTreeData)) {
|
|
71
|
+
return originalTreeData(toolbarState.getAllValues())
|
|
72
|
+
}
|
|
73
|
+
if (originalTreeData && typeof originalTreeData === 'object' && 'value' in originalTreeData) {
|
|
74
|
+
return (originalTreeData as AnyObject).value || []
|
|
75
|
+
}
|
|
76
|
+
return originalTreeData || []
|
|
77
|
+
})()
|
|
78
|
+
|
|
79
|
+
const allValues = () => toolbarState.getAllValues()
|
|
80
|
+
const cachedExpanded = treeExpandedKeysCache.get(treeItem as object)
|
|
81
|
+
const expandedKeys = (props as AnyObject).expandedKeys ?? cachedExpanded
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 同步勾选键值
|
|
85
|
+
*/
|
|
86
|
+
const syncCheckedKeys = (value: any) => {
|
|
87
|
+
const normalized = normalizeCheckedKeys(value)
|
|
88
|
+
if (key) {
|
|
89
|
+
toolbarState.setValue(key, normalized)
|
|
90
|
+
}
|
|
91
|
+
const values = allValues()
|
|
92
|
+
events['onUpdate:checkedKeys']?.(normalized, values, toolbarState)
|
|
93
|
+
;(events as AnyObject)['onUpdate:value']?.(normalized, values, toolbarState)
|
|
94
|
+
events.onChange?.(normalized, values, toolbarState)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 同步展开键值
|
|
99
|
+
*/
|
|
100
|
+
const syncExpandedKeys = (value: any) => {
|
|
101
|
+
treeExpandedKeysCache.set(treeItem as object, value)
|
|
102
|
+
const values = allValues()
|
|
103
|
+
;(events as AnyObject)['onUpdate:expandedKeys']?.(value, values, toolbarState)
|
|
104
|
+
;(events as AnyObject).onExpand?.(value, values, toolbarState)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const Comp = markRaw(Tree)
|
|
108
|
+
return (
|
|
109
|
+
<div
|
|
110
|
+
style={{
|
|
111
|
+
border: '1px solid rgba(228, 229, 235, 1)',
|
|
112
|
+
borderRadius: '6px',
|
|
113
|
+
padding: '8px 0 8px 8px',
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
<Comp
|
|
117
|
+
key={key}
|
|
118
|
+
checkedKeys={resolveTreeCheckedKeys(key, props as AnyObject, toolbarState, formValues)}
|
|
119
|
+
treeData={treeData}
|
|
120
|
+
disabled={finalDisabled}
|
|
121
|
+
{...(expandedKeys !== undefined ? { expandedKeys } : {})}
|
|
122
|
+
{...otherProps}
|
|
123
|
+
onUpdate:checkedKeys={syncCheckedKeys}
|
|
124
|
+
onCheck={(checked: any, info: any) => {
|
|
125
|
+
syncCheckedKeys(checked)
|
|
126
|
+
;(events as AnyObject).onCheck?.(checked, info, allValues(), toolbarState)
|
|
127
|
+
}}
|
|
128
|
+
onUpdate:expandedKeys={syncExpandedKeys}
|
|
129
|
+
onExpand={(keys: any, info: any) => {
|
|
130
|
+
syncExpandedKeys(keys)
|
|
131
|
+
;(events as AnyObject).onExpand?.(keys, info, allValues(), toolbarState)
|
|
132
|
+
}}
|
|
133
|
+
/>
|
|
134
|
+
</div>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
@@ -5,8 +5,8 @@ import { isFunction } from '@antsoo-lib/utils'
|
|
|
5
5
|
import { computed, markRaw } from 'vue'
|
|
6
6
|
import type { VNode } from 'vue'
|
|
7
7
|
|
|
8
|
-
import type { ToolbarState } from '
|
|
9
|
-
import type { ToolbarItem, TreeSelectToolbarItem } from '
|
|
8
|
+
import type { ToolbarState } from './state'
|
|
9
|
+
import type { ToolbarItem, TreeSelectToolbarItem } from './types'
|
|
10
10
|
|
|
11
11
|
// 树选择器渲染函数
|
|
12
12
|
export function renderTreeSelect(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { UploadFile } from '@antsoo-lib/components'
|
|
2
|
+
import type { AnyObject } from '@antsoo-lib/shared'
|
|
2
3
|
import { isFunction } from '@antsoo-lib/utils'
|
|
3
4
|
|
|
4
5
|
import { markRaw } from 'vue'
|
|
5
6
|
import type { VNode } from 'vue'
|
|
6
7
|
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import type { ToolbarState } from '../state'
|
|
11
|
-
import type { ToolbarItem, UploadToolbarItem } from '../types'
|
|
8
|
+
import { getRegisteredComponent } from './registry'
|
|
9
|
+
import type { ToolbarState } from './state'
|
|
10
|
+
import type { ToolbarItem, UploadToolbarItem } from './types'
|
|
12
11
|
|
|
13
12
|
// 上传渲染函数
|
|
14
13
|
export function renderUpload(item: ToolbarItem, toolbarState: ToolbarState): VNode {
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { Button, Dropdown, Menu, MenuItem } from '@antsoo-lib/components'
|
|
1
|
+
import { Button, Dropdown, Menu, MenuItem, Select } from '@antsoo-lib/components'
|
|
2
2
|
import { DownOutlined, UpOutlined } from '@antsoo-lib/icons'
|
|
3
3
|
import { isEmpty, isFunction } from '@antsoo-lib/utils'
|
|
4
4
|
|
|
5
|
-
import { markRaw, ref } from 'vue'
|
|
5
|
+
import { markRaw, nextTick, ref } from 'vue'
|
|
6
6
|
import type { VNode } from 'vue'
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import { rendererMap } from './renderers'
|
|
10
|
-
import { useToolbarState } from './state'
|
|
8
|
+
import { rendererMap } from '.'
|
|
11
9
|
import type { ToolbarState } from './state'
|
|
12
|
-
import type { ToolbarConfig, ToolbarItem } from './types'
|
|
10
|
+
import type { InputGroupToolbarItem, SlotConfig, ToolbarConfig, ToolbarItem } from './types'
|
|
13
11
|
|
|
14
12
|
// 工具栏渲染函数
|
|
15
13
|
export function renderToolbar(
|
|
@@ -139,6 +137,85 @@ export function renderToolbar(
|
|
|
139
137
|
return renderedExtendShow.filter(Boolean) as VNode[]
|
|
140
138
|
}
|
|
141
139
|
|
|
142
|
-
|
|
143
|
-
export
|
|
144
|
-
|
|
140
|
+
// 渲染插槽内容的辅助函数
|
|
141
|
+
export function renderSlotContent(
|
|
142
|
+
slotConfig: SlotConfig,
|
|
143
|
+
toolbarState: ToolbarState,
|
|
144
|
+
): VNode | undefined {
|
|
145
|
+
if (!slotConfig?.content) return undefined
|
|
146
|
+
|
|
147
|
+
// 如果是函数,直接调用
|
|
148
|
+
if (typeof slotConfig.content === 'function') {
|
|
149
|
+
return slotConfig.content(toolbarState)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 如果是组件配置对象
|
|
153
|
+
const { component, key, props = {}, events = {}, options = [] } = slotConfig.content
|
|
154
|
+
const allValues = toolbarState.getAllValues()
|
|
155
|
+
|
|
156
|
+
// 处理事件,注入工具栏状态
|
|
157
|
+
const processedEvents: Record<string, VoidFunction> = {}
|
|
158
|
+
Object.entries(events).forEach(([eventName, handler]) => {
|
|
159
|
+
if (eventName === 'onChange') {
|
|
160
|
+
// 对于 onChange 事件,使用 nextTick 确保在下一个 tick 中执行外部处理函数
|
|
161
|
+
processedEvents[eventName] = (...args: any[]) => {
|
|
162
|
+
nextTick(() => {
|
|
163
|
+
handler(...args, allValues, toolbarState)
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
// 其他事件保持原有逻辑
|
|
168
|
+
processedEvents[eventName] = (...args: any[]) => {
|
|
169
|
+
handler(...args, allValues, toolbarState)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
const value = allValues[key]
|
|
175
|
+
|
|
176
|
+
// 如果是Select组件且有options,添加选项子节点
|
|
177
|
+
if (component === Select && options.length > 0) {
|
|
178
|
+
const Comp = markRaw(component)
|
|
179
|
+
return (
|
|
180
|
+
<Comp value={value ?? ''} {...props} {...processedEvents}>
|
|
181
|
+
{options.map((option: any) => (
|
|
182
|
+
<Select.Option key={option.value} value={option.value}>
|
|
183
|
+
{option.label}
|
|
184
|
+
</Select.Option>
|
|
185
|
+
))}
|
|
186
|
+
</Comp>
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 普通组件渲染
|
|
191
|
+
const Comp = markRaw(component)
|
|
192
|
+
return <Comp value={value ?? ''} {...props} {...processedEvents} />
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function validateInputGroupConfig(cfg: InputGroupToolbarItem): {
|
|
196
|
+
valid: boolean
|
|
197
|
+
errors?: string[]
|
|
198
|
+
} {
|
|
199
|
+
const errors: string[] = []
|
|
200
|
+
if (!cfg) errors.push('inputGroup config is required')
|
|
201
|
+
if (cfg.type !== 'inputGroup') errors.push("type must be 'inputGroup'")
|
|
202
|
+
if (!Array.isArray(cfg.children) || cfg.children.length === 0)
|
|
203
|
+
errors.push('children must be a non-empty array')
|
|
204
|
+
// 校验子项 key 唯一性
|
|
205
|
+
const keys = (cfg.children || []).map((c) => c.key).filter(Boolean) as string[]
|
|
206
|
+
const dup = keys.filter((k, i) => keys.indexOf(k) !== i)
|
|
207
|
+
if (dup.length) errors.push(`duplicate child keys: ${Array.from(new Set(dup)).join(',')}`)
|
|
208
|
+
return { valid: errors.length === 0, errors: errors.length ? errors : undefined }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// InputNumber 的焦点态只用于“显示逻辑(失焦补零)”,不属于业务值:
|
|
212
|
+
// - 不写入 ToolbarState,避免污染 getAllValues() 及其下游(按钮事件、联动禁用、外部 expose、deep watch 等)
|
|
213
|
+
// - 采用 WeakMap:当 ToolbarState 实例被销毁且无引用时,对应缓存可被 GC 自动回收
|
|
214
|
+
const inputNumberFocusState = new WeakMap<ToolbarState, Map<string, boolean>>()
|
|
215
|
+
export function getInputNumberFocusState(toolbarState: ToolbarState) {
|
|
216
|
+
const existing = inputNumberFocusState.get(toolbarState)
|
|
217
|
+
if (existing) return existing
|
|
218
|
+
const next = new Map<string, boolean>()
|
|
219
|
+
inputNumberFocusState.set(toolbarState, next)
|
|
220
|
+
return next
|
|
221
|
+
}
|