@skyfox2000/webui 1.4.24 → 1.4.26

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyfox2000/webui",
3
- "version": "1.4.24",
3
+ "version": "1.4.26",
4
4
  "description": "后台前端通用组件定义",
5
5
  "type": "module",
6
6
  "keywords": [],
@@ -32,6 +32,22 @@ import Toolbar from './toolbar/index.vue';
32
32
  export { Toolbar };
33
33
  import Icontool from './toolbar/icontool.vue';
34
34
  export { Icontool };
35
+ import GroupTools from './toolbar/groupTools.vue';
36
+ export { GroupTools };
35
37
 
36
38
  import Tree from './tree/index.vue';
37
39
  export { Tree };
40
+
41
+ import ToolPanel from './toolpanel/index.vue';
42
+ export { ToolPanel };
43
+
44
+ // 导出ToolPanel相关类型
45
+ export type {
46
+ ToolPanelGroup,
47
+ DisplayMode,
48
+ PanelCollapsed,
49
+ ToolPanelConfig,
50
+ ToolPanelEvents,
51
+ ToolPanelProps,
52
+ DragConfig,
53
+ } from './toolpanel/types';
@@ -1,80 +1,35 @@
1
- <script setup lang="ts" generic="T">
1
+ <script setup lang="ts">
2
2
  import { Button, ToolIcon } from '../../common';
3
- import type { ButtonTool } from '@/typings/tools.d';
4
-
5
- /**
6
- * 工具组类型定义
7
- */
8
- export type GroupType = 'tools' | 'split' | 'space';
9
-
10
- /**
11
- * 扩展的工具定义,支持自定义组件
12
- */
13
- export interface ExtendedButtonTool extends ButtonTool {
14
- /**
15
- * 自定义组件
16
- */
17
- component?: any;
18
- /**
19
- * 组件属性
20
- */
21
- props?: Record<string, any>;
22
- }
23
-
24
- /**
25
- * 工具组定义
26
- */
27
- export interface ToolGroup {
28
- /**
29
- * 组类型
30
- * - tools: 工具组
31
- * - split: 竖线分割
32
- * - space: 空白区域
33
- */
34
- type: GroupType;
35
- /**
36
- * 工具列表,当type为tools时有效
37
- */
38
- tools?: ExtendedButtonTool[];
39
- /**
40
- * 空白区域宽度,当type为space时有效
41
- */
42
- width?: string;
43
- }
3
+ import { getToolVisible, getToolStatus, onToolClicked } from '@/utils/tools';
4
+ import type { ComponentTool, ToolGroup } from '@/typings/tools.d';
44
5
 
45
6
  defineProps<{
46
7
  /**
47
8
  * 分组工具配置
48
9
  */
49
10
  groupTools: ToolGroup[];
11
+ /**
12
+ * 统一样式类,应用于所有工具组
13
+ */
14
+ groupClass?: string;
50
15
  }>();
51
16
 
52
17
  /**
53
18
  * 处理工具点击事件
54
19
  */
55
- const onToolClick = (tool: ExtendedButtonTool) => {
56
- if (tool.click) {
57
- // 传入必要的参数,这里使用空对象作为占位符,实际使用时由外部传入
58
- tool.click({} as any, undefined as any, undefined as any);
20
+ const onToolClick = (tool: ComponentTool, group: ToolGroup) => {
21
+ // 切换模式:单选切换 - 直接修改 group.selected,外部通过监听数据变化来响应
22
+ if (group.mode === 'toggle') {
23
+ group.selected = group.selected === tool.key ? undefined : tool.key;
24
+ }
25
+
26
+ // 使用统一的工具点击处理
27
+ onToolClicked(tool);
28
+
29
+ // 如果工具有自定义点击方法,则执行
30
+ if (tool.click && typeof tool.click === 'function') {
31
+ (tool.click as any)(tool);
59
32
  }
60
- };
61
-
62
- /**
63
- * 判断工具是否可见
64
- */
65
- const isToolVisible = (tool: ExtendedButtonTool): boolean => {
66
- if (typeof tool.visible === 'boolean') return tool.visible;
67
- if (typeof tool.visible === 'function') return tool.visible({} as any);
68
- return true;
69
- };
70
-
71
- /**
72
- * 判断工具是否禁用
73
- */
74
- const isToolDisabled = (tool: ExtendedButtonTool): boolean => {
75
- if (typeof tool.disabled === 'boolean') return tool.disabled;
76
- if (typeof tool.disabled === 'function') return tool.disabled({} as any);
77
- return false;
78
33
  };
79
34
  </script>
80
35
 
@@ -82,26 +37,61 @@ const isToolDisabled = (tool: ExtendedButtonTool): boolean => {
82
37
  <div class="flex items-center">
83
38
  <template v-for="(group, groupIndex) in groupTools" :key="groupIndex">
84
39
  <!-- 工具组 -->
85
- <div v-if="group.type === 'tools'" class="inline-flex [&>button]:ml-[-1px] first:[&>button]:ml-0">
40
+ <div v-if="group.type === 'tools'" :class="[
41
+ 'inline-flex',
42
+ groupClass || '',
43
+ group.class || ''
44
+ ]">
86
45
  <template v-for="(tool, toolIndex) in group.tools" :key="tool.key">
87
- <Button v-if="isToolVisible(tool) && !tool.children" :class="[
88
- 'px-[8px] py-[2px] relative border-[#ccc] bg-[#fcfcfc] rounded-none text-[#666] hover:z-10',
89
- toolIndex === 0 ? 'rounded-l-[5px]' : '',
46
+ <Button v-if="getToolVisible(tool) && !tool.children && !tool.component" :class="[
47
+ group.mode === 'toggle' && group.selected === tool.key
48
+ ? 'px-[8px] py-[2px] relative border-[#1890ff] bg-[#1890ff] text-white rounded-none'
49
+ : 'px-[8px] py-[2px] relative border-[#ccc] bg-[#fcfcfc] rounded-none text-[#666]',
50
+ 'hover:z-10 hover:border-[#666]',
51
+ toolIndex === 0 ? 'rounded-l-[5px] ml-0' : '-ml-[1px]',
90
52
  toolIndex === (group.tools?.length || 0) - 1 ? 'rounded-r-[5px]' : '',
91
- tool.class || ''
92
- ]" :type="tool.type" :danger="tool.danger" :disabled="isToolDisabled(tool)" :tiptext="tool.label"
93
- @click="onToolClick(tool)">
94
- <template v-if="tool.icon">
95
- <ToolIcon :icon="tool.icon" class="w-[18px] h-[18.5px]" clickable />
53
+ tool.class || '',
54
+ tool.display === 'icon' ? 'px-[6px]' : '',
55
+ tool.display === 'text' ? 'px-[8px]' : ''
56
+ ]" :type="tool.type" :danger="tool.danger" :disabled="getToolStatus(tool)" :tiptext="tool.label"
57
+ v-bind="tool.props" @click="onToolClick(tool, group)">
58
+ <!-- 仅显示图标 -->
59
+ <template v-if="tool.display === 'icon' && tool.icon">
60
+ <ToolIcon :icon="tool.icon" class="w-[18px] h-[18.5px]" :class="tool.iconClass"
61
+ v-bind="tool.iconProps" clickable />
96
62
  </template>
97
- <template v-if="tool.label">
63
+ <!-- 仅显示文字 -->
64
+ <template v-else-if="tool.display === 'text' && tool.label">
98
65
  {{ tool.label }}
99
66
  </template>
67
+ <!-- 同时显示图标和文字 -->
68
+ <template v-else>
69
+ <template v-if="tool.icon">
70
+ <ToolIcon :icon="tool.icon" class="w-[18px] h-[18.5px] mr-[4px]" :class="tool.iconClass"
71
+ v-bind="tool.iconProps" clickable />
72
+ </template>
73
+ <template v-if="tool.label">
74
+ {{ tool.label }}
75
+ </template>
76
+ </template>
100
77
  </Button>
101
78
 
102
79
  <!-- 自定义组件 -->
103
- <component v-else-if="tool.component" :is="tool.component" v-bind="tool.props"
104
- @click="onToolClick(tool)" />
80
+ <div v-else-if="tool.component" :class="[
81
+ group.mode === 'toggle' && group.selected === tool.key
82
+ ? 'p-0 relative border-[#1890ff] bg-[#1890ff] text-white rounded-none flex justify-center items-center'
83
+ : 'p-0 relative border-[#ccc] bg-[#fcfcfc] rounded-none text-[#666] flex justify-center items-center',
84
+ 'hover:z-10 hover:border-[#666]',
85
+ toolIndex === 0 ? 'rounded-l-[5px] ml-0' : '-ml-[1px]',
86
+ toolIndex === (group.tools?.length || 0) - 1 ? 'rounded-r-[5px]' : '',
87
+ tool.class || '',
88
+ getToolStatus(tool) ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'
89
+ ]" @click="!getToolStatus(tool) && onToolClick(tool, group)">
90
+ <component :is="tool.component" v-bind="{
91
+ ...tool.props,
92
+ disabled: getToolStatus(tool)
93
+ }" />
94
+ </div>
105
95
  </template>
106
96
  </div>
107
97
 
@@ -8,4 +8,4 @@ export { default as Toolbar } from './index.vue';
8
8
  /**
9
9
  * 工具栏相关类型定义
10
10
  */
11
- export type { ToolGroup } from './groupTools.vue';
11
+ export type { ToolGroup, ComponentTool, GroupType } from '@/typings/tools.d';
@@ -0,0 +1,323 @@
1
+ <script setup lang="ts">
2
+ import { ref, computed } from 'vue';
3
+ import { ToolIcon, Input } from '@/components/';
4
+
5
+
6
+ import { getToolVisible, getToolStatus, onToolClicked } from '@/utils/tools';
7
+ import type { ComponentTool, ToolGroup } from '@/typings/tools.d';
8
+ import GroupTools from '../toolbar/groupTools.vue';
9
+ import type {
10
+ ToolPanelGroup,
11
+ ToolPanelProps
12
+ } from './types';
13
+
14
+ const props = withDefaults(defineProps<ToolPanelProps>(), {
15
+ mode: 'list',
16
+ collapsed: false,
17
+ showSearch: true,
18
+ allowGroupCollapse: true,
19
+ rowCount: 3,
20
+ showModeToggle: true,
21
+ width: () => ({
22
+ expanded: 'w-72',
23
+ collapsed: 'w-16'
24
+ })
25
+ });
26
+
27
+ // 内部状态
28
+ const searchKeyword = ref('');
29
+ const groupCollapsedMap = ref<Record<string, boolean>>({});
30
+
31
+ // 判断工具数据是否为分组格式
32
+ const isGroupedData = computed(() => {
33
+ return Array.isArray(props.tools) && props.tools.length > 0 && 'tools' in props.tools[0];
34
+ });
35
+
36
+ // 合并工具数据 - 支持分组和非分组两种格式
37
+ const toolData = computed(() => {
38
+ if (!props.tools || !Array.isArray(props.tools)) {
39
+ return [];
40
+ }
41
+
42
+ // 如果已经是分组格式,直接返回
43
+ if (isGroupedData.value) {
44
+ return props.tools as ToolPanelGroup[];
45
+ }
46
+
47
+ // 如果是工具数组格式,转换为分组格式
48
+ const tools = props.tools as ComponentTool[];
49
+ return [{
50
+ id: 'default-group',
51
+ name: '工具',
52
+ tools: tools
53
+ }] as ToolPanelGroup[];
54
+ });
55
+
56
+ // 过滤后的工具数据 - 过滤时隐藏分组显示
57
+ const filteredToolData = computed(() => {
58
+ if (!searchKeyword.value.trim()) {
59
+ return toolData.value;
60
+ }
61
+
62
+ const keyword = searchKeyword.value.toLowerCase();
63
+ const filteredGroups = toolData.value.map((group: ToolPanelGroup) => ({
64
+ ...group,
65
+ tools: group.tools.filter((tool: ComponentTool) => {
66
+ const labelMatch = tool.label?.toLowerCase().includes(keyword);
67
+ const descMatch = (tool as any).description?.toLowerCase().includes(keyword);
68
+ return labelMatch || descMatch;
69
+ })
70
+ })).filter((group: ToolPanelGroup) => group.tools.length > 0);
71
+
72
+ // 如果有搜索关键词,返回扁平化的工具列表,不显示分组
73
+ if (searchKeyword.value.trim() && filteredGroups.length > 0) {
74
+ const allTools = filteredGroups.flatMap(group => group.tools);
75
+ return [{
76
+ id: 'search-results',
77
+ name: '搜索结果',
78
+ tools: allTools
79
+ }];
80
+ }
81
+
82
+ return filteredGroups;
83
+ });
84
+
85
+ // 获取面板宽度样式
86
+ const panelWidthClass = computed(() => {
87
+ return props.collapsed ? props.width.collapsed : props.width.expanded;
88
+ });
89
+
90
+ // 模式切换按钮组
91
+ const modeToggleGroup = computed<ToolGroup[]>(() => {
92
+ if (!props.showModeToggle) return [];
93
+
94
+ return [{
95
+ type: 'tools',
96
+ mode: 'toggle',
97
+ selected: props.mode,
98
+ tools: [
99
+ {
100
+ key: 'list',
101
+ label: '列表',
102
+ icon: 'icon-datalist',
103
+ display: 'icon',
104
+ tiptext: '列表视图',
105
+ click: () => {
106
+ props.onModeChange?.('list');
107
+ }
108
+ } as ComponentTool,
109
+ {
110
+ key: 'grid',
111
+ label: '网格',
112
+ icon: 'icon-icon-list',
113
+ display: 'icon',
114
+ tiptext: '网格视图',
115
+ click: () => {
116
+ props.onModeChange?.('grid');
117
+ }
118
+ } as ComponentTool
119
+ ]
120
+ }];
121
+ });
122
+
123
+ // 面板折叠按钮组
124
+ const collapseToggleGroup = computed<ToolGroup[]>(() => {
125
+ return [{
126
+ type: 'tools',
127
+ mode: 'normal',
128
+ tools: [
129
+ {
130
+ key: 'collapse',
131
+ label: props.collapsed ? '展开' : '收起',
132
+ icon: 'icon-menu',
133
+ display: 'icon',
134
+ tiptext: props.collapsed ? '展开面板' : '收起面板',
135
+ // 添加特殊的点击处理
136
+ click: () => {
137
+ props.onCollapseChange?.(!props.collapsed);
138
+ }
139
+ } as ComponentTool
140
+ ]
141
+ }];
142
+ });
143
+
144
+ // 判断分组是否折叠
145
+ const isGroupCollapsed = (groupId: string): boolean => {
146
+ return groupCollapsedMap.value[groupId] ?? false;
147
+ };
148
+
149
+ // 切换分组折叠状态
150
+ const toggleGroupCollapse = (groupId: string) => {
151
+ if (!props.allowGroupCollapse) return;
152
+
153
+ // 使用响应式更新
154
+ const newState = !groupCollapsedMap.value[groupId];
155
+ groupCollapsedMap.value = {
156
+ ...groupCollapsedMap.value,
157
+ [groupId]: newState
158
+ };
159
+ console.log('切换分组折叠状态:', groupId, newState);
160
+ };
161
+
162
+ // 处理工具点击事件
163
+ const handleToolClick = (tool: ComponentTool, event: MouseEvent) => {
164
+ if (getToolStatus(tool)) return;
165
+
166
+ // 使用统一的工具点击处理
167
+ onToolClicked(tool);
168
+
169
+ props.onToolClick?.(tool, event);
170
+ };
171
+
172
+ // 处理搜索
173
+ const handleSearch = (keyword: string) => {
174
+ searchKeyword.value = keyword;
175
+ props.onSearch?.(keyword);
176
+ };
177
+
178
+
179
+
180
+ // 拖拽事件处理
181
+ const handleDragStart = (event: DragEvent, tool: ComponentTool) => {
182
+ props.dragConfig?.onDragStart?.(event, tool);
183
+ };
184
+
185
+ const handleDragEnd = (event: DragEvent) => {
186
+ props.dragConfig?.onDragEnd?.(event);
187
+ };
188
+
189
+
190
+
191
+
192
+ </script>
193
+
194
+ <template>
195
+ <div class="relative h-full">
196
+ <!-- 主面板 -->
197
+ <div
198
+ class="h-full bg-white border-r border-gray-200 transition-all duration-300 ease-in-out shadow-sm"
199
+ :class="panelWidthClass">
200
+ <!-- 展开状态 -->
201
+ <div v-if="!props.collapsed" class="h-full flex flex-col">
202
+ <!-- 顶部工具栏 -->
203
+ <div class="px-3 pt-3 pb-2 flex items-center justify-end gap-2">
204
+ <!-- 模式切换按钮 -->
205
+ <GroupTools v-if="showModeToggle" :group-tools="modeToggleGroup as any" />
206
+
207
+ <!-- 折叠按钮 -->
208
+ <GroupTools :group-tools="collapseToggleGroup as any" />
209
+ </div>
210
+
211
+ <!-- 搜索框区域 -->
212
+ <div v-if="showSearch" class="px-3 pt-3 pb-2">
213
+ <Input v-model:value="searchKeyword" placeholder="搜索工具..." allow-clear size="small" class="w-full"
214
+ @update:value="(value: string) => handleSearch(value)"
215
+ @press-enter="(e: Event) => handleSearch((e.target as HTMLInputElement).value)" />
216
+ </div>
217
+ <!-- 工具列表滚动区域 -->
218
+ <div class="flex-1 overflow-y-auto px-4 pb-4">
219
+ <!-- 工具组 -->
220
+ <div v-for="group in filteredToolData" :key="group.id" class="mb-4 last:mb-0">
221
+ <!-- 分组标题 - 搜索结果时或默认分组时不显示分组标题 -->
222
+ <div v-if="allowGroupCollapse && group.id !== 'search-results' && group.id !== 'default-group'"
223
+ class="flex items-center justify-between text-xs font-semibold text-gray-700 mb-2 px-3 py-2 bg-gradient-to-r from-gray-50 to-gray-100 rounded-lg cursor-pointer hover:from-gray-100 hover:to-gray-200 transition-all"
224
+ @click="toggleGroupCollapse(group.id)">
225
+ <span>{{ group.name }}</span>
226
+ <ToolIcon :icon="isGroupCollapsed(group.id) ? 'icon-chevron-right' : 'icon-chevron-down'"
227
+ class="w-3.5 h-3.5 transition-transform duration-200" />
228
+ </div>
229
+ <h3 v-else-if="group.id !== 'search-results' && group.id !== 'default-group'"
230
+ class="text-xs font-semibold text-gray-700 mb-2 px-3 py-2 bg-gradient-to-r from-gray-50 to-gray-100 rounded-lg">
231
+ {{ group.name }}
232
+ </h3>
233
+
234
+ <!-- 工具列表 -->
235
+ <div
236
+ v-if="!isGroupCollapsed(group.id) || group.id === 'search-results' || group.id === 'default-group'">
237
+ <!-- 网格模式 -->
238
+ <div v-if="props.mode === 'grid'" class="grid grid-cols-3 gap-1.5 px-1">
239
+ <div v-for="tool in group.tools" v-show="getToolVisible(tool)" :key="tool.key"
240
+ :title="`${tool.label}${(tool as any).description ? ': ' + (tool as any).description : ''}`"
241
+ class="aspect-square flex flex-col items-center justify-center p-1.5 bg-gray-50 border border-solid border-gray-200 rounded-lg shadow-sm hover:border-blue-300 hover:shadow-lg hover:bg-blue-50 transition-all duration-200 cursor-move group"
242
+ :class="[
243
+ getToolStatus(tool) ? 'opacity-50 cursor-not-allowed bg-gray-200' : 'hover:scale-105',
244
+ tool.class || '',
245
+ dragConfig?.draggable ? 'cursor-move' : '',
246
+ ]" :draggable="dragConfig?.draggable"
247
+ @click="tool.click ? (tool.click as any)(tool, $event) : handleToolClick(tool, $event)"
248
+ @dragstart="handleDragStart($event, tool as any)" @dragend="handleDragEnd($event)"
249
+ v-bind="dragConfig">
250
+ <ToolIcon v-if="tool.icon" :icon="tool.icon"
251
+ class="w-9 h-9 mb-1 text-blue-600 group-hover:text-blue-700 transition-colors flex-shrink-0 !cursor-move"
252
+ :class="[tool.iconClass,
253
+ dragConfig?.draggable ? 'cursor-move' : '']" v-bind="tool.iconProps" />
254
+ <span
255
+ class="text-xs text-gray-700 font-medium text-center leading-tight truncate w-full group-hover:text-gray-900">{{
256
+ tool.label }}</span>
257
+ </div>
258
+ </div>
259
+
260
+ <!-- 列表模式 -->
261
+ <div v-else class="space-y-1.5">
262
+ <div v-for="tool in group.tools" v-show="getToolVisible(tool)" :key="tool.key"
263
+ :title="`${tool.label}${(tool as any).description ? ': ' + (tool as any).description : ''}`"
264
+ class="flex items-center px-2.5 py-2 bg-gray-50 border border-gray-200 border-solid rounded-lg shadow-sm hover:border-blue-500 hover:shadow-md hover:bg-blue-50 transition-all duration-200 group"
265
+ :class="[
266
+ getToolStatus(tool) ? 'opacity-50 cursor-not-allowed bg-gray-200' : 'hover:scale-[1.02]',
267
+ tool.class || '',
268
+ dragConfig?.draggable ? 'cursor-move' : ''
269
+ ]" :draggable="dragConfig?.draggable"
270
+ @click="tool.click ? (tool.click as any)(tool, $event) : handleToolClick(tool, $event)"
271
+ @dragstart="handleDragStart($event, tool as any)" @dragend="handleDragEnd($event)"
272
+ v-bind="dragConfig">
273
+ <ToolIcon v-if="tool.icon" :icon="tool.icon"
274
+ class="w-7 h-7 mr-2.5 flex-shrink-0 text-blue-600 group-hover:text-blue-700 transition-colors"
275
+ :class="[tool.iconClass,
276
+ dragConfig?.draggable ? '!cursor-move' : '']" v-bind="tool.iconProps" />
277
+ <div class="flex-1 min-w-0">
278
+ <div class="font-medium text-gray-900 text-sm group-hover:text-gray-950 text-center">{{
279
+ tool.label }}</div>
280
+ <div v-if="(tool as any).description"
281
+ class="text-xs text-gray-600 mt-0.5 truncate group-hover:text-gray-700 text-center">
282
+ {{ (tool as any).description }}
283
+ </div>
284
+ </div>
285
+ </div>
286
+ </div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+ </div>
291
+
292
+ <!-- 收起状态 -->
293
+ <div v-else class="relative h-full">
294
+ <!-- 顶部折叠按钮 -->
295
+ <div class="pt-4 pb-2 flex justify-center">
296
+ <GroupTools :group-tools="collapseToggleGroup as any" />
297
+ </div>
298
+ <!-- 工具列表 -->
299
+ <div class="overflow-y-auto flex flex-col items-center gap-3 pb-4">
300
+ <div v-for="group in filteredToolData" :key="group.id" class="flex flex-col items-center gap-2">
301
+ <div v-for="tool in group.tools" v-show="getToolVisible(tool)" :key="tool.key"
302
+ :title="`${tool.label}${(tool as any).description ? ': ' + (tool as any).description : ''}`"
303
+ class="w-12 h-12 flex items-center justify-center bg-gray-50 border border-gray-400 rounded-lg shadow-sm hover:border-blue-500 hover:shadow-md hover:bg-blue-50 transition-all duration-200 cursor-move group"
304
+ :class="[
305
+ getToolStatus(tool) ? 'opacity-50 cursor-not-allowed bg-gray-200' : 'hover:scale-110',
306
+ tool.class || '',
307
+ dragConfig?.draggable ? 'cursor-move' : ''
308
+ ]" :draggable="dragConfig?.draggable"
309
+ @click="tool.click ? (tool.click as any)(tool, $event) : handleToolClick(tool, $event)"
310
+ @dragstart="handleDragStart($event, tool as any)" @dragend="handleDragEnd($event)"
311
+ v-bind="dragConfig">
312
+ <ToolIcon v-if="tool.icon" :icon="tool.icon"
313
+ class="w-7 h-7 text-blue-600 group-hover:text-blue-700 transition-colors"
314
+ :class="tool.iconClass" v-bind="tool.iconProps" />
315
+ </div>
316
+ </div>
317
+ </div>
318
+ </div>
319
+ </div>
320
+
321
+
322
+ </div>
323
+ </template>
@@ -0,0 +1,90 @@
1
+ import type { ComponentTool } from '@/typings/tools.d';
2
+
3
+ /**
4
+ * 工具面板显示模式
5
+ */
6
+ export type DisplayMode = 'list' | 'grid';
7
+
8
+ /**
9
+ * 工具面板折叠状态
10
+ */
11
+ export type PanelCollapsed = boolean;
12
+
13
+ /**
14
+ * 工具面板分组配置
15
+ */
16
+ export interface ToolPanelGroup {
17
+ /** 分组ID */
18
+ id: string;
19
+ /** 分组名称 */
20
+ name: string;
21
+ /** 分组图标 */
22
+ icon?: string;
23
+ /** 分组是否折叠 */
24
+ collapsed?: boolean;
25
+ /** 工具列表 */
26
+ tools: ComponentTool[];
27
+ /** 分组样式类 */
28
+ class?: string;
29
+ }
30
+
31
+ /**
32
+ * 工具面板配置
33
+ */
34
+ export interface ToolPanelConfig {
35
+ /** 工具数据 - 支持分组和非分组两种格式 */
36
+ tools: ToolPanelGroup[] | ComponentTool[];
37
+ /** 显示模式 */
38
+ mode?: DisplayMode;
39
+ /** 面板折叠状态 */
40
+ collapsed?: PanelCollapsed;
41
+ /** 是否显示搜索框 */
42
+ showSearch?: boolean;
43
+ /** 是否支持分组折叠 */
44
+ allowGroupCollapse?: boolean;
45
+ /** 网格模式每行显示数量 */
46
+ rowCount?: number;
47
+ /** 是否显示模式切换按钮 */
48
+ showModeToggle?: boolean;
49
+ /** 面板宽度配置 */
50
+ width?: {
51
+ expanded: string;
52
+ collapsed: string;
53
+ };
54
+ }
55
+
56
+ /**
57
+ * 工具面板事件
58
+ */
59
+ export interface ToolPanelEvents {
60
+ /** 工具点击事件 */
61
+ onToolClick?: (tool: ComponentTool, event: MouseEvent) => void;
62
+ /** 搜索事件 */
63
+ onSearch?: (keyword: string) => void;
64
+ /** 显示模式变化事件 */
65
+ onModeChange?: (mode: DisplayMode) => void;
66
+ /** 面板折叠状态变化事件 */
67
+ onCollapseChange?: (collapsed: PanelCollapsed) => void;
68
+ }
69
+
70
+ /**
71
+ * 拖拽配置接口
72
+ */
73
+ export interface DragConfig {
74
+ /** 是否启用拖拽 */
75
+ draggable?: boolean;
76
+ /** 拖拽开始事件处理 */
77
+ onDragStart?: (event: DragEvent, tool: ComponentTool) => void;
78
+ /** 拖拽结束事件处理 */
79
+ onDragEnd?: (event: DragEvent) => void;
80
+ /** 其他拖拽相关属性 */
81
+ [key: string]: any;
82
+ }
83
+
84
+ /**
85
+ * 工具面板完整属性(包含配置和事件)
86
+ */
87
+ export type ToolPanelProps = ToolPanelConfig & ToolPanelEvents & {
88
+ /** 拖拽配置 */
89
+ dragConfig?: DragConfig;
90
+ };
@@ -1,3 +1,13 @@
1
+ import {
2
+ DisplayMode,
3
+ DragConfig,
4
+ PanelCollapsed,
5
+ ToolPanelConfig,
6
+ ToolPanelEvents,
7
+ ToolPanelGroup,
8
+ ToolPanelProps,
9
+ } from './content';
10
+
1
11
  // 基础组件
2
12
  export {
3
13
  Button,
@@ -27,9 +37,21 @@ export {
27
37
  TableOperate,
28
38
  Toolbar,
29
39
  Icontool,
40
+ GroupTools,
41
+ ToolPanel,
30
42
  Tree,
31
43
  } from './content';
32
44
 
45
+ export type {
46
+ ToolPanelGroup,
47
+ DisplayMode,
48
+ PanelCollapsed,
49
+ ToolPanelConfig,
50
+ ToolPanelEvents,
51
+ ToolPanelProps,
52
+ DragConfig,
53
+ };
54
+
33
55
  // 表单组件
34
56
  export {
35
57
  AutoComplete,