Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

index.tsx 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import { ReactComponent as SelectFilesEndIcon } from '@/assets/svg/select-files-end.svg';
  2. import { ReactComponent as SelectFilesStartIcon } from '@/assets/svg/select-files-start.svg';
  3. import {
  4. useDeleteDocumentById,
  5. useGetDocumentDefaultParser,
  6. useKnowledgeBaseId,
  7. } from '@/hooks/knowledgeHook';
  8. import { ITenantInfo } from '@/interfaces/database/knowledge';
  9. import uploadService from '@/services/uploadService';
  10. import {
  11. ArrowLeftOutlined,
  12. DeleteOutlined,
  13. EditOutlined,
  14. FileDoneOutlined,
  15. InboxOutlined,
  16. } from '@ant-design/icons';
  17. import {
  18. Button,
  19. Card,
  20. Flex,
  21. Popover,
  22. Progress,
  23. Radio,
  24. RadioChangeEvent,
  25. Space,
  26. Upload,
  27. UploadFile,
  28. UploadProps,
  29. } from 'antd';
  30. import classNames from 'classnames';
  31. import { ReactElement, useEffect, useState } from 'react';
  32. import { Nullable } from 'typings';
  33. import { Link, useDispatch, useNavigate, useSelector } from 'umi';
  34. import { KnowledgeRouteKey } from '@/constants/knowledge';
  35. import styles from './index.less';
  36. const { Dragger } = Upload;
  37. type UploadRequestOption = Parameters<
  38. NonNullable<UploadProps['customRequest']>
  39. >[0];
  40. const UploaderItem = ({
  41. file,
  42. actions,
  43. isUpload,
  44. parserArray,
  45. }: {
  46. isUpload: boolean;
  47. originNode: ReactElement;
  48. file: UploadFile;
  49. fileList: object[];
  50. parserArray: string[];
  51. actions: { download: Function; preview: Function; remove: any };
  52. }) => {
  53. const { parserConfig, defaultParserId } = useGetDocumentDefaultParser(
  54. file?.response?.kb_id,
  55. );
  56. const { removeDocument } = useDeleteDocumentById();
  57. const [value, setValue] = useState(defaultParserId);
  58. const dispatch = useDispatch();
  59. const documentId = file?.response?.id;
  60. const onChange = (e: RadioChangeEvent) => {
  61. const val = e.target.value;
  62. setValue(val);
  63. saveParser(val);
  64. };
  65. const content = (
  66. <Radio.Group onChange={onChange} value={value}>
  67. <Space direction="vertical">
  68. {parserArray.map((x) => (
  69. <Radio value={x} key={x}>
  70. {x}
  71. </Radio>
  72. ))}
  73. </Space>
  74. </Radio.Group>
  75. );
  76. const handleRemove = async () => {
  77. const ret: any = await removeDocument(documentId);
  78. if (ret === 0) {
  79. actions?.remove();
  80. }
  81. };
  82. const saveParser = (parserId: string) => {
  83. dispatch({
  84. type: 'kFModel/document_change_parser',
  85. payload: {
  86. parser_id: parserId,
  87. doc_id: documentId,
  88. parser_config: parserConfig,
  89. },
  90. });
  91. };
  92. useEffect(() => {
  93. setValue(defaultParserId);
  94. }, [defaultParserId]);
  95. return (
  96. <Card className={styles.uploaderItem}>
  97. <Flex justify="space-between">
  98. <FileDoneOutlined className={styles.fileIcon} />
  99. <section className={styles.uploaderItemTextWrapper}>
  100. <div>
  101. <b>{file.name}</b>
  102. </div>
  103. <span>{file.size}</span>
  104. </section>
  105. {isUpload ? (
  106. <DeleteOutlined
  107. className={styles.deleteIcon}
  108. onClick={handleRemove}
  109. />
  110. ) : (
  111. <Popover content={content} placement="bottom">
  112. <EditOutlined />
  113. </Popover>
  114. )}
  115. </Flex>
  116. <Flex>
  117. <Progress
  118. showInfo={false}
  119. percent={100}
  120. className={styles.uploaderItemProgress}
  121. strokeColor="
  122. rgba(127, 86, 217, 1)
  123. "
  124. />
  125. <span>100%</span>
  126. </Flex>
  127. </Card>
  128. );
  129. };
  130. const KnowledgeUploadFile = () => {
  131. const knowledgeBaseId = useKnowledgeBaseId();
  132. const [isUpload, setIsUpload] = useState(true);
  133. const dispatch = useDispatch();
  134. const tenantIfo: Nullable<ITenantInfo> = useSelector(
  135. (state: any) => state.settingModel.tenantIfo,
  136. );
  137. const navigate = useNavigate();
  138. const parserArray = tenantIfo?.parser_ids.split(',') ?? [];
  139. const createRequest: (props: UploadRequestOption) => void = async function ({
  140. file,
  141. onSuccess,
  142. onError,
  143. onProgress,
  144. }) {
  145. const { data } = await uploadService.uploadFile(file, knowledgeBaseId);
  146. if (data.retcode === 0) {
  147. onSuccess && onSuccess(data.data);
  148. } else {
  149. onError && onError(data.data);
  150. }
  151. };
  152. const props: UploadProps = {
  153. name: 'file',
  154. multiple: true,
  155. itemRender(originNode, file, fileList, actions) {
  156. return (
  157. <UploaderItem
  158. isUpload={isUpload}
  159. file={file}
  160. fileList={fileList}
  161. originNode={originNode}
  162. actions={actions}
  163. parserArray={parserArray}
  164. ></UploaderItem>
  165. );
  166. },
  167. customRequest: createRequest,
  168. onDrop(e) {
  169. console.log('Dropped files', e.dataTransfer.files);
  170. },
  171. };
  172. const handleNextClick = () => {
  173. if (!isUpload) {
  174. navigate(`/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`);
  175. } else {
  176. setIsUpload(false);
  177. }
  178. };
  179. useEffect(() => {
  180. dispatch({
  181. type: 'settingModel/getTenantInfo',
  182. });
  183. }, []);
  184. return (
  185. <div className={styles.uploadWrapper}>
  186. <section>
  187. <Space className={styles.backToList}>
  188. <ArrowLeftOutlined />
  189. <Link to={`/knowledge/dataset?id=${knowledgeBaseId}`}>
  190. Back to select files
  191. </Link>
  192. </Space>
  193. <div className={styles.progressWrapper}>
  194. <Flex align="center" justify="center">
  195. <SelectFilesStartIcon></SelectFilesStartIcon>
  196. <Progress
  197. percent={100}
  198. showInfo={false}
  199. className={styles.progress}
  200. strokeColor="
  201. rgba(127, 86, 217, 1)
  202. "
  203. />
  204. <SelectFilesEndIcon></SelectFilesEndIcon>
  205. </Flex>
  206. <Flex justify="space-around">
  207. <p className={styles.selectFilesText}>
  208. <b>Select files</b>
  209. </p>
  210. <p className={styles.changeSpecificCategoryText}>
  211. <b>Change specific category</b>
  212. </p>
  213. </Flex>
  214. </div>
  215. </section>
  216. <section className={styles.uploadContent}>
  217. <Dragger
  218. {...props}
  219. className={classNames(styles.uploader, {
  220. [styles.hiddenUploader]: !isUpload,
  221. })}
  222. >
  223. <p className="ant-upload-drag-icon">
  224. <InboxOutlined />
  225. </p>
  226. <p className="ant-upload-text">
  227. Click or drag file to this area to upload
  228. </p>
  229. <p className="ant-upload-hint">
  230. Support for a single or bulk upload. Strictly prohibited from
  231. uploading company data or other banned files.
  232. </p>
  233. </Dragger>
  234. </section>
  235. <section className={styles.footer}>
  236. <Button
  237. type="primary"
  238. className={styles.nextButton}
  239. onClick={handleNextClick}
  240. >
  241. Next
  242. </Button>
  243. </section>
  244. </div>
  245. );
  246. };
  247. export default KnowledgeUploadFile;