@cozeloop/components 0.0.3 → 0.0.5

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 (169) hide show
  1. package/dist/es/index.js +1 -1
  2. package/dist/lib/code-editor/index.js +3 -1
  3. package/dist/lib/code-editor/index.js.map +1 -1
  4. package/dist/lib/tsconfig.build.tsbuildinfo +1 -1
  5. package/package.json +9 -3
  6. package/.eslintcache +0 -1
  7. package/.rush/temp/shrinkwrap-deps.json +0 -770
  8. package/OWNERS +0 -5
  9. package/config/rush-project.json +0 -8
  10. package/eslint.config.js +0 -7
  11. package/rslib.config.js +0 -7
  12. package/script/publish.js +0 -146
  13. package/src/base-search-select/base-search-form-select.tsx +0 -10
  14. package/src/base-search-select/base-search-select.tsx +0 -200
  15. package/src/base-search-select/index.module.less +0 -16
  16. package/src/base-search-select/index.tsx +0 -3
  17. package/src/base-search-select/types.ts +0 -16
  18. package/src/base-search-select/utils.ts +0 -78
  19. package/src/basic-card/index.tsx +0 -23
  20. package/src/card-pane/index.module.less +0 -14
  21. package/src/card-pane/index.tsx +0 -25
  22. package/src/chip-select/index.module.less +0 -17
  23. package/src/chip-select/index.tsx +0 -7
  24. package/src/code-editor/index.tsx +0 -9
  25. package/src/code-usage/code-item.module.less +0 -32
  26. package/src/code-usage/index.tsx +0 -91
  27. package/src/codemirror-editor/code-editor.tsx +0 -139
  28. package/src/codemirror-editor/index.ts +0 -4
  29. package/src/codemirror-editor/json-editor.tsx +0 -183
  30. package/src/codemirror-editor/raw-text-editor.tsx +0 -68
  31. package/src/codemirror-editor/text-editor.tsx +0 -58
  32. package/src/codemirror-editor/themes/coze-dark.ts +0 -116
  33. package/src/codemirror-editor/themes/coze-light.ts +0 -122
  34. package/src/collapse-card/index.module.less +0 -27
  35. package/src/collapse-card/index.tsx +0 -93
  36. package/src/collapsible-card/index.module.less +0 -63
  37. package/src/collapsible-card/index.tsx +0 -57
  38. package/src/column-manage-storage/index.tsx +0 -64
  39. package/src/columns-select/index.tsx +0 -244
  40. package/src/edit-icon-button/index.tsx +0 -36
  41. package/src/footer-actions/index.tsx +0 -33
  42. package/src/hooks/use-infinite-scroll.ts +0 -183
  43. package/src/hooks/use-mouse-down-offset.ts +0 -50
  44. package/src/hooks/use-unsave-leave-warning.ts +0 -49
  45. package/src/id-render/icon-button-container.tsx +0 -37
  46. package/src/id-render/index.tsx +0 -64
  47. package/src/index-controller/record-navigation.tsx +0 -57
  48. package/src/index-controller/use-item-index-controller.ts +0 -197
  49. package/src/index.ts +0 -208
  50. package/src/infinite-scroll-table/index.tsx +0 -99
  51. package/src/info-tooltip/index.tsx +0 -41
  52. package/src/input-components/radio-button.tsx +0 -63
  53. package/src/input-slider/index.module.less +0 -30
  54. package/src/input-slider/index.tsx +0 -161
  55. package/src/input-with-count/index.tsx +0 -31
  56. package/src/jump-button/jump-icon-button.tsx +0 -12
  57. package/src/large-txt-render/index.tsx +0 -46
  58. package/src/layout/content.tsx +0 -28
  59. package/src/layout/header.tsx +0 -15
  60. package/src/layout/index.module.less +0 -28
  61. package/src/layout/index.tsx +0 -9
  62. package/src/layout/tabs.tsx +0 -11
  63. package/src/lazy-load-component/index.tsx +0 -55
  64. package/src/logic-editor/index.ts +0 -3
  65. package/src/logic-editor/logic-editor.module.less +0 -13
  66. package/src/logic-editor/logic-editor.tsx +0 -200
  67. package/src/logic-editor/logic-left-render.tsx +0 -100
  68. package/src/logic-editor/logic-operator-render.tsx +0 -54
  69. package/src/logic-editor/logic-right-render.tsx +0 -51
  70. package/src/logic-editor/logic-types.tsx +0 -238
  71. package/src/logic-editor/utils.ts +0 -22
  72. package/src/logic-expr/assets/select.svg +0 -1
  73. package/src/logic-expr/consts.ts +0 -6
  74. package/src/logic-expr/expr-group-render.tsx +0 -238
  75. package/src/logic-expr/expr-render.tsx +0 -226
  76. package/src/logic-expr/index.module.less +0 -252
  77. package/src/logic-expr/index.ts +0 -13
  78. package/src/logic-expr/logic-expr.tsx +0 -261
  79. package/src/logic-expr/logic-not.tsx +0 -46
  80. package/src/logic-expr/logic-toggle.tsx +0 -96
  81. package/src/logic-expr/types.ts +0 -95
  82. package/src/loop-radio-group/index.tsx +0 -16
  83. package/src/multi-part-editor/components/image-item-renderer.tsx +0 -134
  84. package/src/multi-part-editor/components/index.module.less +0 -21
  85. package/src/multi-part-editor/components/multipart-item-renderer.tsx +0 -74
  86. package/src/multi-part-editor/components/url-input-modal.tsx +0 -317
  87. package/src/multi-part-editor/components/video-item-renderer.tsx +0 -145
  88. package/src/multi-part-editor/index.module.less +0 -8
  89. package/src/multi-part-editor/index.tsx +0 -571
  90. package/src/multi-part-editor/multi-part-render.tsx +0 -87
  91. package/src/multi-part-editor/type.tsx +0 -103
  92. package/src/multi-part-editor/upload-button.tsx +0 -256
  93. package/src/multi-part-editor/utils.ts +0 -64
  94. package/src/open-detail-button/index.tsx +0 -30
  95. package/src/page-content/index.tsx +0 -99
  96. package/src/primary-page/index.tsx +0 -1
  97. package/src/primary-page/primary-header.tsx +0 -64
  98. package/src/primary-title/index.module.less +0 -14
  99. package/src/primary-title/index.tsx +0 -18
  100. package/src/provider/index.tsx +0 -89
  101. package/src/resizable-side-sheet/index.tsx +0 -69
  102. package/src/resize-sidesheet/index.module.less +0 -14
  103. package/src/resize-sidesheet/index.tsx +0 -68
  104. package/src/resize-sidesheet/use-drag.ts +0 -43
  105. package/src/schema-editor/index.tsx +0 -52
  106. package/src/search-form/index.tsx +0 -134
  107. package/src/semi-schema-form/components/tmpls/array-field-item.tsx +0 -97
  108. package/src/semi-schema-form/components/tmpls/array-field.tsx +0 -127
  109. package/src/semi-schema-form/components/tmpls/base-input.tsx +0 -126
  110. package/src/semi-schema-form/components/tmpls/description-field.tsx +0 -23
  111. package/src/semi-schema-form/components/tmpls/error-list.tsx +0 -44
  112. package/src/semi-schema-form/components/tmpls/field-error.tsx +0 -33
  113. package/src/semi-schema-form/components/tmpls/field.tsx +0 -54
  114. package/src/semi-schema-form/components/tmpls/icon-button.tsx +0 -112
  115. package/src/semi-schema-form/components/tmpls/index.ts +0 -39
  116. package/src/semi-schema-form/components/tmpls/object-field.tsx +0 -173
  117. package/src/semi-schema-form/components/tmpls/submit.tsx +0 -31
  118. package/src/semi-schema-form/components/tmpls/title-field.tsx +0 -30
  119. package/src/semi-schema-form/components/widgets/checkbox.tsx +0 -67
  120. package/src/semi-schema-form/components/widgets/checkboxs.tsx +0 -100
  121. package/src/semi-schema-form/components/widgets/index.ts +0 -17
  122. package/src/semi-schema-form/components/widgets/radio.tsx +0 -105
  123. package/src/semi-schema-form/components/widgets/range.tsx +0 -73
  124. package/src/semi-schema-form/components/widgets/select.tsx +0 -108
  125. package/src/semi-schema-form/components/widgets/textarea.tsx +0 -63
  126. package/src/semi-schema-form/index.tsx +0 -14
  127. package/src/sentinel-form/enum.ts +0 -16
  128. package/src/sentinel-form/index.tsx +0 -382
  129. package/src/step-nav/index.module.less +0 -45
  130. package/src/step-nav/index.tsx +0 -53
  131. package/src/table/index.module.less +0 -144
  132. package/src/table/index.tsx +0 -18
  133. package/src/table/sort-icon.tsx +0 -73
  134. package/src/table/table-with-pagination.tsx +0 -150
  135. package/src/table/table-without-pagniation.tsx +0 -66
  136. package/src/table-batch-operate/table-batch-operation.tsx +0 -47
  137. package/src/table-batch-operate/use-batch-operate.ts +0 -111
  138. package/src/table-col-actions/index.module.less +0 -8
  139. package/src/table-col-actions/index.tsx +0 -149
  140. package/src/table-cols-config/index.module.less +0 -34
  141. package/src/table-cols-config/index.tsx +0 -171
  142. package/src/table-cols-config/type.ts +0 -12
  143. package/src/table-cols-config/use-hidden-col-keys.ts +0 -53
  144. package/src/table-cols-config/util.ts +0 -56
  145. package/src/table-empty/index.tsx +0 -23
  146. package/src/table-header/index.module.less +0 -7
  147. package/src/table-header/index.tsx +0 -70
  148. package/src/tabs/index.module.less +0 -48
  149. package/src/tabs/index.tsx +0 -9
  150. package/src/text-area-pro/index.module.less +0 -5
  151. package/src/text-area-pro/index.tsx +0 -49
  152. package/src/text-with-copy/index.tsx +0 -95
  153. package/src/title-with-sub/index.tsx +0 -27
  154. package/src/tooltip-when-disabled/index.tsx +0 -23
  155. package/src/tooltip-with-disabled/index.tsx +0 -17
  156. package/src/types.d.ts +0 -24
  157. package/src/upload/index.ts +0 -39
  158. package/src/user-profile/index.tsx +0 -49
  159. package/src/utils/basic.ts +0 -29
  160. package/src/version-list/index.module.less +0 -16
  161. package/src/version-list/version-descriptions.tsx +0 -80
  162. package/src/version-list/version-item.tsx +0 -30
  163. package/src/version-list/version-list.tsx +0 -59
  164. package/src/version-list/version-switch-panel.tsx +0 -31
  165. package/tailwind.config.ts +0 -6
  166. package/tsconfig.build.json +0 -44
  167. package/tsconfig.json +0 -17
  168. package/tsconfig.misc.json +0 -28
  169. package/vitest.config.mts +0 -7
@@ -1,571 +0,0 @@
1
- /* eslint-disable max-lines */
2
- /* eslint-disable complexity */
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
- /* eslint-disable max-lines-per-function */
5
- /* eslint-disable @coze-arch/use-error-in-catch */
6
- /* eslint-disable @coze-arch/max-line-per-function */
7
- import React, { useRef, useState, useEffect, useCallback } from 'react';
8
-
9
- import Sortable from 'sortablejs';
10
- import { nanoid } from 'nanoid';
11
- import classNames from 'classnames';
12
- import {
13
- ContentType,
14
- type Image as ImageProps,
15
- } from '@cozeloop/api-schema/evaluation';
16
- import { StorageProvider } from '@cozeloop/api-schema/data';
17
- import { IconCozPlus, IconCozHandle } from '@coze-arch/coze-design/icons';
18
- import {
19
- Button,
20
- IconButton,
21
- Menu,
22
- Toast,
23
- Typography,
24
- Upload,
25
- type UploadProps,
26
- } from '@coze-arch/coze-design';
27
-
28
- import { TooltipWhenDisabled } from '../tooltip-when-disabled';
29
-
30
- import { getMultipartConfig } from './utils';
31
- import {
32
- ImageStatus,
33
- type MultipartItemContentType,
34
- type MultipartEditorProps,
35
- type MultipartItem,
36
- } from './type';
37
- import { UrlInputModal } from './components/url-input-modal';
38
- import { MultipartItemRenderer } from './components/multipart-item-renderer';
39
-
40
- import styles from './index.module.less';
41
-
42
- export const MultipartEditor: React.FC<MultipartEditorProps> = ({
43
- spaceID,
44
- uploadFile,
45
- value,
46
- onChange,
47
- className,
48
- multipartConfig,
49
- uploadImageUrl,
50
- readonly,
51
- imageHidden,
52
- videoHidden,
53
- intranetUrlValidator,
54
- }) => {
55
- const uploadRef = useRef<Upload>(null);
56
- const {
57
- maxFileCount,
58
- maxPartCount,
59
- maxFileSize,
60
- imageEnabled,
61
- videoEnabled,
62
- imageSupportedFormats,
63
- videoSupportedFormats,
64
- } = getMultipartConfig(multipartConfig);
65
- const sortableContainer = useRef<HTMLDivElement>(null);
66
- const [items, setItems] = useState<MultipartItem[]>(
67
- (value || []).map(item => ({
68
- ...item,
69
- uid: nanoid(),
70
- })),
71
- );
72
- const [showUrlModal, setShowUrlModal] = useState(false);
73
- const [currentUploadType, setCurrentUploadType] = useState<'image' | 'video'>(
74
- 'image',
75
- );
76
- const [supportedFormats, setSupportedFormats] = useState<string>('');
77
-
78
- const imageCount = items.filter(
79
- item =>
80
- item.content_type === ContentType.Image || item.content_type === 'Video',
81
- ).length;
82
-
83
- const canUsePartLimit = maxPartCount - items.length;
84
- const canUseFileLimit = maxFileCount - imageCount;
85
- const exceedFileCount = !canUseFileLimit;
86
-
87
- // 处理文件上传
88
- const handleUploadFile: UploadProps['customRequest'] = async ({
89
- file,
90
- onProgress,
91
- onSuccess,
92
- onError,
93
- }) => {
94
- const uid = nanoid();
95
-
96
- try {
97
- const fileInstance = (file.fileInstance || file) as File;
98
- const url = URL.createObjectURL(fileInstance);
99
- const beforUploadItem =
100
- currentUploadType === 'image'
101
- ? {
102
- sourceImage: {
103
- status: ImageStatus.Loading,
104
- file: fileInstance,
105
- },
106
- image: {
107
- name: file.name,
108
- url,
109
- storage_provider: StorageProvider.ImageX,
110
- },
111
- }
112
- : {
113
- sourceVideo: {
114
- status: ImageStatus.Loading,
115
- file: fileInstance,
116
- },
117
- video: {
118
- name: file.name,
119
- url,
120
- storage_provider: StorageProvider.ImageX,
121
- },
122
- };
123
- // 添加loading状态的item
124
- setItems(prev => [
125
- ...prev,
126
- {
127
- uid,
128
- content_type:
129
- currentUploadType === 'image' ? ContentType.Image : 'Video',
130
- ...beforUploadItem,
131
- } as any,
132
- ]);
133
- const uri = await uploadFile?.({
134
- file: fileInstance,
135
- fileType: 'image',
136
- onProgress,
137
- onSuccess,
138
- onError,
139
- spaceID,
140
- });
141
-
142
- // 更新为成功状态
143
- setItems(prev =>
144
- prev.map(item => {
145
- if (item.uid === uid) {
146
- const afterUploadItem =
147
- currentUploadType === 'image'
148
- ? {
149
- sourceImage: {
150
- ...item.sourceImage,
151
- status: ImageStatus.Success,
152
- file: fileInstance,
153
- },
154
- image: {
155
- ...item.image,
156
- url,
157
- uri,
158
- storage_provider: StorageProvider.ImageX,
159
- },
160
- }
161
- : {
162
- sourceVideo: {
163
- ...item.sourceVideo,
164
- status: ImageStatus.Success,
165
- file: fileInstance,
166
- },
167
- video: {
168
- ...item.video,
169
- url,
170
- uri,
171
- storage_provider: StorageProvider.ImageX,
172
- },
173
- };
174
- return {
175
- ...item,
176
- ...afterUploadItem,
177
- };
178
- }
179
- return item;
180
- }),
181
- );
182
- } catch (error) {
183
- // 更新为错误状态
184
- setItems(prev =>
185
- prev.map(item =>
186
- item.uid === uid
187
- ? {
188
- ...item,
189
- sourceImage: {
190
- ...item.sourceImage,
191
- status: ImageStatus.Error,
192
- },
193
- }
194
- : item,
195
- ),
196
- );
197
- }
198
- };
199
-
200
- // 添加文本节点
201
- const handleAddText = () => {
202
- setItems(prev => [
203
- ...prev,
204
- {
205
- uid: nanoid(),
206
- content_type: ContentType.Text,
207
- text: '',
208
- },
209
- ]);
210
- };
211
-
212
- // 添加图片文件节点
213
- const handleAddImageFile = () => {
214
- setCurrentUploadType('image');
215
- setSupportedFormats(imageSupportedFormats);
216
- setTimeout(() => {
217
- uploadRef.current?.openFileDialog();
218
- }, 0);
219
- };
220
-
221
- // 添加视频文件节点
222
- const handleAddVideoFile = () => {
223
- setCurrentUploadType('video');
224
- setSupportedFormats(videoSupportedFormats);
225
- setTimeout(() => {
226
- uploadRef.current?.openFileDialog();
227
- }, 0);
228
- };
229
-
230
- // 添加图片链接节点
231
- const handleAddImageUrl = () => {
232
- setCurrentUploadType('image');
233
- setShowUrlModal(true);
234
- };
235
-
236
- // 添加视频链接节点
237
- const handleAddVideoUrl = () => {
238
- setCurrentUploadType('video');
239
- setShowUrlModal(true);
240
- };
241
-
242
- // 确认添加图片链接
243
- const handleConfirmImageUrl = (results: ImageProps[]) => {
244
- const newItems = results.map(result => ({
245
- uid: nanoid(),
246
- content_type: ContentType.Image,
247
- image: {
248
- ...result,
249
- storage_provider: StorageProvider.ImageX,
250
- },
251
- }));
252
-
253
- setItems(prev => [...prev, ...newItems]);
254
- setShowUrlModal(false);
255
- };
256
-
257
- // 确认添加视频链接
258
- const handleConfirmVideoUrl = (results: ImageProps[]) => {
259
- const newItems = results.map(result => ({
260
- uid: nanoid(),
261
- content_type: 'Video' as MultipartItemContentType,
262
- video: {
263
- ...result,
264
- storage_provider: StorageProvider.ImageX,
265
- },
266
- }));
267
-
268
- setItems(prev => [...prev, ...newItems]);
269
- setShowUrlModal(false);
270
- };
271
-
272
- // 更新item
273
- const handleItemChange = (newItem: MultipartItem) => {
274
- setItems(prev =>
275
- prev.map(item => (item.uid === newItem.uid ? newItem : item)),
276
- );
277
- };
278
-
279
- // 删除item
280
- const handleItemRemove = (index: number) => {
281
- setItems(prev => prev.filter((_, i) => i !== index));
282
- };
283
-
284
- const getDisabledTooltip = useCallback(
285
- ({
286
- type,
287
- exceed,
288
- disabled,
289
- }: {
290
- type: MultipartItemContentType;
291
- exceed?: boolean;
292
- disabled?: boolean;
293
- }) => {
294
- if (type === ContentType.Image) {
295
- if (exceed) {
296
- return `多模态图片已达上限,当前仅支持上传${canUseFileLimit}个文件`;
297
- }
298
- if (disabled) {
299
- return '该模型不支持多模态图片';
300
- }
301
- } else if (type === 'Video') {
302
- if (exceed) {
303
- return `多模态视频已达上限,当前仅支持上传${canUseFileLimit}个文件`;
304
- }
305
- if (disabled) {
306
- return '该模型不支持多模态视频';
307
- }
308
- } else {
309
- return '该模型不支持多模态';
310
- }
311
- },
312
- [],
313
- );
314
-
315
- const renderImageSubMenu = useCallback(
316
- (children: React.ReactNode) => (
317
- <TooltipWhenDisabled
318
- disabled={exceedFileCount || !imageEnabled}
319
- content={getDisabledTooltip({
320
- type: ContentType.Image,
321
- exceed: exceedFileCount,
322
- disabled: !imageEnabled,
323
- })}
324
- theme="dark"
325
- needWrap
326
- >
327
- {children}
328
- </TooltipWhenDisabled>
329
- ),
330
- [exceedFileCount, imageEnabled],
331
- );
332
-
333
- const renderVideoSubMenu = useCallback(
334
- (children: React.ReactNode) => (
335
- <TooltipWhenDisabled
336
- disabled={exceedFileCount || !videoEnabled}
337
- content={getDisabledTooltip({
338
- type: 'Video',
339
- exceed: exceedFileCount,
340
- disabled: !videoEnabled,
341
- })}
342
- theme="dark"
343
- needWrap
344
- >
345
- {children}
346
- </TooltipWhenDisabled>
347
- ),
348
- [exceedFileCount, videoEnabled],
349
- );
350
-
351
- const dropdownMenu = (
352
- <Menu.SubMenu mode="menu">
353
- <Menu.Item onClick={handleAddText} disabled={imageCount >= maxPartCount}>
354
- 文本
355
- </Menu.Item>
356
-
357
- {imageHidden ? null : (
358
- <Menu.Item
359
- onClick={handleAddImageFile}
360
- disabled={exceedFileCount || !imageEnabled}
361
- >
362
- {renderImageSubMenu(<span className="w-full">图片-源文件</span>)}
363
- </Menu.Item>
364
- )}
365
-
366
- {imageHidden ? null : (
367
- <Menu.Item
368
- onClick={handleAddImageUrl}
369
- disabled={exceedFileCount || !imageEnabled}
370
- >
371
- {renderImageSubMenu(<span className="w-full">图片-外链</span>)}
372
- </Menu.Item>
373
- )}
374
-
375
- {videoHidden ? null : (
376
- <Menu.Item
377
- onClick={handleAddVideoFile}
378
- disabled={exceedFileCount || !videoEnabled}
379
- >
380
- {renderVideoSubMenu(<span className="w-full">视频-源文件</span>)}
381
- </Menu.Item>
382
- )}
383
-
384
- {videoHidden ? null : (
385
- <Menu.Item
386
- onClick={handleAddVideoUrl}
387
- disabled={exceedFileCount || !videoEnabled}
388
- >
389
- {renderVideoSubMenu(<span className="w-full">视频-外链</span>)}
390
- </Menu.Item>
391
- )}
392
- </Menu.SubMenu>
393
- );
394
-
395
- // 同步数据到父组件
396
- useEffect(() => {
397
- onChange?.(items);
398
- }, [items]);
399
-
400
- // 初始化sortablejs拖拽排序
401
- useEffect(() => {
402
- if (sortableContainer.current) {
403
- new Sortable(sortableContainer.current, {
404
- animation: 150,
405
- handle: '.drag-handle',
406
- ghostClass: styles.ghost,
407
- onEnd: evt => {
408
- setItems(list => {
409
- const draft = [...(list ?? [])];
410
- if (draft.length) {
411
- const { oldIndex = 0, newIndex = 0 } = evt;
412
- const [item] = draft.splice(oldIndex, 1);
413
- draft.splice(newIndex, 0, item);
414
- }
415
- return draft;
416
- });
417
- },
418
- setData(dataTransfer, dragEl) {
419
- // dragEl 是被拖拽的元素
420
- // dataTransfer 是拖拽数据传输对象
421
- // 创建自定义预览元素
422
- // 浅复制(只复制元素本身,不包含子元素)
423
-
424
- // 深复制(复制元素及其所有子元素)
425
- const dragElClone: HTMLElement = dragEl.cloneNode(
426
- true,
427
- ) as HTMLElement;
428
- const customPreview = document.createElement('div');
429
- // // 临时添加到DOM(必须在可见区域外)
430
- customPreview.style.position = 'absolute';
431
- customPreview.style.top = '-1000px';
432
- customPreview.style.width = '200px';
433
- customPreview.appendChild(dragElClone);
434
- const wrapper = dragElClone.getElementsByClassName(
435
- 'semi-collapsible-wrapper',
436
- )?.[0];
437
- if (wrapper) {
438
- wrapper.setAttribute(
439
- 'style',
440
- 'height: 0px; width: 0px; overflow: hidden;',
441
- );
442
- }
443
- document.body.appendChild(customPreview);
444
- dataTransfer.setDragImage(wrapper ? customPreview : dragEl, 0, 0);
445
- // 清理临时元素
446
- setTimeout(() => {
447
- if (customPreview.parentNode) {
448
- document.body.removeChild(customPreview);
449
- }
450
- }, 0);
451
- },
452
- });
453
- }
454
- }, []);
455
-
456
- return (
457
- <div
458
- className={classNames(
459
- 'flex flex-col gap-2 p-0 max-h-[713px] overflow-auto styled-scrollbar',
460
- className,
461
- )}
462
- >
463
- {/* 可拖拽容器 */}
464
- <div
465
- ref={sortableContainer}
466
- className={classNames(
467
- 'flex flex-wrap gap-2 rounded-[6px] coz-bg-primary p-2',
468
- {
469
- hidden: !items.length,
470
- },
471
- )}
472
- >
473
- {items.map((item, index) => (
474
- <div key={item.uid} className="flex items-center gap-2 w-full">
475
- {readonly ? null : (
476
- <IconButton
477
- icon={<IconCozHandle className="drag-handle" />}
478
- color="secondary"
479
- />
480
- )}
481
- <div className="flex-1">
482
- <MultipartItemRenderer
483
- item={item}
484
- onChange={newItem => handleItemChange(newItem)}
485
- onRemove={() => handleItemRemove(index)}
486
- readonly={readonly}
487
- />
488
- </div>
489
- </div>
490
- ))}
491
- </div>
492
- {/* 添加按钮 */}
493
- {items.length >= maxPartCount || readonly ? (
494
- <Button
495
- icon={<IconCozPlus />}
496
- size="small"
497
- className="!w-fit"
498
- color="primary"
499
- disabled
500
- >
501
- 添加数据
502
- <Typography.Text
503
- className="ml-1 !text-inherit"
504
- type="secondary"
505
- >{`${items.length}/${maxPartCount}`}</Typography.Text>
506
- </Button>
507
- ) : (
508
- <Menu
509
- trigger="click"
510
- clickToHide
511
- render={dropdownMenu}
512
- position="bottomLeft"
513
- >
514
- <Button
515
- icon={<IconCozPlus />}
516
- size="small"
517
- className="!w-fit"
518
- color="primary"
519
- disabled={items.length >= maxPartCount}
520
- >
521
- 添加数据
522
- <Typography.Text
523
- className="ml-1"
524
- type="secondary"
525
- >{`${items.length}/${maxPartCount}`}</Typography.Text>
526
- </Button>
527
- </Menu>
528
- )}
529
- {/* 隐藏的文件上传组件 */}
530
- <Upload
531
- ref={uploadRef}
532
- action=""
533
- maxSize={maxFileSize}
534
- onSizeError={() => {
535
- Toast.error('图片大小不能超过20MB');
536
- }}
537
- accept={supportedFormats}
538
- customRequest={handleUploadFile}
539
- showUploadList={false}
540
- style={{ display: 'none' }}
541
- multiple
542
- limit={
543
- canUseFileLimit > canUsePartLimit ? canUsePartLimit : canUseFileLimit
544
- }
545
- onExceed={() => {
546
- Toast.error('图片数量不能超过20张或节点数量不能超过50个');
547
- }}
548
- />
549
- {/* 外链输入模态框 */}
550
- {showUrlModal ? (
551
- <UrlInputModal
552
- visible={showUrlModal}
553
- maxCount={
554
- canUseFileLimit > canUsePartLimit
555
- ? canUsePartLimit
556
- : canUseFileLimit
557
- }
558
- onConfirm={
559
- currentUploadType === 'image'
560
- ? handleConfirmImageUrl
561
- : handleConfirmVideoUrl
562
- }
563
- onCancel={() => setShowUrlModal(false)}
564
- uploadImageUrl={uploadImageUrl}
565
- uploadType={currentUploadType}
566
- intranetUrlValidator={intranetUrlValidator}
567
- />
568
- ) : null}
569
- </div>
570
- );
571
- };
@@ -1,87 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import classNames from 'classnames';
3
- import { ContentType } from '@cozeloop/api-schema/prompt';
4
-
5
- import { type ContentPartLoop, type FileItemStatus, ImageStatus } from './type';
6
- import { VideoItemRenderer } from './components/video-item-renderer';
7
- import { ImageItemRenderer } from './components/image-item-renderer';
8
-
9
- interface MultiPartRenderProps {
10
- fileParts?: ContentPartLoop[];
11
- readonly?: boolean;
12
- className?: string;
13
- onDeleteFilePart?: (part: ContentPartLoop) => void;
14
- onFilePartsChange?: (part: ContentPartLoop) => void;
15
- }
16
-
17
- const convertStatus = (status: FileItemStatus) => {
18
- if (status === 'uploading') {
19
- return ImageStatus.Loading;
20
- }
21
- if (status === 'success') {
22
- return ImageStatus.Success;
23
- }
24
-
25
- return ImageStatus.Error;
26
- };
27
-
28
- export function MultiPartRender({
29
- fileParts,
30
- onDeleteFilePart,
31
- onFilePartsChange,
32
- readonly,
33
- className,
34
- }: MultiPartRenderProps) {
35
- return (
36
- <div
37
- className={classNames(
38
- 'flex gap-2 flex-wrap pt-0 pb-3 px-2 w-full border border-solid border-t-0 border-l-0 border-r-0 border-b-[rgba(68,83,130,.25)]',
39
- className,
40
- )}
41
- >
42
- {fileParts?.map(part =>
43
- part.type === ContentType.VideoURL ? (
44
- <VideoItemRenderer
45
- className="!w-[45px] !h-[45px]"
46
- item={{
47
- content_type: 'Video',
48
- uid: part.uid,
49
- video: part.video_url,
50
- sourceVideo: {
51
- status: convertStatus(part.status || 'success'),
52
- },
53
- }}
54
- onRemove={() => onDeleteFilePart?.(part)}
55
- onChange={file =>
56
- onFilePartsChange?.({
57
- ...file,
58
- type: ContentType.VideoURL,
59
- })
60
- }
61
- readonly={readonly}
62
- />
63
- ) : (
64
- <ImageItemRenderer
65
- className="!w-[45px] !h-[45px]"
66
- item={{
67
- content_type: 'Image' as any,
68
- uid: part.uid,
69
- image: part.image_url,
70
- sourceImage: {
71
- status: convertStatus(part.status || 'success'),
72
- },
73
- }}
74
- onRemove={() => onDeleteFilePart?.(part)}
75
- onChange={file =>
76
- onFilePartsChange?.({
77
- ...file,
78
- type: ContentType.ImageURL,
79
- })
80
- }
81
- readonly={readonly}
82
- />
83
- ),
84
- )}
85
- </div>
86
- );
87
- }