@baishuyun/chat-sdk 0.0.16 → 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 (95) hide show
  1. package/.turbo/turbo-build.log +178 -115
  2. package/CHANGELOG.md +16 -0
  3. package/dist/chat-sdk.js +37309 -44637
  4. package/dist/chat-sdk.js.map +1 -1
  5. package/dist/chat-sdk.umd.cjs +218 -295
  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 +19 -2
  10. package/src/components/biz-comp/FieldChecker.tsx +49 -7
  11. package/src/components/biz-comp/FieldCheckerListMsg.tsx +101 -22
  12. package/src/components/biz-comp/chat-client.tsx +8 -3
  13. package/src/components/biz-comp/error-msg.tsx +10 -0
  14. package/src/components/biz-comp/messages.tsx +10 -0
  15. package/src/components/biz-comp/multi-modal-input/clear-btn.tsx +3 -1
  16. package/src/components/biz-comp/multi-modal-input/index.tsx +80 -43
  17. package/src/components/biz-comp/multi-modal-input/prompt-input.tsx +13 -10
  18. package/src/components/biz-comp/preview-message-wrapper.tsx +4 -4
  19. package/src/components/biz-comp/preview-message.tsx +26 -2
  20. package/src/components/biz-comp/suggestions.tsx +5 -1
  21. package/src/components/bs-ui/attachment-part-group.tsx +5 -2
  22. package/src/components/bs-ui/attachment-part.tsx +14 -9
  23. package/src/components/bs-ui/attachments-previewer.tsx +6 -3
  24. package/src/components/bs-ui/base-button.tsx +20 -5
  25. package/src/components/bs-ui/border-animation.tsx +107 -0
  26. package/src/components/bs-ui/bs-icons.tsx +35 -0
  27. package/src/components/bs-ui/card.tsx +4 -3
  28. package/src/components/bs-ui/chat-area-header.tsx +7 -3
  29. package/src/components/bs-ui/confirm-dialog.tsx +17 -11
  30. package/src/components/bs-ui/fields-design-info-table.tsx +160 -0
  31. package/src/components/bs-ui/fields-previewer.tsx +18 -8
  32. package/src/components/bs-ui/form-info-editor.tsx +2 -42
  33. package/src/components/bs-ui/generate-animation.tsx +7 -5
  34. package/src/components/bs-ui/img-part.tsx +4 -2
  35. package/src/components/bs-ui/line-checker.tsx +19 -5
  36. package/src/components/bs-ui/previewer-header.tsx +48 -4
  37. package/src/components/bs-ui/primary-entry-btn.tsx +2 -1
  38. package/src/components/bs-ui/square-checker.tsx +30 -5
  39. package/src/components/bs-ui/tooltip.tsx +1 -1
  40. package/src/components/ui/dialog.tsx +1 -1
  41. package/src/components/ui/tooltip.tsx +1 -1
  42. package/src/const/ui.ts +42 -0
  43. package/src/hooks/use-frame-mode.ts +15 -0
  44. package/src/index.tsx +0 -1
  45. package/src/lib/parse-design-doc.ts +60 -0
  46. package/src/lib/utils.ts +79 -2
  47. package/src/plugins/form-builder-base-plugin/const.ts +3 -0
  48. package/src/plugins/form-builder-plugin/components/create-form-confirm.tsx +12 -1
  49. package/src/plugins/form-builder-plugin/components/design-doc-part.tsx +19 -0
  50. package/src/plugins/form-builder-plugin/components/design-info.tsx +47 -0
  51. package/src/plugins/form-builder-plugin/components/entry-btn.tsx +10 -2
  52. package/src/plugins/form-builder-plugin/components/fields-part.tsx +78 -0
  53. package/src/plugins/form-builder-plugin/components/follow-up.tsx +21 -6
  54. package/src/plugins/form-builder-plugin/components/msg-part.tsx +20 -145
  55. package/src/plugins/form-builder-plugin/components/opening-lines.tsx +11 -6
  56. package/src/plugins/form-builder-plugin/components/suggestion-part.tsx +62 -0
  57. package/src/plugins/form-builder-plugin/hooks/index.tsx +50 -0
  58. package/src/plugins/form-builder-plugin/index.ts +91 -14
  59. package/src/plugins/form-builder-plugin/types.ts +22 -2
  60. package/src/plugins/form-builder-plugin/utils/get-render-strategy.ts +27 -0
  61. package/src/plugins/form-builder-plugin/utils/index.ts +75 -41
  62. package/src/plugins/form-filling-plugin/components/FormFillingOpeningLines.tsx +4 -0
  63. package/src/plugins/form-filling-plugin/components/batch-fill-part.tsx +17 -0
  64. package/src/plugins/form-filling-plugin/components/batch-generator-action.tsx +50 -35
  65. package/src/plugins/form-filling-plugin/components/entry-btn.tsx +1 -1
  66. package/src/plugins/form-filling-plugin/components/first-batch-generating-animation.tsx +11 -0
  67. package/src/plugins/form-filling-plugin/components/generated-data-counter.tsx +17 -0
  68. package/src/plugins/form-filling-plugin/components/msg-part.tsx +39 -122
  69. package/src/plugins/form-filling-plugin/components/non-first-batch-generating-animation.tsx +18 -0
  70. package/src/plugins/form-filling-plugin/components/single-fill-part.tsx +42 -0
  71. package/src/plugins/form-filling-plugin/hooks/use-conversation-id-in-ctx.ts +13 -0
  72. package/src/plugins/form-filling-plugin/hooks/use-fields-data.ts +110 -0
  73. package/src/plugins/form-filling-plugin/index.ts +62 -42
  74. package/src/plugins/form-filling-plugin/types.ts +21 -1
  75. package/src/plugins/report-query-plugin/components/query-msg-part.tsx +25 -18
  76. package/src/plugins/report-query-plugin/components/result-cards/CreatedSourceMsg.tsx +36 -0
  77. package/src/plugins/report-query-plugin/components/result-cards/DataTableCard.tsx +15 -2
  78. package/src/plugins/report-query-plugin/const.ts +22 -0
  79. package/src/plugins/report-query-plugin/index.ts +41 -5
  80. package/src/plugins/report-query-plugin/types.ts +6 -0
  81. package/src/sdk.impl.tsx +4 -0
  82. package/src/store/index.ts +11 -1
  83. package/src/stories/BorderAnimation.stories.tsx +116 -0
  84. package/src/stories/FormInfoEditor.stories.tsx +19 -28
  85. package/src/stories/PreviewerHeader.stories.tsx +24 -0
  86. package/src/stories/fields-design-info-table.stories.tsx +203 -0
  87. package/src/style.css +25 -0
  88. package/src/plugins/form-builder-plugin/hooks/index.ts +0 -0
  89. package/src/plugins/general-model-form-builder-plugin/components/confirmer.tsx +0 -90
  90. package/src/plugins/general-model-form-builder-plugin/components/ghost-evt-dispatcher.tsx +0 -69
  91. package/src/plugins/general-model-form-builder-plugin/components/msg-part.tsx +0 -147
  92. package/src/plugins/general-model-form-builder-plugin/components/new-confirmer.tsx +0 -191
  93. package/src/plugins/general-model-form-builder-plugin/const.ts +0 -3
  94. package/src/plugins/general-model-form-builder-plugin/index.ts +0 -20
  95. package/src/plugins/general-model-form-builder-plugin/types.ts +0 -1
@@ -18,6 +18,7 @@ import { FormFillingOpeningLines } from './components/FormFillingOpeningLines';
18
18
  import { FillMessagePart } from './components/msg-part';
19
19
  import { UIDataTypes, UIMessagePart, UITools } from 'ai';
20
20
  import {
21
+ ensureEndSlash,
21
22
  extractTextPartMeta,
22
23
  IsFieldsJsonPart,
23
24
  mergeConsecutiveTargets,
@@ -74,26 +75,11 @@ export class FormFillingPlugin extends ChatAreaPlugin<FormFillingPluginCtx> {
74
75
  this.handleFillModeUpdate
75
76
  );
76
77
 
77
- sdk.eventBus.on<'chat-area-visibility-change'>(
78
- 'chat-area-visibility-change',
79
- this.handleChatAreaVisibilityChange
80
- );
81
-
82
78
  // this.handleFormStructureReady({
83
79
  // fields: MOCK_FORM_STRUCTURE,
84
80
  // });
85
81
  };
86
82
 
87
- private handleChatAreaVisibilityChange: EventHandler<{ visible: boolean }> = ({
88
- visible,
89
- }: {
90
- visible: boolean;
91
- }) => {
92
- if (!visible) {
93
- this.lifecycleHooks?.onBeforeMessagesClear?.();
94
- }
95
- };
96
-
97
83
  private handleFillModeUpdate: EventHandler<{ mode: FormFillingMode }> = ({
98
84
  mode,
99
85
  }: {
@@ -102,6 +88,18 @@ export class FormFillingPlugin extends ChatAreaPlugin<FormFillingPluginCtx> {
102
88
  this.Context!.fillMode = mode;
103
89
  };
104
90
 
91
+ public getCount = (messageId: string): number => {
92
+ console.log('get count', messageId, this.Context.counterMap.get(messageId));
93
+ return this.Context.counterMap.get(messageId) || 0;
94
+ };
95
+
96
+ public setCount = (messageId: string, inc: number) => {
97
+ const existingCount = this.Context.counterMap.get(messageId) || 0;
98
+ const newCount = existingCount + inc;
99
+ console.log('set count', messageId, newCount);
100
+ this.Context.counterMap.set(messageId, newCount);
101
+ };
102
+
105
103
  public dispose?: (() => void) | undefined = () => {
106
104
  this.batchFillingDataManager.dispose();
107
105
 
@@ -114,11 +112,6 @@ export class FormFillingPlugin extends ChatAreaPlugin<FormFillingPluginCtx> {
114
112
  FILLING_EVENTS.FORM_FILLING_MODE_UPDATE,
115
113
  this.handleFillModeUpdate
116
114
  );
117
-
118
- this.sdkInst.eventBus.off<'chat-area-visibility-change'>(
119
- 'chat-area-visibility-change',
120
- this.handleChatAreaVisibilityChange
121
- );
122
115
  };
123
116
 
124
117
  private handleFormStructureReady: EventHandler<FormStructure> = (params: FormStructure) => {
@@ -144,7 +137,38 @@ export class FormFillingPlugin extends ChatAreaPlugin<FormFillingPluginCtx> {
144
137
  });
145
138
  };
146
139
 
140
+ private clearHistoryConversation = async (conversationId: string) => {
141
+ const apiEndpoint = this.sdkInst?.options.backendApiEndpoint;
142
+ if (!apiEndpoint) {
143
+ console.error('Backend API endpoint is not defined in SDK options.');
144
+ return;
145
+ }
146
+
147
+ if (!conversationId) {
148
+ console.error('Conversation ID is required to clear history.');
149
+ return;
150
+ }
151
+
152
+ await fetch(`${ensureEndSlash(apiEndpoint)}form/conversation/clear`, {
153
+ method: 'POST',
154
+ body: JSON.stringify({ conversationId }),
155
+ });
156
+ };
157
+
158
+ public clearBatchFilledData = () => {
159
+ this.clearHistoryConversation(this.Context.conversationId);
160
+ this.sdkInst.clearChatHistory();
161
+ this.batchFillingDataManager.clear();
162
+ };
163
+
147
164
  public lifecycleHooks?: PluginHooks | undefined = {
165
+ onAfterChatAreaHide: ({ clearMsgs }) => {
166
+ // reset to AI mode when chat area is hidden
167
+ clearMsgs?.();
168
+ this.Context.fillMode = 'AI';
169
+ this.Context.counterMap.clear();
170
+ this.clearHistoryConversation(this.Context.conversationId);
171
+ },
148
172
  onBeforeChatRender: () => {
149
173
  return {
150
174
  enableMessageMerge: true,
@@ -163,39 +187,31 @@ export class FormFillingPlugin extends ChatAreaPlugin<FormFillingPluginCtx> {
163
187
  onBeforeMessagePartsRender: (parts: Array<part>) => {
164
188
  // todo: reduce loops
165
189
  const mergedParts = mergeParts(parts as UIMessagePart<UIDataTypes, UITools>[], (p0, p1) => {
190
+ if (p0.type !== p1.type) {
191
+ return false;
192
+ }
193
+
166
194
  if (Array.isArray(p0) || Array.isArray(p1)) {
167
195
  return false;
168
196
  }
169
197
 
170
198
  const meta0 = extractTextPartMeta(p0);
171
199
  const meta1 = extractTextPartMeta(p1);
172
- return meta0?.field?.fieldName == meta1?.field?.fieldName;
173
- });
174
-
175
- return mergeConsecutiveTargets<part>(mergedParts, IsFieldsJsonPart) as part[];
176
- },
177
- onBeforeMessagesClear: () => {
178
- const conversationId = this.Context?.conversationId || '';
179
- if (!conversationId) {
180
- return;
181
- }
182
200
 
183
- const req = async () => {
184
- await fetch(`https://agent.online-office.net/web/api/form/conversation/clear`, {
185
- method: 'POST',
186
- body: JSON.stringify({ conversationId }),
187
- });
201
+ const fieldName0 = meta0?.field?.fieldName;
202
+ const fieldName1 = meta1?.field?.fieldName;
188
203
 
189
- const keepCtx = this.Context.fillMode === 'batch';
190
-
191
- if (keepCtx) {
192
- return;
204
+ if (!fieldName0 || !fieldName1) {
205
+ return false;
193
206
  }
194
207
 
195
- this.Context = FormFillingPluginRegisterEntry.createContext();
196
- };
208
+ return fieldName0 === fieldName1;
209
+ });
197
210
 
198
- req();
211
+ return mergeConsecutiveTargets<part>(mergedParts, IsFieldsJsonPart) as part[];
212
+ },
213
+ onBeforeMessagesClear: (id) => {
214
+ this.clearHistoryConversation(id!);
199
215
  },
200
216
  onBeforeMessageSend: (ctx) => {
201
217
  const formStructure = Array.from(this.Context?.fieldMap.values() || []);
@@ -216,6 +232,9 @@ export class FormFillingPlugin extends ChatAreaPlugin<FormFillingPluginCtx> {
216
232
  },
217
233
  };
218
234
  },
235
+ onAfterMessageSend: (_) => {
236
+ this.sdkInst?.setGlobalLoadingMessage('正在处理');
237
+ },
219
238
  };
220
239
  }
221
240
 
@@ -229,6 +248,7 @@ export const FormFillingPluginRegisterEntry: PluginRegistryEntry<FormFillingPlug
229
248
  subFieldsNameMap: new Map(),
230
249
  conversationId: '',
231
250
  fillMode: 'AI',
251
+ counterMap: new Map(),
232
252
  };
233
253
  },
234
254
  };
@@ -1,5 +1,7 @@
1
- import { FormFillingMode } from '@baishuyun/types';
1
+ import { FormFillingMode, MsgPartCompProps } from '@baishuyun/types';
2
2
  import { Field } from '../form-builder-base-plugin/types';
3
+ import { TextUIPart } from 'ai';
4
+ import { FieldValueCheckerProps } from '@/components/biz-comp/FieldValueChecker';
3
5
 
4
6
  export interface FormFillingPluginCtx {
5
7
  fieldMap: Map<string, Field>;
@@ -11,4 +13,22 @@ export interface FormFillingPluginCtx {
11
13
  conversationId: string;
12
14
 
13
15
  fillMode: FormFillingMode;
16
+
17
+ counterMap: Map<string, number>; // key is messageId, value is row counter
14
18
  }
19
+
20
+ export type FillPartRenderStrategy =
21
+ | 'batch' // 批量填写模式渲染
22
+ | 'single' // 单条填写模式渲染
23
+ | 'markdown' // markdown 内容渲染,通用行为
24
+ | 'unknown'; // 未知类型,null
25
+
26
+ export interface IFieldsData {
27
+ fieldsParts: TextUIPart[];
28
+ filledFields: Array<FieldValueCheckerProps>;
29
+ fieldPropsArray: Array<FieldValueCheckerProps | null>;
30
+ }
31
+
32
+ export type FillPartRenderStrategyMap = {
33
+ [key in FillPartRenderStrategy]: React.FC<MsgPartCompProps & IFieldsData>;
34
+ };
@@ -7,11 +7,9 @@ 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
 
12
+ // TODO: refactor with strategy pattern;
15
13
  export const QueryMsgPart = ({ part, ...rest }: MsgPartCompProps) => {
16
14
  const textPart = part as TextUIPart;
17
15
  const ctx = usePluginCtx<IReportQueryContext, ReportQueryPlugin>(PLUGIN_NAME);
@@ -29,25 +27,34 @@ export const QueryMsgPart = ({ part, ...rest }: MsgPartCompProps) => {
29
27
 
30
28
  if (result.isAggregate) {
31
29
  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>
30
+ <CreatedSourceMsg
31
+ type={'aggregate'}
32
+ title={result.title || ''}
33
+ done={textPart.state === 'done'}
34
+ />
44
35
  );
45
36
  }
46
37
 
47
- console.log('set query result in context', result);
38
+ console.log('queryResult', result);
39
+
48
40
  ctx.queryResult = result;
49
41
  ctx.queryResult.appID = ctx.appInfo?.appId || '';
50
- return <DataTableCard {...(result || {})}></DataTableCard>;
42
+
43
+ return (
44
+ <>
45
+ {result.source && result.source !== 'aggregate' ? (
46
+ <CreatedSourceMsg
47
+ type={result.source}
48
+ title={result.title || ''}
49
+ done={textPart.state === 'done'}
50
+ />
51
+ ) : null}
52
+ <DataTableCard
53
+ {...(result || {})}
54
+ streaming={textPart?.state === 'streaming'}
55
+ ></DataTableCard>
56
+ </>
57
+ );
51
58
  }
52
59
 
53
60
  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,
@@ -12,8 +13,15 @@ import { QueryEntryBtn } from './components/query-entry-btn';
12
13
  import { QueryAvatar } from './components/avatar';
13
14
  import { QueryMsgPart } from './components/query-msg-part';
14
15
  import { queryResult2createParams, queryResult2previewerProps } from './utils';
16
+ import { ensureEndSlash } from '@/lib/utils';
15
17
 
16
18
  export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
19
+ private _inst: IChatSDK | null = null;
20
+
21
+ public init?: ((sdk: IChatSDK) => void) | undefined = (sdkInst: IChatSDK) => {
22
+ this._inst = sdkInst;
23
+ };
24
+
17
25
  public pluginName: string = PLUGIN_NAME;
18
26
 
19
27
  public customComponents?: Partial<PluginCustomComponent> | undefined = {
@@ -24,8 +32,12 @@ export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
24
32
  };
25
33
 
26
34
  public lifecycleHooks?: PluginHooks | undefined = {
35
+ onBeforeMessagesClear: (conversationId) => {
36
+ this.clearHistoryConversation(conversationId || '');
37
+ },
38
+
27
39
  onAfterChatAreaHide: ({ clearMsgs }) => {
28
- // clearMsgs();
40
+ clearMsgs();
29
41
  },
30
42
 
31
43
  onBeforeChatRender: () => {
@@ -43,11 +55,15 @@ export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
43
55
  },
44
56
  };
45
57
  },
58
+
59
+ onAfterMessageSend: (_) => {
60
+ console.log('enter onAfterMessageSend hook in ReportQueryPlugin');
61
+ this.setLoadingMsg('正在处理');
62
+ },
46
63
  };
47
64
 
48
65
  public getPreviewerProps = (entryId: string) => {
49
66
  if (!this.Context.queryResult) {
50
- console.log('No query result in context');
51
67
  return null;
52
68
  }
53
69
 
@@ -56,7 +72,6 @@ export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
56
72
 
57
73
  public getCreateParams = (entryId: string) => {
58
74
  if (!this.Context.queryResult) {
59
- console.log('No query result in context');
60
75
  return null;
61
76
  }
62
77
 
@@ -92,14 +107,35 @@ export class ReportQueryPlugin extends ChatAreaPlugin<IReportQueryContext> {
92
107
  console.log('forms received in plugin:', formMap);
93
108
  };
94
109
 
110
+ private clearHistoryConversation = async (conversationId: string, inst?: IChatSDK) => {
111
+ const apiEndpoint = (inst || this._inst)?.options.backendApiEndpoint;
112
+ if (!apiEndpoint) {
113
+ console.error('Backend API endpoint is not defined in SDK options.');
114
+ return;
115
+ }
116
+
117
+ if (!conversationId) {
118
+ console.error('Conversation ID is required to clear history.');
119
+ return;
120
+ }
121
+
122
+ await fetch(`${ensureEndSlash(apiEndpoint)}/form/conversation/clear`, {
123
+ method: 'POST',
124
+ body: JSON.stringify({ conversationId }),
125
+ });
126
+ };
127
+
128
+ private setLoadingMsg = (message: string) => {
129
+ this._inst?.setGlobalLoadingMessage(message);
130
+ };
131
+
95
132
  public constructor(ctx: IReportQueryContext) {
96
133
  super(ctx);
97
134
  this.Context = ctx;
98
135
  }
99
136
 
100
137
  public clearCtx = () => {
101
- // console.log('clear plugin context');
102
- // this.Context.queryResult = undefined;
138
+ this.Context.queryResult = undefined;
103
139
  };
104
140
  }
105
141
 
@@ -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,
@@ -107,7 +118,6 @@ export const setupStoreSubscriptions = (store: ChatStore, option: IChatSDKOption
107
118
  option.onChatStatusChange?.(status);
108
119
  // @deprecated, will be removed in future versions
109
120
  eventBus.emit('chat-area-visibility-change', { visible, status });
110
- console.log('chat status changed:', status);
111
121
  }
112
122
  );
113
123
  };
@@ -0,0 +1,116 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+
3
+ import { BorderAnimation } from '@/components/bs-ui/border-animation';
4
+
5
+ const meta = {
6
+ title: 'Animation/BorderAnimation',
7
+ component: BorderAnimation,
8
+ tags: ['autodocs'],
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ args: {},
13
+ } satisfies Meta<typeof BorderAnimation>;
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof meta>;
17
+
18
+ export const Default: Story = {
19
+ args: {
20
+ children: (
21
+ <div className="flex items-center gap-[6px] bg-white px-[10px] py-[4px] rounded-[4px]">
22
+ <span className="text-[#999] text-[14px]">
23
+ 数据生成中,可点击下方按钮暂停
24
+ </span>
25
+ </div>
26
+ ),
27
+ },
28
+ };
29
+
30
+ export const WithCustomContent: Story = {
31
+ args: {
32
+ children: (
33
+ <div className="bg-white px-4 py-3 rounded-[4px]">
34
+ <h3 className="text-[16px] font-medium text-[#333]">标题内容</h3>
35
+ <p className="text-[14px] text-[#666] mt-1">
36
+ 这是一段描述文字,展示边框动画效果。
37
+ </p>
38
+ </div>
39
+ ),
40
+ },
41
+ };
42
+
43
+ export const LargerRadius: Story = {
44
+ args: {
45
+ borderRadius: 12,
46
+ children: (
47
+ <div className="bg-white px-4 py-3 rounded-[12px]">
48
+ <p className="text-[14px] text-[#666]">圆角 12px 的边框动画</p>
49
+ </div>
50
+ ),
51
+ },
52
+ };
53
+
54
+ export const SlowAnimation: Story = {
55
+ args: {
56
+ duration: 5,
57
+ children: (
58
+ <div className="bg-white px-4 py-3 rounded-[4px]">
59
+ <p className="text-[14px] text-[#666]">慢速动画(5秒一圈)</p>
60
+ </div>
61
+ ),
62
+ },
63
+ };
64
+
65
+ export const FastAnimation: Story = {
66
+ args: {
67
+ duration: 1,
68
+ children: (
69
+ <div className="bg-white px-4 py-3 rounded-[4px]">
70
+ <p className="text-[14px] text-[#666]">快速动画(1秒一圈)</p>
71
+ </div>
72
+ ),
73
+ },
74
+ };
75
+
76
+ export const CustomGradient: Story = {
77
+ args: {
78
+ gradient:
79
+ 'linear-gradient(180deg, #FF84B4 0%, #FF0265 50%, #FFB1FA 100%)',
80
+ children: (
81
+ <div className="bg-white px-4 py-3 rounded-[4px]">
82
+ <p className="text-[14px] text-[#666]">自定义渐变色(粉色系)</p>
83
+ </div>
84
+ ),
85
+ },
86
+ };
87
+
88
+ export const CustomClassName: Story = {
89
+ args: {
90
+ className: 'w-[300px]',
91
+ children: (
92
+ <div className="bg-white px-4 py-3 rounded-[4px]">
93
+ <p className="text-[14px] text-[#666]">自定义宽度 300px</p>
94
+ </div>
95
+ ),
96
+ },
97
+ };
98
+
99
+ export const FullWidth: Story = {
100
+ decorators: [
101
+ (Story) => (
102
+ <div style={{ width: '500px' }}>
103
+ <Story />
104
+ </div>
105
+ ),
106
+ ],
107
+ args: {
108
+ children: (
109
+ <div className="bg-white px-4 py-3 rounded-[4px]">
110
+ <p className="text-[14px] text-[#666]">
111
+ 宽度 100%,自动填满父容器
112
+ </p>
113
+ </div>
114
+ ),
115
+ },
116
+ };