@cozeloop/components 0.0.3 → 0.0.4

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 (165) hide show
  1. package/package.json +9 -3
  2. package/.eslintcache +0 -1
  3. package/.rush/temp/shrinkwrap-deps.json +0 -770
  4. package/OWNERS +0 -5
  5. package/config/rush-project.json +0 -8
  6. package/eslint.config.js +0 -7
  7. package/rslib.config.js +0 -7
  8. package/script/publish.js +0 -146
  9. package/src/base-search-select/base-search-form-select.tsx +0 -10
  10. package/src/base-search-select/base-search-select.tsx +0 -200
  11. package/src/base-search-select/index.module.less +0 -16
  12. package/src/base-search-select/index.tsx +0 -3
  13. package/src/base-search-select/types.ts +0 -16
  14. package/src/base-search-select/utils.ts +0 -78
  15. package/src/basic-card/index.tsx +0 -23
  16. package/src/card-pane/index.module.less +0 -14
  17. package/src/card-pane/index.tsx +0 -25
  18. package/src/chip-select/index.module.less +0 -17
  19. package/src/chip-select/index.tsx +0 -7
  20. package/src/code-editor/index.tsx +0 -9
  21. package/src/code-usage/code-item.module.less +0 -32
  22. package/src/code-usage/index.tsx +0 -91
  23. package/src/codemirror-editor/code-editor.tsx +0 -139
  24. package/src/codemirror-editor/index.ts +0 -4
  25. package/src/codemirror-editor/json-editor.tsx +0 -183
  26. package/src/codemirror-editor/raw-text-editor.tsx +0 -68
  27. package/src/codemirror-editor/text-editor.tsx +0 -58
  28. package/src/codemirror-editor/themes/coze-dark.ts +0 -116
  29. package/src/codemirror-editor/themes/coze-light.ts +0 -122
  30. package/src/collapse-card/index.module.less +0 -27
  31. package/src/collapse-card/index.tsx +0 -93
  32. package/src/collapsible-card/index.module.less +0 -63
  33. package/src/collapsible-card/index.tsx +0 -57
  34. package/src/column-manage-storage/index.tsx +0 -64
  35. package/src/columns-select/index.tsx +0 -244
  36. package/src/edit-icon-button/index.tsx +0 -36
  37. package/src/footer-actions/index.tsx +0 -33
  38. package/src/hooks/use-infinite-scroll.ts +0 -183
  39. package/src/hooks/use-mouse-down-offset.ts +0 -50
  40. package/src/hooks/use-unsave-leave-warning.ts +0 -49
  41. package/src/id-render/icon-button-container.tsx +0 -37
  42. package/src/id-render/index.tsx +0 -64
  43. package/src/index-controller/record-navigation.tsx +0 -57
  44. package/src/index-controller/use-item-index-controller.ts +0 -197
  45. package/src/index.ts +0 -208
  46. package/src/infinite-scroll-table/index.tsx +0 -99
  47. package/src/info-tooltip/index.tsx +0 -41
  48. package/src/input-components/radio-button.tsx +0 -63
  49. package/src/input-slider/index.module.less +0 -30
  50. package/src/input-slider/index.tsx +0 -161
  51. package/src/input-with-count/index.tsx +0 -31
  52. package/src/jump-button/jump-icon-button.tsx +0 -12
  53. package/src/large-txt-render/index.tsx +0 -46
  54. package/src/layout/content.tsx +0 -28
  55. package/src/layout/header.tsx +0 -15
  56. package/src/layout/index.module.less +0 -28
  57. package/src/layout/index.tsx +0 -9
  58. package/src/layout/tabs.tsx +0 -11
  59. package/src/lazy-load-component/index.tsx +0 -55
  60. package/src/logic-editor/index.ts +0 -3
  61. package/src/logic-editor/logic-editor.module.less +0 -13
  62. package/src/logic-editor/logic-editor.tsx +0 -200
  63. package/src/logic-editor/logic-left-render.tsx +0 -100
  64. package/src/logic-editor/logic-operator-render.tsx +0 -54
  65. package/src/logic-editor/logic-right-render.tsx +0 -51
  66. package/src/logic-editor/logic-types.tsx +0 -238
  67. package/src/logic-editor/utils.ts +0 -22
  68. package/src/logic-expr/assets/select.svg +0 -1
  69. package/src/logic-expr/consts.ts +0 -6
  70. package/src/logic-expr/expr-group-render.tsx +0 -238
  71. package/src/logic-expr/expr-render.tsx +0 -226
  72. package/src/logic-expr/index.module.less +0 -252
  73. package/src/logic-expr/index.ts +0 -13
  74. package/src/logic-expr/logic-expr.tsx +0 -261
  75. package/src/logic-expr/logic-not.tsx +0 -46
  76. package/src/logic-expr/logic-toggle.tsx +0 -96
  77. package/src/logic-expr/types.ts +0 -95
  78. package/src/loop-radio-group/index.tsx +0 -16
  79. package/src/multi-part-editor/components/image-item-renderer.tsx +0 -134
  80. package/src/multi-part-editor/components/index.module.less +0 -21
  81. package/src/multi-part-editor/components/multipart-item-renderer.tsx +0 -74
  82. package/src/multi-part-editor/components/url-input-modal.tsx +0 -317
  83. package/src/multi-part-editor/components/video-item-renderer.tsx +0 -145
  84. package/src/multi-part-editor/index.module.less +0 -8
  85. package/src/multi-part-editor/index.tsx +0 -571
  86. package/src/multi-part-editor/multi-part-render.tsx +0 -87
  87. package/src/multi-part-editor/type.tsx +0 -103
  88. package/src/multi-part-editor/upload-button.tsx +0 -256
  89. package/src/multi-part-editor/utils.ts +0 -64
  90. package/src/open-detail-button/index.tsx +0 -30
  91. package/src/page-content/index.tsx +0 -99
  92. package/src/primary-page/index.tsx +0 -1
  93. package/src/primary-page/primary-header.tsx +0 -64
  94. package/src/primary-title/index.module.less +0 -14
  95. package/src/primary-title/index.tsx +0 -18
  96. package/src/provider/index.tsx +0 -89
  97. package/src/resizable-side-sheet/index.tsx +0 -69
  98. package/src/resize-sidesheet/index.module.less +0 -14
  99. package/src/resize-sidesheet/index.tsx +0 -68
  100. package/src/resize-sidesheet/use-drag.ts +0 -43
  101. package/src/schema-editor/index.tsx +0 -52
  102. package/src/search-form/index.tsx +0 -134
  103. package/src/semi-schema-form/components/tmpls/array-field-item.tsx +0 -97
  104. package/src/semi-schema-form/components/tmpls/array-field.tsx +0 -127
  105. package/src/semi-schema-form/components/tmpls/base-input.tsx +0 -126
  106. package/src/semi-schema-form/components/tmpls/description-field.tsx +0 -23
  107. package/src/semi-schema-form/components/tmpls/error-list.tsx +0 -44
  108. package/src/semi-schema-form/components/tmpls/field-error.tsx +0 -33
  109. package/src/semi-schema-form/components/tmpls/field.tsx +0 -54
  110. package/src/semi-schema-form/components/tmpls/icon-button.tsx +0 -112
  111. package/src/semi-schema-form/components/tmpls/index.ts +0 -39
  112. package/src/semi-schema-form/components/tmpls/object-field.tsx +0 -173
  113. package/src/semi-schema-form/components/tmpls/submit.tsx +0 -31
  114. package/src/semi-schema-form/components/tmpls/title-field.tsx +0 -30
  115. package/src/semi-schema-form/components/widgets/checkbox.tsx +0 -67
  116. package/src/semi-schema-form/components/widgets/checkboxs.tsx +0 -100
  117. package/src/semi-schema-form/components/widgets/index.ts +0 -17
  118. package/src/semi-schema-form/components/widgets/radio.tsx +0 -105
  119. package/src/semi-schema-form/components/widgets/range.tsx +0 -73
  120. package/src/semi-schema-form/components/widgets/select.tsx +0 -108
  121. package/src/semi-schema-form/components/widgets/textarea.tsx +0 -63
  122. package/src/semi-schema-form/index.tsx +0 -14
  123. package/src/sentinel-form/enum.ts +0 -16
  124. package/src/sentinel-form/index.tsx +0 -382
  125. package/src/step-nav/index.module.less +0 -45
  126. package/src/step-nav/index.tsx +0 -53
  127. package/src/table/index.module.less +0 -144
  128. package/src/table/index.tsx +0 -18
  129. package/src/table/sort-icon.tsx +0 -73
  130. package/src/table/table-with-pagination.tsx +0 -150
  131. package/src/table/table-without-pagniation.tsx +0 -66
  132. package/src/table-batch-operate/table-batch-operation.tsx +0 -47
  133. package/src/table-batch-operate/use-batch-operate.ts +0 -111
  134. package/src/table-col-actions/index.module.less +0 -8
  135. package/src/table-col-actions/index.tsx +0 -149
  136. package/src/table-cols-config/index.module.less +0 -34
  137. package/src/table-cols-config/index.tsx +0 -171
  138. package/src/table-cols-config/type.ts +0 -12
  139. package/src/table-cols-config/use-hidden-col-keys.ts +0 -53
  140. package/src/table-cols-config/util.ts +0 -56
  141. package/src/table-empty/index.tsx +0 -23
  142. package/src/table-header/index.module.less +0 -7
  143. package/src/table-header/index.tsx +0 -70
  144. package/src/tabs/index.module.less +0 -48
  145. package/src/tabs/index.tsx +0 -9
  146. package/src/text-area-pro/index.module.less +0 -5
  147. package/src/text-area-pro/index.tsx +0 -49
  148. package/src/text-with-copy/index.tsx +0 -95
  149. package/src/title-with-sub/index.tsx +0 -27
  150. package/src/tooltip-when-disabled/index.tsx +0 -23
  151. package/src/tooltip-with-disabled/index.tsx +0 -17
  152. package/src/types.d.ts +0 -24
  153. package/src/upload/index.ts +0 -39
  154. package/src/user-profile/index.tsx +0 -49
  155. package/src/utils/basic.ts +0 -29
  156. package/src/version-list/index.module.less +0 -16
  157. package/src/version-list/version-descriptions.tsx +0 -80
  158. package/src/version-list/version-item.tsx +0 -30
  159. package/src/version-list/version-list.tsx +0 -59
  160. package/src/version-list/version-switch-panel.tsx +0 -31
  161. package/tailwind.config.ts +0 -6
  162. package/tsconfig.build.json +0 -44
  163. package/tsconfig.json +0 -17
  164. package/tsconfig.misc.json +0 -28
  165. 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
- }