Resource.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { apiInterceptors, postChatModeParamsFileLoad } from '@/client/api';
  2. import { dbMapper } from '@/utils';
  3. import { FolderAddOutlined, LoadingOutlined, SwapOutlined } from '@ant-design/icons';
  4. import { useRequest } from 'ahooks';
  5. import type { MenuProps } from 'antd';
  6. import { Dropdown, Spin, Upload } from 'antd';
  7. import React, { useContext, useMemo, useState } from 'react';
  8. import { MobileChatContext } from '../';
  9. import OptionIcon from './OptionIcon';
  10. const Resource: React.FC = () => {
  11. const { appInfo, resourceList, scene, model, conv_uid, getChatHistoryRun, setResource, resource } =
  12. useContext(MobileChatContext);
  13. const [selectedVal, setSelectedVal] = useState<any>(null);
  14. // 资源类型
  15. const resourceVal = useMemo(() => {
  16. return appInfo?.param_need?.filter(item => item.type === 'resource')?.[0]?.value;
  17. }, [appInfo]);
  18. const items: MenuProps['items'] = useMemo(() => {
  19. if (resourceList && resourceList.length > 0) {
  20. return resourceList.map(item => {
  21. return {
  22. label: (
  23. <div
  24. className='flex items-center gap-2'
  25. onClick={() => {
  26. setSelectedVal(item);
  27. setResource(item.space_id || item.param);
  28. }}
  29. >
  30. <OptionIcon width={14} height={14} src={dbMapper[item.type].icon} label={dbMapper[item.type].label} />
  31. <span className='text-xs'>{item.param}</span>
  32. </div>
  33. ),
  34. key: item.space_id || item.param,
  35. };
  36. });
  37. }
  38. return [];
  39. }, [resourceList, setResource]);
  40. // 上传文件
  41. const { run: uploadFile, loading } = useRequest(
  42. async formData => {
  43. const [, res] = await apiInterceptors(
  44. postChatModeParamsFileLoad({
  45. convUid: conv_uid,
  46. chatMode: scene,
  47. data: formData,
  48. model,
  49. config: {
  50. timeout: 1000 * 60 * 60,
  51. },
  52. }),
  53. );
  54. setResource(res);
  55. return res;
  56. },
  57. {
  58. manual: true,
  59. onSuccess: async () => {
  60. await getChatHistoryRun();
  61. },
  62. },
  63. );
  64. // 上传文件变化
  65. const handleFileChange = async (info: any) => {
  66. const formData = new FormData();
  67. formData.append('doc_file', info?.file);
  68. await uploadFile(formData);
  69. };
  70. // 上传文件展示内容
  71. const uploadContent = useMemo(() => {
  72. if (loading) {
  73. return (
  74. <div className='flex items-center gap-1'>
  75. <Spin size='small' indicator={<LoadingOutlined spin />} />
  76. <span className='text-xs'>上传中</span>
  77. </div>
  78. );
  79. }
  80. if (resource) {
  81. return (
  82. <div className='flex gap-1'>
  83. <span className='text-xs'>{resource.file_name}</span>
  84. <SwapOutlined rotate={90} />
  85. </div>
  86. );
  87. }
  88. return (
  89. <div className='flex items-center gap-1'>
  90. <FolderAddOutlined className='text-base' />
  91. <span className='text-xs'>上传文件</span>
  92. </div>
  93. );
  94. }, [loading, resource]);
  95. const renderContent = () => {
  96. switch (resourceVal) {
  97. case 'excel_file':
  98. case 'text_file':
  99. case 'image_file':
  100. return (
  101. <div className='flex items-center justify-center gap-1 border rounded-xl bg-white dark:bg-black px-2 flex-shrink-0'>
  102. <Upload
  103. name='file'
  104. accept='.xlsx,.xls'
  105. maxCount={1}
  106. showUploadList={false}
  107. beforeUpload={() => false}
  108. onChange={handleFileChange}
  109. className='flex h-full w-full items-center justify-center'
  110. >
  111. {uploadContent}
  112. </Upload>
  113. </div>
  114. );
  115. case 'database':
  116. case 'knowledge':
  117. case 'plugin':
  118. case 'awel_flow':
  119. if (!resourceList?.length) {
  120. return null;
  121. }
  122. return (
  123. <Dropdown
  124. menu={{
  125. items,
  126. }}
  127. placement='top'
  128. trigger={['click']}
  129. >
  130. <div className='flex items-center gap-1 border rounded-xl bg-white dark:bg-black p-2 flex-shrink-0'>
  131. <OptionIcon
  132. width={14}
  133. height={14}
  134. src={dbMapper[selectedVal?.type || resourceList?.[0]?.type]?.icon}
  135. label={dbMapper[selectedVal?.type || resourceList?.[0]?.type]?.label}
  136. />
  137. <span className='text-xs font-medium'>{selectedVal?.param || resourceList?.[0]?.param}</span>
  138. <SwapOutlined rotate={90} />
  139. </div>
  140. </Dropdown>
  141. );
  142. }
  143. };
  144. return <>{renderContent()}</>;
  145. };
  146. export default Resource;