@baishuyun/chat-sdk 0.0.16 → 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.
Files changed (65) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/chat-sdk.js +16293 -15784
  3. package/dist/chat-sdk.js.map +1 -1
  4. package/dist/chat-sdk.umd.cjs +149 -149
  5. package/dist/chat-sdk.umd.cjs.map +1 -1
  6. package/dist/index.css +1 -1
  7. package/package.json +4 -4
  8. package/src/chat.tsx +15 -1
  9. package/src/components/biz-comp/FieldChecker.tsx +49 -7
  10. package/src/components/biz-comp/FieldCheckerListMsg.tsx +101 -22
  11. package/src/components/biz-comp/chat-client.tsx +7 -2
  12. package/src/components/biz-comp/error-msg.tsx +10 -0
  13. package/src/components/biz-comp/messages.tsx +10 -0
  14. package/src/components/biz-comp/multi-modal-input/clear-btn.tsx +3 -1
  15. package/src/components/biz-comp/multi-modal-input/index.tsx +58 -38
  16. package/src/components/biz-comp/multi-modal-input/prompt-input.tsx +13 -10
  17. package/src/components/biz-comp/preview-message-wrapper.tsx +4 -4
  18. package/src/components/biz-comp/preview-message.tsx +3 -1
  19. package/src/components/biz-comp/suggestions.tsx +5 -1
  20. package/src/components/bs-ui/attachments-previewer.tsx +4 -1
  21. package/src/components/bs-ui/base-button.tsx +7 -2
  22. package/src/components/bs-ui/bs-icons.tsx +29 -0
  23. package/src/components/bs-ui/card.tsx +4 -3
  24. package/src/components/bs-ui/chat-area-header.tsx +7 -3
  25. package/src/components/bs-ui/fields-design-info-table.tsx +160 -0
  26. package/src/components/bs-ui/fields-previewer.tsx +2 -0
  27. package/src/components/bs-ui/form-info-editor.tsx +2 -42
  28. package/src/components/bs-ui/generate-animation.tsx +7 -5
  29. package/src/components/bs-ui/img-part.tsx +1 -1
  30. package/src/components/bs-ui/line-checker.tsx +19 -5
  31. package/src/components/bs-ui/previewer-header.tsx +28 -3
  32. package/src/components/bs-ui/square-checker.tsx +30 -5
  33. package/src/components/bs-ui/tooltip.tsx +1 -1
  34. package/src/components/ui/dialog.tsx +1 -1
  35. package/src/components/ui/tooltip.tsx +1 -1
  36. package/src/const/ui.ts +42 -0
  37. package/src/hooks/use-frame-mode.ts +15 -0
  38. package/src/lib/parse-design-doc.ts +60 -0
  39. package/src/lib/utils.ts +19 -0
  40. package/src/plugins/form-builder-base-plugin/const.ts +3 -0
  41. package/src/plugins/form-builder-plugin/components/create-form-confirm.tsx +14 -1
  42. package/src/plugins/form-builder-plugin/components/design-info.tsx +47 -0
  43. package/src/plugins/form-builder-plugin/components/entry-btn.tsx +10 -2
  44. package/src/plugins/form-builder-plugin/components/follow-up.tsx +21 -6
  45. package/src/plugins/form-builder-plugin/components/msg-part.tsx +29 -9
  46. package/src/plugins/form-builder-plugin/components/opening-lines.tsx +11 -6
  47. package/src/plugins/form-builder-plugin/index.ts +73 -5
  48. package/src/plugins/form-builder-plugin/types.ts +3 -0
  49. package/src/plugins/form-builder-plugin/utils/index.ts +33 -6
  50. package/src/plugins/form-filling-plugin/components/batch-generator-action.tsx +44 -34
  51. package/src/plugins/form-filling-plugin/components/first-batch-generating-animation.tsx +21 -0
  52. package/src/plugins/form-filling-plugin/components/generated-data-counter.tsx +17 -0
  53. package/src/plugins/form-filling-plugin/components/non-first-batch-generating-animation.tsx +28 -0
  54. package/src/plugins/form-filling-plugin/index.ts +14 -0
  55. package/src/plugins/form-filling-plugin/types.ts +2 -0
  56. package/src/plugins/report-query-plugin/components/query-msg-part.tsx +16 -18
  57. package/src/plugins/report-query-plugin/components/result-cards/CreatedSourceMsg.tsx +36 -0
  58. package/src/plugins/report-query-plugin/components/result-cards/DataTableCard.tsx +15 -2
  59. package/src/plugins/report-query-plugin/const.ts +22 -0
  60. package/src/plugins/report-query-plugin/index.ts +30 -3
  61. package/src/plugins/report-query-plugin/types.ts +6 -0
  62. package/src/sdk.impl.tsx +4 -0
  63. package/src/store/index.ts +11 -0
  64. package/src/stories/FormInfoEditor.stories.tsx +19 -28
  65. package/src/stories/fields-design-info-table.stories.tsx +203 -0
@@ -1,5 +1,3 @@
1
- import { BorderColorAnimation } from '@/components/bs-ui/border-color-animation';
2
- import { GenerateAnimation } from '@/components/bs-ui/generate-animation';
3
1
  import { PrimaryConfirmBtn } from '@/components/bs-ui/primary-confirm-btn';
4
2
  import { TextUIPart } from 'ai';
5
3
  import { memo, useCallback, useEffect, useRef, useState } from 'react';
@@ -11,7 +9,10 @@ import { DATA_COUNT_PER_BATCH, FILLING_EVENTS, PLUGIN_NAME } from '../const';
11
9
  import { useEvtBus } from '@/hooks/use-evt-bus';
12
10
  import { ChatMessage, UseChatHelpers } from '@baishuyun/types';
13
11
  import { type Field } from '@/plugins/form-builder-base-plugin/types';
14
- import { CircleChecker } from '@/components/bs-ui/circle-checker';
12
+ import { GeneratedDataCounter } from './generated-data-counter';
13
+ import { FirstBatchGeneratingAnimation } from './first-batch-generating-animation';
14
+ import { NonFirstBatchGeneratingAnimation } from './non-first-batch-generating-animation';
15
+ import { usePlugin } from '@/hooks/use-plugin';
15
16
 
16
17
  type FilledField = {
17
18
  fieldName: string;
@@ -93,30 +94,51 @@ const BaseBatchGeneratorAction = ({
93
94
  id,
94
95
  fields,
95
96
  }: BatchGeneratorActionProps) => {
97
+ const pluginInst = usePlugin<FormFillingPlugin>(PLUGIN_NAME);
98
+
96
99
  const [streamingState, setStreamingState] = useState(status === 'streaming');
97
100
 
101
+ const [totalCount, setTotalCount] = useState(pluginInst?.getCount(id) || 0);
102
+
103
+ const [next, setNext] = useState(totalCount > 0);
104
+
98
105
  const evtBus = useEvtBus();
99
106
 
107
+ const getRowNum = useCallback(() => {
108
+ if (!fields || fields.length === 0) {
109
+ return 0;
110
+ }
111
+
112
+ const lastField = fields[fields.length - 1];
113
+ return lastField.row || 0;
114
+ }, [fields]);
115
+
100
116
  useEffect(() => {
101
117
  if (status === 'ready' || status === 'error') {
102
118
  setStreamingState(false);
103
119
  }
104
120
  }, [status]);
105
121
 
122
+ useEffect(() => {
123
+ if (!pluginInst) {
124
+ return;
125
+ }
126
+
127
+ if (streamingState) {
128
+ return;
129
+ }
130
+
131
+ const newRows = getRowNum();
132
+ pluginInst.setCount(id, newRows);
133
+
134
+ setTotalCount(pluginInst.getCount(id) || 0);
135
+ }, [streamingState, getRowNum, pluginInst, id]);
136
+
106
137
  const formFillingCtx: FormFillingPluginCtx | null = usePluginCtx<
107
138
  FormFillingPluginCtx,
108
139
  FormFillingPlugin
109
140
  >(PLUGIN_NAME);
110
141
 
111
- const getRowNum = () => {
112
- if (!fields || fields.length === 0) {
113
- return 0;
114
- }
115
-
116
- const lastField = fields[fields.length - 1];
117
- return lastField.row || 0;
118
- };
119
-
120
142
  const handleCheckChange = useCallback(
121
143
  (checked: boolean) => {
122
144
  evtBus.emit('form-filling-fields-checked-update', {
@@ -132,11 +154,7 @@ const BaseBatchGeneratorAction = ({
132
154
  if (!streamingState) {
133
155
  return (
134
156
  <div className="rounded-[10px] border border-[var(--e0e0e0,#E0E0E0)] w-full flex items-center flex-col gap-[10px] p-[4px] pb-[20px]">
135
- <div className="flex items-center w-full py-[10px] px-[16px] gap-[6px]">
136
- <CircleChecker defaultChecked onCheckedChange={handleCheckChange}>
137
- 已生成{getRowNum()}条数据
138
- </CircleChecker>
139
- </div>
157
+ <GeneratedDataCounter count={totalCount} handleCheckChange={handleCheckChange} />
140
158
 
141
159
  <PrimaryConfirmBtn
142
160
  text={`继续生成${DATA_COUNT_PER_BATCH}条`}
@@ -146,6 +164,8 @@ const BaseBatchGeneratorAction = ({
146
164
  return;
147
165
  }
148
166
 
167
+ setNext(true);
168
+
149
169
  setStreamingState(true);
150
170
 
151
171
  const formStructure = Array.from(formFillingCtx?.fieldMap.values() || []);
@@ -169,22 +189,12 @@ const BaseBatchGeneratorAction = ({
169
189
  );
170
190
  }
171
191
 
172
- return (
173
- <BorderColorAnimation
174
- width="100%"
175
- height={40}
176
- padding={10}
177
- borderRadius={4}
178
- bgInset={1000}
179
- borderWidth={1.5}
180
- style={{
181
- display: 'flex',
182
- alignItems: 'center',
183
- }}
184
- >
185
- <GenerateAnimation>数据生成中,可点击下方按钮暂停</GenerateAnimation>
186
- </BorderColorAnimation>
187
- );
192
+ const isFirstBatch = totalCount <= DATA_COUNT_PER_BATCH && !next;
193
+ if (isFirstBatch) {
194
+ return <FirstBatchGeneratingAnimation />;
195
+ }
196
+
197
+ return <NonFirstBatchGeneratingAnimation />;
188
198
  };
189
199
 
190
200
  const PartParser = ({ parts, ...rest }: BatchGeneratorActionProps) => {
@@ -218,7 +228,7 @@ export const BatchGeneratorAction = memo(PartParser, (prevProps, nextProps) => {
218
228
  prevProps.parts?.length === nextProps.parts?.length &&
219
229
  prevLastPart?.text === lastPart?.text &&
220
230
  prevProps.status === nextProps.status &&
221
- prevProps.sendMessage === nextProps.sendMessage &&
231
+ // prevProps.sendMessage === nextProps.sendMessage &&
222
232
  prevProps.id === nextProps.id
223
233
  );
224
234
  });
@@ -0,0 +1,21 @@
1
+ import { BorderColorAnimation } from '@/components/bs-ui/border-color-animation';
2
+ import { GenerateAnimation } from '@/components/bs-ui/generate-animation';
3
+
4
+ export const FirstBatchGeneratingAnimation = () => {
5
+ 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
+ >
18
+ <GenerateAnimation>数据生成中,可点击下方按钮暂停</GenerateAnimation>
19
+ </BorderColorAnimation>
20
+ );
21
+ };
@@ -0,0 +1,17 @@
1
+ import { CircleChecker } from '@/components/bs-ui/circle-checker';
2
+
3
+ export const GeneratedDataCounter = ({
4
+ count,
5
+ handleCheckChange,
6
+ }: {
7
+ count: number;
8
+ handleCheckChange: (checked: boolean) => void;
9
+ }) => {
10
+ return (
11
+ <div className="flex items-center w-full py-[10px] px-[16px] gap-[6px]">
12
+ <CircleChecker defaultChecked onCheckedChange={handleCheckChange}>
13
+ 已生成{count}条数据
14
+ </CircleChecker>
15
+ </div>
16
+ );
17
+ };
@@ -0,0 +1,28 @@
1
+ import { BorderColorAnimation } from '@/components/bs-ui/border-color-animation';
2
+ import { GenerateAnimation } from '@/components/bs-ui/generate-animation';
3
+ import { PrimaryConfirmBtn } from '@/components/bs-ui/primary-confirm-btn';
4
+ import { DATA_COUNT_PER_BATCH } from '../const';
5
+
6
+ export const NonFirstBatchGeneratingAnimation = () => {
7
+ 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>
22
+ <PrimaryConfirmBtn
23
+ className="w-[300px] mx-auto"
24
+ text={`继续生成${DATA_COUNT_PER_BATCH}条`} disabled />
25
+ </div>
26
+ </BorderColorAnimation>
27
+ );
28
+ };
@@ -91,6 +91,7 @@ export class FormFillingPlugin extends ChatAreaPlugin<FormFillingPluginCtx> {
91
91
  }) => {
92
92
  if (!visible) {
93
93
  this.lifecycleHooks?.onBeforeMessagesClear?.();
94
+ this.Context.counterMap.clear();
94
95
  }
95
96
  };
96
97
 
@@ -102,6 +103,18 @@ export class FormFillingPlugin extends ChatAreaPlugin<FormFillingPluginCtx> {
102
103
  this.Context!.fillMode = mode;
103
104
  };
104
105
 
106
+ public getCount = (messageId: string): number => {
107
+ console.log('get count', messageId, this.Context.counterMap.get(messageId));
108
+ return this.Context.counterMap.get(messageId) || 0;
109
+ };
110
+
111
+ public setCount = (messageId: string, inc: number) => {
112
+ const existingCount = this.Context.counterMap.get(messageId) || 0;
113
+ const newCount = existingCount + inc;
114
+ console.log('set count', messageId, newCount);
115
+ this.Context.counterMap.set(messageId, newCount);
116
+ };
117
+
105
118
  public dispose?: (() => void) | undefined = () => {
106
119
  this.batchFillingDataManager.dispose();
107
120
 
@@ -229,6 +242,7 @@ export const FormFillingPluginRegisterEntry: PluginRegistryEntry<FormFillingPlug
229
242
  subFieldsNameMap: new Map(),
230
243
  conversationId: '',
231
244
  fillMode: 'AI',
245
+ counterMap: new Map(),
232
246
  };
233
247
  },
234
248
  };
@@ -11,4 +11,6 @@ export interface FormFillingPluginCtx {
11
11
  conversationId: string;
12
12
 
13
13
  fillMode: FormFillingMode;
14
+
15
+ counterMap: Map<string, number>; // key is messageId, value is row counter
14
16
  }
@@ -7,10 +7,7 @@ import { usePluginCtx } from '@/hooks/use-plugin-ctx';
7
7
  import { ReportQueryPlugin } from '@/index';
8
8
  import { PLUGIN_NAME } from '../const';
9
9
  import { IReportQueryContext } from '../types';
10
- import { FakeBotMessage } from '@/components/biz-comp/FakeBotMsg';
11
- import { HighlightMsg } from '@/components/biz-comp/highlight-msg';
12
- import { CollapsibleTxtMsg } from '@/components/bs-ui/collapsible-txt-msg';
13
- import { AggregateTableIcon } from '@/components/bs-ui/bs-icons';
10
+ import { CreatedSourceMsg } from './result-cards/CreatedSourceMsg';
14
11
 
15
12
  export const QueryMsgPart = ({ part, ...rest }: MsgPartCompProps) => {
16
13
  const textPart = part as TextUIPart;
@@ -29,25 +26,26 @@ export const QueryMsgPart = ({ part, ...rest }: MsgPartCompProps) => {
29
26
 
30
27
  if (result.isAggregate) {
31
28
  return (
32
- <FakeBotMessage headless className="w-full">
33
- <HighlightMsg>已为你创建聚合表</HighlightMsg>
34
- <CollapsibleTxtMsg
35
- icon={
36
- <span className="text-[#0265ff]">
37
- <AggregateTableIcon />
38
- </span>
39
- }
40
- title={result.title!}
41
- disableExpand
42
- />
43
- </FakeBotMessage>
29
+ <CreatedSourceMsg type={'aggregate'} title={result.title || ''} done={textPart.state === 'done'} />
44
30
  );
45
31
  }
46
32
 
47
- console.log('set query result in context', result);
33
+ console.log('queryResult', result)
34
+
48
35
  ctx.queryResult = result;
49
36
  ctx.queryResult.appID = ctx.appInfo?.appId || '';
50
- return <DataTableCard {...(result || {})}></DataTableCard>;
37
+
38
+ return (
39
+ <>
40
+ {(result.source && (result.source !== 'aggregate')) ? (
41
+ <CreatedSourceMsg type={result.source} title={result.title || ''} done={textPart.state === 'done'} />
42
+ ) : null}
43
+ <DataTableCard
44
+ {...(result || {})}
45
+ streaming={textPart?.state === 'streaming'}
46
+ ></DataTableCard>
47
+ </>
48
+ );
51
49
  }
52
50
 
53
51
  if (textPart.text !== undefined && textPart.text.trim() !== '') {
@@ -0,0 +1,36 @@
1
+ import { FakeBotMessage } from '@/components/biz-comp/FakeBotMsg';
2
+ import { HighlightMsg } from '@/components/biz-comp/highlight-msg';
3
+ import { CollapsibleTxtMsg } from '@/components/bs-ui/collapsible-txt-msg';
4
+ import { QuerySourceType } from '@baishuyun/types';
5
+ import { CreatedSourceConfigMap } from '../../const';
6
+ import { useEffect } from 'react';
7
+ import { useFakeGlobalLoadingMessage } from '@/hooks/use-frame-mode';
8
+
9
+ export const CreatedSourceMsg = ({ type, title, done }: { type: QuerySourceType; title: string; done?: boolean }) => {
10
+ const config = CreatedSourceConfigMap[type];
11
+ if (!config) {
12
+ return null;
13
+ }
14
+
15
+ const loading = useFakeGlobalLoadingMessage();
16
+
17
+ useEffect(() => {
18
+ // if (done) {
19
+
20
+ // }
21
+ loading?.clearGlobalFakeLoadingMessage();
22
+
23
+ }, [])
24
+
25
+ const icon = <config.iconComponent />;
26
+ return (
27
+ <FakeBotMessage headless className="w-full">
28
+ <HighlightMsg>已为你创建{config.label}</HighlightMsg>
29
+ <CollapsibleTxtMsg
30
+ icon={<span className={`text-[${config.color}]`}>{icon}</span>}
31
+ title={title}
32
+ disableExpand
33
+ />
34
+ </FakeBotMessage>
35
+ );
36
+ };
@@ -4,16 +4,23 @@ import { IQueryResult } from '@baishuyun/types';
4
4
  import { IReportQueryContext } from '../../types';
5
5
  import { ReportQueryPlugin } from '../..';
6
6
  import { PLUGIN_NAME } from '../../const';
7
- import { useCallback } from 'react';
7
+ import { useCallback, useEffect } from 'react';
8
8
  import { ConditionField, DataSourceField, DimensionField, MetricField } from './DataTableFields';
9
9
  import { CardFieldsWrapper } from '@/components/bs-ui/card-field';
10
10
  import { FilterCondition } from './FilterCondition';
11
11
  import { SplitLine } from '@/components/bs-ui/split-line';
12
12
  import { DashWidgetIcon } from '@/components/biz-comp/dash-widget-icon';
13
+ import { useFakeGlobalLoadingMessage } from '@/hooks/use-frame-mode';
13
14
 
14
- export const DataTableCard = (props: IQueryResult) => {
15
+ export const DataTableCard = (
16
+ props: IQueryResult & {
17
+ streaming?: boolean;
18
+ }
19
+ ) => {
15
20
  const ctx = usePluginCtx<IReportQueryContext, ReportQueryPlugin>(PLUGIN_NAME);
16
21
 
22
+ const globalLoading = useFakeGlobalLoadingMessage();
23
+
17
24
  const getFormName = useCallback(
18
25
  (id: string) => {
19
26
  const form = ctx?.appInfo?.formMap?.get(id);
@@ -22,6 +29,12 @@ export const DataTableCard = (props: IQueryResult) => {
22
29
  [ctx]
23
30
  );
24
31
 
32
+ useEffect(() => {
33
+ if (props.streaming) {
34
+ globalLoading.clearGlobalFakeLoadingMessage();
35
+ }
36
+ }, [props.streaming]);
37
+
25
38
  const formId = props.formIds?.[0] || '';
26
39
  const name = formId ? getFormName(formId) : '';
27
40
 
@@ -1 +1,23 @@
1
+ import { QuerySourceType } from '@baishuyun/types';
2
+ import { ICreatedSourceConfig } from './types';
3
+ import { AggregateTableIcon, DataReportIcon, DataViewIcon } from '@/components/bs-ui/bs-icons';
4
+
1
5
  export const PLUGIN_NAME = 'ReportQueryPlugin';
6
+
7
+ export const CreatedSourceConfigMap: Record<QuerySourceType, ICreatedSourceConfig> = {
8
+ etl: {
9
+ label: '数据视图',
10
+ color: '#0265ff',
11
+ iconComponent: DataViewIcon,
12
+ },
13
+ aggregate: {
14
+ label: '聚合表',
15
+ color: '#0265ff',
16
+ iconComponent: AggregateTableIcon,
17
+ },
18
+ report: {
19
+ label: '数据报表',
20
+ color: '#4ACC8C',
21
+ iconComponent: DataReportIcon,
22
+ },
23
+ };
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ChatAreaPlugin,
3
+ IChatSDK,
3
4
  IDashForm,
4
5
  PluginCustomComponent,
5
6
  PluginHooks,
@@ -14,6 +15,12 @@ import { QueryMsgPart } from './components/query-msg-part';
14
15
  import { queryResult2createParams, queryResult2previewerProps } from './utils';
15
16
 
16
17
  export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
18
+ private _inst: IChatSDK | null = null;
19
+
20
+ public init?: ((sdk: IChatSDK) => void) | undefined = (sdkInst: IChatSDK) => {
21
+ this._inst = sdkInst;
22
+ };
23
+
17
24
  public pluginName: string = PLUGIN_NAME;
18
25
 
19
26
  public customComponents?: Partial<PluginCustomComponent> | undefined = {
@@ -24,8 +31,20 @@ export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
24
31
  };
25
32
 
26
33
  public lifecycleHooks?: PluginHooks | undefined = {
34
+ onBeforeMessagesClear: (conversationId) => {
35
+ const req = async () => {
36
+ await fetch(`https://agent.online-office.net/web/api/form/conversation/clear`, {
37
+ // await fetch(`http://192.168.50.38:3001/web/api/form/conversation/clear`, {
38
+ method: 'POST',
39
+ body: JSON.stringify({ conversationId }),
40
+ });
41
+ };
42
+
43
+ req();
44
+ },
45
+
27
46
  onAfterChatAreaHide: ({ clearMsgs }) => {
28
- // clearMsgs();
47
+ clearMsgs();
29
48
  },
30
49
 
31
50
  onBeforeChatRender: () => {
@@ -43,6 +62,11 @@ export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
43
62
  },
44
63
  };
45
64
  },
65
+
66
+ onAfterMessageSend: (_) => {
67
+ console.log('enter onAfterMessageSend hook in ReportQueryPlugin');
68
+ this.setLoadingMsg('正在处理');
69
+ },
46
70
  };
47
71
 
48
72
  public getPreviewerProps = (entryId: string) => {
@@ -92,14 +116,17 @@ export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
92
116
  console.log('forms received in plugin:', formMap);
93
117
  };
94
118
 
119
+ private setLoadingMsg = (message: string) => {
120
+ this._inst?.setGlobalLoadingMessage(message);
121
+ };
122
+
95
123
  public constructor(ctx: IReportQueryContext) {
96
124
  super(ctx);
97
125
  this.Context = ctx;
98
126
  }
99
127
 
100
128
  public clearCtx = () => {
101
- // console.log('clear plugin context');
102
- // this.Context.queryResult = undefined;
129
+ this.Context.queryResult = undefined;
103
130
  };
104
131
  }
105
132
 
@@ -14,3 +14,9 @@ export interface IReportQueryContext {
14
14
 
15
15
  queryResult?: IQueryResult;
16
16
  }
17
+
18
+ export interface ICreatedSourceConfig {
19
+ label: string;
20
+ color: string;
21
+ iconComponent: React.ComponentType;
22
+ }
package/src/sdk.impl.tsx CHANGED
@@ -69,6 +69,10 @@ export class ChatSDK implements IChatSDK {
69
69
  this.Store.getState().setChatAreaPluginInstList(instList);
70
70
  }
71
71
 
72
+ public setGlobalLoadingMessage(message?: string): void {
73
+ this.Store.getState().setGlobalFakeLoadingMessage(message);
74
+ }
75
+
72
76
  public getPluginCtx<T>(pluginName: string): DeepReadonly<T> | undefined {
73
77
  const pluginInst = this.Store.getState().chatAreaPluginInstList.find(
74
78
  (inst) => inst.pluginName === pluginName
@@ -23,6 +23,7 @@ export const createStore = (sdkInst: ChatSDK) => {
23
23
  clientStyle: '',
24
24
 
25
25
  msgClearTimestamp: Date.now(),
26
+ globalFakeLoadingMessage: '',
26
27
  };
27
28
 
28
29
  return create<ChatContextType>()(
@@ -36,6 +37,16 @@ export const createStore = (sdkInst: ChatSDK) => {
36
37
 
37
38
  clearMessages: () => set(() => ({ msgClearTimestamp: Date.now() })),
38
39
 
40
+ clearGlobalFakeLoadingMessage: () =>
41
+ set(() => ({
42
+ globalFakeLoadingMessage: undefined,
43
+ })),
44
+
45
+ setGlobalFakeLoadingMessage: (message) =>
46
+ set(() => ({
47
+ globalFakeLoadingMessage: message,
48
+ })),
49
+
39
50
  setChatStatus: (status: ChatStatus) =>
40
51
  set(() => ({
41
52
  chatStatus: status,
@@ -1,21 +1,18 @@
1
- import type { Meta, StoryObj } from "@storybook/react-vite";
2
- import { useState } from "react";
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { useState } from 'react';
3
3
 
4
- import {
5
- FormInfoEditor,
6
- FormIconOption,
7
- FORM_ICON_OPTIONS,
8
- } from "@/components/bs-ui/form-info-editor";
4
+ import { FormInfoEditor, FormIconOption } from '@/components/bs-ui/form-info-editor';
5
+ import { FORM_ICON_OPTIONS } from '@/const/ui';
9
6
 
10
7
  const meta: Meta<typeof FormInfoEditor> = {
11
- title: "Example/Chat/FormInfoEditor",
8
+ title: 'Example/Chat/FormInfoEditor',
12
9
  component: FormInfoEditor,
13
- tags: ["autodocs"],
10
+ tags: ['autodocs'],
14
11
  parameters: {
15
- layout: "centered",
12
+ layout: 'centered',
16
13
  },
17
14
  args: {
18
- name: "供应商管理表",
15
+ name: '供应商管理表',
19
16
  },
20
17
  decorators: [
21
18
  (Story) => (
@@ -32,7 +29,7 @@ type Story = StoryObj<typeof meta>;
32
29
  // Default collapsed state
33
30
  export const Default: Story = {
34
31
  args: {
35
- name: "供应商管理表",
32
+ name: '供应商管理表',
36
33
  selectedIcon: FORM_ICON_OPTIONS[0],
37
34
  },
38
35
  };
@@ -40,7 +37,7 @@ export const Default: Story = {
40
37
  // Expanded edit state
41
38
  export const Expanded: Story = {
42
39
  args: {
43
- name: "供应商管理表",
40
+ name: '供应商管理表',
44
41
  expanded: true,
45
42
  selectedIcon: FORM_ICON_OPTIONS[0],
46
43
  },
@@ -49,7 +46,7 @@ export const Expanded: Story = {
49
46
  // With icon options in expanded state (using all 36 form icons)
50
47
  export const WithIconOptions: Story = {
51
48
  args: {
52
- name: "供应商管理表",
49
+ name: '供应商管理表',
53
50
  expanded: true,
54
51
  iconOptions: FORM_ICON_OPTIONS,
55
52
  selectedIcon: FORM_ICON_OPTIONS[20],
@@ -65,11 +62,9 @@ export const WithIconOptions: Story = {
65
62
 
66
63
  // Interactive example with state management
67
64
  const InteractiveTemplate = () => {
68
- const [name, setName] = useState("供应商管理表");
65
+ const [name, setName] = useState('供应商管理表');
69
66
  const [expanded, setExpanded] = useState(false);
70
- const [selectedIcon, setSelectedIcon] = useState<FormIconOption>(
71
- FORM_ICON_OPTIONS[0]
72
- );
67
+ const [selectedIcon, setSelectedIcon] = useState<FormIconOption>(FORM_ICON_OPTIONS[0]);
73
68
 
74
69
  return (
75
70
  <FormInfoEditor
@@ -101,7 +96,7 @@ export const Interactive: Story = {
101
96
  // Long form name - test ellipsis
102
97
  export const LongName: Story = {
103
98
  args: {
104
- name: "这是一个很长的表单名称用于测试文本溢出情况显示省略号",
99
+ name: '这是一个很长的表单名称用于测试文本溢出情况显示省略号',
105
100
  selectedIcon: FORM_ICON_OPTIONS[5],
106
101
  },
107
102
  };
@@ -109,8 +104,8 @@ export const LongName: Story = {
109
104
  // Custom width
110
105
  export const CustomWidth: Story = {
111
106
  args: {
112
- name: "供应商管理表",
113
- className: "w-[400px]",
107
+ name: '供应商管理表',
108
+ className: 'w-[400px]',
114
109
  selectedIcon: FORM_ICON_OPTIONS[0],
115
110
  },
116
111
  decorators: [
@@ -125,7 +120,7 @@ export const CustomWidth: Story = {
125
120
  // Expanded with long name
126
121
  export const ExpandedLongName: Story = {
127
122
  args: {
128
- name: "这是一个很长的表单名称用于测试文本溢出情况",
123
+ name: '这是一个很长的表单名称用于测试文本溢出情况',
129
124
  expanded: true,
130
125
  iconOptions: FORM_ICON_OPTIONS.slice(0, 18), // Show 18 icons (3 rows)
131
126
  selectedIcon: FORM_ICON_OPTIONS[0],
@@ -135,7 +130,7 @@ export const ExpandedLongName: Story = {
135
130
  // Empty name
136
131
  export const EmptyName: Story = {
137
132
  args: {
138
- name: "",
133
+ name: '',
139
134
  expanded: true,
140
135
  selectedIcon: FORM_ICON_OPTIONS[0],
141
136
  },
@@ -147,11 +142,7 @@ export const SideBySide: Story = {
147
142
  <div className="flex flex-col gap-4 w-[328px]">
148
143
  <div>
149
144
  <p className="text-sm text-gray-500 mb-2">默认状态 (收起)</p>
150
- <FormInfoEditor
151
- name="供应商管理表"
152
- expanded={false}
153
- selectedIcon={FORM_ICON_OPTIONS[0]}
154
- />
145
+ <FormInfoEditor name="供应商管理表" expanded={false} selectedIcon={FORM_ICON_OPTIONS[0]} />
155
146
  </div>
156
147
  <div>
157
148
  <p className="text-sm text-gray-500 mb-2">长名称 (带省略号)</p>