@baishuyun/chat-sdk 0.0.17 → 0.0.18
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 +178 -115
- package/CHANGELOG.md +8 -0
- package/dist/chat-sdk.js +26425 -34262
- package/dist/chat-sdk.js.map +1 -1
- package/dist/chat-sdk.umd.cjs +219 -296
- package/dist/chat-sdk.umd.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/package.json +4 -4
- package/src/chat.tsx +4 -1
- package/src/components/biz-comp/chat-client.tsx +1 -1
- package/src/components/biz-comp/multi-modal-input/index.tsx +22 -5
- package/src/components/biz-comp/preview-message.tsx +25 -3
- package/src/components/bs-ui/attachment-part-group.tsx +5 -2
- package/src/components/bs-ui/attachment-part.tsx +14 -9
- package/src/components/bs-ui/attachments-previewer.tsx +2 -2
- package/src/components/bs-ui/base-button.tsx +14 -4
- package/src/components/bs-ui/border-animation.tsx +107 -0
- package/src/components/bs-ui/bs-icons.tsx +6 -0
- package/src/components/bs-ui/confirm-dialog.tsx +17 -11
- package/src/components/bs-ui/fields-previewer.tsx +16 -8
- package/src/components/bs-ui/img-part.tsx +4 -2
- package/src/components/bs-ui/previewer-header.tsx +26 -7
- package/src/components/bs-ui/primary-entry-btn.tsx +2 -1
- package/src/index.tsx +0 -1
- package/src/lib/utils.ts +60 -2
- package/src/plugins/form-builder-plugin/components/create-form-confirm.tsx +0 -2
- package/src/plugins/form-builder-plugin/components/design-doc-part.tsx +19 -0
- package/src/plugins/form-builder-plugin/components/fields-part.tsx +78 -0
- package/src/plugins/form-builder-plugin/components/msg-part.tsx +20 -165
- package/src/plugins/form-builder-plugin/components/suggestion-part.tsx +62 -0
- package/src/plugins/form-builder-plugin/hooks/index.tsx +50 -0
- package/src/plugins/form-builder-plugin/index.ts +39 -30
- package/src/plugins/form-builder-plugin/types.ts +19 -2
- package/src/plugins/form-builder-plugin/utils/get-render-strategy.ts +27 -0
- package/src/plugins/form-builder-plugin/utils/index.ts +44 -37
- package/src/plugins/form-filling-plugin/components/FormFillingOpeningLines.tsx +4 -0
- package/src/plugins/form-filling-plugin/components/batch-fill-part.tsx +17 -0
- package/src/plugins/form-filling-plugin/components/batch-generator-action.tsx +6 -1
- package/src/plugins/form-filling-plugin/components/entry-btn.tsx +1 -1
- package/src/plugins/form-filling-plugin/components/first-batch-generating-animation.tsx +6 -16
- package/src/plugins/form-filling-plugin/components/msg-part.tsx +39 -122
- package/src/plugins/form-filling-plugin/components/non-first-batch-generating-animation.tsx +9 -19
- package/src/plugins/form-filling-plugin/components/single-fill-part.tsx +42 -0
- package/src/plugins/form-filling-plugin/hooks/use-conversation-id-in-ctx.ts +13 -0
- package/src/plugins/form-filling-plugin/hooks/use-fields-data.ts +110 -0
- package/src/plugins/form-filling-plugin/index.ts +49 -43
- package/src/plugins/form-filling-plugin/types.ts +19 -1
- package/src/plugins/report-query-plugin/components/query-msg-part.tsx +13 -4
- package/src/plugins/report-query-plugin/index.ts +20 -11
- package/src/store/index.ts +0 -1
- package/src/stories/BorderAnimation.stories.tsx +116 -0
- package/src/stories/PreviewerHeader.stories.tsx +24 -0
- package/src/style.css +25 -0
- package/src/plugins/form-builder-plugin/hooks/index.ts +0 -0
- package/src/plugins/general-model-form-builder-plugin/components/confirmer.tsx +0 -90
- package/src/plugins/general-model-form-builder-plugin/components/ghost-evt-dispatcher.tsx +0 -69
- package/src/plugins/general-model-form-builder-plugin/components/msg-part.tsx +0 -147
- package/src/plugins/general-model-form-builder-plugin/components/new-confirmer.tsx +0 -191
- package/src/plugins/general-model-form-builder-plugin/const.ts +0 -3
- package/src/plugins/general-model-form-builder-plugin/index.ts +0 -20
- package/src/plugins/general-model-form-builder-plugin/types.ts +0 -1
|
@@ -29,14 +29,6 @@ function getMatchResult(origin: string, pattern: RegExp) {
|
|
|
29
29
|
return matches ? matches[1] : '';
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function ensureFormNameSuffix(name: string, suffix: string = '表') {
|
|
33
|
-
if (name.endsWith(suffix)) {
|
|
34
|
-
return name;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return name + suffix;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
32
|
function extraFormNameFromFieldDesc(desc?: string) {
|
|
41
33
|
if (!desc) {
|
|
42
34
|
return '';
|
|
@@ -46,10 +38,7 @@ function extraFormNameFromFieldDesc(desc?: string) {
|
|
|
46
38
|
const patternLib = [/关联来源:(.*)表?,/, /关联(.*)表?/, /(从(.*)表?中查询)/, /来自(.*)表?/];
|
|
47
39
|
|
|
48
40
|
for (const pattern of patternLib) {
|
|
49
|
-
|
|
50
|
-
if (result) {
|
|
51
|
-
return ensureFormNameSuffix(result);
|
|
52
|
-
}
|
|
41
|
+
return getMatchResult(desc, pattern);
|
|
53
42
|
}
|
|
54
43
|
|
|
55
44
|
return '';
|
|
@@ -75,6 +64,7 @@ export function parseRawFormText(rawText: string): IFieldDesignInfo[] {
|
|
|
75
64
|
const lines = rawText.split('\n').filter((line) => line.trim());
|
|
76
65
|
const fields: IFieldDesignInfo[] = [];
|
|
77
66
|
|
|
67
|
+
let subFormName = '';
|
|
78
68
|
lines.forEach((line) => {
|
|
79
69
|
// 分割字段名和属性(如:合同编号 | 类型:流水号 | 必填:是 | 说明:xxx)
|
|
80
70
|
let [fieldName, typePart, requiredPart, descPart, relationPart = ''] = line
|
|
@@ -89,6 +79,10 @@ export function parseRawFormText(rawText: string): IFieldDesignInfo[] {
|
|
|
89
79
|
const typeMatch = typePart.match(/类型:(.*)/);
|
|
90
80
|
const type = typeMatch ? typeMatch[1] : '';
|
|
91
81
|
|
|
82
|
+
if (type === '子表单') {
|
|
83
|
+
subFormName = fieldName;
|
|
84
|
+
}
|
|
85
|
+
|
|
92
86
|
// 提取必填状态
|
|
93
87
|
const requiredMatch = requiredPart.match(/必填:(\w+)/);
|
|
94
88
|
const required = requiredMatch ? requiredMatch[1] === '是' : false;
|
|
@@ -107,8 +101,10 @@ export function parseRawFormText(rawText: string): IFieldDesignInfo[] {
|
|
|
107
101
|
const parsedDesc = parseDesc(description);
|
|
108
102
|
|
|
109
103
|
const splitFieldName = fieldName.split('-');
|
|
110
|
-
const isFieldInSubForm =
|
|
111
|
-
|
|
104
|
+
const isFieldInSubForm =
|
|
105
|
+
splitFieldName.length > 1 || parsedDesc.isSubForm || description.includes('子表单字段');
|
|
106
|
+
const parentFormName =
|
|
107
|
+
(isFieldInSubForm ? splitFieldName[0] || parsedDesc.formName : undefined) || subFormName;
|
|
112
108
|
|
|
113
109
|
fields.push({
|
|
114
110
|
fieldName: isFieldInSubForm ? splitFieldName[splitFieldName.length - 1] : fieldName,
|
|
@@ -134,8 +130,8 @@ function extractLinkInfo(fields: IFieldDesignInfo[]): Map<string, LinkInfo> {
|
|
|
134
130
|
// 仅处理关联查询类型的字段
|
|
135
131
|
if (field.type === '关联查询' || field.type === '关联数据') {
|
|
136
132
|
const targetFormName =
|
|
137
|
-
extraFormNameFromFieldDesc(field.
|
|
138
|
-
extraFormNameFromFieldDesc(field.
|
|
133
|
+
extraFormNameFromFieldDesc(field.description) ||
|
|
134
|
+
extraFormNameFromFieldDesc(field.relationDesc);
|
|
139
135
|
const fieldNameMatch = field.fieldName.match(/\d+\. (.*)/);
|
|
140
136
|
const fName = fieldNameMatch ? fieldNameMatch[1] : field.fieldName;
|
|
141
137
|
|
|
@@ -155,6 +151,10 @@ function extractLinkInfo(fields: IFieldDesignInfo[]): Map<string, LinkInfo> {
|
|
|
155
151
|
return linkInfoMap;
|
|
156
152
|
}
|
|
157
153
|
|
|
154
|
+
export const ensureCleanFormName = (name: string) => {
|
|
155
|
+
return name.replace(/表单|表|管理表/g, '').trim();
|
|
156
|
+
};
|
|
157
|
+
|
|
158
158
|
/**
|
|
159
159
|
* 解析 mcp 返回的表单设计文档,提取关联信息
|
|
160
160
|
* @param designDoc
|
|
@@ -163,7 +163,7 @@ function extractLinkInfo(fields: IFieldDesignInfo[]): Map<string, LinkInfo> {
|
|
|
163
163
|
export const parseFormDesignInfo = (designDoc: string): DesignInfo => {
|
|
164
164
|
return {
|
|
165
165
|
linkInfoMap: extractLinkInfo(parseRawFormText(designDoc)),
|
|
166
|
-
formName: extractFormName(designDoc),
|
|
166
|
+
formName: ensureCleanFormName(extractFormName(designDoc)),
|
|
167
167
|
};
|
|
168
168
|
};
|
|
169
169
|
|
|
@@ -242,23 +242,30 @@ export const formFieldsWalker = (
|
|
|
242
242
|
for (const [name, info] of infoMap) {
|
|
243
243
|
isDirty = false;
|
|
244
244
|
|
|
245
|
-
if (!isTargetForm(name, info)) {
|
|
246
|
-
console.log('不是目标表单,不处理');
|
|
245
|
+
if (!isTargetForm(ensureCleanFormName(name), info)) {
|
|
246
|
+
console.log('[formFieldsWalker]', '不是目标表单,不处理', name, info);
|
|
247
247
|
continue;
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
const linkMap = info.designInfo.linkInfoMap;
|
|
251
251
|
|
|
252
252
|
for (const [fieldName, linkInfo] of linkMap) {
|
|
253
|
-
if (isTargetField(fieldName, linkInfo)) {
|
|
254
|
-
|
|
253
|
+
if (!isTargetField(fieldName, linkInfo)) {
|
|
254
|
+
console.log('[formFieldsWalker]', '不是目标字段,不处理', name, info, fieldName);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
255
257
|
|
|
256
|
-
|
|
258
|
+
const targetField = info.fieldMap.get(fieldName);
|
|
259
|
+
if (!targetField) {
|
|
260
|
+
console.log('[formFieldsWalker]', '未找到目标字段,不处理', name, info, fieldName);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
257
263
|
|
|
258
|
-
|
|
264
|
+
const result = fieldProcessor(info, targetField, linkInfo);
|
|
259
265
|
|
|
260
|
-
|
|
261
|
-
|
|
266
|
+
isDirty = true;
|
|
267
|
+
|
|
268
|
+
info.fieldMap.set(fieldName, result);
|
|
262
269
|
}
|
|
263
270
|
|
|
264
271
|
if (isDirty) {
|
|
@@ -360,30 +367,30 @@ export const enhanceLinkField = (
|
|
|
360
367
|
formMap: Map<string, FormInfo>,
|
|
361
368
|
onEnhanced: (processed?: Field) => void
|
|
362
369
|
): Field => {
|
|
363
|
-
console.log(field, linkInfo, formMap);
|
|
370
|
+
console.log('开始关联字段处理', field, linkInfo, formMap);
|
|
364
371
|
|
|
365
372
|
// 非关联字段直接返回
|
|
366
373
|
if (!isLinkField(field)) {
|
|
367
|
-
console.log('非关联字段,跳过处理', field);
|
|
374
|
+
console.log('[enhanceLinkField] 非关联字段,跳过处理', field);
|
|
368
375
|
return field;
|
|
369
376
|
}
|
|
370
377
|
|
|
371
378
|
// 无关联信息直接返回
|
|
372
379
|
if (!linkInfo.targetFormName) {
|
|
373
|
-
console.log('无关联信息,跳过处理', field);
|
|
380
|
+
console.log('[enhanceLinkField] 无关联信息,跳过处理', field);
|
|
374
381
|
return field;
|
|
375
382
|
}
|
|
376
383
|
|
|
377
384
|
// 无表单映射直接返回
|
|
378
385
|
if (formMap.size === 0) {
|
|
379
|
-
console.log('无表单映射,跳过处理', field);
|
|
386
|
+
console.log('[enhanceLinkField] 无表单映射,跳过处理', field);
|
|
380
387
|
return field;
|
|
381
388
|
}
|
|
382
389
|
|
|
383
390
|
// 未找到目标表单直接返回
|
|
384
|
-
const targetForm = formMap.get(linkInfo.targetFormName);
|
|
391
|
+
const targetForm = formMap.get(ensureCleanFormName(linkInfo.targetFormName));
|
|
385
392
|
if (!targetForm) {
|
|
386
|
-
console.log('未找到目标表单,跳过处理',
|
|
393
|
+
console.log('[enhanceLinkField] 未找到目标表单,跳过处理', formMap, linkInfo.targetFormName);
|
|
387
394
|
return field;
|
|
388
395
|
}
|
|
389
396
|
|
|
@@ -392,13 +399,13 @@ export const enhanceLinkField = (
|
|
|
392
399
|
field.widget.linkForm = targetForm.formId;
|
|
393
400
|
// field.widget.type = "linkdata";
|
|
394
401
|
} catch (e) {
|
|
395
|
-
console.
|
|
402
|
+
console.log('[enhanceLinkField] 尝试建立表单关联失败');
|
|
396
403
|
return field;
|
|
397
404
|
}
|
|
398
405
|
|
|
399
406
|
const targetSNFieldInTargetForm = targetForm.fields.find(isSNField);
|
|
400
407
|
if (!targetSNFieldInTargetForm) {
|
|
401
|
-
console.log('未找到目标表单的主键字段,跳过处理', field);
|
|
408
|
+
console.log('[enhanceLinkField] 未找到目标表单的主键字段,跳过处理', field);
|
|
402
409
|
return field;
|
|
403
410
|
}
|
|
404
411
|
|
|
@@ -408,14 +415,14 @@ export const enhanceLinkField = (
|
|
|
408
415
|
field.widget.linkKey = targetSNFieldInTargetForm.widget.widgetName;
|
|
409
416
|
field.widget.linkType = 'sn';
|
|
410
417
|
} catch (e) {
|
|
411
|
-
console.
|
|
418
|
+
console.log('[enhanceLinkField] 尝试建立主键关联失败');
|
|
412
419
|
return field;
|
|
413
420
|
}
|
|
414
421
|
}
|
|
415
422
|
|
|
416
423
|
const targetTargetTextFieldInTargetForm = targetForm.fields.find(isTextField);
|
|
417
424
|
if (!targetTargetTextFieldInTargetForm) {
|
|
418
|
-
console.log('未找到目标表单的显示字段,跳过处理', field);
|
|
425
|
+
console.log('[enhanceLinkField] 未找到目标表单的显示字段,跳过处理', field);
|
|
419
426
|
return field;
|
|
420
427
|
}
|
|
421
428
|
|
|
@@ -434,12 +441,12 @@ export const enhanceLinkField = (
|
|
|
434
441
|
// },
|
|
435
442
|
];
|
|
436
443
|
} catch (e) {
|
|
437
|
-
console.
|
|
444
|
+
console.log('[enhanceLinkField] 尝试建立显示字段关联失败');
|
|
438
445
|
return field;
|
|
439
446
|
}
|
|
440
447
|
|
|
441
448
|
// 关联信息已补全
|
|
442
|
-
console.log('关联字段信息已补全', field);
|
|
449
|
+
console.log('[enhanceLinkField] 关联字段信息已补全', field);
|
|
443
450
|
onEnhanced(field);
|
|
444
451
|
return field;
|
|
445
452
|
};
|
|
@@ -6,9 +6,11 @@ import { PrimaryConfirmBtn } from '@/components/bs-ui/primary-confirm-btn';
|
|
|
6
6
|
import { OpeningLinesProps } from '@baishuyun/types';
|
|
7
7
|
import { useEvtBus } from '@/hooks/use-evt-bus';
|
|
8
8
|
import { GetSafeFormStructure } from '../utils';
|
|
9
|
+
import { useFakeGlobalLoadingMessage } from '@/hooks/use-frame-mode';
|
|
9
10
|
|
|
10
11
|
export const FormFillingOpeningLines = ({ sendMessage }: OpeningLinesProps) => {
|
|
11
12
|
const ctx = usePluginCtx<FormFillingPluginCtx, FormFillingPlugin>(PLUGIN_NAME);
|
|
13
|
+
const loading = useFakeGlobalLoadingMessage();
|
|
12
14
|
const evtBus = useEvtBus();
|
|
13
15
|
if (ctx?.fillMode === 'batch') {
|
|
14
16
|
const formStructure = Array.from(ctx?.fieldMap.values() || []);
|
|
@@ -21,6 +23,8 @@ export const FormFillingOpeningLines = ({ sendMessage }: OpeningLinesProps) => {
|
|
|
21
23
|
onClick={() => {
|
|
22
24
|
evtBus.emit('form-filling-batch-fill-begin', {});
|
|
23
25
|
|
|
26
|
+
loading?.setGlobalFakeLoadingMessage('正在处理');
|
|
27
|
+
|
|
24
28
|
sendMessage(
|
|
25
29
|
{
|
|
26
30
|
text: `添加 ${DATA_COUNT_PER_BATCH} 条示例数据`,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MsgPartCompProps } from "@baishuyun/types";
|
|
2
|
+
import { IFieldsData } from "../types";
|
|
3
|
+
import { BatchGeneratorAction } from "./batch-generator-action";
|
|
4
|
+
|
|
5
|
+
export const BatchFillPart: React.FC<MsgPartCompProps & IFieldsData> = (props) => {
|
|
6
|
+
const { id, setMessages, status, fieldsParts, sendMessage } = props;
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<BatchGeneratorAction
|
|
10
|
+
id={id}
|
|
11
|
+
setMessages={setMessages}
|
|
12
|
+
status={status}
|
|
13
|
+
parts={fieldsParts}
|
|
14
|
+
sendMessage={sendMessage}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -13,6 +13,7 @@ import { GeneratedDataCounter } from './generated-data-counter';
|
|
|
13
13
|
import { FirstBatchGeneratingAnimation } from './first-batch-generating-animation';
|
|
14
14
|
import { NonFirstBatchGeneratingAnimation } from './non-first-batch-generating-animation';
|
|
15
15
|
import { usePlugin } from '@/hooks/use-plugin';
|
|
16
|
+
import { useFakeGlobalLoadingMessage } from '@/hooks/use-frame-mode';
|
|
16
17
|
|
|
17
18
|
type FilledField = {
|
|
18
19
|
fieldName: string;
|
|
@@ -24,7 +25,6 @@ type FilledField = {
|
|
|
24
25
|
|
|
25
26
|
const useFillingEvtEmitter = (id: string) => {
|
|
26
27
|
const evtBus = useEvtBus();
|
|
27
|
-
|
|
28
28
|
return useCallback((f: FilledField) => {
|
|
29
29
|
const normalizedValue = valueNormalizer(f.value as string | string[]);
|
|
30
30
|
|
|
@@ -104,6 +104,7 @@ const BaseBatchGeneratorAction = ({
|
|
|
104
104
|
|
|
105
105
|
const evtBus = useEvtBus();
|
|
106
106
|
|
|
107
|
+
|
|
107
108
|
const getRowNum = useCallback(() => {
|
|
108
109
|
if (!fields || fields.length === 0) {
|
|
109
110
|
return 0;
|
|
@@ -159,6 +160,7 @@ const BaseBatchGeneratorAction = ({
|
|
|
159
160
|
<PrimaryConfirmBtn
|
|
160
161
|
text={`继续生成${DATA_COUNT_PER_BATCH}条`}
|
|
161
162
|
className="w-[300px]"
|
|
163
|
+
light
|
|
162
164
|
onClick={() => {
|
|
163
165
|
if (status === 'streaming' || streamingState) {
|
|
164
166
|
return;
|
|
@@ -204,9 +206,12 @@ const PartParser = ({ parts, ...rest }: BatchGeneratorActionProps) => {
|
|
|
204
206
|
|
|
205
207
|
const emit = useFillingEvtEmitter(rest.id);
|
|
206
208
|
|
|
209
|
+
const loadingMsg = useFakeGlobalLoadingMessage();
|
|
210
|
+
|
|
207
211
|
usePartParser(lastPart, (all, latestField) => {
|
|
208
212
|
setFields(all);
|
|
209
213
|
emit(latestField);
|
|
214
|
+
loadingMsg.clearGlobalFakeLoadingMessage();
|
|
210
215
|
});
|
|
211
216
|
|
|
212
217
|
if (!lastPart) {
|
|
@@ -1,21 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BorderAnimation from '@/components/bs-ui/border-animation';
|
|
2
2
|
import { GenerateAnimation } from '@/components/bs-ui/generate-animation';
|
|
3
|
+
import { memo } from 'react';
|
|
3
4
|
|
|
4
|
-
export const FirstBatchGeneratingAnimation = () => {
|
|
5
|
+
export const FirstBatchGeneratingAnimation = memo(() => {
|
|
5
6
|
return (
|
|
6
|
-
<
|
|
7
|
-
width="100%"
|
|
8
|
-
height={40}
|
|
9
|
-
padding={10}
|
|
10
|
-
borderRadius={10}
|
|
11
|
-
bgInset={1000}
|
|
12
|
-
borderWidth={1.5}
|
|
13
|
-
style={{
|
|
14
|
-
display: 'flex',
|
|
15
|
-
alignItems: 'center',
|
|
16
|
-
}}
|
|
17
|
-
>
|
|
7
|
+
<BorderAnimation borderRadius={4} height={40} className="flex items-center px-[10px]">
|
|
18
8
|
<GenerateAnimation>数据生成中,可点击下方按钮暂停</GenerateAnimation>
|
|
19
|
-
</
|
|
9
|
+
</BorderAnimation>
|
|
20
10
|
);
|
|
21
|
-
};
|
|
11
|
+
});
|
|
@@ -1,141 +1,58 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
1
|
import { MarkdownMsgpart } from '@/components/biz-comp/markdown-part';
|
|
3
|
-
import { MessageContent } from '@/components/biz-comp/message-content';
|
|
4
2
|
import { usePluginCtx } from '@/hooks/use-plugin-ctx';
|
|
5
|
-
|
|
6
|
-
import { GetFieldJsonInfo, IsFieldsJsonPart, NeedToAppendFieldsSaveConfirm } from '@/lib/utils';
|
|
7
3
|
import { MsgPartCompProps } from '@baishuyun/types';
|
|
8
4
|
import { TextUIPart } from 'ai';
|
|
9
|
-
import { FILLING_EVENTS, PLUGIN_NAME } from '../const';
|
|
10
|
-
import { FormFillingPluginCtx } from '../types';
|
|
11
|
-
import { useEvtBus } from '@/hooks/use-evt-bus';
|
|
12
|
-
import { FormFillingPlugin } from '..';
|
|
13
|
-
import { valueNormalizer } from '../utils';
|
|
14
|
-
import { FieldValueCheckerProps } from '@/components/biz-comp/FieldValueChecker';
|
|
15
|
-
import { FieldValueCheckerListMsg } from '@/components/biz-comp/FieldCheckerListMsg';
|
|
16
|
-
import { PrimaryConfirmBtn } from '@/components/bs-ui/primary-confirm-btn';
|
|
17
|
-
import { BatchGeneratorAction } from './batch-generator-action';
|
|
18
|
-
import { useEvt } from '@/hooks/use-evt';
|
|
19
|
-
|
|
20
|
-
export const FillMessagePart = (props: MsgPartCompProps) => {
|
|
21
|
-
const { part: p, id, sendMessage, setMessages, status } = props;
|
|
22
|
-
|
|
23
|
-
const part = p as TextUIPart;
|
|
24
5
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
6
|
+
import { PLUGIN_NAME } from '../const';
|
|
7
|
+
import { FillPartRenderStrategy, FillPartRenderStrategyMap, FormFillingPluginCtx, IFieldsData } from '../types';
|
|
8
|
+
import { FormFillingPlugin } from '..';
|
|
9
|
+
import { useConversationIdInCtx } from '../hooks/use-conversation-id-in-ctx';
|
|
10
|
+
import { useFieldsData } from '../hooks/use-fields-data';
|
|
11
|
+
import { BatchFillPart } from './batch-fill-part';
|
|
12
|
+
import { SingleFillPart } from './single-fill-part';
|
|
13
|
+
|
|
14
|
+
const RENDER_STRATEGY_COMPONENT_MAP: FillPartRenderStrategyMap = {
|
|
15
|
+
batch: BatchFillPart,
|
|
16
|
+
single: SingleFillPart,
|
|
17
|
+
markdown: MarkdownMsgpart,
|
|
18
|
+
unknown: (_) => null,
|
|
19
|
+
};
|
|
32
20
|
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
const getRenderStrategy = (ctx: FormFillingPluginCtx | null, fieldsData: IFieldsData, part: any): FillPartRenderStrategy => {
|
|
22
|
+
if (fieldsData.fieldsParts.length && ctx && ctx.fillMode !== 'batch') {
|
|
23
|
+
return 'single';
|
|
35
24
|
}
|
|
36
25
|
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
if (ctx?.fillMode === 'batch' && fieldsData.fieldsParts.length) {
|
|
27
|
+
return 'batch';
|
|
28
|
+
}
|
|
39
29
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
30
|
+
if (part.text !== undefined && part.text.trim() !== '') {
|
|
31
|
+
return 'markdown';
|
|
32
|
+
}
|
|
44
33
|
|
|
45
|
-
|
|
34
|
+
return 'unknown';
|
|
35
|
+
}
|
|
46
36
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const fieldPropsArray: Array<FieldValueCheckerProps | null> = fieldsParts.map((p) => {
|
|
50
|
-
const field = GetFieldJsonInfo(p);
|
|
51
|
-
if (
|
|
52
|
-
!formFillingCtx.fieldMap?.has(field.fieldName) &&
|
|
53
|
-
!formFillingCtx.subFieldsNameMap?.has(field.fieldName)
|
|
54
|
-
) {
|
|
55
|
-
console.warn('unregistered field:', field.fieldName, formFillingCtx.fieldMap);
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
37
|
+
export const FillMessagePart = (props: MsgPartCompProps) => {
|
|
38
|
+
const { part: p, id } = props;
|
|
58
39
|
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
field: {
|
|
62
|
-
label: field.label,
|
|
63
|
-
widget: {
|
|
64
|
-
widgetName: field.fieldName,
|
|
65
|
-
type: field.fieldType,
|
|
66
|
-
value: field.value,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
onLoaded: (f: any) => {
|
|
70
|
-
f.widget.value = normalizedValue;
|
|
71
|
-
formFillingCtx.valueMap.set(f.widget?.widgetName, normalizedValue);
|
|
72
|
-
evtBus.emit(FILLING_EVENTS.FIELD_FILLED_UPDATE, {
|
|
73
|
-
field: f,
|
|
74
|
-
checked: true,
|
|
75
|
-
});
|
|
76
|
-
},
|
|
77
|
-
onChange: (check: boolean, f: any, parentFieldName?: string, row?: number) => {
|
|
78
|
-
if (check) {
|
|
79
|
-
formFillingCtx.valueMap.set(f.widget?.widgetName, normalizedValue);
|
|
80
|
-
}
|
|
81
|
-
evtBus.emit(FILLING_EVENTS.FIELD_FILLED_UPDATE, {
|
|
82
|
-
field: f,
|
|
83
|
-
checked: check,
|
|
84
|
-
parentFieldName,
|
|
85
|
-
rowIndex: row,
|
|
86
|
-
});
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
});
|
|
40
|
+
const part = p as TextUIPart;
|
|
90
41
|
|
|
91
|
-
|
|
42
|
+
const formFillingCtx = usePluginCtx<FormFillingPluginCtx, FormFillingPlugin>(PLUGIN_NAME);
|
|
92
43
|
|
|
93
|
-
|
|
94
|
-
<MessageContent className="gap-0 py-0" compact>
|
|
95
|
-
{status === 'ready' ? `已为你填写${filled.length}个字段` : null}
|
|
96
|
-
<FieldValueCheckerListMsg
|
|
97
|
-
props={filled}
|
|
98
|
-
readonly={confirmed}
|
|
99
|
-
streaming={status === 'streaming'}
|
|
100
|
-
>
|
|
101
|
-
{status === 'ready' ? (
|
|
102
|
-
<PrimaryConfirmBtn
|
|
103
|
-
className="mt-[20px] mb-[10px]"
|
|
104
|
-
disabled={confirmed}
|
|
105
|
-
onClick={() => {
|
|
106
|
-
setConfirmed(true);
|
|
107
|
-
}}
|
|
108
|
-
>
|
|
109
|
-
{confirmed ? '已确认' : '确认'}
|
|
110
|
-
</PrimaryConfirmBtn>
|
|
111
|
-
) : null}
|
|
112
|
-
</FieldValueCheckerListMsg>
|
|
113
|
-
{status === 'ready'
|
|
114
|
-
? '请选择需要的字段添加到表单。你可以补充描述后重新生成,表单中已添加字段在下次生成时保留。'
|
|
115
|
-
: null}
|
|
116
|
-
</MessageContent>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
44
|
+
useConversationIdInCtx(formFillingCtx, id);
|
|
119
45
|
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<BatchGeneratorAction
|
|
123
|
-
id={id}
|
|
124
|
-
setMessages={setMessages}
|
|
125
|
-
status={status}
|
|
126
|
-
parts={fieldsParts}
|
|
127
|
-
sendMessage={sendMessage}
|
|
128
|
-
/>
|
|
129
|
-
);
|
|
130
|
-
}
|
|
46
|
+
const fieldsData = useFieldsData(part, formFillingCtx);
|
|
131
47
|
|
|
132
|
-
|
|
133
|
-
return <PrimaryConfirmBtn>保存</PrimaryConfirmBtn>;
|
|
134
|
-
}
|
|
48
|
+
const renderStrategy = getRenderStrategy(formFillingCtx, fieldsData, part);
|
|
135
49
|
|
|
136
|
-
|
|
137
|
-
return <MarkdownMsgpart {...props} />;
|
|
138
|
-
}
|
|
50
|
+
const Component = RENDER_STRATEGY_COMPONENT_MAP[renderStrategy];
|
|
139
51
|
|
|
140
|
-
return
|
|
52
|
+
return (
|
|
53
|
+
<Component
|
|
54
|
+
{...props}
|
|
55
|
+
{...fieldsData}
|
|
56
|
+
/>
|
|
57
|
+
)
|
|
141
58
|
};
|
|
@@ -1,28 +1,18 @@
|
|
|
1
|
-
import { BorderColorAnimation } from '@/components/bs-ui/border-color-animation';
|
|
2
1
|
import { GenerateAnimation } from '@/components/bs-ui/generate-animation';
|
|
3
2
|
import { PrimaryConfirmBtn } from '@/components/bs-ui/primary-confirm-btn';
|
|
4
3
|
import { DATA_COUNT_PER_BATCH } from '../const';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import BorderAnimation from '@/components/bs-ui/border-animation';
|
|
5
6
|
|
|
6
|
-
export const NonFirstBatchGeneratingAnimation = () => {
|
|
7
|
+
export const NonFirstBatchGeneratingAnimation = memo(() => {
|
|
7
8
|
return (
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
padding={4}
|
|
12
|
-
borderRadius={10}
|
|
13
|
-
bgInset={1000}
|
|
14
|
-
borderWidth={1.5}
|
|
15
|
-
style={{
|
|
16
|
-
display: 'flex',
|
|
17
|
-
alignItems: 'center',
|
|
18
|
-
}}
|
|
19
|
-
>
|
|
20
|
-
<div className="flex flex-col gap-[10px] w-full">
|
|
21
|
-
<GenerateAnimation className='ml-[16px]'>继续生成中,可点击下方暂停按钮暂停</GenerateAnimation>
|
|
9
|
+
<BorderAnimation borderRadius={10} height={110}>
|
|
10
|
+
<div className="flex flex-col gap-[10px] w-full pt-[4px]">
|
|
11
|
+
<GenerateAnimation className='ml-[16px] py-[10px]'>继续生成中,可点击下方暂停按钮暂停</GenerateAnimation>
|
|
22
12
|
<PrimaryConfirmBtn
|
|
23
13
|
className="w-[300px] mx-auto"
|
|
24
|
-
|
|
14
|
+
text={`继续生成${DATA_COUNT_PER_BATCH}条`} disabled />
|
|
25
15
|
</div>
|
|
26
|
-
</
|
|
16
|
+
</BorderAnimation>
|
|
27
17
|
);
|
|
28
|
-
};
|
|
18
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { MsgPartCompProps } from "@baishuyun/types";
|
|
2
|
+
import { IFieldsData } from "../types";
|
|
3
|
+
import { MessageContent } from "@/components/biz-comp/message-content";
|
|
4
|
+
import { FieldValueCheckerListMsg } from "@/components/biz-comp/FieldCheckerListMsg";
|
|
5
|
+
import { PrimaryConfirmBtn } from "@/components/bs-ui/primary-confirm-btn";
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
|
|
8
|
+
export const SingleFillPart: React.FC<MsgPartCompProps & IFieldsData> = (props) => {
|
|
9
|
+
const { status, filledFields} = props;
|
|
10
|
+
const [confirmed, setConfirmed] = useState(false);
|
|
11
|
+
|
|
12
|
+
const prefixTips = status === 'ready' ? `已为你填写${filledFields.length}个字段` : null;
|
|
13
|
+
const suffixTips = status === 'ready'
|
|
14
|
+
? '请选择需要的字段添加到表单。你可以补充描述后重新生成,表单中已添加字段在下次生成时保留。'
|
|
15
|
+
: null;
|
|
16
|
+
|
|
17
|
+
const confirmedText = confirmed ? '已确认' : '确认';
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<MessageContent className="gap-0 py-0" compact>
|
|
21
|
+
{prefixTips}
|
|
22
|
+
<FieldValueCheckerListMsg
|
|
23
|
+
props={filledFields}
|
|
24
|
+
readonly={confirmed}
|
|
25
|
+
streaming={status === 'streaming'}
|
|
26
|
+
>
|
|
27
|
+
{status === 'ready' ? (
|
|
28
|
+
<PrimaryConfirmBtn
|
|
29
|
+
className="mt-[20px] mb-[10px]"
|
|
30
|
+
disabled={confirmed}
|
|
31
|
+
onClick={() => {
|
|
32
|
+
setConfirmed(true);
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
{confirmedText}
|
|
36
|
+
</PrimaryConfirmBtn>
|
|
37
|
+
) : null}
|
|
38
|
+
</FieldValueCheckerListMsg>
|
|
39
|
+
{suffixTips}
|
|
40
|
+
</MessageContent>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { FormFillingPluginCtx } from '../types';
|
|
3
|
+
|
|
4
|
+
export const useConversationIdInCtx = (
|
|
5
|
+
ctx: FormFillingPluginCtx | null,
|
|
6
|
+
conversationId?: string
|
|
7
|
+
) => {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (ctx && conversationId) {
|
|
10
|
+
ctx.conversationId = conversationId;
|
|
11
|
+
}
|
|
12
|
+
}, [ctx, conversationId]);
|
|
13
|
+
};
|