Преглед на файлове

切片编辑新增markdown编辑功能

sunsheng преди 2 месеца
родител
ревизия
614f4cac7e

+ 2 - 2
env/.env.development

@@ -2,8 +2,8 @@
 VITE_ENV = 'development'
 
 # Api地址
-# VITE_API_URL = 'http://192.168.3.123:8091'
-VITE_API_URL = 'http://xia0miduo.gicp.net:8091'
+VITE_API_URL = 'http://192.168.3.123:8091'
+# VITE_API_URL = 'http://xia0miduo.gicp.net:8091'
 
 #跳转地址
 VITE_JUMP_URL = 'http://localhost:4000/#/knowledgeChat?showMenu=true&chatMode=LOCAL'

+ 111 - 0
package-lock.json

@@ -14,15 +14,18 @@
         "antd-style": "^3.7.1",
         "axios": "1.8.2",
         "dayjs": "^1.11.0",
+        "markdown-it": "^14.1.0",
         "mobx": "^6.13.0",
         "mobx-react": "^9.2.0",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-markdown": "^10.1.0",
+        "react-markdown-editor-lite": "^1.3.4",
         "react-quill": "^2.0.0",
         "react-router-dom": "^7.1.0"
       },
       "devDependencies": {
+        "@types/markdown-it": "^14.1.2",
         "@types/node": "^22.0.0",
         "@types/react": "^18.2.0",
         "@types/react-dom": "^18.2.0",
@@ -1832,6 +1835,24 @@
         "@types/unist": "*"
       }
     },
+    "node_modules/@types/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/markdown-it": {
+      "version": "14.1.2",
+      "resolved": "https://registry.npmmirror.com/@types/markdown-it/-/markdown-it-14.1.2.tgz",
+      "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/linkify-it": "^5",
+        "@types/mdurl": "^2"
+      }
+    },
     "node_modules/@types/mdast": {
       "version": "4.0.4",
       "resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-4.0.4.tgz",
@@ -1841,6 +1862,13 @@
         "@types/unist": "*"
       }
     },
+    "node_modules/@types/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/@types/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/@types/ms": {
       "version": "2.1.0",
       "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-2.1.0.tgz",
@@ -3461,6 +3489,15 @@
       "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
       "license": "MIT"
     },
+    "node_modules/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+      "license": "MIT",
+      "dependencies": {
+        "uc.micro": "^2.0.0"
+      }
+    },
     "node_modules/local-pkg": {
       "version": "1.1.2",
       "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.2.tgz",
@@ -3547,6 +3584,29 @@
         "semver": "bin/semver"
       }
     },
+    "node_modules/markdown-it": {
+      "version": "14.1.0",
+      "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz",
+      "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "^4.4.0",
+        "linkify-it": "^5.0.0",
+        "mdurl": "^2.0.0",
+        "punycode.js": "^2.3.1",
+        "uc.micro": "^2.1.0"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.mjs"
+      }
+    },
+    "node_modules/markdown-it/node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "license": "Python-2.0"
+    },
     "node_modules/math-intrinsics": {
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -3709,6 +3769,12 @@
         "url": "https://opencollective.com/unified"
       }
     },
+    "node_modules/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+      "license": "MIT"
+    },
     "node_modules/micromark": {
       "version": "4.0.2",
       "resolved": "https://registry.npmmirror.com/micromark/-/micromark-4.0.2.tgz",
@@ -4557,6 +4623,15 @@
         "node": ">=6"
       }
     },
+    "node_modules/punycode.js": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/punycode.js/-/punycode.js-2.3.1.tgz",
+      "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/quansync": {
       "version": "0.2.11",
       "resolved": "https://registry.npmmirror.com/quansync/-/quansync-0.2.11.tgz",
@@ -5261,6 +5336,27 @@
         "react": ">=18"
       }
     },
+    "node_modules/react-markdown-editor-lite": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmmirror.com/react-markdown-editor-lite/-/react-markdown-editor-lite-1.3.4.tgz",
+      "integrity": "sha512-PhS4HzLzSgCsr8O9CfJX75nAYmZ0NwpfviLxARlT0Tau+APOerDSHSw3u9hub5wd0EqmonWibw0vhXXNu4ldRA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "classnames": "^2.2.6",
+        "eventemitter3": "^4.0.0",
+        "uuid": "^8.3.2"
+      },
+      "peerDependencies": {
+        "react": "^16.9.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
+    "node_modules/react-markdown-editor-lite/node_modules/eventemitter3": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz",
+      "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+      "license": "MIT"
+    },
     "node_modules/react-quill": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/react-quill/-/react-quill-2.0.0.tgz",
@@ -5759,6 +5855,12 @@
         "node": ">=14.17"
       }
     },
+    "node_modules/uc.micro": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz",
+      "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+      "license": "MIT"
+    },
     "node_modules/ufo": {
       "version": "1.6.1",
       "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.6.1.tgz",
@@ -5923,6 +6025,15 @@
         "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
       }
     },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
     "node_modules/vfile": {
       "version": "6.0.3",
       "resolved": "https://registry.npmmirror.com/vfile/-/vfile-6.0.3.tgz",

+ 3 - 0
package.json

@@ -17,15 +17,18 @@
     "antd-style": "^3.7.1",
     "axios": "1.8.2",
     "dayjs": "^1.11.0",
+    "markdown-it": "^14.1.0",
     "mobx": "^6.13.0",
     "mobx-react": "^9.2.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-markdown": "^10.1.0",
+    "react-markdown-editor-lite": "^1.3.4",
     "react-quill": "^2.0.0",
     "react-router-dom": "^7.1.0"
   },
   "devDependencies": {
+    "@types/markdown-it": "^14.1.2",
     "@types/node": "^22.0.0",
     "@types/react": "^18.2.0",
     "@types/react-dom": "^18.2.0",

+ 0 - 164
src/pages/deepseek/knowledgeLib/slice/detail/ceshi.tsx

@@ -1,164 +0,0 @@
-import * as React from 'react';
-import { observer } from 'mobx-react';
-// import workSrc from '@/assets/workbench/work.png';
-// import store from './store';
-// import './style.less';
-import { Input } from 'antd';
-
-const Workbench: React.FC = () => {
-    // const {
-    //     state,
-    //     init,
-    //     reset
-    // } = store;
-    // const {
-    //     pageLoading
-    // } = state;
-
-    React.useEffect(() => {
-        // init();
-        // return () => reset();
-    }, []);
-
-    const [value, setValue] = React.useState('');
-
-    // 处理鼠标悬停事件
-    const handleMouseOver = (e: React.MouseEvent<HTMLTextAreaElement>) => {
-        const textarea = e.target as HTMLTextAreaElement;
-        const text = textarea.value;
-        
-        // 获取鼠标位置
-        const rect = textarea.getBoundingClientRect();
-        const mouseX = e.clientX - rect.left;
-        const mouseY = e.clientY - rect.top;
-        
-        // 获取textarea的样式信息
-        const computedStyle = window.getComputedStyle(textarea);
-        const fontSize = parseInt(computedStyle.fontSize);
-        const fontFamily = computedStyle.fontFamily;
-        const lineHeight = parseInt(computedStyle.lineHeight) || fontSize * 1.2;
-        const paddingTop = parseInt(computedStyle.paddingTop);
-        const paddingLeft = parseInt(computedStyle.paddingLeft);
-        
-        // 创建canvas来测量文本
-        const canvas = document.createElement('canvas');
-        const ctx = canvas.getContext('2d');
-        if (!ctx) return;
-        
-        ctx.font = `${fontSize}px ${fontFamily}`;
-        
-        // 获取光标位置(字符索引)
-        const caretPosition = getCaretPosition(textarea, mouseX, mouseY);
-        
-        // 查找所有"打印"的位置
-        const printPositions: {start: number, end: number, isPrinter: boolean}[] = [];
-        let startIndex = 0;
-        while (startIndex < text.length) {
-            const printIndex = text.indexOf('打印', startIndex);
-            if (printIndex === -1) break;
-            
-            // 检查是否是"打印机"
-            const isPrinter = text.substring(printIndex, printIndex + 3) === '富文本';
-            printPositions.push({
-                start: printIndex,
-                end: printIndex + (isPrinter ? 3 : 2),
-                isPrinter
-            });
-            
-            startIndex = printIndex + 2;
-        }
-        
-        // 检查光标是否在任何一个"打印"文本上
-        let isOnPrint = false;
-        for (const pos of printPositions) {
-            if (caretPosition >= pos.start && caretPosition <= pos.end && !pos.isPrinter) {
-                isOnPrint = true;
-                break;
-            }
-        }
-        
-        if (isOnPrint) {
-            console.log('鼠标悬停在"打印"上');
-        }
-    };
-
-    // 获取光标位置的辅助函数(字符索引)
-    const getCaretPosition = (element: HTMLTextAreaElement, x: number, y: number) => {
-        const computedStyle = window.getComputedStyle(element);
-        const lineHeight = parseInt(computedStyle.lineHeight) || parseInt(computedStyle.fontSize) * 1.2;
-        const paddingTop = parseInt(computedStyle.paddingTop);
-        const paddingLeft = parseInt(computedStyle.paddingLeft);
-        const fontSize = parseInt(computedStyle.fontSize);
-        const fontFamily = computedStyle.fontFamily;
-        
-        // 计算行号
-        const row = Math.floor((y - paddingTop) / lineHeight);
-        
-        // 获取每行文本
-        const lines = element.value.split('\n');
-        
-        // 计算到目标行之前的字符数
-        let position = 0;
-        for (let i = 0; i < row && i < lines.length; i++) {
-            position += lines[i].length + 1; // +1 for \n
-        }
-        
-        // 计算列位置(字符索引)
-        const canvas = document.createElement('canvas');
-        const ctx = canvas.getContext('2d');
-        if (!ctx) return position;
-        
-        ctx.font = `${fontSize}px ${fontFamily}`;
-        const currentLine = lines[row] || '';
-        
-        // 计算每个字符的位置,找到最接近鼠标位置的字符
-        let currentWidth = paddingLeft;
-        let col = 0;
-        
-        while (col < currentLine.length) {
-            const charWidth = ctx.measureText(currentLine[col]).width;
-            // 如果鼠标位置在当前字符的中间之前,则选择当前字符位置
-            if (currentWidth + charWidth / 2 > x) {
-                break;
-            }
-            currentWidth += charWidth;
-            col++;
-        }
-        
-        return position + col;
-    };
-
-    return (
-        <div className='workbench'>
-            <div className='workbench-top'>
-                <div className='workbench-top-style'>
-                    <div className='workbench-top-style-welcome'>
-                        <div className='workbench-top-style-welcome-text'>
-                            <div className='workbench-top-style-welcome-text-first'>
-                                欢迎使用
-                            </div>
-                            <div className='workbench-top-style-welcome-text-second'>
-                                React框架
-                            </div>
-                        </div>
-                        <div className='workbench-top-style-welcome-picture'>
-                            {/* <img src={workSrc} /> */}
-                        </div>
-                    </div>
-                    <div className='workbench-top-style-fast'></div>
-                </div>
-                <div className='workbench-top-weather'>
-                    <Input.TextArea
-                        style={{ height: 200 }}
-                        value={value}
-                        onChange={(e) => setValue(e.target.value)}
-                        onMouseMove={handleMouseOver}
-                    />
-                </div>
-            </div>
-            <div className='workbench-bottom'></div>
-        </div>
-    );
-};
-
-export default observer(Workbench);

+ 419 - 196
src/pages/deepseek/knowledgeLib/slice/detail/imgPre.tsx

@@ -1,220 +1,443 @@
-import React, { useState, useRef, useEffect } from 'react';
+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';
+import ImgPre from './imgPre';
+const { TextArea } = Input;
+import { useState, useRef, useEffect } from 'react';
 import ReactQuill from 'react-quill';
 import 'react-quill/dist/quill.snow.css';
-import { Form } from 'antd';
 import { EyeOutlined, CloseOutlined } from '@ant-design/icons';
+import './style.less';
 
-// 提取纯文本工具函数
 const extractPlainText = (html: string): string => {
-  if (!html) return '';
-  const tempDiv = document.createElement('div');
-  tempDiv.innerHTML = html;
-  return tempDiv.textContent || '';
+    if (!html) return '';
+    const tempDiv = document.createElement('div');
+    tempDiv.innerHTML = html;
+    return tempDiv.textContent || '';
 };
 
 interface LinkData {
-  id: string;
-  originalText: string;
-  url: string;
-  isDeleted: boolean;
+    id: string;
+    originalText: string;
+    url: string;
+    isDeleted: boolean;
 }
 
-const PersistentImagePreviewEditor = () => {
-  const [form] = Form.useForm();
-  const [editorHtml, setEditorHtml] = useState<string>(`
-    <p>系统工作人员联系方式</p>
-    <p>系统工作人员联系方式表:
-      <a href="http://xia0miduo.gicp.net:9000/papbtest//pdf/a2965738189226381312/a2966033634305507328/【示意图序号_a2966033634305507328_3】.jpg" target="_blank">【示意图序号_a2966033634305507328_2】</a>,
-      第二个标签 <a href="https://jkeckms.ryuiso.com/chat-bg.jpg" target="_blank">【示意图序号_a2966033634305507328_2】</a>,
-      第三个标签 <a href="https://jkeckms.ryuiso.com/chat-bg.jpg" target="_blank">【示意图序号_a2966033634305507328_2】</a>
-    </p>
-  `);
-  const [plainText, setPlainText] = useState<string>(extractPlainText(editorHtml));
-  const [linkDataList, setLinkDataList] = useState<LinkData[]>([]);
-  const [activeImageUrl, setActiveImageUrl] = useState<string | null>(null);
-  
-  // 跟踪鼠标是否在链接或预览区上
-  const [isHoveringLink, setIsHoveringLink] = useState(false);
-  const [isHoveringPreview, setIsHoveringPreview] = useState(false);
-  
-  const editorContainerRef = useRef<HTMLDivElement>(null);
-  const previewRef = useRef<HTMLDivElement>(null);
-
-  // 初始化链接数据
-  useEffect(() => {
-    const parser = new DOMParser();
-    const doc = parser.parseFromString(editorHtml, 'text/html');
-    const links = doc.getElementsByTagName('a');
-    const linksData: LinkData[] = [];
-
-    Array.from(links).forEach((link, index) => {
-      linksData.push({
-        id: `link-${index}-${Date.now()}`,
-        originalText: link.textContent || '',
-        url: link.href,
-        isDeleted: false
-      });
-    });
-
-    setLinkDataList(linksData);
-  }, []);
-
-  // 处理内容变化
-  const handleEditorChange = (html: string) => {
-    setEditorHtml(html);
-    const text = extractPlainText(html);
-    setPlainText(text);
-    form.setFieldsValue({ slice_text: text });
-
-    if (linkDataList.length > 0) {
-      const updatedLinks = [...linkDataList];
-      updatedLinks.forEach(link => {
-        const feature = link.originalText.slice(0, 5);
-        link.isDeleted = !text.includes(feature);
-      });
-      setLinkDataList(updatedLinks);
-    }
-  };
-
-  // 处理鼠标悬停链接事件
-  useEffect(() => {
-    if (!editorContainerRef.current) return;
-
-    const handleMouseOverLink = (e: MouseEvent) => {
-      const target = e.target as HTMLAnchorElement;
-      if (target.tagName === 'A') {
-        const url = target.href;
-        const isKnownLink = linkDataList.some(link => 
-          !link.isDeleted && url.includes(link.url)
+
+
+
+
+
+const FormItem = Form.Item;
+
+interface TakaiSliceDetailRequest {
+    knowledgeId: string,
+    sliceId: string,
+    sliceText: string,
+}
+
+const SliceDetail: React.FC = () => {
+
+    const [form] = Form.useForm();
+
+    const params = useParams();
+    const location = useLocation();
+    const { text, page } = location.state;
+    const [listLoading, setListLoading] = React.useState(false);
+
+    const [editorHtml, setEditorHtml] = useState<string>(``);
+    // RichTextImageRight
+    const RichTextImageRight = () => {
+        const [plainText, setPlainText] = useState<string>(extractPlainText(editorHtml));
+        const [linkDataList, setLinkDataList] = useState<LinkData[]>([]);
+        const [activeImageUrl, setActiveImageUrl] = useState<string | null>(null);
+
+        // 跟踪鼠标是否在链接或预览区上
+        const [isHoveringLink, setIsHoveringLink] = useState(false);
+        const [isHoveringPreview, setIsHoveringPreview] = useState(false);
+
+        const editorContainerRef = useRef<HTMLDivElement>(null);
+        const previewRef = useRef<HTMLDivElement>(null);
+
+        // 初始化链接数据
+        useEffect(() => {
+            const start = async () => {
+                if (!params.sliceId || !params.knowledgeId) {
+                    throw new Error('参数错误');
+                }
+                const res = await apis.fetchTakaiSliceDetail(params.sliceId, params.knowledgeId);
+                const info = res.data.data;
+                const parser = new DOMParser();
+                const doc = parser.parseFromString(info.slice_text, 'text/html');
+                const links = doc.getElementsByTagName('a');
+                const linksData: LinkData[] = [];
+                Array.from(links).forEach((link, index) => {
+                    linksData.push({
+                        id: `link-${index}-${Date.now()}`,
+                        originalText: link.textContent || '',
+                        url: link.href,
+                        isDeleted: false
+                    });
+                });
+
+                setLinkDataList(linksData);
+            }
+            start()
+        }, []);
+
+        // 处理内容变化
+        const handleEditorChange = (html: string) => {
+            setEditorHtml(html);
+            const text = extractPlainText(html);
+            setPlainText(text);
+            form.setFieldsValue({ slice_text: text });
+
+            if (linkDataList.length > 0) {
+                const updatedLinks = [...linkDataList];
+                updatedLinks.forEach(link => {
+                    const feature = link.originalText.slice(0, 5);
+                    link.isDeleted = !text.includes(feature);
+                });
+                setLinkDataList(updatedLinks);
+            }
+        };
+
+        // 处理鼠标悬停链接事件
+        useEffect(() => {
+            if (!editorContainerRef.current) return;
+
+            const handleMouseOverLink = (e: MouseEvent) => {
+                const target = e.target as HTMLAnchorElement;
+                if (target.tagName === 'A') {
+                    const url = target.href;
+                    const isKnownLink = linkDataList.some(link =>
+                        !link.isDeleted && url.includes(link.url)
+                    );
+
+                    if (isKnownLink) {
+                        console.log('图片地址:', url);
+                        setActiveImageUrl(url);
+                        setIsHoveringLink(true);
+                    }
+                }
+            };
+
+            const handleMouseOutLink = () => {
+                setIsHoveringLink(false);
+            };
+
+            const container = editorContainerRef.current;
+            container.addEventListener('mouseover', handleMouseOverLink);
+            container.addEventListener('mouseout', handleMouseOutLink);
+
+            return () => {
+                container.removeEventListener('mouseover', handleMouseOverLink);
+                container.removeEventListener('mouseout', handleMouseOutLink);
+            };
+        }, [linkDataList]);
+
+        // 控制预览区显示/隐藏的核心逻辑
+        useEffect(() => {
+            // 当鼠标既不在链接上也不在预览区上时,才隐藏预览
+            if (!isHoveringLink && !isHoveringPreview) {
+                setActiveImageUrl(null);
+            }
+        }, [isHoveringLink, isHoveringPreview]);
+
+        // 配置编辑器(无工具栏)
+        const modules = {
+            toolbar: false
+        };
+
+        return (
+            <div>
+                {/* 容器:编辑器 + 右侧图片预览区 */}
+                <div style={{
+                    display: 'flex',
+                    gap: '16px',
+                    alignItems: 'flex-start'
+                }}>
+                    {/* 500x500的编辑器 */}
+                    <div
+                        ref={editorContainerRef}
+                        style={{
+                            width: '500px',
+                            height: '500px',
+                            border: '1px solid #d9d9d9',
+                            borderRadius: '4px',
+                            overflow: 'hidden'
+                        }}
+                    >
+                        <ReactQuill
+                            value={editorHtml}
+                            onChange={handleEditorChange}
+                            modules={modules}
+                            style={{ height: '100%' }}
+                            placeholder="请输入内容..."
+                        />
+                    </div>
+
+                    {/* 右侧图片预览区(固定位置) */}
+                    {activeImageUrl && (
+                        <div
+                            ref={previewRef}
+                            style={{
+                                width: '300px',
+                                height: '500px',
+                                backgroundColor: 'white',
+                                borderRadius: '8px',
+                                boxShadow: '0 4px 16px rgba(0, 0, 0, 0.15)',
+                                padding: '12px',
+                                border: '1px solid #eee',
+                                display: 'flex',
+                                flexDirection: 'column'
+                            }}
+                            onMouseOver={() => setIsHoveringPreview(true)}
+                            onMouseOut={() => setIsHoveringPreview(false)}
+                        >
+                            <div style={{
+                                display: 'flex',
+                                justifyContent: 'space-between',
+                                alignItems: 'center',
+                                marginBottom: '12px',
+                                paddingBottom: '8px',
+                                borderBottom: '1px solid #f0f0f0'
+                            }}>
+                                <div style={{ display: 'flex', alignItems: 'center' }}>
+                                    <EyeOutlined style={{ color: '#1890ff', marginRight: '8px' }} />
+                                    <span style={{ fontSize: '14px', color: '#333' }}>图片预览</span>
+                                </div>
+                                <CloseOutlined
+                                    style={{ color: '#999', cursor: 'pointer', fontSize: '16px' }}
+                                    onClick={() => setActiveImageUrl(null)}
+                                />
+                            </div>
+
+                            <div style={{
+                                flex: 1,
+                                display: 'flex',
+                                alignItems: 'center',
+                                justifyContent: 'center',
+                                overflow: 'hidden'
+                            }}>
+                                <img
+                                    src={activeImageUrl}
+                                    alt="示意图预览"
+                                    style={{
+                                        maxWidth: '100%',
+                                        maxHeight: '100%',
+                                        objectFit: 'contain'
+                                    }}
+                                    onError={() => setActiveImageUrl(null)}
+                                />
+                            </div>
+                        </div>
+                    )}
+                </div>
+            </div>
         );
+    };
+
 
-        if (isKnownLink) {
-          console.log('图片地址:', url);
-          setActiveImageUrl(url);
-          setIsHoveringLink(true);
+    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;
+                setEditorHtml(info.slice_text || '');
+                form.setFieldsValue({
+                    slice_id: info.slice_id,
+                    slice_text: info.slice_text,
+                    document_id: info.document_id,
+                })
+                console.log(res, 'info');
+            } catch (error) {
+                console.error(error);
+            } finally {
+                setListLoading(false);
+            }
         }
-      }
     };
 
-    const handleMouseOutLink = () => {
-      setIsHoveringLink(false);
-    };
+    const init = async () => {
+        if (params.sliceId && params.sliceId !== 'new') {
+            await appApi.fetchList();
+        }
+    }
 
-    const container = editorContainerRef.current;
-    container.addEventListener('mouseover', handleMouseOverLink);
-    container.addEventListener('mouseout', handleMouseOutLink);
+    React.useEffect(() => {
+        init();
+    }, [])
 
-    return () => {
-      container.removeEventListener('mouseover', handleMouseOverLink);
-      container.removeEventListener('mouseout', handleMouseOutLink);
+    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,
     };
-  }, [linkDataList]);
 
-  // 控制预览区显示/隐藏的核心逻辑
-  useEffect(() => {
-    // 当鼠标既不在链接上也不在预览区上时,才隐藏预览
-    if (!isHoveringLink && !isHoveringPreview) {
-      setActiveImageUrl(null);
-    }
-  }, [isHoveringLink, isHoveringPreview]);
-
-  // 配置编辑器(无工具栏)
-  const modules = {
-    toolbar: false
-  };
-
-  return (
-    <Form form={form} initialValues={{ slice_text: plainText }}>
-      <Form.Item
-        name="slice_text"
-        rules={[{ required: true, message: '内容不能为空' }]}
-      >
-        {/* 容器:编辑器 + 右侧图片预览区 */}
-        <div style={{ 
-          display: 'flex', 
-          gap: '16px', 
-          alignItems: 'flex-start'
-        }}>
-          {/* 500x500的编辑器 */}
-          <div 
-            ref={editorContainerRef}
-            style={{ 
-              width: '500px', 
-              height: '500px',
-              border: '1px solid #d9d9d9', 
-              borderRadius: '4px',
-              overflow: 'hidden'
-            }}
-          >
-            <ReactQuill
-              value={editorHtml}
-              onChange={handleEditorChange}
-              modules={modules}
-              style={{ height: '100%' }}
-              placeholder="请输入内容..."
-            />
-          </div>
-
-          {/* 右侧图片预览区(固定位置) */}
-          {activeImageUrl && (
-            <div
-              ref={previewRef}
-              style={{
-                width: '300px',
-                height: '500px',
-                backgroundColor: 'white',
-                borderRadius: '8px',
-                boxShadow: '0 4px 16px rgba(0, 0, 0, 0.15)',
-                padding: '12px',
-                border: '1px solid #eee',
-                display: 'flex',
-                flexDirection: 'column'
-              }}
-              onMouseOver={() => setIsHoveringPreview(true)}
-              onMouseOut={() => setIsHoveringPreview(false)}
-            >
-              <div style={{ 
-                display: 'flex', 
-                justifyContent: 'space-between', 
-                alignItems: 'center', 
-                marginBottom: '12px',
-                paddingBottom: '8px',
-                borderBottom: '1px solid #f0f0f0'
-              }}>
-                <div style={{ display: 'flex', alignItems: 'center' }}>
-                  <EyeOutlined style={{ color: '#1890ff', marginRight: '8px' }} />
-                  <span style={{ fontSize: '14px', color: '#333' }}>图片预览</span>
+    return (
+        <div>
+            {/* <ImgPre></ImgPre> */}
+            <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: '内容不能为空' }]}
+                        >
+                            {RichTextImageRight()}
+
+                        </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 } = form.getFieldsValue();
+
+                                    // 获取当前光标位置
+                                    const position = cursorEndPosition;
+
+                                    let newValue = '';
+
+                                    if (!slice_text) {
+                                        newValue = text;
+                                    } else {
+                                        newValue = slice_text.slice(0, position) + text + slice_text.slice(position);
+                                    }
+                                    setEditorHtml(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.join('');
+                                        insertToSliceText(text);
+                                        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/slice/:documentId/:embeddingId', {
+                                    knowledgeId: params.knowledgeId as string,
+                                    documentId: params.documentId 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) => {
+                                    console.log('values', values)
+                                    // 验证参数是否存在
+                                    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/slice/:documentId/:embeddingId', {
+                                        knowledgeId: params.knowledgeId 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>
-                <CloseOutlined 
-                  style={{ color: '#999', cursor: 'pointer', fontSize: '16px' }}
-                  onClick={() => setActiveImageUrl(null)}
-                />
-              </div>
-              
-              <div style={{ 
-                flex: 1, 
-                display: 'flex', 
-                alignItems: 'center', 
-                justifyContent: 'center',
-                overflow: 'hidden'
-              }}>
-                <img
-                  src={activeImageUrl}
-                  alt="示意图预览"
-                  style={{ 
-                    maxWidth: '100%', 
-                    maxHeight: '100%', 
-                    objectFit: 'contain' 
-                  }}
-                  onError={() => setActiveImageUrl(null)}
-                />
-              </div>
             </div>
-          )}
         </div>
-      </Form.Item>
-    </Form>
-  );
+    )
 };
 
-export default PersistentImagePreviewEditor;
+export default observer(SliceDetail);

+ 76 - 233
src/pages/deepseek/knowledgeLib/slice/detail/index.tsx

@@ -6,242 +6,48 @@ import { apis } from '@/apis';
 import router from '@/router';
 import { ArrowLeftOutlined } from '@ant-design/icons';
 import config, { getHeaders } from '@/apis/config';
-import ImgPre from './imgPre';
 const { TextArea } = Input;
 import { useState, useRef, useEffect } from 'react';
-import ReactQuill from 'react-quill';
-import 'react-quill/dist/quill.snow.css';
 import { EyeOutlined, CloseOutlined } from '@ant-design/icons';
-import './style.less';
-
-const extractPlainText = (html: string): string => {
-    if (!html) return '';
-    const tempDiv = document.createElement('div');
-    tempDiv.innerHTML = html;
-    return tempDiv.textContent || '';
-};
-
-interface LinkData {
-    id: string;
-    originalText: string;
-    url: string;
-    isDeleted: boolean;
-}
-
-
-
-
-
-
 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';
 
-interface TakaiSliceDetailRequest {
-    knowledgeId: string,
-    sliceId: string,
-    sliceText: string,
+// 初始化 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();
     const { text, page } = location.state;
     const [listLoading, setListLoading] = React.useState(false);
+    const [mdImgUrlList, setMdImgUrlList] = useState<MdImg[]>();
 
-    const [editorHtml, setEditorHtml] = useState<string>(``);
-    // RichTextImageRight
-    const RichTextImageRight = () => {
-        const [plainText, setPlainText] = useState<string>(extractPlainText(editorHtml));
-        const [linkDataList, setLinkDataList] = useState<LinkData[]>([]);
-        const [activeImageUrl, setActiveImageUrl] = useState<string | null>(null);
-
-        // 跟踪鼠标是否在链接或预览区上
-        const [isHoveringLink, setIsHoveringLink] = useState(false);
-        const [isHoveringPreview, setIsHoveringPreview] = useState(false);
-
-        const editorContainerRef = useRef<HTMLDivElement>(null);
-        const previewRef = useRef<HTMLDivElement>(null);
-
-        // 初始化链接数据
-        useEffect(() => {
-            const start = async () => {
-                if (!params.sliceId || !params.knowledgeId) {
-                    throw new Error('参数错误');
-                }
-                const res = await apis.fetchTakaiSliceDetail(params.sliceId, params.knowledgeId);
-                const info = res.data.data;
-                const parser = new DOMParser();
-                const doc = parser.parseFromString(info.slice_text, 'text/html');
-                const links = doc.getElementsByTagName('a');
-                const linksData: LinkData[] = [];
-                Array.from(links).forEach((link, index) => {
-                    linksData.push({
-                        id: `link-${index}-${Date.now()}`,
-                        originalText: link.textContent || '',
-                        url: link.href,
-                        isDeleted: false
-                    });
-                });
-
-                setLinkDataList(linksData);
-            }
-            start()
-        }, []);
-
-        // 处理内容变化
-        const handleEditorChange = (html: string) => {
-            setEditorHtml(html);
-            const text = extractPlainText(html);
-            setPlainText(text);
-            form.setFieldsValue({ slice_text: text });
-
-            if (linkDataList.length > 0) {
-                const updatedLinks = [...linkDataList];
-                updatedLinks.forEach(link => {
-                    const feature = link.originalText.slice(0, 5);
-                    link.isDeleted = !text.includes(feature);
-                });
-                setLinkDataList(updatedLinks);
-            }
-        };
-
-        // 处理鼠标悬停链接事件
-        useEffect(() => {
-            if (!editorContainerRef.current) return;
-
-            const handleMouseOverLink = (e: MouseEvent) => {
-                const target = e.target as HTMLAnchorElement;
-                if (target.tagName === 'A') {
-                    const url = target.href;
-                    const isKnownLink = linkDataList.some(link =>
-                        !link.isDeleted && url.includes(link.url)
-                    );
-
-                    if (isKnownLink) {
-                        console.log('图片地址:', url);
-                        setActiveImageUrl(url);
-                        setIsHoveringLink(true);
-                    }
-                }
-            };
-
-            const handleMouseOutLink = () => {
-                setIsHoveringLink(false);
-            };
-
-            const container = editorContainerRef.current;
-            container.addEventListener('mouseover', handleMouseOverLink);
-            container.addEventListener('mouseout', handleMouseOutLink);
-
-            return () => {
-                container.removeEventListener('mouseover', handleMouseOverLink);
-                container.removeEventListener('mouseout', handleMouseOutLink);
-            };
-        }, [linkDataList]);
-
-        // 控制预览区显示/隐藏的核心逻辑
-        useEffect(() => {
-            // 当鼠标既不在链接上也不在预览区上时,才隐藏预览
-            if (!isHoveringLink && !isHoveringPreview) {
-                setActiveImageUrl(null);
-            }
-        }, [isHoveringLink, isHoveringPreview]);
-
-        // 配置编辑器(无工具栏)
-        const modules = {
-            toolbar: false
-        };
-
-        return (
-            <div>
-                {/* 容器:编辑器 + 右侧图片预览区 */}
-                <div style={{
-                    display: 'flex',
-                    gap: '16px',
-                    alignItems: 'flex-start'
-                }}>
-                    {/* 500x500的编辑器 */}
-                    <div
-                        ref={editorContainerRef}
-                        style={{
-                            width: '500px',
-                            height: '500px',
-                            border: '1px solid #d9d9d9',
-                            borderRadius: '4px',
-                            overflow: 'hidden'
-                        }}
-                    >
-                        <ReactQuill
-                            value={editorHtml}
-                            onChange={handleEditorChange}
-                            modules={modules}
-                            style={{ height: '100%' }}
-                            placeholder="请输入内容..."
-                        />
-                    </div>
-
-                    {/* 右侧图片预览区(固定位置) */}
-                    {activeImageUrl && (
-                        <div
-                            ref={previewRef}
-                            style={{
-                                width: '300px',
-                                height: '500px',
-                                backgroundColor: 'white',
-                                borderRadius: '8px',
-                                boxShadow: '0 4px 16px rgba(0, 0, 0, 0.15)',
-                                padding: '12px',
-                                border: '1px solid #eee',
-                                display: 'flex',
-                                flexDirection: 'column'
-                            }}
-                            onMouseOver={() => setIsHoveringPreview(true)}
-                            onMouseOut={() => setIsHoveringPreview(false)}
-                        >
-                            <div style={{
-                                display: 'flex',
-                                justifyContent: 'space-between',
-                                alignItems: 'center',
-                                marginBottom: '12px',
-                                paddingBottom: '8px',
-                                borderBottom: '1px solid #f0f0f0'
-                            }}>
-                                <div style={{ display: 'flex', alignItems: 'center' }}>
-                                    <EyeOutlined style={{ color: '#1890ff', marginRight: '8px' }} />
-                                    <span style={{ fontSize: '14px', color: '#333' }}>图片预览</span>
-                                </div>
-                                <CloseOutlined
-                                    style={{ color: '#999', cursor: 'pointer', fontSize: '16px' }}
-                                    onClick={() => setActiveImageUrl(null)}
-                                />
-                            </div>
-
-                            <div style={{
-                                flex: 1,
-                                display: 'flex',
-                                alignItems: 'center',
-                                justifyContent: 'center',
-                                overflow: 'hidden'
-                            }}>
-                                <img
-                                    src={activeImageUrl}
-                                    alt="示意图预览"
-                                    style={{
-                                        maxWidth: '100%',
-                                        maxHeight: '100%',
-                                        objectFit: 'contain'
-                                    }}
-                                    onError={() => setActiveImageUrl(null)}
-                                />
-                            </div>
-                        </div>
-                    )}
-                </div>
-            </div>
-        );
-    };
 
 
     const appApi = {
@@ -253,13 +59,13 @@ const SliceDetail: React.FC = () => {
                 }
                 const res = await apis.fetchTakaiSliceDetail(params.sliceId, params.knowledgeId);
                 const info = res.data.data;
-                setEditorHtml(info.slice_text || '');
                 form.setFieldsValue({
                     slice_id: info.slice_id,
                     slice_text: info.slice_text,
                     document_id: info.document_id,
                 })
-                console.log(res, 'info');
+                setContentMd(info.slice_text || '');
+                setMdImgUrlList(info.imageList || []);
             } catch (error) {
                 console.error(error);
             } finally {
@@ -292,9 +98,30 @@ const SliceDetail: React.FC = () => {
         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>
-            {/* <ImgPre></ImgPre> */}
             <div className='questionAnswerList'>
                 <div style={{ height: '100%', marginLeft: '10px' }}>
                     <Form
@@ -303,11 +130,23 @@ const SliceDetail: React.FC = () => {
                         layout='vertical'
                     >
                         <Form.Item
-                            name="slice_text"
+                            // name="slice_text"
                             rules={[{ required: true, message: '内容不能为空' }]}
                         >
-                            {RichTextImageRight()}
-
+                            <MdEditor
+                                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"
@@ -334,8 +173,7 @@ const SliceDetail: React.FC = () => {
                             {...uploadImageConfig}
                             onChange={(info) => {
                                 const insertToSliceText = (text: string) => {
-                                    const { slice_text } = form.getFieldsValue();
-
+                                    const slice_text = contentMd
                                     // 获取当前光标位置
                                     const position = cursorEndPosition;
 
@@ -346,15 +184,18 @@ const SliceDetail: React.FC = () => {
                                     } else {
                                         newValue = slice_text.slice(0, position) + text + slice_text.slice(position);
                                     }
-                                    setEditorHtml(newValue || '');
+                                    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.join('');
+                                        const text = data&&data[0]?.name||'';
                                         insertToSliceText(text);
+                                        const flagList = mdImgUrlList || [];
+                                        const flagList1 = [...flagList,...data];
+                                        setMdImgUrlList(flagList1)
                                         message.success('上传成功');
                                     } else {
                                         message.error(msg);
@@ -387,7 +228,9 @@ const SliceDetail: React.FC = () => {
                             type='primary'
                             onClick={() => {
                                 form.validateFields().then(async (values) => {
-                                    console.log('values', values)
+                                    values = {
+                                        slice_text:contentMd
+                                    }
                                     // 验证参数是否存在
                                     if (!params.knowledgeId || !params.sliceId) {
                                         message.error('知识库ID或切片ID无效');

Файловите разлики са ограничени, защото са твърде много
+ 45 - 0
src/pages/deepseek/knowledgeLib/slice/detail/mdk.tsx


+ 17 - 2
src/pages/deepseek/knowledgeLib/slice/detail/style.less

@@ -1,3 +1,18 @@
-.ql-container.ql-snow{
-    border: 1px solid #d9d9d9;
+/* 覆盖 markdown 渲染出来的样式 */
+ .custom-html-style h1 {
+  font-size: 22px;   /* 调整大小 */
+  color: #333;       /* 字体颜色 */
+//   border-bottom: 2px solid #eee; /* 底部加一条分隔线 */
+  padding-bottom: 4px;
+  margin-top: 16px;
+  margin-bottom: 12px;
+}
+
+.custom-html-style h2 {
+  font-size: 18px;
+  color: #333;
+//   border-left: 4px solid #4caf50; /* 左边加一条绿色竖线 */
+  padding-left: 8px;
+  margin-top: 14px;
+  margin-bottom: 10px;
 }

Файловите разлики са ограничени, защото са твърде много
+ 25 - 0
src/pages/deepseek/knowledgeLib/slice/detail/testPreImg.tsx


+ 13 - 1
src/router.tsx

@@ -221,7 +221,19 @@ const routerList: RouteObject[] = [
     {   /* 登录 */
         path: '/login',
         element: lazyLoad(() => import('@/pages/login/index'))
-    }
+    },
+    // {   /* 登录 */
+    //     path: '/imgPre',
+    //     element: lazyLoad(() => import('@/pages/deepseek/knowledgeLib/slice/detail/imgPre'))
+    // },
+    // {   /* 登录 */
+    //     path: '/mdk',
+    //     element: lazyLoad(() => import('@/pages/deepseek/knowledgeLib/slice/detail/mdk'))
+    // },
+    // {   /* 登录 */
+    //     path: '/testPreImg',
+    //     element: lazyLoad(() => import('@/pages/deepseek/knowledgeLib/slice/detail/testPreImg'))
+    // }
 ]
 
 // 路由模式-浏览器路由

Някои файлове не бяха показани, защото твърде много файлове са промени