index.tsx 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import * as React from 'react';
  2. import { observer } from 'mobx-react';
  3. import { generatePath, useLocation, useParams } from 'react-router-dom';
  4. import { Form, Input, Button, message, Upload, UploadProps } from 'antd';
  5. import { apis } from '@/apis';
  6. import router from '@/router';
  7. import { ArrowLeftOutlined } from '@ant-design/icons';
  8. import config, { getHeaders } from '@/apis/config';
  9. const { TextArea } = Input;
  10. const FormItem = Form.Item;
  11. interface TakaiSliceDetailRequest {
  12. knowledgeId: string,
  13. sliceId: string,
  14. sliceText: string,
  15. }
  16. const SliceDetail: React.FC = () => {
  17. const [form] = Form.useForm();
  18. const params = useParams();
  19. const location = useLocation();
  20. const { text, page } = location.state;
  21. const [listLoading, setListLoading] = React.useState(false);
  22. const appApi = {
  23. fetchList: async () => {
  24. setListLoading(true);
  25. try {
  26. if (!params.sliceId || !params.knowledgeId) {
  27. throw new Error('参数错误');
  28. }
  29. const res = await apis.fetchTakaiSliceDetail(params.sliceId, params.knowledgeId);
  30. const info = res.data.data;
  31. form.setFieldsValue({
  32. slice_id: info.slice_id,
  33. slice_text: info.slice_text,
  34. document_id: info.document_id,
  35. })
  36. console.log(res, 'info');
  37. } catch (error) {
  38. console.error(error);
  39. } finally {
  40. setListLoading(false);
  41. }
  42. }
  43. };
  44. const init = async () => {
  45. if (params.sliceId && params.sliceId !== 'new') {
  46. await appApi.fetchList();
  47. }
  48. }
  49. React.useEffect(() => {
  50. init();
  51. }, [])
  52. const [cursorEndPosition, setCursorEndPosition] = React.useState<number>(0);
  53. // 上传图片配置
  54. const uploadImageConfig: UploadProps = {
  55. name: 'files',
  56. action: config.baseURL + `/deepseek/api/uploadSliceImage/${params.knowledgeId}/${params.documentId}`,
  57. method: 'POST',
  58. headers: getHeaders(),
  59. accept: ['.png', '.jpg', '.jpeg'].join(','),
  60. multiple: true,
  61. maxCount: 5,
  62. showUploadList: false,
  63. };
  64. return (
  65. <div>
  66. <div className='questionAnswerList'>
  67. <div style={{ overflow: 'hidden' }}>
  68. <Form
  69. style={{ paddingTop: '20px', height: '100%' }}
  70. form={form}
  71. layout='vertical'
  72. >
  73. <FormItem
  74. name="slice_text"
  75. rules={[{ required: true, message: '切片内容不能为空' }]}>
  76. <TextArea
  77. style={{
  78. width: '50%',
  79. height: '200px',
  80. overflow: 'auto',
  81. resize: 'both',
  82. boxSizing: 'border-box',
  83. }}
  84. placeholder=""
  85. autoSize={{ minRows: 20, maxRows: 5000 }}
  86. onBlur={(e) => {
  87. const target = e.target as HTMLTextAreaElement;
  88. // 更新光标终点位置
  89. setCursorEndPosition(target.selectionEnd);
  90. }}
  91. />
  92. </FormItem>
  93. <Upload
  94. {...uploadImageConfig}
  95. onChange={(info) => {
  96. const insertToSliceText = (text: string) => {
  97. const { slice_text } = form.getFieldsValue();
  98. // 获取当前光标位置
  99. const position = cursorEndPosition;
  100. let newValue = '';
  101. if (!slice_text) {
  102. newValue = text;
  103. } else {
  104. newValue = slice_text.slice(0, position) + text + slice_text.slice(position);
  105. }
  106. form.setFieldsValue({ slice_text: newValue });
  107. }
  108. const file = info.file;
  109. if (file.status === 'done') {// 上传成功
  110. const { code, msg, data } = file.response;
  111. if (code === 200) {
  112. const text = data.join('');
  113. insertToSliceText(text);
  114. message.success('上传成功');
  115. } else {
  116. message.error(msg);
  117. }
  118. } else if (file.status === 'error') {// 上传失败
  119. message.error('上传失败');
  120. }
  121. }}
  122. >
  123. <Button type='primary'>
  124. 解析图片
  125. </Button>
  126. </Upload>
  127. <Button
  128. style={{ margin: '0 16px' }}
  129. type='primary'
  130. icon={<ArrowLeftOutlined />}
  131. onClick={() => {
  132. const path = generatePath('/deepseek/knowledgeLib/:knowledgeId/slice/:documentId/:embeddingId', {
  133. knowledgeId: params.knowledgeId as string,
  134. documentId: params.documentId as string,
  135. embeddingId: params.embeddingId as string,
  136. });
  137. router.navigate({ pathname: path }, { state: { text: text, page } });
  138. }}
  139. >
  140. 返回
  141. </Button>
  142. <Button
  143. type='primary'
  144. onClick={() => {
  145. form.validateFields().then(async (values) => {
  146. // 验证参数是否存在
  147. if (!params.knowledgeId || !params.sliceId) {
  148. message.error('知识库ID或切片ID无效');
  149. return;
  150. }
  151. const data = values;
  152. const info = {
  153. knowledgeId: params.knowledgeId,
  154. sliceId: params.sliceId === null ? '' : params.sliceId,
  155. sliceText: values.slice_text,
  156. documentId: params.documentId,
  157. };
  158. let res = null;
  159. if (params.sliceId && params.sliceId !== 'null' && params.sliceId !== 'new') {
  160. // 编辑应用
  161. res = await apis.modifyTakaiSliceInfo(info as any);
  162. } else {
  163. res = await apis.addTakaiSlice(info as any);
  164. }
  165. if (res.code === 200 && res.data === 1) {
  166. if (params.sliceId && params.sliceId !== 'null' && params.sliceId !== 'new') {
  167. message.success('修改成功');
  168. } else {
  169. message.success('新增成功');
  170. }
  171. } else {
  172. if (params.sliceId && params.sliceId !== 'null' && params.sliceId !== 'new') {
  173. message.error('修改失败');
  174. } else {
  175. message.error('新增失败');
  176. }
  177. }
  178. const path = generatePath('/deepseek/knowledgeLib/:knowledgeId/slice/:documentId/:embeddingId', {
  179. knowledgeId: params.knowledgeId as string,
  180. documentId: params.documentId as string,
  181. embeddingId: params.embeddingId as string,
  182. });
  183. router.navigate({ pathname: path }, { state: { text: text, page } });
  184. }).catch((error) => {
  185. console.error(error);
  186. });
  187. }}
  188. >
  189. 保存
  190. </Button>
  191. </Form>
  192. </div>
  193. </div>
  194. </div>
  195. )
  196. };
  197. export default observer(SliceDetail);