@antsoo-lib/core 1.0.17 → 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.
Files changed (77) hide show
  1. package/.turbo/turbo-build.log +0 -0
  2. package/CHANGELOG.md +16 -0
  3. package/dist/core.css +1 -1
  4. package/dist/index.cjs +4 -8
  5. package/dist/index.js +2367 -49071
  6. package/dist/types/BaseSearch/index.d.ts +59 -0
  7. package/dist/types/{core/src/BaseTable → BaseTable}/index.d.ts +20 -6
  8. package/dist/types/Form/CoreForm.d.ts +82 -0
  9. package/dist/types/Form/types.d.ts +57 -0
  10. package/dist/types/SSelectPage/index.d.ts +102 -0
  11. package/dist/types/index.d.ts +13 -0
  12. package/dist/types/{core/src/BaseTable/renderers → render}/AreaCascader.d.ts +3 -3
  13. package/dist/types/{core/src/BaseTable/renderers → render}/AutoComplete.d.ts +2 -2
  14. package/dist/types/{core/src/BaseTable/renderers → render}/Button.d.ts +2 -2
  15. package/dist/types/{core/src/BaseTable/renderers → render}/Cascader.d.ts +3 -3
  16. package/dist/types/{core/src/BaseTable/renderers → render}/Checkbox.d.ts +2 -2
  17. package/dist/types/{core/src/BaseTable/renderers → render}/CheckboxGroup.d.ts +2 -2
  18. package/dist/types/render/Custom.d.ts +8 -0
  19. package/dist/types/{core/src/BaseTable/renderers → render}/DatePicker.d.ts +2 -2
  20. package/dist/types/{core/src/BaseTable/renderers → render}/Input.d.ts +2 -2
  21. package/dist/types/{core/src/BaseTable/renderers → render}/InputGroup.d.ts +3 -3
  22. package/dist/types/{core/src/BaseTable/renderers → render}/InputNumber.d.ts +2 -2
  23. package/dist/types/{core/src/BaseTable/renderers → render}/InputPassword.d.ts +2 -2
  24. package/dist/types/render/InputRange.d.ts +9 -0
  25. package/dist/types/{core/src/BaseTable/renderers → render}/RadioGroup.d.ts +2 -2
  26. package/dist/types/{core/src/BaseTable/renderers → render}/Select.d.ts +2 -2
  27. package/dist/types/{core/src/BaseTable/renderers → render}/SselectPage.d.ts +2 -2
  28. package/dist/types/{core/src/BaseTable/renderers → render}/Switch.d.ts +2 -2
  29. package/dist/types/render/Tree.d.ts +9 -0
  30. package/dist/types/{core/src/BaseTable/renderers → render}/TreeSelect.d.ts +2 -2
  31. package/dist/types/{core/src/BaseTable/renderers → render}/Upload.d.ts +2 -2
  32. package/dist/types/{core/src/BaseTable/helpers.d.ts → render/helper.d.ts} +2 -1
  33. package/dist/types/{core/src/BaseTable/renderers → render}/index.d.ts +24 -5
  34. package/dist/types/{core/src/BaseTable → render}/types.d.ts +48 -4
  35. package/dist/types/utils/attrMapping.d.ts +26 -0
  36. package/package.json +12 -15
  37. package/src/BaseSearch/index.vue +371 -0
  38. package/src/BaseTable/index.vue +48 -22
  39. package/src/Form/CoreForm.vue +782 -0
  40. package/src/Form/types.ts +86 -0
  41. package/src/SSelectPage/index.vue +607 -0
  42. package/src/index.ts +15 -1
  43. package/src/{BaseTable/renderers → render}/AreaCascader.tsx +3 -3
  44. package/src/{BaseTable/renderers → render}/AutoComplete.tsx +3 -3
  45. package/src/{BaseTable/renderers → render}/Button.tsx +2 -2
  46. package/src/{BaseTable/renderers → render}/Cascader.tsx +3 -3
  47. package/src/{BaseTable/renderers → render}/Checkbox.tsx +2 -2
  48. package/src/{BaseTable/renderers → render}/CheckboxGroup.tsx +2 -2
  49. package/src/render/Custom.tsx +19 -0
  50. package/src/{BaseTable/renderers → render}/DatePicker.tsx +2 -2
  51. package/src/{BaseTable/renderers → render}/Input.tsx +3 -3
  52. package/src/{BaseTable/renderers → render}/InputGroup.tsx +3 -3
  53. package/src/{BaseTable/renderers → render}/InputNumber.tsx +3 -3
  54. package/src/{BaseTable/renderers → render}/InputPassword.tsx +3 -3
  55. package/src/render/InputRange.tsx +154 -0
  56. package/src/{BaseTable/renderers → render}/RadioGroup.tsx +2 -2
  57. package/src/{BaseTable/renderers → render}/Select.tsx +2 -2
  58. package/src/{BaseTable/renderers → render}/SselectPage.tsx +3 -3
  59. package/src/{BaseTable/renderers → render}/Switch.tsx +2 -2
  60. package/src/render/Tree.tsx +136 -0
  61. package/src/{BaseTable/renderers → render}/TreeSelect.tsx +2 -2
  62. package/src/{BaseTable/renderers → render}/Upload.tsx +4 -5
  63. package/src/{BaseTable/utils.tsx → render/helper.tsx} +86 -9
  64. package/src/{BaseTable/renderers → render}/index.ts +45 -4
  65. package/src/{BaseTable → render}/types.ts +62 -2
  66. package/src/utils/attrMapping.ts +106 -0
  67. package/vite.config.ts +15 -2
  68. package/dist/types/core/index.d.ts +0 -6
  69. package/dist/types/core/src/BaseTable/utils.d.ts +0 -8
  70. package/dist/types/core/src/index.d.ts +0 -2
  71. package/index.css +0 -2
  72. package/index.ts +0 -21
  73. package/src/BaseTable/helpers.tsx +0 -91
  74. /package/dist/types/{core/src/BaseTable → render}/registry.d.ts +0 -0
  75. /package/dist/types/{core/src/BaseTable → render}/state.d.ts +0 -0
  76. /package/src/{BaseTable → render}/registry.ts +0 -0
  77. /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 '../registry'
8
- import type { ToolbarState } from '../state'
9
- import type { AreaCascaderProps, AreaCascaderToolbarItem } from '../types'
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 '../registry'
8
- import type { ToolbarState } from '../state'
9
- import type { AutoCompleteToolbarItem, ToolbarItem } from '../types'
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 '../state'
8
- import type { ButtonToolbarItem, ToolbarItem } from '../types'
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 '../registry'
8
- import type { ToolbarState } from '../state'
9
- import type { CascaderToolbarItem } from '../types'
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 '../state'
10
- import type { CheckboxToolbarItem, ToolbarItem } from '../types'
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 '../state'
10
- import type { CheckboxGroupToolbarItem, ToolbarItem } from '../types'
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 '../state'
11
- import type { DatePickerToolbarItem, ToolbarItem } from '../types'
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 '../helpers'
10
- import type { ToolbarState } from '../state'
11
- import type { InputToolbarItem, ToolbarItem } from '../types'
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 '../helpers'
9
- import type { ToolbarState } from '../state'
10
- import type { InputGroupPropsLike, InputGroupToolbarItem, ToolbarItem } from '../types'
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 '../helpers'
10
- import type { ToolbarState } from '../state'
11
- import type { InputNumberToolbarItem, ToolbarItem } from '../types'
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 '../helpers'
10
- import type { ToolbarState } from '../state'
11
- import type { InputPasswordToolbarItem, ToolbarItem } from '../types'
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 '../state'
10
- import type { RadioGroupToolbarItem, ToolbarItem } from '../types'
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 '../state'
10
- import type { SelectToolbarItem, ToolbarItem } from '../types'
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 '../registry'
8
- import type { ToolbarState } from '../state'
9
- import type { SselectPageProps, SselectPageToolbarItem, ToolbarItem } from '../types'
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 '../state'
10
- import type { SwitchToolbarItem, ToolbarItem } from '../types'
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 '../state'
9
- import type { ToolbarItem, TreeSelectToolbarItem } from '../types'
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 type { AnyObject } from '@/packages/shared'
8
-
9
- import { getRegisteredComponent } from '../registry'
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 { registerBaseTableComponents } from './registry'
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
- export { registerBaseTableComponents, ToolbarState, useToolbarState }
143
- export * from './types'
144
- export * from './renderers'
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
+ }