@baishuyun/ai-design 1.0.2 → 1.0.3
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/.turbo/turbo-build.log +16 -14
- package/CHANGELOG.md +9 -0
- package/dist/ai-design.js +6255 -5314
- package/dist/ai-design.js.map +1 -1
- package/dist/ai-design.umd.cjs +67 -67
- package/dist/ai-design.umd.cjs.map +1 -1
- package/dist/src/components/agent-scroll-selector.d.ts +2 -1
- package/dist/src/components/agent-scroll-selector.d.ts.map +1 -1
- package/dist/src/components/bs-entry-select/app-group-folder.d.ts +6 -0
- package/dist/src/components/bs-entry-select/app-group-folder.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/bs-entry-select.d.ts +4 -0
- package/dist/src/components/bs-entry-select/bs-entry-select.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/build-tree.d.ts +9 -0
- package/dist/src/components/bs-entry-select/build-tree.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/entry-item.d.ts +8 -0
- package/dist/src/components/bs-entry-select/entry-item.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/entry-popover.d.ts +17 -0
- package/dist/src/components/bs-entry-select/entry-popover.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/index.d.ts +3 -0
- package/dist/src/components/bs-entry-select/index.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/other-app-section.d.ts +11 -0
- package/dist/src/components/bs-entry-select/other-app-section.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/scroll-slider.d.ts +10 -0
- package/dist/src/components/bs-entry-select/scroll-slider.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/search-input.d.ts +5 -0
- package/dist/src/components/bs-entry-select/search-input.d.ts.map +1 -0
- package/dist/src/components/bs-entry-select/tree-item-node.d.ts +9 -0
- package/dist/src/components/bs-entry-select/tree-item-node.d.ts.map +1 -0
- package/dist/src/components/{bs-entry-select.d.ts → bs-entry-select/types.d.ts} +12 -2
- package/dist/src/components/bs-entry-select/types.d.ts.map +1 -0
- package/dist/src/components/bs-icons.d.ts +2 -0
- package/dist/src/components/bs-icons.d.ts.map +1 -1
- package/dist/src/components/collapsible.d.ts +6 -0
- package/dist/src/components/collapsible.d.ts.map +1 -0
- package/dist/src/components/field-checker-list-msg.d.ts +19 -0
- package/dist/src/components/field-checker-list-msg.d.ts.map +1 -0
- package/dist/src/components/field-checker.d.ts +19 -0
- package/dist/src/components/field-checker.d.ts.map +1 -0
- package/dist/src/components/field-icon.d.ts +5 -0
- package/dist/src/components/field-icon.d.ts.map +1 -0
- package/dist/src/components/field-value-checker.d.ts +16 -0
- package/dist/src/components/field-value-checker.d.ts.map +1 -0
- package/dist/src/components/legacy-slot.d.ts.map +1 -1
- package/dist/src/components/office-container.d.ts +5 -0
- package/dist/src/components/office-container.d.ts.map +1 -1
- package/dist/src/components/subform-fields-value-checker.d.ts +22 -0
- package/dist/src/components/subform-fields-value-checker.d.ts.map +1 -0
- package/dist/src/const/ui.d.ts +3 -0
- package/dist/src/const/ui.d.ts.map +1 -1
- package/dist/src/hooks/use-column-appear.d.ts +22 -0
- package/dist/src/hooks/use-column-appear.d.ts.map +1 -0
- package/dist/src/hooks/use-resizable-width.d.ts +3 -1
- package/dist/src/hooks/use-resizable-width.d.ts.map +1 -1
- package/dist/src/index.d.ts +11 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/lib/utils.d.ts +3 -0
- package/dist/src/lib/utils.d.ts.map +1 -1
- package/dist/src/stories/BsEntrySelect.stories.d.ts +4 -0
- package/dist/src/stories/BsEntrySelect.stories.d.ts.map +1 -1
- package/dist/src/stories/OfficeContainer.stories.d.ts +5 -0
- package/dist/src/stories/OfficeContainer.stories.d.ts.map +1 -1
- package/dist/src/stories/collapsible.stories.d.ts +8 -0
- package/dist/src/stories/collapsible.stories.d.ts.map +1 -0
- package/dist/src/stories/field-checker-list-msg.stories.d.ts +11 -0
- package/dist/src/stories/field-checker-list-msg.stories.d.ts.map +1 -0
- package/dist/src/stories/field-checker.stories.d.ts +13 -0
- package/dist/src/stories/field-checker.stories.d.ts.map +1 -0
- package/dist/src/stories/field-icon.stories.d.ts +15 -0
- package/dist/src/stories/field-icon.stories.d.ts.map +1 -0
- package/dist/src/stories/field-value-checker.stories.d.ts +13 -0
- package/dist/src/stories/field-value-checker.stories.d.ts.map +1 -0
- package/dist/src/stories/subform-fields-value-checker.stories.d.ts +9 -0
- package/dist/src/stories/subform-fields-value-checker.stories.d.ts.map +1 -0
- package/package.json +7 -5
- package/src/components/agent-scroll-selector.tsx +10 -3
- package/src/components/bs-entry-select/app-group-folder.tsx +61 -0
- package/src/components/bs-entry-select/bs-entry-select.tsx +271 -0
- package/src/components/bs-entry-select/build-tree.ts +144 -0
- package/src/components/bs-entry-select/entry-item.tsx +43 -0
- package/src/components/bs-entry-select/entry-popover.tsx +97 -0
- package/src/components/bs-entry-select/index.ts +2 -0
- package/src/components/bs-entry-select/other-app-section.tsx +96 -0
- package/src/components/bs-entry-select/scroll-slider.tsx +455 -0
- package/src/components/bs-entry-select/search-input.tsx +32 -0
- package/src/components/bs-entry-select/tree-item-node.tsx +84 -0
- package/src/components/bs-entry-select/types.ts +30 -0
- package/src/components/bs-icons.tsx +36 -1
- package/src/components/card.tsx +1 -1
- package/src/components/collapsible.tsx +9 -0
- package/src/components/field-checker-list-msg.tsx +146 -0
- package/src/components/field-checker.tsx +182 -0
- package/src/components/field-icon.tsx +13 -0
- package/src/components/field-value-checker.tsx +118 -0
- package/src/components/office-container.tsx +111 -28
- package/src/components/subform-fields-value-checker.tsx +185 -0
- package/src/const/ui.ts +67 -0
- package/src/hooks/use-column-appear.ts +78 -0
- package/src/hooks/use-resizable-width.ts +10 -2
- package/src/index.ts +11 -2
- package/src/lib/utils.ts +67 -0
- package/src/stories/BsEntrySelect.stories.tsx +45 -2
- package/src/stories/OfficeContainer.stories.tsx +150 -1
- package/src/stories/collapsible.stories.tsx +47 -0
- package/src/stories/field-checker-list-msg.stories.tsx +95 -0
- package/src/stories/field-checker.stories.tsx +117 -0
- package/src/stories/field-icon.stories.tsx +70 -0
- package/src/stories/field-value-checker.stories.tsx +113 -0
- package/src/stories/subform-fields-value-checker.stories.tsx +98 -0
- package/dist/src/components/bs-entry-select.d.ts.map +0 -1
- package/src/components/bs-entry-select.tsx +0 -724
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { memo, useEffect } from 'react';
|
|
2
|
+
import { FieldType, ValueOf } from '@baishuyun/types';
|
|
3
|
+
import { FieldTypeNameMap } from '../const/ui';
|
|
4
|
+
import { ToolUIPart } from 'ai';
|
|
5
|
+
import { FieldsTools } from '@baishuyun/agents';
|
|
6
|
+
import { isSubformFieldEqual, toHumanReadable } from '../lib/utils';
|
|
7
|
+
import { SubformFieldsValueChecker } from './subform-fields-value-checker';
|
|
8
|
+
import LineChecker from './line-checker';
|
|
9
|
+
|
|
10
|
+
type Field = ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
|
|
11
|
+
|
|
12
|
+
export interface FieldValueCheckerProps {
|
|
13
|
+
field: ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
|
|
14
|
+
isSubField?: boolean;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
readonly?: boolean;
|
|
17
|
+
onChange?: (checked: boolean, field: Field, parentFieldName?: string, index?: number) => void;
|
|
18
|
+
onLoaded?: (field: Field) => void;
|
|
19
|
+
streaming?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const FieldValueChecker = memo(
|
|
23
|
+
({
|
|
24
|
+
field,
|
|
25
|
+
disabled,
|
|
26
|
+
isSubField,
|
|
27
|
+
readonly,
|
|
28
|
+
streaming,
|
|
29
|
+
onChange,
|
|
30
|
+
onLoaded,
|
|
31
|
+
}: FieldValueCheckerProps) => {
|
|
32
|
+
const { widget, label } = field;
|
|
33
|
+
if (!widget) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { type, value: v } = widget;
|
|
38
|
+
|
|
39
|
+
const t = type as FieldType;
|
|
40
|
+
|
|
41
|
+
const value = toHumanReadable(v, t);
|
|
42
|
+
|
|
43
|
+
if (!FieldTypeNameMap.hasOwnProperty(type)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const isSubForm = type === 'subform';
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
onLoaded?.(field);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
const handleCheck = (checked: boolean) => {
|
|
54
|
+
onChange?.(checked, field);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const extraPadding = isSubField ? 'pl-6' : '';
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
<LineChecker
|
|
62
|
+
streaming={streaming}
|
|
63
|
+
title={label}
|
|
64
|
+
disabled={disabled}
|
|
65
|
+
defaultChecked={true}
|
|
66
|
+
onCheckedChange={handleCheck}
|
|
67
|
+
className={extraPadding}
|
|
68
|
+
readonly={readonly}
|
|
69
|
+
shortDesc={isSubForm ? '' : (value as string)}
|
|
70
|
+
/>
|
|
71
|
+
{isSubForm && (
|
|
72
|
+
<SubformFieldsValueChecker
|
|
73
|
+
readonly={readonly}
|
|
74
|
+
subformField={field}
|
|
75
|
+
onChange={(detail) => {
|
|
76
|
+
onChange?.(detail.checked, detail.field, detail.parentFieldName, detail.row);
|
|
77
|
+
}}
|
|
78
|
+
streaming={streaming}
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
81
|
+
</>
|
|
82
|
+
);
|
|
83
|
+
},
|
|
84
|
+
(p1, p2) => {
|
|
85
|
+
// 标签一致
|
|
86
|
+
const isLabelEqual = p1.field?.label === p2.field?.label;
|
|
87
|
+
if (!isLabelEqual) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// id 一致
|
|
92
|
+
const isFieldNameEqual = p1.field?.widget?.widgetName === p2.field?.widget?.widgetName;
|
|
93
|
+
if (!isFieldNameEqual) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 禁用状态一致
|
|
98
|
+
const isDisabledEqual = p1.disabled === p2.disabled;
|
|
99
|
+
if (!isDisabledEqual) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 只读状态一致
|
|
104
|
+
const isReadonlyEqual = p1.readonly === p2.readonly;
|
|
105
|
+
if (!isReadonlyEqual) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 流式状态一致
|
|
110
|
+
const isStreamingEqual = p1.streaming === p2.streaming;
|
|
111
|
+
if (!isStreamingEqual) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 进一步比较子表单下的字段
|
|
116
|
+
return isSubformFieldEqual(p1?.field, p2?.field);
|
|
117
|
+
}
|
|
118
|
+
);
|
|
@@ -1,80 +1,163 @@
|
|
|
1
|
-
import { FC } from 'react';
|
|
1
|
+
import { FC, useCallback, useRef } from 'react';
|
|
2
2
|
import { useResizableWidth } from '../hooks/use-resizable-width';
|
|
3
|
+
import { useColumnAppear } from '../hooks/use-column-appear';
|
|
3
4
|
import classNames from 'classnames';
|
|
4
5
|
|
|
6
|
+
export type FullScreenPart = 'leftCol' | 'rightCol' | 'none';
|
|
7
|
+
|
|
5
8
|
export interface IOfficeContainerProps {
|
|
6
9
|
headerHeight?: number;
|
|
7
10
|
|
|
8
11
|
hideLeftCol?: boolean;
|
|
9
12
|
|
|
10
13
|
leftColWidthRange?: [number, number];
|
|
14
|
+
rightColWidthRange?: [number, number];
|
|
15
|
+
|
|
16
|
+
leftColCls?: string;
|
|
17
|
+
rightColCls?: string;
|
|
18
|
+
|
|
11
19
|
leftColHeaderElement?: React.ReactNode;
|
|
12
20
|
leftColContentElement?: React.ReactNode;
|
|
13
21
|
rightColHeaderElement?: React.ReactNode;
|
|
14
22
|
rightColContentElement?: React.ReactNode;
|
|
23
|
+
|
|
24
|
+
fullscreenPart?: FullScreenPart;
|
|
15
25
|
}
|
|
16
26
|
|
|
27
|
+
|
|
17
28
|
export const OfficeContainer: FC<IOfficeContainerProps> = ({
|
|
18
29
|
headerHeight = 64,
|
|
19
30
|
hideLeftCol = false,
|
|
20
31
|
leftColWidthRange = [360, 500],
|
|
32
|
+
rightColWidthRange,
|
|
33
|
+
leftColCls,
|
|
34
|
+
rightColCls,
|
|
21
35
|
leftColHeaderElement,
|
|
22
36
|
leftColContentElement,
|
|
23
37
|
rightColHeaderElement,
|
|
24
38
|
rightColContentElement,
|
|
39
|
+
fullscreenPart = 'none',
|
|
25
40
|
}) => {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
const isRightResizable = !!rightColWidthRange;
|
|
42
|
+
const activeRange = rightColWidthRange ?? leftColWidthRange;
|
|
43
|
+
|
|
44
|
+
const { width, handleMouseDown, isDragging } = useResizableWidth({
|
|
45
|
+
range: activeRange,
|
|
46
|
+
initialWidth: activeRange[0],
|
|
47
|
+
invertDrag: isRightResizable,
|
|
29
48
|
});
|
|
30
49
|
|
|
31
|
-
const
|
|
50
|
+
const isLeftFullscreen = fullscreenPart === 'leftCol';
|
|
51
|
+
const isRightFullscreen = fullscreenPart === 'rightCol';
|
|
52
|
+
const isFullscreen = isLeftFullscreen || isRightFullscreen;
|
|
53
|
+
|
|
54
|
+
const leftHidden = hideLeftCol || isRightFullscreen;
|
|
55
|
+
const rightHidden = isLeftFullscreen;
|
|
56
|
+
|
|
57
|
+
// ---- column appear/hide animation ----
|
|
58
|
+
|
|
59
|
+
const {
|
|
60
|
+
colRef: leftColRef,
|
|
61
|
+
getTransitionStyle: leftTransitionStyle,
|
|
62
|
+
} = useColumnAppear({ hidden: leftHidden });
|
|
63
|
+
|
|
64
|
+
const {
|
|
65
|
+
colRef: rightColRef,
|
|
66
|
+
getTransitionStyle: rightTransitionStyle,
|
|
67
|
+
} = useColumnAppear({ hidden: rightHidden });
|
|
68
|
+
|
|
69
|
+
// ---- 列宽计算:始终返回明确像素值,避免 flex 计算宽与 transition 冲突 ----
|
|
70
|
+
|
|
71
|
+
const leftColInnerRef = useRef<HTMLDivElement>(null);
|
|
72
|
+
const rightColInnerRef = useRef<HTMLDivElement>(null);
|
|
73
|
+
|
|
74
|
+
const getColWidth = useCallback((col: 'left' | 'right'): number | string => {
|
|
75
|
+
if (col === 'left') {
|
|
76
|
+
if (hideLeftCol || isRightFullscreen) return 0;
|
|
77
|
+
if (isLeftFullscreen) return '100%';
|
|
78
|
+
if (isRightResizable) {
|
|
79
|
+
if (leftColInnerRef.current) return leftColInnerRef.current.offsetWidth;
|
|
80
|
+
return `calc(100% - ${width}px)`;
|
|
81
|
+
}
|
|
82
|
+
return width;
|
|
83
|
+
}
|
|
84
|
+
// right col
|
|
85
|
+
if (isLeftFullscreen) return 0;
|
|
86
|
+
if (isRightFullscreen) return '100%';
|
|
87
|
+
if (isRightResizable) return width;
|
|
88
|
+
if (rightColInnerRef.current) return rightColInnerRef.current.offsetWidth;
|
|
89
|
+
return `calc(100% - ${width}px)`;
|
|
90
|
+
}, [hideLeftCol, isLeftFullscreen, isRightFullscreen, isRightResizable, width]);
|
|
91
|
+
|
|
92
|
+
const borderColorCls = 'border-[#0265fc]';
|
|
93
|
+
|
|
94
|
+
// 全屏时补全 shrink-0,确保 width: 100% 或 width: 0 不会被 flex 容器挤压
|
|
95
|
+
const leftFlexCls = isFullscreen
|
|
96
|
+
? 'shrink-0'
|
|
97
|
+
: isRightResizable
|
|
98
|
+
? 'flex-1'
|
|
99
|
+
: 'shrink-0';
|
|
100
|
+
const rightFlexCls = isFullscreen
|
|
101
|
+
? 'shrink-0'
|
|
102
|
+
: isRightResizable
|
|
103
|
+
? 'shrink-0'
|
|
104
|
+
: 'flex-1';
|
|
105
|
+
|
|
106
|
+
// 滚动条使用 scrollbar-gutter: stable 预留空间,避免 overflow 切换时布局抖动
|
|
107
|
+
const contentCls = 'flex-1 min-h-0 overflow-auto w-full';
|
|
108
|
+
const contentStyle: React.CSSProperties = { /*scrollbarGutter: 'stable' */};
|
|
32
109
|
|
|
33
110
|
return (
|
|
34
111
|
<div className="relative h-full w-full flex overflow-hidden bg-white">
|
|
35
112
|
{/* left col */}
|
|
36
113
|
<div
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
114
|
+
ref={leftColRef}
|
|
115
|
+
className={classNames("h-full flex flex-col relative", leftColCls, leftFlexCls, {
|
|
116
|
+
"pointer-events-none": hideLeftCol || isRightFullscreen,
|
|
117
|
+
"opacity-0": hideLeftCol || isRightFullscreen,
|
|
118
|
+
"overflow-hidden": /* isRightFullscreen */ true,
|
|
40
119
|
})}
|
|
41
|
-
style={{ width:
|
|
120
|
+
style={{ ...leftTransitionStyle, width: getColWidth('left'), ...(isDragging ? { transition: 'none' } : {}) }}
|
|
42
121
|
>
|
|
43
|
-
|
|
44
|
-
|
|
122
|
+
<div
|
|
123
|
+
ref={leftColInnerRef}
|
|
124
|
+
className="shrink-0 w-full overflow-hidden"
|
|
45
125
|
style={{ height: headerHeight }}
|
|
46
126
|
>
|
|
47
127
|
{leftColHeaderElement}
|
|
48
128
|
</div>
|
|
49
|
-
<div className=
|
|
129
|
+
<div className={contentCls} style={contentStyle}>
|
|
50
130
|
{leftColContentElement}
|
|
51
131
|
</div>
|
|
52
132
|
{/* resizer */}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
133
|
+
{!isFullscreen && (
|
|
134
|
+
<div
|
|
135
|
+
className={classNames(`h-full w-5 cursor-col-resize z-10 flex justify-center group absolute top-0 right-0 hover:border-r hover:${borderColorCls}`, {
|
|
136
|
+
[`border-r ${borderColorCls}`]: isDragging,
|
|
137
|
+
})}
|
|
138
|
+
onMouseDown={handleMouseDown}
|
|
139
|
+
/>
|
|
140
|
+
)}
|
|
61
141
|
</div>
|
|
62
142
|
|
|
63
|
-
|
|
64
143
|
{/* right col */}
|
|
65
|
-
<div
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
144
|
+
<div
|
|
145
|
+
ref={rightColRef}
|
|
146
|
+
className={classNames("h-full flex flex-col min-w-0", rightColCls, rightFlexCls, {
|
|
147
|
+
"pointer-events-none": isLeftFullscreen,
|
|
148
|
+
"opacity-0": isLeftFullscreen,
|
|
149
|
+
"overflow-hidden": isLeftFullscreen,
|
|
150
|
+
})}
|
|
151
|
+
style={{ ...rightTransitionStyle, width: getColWidth('right'), ...(isDragging ? { transition: 'none' } : {}) }}
|
|
152
|
+
>
|
|
71
153
|
<div
|
|
154
|
+
ref={rightColInnerRef}
|
|
72
155
|
className="shrink-0 w-full"
|
|
73
156
|
style={{ height: headerHeight }}
|
|
74
157
|
>
|
|
75
158
|
{rightColHeaderElement}
|
|
76
159
|
</div>
|
|
77
|
-
<div className=
|
|
160
|
+
<div className={contentCls} style={contentStyle}>
|
|
78
161
|
{rightColContentElement}
|
|
79
162
|
</div>
|
|
80
163
|
</div>
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { memo, useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { FieldType, ValueOf } from '@baishuyun/types';
|
|
3
|
+
import { FieldTypeNameMap } from '../const/ui';
|
|
4
|
+
import { ToolUIPart } from 'ai';
|
|
5
|
+
import { FieldsTools } from '@baishuyun/agents';
|
|
6
|
+
import { toHumanReadable } from '../lib/utils';
|
|
7
|
+
import { Collapsible, CollapsibleContent } from './collapsible';
|
|
8
|
+
import LineChecker from './line-checker';
|
|
9
|
+
|
|
10
|
+
const Checker = ({
|
|
11
|
+
disabled,
|
|
12
|
+
onCheckedChange,
|
|
13
|
+
|
|
14
|
+
label,
|
|
15
|
+
val,
|
|
16
|
+
streaming,
|
|
17
|
+
readonly,
|
|
18
|
+
}: {
|
|
19
|
+
label: string;
|
|
20
|
+
val: string;
|
|
21
|
+
onCheckedChange: (v: boolean) => void;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
desc: string;
|
|
24
|
+
readonly?: boolean;
|
|
25
|
+
streaming?: boolean;
|
|
26
|
+
}) => {
|
|
27
|
+
return (
|
|
28
|
+
<LineChecker
|
|
29
|
+
streaming={streaming}
|
|
30
|
+
readonly={readonly}
|
|
31
|
+
title={label}
|
|
32
|
+
disabled={disabled}
|
|
33
|
+
defaultChecked={true}
|
|
34
|
+
onCheckedChange={onCheckedChange}
|
|
35
|
+
className="pl-9"
|
|
36
|
+
shortDesc={val}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const SubFieldChecker = memo(
|
|
42
|
+
({
|
|
43
|
+
field,
|
|
44
|
+
readonly,
|
|
45
|
+
onCheckedChange,
|
|
46
|
+
streaming,
|
|
47
|
+
}: {
|
|
48
|
+
onCheckedChange: (
|
|
49
|
+
checked: boolean,
|
|
50
|
+
field: ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>
|
|
51
|
+
) => void;
|
|
52
|
+
readonly?: boolean;
|
|
53
|
+
streaming?: boolean;
|
|
54
|
+
field: ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
|
|
55
|
+
}) => {
|
|
56
|
+
const { widget, label } = field;
|
|
57
|
+
if (!widget) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { type, value: v } = widget;
|
|
62
|
+
const t = type as FieldType;
|
|
63
|
+
if (!FieldTypeNameMap.hasOwnProperty(t)) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const value = toHumanReadable(v, t);
|
|
68
|
+
|
|
69
|
+
const typeDesc = FieldTypeNameMap[t] || FieldTypeNameMap.unknown;
|
|
70
|
+
|
|
71
|
+
const handleCheckChange = useCallback(
|
|
72
|
+
(v: boolean) => {
|
|
73
|
+
onCheckedChange(v, field);
|
|
74
|
+
},
|
|
75
|
+
[field]
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
// 默认勾选上
|
|
80
|
+
handleCheckChange(true);
|
|
81
|
+
}, []);
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<Checker
|
|
85
|
+
streaming={streaming}
|
|
86
|
+
readonly={readonly}
|
|
87
|
+
desc={typeDesc}
|
|
88
|
+
label={label}
|
|
89
|
+
val={value as string}
|
|
90
|
+
onCheckedChange={handleCheckChange}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
},
|
|
94
|
+
(p1, p2) => {
|
|
95
|
+
const isNameEqual =
|
|
96
|
+
p1.field.widget?.widgetName === p2.field.widget?.widgetName &&
|
|
97
|
+
p1.readonly === p2.readonly &&
|
|
98
|
+
p1.streaming === p2.streaming;
|
|
99
|
+
return isNameEqual;
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
type F = ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
|
|
104
|
+
|
|
105
|
+
interface generatedField {
|
|
106
|
+
label: string;
|
|
107
|
+
fieldName: string;
|
|
108
|
+
fieldType: string;
|
|
109
|
+
value: any;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
type onSubformFieldChangeParam = {
|
|
113
|
+
checked: boolean;
|
|
114
|
+
field: F;
|
|
115
|
+
parentFieldName: string;
|
|
116
|
+
row?: number;
|
|
117
|
+
col?: number;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 专门渲染子表单下的字段勾选
|
|
122
|
+
*/
|
|
123
|
+
export const SubformFieldsValueChecker = ({
|
|
124
|
+
subformField,
|
|
125
|
+
onChange,
|
|
126
|
+
streaming,
|
|
127
|
+
readonly,
|
|
128
|
+
}: {
|
|
129
|
+
onChange: (p: onSubformFieldChangeParam) => void;
|
|
130
|
+
subformField: ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
|
|
131
|
+
streaming?: boolean;
|
|
132
|
+
readonly?: boolean;
|
|
133
|
+
}) => {
|
|
134
|
+
if (!subformField.widget.value || !subformField.widget.value.length) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const subformRecords = subformField.widget.value;
|
|
139
|
+
|
|
140
|
+
// 默认展开
|
|
141
|
+
const [openAll, setOpenAll] = useState(true);
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<Collapsible open={openAll} onOpenChange={setOpenAll}>
|
|
145
|
+
<CollapsibleContent>
|
|
146
|
+
{subformRecords.map((rowData: generatedField[], row: number) => {
|
|
147
|
+
if (!rowData || !rowData.length) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
return (
|
|
151
|
+
<Collapsible defaultOpen={true} key={row}>
|
|
152
|
+
<CollapsibleContent>
|
|
153
|
+
{rowData.map((fData: generatedField, col: number) => {
|
|
154
|
+
return (
|
|
155
|
+
<SubFieldChecker
|
|
156
|
+
readonly={readonly}
|
|
157
|
+
streaming={streaming}
|
|
158
|
+
field={{
|
|
159
|
+
label: fData.label,
|
|
160
|
+
widget: {
|
|
161
|
+
widgetName: fData.fieldName,
|
|
162
|
+
type: fData.fieldType,
|
|
163
|
+
value: fData.value,
|
|
164
|
+
},
|
|
165
|
+
}}
|
|
166
|
+
onCheckedChange={(checked: boolean, field: F) => {
|
|
167
|
+
onChange({
|
|
168
|
+
checked,
|
|
169
|
+
field,
|
|
170
|
+
row,
|
|
171
|
+
col,
|
|
172
|
+
parentFieldName: subformField.widget.widgetName,
|
|
173
|
+
});
|
|
174
|
+
}}
|
|
175
|
+
/>
|
|
176
|
+
);
|
|
177
|
+
})}
|
|
178
|
+
</CollapsibleContent>
|
|
179
|
+
</Collapsible>
|
|
180
|
+
);
|
|
181
|
+
})}
|
|
182
|
+
</CollapsibleContent>
|
|
183
|
+
</Collapsible>
|
|
184
|
+
);
|
|
185
|
+
};
|
package/src/const/ui.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FormIconOption } from "../types";
|
|
2
|
+
import { FieldType } from "@baishuyun/types";
|
|
2
3
|
|
|
3
4
|
export const BotImgUrl = `
|
|
4
5
|
url(data:image/png;base64,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)
|
|
@@ -50,3 +51,69 @@ export const FORM_ICON_OPTIONS: FormIconOption[] = [
|
|
|
50
51
|
{ id: 'biaodan35', code: '', label: '表单35', value: 59 },
|
|
51
52
|
{ id: 'biaodan36', code: '', label: '表单36', value: 60 },
|
|
52
53
|
];
|
|
54
|
+
|
|
55
|
+
export const FieldTypeNameMap: Record<FieldType, string> = {
|
|
56
|
+
text: '输入框',
|
|
57
|
+
password: '密码输入框',
|
|
58
|
+
location: '定位',
|
|
59
|
+
datetime: '日期时间选择器',
|
|
60
|
+
radiogroup: '单选框',
|
|
61
|
+
radio: '单选框',
|
|
62
|
+
combo: '下拉框',
|
|
63
|
+
address: '地址',
|
|
64
|
+
button: '按钮',
|
|
65
|
+
textarea: '多行输入框',
|
|
66
|
+
combocheck: '多选下拉框',
|
|
67
|
+
checkboxgroup: '多选框组',
|
|
68
|
+
separator: '分割线',
|
|
69
|
+
upload: '附件上传',
|
|
70
|
+
number: '数字输入框',
|
|
71
|
+
dataload: '数据加载',
|
|
72
|
+
image: '图片上传',
|
|
73
|
+
signature: '签名',
|
|
74
|
+
dept: '部门选择',
|
|
75
|
+
user: '成员选择',
|
|
76
|
+
usergroup: '成员多选',
|
|
77
|
+
deptgroup: '部门多选',
|
|
78
|
+
unknown: '未知类型',
|
|
79
|
+
sn: '流水号',
|
|
80
|
+
formula: '公式字段',
|
|
81
|
+
linkdata: '关联数据',
|
|
82
|
+
linkquery: '关联查询',
|
|
83
|
+
subform: '子表单',
|
|
84
|
+
flowState: '流程状态',
|
|
85
|
+
flowstate: '流程状态',
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const FIELD_ICON_CODE_MAP: Record<FieldType, string> = {
|
|
89
|
+
address: '',
|
|
90
|
+
subform: '',
|
|
91
|
+
password: '',
|
|
92
|
+
button: '',
|
|
93
|
+
textarea: '',
|
|
94
|
+
datetime: '',
|
|
95
|
+
text: '',
|
|
96
|
+
location: '',
|
|
97
|
+
radiogroup: '',
|
|
98
|
+
radio: '',
|
|
99
|
+
combo: '',
|
|
100
|
+
formula: '',
|
|
101
|
+
flowState: '',
|
|
102
|
+
flowstate: '',
|
|
103
|
+
combocheck: '',
|
|
104
|
+
separator: '',
|
|
105
|
+
checkboxgroup: '',
|
|
106
|
+
upload: '',
|
|
107
|
+
number: '',
|
|
108
|
+
image: '',
|
|
109
|
+
signature: '',
|
|
110
|
+
user: '',
|
|
111
|
+
dataload: '',
|
|
112
|
+
linkdata: '',
|
|
113
|
+
linkquery: '',
|
|
114
|
+
usergroup: '',
|
|
115
|
+
dept: '',
|
|
116
|
+
sn: '',
|
|
117
|
+
deptgroup: '',
|
|
118
|
+
unknown: '',
|
|
119
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export const TRANSITION = {
|
|
4
|
+
appearing: 'width 300ms cubic-bezier(0.4,0,0.2,1), opacity 250ms cubic-bezier(0.4,0,0.2,1) 100ms',
|
|
5
|
+
hiding: 'width 350ms cubic-bezier(0.4,0,0.2,1) 60ms, opacity 200ms ease-out',
|
|
6
|
+
neutral: 'width 350ms cubic-bezier(0.4,0,0.2,1), opacity 200ms ease-out',
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
/** hiding 场景最长的 transition 耗时 (width 350ms + delay 60ms),加少量余量用于 transitionend 兜底 */
|
|
10
|
+
export const TRANSITION_FALLBACK_MS = 500;
|
|
11
|
+
|
|
12
|
+
interface UseColumnAppearOptions {
|
|
13
|
+
/** 当前列是否处于隐藏状态 */
|
|
14
|
+
hidden: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface UseColumnAppearResult {
|
|
18
|
+
/** 列是否正在执行 appear (hidden→visible) 动画 */
|
|
19
|
+
appearing: boolean;
|
|
20
|
+
/** 附加到列最外层 DOM 元素的 ref,用于监听 transitionend */
|
|
21
|
+
colRef: React.RefObject<HTMLDivElement>;
|
|
22
|
+
/** 当前适用的 transition CSS 属性,直接展开到 style={} */
|
|
23
|
+
getTransitionStyle: React.CSSProperties;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const useColumnAppear = ({ hidden }: UseColumnAppearOptions): UseColumnAppearResult => {
|
|
27
|
+
const [appearing, setAppearing] = useState(false);
|
|
28
|
+
const prevHiddenRef = useRef<boolean | null>(null);
|
|
29
|
+
const colRef = useRef<HTMLDivElement>(null);
|
|
30
|
+
|
|
31
|
+
// 检测 hidden → visible 转换,触发 appearing
|
|
32
|
+
useLayoutEffect(() => {
|
|
33
|
+
if (prevHiddenRef.current === null) {
|
|
34
|
+
prevHiddenRef.current = hidden;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (prevHiddenRef.current && !hidden) {
|
|
38
|
+
setAppearing(true);
|
|
39
|
+
}
|
|
40
|
+
prevHiddenRef.current = hidden;
|
|
41
|
+
}, [hidden]);
|
|
42
|
+
|
|
43
|
+
// transitionend 监听 + 兜底 timeout 清除 appearing
|
|
44
|
+
useLayoutEffect(() => {
|
|
45
|
+
if (!appearing) return;
|
|
46
|
+
const el = colRef.current;
|
|
47
|
+
if (!el) return;
|
|
48
|
+
|
|
49
|
+
const onTransitionEnd = (e: TransitionEvent) => {
|
|
50
|
+
if (e.propertyName === 'width') {
|
|
51
|
+
setAppearing(false);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
window.dispatchEvent(new Event('resize'));
|
|
55
|
+
};
|
|
56
|
+
el.addEventListener('transitionend', onTransitionEnd);
|
|
57
|
+
|
|
58
|
+
const fallback = setTimeout(() => setAppearing(false), TRANSITION_FALLBACK_MS);
|
|
59
|
+
|
|
60
|
+
return () => {
|
|
61
|
+
el.removeEventListener('transitionend', onTransitionEnd);
|
|
62
|
+
clearTimeout(fallback);
|
|
63
|
+
};
|
|
64
|
+
}, [appearing]);
|
|
65
|
+
|
|
66
|
+
// 计算当前适用的 transition 样式
|
|
67
|
+
const willChange = hidden || appearing ? ({ willChange: 'width, opacity' } as const) : {};
|
|
68
|
+
let transitionStyle: React.CSSProperties;
|
|
69
|
+
if (appearing) {
|
|
70
|
+
transitionStyle = { transition: TRANSITION.appearing, ...willChange };
|
|
71
|
+
} else if (hidden) {
|
|
72
|
+
transitionStyle = { transition: TRANSITION.hiding, ...willChange };
|
|
73
|
+
} else {
|
|
74
|
+
transitionStyle = { transition: TRANSITION.neutral };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { appearing, colRef, getTransitionStyle: transitionStyle };
|
|
78
|
+
};
|