@baishuyun/chat-sdk 0.0.15 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/chat-sdk.js +16307 -15780
  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 +31 -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/PreviewerHeader.stories.tsx +14 -0
  66. package/src/stories/fields-design-info-table.stories.tsx +203 -0
@@ -44,14 +44,18 @@ export const ChatAreaHeader = ({
44
44
 
45
45
  <div className="actions flex items-center gap-2.5 text-[#666]">
46
46
  <IconBtn
47
+ onMouseDown={(e) => {
48
+ // 阻止事件冒泡,避免触发拖拽
49
+ e.stopPropagation();
50
+ }}
47
51
  tooltip={isDocked ? '悬浮' : '右侧打开'}
48
- className="hover:!bg-[#ffffff]"
52
+ // className="hover:!bg-[#ffffff]"
49
53
  icon={isDocked ? <FloatIcon /> : <DockIcon />}
50
54
  onClick={onDockClick}
51
55
  />
52
56
  <IconBtn
53
- tooltip="关闭"
54
- className="hover:!bg-[#ffffff]"
57
+ // tooltip="关闭"
58
+ // className="hover:!bg-[#ffffff]"
55
59
  icon={<CloseIcon />}
56
60
  onClick={onCloseClick}
57
61
  />
@@ -0,0 +1,160 @@
1
+ import { useState, useCallback, useMemo } from 'react';
2
+ import { IFieldDesignInfo } from '@baishuyun/types';
3
+ import { cn } from '@/lib/utils';
4
+ import { ChevronIcon } from './bs-icons';
5
+
6
+ interface FieldsDesignInfoTableProps {
7
+ fields: IFieldDesignInfo[];
8
+ }
9
+
10
+ /** Group fields into top-level items and subform groups */
11
+ function groupFields(fields: IFieldDesignInfo[]) {
12
+ const groups: Array<
13
+ | { kind: 'field'; field: IFieldDesignInfo }
14
+ | { kind: 'subform'; parent: IFieldDesignInfo; children: IFieldDesignInfo[] }
15
+ > = [];
16
+
17
+ let i = 0;
18
+ while (i < fields.length) {
19
+ const f = fields[i];
20
+ if (f.isSubForm) {
21
+ const children: IFieldDesignInfo[] = [];
22
+ let j = i + 1;
23
+ while (
24
+ j < fields.length &&
25
+ fields[j].isFieldInSubForm &&
26
+ fields[j].parentFormName === f.fieldName
27
+ ) {
28
+ children.push(fields[j]);
29
+ j++;
30
+ }
31
+ groups.push({ kind: 'subform', parent: f, children });
32
+ i = j;
33
+ } else {
34
+ groups.push({ kind: 'field', field: f });
35
+ i++;
36
+ }
37
+ }
38
+ return groups;
39
+ }
40
+
41
+ const cellCls = 'flex items-center px-1.5 py-2.5 text-xs leading-normal';
42
+
43
+ function FieldRow({
44
+ field,
45
+ isSubFormChild = false,
46
+ }: {
47
+ field: IFieldDesignInfo;
48
+ isSubFormChild?: boolean;
49
+ }) {
50
+ return (
51
+ <div className="flex items-center w-full">
52
+ {/* 名称 */}
53
+ <div className={cn(cellCls, 'w-20 shrink-0 min-h-[34px] whitespace-nowrap')}>
54
+ {isSubFormChild && (
55
+ <span className="inline-flex items-center justify-center shrink-0 w-5 h-5 opacity-0">
56
+ <ChevronIcon />
57
+ </span>
58
+ )}
59
+ <span>{field.fieldName}</span>
60
+ </div>
61
+ {/* 类型 */}
62
+ <div className={cn(cellCls, 'w-[72px] shrink-0 min-h-[34px] whitespace-nowrap')}>
63
+ {field.type}
64
+ </div>
65
+ {/* 必填 */}
66
+ <div className={cn(cellCls, 'w-9 shrink-0 min-h-[34px] whitespace-nowrap')}>
67
+ {field.required ? '是' : '否'}
68
+ </div>
69
+ {/* 说明 */}
70
+ <div className={cn(cellCls, 'flex-1 min-w-0 min-h-[34px]')}>
71
+ <span className="break-words min-w-0">{field.description}</span>
72
+ </div>
73
+ </div>
74
+ );
75
+ }
76
+
77
+ function SubFormGroup({
78
+ parent,
79
+ children,
80
+ }: {
81
+ parent: IFieldDesignInfo;
82
+ children: IFieldDesignInfo[];
83
+ }) {
84
+ const [isOpen, setIsOpen] = useState(true);
85
+ const toggle = useCallback(() => setIsOpen((v) => !v), []);
86
+
87
+ return (
88
+ <>
89
+ {/* 子表单 parent row */}
90
+ <div className="flex items-center w-full">
91
+ {/* 名称 */}
92
+ <div className={cn(cellCls, 'w-20 shrink-0 min-h-[34px]')}>
93
+ <button
94
+ type="button"
95
+ onClick={toggle}
96
+ className="inline-flex items-center justify-center shrink-0 w-5 h-5 rounded cursor-pointer text-[#666] relative -left-[2px]"
97
+ >
98
+ <ChevronIcon isOpen={isOpen} />
99
+ </button>
100
+ <span>{parent.fieldName}</span>
101
+ </div>
102
+ {/* 类型 */}
103
+ <div className={cn(cellCls, 'w-[72px] shrink-0 min-h-[34px] whitespace-nowrap')}>
104
+ {parent.type}
105
+ </div>
106
+ {/* 必填 */}
107
+ <div className={cn(cellCls, 'w-9 shrink-0 min-h-[34px] whitespace-nowrap')}>
108
+ {parent.required ? '是' : '否'}
109
+ </div>
110
+ {/* 说明 */}
111
+ <div className={cn(cellCls, 'flex-1 min-w-0 min-h-[34px]')}>
112
+ <span className="break-words min-w-0">{parent.description}</span>
113
+ </div>
114
+ </div>
115
+
116
+ {/* 子表单 children */}
117
+ {isOpen && children.map((child, idx) => <FieldRow key={idx} field={child} isSubFormChild />)}
118
+ </>
119
+ );
120
+ }
121
+
122
+ export function FieldsDesignInfoTable({ fields }: FieldsDesignInfoTableProps) {
123
+ const groups = useMemo(() => groupFields(fields), [fields]);
124
+
125
+ return (
126
+ <div className="flex flex-col items-start w-full bg-white rounded-[10px] overflow-hidden text-black my-[10px] border border-[#E0E0E0]">
127
+ {/* 表头 */}
128
+ <div className="flex items-center w-full shrink-0 bg-[#E5E6EB] rounded-t-[10px] border-b border-[#E0E0E0]">
129
+ <div className={cn(cellCls, 'w-20 shrink-0 h-[34px] font-bold whitespace-nowrap')}>
130
+ 名称
131
+ </div>
132
+ <div className={cn(cellCls, 'w-[72px] shrink-0 h-[34px] font-bold whitespace-nowrap')}>
133
+ 类型
134
+ </div>
135
+ <div
136
+ className={cn(
137
+ cellCls,
138
+ 'w-9 shrink-0 h-[34px] font-bold whitespace-nowrap justify-center'
139
+ )}
140
+ >
141
+ 必填
142
+ </div>
143
+ <div className={cn(cellCls, 'flex-1 min-w-0 h-[34px] font-bold whitespace-nowrap')}>
144
+ 说明
145
+ </div>
146
+ </div>
147
+
148
+ {/* 表体 */}
149
+ <div className="flex flex-col items-start w-full">
150
+ {groups.map((g, idx) =>
151
+ g.kind === 'field' ? (
152
+ <FieldRow key={idx} field={g.field} />
153
+ ) : (
154
+ <SubFormGroup key={idx} parent={g.parent} children={g.children} />
155
+ )
156
+ )}
157
+ </div>
158
+ </div>
159
+ );
160
+ }
@@ -76,6 +76,7 @@ export const FieldsPreviewer = forwardRef<HTMLDivElement, FieldsPreviewerProps>(
76
76
 
77
77
  closeBtnLabel,
78
78
  disableOperation,
79
+ disableConfirm,
79
80
  }: FieldsPreviewerProps) => {
80
81
  const p = fullscreen ? 0 : padding;
81
82
  const pr = fullscreen ? 0 : rightSpaceWidth;
@@ -137,6 +138,7 @@ export const FieldsPreviewer = forwardRef<HTMLDivElement, FieldsPreviewerProps>(
137
138
  confirmContent={confirmContent}
138
139
  closeBtnLabel={closeBtnLabel}
139
140
  disableOperation={disableOperation}
141
+ disableConfirm={disableConfirm}
140
142
  />
141
143
  <div className={contentCls} style={fullContentStyle}>
142
144
  {empty && isFields ? <PlaceholderDashedBox /> : children}
@@ -1,5 +1,5 @@
1
1
  import { cn } from '@/lib/utils';
2
- import { transCls } from '@/const/ui';
2
+ import { FORM_ICON_OPTIONS, transCls } from '@/const/ui';
3
3
  import { useState, memo, useEffect } from 'react';
4
4
  import { ChevronDownIcon } from '../ui/icons';
5
5
  import { PrimaryConfirmBtn } from './primary-confirm-btn';
@@ -15,46 +15,6 @@ export interface FormIconOption {
15
15
  value: number;
16
16
  }
17
17
 
18
- // Form icon data from iconfont.json (icons with name starting with "表单")
19
- export const FORM_ICON_OPTIONS: FormIconOption[] = [
20
- { id: 'biaodan1', code: '&#xe814;', label: '表单1', value: 25 },
21
- { id: 'biaodan2', code: '&#xe81d;', label: '表单2', value: 26 },
22
- { id: 'biaodan3', code: '&#xe81c;', label: '表单3', value: 27 },
23
- { id: 'biaodan4', code: '&#xe81a;', label: '表单4', value: 28 },
24
- { id: 'biaodan5', code: '&#xe813;', label: '表单5', value: 29 },
25
- { id: 'biaodan6', code: '&#xe81b;', label: '表单6', value: 30 },
26
- { id: 'biaodan7', code: '&#xe818;', label: '表单7', value: 31 },
27
- { id: 'biaodan8', code: '&#xe819;', label: '表单8', value: 32 },
28
- { id: 'biaodan9', code: '&#xe817;', label: '表单9', value: 33 },
29
- { id: 'biaodan10', code: '&#xe816;', label: '表单10', value: 34 },
30
- { id: 'biaodan11', code: '&#xe810;', label: '表单11', value: 35 },
31
- { id: 'biaodan12', code: '&#xe815;', label: '表单12', value: 36 },
32
- { id: 'biaodan13', code: '&#xe812;', label: '表单13', value: 37 },
33
- { id: 'biaodan14', code: '&#xe811;', label: '表单14', value: 38 },
34
- { id: 'biaodan15', code: '&#xe80e;', label: '表单15', value: 39 },
35
- { id: 'biaodan16', code: '&#xe80f;', label: '表单16', value: 40 },
36
- { id: 'biaodan17', code: '&#xe80d;', label: '表单17', value: 41 },
37
- { id: 'biaodan18', code: '&#xe807;', label: '表单18', value: 42 },
38
- { id: 'biaodan19', code: '&#xe80b;', label: '表单19', value: 43 },
39
- { id: 'biaodan20', code: '&#xe80a;', label: '表单20', value: 44 },
40
- { id: 'biaodan21', code: '&#xe80c;', label: '表单21', value: 45 },
41
- { id: 'biaodan22', code: '&#xe809;', label: '表单22', value: 46 },
42
- { id: 'biaodan23', code: '&#xe808;', label: '表单23', value: 47 },
43
- { id: 'biaodan24', code: '&#xe805;', label: '表单24', value: 48 },
44
- { id: 'biaodan25', code: '&#xe7ff;', label: '表单25', value: 49 },
45
- { id: 'biaodan26', code: '&#xe803;', label: '表单26', value: 50 },
46
- { id: 'biaodan27', code: '&#xe806;', label: '表单27', value: 51 },
47
- { id: 'biaodan28', code: '&#xe802;', label: '表单28', value: 52 },
48
- { id: 'biaodan29', code: '&#xe800;', label: '表单29', value: 53 },
49
- { id: 'biaodan30', code: '&#xe804;', label: '表单30', value: 54 },
50
- { id: 'biaodan31', code: '&#xe801;', label: '表单31', value: 55 },
51
- { id: 'biaodan32', code: '&#xe7fe;', label: '表单32', value: 56 },
52
- { id: 'biaodan33', code: '&#xe7fc;', label: '表单33', value: 57 },
53
- { id: 'biaodan34', code: '&#xe7fd;', label: '表单34', value: 58 },
54
- { id: 'biaodan35', code: '&#xe7fb;', label: '表单35', value: 59 },
55
- { id: 'biaodan36', code: '&#xe7fa;', label: '表单36', value: 60 },
56
- ];
57
-
58
18
  // Form icon component with blue background - dynamically shows selected icon
59
19
  const FormIcon = ({
60
20
  size = 36,
@@ -116,7 +76,7 @@ export const FormInfoEditor = memo(
116
76
  name,
117
77
  onNameChange,
118
78
  onMount,
119
- selectedIcon,
79
+ selectedIcon = FORM_ICON_OPTIONS[0],
120
80
  iconOptions = [],
121
81
  onIconChange,
122
82
  readonly,
@@ -1,11 +1,13 @@
1
- export const GenerateAnimation = (props: { children?: React.ReactNode }) => {
1
+ import classNames from "classnames";
2
+
3
+ export const GenerateAnimation = (props: { children?: React.ReactNode, className?: string }) => {
2
4
  return (
3
- <div className="flex items-center gap-[6px]">
5
+ <div className={classNames("flex items-center gap-[6px]", props.className)}>
4
6
  <div className="flex gap-[2px] flex-shrink-0" style={{ marginRight: '6px' }}>
5
7
  <div
6
8
  className="w-[5px] h-[5px] rounded-full bg-[#999] flex-shrink-0"
7
9
  style={{
8
- animation: 'pulse 1.4s ease-in-out infinite',
10
+ animation: 'pulse 1.0s ease-in-out infinite',
9
11
  animationDelay: '0s',
10
12
  width: '5px',
11
13
  height: '5px',
@@ -16,7 +18,7 @@ export const GenerateAnimation = (props: { children?: React.ReactNode }) => {
16
18
  <div
17
19
  className="w-[5px] h-[5px] rounded-full bg-[#999] flex-shrink-0"
18
20
  style={{
19
- animation: 'pulse 1.4s ease-in-out infinite',
21
+ animation: 'pulse 1.0s ease-in-out infinite',
20
22
  width: '5px',
21
23
  height: '5px',
22
24
  background: '#999',
@@ -27,7 +29,7 @@ export const GenerateAnimation = (props: { children?: React.ReactNode }) => {
27
29
  <div
28
30
  className="w-[5px] h-[5px] rounded-full bg-[#999] flex-shrink-0"
29
31
  style={{
30
- animation: 'pulse 1.4s ease-in-out infinite',
32
+ animation: 'pulse 1.0s ease-in-out infinite',
31
33
  width: '5px',
32
34
  height: '5px',
33
35
  marginRight: '3px',
@@ -11,7 +11,7 @@ export interface ImgMsgPartProps {
11
11
  export const ImgMsgPart = ({ url, alt = '', className, size = 102 }: ImgMsgPartProps) => {
12
12
  return (
13
13
  <div
14
- className={cn('relative overflow-hidden rounded-[10px]', className)}
14
+ className={cn('relative overflow-hidden rounded-[10px] border border-[#e0e0e0]', className)}
15
15
  style={{ width: size, height: size }}
16
16
  >
17
17
  <img
@@ -1,5 +1,4 @@
1
- import React, { CSSProperties, useState } from 'react';
2
- import { Checkbox } from '@/components/ui/checkbox';
1
+ import React, { CSSProperties, useEffect, useState } from 'react';
3
2
  import classNames from 'classnames';
4
3
  import { cn } from '@/lib/utils';
5
4
  import { CheckerIcon } from './bs-icons';
@@ -7,6 +6,7 @@ import { SquareChecker } from './square-checker';
7
6
 
8
7
  export interface LineCheckerProps {
9
8
  defaultChecked?: boolean;
9
+ checked?: boolean;
10
10
  disabled?: boolean;
11
11
  onCheckedChange?: (checked: boolean) => void;
12
12
 
@@ -24,6 +24,7 @@ export interface LineCheckerProps {
24
24
 
25
25
  export const LineChecker: React.FC<LineCheckerProps> = ({
26
26
  defaultChecked = false,
27
+ checked: checkedProp,
27
28
  disabled = false,
28
29
  onCheckedChange,
29
30
  icon,
@@ -38,6 +39,12 @@ export const LineChecker: React.FC<LineCheckerProps> = ({
38
39
  }) => {
39
40
  const [checked, setChecked] = useState(defaultChecked);
40
41
 
42
+ useEffect(() => {
43
+ if (checkedProp !== undefined) {
44
+ setChecked(checkedProp);
45
+ }
46
+ }, [checkedProp]);
47
+
41
48
  const handleClick = () => {
42
49
  if (streaming || disabled) return;
43
50
 
@@ -111,7 +118,7 @@ export const LineChecker: React.FC<LineCheckerProps> = ({
111
118
 
112
119
  {/* Title - truncates */}
113
120
  <p
114
- className={classNames(' min-w-0 text-sm text-[#121111] truncate', {
121
+ className={classNames(' min-w-0 text-sm text-[#121111] truncate text-[12px]', {
115
122
  'flex-1': !!icon,
116
123
  'flex-grow-1 flex-shrink-0': !icon,
117
124
  '!text-[#666]': readonly,
@@ -123,7 +130,7 @@ export const LineChecker: React.FC<LineCheckerProps> = ({
123
130
 
124
131
  {shortDesc && (
125
132
  <p
126
- className={classNames('text-sm text-[#666]', {
133
+ className={classNames('text-sm text-[#666] text-[12px]', {
127
134
  'whitespace-nowrap flex-shrink-0': !!icon,
128
135
  anywhere: !icon,
129
136
  '!text-[#121111]': readonly,
@@ -134,7 +141,14 @@ export const LineChecker: React.FC<LineCheckerProps> = ({
134
141
  )}
135
142
  </div>
136
143
  {hasExtra ? (
137
- <div className="overflow-x-auto whitespace-nowrap no-scrollbar flex items-center gap-2">
144
+ <div
145
+ className={cn(
146
+ 'overflow-x-auto whitespace-nowrap no-scrollbar flex items-center gap-2',
147
+ {
148
+ '!overflow-x-hidden': disabled || readonly || confirmed,
149
+ }
150
+ )}
151
+ >
138
152
  {extra}
139
153
  </div>
140
154
  ) : null}
@@ -4,6 +4,7 @@ import { IconBtn } from './icon-btn';
4
4
  import { BackIcon, InfoIcon } from './bs-icons';
5
5
  import { LinearGradientColorBgAnimation } from './linear-gradient-color-bg-animation';
6
6
  import { ConfirmDialog } from './confirm-dialog';
7
+ import { Spinner } from '../ui/spinner';
7
8
 
8
9
  export interface PreviewerHeaderProps {
9
10
  title: string;
@@ -11,7 +12,7 @@ export interface PreviewerHeaderProps {
11
12
  active?: boolean;
12
13
  className?: string;
13
14
  onBackClick?: () => void;
14
- onSave?: () => void;
15
+ onSave?: (isConfirm?: boolean) => void;
15
16
  onCancel?: () => void;
16
17
  style?: React.CSSProperties;
17
18
 
@@ -21,6 +22,8 @@ export interface PreviewerHeaderProps {
21
22
  variant?: 'fields-previewer' | 'data-previewer';
22
23
  closeBtnLabel?: string;
23
24
 
25
+ disableConfirm?: boolean;
26
+
24
27
  disableOperation?: boolean;
25
28
  }
26
29
 
@@ -38,6 +41,7 @@ export const PreviewerHeader = ({
38
41
  onCancel,
39
42
  variant = 'fields-previewer',
40
43
  dialogContainer,
44
+ disableConfirm,
41
45
  disableOperation,
42
46
  }: PreviewerHeaderProps) => {
43
47
  const [showConfirmDialog, setShowConfirmDialog] = useState(false);
@@ -62,7 +66,19 @@ export const PreviewerHeader = ({
62
66
  {isData ? null : (
63
67
  <IconBtn
64
68
  icon={<BackIcon />}
65
- onClick={() => setShowConfirmDialog(true)}
69
+ onClick={() => {
70
+ if (disableOperation) {
71
+ return;
72
+ }
73
+
74
+ if (disableConfirm) {
75
+ onCancel?.();
76
+ onBackClick?.();
77
+ return;
78
+ }
79
+
80
+ setShowConfirmDialog(true);
81
+ }}
66
82
  className="text-[#0265FF] hover:text-[#0265FF]"
67
83
  />
68
84
  )}
@@ -89,6 +105,7 @@ export const PreviewerHeader = ({
89
105
  }}
90
106
  className={classNames(
91
107
  btnResetStyle,
108
+ 'flex items-center gap-[6px]',
92
109
  'bg-[#0265FF] hover:opacity-90 text-white text-[14px]',
93
110
  {
94
111
  'w-[115px]': isData,
@@ -96,12 +113,23 @@ export const PreviewerHeader = ({
96
113
  }
97
114
  )}
98
115
  >
116
+ {loading ? <Spinner /> : null}
99
117
  {isFields ? '保存' : '添加到表单'}
100
118
  </button>
101
119
  )}
102
120
  {onCancel && (
103
121
  <button
104
122
  onClick={() => {
123
+ if (disableOperation) {
124
+ return;
125
+ }
126
+
127
+ if (disableConfirm) {
128
+ onCancel?.();
129
+ onBackClick?.();
130
+ return;
131
+ }
132
+
105
133
  setShowConfirmDialog(true);
106
134
  }}
107
135
  className={classNames(
@@ -132,7 +160,7 @@ export const PreviewerHeader = ({
132
160
  setShowConfirmDialog(false);
133
161
  setLoading(true);
134
162
  try {
135
- await onSave?.();
163
+ await onSave?.(true);
136
164
  } catch (error) {
137
165
  console.error('Save failed:', error);
138
166
  } finally {
@@ -3,15 +3,32 @@ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
3
3
  import { cn } from '@/lib/utils';
4
4
  import { CheckerInBoxIcon } from './bs-icons';
5
5
 
6
+ const SquareInBoxIcon = () => {
7
+ // size 8, border 1px svg
8
+ return (
9
+ <svg
10
+ width="8"
11
+ height="8"
12
+ viewBox="0 0 8 8"
13
+ // fill="currentColor"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ >
16
+ <rect x="0.5" y="0.5" width="7" height="7" rx="1" fill="#0265ff" />
17
+ </svg>
18
+ );
19
+ };
20
+
6
21
  export type SquareCheckerProps = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> & {
7
22
  /** Optional label rendered beside the checkbox */
8
23
  children?: React.ReactNode;
24
+ readonly?: boolean;
25
+ intermediate?: boolean;
9
26
  };
10
27
 
11
28
  export const SquareChecker = React.forwardRef<
12
29
  React.ElementRef<typeof CheckboxPrimitive.Root>,
13
30
  SquareCheckerProps
14
- >(({ className, children, id, disabled, ...props }, ref) => {
31
+ >(({ className, children, id, readonly, disabled, intermediate, ...props }, ref) => {
15
32
  const generatedId = React.useId();
16
33
  const checkboxId = id ?? generatedId;
17
34
 
@@ -20,7 +37,10 @@ export const SquareChecker = React.forwardRef<
20
37
  htmlFor={checkboxId}
21
38
  className={cn(
22
39
  'inline-flex items-center gap-[6px] select-none text-[#121111] text-[14px]',
23
- disabled ? 'cursor-not-allowed' : 'cursor-pointer'
40
+ disabled ? 'cursor-not-allowed' : 'cursor-pointer',
41
+ {
42
+ 'pointer-events-none': readonly,
43
+ }
24
44
  )}
25
45
  >
26
46
  <CheckboxPrimitive.Root
@@ -43,12 +63,17 @@ export const SquareChecker = React.forwardRef<
43
63
  'disabled:cursor-not-allowed disabled:bg-[#F0F0F0] disabled:border-[#C2C2C2]',
44
64
  // disabled checked: use muted gray fill
45
65
  'disabled:data-[state=checked]:bg-[#C2C2C2] disabled:data-[state=checked]:border-[#C2C2C2]',
46
- className
66
+ // indeterminate: blue fill
67
+ intermediate && 'bg-white border-[#0265FF] text-[#0265FF]',
68
+ className,
69
+ {
70
+ 'opacity-50': readonly,
71
+ }
47
72
  )}
48
73
  {...props}
49
74
  >
50
- <CheckboxPrimitive.Indicator className="text-white">
51
- <CheckerInBoxIcon />
75
+ <CheckboxPrimitive.Indicator className="text-white" forceMount={intermediate || undefined}>
76
+ {intermediate ? <SquareInBoxIcon /> : <CheckerInBoxIcon />}
52
77
  </CheckboxPrimitive.Indicator>
53
78
  </CheckboxPrimitive.Root>
54
79
 
@@ -44,7 +44,7 @@ export const BsTooltip = ({
44
44
  </TooltipTrigger>
45
45
  <TooltipContent
46
46
  portalContainer={portalContainer}
47
- className="rounded-[4px] bg-[#525867] px-[12px] !py-[7px] text-[12px] text-white leading-normal max-w-[288px]"
47
+ className="rounded-[4px] bg-[#525867] px-[12px] !py-[7px] text-[12px] text-white leading-normal max-w-[288px] animate-in fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 duration-200"
48
48
  >
49
49
  {content}
50
50
  </TooltipContent>
@@ -40,7 +40,7 @@ const DialogContent = React.forwardRef<
40
40
  style={{ padding: 0 }}
41
41
  ref={ref}
42
42
  className={cn(
43
- 'left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
43
+ 'left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg',
44
44
  container ? 'absolute' : 'fixed',
45
45
  className
46
46
  )}
@@ -42,7 +42,7 @@ const TooltipContent = React.forwardRef<
42
42
  {...props}
43
43
  >
44
44
  {props.children}
45
- <TooltipPrimitive.Arrow className="fill-[#525867]" />
45
+ <TooltipPrimitive.Arrow className="fill-[#525867] stroke-[#525867] stroke-[2px] stroke-linejoin-round [paint-order:stroke_fill]" />
46
46
  </TooltipPrimitive.Content>
47
47
  </TooltipPrimitive.Portal>
48
48
  );
package/src/const/ui.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { FormIconOption } from '@/components/bs-ui/form-info-editor';
2
+
1
3
  export const BotImgUrl = `
2
4
  url(data:image/png;base64,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)
3
5
  `;
@@ -8,3 +10,43 @@ url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAACaCAMAAACg5DWcAAAC/VBMVE
8
10
  export const ChatHeaderBgImgUrl = `url(data:image/png;base64,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)`;
9
11
 
10
12
  export const transCls = 'transition-all duration-200 ease-out';
13
+ // Form icon data from iconfont.json (icons with name starting with "表单")
14
+
15
+ export const FORM_ICON_OPTIONS: FormIconOption[] = [
16
+ { id: 'biaodan1', code: '&#xe814;', label: '表单1', value: 25 },
17
+ { id: 'biaodan2', code: '&#xe81d;', label: '表单2', value: 26 },
18
+ { id: 'biaodan3', code: '&#xe81c;', label: '表单3', value: 27 },
19
+ { id: 'biaodan4', code: '&#xe81a;', label: '表单4', value: 28 },
20
+ { id: 'biaodan5', code: '&#xe813;', label: '表单5', value: 29 },
21
+ { id: 'biaodan6', code: '&#xe81b;', label: '表单6', value: 30 },
22
+ { id: 'biaodan7', code: '&#xe818;', label: '表单7', value: 31 },
23
+ { id: 'biaodan8', code: '&#xe819;', label: '表单8', value: 32 },
24
+ { id: 'biaodan9', code: '&#xe817;', label: '表单9', value: 33 },
25
+ { id: 'biaodan10', code: '&#xe816;', label: '表单10', value: 34 },
26
+ { id: 'biaodan11', code: '&#xe810;', label: '表单11', value: 35 },
27
+ { id: 'biaodan12', code: '&#xe815;', label: '表单12', value: 36 },
28
+ { id: 'biaodan13', code: '&#xe812;', label: '表单13', value: 37 },
29
+ { id: 'biaodan14', code: '&#xe811;', label: '表单14', value: 38 },
30
+ { id: 'biaodan15', code: '&#xe80e;', label: '表单15', value: 39 },
31
+ { id: 'biaodan16', code: '&#xe80f;', label: '表单16', value: 40 },
32
+ { id: 'biaodan17', code: '&#xe80d;', label: '表单17', value: 41 },
33
+ { id: 'biaodan18', code: '&#xe807;', label: '表单18', value: 42 },
34
+ { id: 'biaodan19', code: '&#xe80b;', label: '表单19', value: 43 },
35
+ { id: 'biaodan20', code: '&#xe80a;', label: '表单20', value: 44 },
36
+ { id: 'biaodan21', code: '&#xe80c;', label: '表单21', value: 45 },
37
+ { id: 'biaodan22', code: '&#xe809;', label: '表单22', value: 46 },
38
+ { id: 'biaodan23', code: '&#xe808;', label: '表单23', value: 47 },
39
+ { id: 'biaodan24', code: '&#xe805;', label: '表单24', value: 48 },
40
+ { id: 'biaodan25', code: '&#xe7ff;', label: '表单25', value: 49 },
41
+ { id: 'biaodan26', code: '&#xe803;', label: '表单26', value: 50 },
42
+ { id: 'biaodan27', code: '&#xe806;', label: '表单27', value: 51 },
43
+ { id: 'biaodan28', code: '&#xe802;', label: '表单28', value: 52 },
44
+ { id: 'biaodan29', code: '&#xe800;', label: '表单29', value: 53 },
45
+ { id: 'biaodan30', code: '&#xe804;', label: '表单30', value: 54 },
46
+ { id: 'biaodan31', code: '&#xe801;', label: '表单31', value: 55 },
47
+ { id: 'biaodan32', code: '&#xe7fe;', label: '表单32', value: 56 },
48
+ { id: 'biaodan33', code: '&#xe7fc;', label: '表单33', value: 57 },
49
+ { id: 'biaodan34', code: '&#xe7fd;', label: '表单34', value: 58 },
50
+ { id: 'biaodan35', code: '&#xe7fb;', label: '表单35', value: 59 },
51
+ { id: 'biaodan36', code: '&#xe7fa;', label: '表单36', value: 60 },
52
+ ];
@@ -17,6 +17,21 @@ export const useChatStatus = () => {
17
17
  };
18
18
  };
19
19
 
20
+ export const useFakeGlobalLoadingMessage = () => {
21
+ const { globalFakeLoadingMessage, setGlobalFakeLoadingMessage, clearGlobalFakeLoadingMessage } =
22
+ useChatStore((store) => ({
23
+ globalFakeLoadingMessage: store.globalFakeLoadingMessage,
24
+ setGlobalFakeLoadingMessage: store.setGlobalFakeLoadingMessage,
25
+ clearGlobalFakeLoadingMessage: store.clearGlobalFakeLoadingMessage,
26
+ }));
27
+
28
+ return {
29
+ globalFakeLoadingMessage,
30
+ setGlobalFakeLoadingMessage,
31
+ clearGlobalFakeLoadingMessage,
32
+ };
33
+ };
34
+
20
35
  /** @deprecated Use useChatStatus instead */
21
36
  export const useFrameMode = () => {
22
37
  const { status, setStatus } = useChatStatus();