@baishuyun/chat-sdk 0.0.15 → 0.0.17
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 +14 -0
- package/dist/chat-sdk.js +16307 -15780
- package/dist/chat-sdk.js.map +1 -1
- package/dist/chat-sdk.umd.cjs +149 -149
- package/dist/chat-sdk.umd.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/package.json +4 -4
- package/src/chat.tsx +15 -1
- package/src/components/biz-comp/FieldChecker.tsx +49 -7
- package/src/components/biz-comp/FieldCheckerListMsg.tsx +101 -22
- package/src/components/biz-comp/chat-client.tsx +7 -2
- package/src/components/biz-comp/error-msg.tsx +10 -0
- package/src/components/biz-comp/messages.tsx +10 -0
- package/src/components/biz-comp/multi-modal-input/clear-btn.tsx +3 -1
- package/src/components/biz-comp/multi-modal-input/index.tsx +58 -38
- package/src/components/biz-comp/multi-modal-input/prompt-input.tsx +13 -10
- package/src/components/biz-comp/preview-message-wrapper.tsx +4 -4
- package/src/components/biz-comp/preview-message.tsx +3 -1
- package/src/components/biz-comp/suggestions.tsx +5 -1
- package/src/components/bs-ui/attachments-previewer.tsx +4 -1
- package/src/components/bs-ui/base-button.tsx +7 -2
- package/src/components/bs-ui/bs-icons.tsx +29 -0
- package/src/components/bs-ui/card.tsx +4 -3
- package/src/components/bs-ui/chat-area-header.tsx +7 -3
- package/src/components/bs-ui/fields-design-info-table.tsx +160 -0
- package/src/components/bs-ui/fields-previewer.tsx +2 -0
- package/src/components/bs-ui/form-info-editor.tsx +2 -42
- package/src/components/bs-ui/generate-animation.tsx +7 -5
- package/src/components/bs-ui/img-part.tsx +1 -1
- package/src/components/bs-ui/line-checker.tsx +19 -5
- package/src/components/bs-ui/previewer-header.tsx +31 -3
- package/src/components/bs-ui/square-checker.tsx +30 -5
- package/src/components/bs-ui/tooltip.tsx +1 -1
- package/src/components/ui/dialog.tsx +1 -1
- package/src/components/ui/tooltip.tsx +1 -1
- package/src/const/ui.ts +42 -0
- package/src/hooks/use-frame-mode.ts +15 -0
- package/src/lib/parse-design-doc.ts +60 -0
- package/src/lib/utils.ts +19 -0
- package/src/plugins/form-builder-base-plugin/const.ts +3 -0
- package/src/plugins/form-builder-plugin/components/create-form-confirm.tsx +14 -1
- package/src/plugins/form-builder-plugin/components/design-info.tsx +47 -0
- package/src/plugins/form-builder-plugin/components/entry-btn.tsx +10 -2
- package/src/plugins/form-builder-plugin/components/follow-up.tsx +21 -6
- package/src/plugins/form-builder-plugin/components/msg-part.tsx +29 -9
- package/src/plugins/form-builder-plugin/components/opening-lines.tsx +11 -6
- package/src/plugins/form-builder-plugin/index.ts +73 -5
- package/src/plugins/form-builder-plugin/types.ts +3 -0
- package/src/plugins/form-builder-plugin/utils/index.ts +33 -6
- package/src/plugins/form-filling-plugin/components/batch-generator-action.tsx +44 -34
- package/src/plugins/form-filling-plugin/components/first-batch-generating-animation.tsx +21 -0
- package/src/plugins/form-filling-plugin/components/generated-data-counter.tsx +17 -0
- package/src/plugins/form-filling-plugin/components/non-first-batch-generating-animation.tsx +28 -0
- package/src/plugins/form-filling-plugin/index.ts +14 -0
- package/src/plugins/form-filling-plugin/types.ts +2 -0
- package/src/plugins/report-query-plugin/components/query-msg-part.tsx +16 -18
- package/src/plugins/report-query-plugin/components/result-cards/CreatedSourceMsg.tsx +36 -0
- package/src/plugins/report-query-plugin/components/result-cards/DataTableCard.tsx +15 -2
- package/src/plugins/report-query-plugin/const.ts +22 -0
- package/src/plugins/report-query-plugin/index.ts +30 -3
- package/src/plugins/report-query-plugin/types.ts +6 -0
- package/src/sdk.impl.tsx +4 -0
- package/src/store/index.ts +11 -0
- package/src/stories/FormInfoEditor.stories.tsx +19 -28
- package/src/stories/PreviewerHeader.stories.tsx +14 -0
- package/src/stories/fields-design-info-table.stories.tsx +203 -0
|
@@ -1,38 +1,117 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
memo,
|
|
4
|
+
ReactNode,
|
|
5
|
+
useCallback,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useMemo,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
2
10
|
import { CollapsibleTxtMsg } from '../bs-ui/collapsible-txt-msg';
|
|
3
11
|
import { FieldChecker, FieldCheckerProps } from './FieldChecker';
|
|
4
12
|
import { EditIcon, LetterAIcon } from '../bs-ui/bs-icons';
|
|
5
13
|
import { FieldValueChecker, FieldValueCheckerProps } from './FieldValueChecker';
|
|
14
|
+
import { SquareChecker } from '../bs-ui/square-checker';
|
|
15
|
+
import { cn } from '@/lib/utils';
|
|
16
|
+
|
|
17
|
+
export interface FieldCheckerListMsgRef {
|
|
18
|
+
getCheckedFieldsLength: () => number;
|
|
19
|
+
}
|
|
6
20
|
|
|
7
21
|
export const FieldCheckerListMsg = memo(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
forwardRef<
|
|
23
|
+
FieldCheckerListMsgRef,
|
|
24
|
+
{
|
|
25
|
+
fields: Array<FieldCheckerProps>;
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
streaming: boolean;
|
|
28
|
+
confirmed?: boolean;
|
|
29
|
+
}
|
|
30
|
+
>(({ fields, children, streaming, confirmed }, ref) => {
|
|
31
|
+
// Track individual field checked states (all default to true)
|
|
32
|
+
const [checkedMap, setCheckedMap] = useState<Record<string, boolean>>(() =>
|
|
33
|
+
Object.fromEntries(fields.map((f) => [f.field?.label ?? '', true]))
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const allChecked = useMemo(
|
|
37
|
+
() => fields.length > 0 && fields.every((f) => checkedMap[f.field?.label ?? ''] !== false),
|
|
38
|
+
[checkedMap, fields]
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const someChecked = useMemo(
|
|
42
|
+
() => fields.some((f) => checkedMap[f.field?.label ?? ''] !== false),
|
|
43
|
+
[checkedMap, fields]
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const intermediate = streaming || (!allChecked && someChecked);
|
|
47
|
+
|
|
48
|
+
useImperativeHandle(
|
|
49
|
+
ref,
|
|
50
|
+
() => ({
|
|
51
|
+
getCheckedFieldsLength: () =>
|
|
52
|
+
fields.filter((f) => checkedMap[f.field?.label ?? ''] !== false).length,
|
|
53
|
+
}),
|
|
54
|
+
[checkedMap, fields]
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const handleToggleAll = useCallback(
|
|
58
|
+
(checked: boolean | 'indeterminate') => {
|
|
59
|
+
const value = checked === true;
|
|
60
|
+
setCheckedMap(Object.fromEntries(fields.map((f) => [f.field?.label ?? '', value])));
|
|
61
|
+
fields.forEach((f) => f.onChange?.(value, f.field));
|
|
62
|
+
},
|
|
63
|
+
[fields]
|
|
64
|
+
);
|
|
65
|
+
|
|
19
66
|
return (
|
|
20
67
|
<CollapsibleTxtMsg title="字段生成" icon={<LetterAIcon />} defaultOpen>
|
|
68
|
+
{
|
|
69
|
+
<div
|
|
70
|
+
className={cn(
|
|
71
|
+
'flex gap-[10px] px-4 py-[10px] rounded-[4px] w-full transition-colors cursor-pointer hover:bg-[#EFF0F6] items-center',
|
|
72
|
+
{
|
|
73
|
+
'pointer-events-none': confirmed || streaming,
|
|
74
|
+
}
|
|
75
|
+
)}
|
|
76
|
+
onClick={() => {
|
|
77
|
+
if (confirmed) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const newChecked = !allChecked;
|
|
82
|
+
handleToggleAll(newChecked);
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
<SquareChecker
|
|
86
|
+
readonly={confirmed || streaming}
|
|
87
|
+
checked={allChecked && !streaming}
|
|
88
|
+
onCheckedChange={handleToggleAll}
|
|
89
|
+
intermediate={intermediate}
|
|
90
|
+
>
|
|
91
|
+
<span className="!text-[#0265ff] !font-[700]">全选</span>
|
|
92
|
+
</SquareChecker>
|
|
93
|
+
</div>
|
|
94
|
+
}
|
|
21
95
|
{fields.map((f) => (
|
|
22
|
-
<FieldChecker
|
|
96
|
+
<FieldChecker
|
|
97
|
+
{...f}
|
|
98
|
+
key={f.field?.label}
|
|
99
|
+
checked={checkedMap[f.field?.label ?? '']}
|
|
100
|
+
streaming={streaming}
|
|
101
|
+
confirmed={confirmed}
|
|
102
|
+
onChange={(checked, field, parentFieldName, index) => {
|
|
103
|
+
const isSubField = index !== undefined && parentFieldName !== undefined;
|
|
104
|
+
if (!isSubField) {
|
|
105
|
+
setCheckedMap((prev) => ({ ...prev, [f.field?.label ?? '']: checked }));
|
|
106
|
+
}
|
|
107
|
+
f.onChange?.(checked, field, parentFieldName, index);
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
23
110
|
))}
|
|
24
111
|
{children}
|
|
25
112
|
</CollapsibleTxtMsg>
|
|
26
113
|
);
|
|
27
|
-
}
|
|
28
|
-
(p1, p2) => {
|
|
29
|
-
return (
|
|
30
|
-
p1.fields.length === p2.fields.length &&
|
|
31
|
-
p1.streaming === p2.streaming &&
|
|
32
|
-
p1.confirmed === p2.confirmed &&
|
|
33
|
-
p1.children === p2.children
|
|
34
|
-
);
|
|
35
|
-
}
|
|
114
|
+
})
|
|
36
115
|
);
|
|
37
116
|
|
|
38
117
|
export const FieldValueCheckerListMsg = memo(
|
|
@@ -109,12 +109,13 @@ const ChatContent: React.FC<{ client?: ChatSDK }> = ({ client }): ReactPortal |
|
|
|
109
109
|
export const ChatEntryBtn = ({ client }: { client: ChatSDK }) => {
|
|
110
110
|
const { bottom = 10, right = 10 } = client?.options?.btnOffset || {};
|
|
111
111
|
|
|
112
|
-
const { entryVisible, entryWrapper, setStatus, isVisible, entryVariant } = useChatStore(
|
|
112
|
+
const { entryVisible, status, entryWrapper, setStatus, isVisible, entryVariant } = useChatStore(
|
|
113
113
|
(store) => ({
|
|
114
114
|
setStatus: store.setChatStatus,
|
|
115
115
|
entryVariant: store.chatEntryVariant,
|
|
116
116
|
entryWrapper: store.chatEntryElWrapper,
|
|
117
117
|
isVisible: store.chatStatus !== 'hide',
|
|
118
|
+
status: store.chatStatus,
|
|
118
119
|
entryVisible: store.chatEntryVisible,
|
|
119
120
|
})
|
|
120
121
|
);
|
|
@@ -138,6 +139,7 @@ export const ChatEntryBtn = ({ client }: { client: ChatSDK }) => {
|
|
|
138
139
|
|
|
139
140
|
const EntryJsx = EntryCom ? (
|
|
140
141
|
<EntryCom
|
|
142
|
+
chatStatus={status}
|
|
141
143
|
client={client}
|
|
142
144
|
variant={entryVariant}
|
|
143
145
|
chatVisible={isVisible}
|
|
@@ -191,9 +193,10 @@ const MultiEntryButtonItem = ({
|
|
|
191
193
|
client: ChatSDK;
|
|
192
194
|
config: ChatEntryButtonConfig;
|
|
193
195
|
}) => {
|
|
194
|
-
const { setStatus, isVisible } = useChatStore((store) => ({
|
|
196
|
+
const { setStatus, isVisible, status } = useChatStore((store) => ({
|
|
195
197
|
setStatus: store.setChatStatus,
|
|
196
198
|
isVisible: store.chatStatus !== 'hide',
|
|
199
|
+
status: store.chatStatus,
|
|
197
200
|
}));
|
|
198
201
|
|
|
199
202
|
const EntryInfo = useDefaultPluginCustomComponent('EntryButton');
|
|
@@ -215,6 +218,7 @@ const MultiEntryButtonItem = ({
|
|
|
215
218
|
|
|
216
219
|
const EntryJsx = EntryCom ? (
|
|
217
220
|
<EntryCom
|
|
221
|
+
chatStatus={status}
|
|
218
222
|
client={client}
|
|
219
223
|
variant={config.variant}
|
|
220
224
|
chatVisible={isVisible}
|
|
@@ -284,6 +288,7 @@ export const ChatClient = ({ store, client }: { client: ChatSDK; store: ChatStor
|
|
|
284
288
|
return (
|
|
285
289
|
<ChatStoreProvider store={store}>
|
|
286
290
|
<TooltipProvider
|
|
291
|
+
delayDuration={100}
|
|
287
292
|
zIndex={client?.options?.safeZIndex != null ? client.options.safeZIndex + 1 : 50}
|
|
288
293
|
>
|
|
289
294
|
<ChatWidgets client={client} />
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
1
2
|
import { FakeBotMessage } from './FakeBotMsg';
|
|
3
|
+
import { useFakeGlobalLoadingMessage } from '@/hooks/use-frame-mode';
|
|
2
4
|
|
|
3
5
|
export const ErrorFallbackMsg = ({ error }: { error?: string }) => {
|
|
6
|
+
const loading = useFakeGlobalLoadingMessage();
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (loading) {
|
|
10
|
+
loading.clearGlobalFakeLoadingMessage();
|
|
11
|
+
}
|
|
12
|
+
}, [loading]);
|
|
13
|
+
|
|
4
14
|
return (
|
|
5
15
|
<FakeBotMessage headless>
|
|
6
16
|
{error || '出现了一些问题,无法显示预览内容,请稍后重试。'}
|
|
@@ -4,12 +4,16 @@ import { PreviewMessage } from './preview-message';
|
|
|
4
4
|
import { FakeBotMessage } from './FakeBotMsg';
|
|
5
5
|
import { OpeningLines } from './opening-lines';
|
|
6
6
|
import { useRef } from 'react';
|
|
7
|
+
import { useFakeGlobalLoadingMessage } from '@/hooks/use-frame-mode';
|
|
8
|
+
import { GenerateAnimation } from '../bs-ui/generate-animation';
|
|
7
9
|
|
|
8
10
|
export const Messages = (props: MessagesProps) => {
|
|
9
11
|
const messagesContainerRef = useRef(null);
|
|
10
12
|
|
|
11
13
|
const { messages, setMessages, addToolOutput, sendMessage, regenerate } = props;
|
|
12
14
|
|
|
15
|
+
const { globalFakeLoadingMessage } = useFakeGlobalLoadingMessage();
|
|
16
|
+
|
|
13
17
|
return (
|
|
14
18
|
<div
|
|
15
19
|
className="relative overscroll-behavior-contain -webkit-overflow-scrolling-touch flex-1 touch-pan-y overflow-y-auto m-h-0 h-full"
|
|
@@ -38,6 +42,12 @@ export const Messages = (props: MessagesProps) => {
|
|
|
38
42
|
/>
|
|
39
43
|
);
|
|
40
44
|
})}
|
|
45
|
+
|
|
46
|
+
{globalFakeLoadingMessage && (
|
|
47
|
+
<FakeBotMessage key={'fake'}>
|
|
48
|
+
<GenerateAnimation>{globalFakeLoadingMessage}</GenerateAnimation>
|
|
49
|
+
</FakeBotMessage>
|
|
50
|
+
)}
|
|
41
51
|
</ConversationContent>
|
|
42
52
|
<ConversationScrollButton />
|
|
43
53
|
</Conversation>
|
|
@@ -9,15 +9,17 @@ import { IconBtn } from '@/components/bs-ui/icon-btn';
|
|
|
9
9
|
export const ClearBtn = ({
|
|
10
10
|
setMessages,
|
|
11
11
|
status,
|
|
12
|
+
chatId,
|
|
12
13
|
}: {
|
|
13
14
|
setMessages: UseChatHelpers<ChatMessage>['setMessages'];
|
|
14
15
|
status: UseChatHelpers<ChatMessage>['status'];
|
|
16
|
+
chatId: string;
|
|
15
17
|
}) => {
|
|
16
18
|
const { exec: onBeforeClearMsg = () => {} } =
|
|
17
19
|
usePluginLifeCycleChainRunner('onBeforeMessagesClear');
|
|
18
20
|
|
|
19
21
|
const clearMsg = useCallback(() => {
|
|
20
|
-
onBeforeClearMsg(
|
|
22
|
+
onBeforeClearMsg(chatId);
|
|
21
23
|
setMessages(() => []);
|
|
22
24
|
}, [onBeforeClearMsg, setMessages]);
|
|
23
25
|
|
|
@@ -28,6 +28,8 @@ import { IconBtn } from '@/components/bs-ui/icon-btn';
|
|
|
28
28
|
import { DividerIcon, PlaneIcon, UploadIcon } from '@/components/bs-ui/bs-icons';
|
|
29
29
|
import { useChatPreference } from '@/hooks/use-chat-preference';
|
|
30
30
|
import { useToast } from '@/hooks/use-toast';
|
|
31
|
+
import { BsTooltip } from '@/components/bs-ui/tooltip';
|
|
32
|
+
import { useChatStatus } from '@/hooks/use-frame-mode';
|
|
31
33
|
|
|
32
34
|
function PureMultimodalInput({
|
|
33
35
|
chatId,
|
|
@@ -59,19 +61,28 @@ function PureMultimodalInput({
|
|
|
59
61
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
60
62
|
const adjustHeight = useCallback(() => {
|
|
61
63
|
if (textareaRef.current) {
|
|
62
|
-
textareaRef.current.style.height = '
|
|
64
|
+
textareaRef.current.style.height = '';
|
|
63
65
|
}
|
|
64
66
|
}, []);
|
|
65
67
|
|
|
68
|
+
const { status: chatUIStatus } = useChatStatus();
|
|
69
|
+
|
|
66
70
|
useEffect(() => {
|
|
67
71
|
if (textareaRef.current) {
|
|
68
72
|
adjustHeight();
|
|
69
73
|
}
|
|
70
74
|
}, [adjustHeight]);
|
|
71
75
|
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (chatUIStatus === 'hide') {
|
|
78
|
+
clearAttachmentsAndUploadQueue();
|
|
79
|
+
setInput('');
|
|
80
|
+
}
|
|
81
|
+
}, [chatUIStatus]);
|
|
82
|
+
|
|
72
83
|
const resetHeight = useCallback(() => {
|
|
73
84
|
if (textareaRef.current) {
|
|
74
|
-
textareaRef.current.style.height = '
|
|
85
|
+
textareaRef.current.style.height = '';
|
|
75
86
|
}
|
|
76
87
|
}, []);
|
|
77
88
|
|
|
@@ -92,38 +103,48 @@ function PureMultimodalInput({
|
|
|
92
103
|
const [uploadQueue, setUploadQueue] = useState<string[]>([]);
|
|
93
104
|
|
|
94
105
|
const { exec: onBeforeSendMsg } = usePluginLifeCycleChainRunner('onBeforeMessageSend');
|
|
106
|
+
const { exec: onAfterSendMsg } = usePluginLifeCycleChainRunner('onAfterMessageSend');
|
|
95
107
|
|
|
96
108
|
const placeholder = useChatPreference()?.placeholder || 'Send a message...';
|
|
97
109
|
const maxCount = useChatPreference()?.acceptAttachmentMaxCount || 5;
|
|
98
110
|
const maxSizeMb = useChatPreference()?.acceptAttachmentMaxSizeMb || 100;
|
|
99
111
|
const tooltip = `上传附件(仅识别文字),最多${maxCount}个,单个文件最大${maxSizeMb}MB`;
|
|
100
112
|
|
|
113
|
+
const clearAttachmentsAndUploadQueue = useCallback(() => {
|
|
114
|
+
setAttachments([]);
|
|
115
|
+
setUploadQueue([]);
|
|
116
|
+
if (fileInputRef.current) {
|
|
117
|
+
fileInputRef.current.value = '';
|
|
118
|
+
}
|
|
119
|
+
}, [setAttachments]);
|
|
120
|
+
|
|
101
121
|
const submitForm = useCallback(() => {
|
|
102
122
|
const finalMsg = onBeforeSendMsg({
|
|
103
123
|
text: input,
|
|
104
124
|
});
|
|
105
125
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
uploadMetadata: attachment,
|
|
117
|
-
},
|
|
118
|
-
})),
|
|
119
|
-
{
|
|
120
|
-
type: 'text',
|
|
121
|
-
text: input,
|
|
126
|
+
const msg = {
|
|
127
|
+
role: 'user',
|
|
128
|
+
parts: [
|
|
129
|
+
...attachments.map((attachment) => ({
|
|
130
|
+
type: 'file' as const,
|
|
131
|
+
url: attachment.url,
|
|
132
|
+
name: attachment.name,
|
|
133
|
+
mediaType: attachment.contentType,
|
|
134
|
+
providerMetadata: {
|
|
135
|
+
uploadMetadata: attachment,
|
|
122
136
|
},
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
137
|
+
})),
|
|
138
|
+
{
|
|
139
|
+
type: 'text',
|
|
140
|
+
text: input,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
} as ChatMessage;
|
|
144
|
+
|
|
145
|
+
sendMessage(msg, finalMsg.options);
|
|
146
|
+
|
|
147
|
+
onAfterSendMsg?.(msg);
|
|
127
148
|
|
|
128
149
|
setAttachments([]);
|
|
129
150
|
resetHeight();
|
|
@@ -310,15 +331,12 @@ function PureMultimodalInput({
|
|
|
310
331
|
)}
|
|
311
332
|
<div className="flex flex-row items-start gap-1 sm:gap-2">
|
|
312
333
|
<PromptInputTextarea
|
|
313
|
-
className="grow resize-none border-0! border-none! bg-transparent p-0 text-base outline-none ring-0
|
|
334
|
+
className="grow resize-none border-0! border-none! bg-transparent p-0 text-base outline-none ring-0 placeholder:text-[#999] focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 text-[#12111]"
|
|
314
335
|
data-testid="multimodal-input"
|
|
315
|
-
disableAutoResize={true}
|
|
316
|
-
maxHeight={200}
|
|
317
|
-
minHeight={44}
|
|
318
336
|
onChange={handleInput}
|
|
319
337
|
placeholder={placeholder}
|
|
320
338
|
ref={textareaRef}
|
|
321
|
-
rows={
|
|
339
|
+
rows={3}
|
|
322
340
|
value={input}
|
|
323
341
|
/>
|
|
324
342
|
</div>
|
|
@@ -328,7 +346,7 @@ function PureMultimodalInput({
|
|
|
328
346
|
{hasAcceptableFileType ? (
|
|
329
347
|
<AttachmentsButton fileInputRef={fileInputRef} status={status} tooltip={tooltip} />
|
|
330
348
|
) : null}
|
|
331
|
-
<ClearBtn setMessages={setMessages} status={status} />
|
|
349
|
+
<ClearBtn setMessages={setMessages} status={status} chatId={chatId} />
|
|
332
350
|
<DividerIcon />
|
|
333
351
|
{status === 'submitted' || status === 'streaming' ? (
|
|
334
352
|
<StopButton setMessages={setMessages} stop={stop} />
|
|
@@ -396,16 +414,18 @@ function PureStopButton({
|
|
|
396
414
|
setMessages: UseChatHelpers<ChatMessage>['setMessages'];
|
|
397
415
|
}) {
|
|
398
416
|
return (
|
|
399
|
-
<
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
event
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
417
|
+
<BsTooltip content="停止生成">
|
|
418
|
+
<Button
|
|
419
|
+
className="cursor-pointer rounded-full bg-[#0265FF] text-primary-foreground transition-colors duration-200 hover:bg-[#0265FF]/90 disabled:bg-[#E5E6EB] disabled:text-white h-[26px] w-[26px] flex items-center justify-center aspect-square p-0 disabled:!opacity-100"
|
|
420
|
+
onClick={(event: any) => {
|
|
421
|
+
event.preventDefault();
|
|
422
|
+
stop();
|
|
423
|
+
setMessages((messages) => messages);
|
|
424
|
+
}}
|
|
425
|
+
>
|
|
426
|
+
<div className="rounded-[2px] w-[8px] h-[8px] bg-white flex-shrink-0" />
|
|
427
|
+
</Button>
|
|
428
|
+
</BsTooltip>
|
|
409
429
|
);
|
|
410
430
|
}
|
|
411
431
|
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { Textarea } from '@/components/ui/textarea';
|
|
15
15
|
import { cn } from '@/lib/utils';
|
|
16
16
|
import { StopIcon } from '@/components/bs-ui/bs-icons';
|
|
17
|
+
import { BsTooltip } from '@/components/bs-ui/tooltip';
|
|
17
18
|
|
|
18
19
|
export type PromptInputProps = HTMLAttributes<HTMLFormElement>;
|
|
19
20
|
|
|
@@ -77,7 +78,7 @@ export const PromptInputTextarea = react.forwardRef<HTMLTextAreaElement, PromptI
|
|
|
77
78
|
? 'field-sizing-fixed'
|
|
78
79
|
: resizeOnNewLinesOnly
|
|
79
80
|
? 'field-sizing-fixed'
|
|
80
|
-
: 'field-sizing-content max-h-[
|
|
81
|
+
: 'field-sizing-content min-h-[3lh] max-h-[8lh]',
|
|
81
82
|
'bg-transparent dark:bg-transparent',
|
|
82
83
|
'focus-visible:ring-0',
|
|
83
84
|
className
|
|
@@ -171,15 +172,17 @@ export const PromptInputSubmit = ({
|
|
|
171
172
|
let Icon = getIconForStatus(status);
|
|
172
173
|
|
|
173
174
|
return (
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
175
|
+
<BsTooltip content="发送">
|
|
176
|
+
<Button
|
|
177
|
+
className={cn('gap-1.5 rounded-full', className)}
|
|
178
|
+
size={size}
|
|
179
|
+
type="submit"
|
|
180
|
+
variant={variant}
|
|
181
|
+
{...props}
|
|
182
|
+
>
|
|
183
|
+
{children ?? Icon}
|
|
184
|
+
</Button>
|
|
185
|
+
</BsTooltip>
|
|
183
186
|
);
|
|
184
187
|
};
|
|
185
188
|
|
|
@@ -38,9 +38,9 @@ export const PreviewMessageWrapper = ({
|
|
|
38
38
|
avatarComInfo?.Component;
|
|
39
39
|
const avatarJsx = Avatar ? <Avatar /> : <BotAvatarAndName name={'AI表单搭建'} />;
|
|
40
40
|
|
|
41
|
-
const [isHovered, setIsHovered] = useState(false);
|
|
41
|
+
// const [isHovered, setIsHovered] = useState(false);
|
|
42
42
|
|
|
43
|
-
const showAction = isBot && isHovered
|
|
43
|
+
const showAction = isBot && /* isHovered &&*/ !isLoading;
|
|
44
44
|
|
|
45
45
|
const visibilityCls = showAction ? 'opacity-100' : 'opacity-0';
|
|
46
46
|
const pointerEventsCls = showAction ? 'pointer-events-auto' : 'pointer-events-none';
|
|
@@ -77,8 +77,8 @@ export const PreviewMessageWrapper = ({
|
|
|
77
77
|
className="group/message w-full"
|
|
78
78
|
data-role={role}
|
|
79
79
|
data-testid={`message-${role}`}
|
|
80
|
-
onMouseEnter={() => setIsHovered(true)}
|
|
81
|
-
onMouseLeave={() => setIsHovered(false)}
|
|
80
|
+
// onMouseEnter={() => setIsHovered(true)}
|
|
81
|
+
// onMouseLeave={() => setIsHovered(false)}
|
|
82
82
|
>
|
|
83
83
|
<div
|
|
84
84
|
className={cn('flex w-full justify-start flex-col gap-2.5', {
|
|
@@ -20,7 +20,7 @@ import { WarningMessage } from '../bs-ui/warning-msg';
|
|
|
20
20
|
import { GenerateAnimation } from '../bs-ui/generate-animation';
|
|
21
21
|
import { AttachmentPartGroup } from '../bs-ui/attachment-part-group';
|
|
22
22
|
import { AttachmentPart } from '../bs-ui/attachment-part';
|
|
23
|
-
import { useChatStatus } from '@/hooks/use-frame-mode';
|
|
23
|
+
import { useChatStatus, useFakeGlobalLoadingMessage } from '@/hooks/use-frame-mode';
|
|
24
24
|
import { useEvtBus } from '@/hooks/use-evt-bus';
|
|
25
25
|
|
|
26
26
|
const PurePreviewMessage = ({
|
|
@@ -73,6 +73,7 @@ const PurePreviewMessage = ({
|
|
|
73
73
|
const evtBus = useEvtBus();
|
|
74
74
|
|
|
75
75
|
const { exec: onBeforeSendMsg } = usePluginLifeCycleChainRunner('onBeforeMessageSend');
|
|
76
|
+
const { exec: onAfterSendMsg } = usePluginLifeCycleChainRunner('onAfterMessageSend');
|
|
76
77
|
|
|
77
78
|
const handleCopy = () => {
|
|
78
79
|
const textParts = message.parts
|
|
@@ -97,6 +98,7 @@ const PurePreviewMessage = ({
|
|
|
97
98
|
messageId: message.id,
|
|
98
99
|
...options,
|
|
99
100
|
});
|
|
101
|
+
onAfterSendMsg(message);
|
|
100
102
|
};
|
|
101
103
|
|
|
102
104
|
if (chatStatus.isHide) {
|
|
@@ -31,12 +31,14 @@ export const SuggestionCard = ({
|
|
|
31
31
|
const defaultSuggestions: ISuggestion[] = [
|
|
32
32
|
{
|
|
33
33
|
icon: <UserIcon />,
|
|
34
|
+
iconCode: '',
|
|
34
35
|
title: '供应商管理,子表单为产品信息',
|
|
35
36
|
description:
|
|
36
37
|
'用于记录和管理企业供应商的基本信息、资质认证、合作状态等,便于采购部门进行供应商评估和选择。',
|
|
37
38
|
},
|
|
38
39
|
{
|
|
39
40
|
icon: <BagIcon />,
|
|
41
|
+
iconCode: '',
|
|
40
42
|
title: '搭建订单表',
|
|
41
43
|
description:
|
|
42
44
|
'子表单为商品列表(包含:商品ID、商品名称、商品供应商为关联数据字段、商品原价、商品销售价、商品型号为关联查询字段)',
|
|
@@ -48,6 +50,7 @@ const defaultSuggestions: ISuggestion[] = [
|
|
|
48
50
|
// },
|
|
49
51
|
{
|
|
50
52
|
icon: <BuildingIcon />,
|
|
53
|
+
iconCode: '',
|
|
51
54
|
title: '创建合同表关联供应商信息管理表',
|
|
52
55
|
description:
|
|
53
56
|
'创建合同表用于记录与供应商签订的合同信息,并与供应商信息管理表进行关联,方便查询和管理合同相关的供应商信息。',
|
|
@@ -61,13 +64,14 @@ export const Suggestions = ({
|
|
|
61
64
|
}: {
|
|
62
65
|
items?: ISuggestion[];
|
|
63
66
|
iconColor?: string;
|
|
64
|
-
onSelect?: (title: string) => void;
|
|
67
|
+
onSelect?: (title: string, iconCode?: string) => void;
|
|
65
68
|
}) => {
|
|
66
69
|
return (
|
|
67
70
|
<>
|
|
68
71
|
{items.map((item, index) => (
|
|
69
72
|
<BsCard
|
|
70
73
|
icon={<div style={{ color: iconColor }}>{item.icon}</div>}
|
|
74
|
+
iconCode={item.iconCode}
|
|
71
75
|
index={index + 1}
|
|
72
76
|
key={index}
|
|
73
77
|
title={item.title}
|
|
@@ -238,7 +238,10 @@ export const AttachmentsPreviewer = ({
|
|
|
238
238
|
return (
|
|
239
239
|
<div
|
|
240
240
|
key={attachment.id}
|
|
241
|
-
className={cn(
|
|
241
|
+
className={cn(
|
|
242
|
+
'relative shrink-0 cursor-pointer group border border-[#e0e0e0] rounded-[10px]',
|
|
243
|
+
transCls
|
|
244
|
+
)}
|
|
242
245
|
style={{ width: imageSize, height: imageSize }}
|
|
243
246
|
onClick={() => onImageClick?.(attachment, index)}
|
|
244
247
|
>
|
|
@@ -5,10 +5,11 @@ import { transCls } from '@/const/ui';
|
|
|
5
5
|
|
|
6
6
|
export interface BaseButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
7
|
icon?: ReactNode;
|
|
8
|
+
hoverTextCls?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export const BaseButton = forwardRef<HTMLButtonElement, BaseButtonProps>(
|
|
11
|
-
({ className, children, icon, type, ...rest }, ref) => {
|
|
12
|
+
({ className, children, hoverTextCls, icon, type, ...rest }, ref) => {
|
|
12
13
|
return (
|
|
13
14
|
<button
|
|
14
15
|
ref={ref}
|
|
@@ -17,8 +18,12 @@ export const BaseButton = forwardRef<HTMLButtonElement, BaseButtonProps>(
|
|
|
17
18
|
'group inline-flex items-center gap-[6px] px-[16px] rounded-[4px] h-[34px]',
|
|
18
19
|
'border border-[#E0E0E0] bg-transparent',
|
|
19
20
|
'text-[14px] font-[400] leading-[normal] text-[#030303]',
|
|
20
|
-
'hover:bg-[#EFF0F6] hover:
|
|
21
|
+
'hover:bg-[#EFF0F6] hover:border-transparent',
|
|
21
22
|
'cursor-pointer',
|
|
23
|
+
{
|
|
24
|
+
'hover:text-[#0265FF]': !hoverTextCls,
|
|
25
|
+
[`hover:${hoverTextCls}`]: hoverTextCls,
|
|
26
|
+
},
|
|
22
27
|
transCls,
|
|
23
28
|
className
|
|
24
29
|
)}
|
|
@@ -1065,3 +1065,32 @@ export const DashLayoutContainerIcon = () => (
|
|
|
1065
1065
|
/>
|
|
1066
1066
|
</svg>
|
|
1067
1067
|
);
|
|
1068
|
+
|
|
1069
|
+
export const DataViewIcon = () => (
|
|
1070
|
+
<svg
|
|
1071
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1072
|
+
width="20"
|
|
1073
|
+
height="20"
|
|
1074
|
+
viewBox="0 0 20 20"
|
|
1075
|
+
fill="currentColor"
|
|
1076
|
+
>
|
|
1077
|
+
<path d="M16.25 1.25C16.9404 1.25 17.5 1.80964 17.5 2.5V5C17.5 5.69036 16.9404 6.25 16.25 6.25H3.75C3.05964 6.25 2.5 5.69036 2.5 5V2.5C2.5 1.80964 3.05964 1.25 3.75 1.25H16.25ZM6.25 2.5C5.55964 2.5 5 3.05964 5 3.75C5 4.44036 5.55964 5 6.25 5C6.94036 5 7.5 4.44036 7.5 3.75C7.5 3.05964 6.94036 2.5 6.25 2.5Z" />
|
|
1078
|
+
<path d="M16.25 7.5C16.9404 7.5 17.5 8.05964 17.5 8.75V11.25C17.5 11.9404 16.9404 12.5 16.25 12.5H3.75C3.05964 12.5 2.5 11.9404 2.5 11.25V8.75C2.5 8.05964 3.05964 7.5 3.75 7.5H16.25ZM6.25 8.75C5.55964 8.75 5 9.30964 5 10C5 10.6904 5.55964 11.25 6.25 11.25C6.94036 11.25 7.5 10.6904 7.5 10C7.5 9.30964 6.94036 8.75 6.25 8.75Z" />
|
|
1079
|
+
<path d="M16.25 13.75C16.9404 13.75 17.5 14.3096 17.5 15V17.5C17.5 18.1904 16.9404 18.75 16.25 18.75H3.75C3.05964 18.75 2.5 18.1904 2.5 17.5V15C2.5 14.3096 3.05964 13.75 3.75 13.75H16.25ZM6.25 15C5.55964 15 5 15.5596 5 16.25C5 16.9404 5.55964 17.5 6.25 17.5C6.94036 17.5 7.5 16.9404 7.5 16.25C7.5 15.5596 6.94036 15 6.25 15Z" />
|
|
1080
|
+
</svg>
|
|
1081
|
+
);
|
|
1082
|
+
|
|
1083
|
+
export const DataReportIcon = () => (
|
|
1084
|
+
<svg
|
|
1085
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1086
|
+
width="20"
|
|
1087
|
+
height="20"
|
|
1088
|
+
viewBox="0 0 20 20"
|
|
1089
|
+
fill="currentColor"
|
|
1090
|
+
>
|
|
1091
|
+
<path
|
|
1092
|
+
d="M1.25 18.2377V15.9502H18.75V18.2377H1.25ZM16.4075 5.4427L16.4062 6.6677L16.4075 6.66895V14.7227L16.4062 14.7214L16.4075 14.7239H12.8912V5.4427H16.4075ZM11.7212 1.7627L11.72 3.1177H11.7212V14.7239H9.4875V14.7227H8.205V1.7627H11.7212ZM7.035 7.76644L7.03375 9.08395L7.035 9.0852V14.7239L3.52 14.7227V7.76644H7.035Z"
|
|
1093
|
+
// fill=""
|
|
1094
|
+
/>
|
|
1095
|
+
</svg>
|
|
1096
|
+
);
|
|
@@ -7,10 +7,11 @@ export interface CardProps {
|
|
|
7
7
|
desc?: string;
|
|
8
8
|
index?: number;
|
|
9
9
|
icon?: ReactNode;
|
|
10
|
-
|
|
10
|
+
iconCode?: string;
|
|
11
|
+
onClick?: (title: string, iconCode?: string) => void;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
export const Card = ({ title, desc, index, icon, onClick }: CardProps) => {
|
|
14
|
+
export const Card = ({ title, desc, index, icon, onClick, iconCode }: CardProps) => {
|
|
14
15
|
return (
|
|
15
16
|
<div
|
|
16
17
|
className={cn(
|
|
@@ -20,7 +21,7 @@ export const Card = ({ title, desc, index, icon, onClick }: CardProps) => {
|
|
|
20
21
|
}
|
|
21
22
|
)}
|
|
22
23
|
onClick={() => {
|
|
23
|
-
onClick?.(title);
|
|
24
|
+
onClick?.(title, iconCode);
|
|
24
25
|
}}
|
|
25
26
|
>
|
|
26
27
|
<div className="px-2.5 flex items-center gap-1.5 rounded-[4px] h-[34px] bg-white">
|