@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.
Files changed (61) hide show
  1. package/.turbo/turbo-build.log +178 -115
  2. package/CHANGELOG.md +8 -0
  3. package/dist/chat-sdk.js +26425 -34262
  4. package/dist/chat-sdk.js.map +1 -1
  5. package/dist/chat-sdk.umd.cjs +219 -296
  6. package/dist/chat-sdk.umd.cjs.map +1 -1
  7. package/dist/index.css +1 -1
  8. package/package.json +4 -4
  9. package/src/chat.tsx +4 -1
  10. package/src/components/biz-comp/chat-client.tsx +1 -1
  11. package/src/components/biz-comp/multi-modal-input/index.tsx +22 -5
  12. package/src/components/biz-comp/preview-message.tsx +25 -3
  13. package/src/components/bs-ui/attachment-part-group.tsx +5 -2
  14. package/src/components/bs-ui/attachment-part.tsx +14 -9
  15. package/src/components/bs-ui/attachments-previewer.tsx +2 -2
  16. package/src/components/bs-ui/base-button.tsx +14 -4
  17. package/src/components/bs-ui/border-animation.tsx +107 -0
  18. package/src/components/bs-ui/bs-icons.tsx +6 -0
  19. package/src/components/bs-ui/confirm-dialog.tsx +17 -11
  20. package/src/components/bs-ui/fields-previewer.tsx +16 -8
  21. package/src/components/bs-ui/img-part.tsx +4 -2
  22. package/src/components/bs-ui/previewer-header.tsx +26 -7
  23. package/src/components/bs-ui/primary-entry-btn.tsx +2 -1
  24. package/src/index.tsx +0 -1
  25. package/src/lib/utils.ts +60 -2
  26. package/src/plugins/form-builder-plugin/components/create-form-confirm.tsx +0 -2
  27. package/src/plugins/form-builder-plugin/components/design-doc-part.tsx +19 -0
  28. package/src/plugins/form-builder-plugin/components/fields-part.tsx +78 -0
  29. package/src/plugins/form-builder-plugin/components/msg-part.tsx +20 -165
  30. package/src/plugins/form-builder-plugin/components/suggestion-part.tsx +62 -0
  31. package/src/plugins/form-builder-plugin/hooks/index.tsx +50 -0
  32. package/src/plugins/form-builder-plugin/index.ts +39 -30
  33. package/src/plugins/form-builder-plugin/types.ts +19 -2
  34. package/src/plugins/form-builder-plugin/utils/get-render-strategy.ts +27 -0
  35. package/src/plugins/form-builder-plugin/utils/index.ts +44 -37
  36. package/src/plugins/form-filling-plugin/components/FormFillingOpeningLines.tsx +4 -0
  37. package/src/plugins/form-filling-plugin/components/batch-fill-part.tsx +17 -0
  38. package/src/plugins/form-filling-plugin/components/batch-generator-action.tsx +6 -1
  39. package/src/plugins/form-filling-plugin/components/entry-btn.tsx +1 -1
  40. package/src/plugins/form-filling-plugin/components/first-batch-generating-animation.tsx +6 -16
  41. package/src/plugins/form-filling-plugin/components/msg-part.tsx +39 -122
  42. package/src/plugins/form-filling-plugin/components/non-first-batch-generating-animation.tsx +9 -19
  43. package/src/plugins/form-filling-plugin/components/single-fill-part.tsx +42 -0
  44. package/src/plugins/form-filling-plugin/hooks/use-conversation-id-in-ctx.ts +13 -0
  45. package/src/plugins/form-filling-plugin/hooks/use-fields-data.ts +110 -0
  46. package/src/plugins/form-filling-plugin/index.ts +49 -43
  47. package/src/plugins/form-filling-plugin/types.ts +19 -1
  48. package/src/plugins/report-query-plugin/components/query-msg-part.tsx +13 -4
  49. package/src/plugins/report-query-plugin/index.ts +20 -11
  50. package/src/store/index.ts +0 -1
  51. package/src/stories/BorderAnimation.stories.tsx +116 -0
  52. package/src/stories/PreviewerHeader.stories.tsx +24 -0
  53. package/src/style.css +25 -0
  54. package/src/plugins/form-builder-plugin/hooks/index.ts +0 -0
  55. package/src/plugins/general-model-form-builder-plugin/components/confirmer.tsx +0 -90
  56. package/src/plugins/general-model-form-builder-plugin/components/ghost-evt-dispatcher.tsx +0 -69
  57. package/src/plugins/general-model-form-builder-plugin/components/msg-part.tsx +0 -147
  58. package/src/plugins/general-model-form-builder-plugin/components/new-confirmer.tsx +0 -191
  59. package/src/plugins/general-model-form-builder-plugin/const.ts +0 -3
  60. package/src/plugins/general-model-form-builder-plugin/index.ts +0 -20
  61. 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
- const result = getMatchResult(desc, pattern);
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 = splitFieldName.length > 1 || parsedDesc.isSubForm;
111
- const parentFormName = isFieldInSubForm ? splitFieldName[0] || parsedDesc.formName : undefined;
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.relationDesc) ||
138
- extraFormNameFromFieldDesc(field.description);
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
- isDirty = true;
253
+ if (!isTargetField(fieldName, linkInfo)) {
254
+ console.log('[formFieldsWalker]', '不是目标字段,不处理', name, info, fieldName);
255
+ continue;
256
+ }
255
257
 
256
- const targetField = info.fieldMap.get(fieldName);
258
+ const targetField = info.fieldMap.get(fieldName);
259
+ if (!targetField) {
260
+ console.log('[formFieldsWalker]', '未找到目标字段,不处理', name, info, fieldName);
261
+ continue;
262
+ }
257
263
 
258
- const result = fieldProcessor(info, targetField, linkInfo);
264
+ const result = fieldProcessor(info, targetField, linkInfo);
259
265
 
260
- info.fieldMap.set(fieldName, result);
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('未找到目标表单,跳过处理', field);
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.error('尝试建立表单关联失败');
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.error('尝试建立主键关联失败');
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.error('尝试建立显示字段关联失败');
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) {
@@ -39,7 +39,7 @@ export const EntryButton = ({ style, onClick, variant }: EntryButtonProps) => {
39
39
  }
40
40
  onClick?.();
41
41
  }}
42
- entryVariant="ghost"
42
+ entryVariant="light"
43
43
  icon={<ColorfulEditIcon />}
44
44
  >
45
45
  AI填写
@@ -1,21 +1,11 @@
1
- import { BorderColorAnimation } from '@/components/bs-ui/border-color-animation';
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
- <BorderColorAnimation
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
- </BorderColorAnimation>
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
- const isFieldsJson = IsFieldsJsonPart(part);
26
-
27
- const formFillingCtx = usePluginCtx<FormFillingPluginCtx, FormFillingPlugin>(PLUGIN_NAME);
28
-
29
- const showConfirmBtn = NeedToAppendFieldsSaveConfirm(part);
30
-
31
- const [confirmed, setConfirmed] = useState(false);
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
- if (formFillingCtx) {
34
- formFillingCtx.conversationId = id;
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
- useEvt('chat-area-visibility-change', (data) => {
38
- const visible = (data as { visible?: boolean } | undefined)?.visible;
26
+ if (ctx?.fillMode === 'batch' && fieldsData.fieldsParts.length) {
27
+ return 'batch';
28
+ }
39
29
 
40
- if (visible === false && formFillingCtx?.fillMode === 'batch') {
41
- setMessages(() => []);
42
- }
43
- });
30
+ if (part.text !== undefined && part.text.trim() !== '') {
31
+ return 'markdown';
32
+ }
44
33
 
45
- const evtBus = useEvtBus();
34
+ return 'unknown';
35
+ }
46
36
 
47
- const fieldsParts = Array.isArray(part) && part.length ? part : isFieldsJson ? [part] : [];
48
- if (fieldsParts.length && formFillingCtx && formFillingCtx.fillMode !== 'batch') {
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
- const normalizedValue = valueNormalizer(field.value);
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
- const filled = fieldPropsArray.filter((f) => f !== null);
42
+ const formFillingCtx = usePluginCtx<FormFillingPluginCtx, FormFillingPlugin>(PLUGIN_NAME);
92
43
 
93
- return (
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
- if (formFillingCtx?.fillMode === 'batch' && fieldsParts.length) {
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
- if (showConfirmBtn) {
133
- return <PrimaryConfirmBtn>保存</PrimaryConfirmBtn>;
134
- }
48
+ const renderStrategy = getRenderStrategy(formFillingCtx, fieldsData, part);
135
49
 
136
- if (part.text !== undefined && part.text.trim() !== '') {
137
- return <MarkdownMsgpart {...props} />;
138
- }
50
+ const Component = RENDER_STRATEGY_COMPONENT_MAP[renderStrategy];
139
51
 
140
- return null;
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
- <BorderColorAnimation
9
- width="100%"
10
- height={110}
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
- text={`继续生成${DATA_COUNT_PER_BATCH}条`} disabled />
14
+ text={`继续生成${DATA_COUNT_PER_BATCH}条`} disabled />
25
15
  </div>
26
- </BorderColorAnimation>
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
+ };