| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- import * as React from 'react';
- import { observer } from 'mobx-react';
- import { generatePath, useLocation, useParams } from 'react-router-dom';
- import { Form, Input, Button, message, Upload, UploadProps } from 'antd';
- import { apis } from '@/apis';
- import router from '@/router';
- import { ArrowLeftOutlined } from '@ant-design/icons';
- import config, { getHeaders } from '@/apis/config';
- const { TextArea } = Input;
- import { useState, useRef, useEffect } from 'react';
- import { EyeOutlined, CloseOutlined } from '@ant-design/icons';
- const FormItem = Form.Item;
- // 引入富文本
- import MarkdownIt from "markdown-it";
- import MdEditor from "react-markdown-editor-lite";
- import "react-markdown-editor-lite/lib/index.css";
- import './style.less';
- // 初始化 markdown-it
- const mdParser = new MarkdownIt({
- html: true,
- typographer: true
- });
- const ar2 = [
- {
- name:'我是图片1',
- url:'https://jkeckms.ryuiso.com/chat-bg.jpg'
- },
- {
- name:'我是图片2',
- url:'https://jkeckms.ryuiso.com/chat-bg.jpg'
- },
- {
- name:'我是图片3',
- url:'https://jkeckms.ryuiso.com/chat-bg.jpg'
- }
- ]
- interface MdImg {
- name: string;
- url: string;
- }
- const SliceDetail: React.FC = () => {
- const [form] = Form.useForm();
- const params = useParams();
- const location = useLocation();
- // console.log('location------',location);
- const { text = '', page } = location.state??{};
- const [listLoading, setListLoading] = React.useState(false);
- const [mdImgUrlList, setMdImgUrlList] = useState<MdImg[]>();
- const appApi = {
- fetchList: async () => {
- setListLoading(true);
- try {
- if (!params.sliceId || !params.knowledgeId) {
- throw new Error('参数错误');
- }
- const res = await apis.fetchTakaiSliceDetail(params.sliceId, params.knowledgeId);
- const info = res.data.data;
- form.setFieldsValue({
- slice_id: info.slice_id,
- slice_text: info.slice_text,
- document_id: info.document_id,
- })
- setContentMd(info.slice_text || '');
- setMdImgUrlList(info.imageList || []);
- } catch (error) {
- console.error(error);
- } finally {
- setListLoading(false);
- }
- }
- };
- const init = async () => {
- if (params.sliceId && params.sliceId !== 'new') {
- await appApi.fetchList();
- }
- }
- React.useEffect(() => {
- init();
- }, [])
- const [cursorEndPosition, setCursorEndPosition] = React.useState<number>(0);
- // 上传图片配置
- const uploadImageConfig: UploadProps = {
- name: 'files',
- action: config.baseURL + `/deepseek/api/uploadSliceImage/${params.knowledgeId}/${params.documentId}`,
- method: 'POST',
- headers: getHeaders(),
- accept: ['.png', '.jpg', '.jpeg'].join(','),
- multiple: true,
- maxCount: 5,
- showUploadList: false,
- };
- // 处理markdown编辑器
- const [contentMd, setContentMd] = React.useState('');
- // 在这里做关键字替换
- const customRender = (text: string)=> {
- let html = mdParser.render(text);
- // 比如:把 "我是图片" 替换成一张图片
- mdImgUrlList?.forEach(item=>{
- html = html.replace(new RegExp(item.name, 'g'), `<img src="${item.url}" alt="${item.name}" />`);
- })
- // html = html.replace(/我是图片/g, `<img src="https://jkeckms.ryuiso.com/chat-bg.jpg" alt="我是图片" />`);
- // 你还可以做更多规则,比如匹配 [img:xxx] 这种自定义语法
- // html = html.replace(/\[img:(.+?)\]/g, (_, name) => `<img src="/images/${name}.png" />`);
- form.setFieldsValue({ slice_text: text });
- return html;
- }
- return (
- <div>
- <div className='questionAnswerList'>
- <div style={{ height: '100%', marginLeft: '10px' }}>
- <Form
- style={{ paddingTop: '20px', height: '100%' }}
- form={form}
- layout='vertical'
- >
- <Form.Item
- // name="slice_text"
- rules={[{ required: true, message: '内容不能为空' }]}
- >
- <MdEditor
- config={{
- view:{
- menu:false
- }
- }}
- value={contentMd}
- style={{ height: "450px",width:'98%' }}
- renderHTML={customRender}
- onChange={({ text }) => setContentMd(text)}
- onBlur={(e: React.FocusEvent<HTMLTextAreaElement>) => {
- const ta = e.target as HTMLTextAreaElement;
- const start = ta.selectionStart;
- const end = ta.selectionEnd;
- setCursorEndPosition(end);
- // setCursor({ start, end });
- // console.log('blur cursor', start, end, ta.value);
- }}
- />
- </Form.Item>
- {false && <FormItem
- name="slice_text"
- rules={[{ required: true, message: '切片内容不能为空' }]}>
- <TextArea
- style={{
- width: '50%',
- height: '200px',
- overflow: 'auto',
- resize: 'both',
- boxSizing: 'border-box',
- }}
- placeholder=""
- autoSize={{ minRows: 20, maxRows: 5000 }}
- onBlur={(e) => {
- const target = e.target as HTMLTextAreaElement;
- // 更新光标终点位置
- setCursorEndPosition(target.selectionEnd);
- }}
- />
- </FormItem>}
- <Upload
- {...uploadImageConfig}
- onChange={(info) => {
- const insertToSliceText = (text: string) => {
- const slice_text = contentMd
- // 获取当前光标位置
- const position = cursorEndPosition;
- let newValue = '';
- if (!slice_text) {
- newValue = text;
- } else {
- newValue = slice_text.slice(0, position) + text + slice_text.slice(position);
- }
- setContentMd(newValue);
- form.setFieldsValue({ slice_text: newValue });
- }
- const file = info.file;
- if (file.status === 'done') {// 上传成功
- const { code, msg, data } = file.response;
- if (code === 200) {
- const text = data&&data[0]?.name||'';
- insertToSliceText(text);
- const flagList = mdImgUrlList || [];
- const flagList1 = [...flagList,...data];
- setMdImgUrlList(flagList1)
- message.success('上传成功');
- } else {
- message.error(msg);
- }
- } else if (file.status === 'error') {// 上传失败
- message.error('上传失败');
- }
- }}
- >
- <Button type='primary'>
- 解析图片
- </Button>
- </Upload>
- <Button
- style={{ margin: '0 16px' }}
- type='primary'
- icon={<ArrowLeftOutlined />}
- onClick={() => {
- const path = generatePath('/deepseek/knowledgeLib/:knowledgeId/:createBy/slice/:documentId/:embeddingId', {
- knowledgeId: params.knowledgeId as string,
- documentId: params.documentId as string,
- createBy: params.createBy as string,
- embeddingId: params.embeddingId as string,
- });
- router.navigate({ pathname: path },
- { state: { text: text, page } }
- );
- }}
- >
- 返回
- </Button>
- <Button
- type='primary'
- onClick={() => {
- form.validateFields().then(async (values) => {
- values = {
- slice_text:contentMd
- }
- // 验证参数是否存在
- if (!params.knowledgeId || !params.sliceId) {
- message.error('知识库ID或切片ID无效');
- return;
- }
- const data = values;
- const info = {
- knowledgeId: params.knowledgeId,
- sliceId: params.sliceId === null ? '' : params.sliceId,
- sliceText: values.slice_text,
- documentId: params.documentId,
- };
- let res = null;
- if (params.sliceId && params.sliceId !== 'null' && params.sliceId !== 'new') {
- // 编辑应用
- res = await apis.modifyTakaiSliceInfo(info as any);
- } else {
- res = await apis.addTakaiSlice(info as any);
- }
- if (res.code === 200 && res.data === 1) {
- if (params.sliceId && params.sliceId !== 'null' && params.sliceId !== 'new') {
- message.success('修改成功');
- } else {
- message.success('新增成功');
- }
- } else {
- if (params.sliceId && params.sliceId !== 'null' && params.sliceId !== 'new') {
- message.error('修改失败');
- } else {
- message.error('新增失败');
- }
- }
- const path = generatePath('/deepseek/knowledgeLib/:knowledgeId/:createBy/slice/:documentId/:embeddingId', {
- knowledgeId: params.knowledgeId as string,
- createBy: params.createBy as string,
- documentId: params.documentId as string,
- embeddingId: params.embeddingId as string,
- });
- router.navigate({ pathname: path }, {
- state: { text: text, page }
- });
- }).catch((error) => {
- console.error(error);
- });
- }}
- >
- 保存
- </Button>
- </Form>
- </div>
- </div>
- </div>
- )
- };
- export default observer(SliceDetail);
|