Ryuiso vor 3 Wochen
Commit
d5997be2da
100 geänderte Dateien mit 19128 neuen und 0 gelöschten Zeilen
  1. 21 0
      .gitignore
  2. 41 0
      README.md
  3. 375 0
      REFACTORING_PLAN.md
  4. 16 0
      env/.env.production
  5. 17 0
      index.html
  6. 53 0
      package.json
  7. 104 0
      src/App.tsx
  8. 147 0
      src/LocalStorage.ts
  9. 82 0
      src/apis/api.ts
  10. 19 0
      src/apis/config.ts
  11. 947 0
      src/apis/index.ts
  12. BIN
      src/assets/login/background.jpg
  13. 24 0
      src/assets/pdf.worker.min.js
  14. BIN
      src/assets/public/aiIcon.png
  15. BIN
      src/assets/public/aiwj.png
  16. BIN
      src/assets/public/avatar.png
  17. BIN
      src/assets/public/bg1.png
  18. BIN
      src/assets/public/bg2.png
  19. 22 0
      src/assets/public/dllogo.svg
  20. BIN
      src/assets/public/favicon.ico
  21. 5 0
      src/assets/public/icon.svg
  22. BIN
      src/assets/public/logo.png
  23. 22 0
      src/assets/public/logo.svg
  24. BIN
      src/assets/public/logo1.png
  25. BIN
      src/assets/public/model.png
  26. BIN
      src/assets/public/notFound.png
  27. BIN
      src/assets/public/rfq.png
  28. BIN
      src/assets/public/tubing.png
  29. 0 0
      src/assets/public/z-duoban.svg
  30. 1 0
      src/assets/public/z-hebing.svg
  31. 1 0
      src/assets/public/z-huifu.svg
  32. 1 0
      src/assets/public/z-jiexi.svg
  33. 1 0
      src/assets/public/z-qiefen.svg
  34. 0 0
      src/assets/public/z-tuozhan.svg
  35. 1 0
      src/assets/public/z-xinzeng.svg
  36. 16 0
      src/components/404/index.tsx
  37. 23 0
      src/components/404/style.less
  38. 618 0
      src/components/chat/index.tsx
  39. 36 0
      src/components/chat/store.ts
  40. 4 0
      src/components/chat/welcome.less
  41. 84 0
      src/components/chat/welcome.tsx
  42. 96 0
      src/components/step/index.tsx
  43. 35 0
      src/main.tsx
  44. 188 0
      src/pages/deepseek/audit/components/InfoModal.tsx
  45. 1602 0
      src/pages/deepseek/audit/components/PreviewModal.tsx
  46. 193 0
      src/pages/deepseek/audit/components/auditHistory.tsx
  47. 193 0
      src/pages/deepseek/audit/components/auditHistoryStore.ts
  48. 998 0
      src/pages/deepseek/audit/components/style.less
  49. 228 0
      src/pages/deepseek/audit/index.tsx
  50. 193 0
      src/pages/deepseek/audit/store.ts
  51. 14 0
      src/pages/deepseek/audit/style.less
  52. 49 0
      src/pages/deepseek/audit/types.ts
  53. 165 0
      src/pages/deepseek/dataExport/components/InfoModal.tsx
  54. 101 0
      src/pages/deepseek/dataExport/components/Search.tsx
  55. 130 0
      src/pages/deepseek/dataExport/index.tsx
  56. 147 0
      src/pages/deepseek/dataExport/store.ts
  57. 14 0
      src/pages/deepseek/dataExport/style.less
  58. 44 0
      src/pages/deepseek/dataExport/types.ts
  59. 271 0
      src/pages/deepseek/evaluationTool/datasetManagement/components/dataManagementMode.tsx
  60. 67 0
      src/pages/deepseek/evaluationTool/datasetManagement/components/exampleModel.tsx
  61. 184 0
      src/pages/deepseek/evaluationTool/datasetManagement/list/index.tsx
  62. 88 0
      src/pages/deepseek/evaluationTool/datasetManagement/list/store.ts
  63. 303 0
      src/pages/deepseek/evaluationTool/evaluationTask/components/CreateTaskMode.tsx
  64. 163 0
      src/pages/deepseek/evaluationTool/evaluationTask/components/evaluationTaskHistory.tsx
  65. 167 0
      src/pages/deepseek/evaluationTool/evaluationTask/components/evaluationTaskHistoryStore.ts
  66. 74 0
      src/pages/deepseek/evaluationTool/evaluationTask/components/indicatorRag.tsx
  67. 269 0
      src/pages/deepseek/evaluationTool/evaluationTask/list/index.tsx
  68. 77 0
      src/pages/deepseek/evaluationTool/evaluationTask/list/store.ts
  69. 52 0
      src/pages/deepseek/evaluationTool/evaluationTask/types.ts
  70. 116 0
      src/pages/deepseek/knowledgeLib/detail/components/InfoModal.tsx
  71. 305 0
      src/pages/deepseek/knowledgeLib/detail/components/InfoModalSetting.tsx
  72. 1573 0
      src/pages/deepseek/knowledgeLib/detail/components/MdModal.tsx
  73. 358 0
      src/pages/deepseek/knowledgeLib/detail/components/QuoteModal.tsx
  74. 669 0
      src/pages/deepseek/knowledgeLib/detail/components/UploadModal.tsx
  75. 437 0
      src/pages/deepseek/knowledgeLib/detail/components/prevewSlice.tsx
  76. 29 0
      src/pages/deepseek/knowledgeLib/detail/components/store.ts
  77. 40 0
      src/pages/deepseek/knowledgeLib/detail/components/style.less
  78. 364 0
      src/pages/deepseek/knowledgeLib/detail/drawerIndex.tsx
  79. 680 0
      src/pages/deepseek/knowledgeLib/detail/index.tsx
  80. 410 0
      src/pages/deepseek/knowledgeLib/detail/store.ts
  81. 40 0
      src/pages/deepseek/knowledgeLib/detail/style.less
  82. 86 0
      src/pages/deepseek/knowledgeLib/detail/types.ts
  83. 345 0
      src/pages/deepseek/knowledgeLib/list/components/InfoModal.tsx
  84. 347 0
      src/pages/deepseek/knowledgeLib/list/index.tsx
  85. 260 0
      src/pages/deepseek/knowledgeLib/list/store.ts
  86. 32 0
      src/pages/deepseek/knowledgeLib/list/style.less
  87. 59 0
      src/pages/deepseek/knowledgeLib/list/types.ts
  88. 20 0
      src/pages/deepseek/knowledgeLib/revisionTool/components/reviseDrawer.less
  89. 547 0
      src/pages/deepseek/knowledgeLib/revisionTool/components/reviseDrawer.tsx
  90. 344 0
      src/pages/deepseek/knowledgeLib/revisionTool/components/revisionHistory.tsx
  91. 163 0
      src/pages/deepseek/knowledgeLib/revisionTool/list/index.tsx
  92. 77 0
      src/pages/deepseek/knowledgeLib/revisionTool/list/store.ts
  93. 434 0
      src/pages/deepseek/questionAnswer/appPlazaList/index.tsx
  94. 2 0
      src/pages/deepseek/questionAnswer/appPlazaList/store.ts
  95. 226 0
      src/pages/deepseek/questionAnswer/appPlazaList/style.less
  96. 140 0
      src/pages/deepseek/questionAnswer/info/README.md
  97. 482 0
      src/pages/deepseek/questionAnswer/info/component/IconPicker.tsx
  98. 1575 0
      src/pages/deepseek/questionAnswer/info/index.tsx
  99. 96 0
      src/pages/deepseek/questionAnswer/info/promptTemplates.ts
  100. 86 0
      src/pages/deepseek/questionAnswer/info/store.ts

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+# 系统文件
+.DS_Store
+*.rar
+*.zip
+
+# 编辑器配置
+.vscode/
+.idea/
+
+# 项目依赖
+node_modules
+package-lock.json
+
+# 打包文件
+/build
+/dist
+
+env/.env.development
+
+.cursor
+.history

+ 41 - 0
README.md

@@ -0,0 +1,41 @@
+##  基础运行环境
+01. `node 18.15.0`
+02. `npm 9.5.0`
+
+##  本地启动项目
+01. `npm ci`
+02. `npm run *start`
+
+##  服务构建项目
+01. `npm ci`
+02. `npm run *build`
+
+##  技术栈
+01. 框架——React@v18  
+02. 路由——React-Router-Dom@v7  
+03. 状态管理——Mobx@v6  
+04. UI组件库——Ant-Design@v5  
+05. 语法——TypeScript Less  
+06. 网络——Axios  
+07. 日期——Day.js  
+08. 打包工具——Vite@v6  
+
+##  文件结构
+src                资源文件  
+|-- apis           网络请求  
+|-- assets         静态资源  
+|-- components     全局组件  
+|-- pages          页面目录  
+|-- style          全局样式  
+|-- typings        类 型 库  
+|-- utils          通用方法  
+|-- App            根 组 件  
+|-- LocalStorage  本地存储  
+|-- main          入口文件  
+|-- router        全局路由  
+vite.config        打包配置  
+
+
+
+
+

+ 375 - 0
REFACTORING_PLAN.md

@@ -0,0 +1,375 @@
+# 项目结构重构计划
+
+## 当前问题分析
+
+### 1. 目录结构混乱
+- `takai` 目录名称不明确,无法直观理解其用途
+- 智谱AI 和 DeepSeek AI 的页面分散在不同目录
+- 缺乏清晰的平台分离
+
+### 2. 路由配置复杂
+- 两套独立的路由配置
+- 路由路径不够语义化
+- 缺乏统一的平台标识
+
+### 3. 代码复用困难
+- 相似功能的组件分散在不同目录
+- 缺乏共享组件的统一管理
+- 平台特定的逻辑与通用逻辑混合
+
+## 重构目标
+
+### 1. 清晰的平台分离
+- 按 AI 平台组织代码结构
+- 统一的命名规范
+- 清晰的职责划分
+
+### 2. 提高代码复用性
+- 提取共享组件
+- 统一 API 调用方式
+- 减少重复代码
+
+### 3. 改善可维护性
+- 统一的开发规范
+- 清晰的模块边界
+- 便于功能扩展
+
+## 重构方案
+
+### 阶段一:目录结构重组
+
+#### 1. 创建新的目录结构
+```
+src/pages/
+├── platforms/
+│   ├── deepseek/           # DeepSeek AI 平台
+│   │   ├── questionAnswer/
+│   │   ├── knowledgeLib/
+│   │   ├── audit/
+│   │   └── dataExport/
+│   └── zhipu/              # 智谱AI 平台
+│       ├── questionAnswer/
+│       ├── knowledgeLib/
+│       └── dataExport/
+└── shared/                 # 共享页面组件
+```
+
+#### 2. 迁移现有组件
+```bash
+# 迁移 DeepSeek AI 组件
+mv src/pages/takai/* src/pages/platforms/deepseek/
+
+# 迁移智谱AI 组件
+mv src/pages/questionAnswer src/pages/platforms/zhipu/
+mv src/pages/knowledgeLib src/pages/platforms/zhipu/
+mv src/pages/dataExport src/pages/platforms/zhipu/
+```
+
+### 阶段二:路由配置优化
+
+#### 1. 统一路由前缀
+```typescript
+// 新的路由结构
+const platformRoutes = {
+    deepseek: {
+        path: '/deepseek',
+        children: [
+            { path: 'questionAnswer', element: lazyLoad(() => import('@/pages/platforms/deepseek/questionAnswer')) },
+            { path: 'knowledgeLib', element: lazyLoad(() => import('@/pages/platforms/deepseek/knowledgeLib')) },
+            { path: 'audit', element: lazyLoad(() => import('@/pages/platforms/deepseek/audit')) },
+            { path: 'dataExport', element: lazyLoad(() => import('@/pages/platforms/deepseek/dataExport')) },
+        ]
+    },
+    zhipu: {
+        path: '/zhipu',
+        children: [
+            { path: 'questionAnswer', element: lazyLoad(() => import('@/pages/platforms/zhipu/questionAnswer')) },
+            { path: 'knowledgeLib', element: lazyLoad(() => import('@/pages/platforms/zhipu/knowledgeLib')) },
+            { path: 'dataExport', element: lazyLoad(() => import('@/pages/platforms/zhipu/dataExport')) },
+        ]
+    }
+};
+```
+
+#### 2. 更新路由配置
+- 修改 `src/router.tsx` 文件
+- 更新面包屑配置
+- 调整默认重定向逻辑
+
+### 阶段三:API 层重构
+
+#### 1. 创建平台特定的 API 模块
+```typescript
+// src/apis/platforms/deepseek.ts
+export const deepseekApis = {
+    questionAnswer: {
+        list: (params: any) => request.get('/deepseek/question-answer', { params }),
+        create: (data: any) => request.post('/deepseek/question-answer', data),
+        update: (id: string, data: any) => request.put(`/deepseek/question-answer/${id}`, data),
+        delete: (id: string) => request.delete(`/deepseek/question-answer/${id}`),
+    },
+    knowledgeLib: {
+        list: (params: any) => request.get('/deepseek/knowledge-lib', { params }),
+        detail: (id: string) => request.get(`/deepseek/knowledge-lib/${id}`),
+        create: (data: any) => request.post('/deepseek/knowledge-lib', data),
+    },
+    audit: {
+        list: (params: any) => request.get('/deepseek/audit', { params }),
+    },
+    dataExport: {
+        export: (params: any) => request.get('/deepseek/data-export', { params }),
+    },
+};
+
+// src/apis/platforms/zhipu.ts
+export const zhipuApis = {
+    questionAnswer: {
+        list: (params: any) => request.get('/zhipu/question-answer', { params }),
+        create: (data: any) => request.post('/zhipu/question-answer', data),
+        update: (id: string, data: any) => request.put(`/zhipu/question-answer/${id}`, data),
+        delete: (id: string) => request.delete(`/zhipu/question-answer/${id}`),
+    },
+    knowledgeLib: {
+        list: (params: any) => request.get('/zhipu/knowledge-lib', { params }),
+        detail: (id: string) => request.get(`/zhipu/knowledge-lib/${id}`),
+        create: (data: any) => request.post('/zhipu/knowledge-lib', data),
+    },
+    dataExport: {
+        export: (params: any) => request.get('/zhipu/data-export', { params }),
+    },
+};
+```
+
+#### 2. 创建统一的 API 接口
+```typescript
+// src/apis/platforms/index.ts
+export interface PlatformApi {
+    questionAnswer: {
+        list: (params: any) => Promise<any>;
+        create: (data: any) => Promise<any>;
+        update: (id: string, data: any) => Promise<any>;
+        delete: (id: string) => Promise<any>;
+    };
+    knowledgeLib: {
+        list: (params: any) => Promise<any>;
+        detail: (id: string) => Promise<any>;
+        create: (data: any) => Promise<any>;
+    };
+    dataExport: {
+        export: (params: any) => Promise<any>;
+    };
+}
+
+export const platformApis: Record<string, PlatformApi> = {
+    deepseek: deepseekApis,
+    zhipu: zhipuApis,
+};
+```
+
+### 阶段四:组件重构
+
+#### 1. 提取共享组件
+```typescript
+// src/components/shared/QuestionAnswerList.tsx
+interface QuestionAnswerListProps {
+    platform: 'deepseek' | 'zhipu';
+    data: any[];
+    loading: boolean;
+    onAction: (action: string, data: any) => void;
+}
+
+const QuestionAnswerList: React.FC<QuestionAnswerListProps> = ({
+    platform,
+    data,
+    loading,
+    onAction,
+}) => {
+    // 通用的列表组件实现
+};
+
+// src/components/shared/KnowledgeLibList.tsx
+interface KnowledgeLibListProps {
+    platform: 'deepseek' | 'zhipu';
+    data: any[];
+    loading: boolean;
+    onAction: (action: string, data: any) => void;
+}
+
+const KnowledgeLibList: React.FC<KnowledgeLibListProps> = ({
+    platform,
+    data,
+    loading,
+    onAction,
+}) => {
+    // 通用的知识库列表组件实现
+};
+```
+
+#### 2. 平台特定组件
+```typescript
+// src/pages/platforms/deepseek/questionAnswer/index.tsx
+const DeepSeekQuestionAnswer: React.FC = () => {
+    const store = useDeepSeekStore();
+    
+    return (
+        <QuestionAnswerList
+            platform="deepseek"
+            data={store.questionAnswerList}
+            loading={store.loading}
+            onAction={store.handleAction}
+        />
+    );
+};
+
+// src/pages/platforms/zhipu/questionAnswer/index.tsx
+const ZhipuQuestionAnswer: React.FC = () => {
+    const store = useZhipuStore();
+    
+    return (
+        <QuestionAnswerList
+            platform="zhipu"
+            data={store.questionAnswerList}
+            loading={store.loading}
+            onAction={store.handleAction}
+        />
+    );
+};
+```
+
+### 阶段五:状态管理重构
+
+#### 1. 创建平台特定的 Store
+```typescript
+// src/stores/platforms/deepseek.ts
+class DeepSeekStore {
+    @observable questionAnswerList = [];
+    @observable knowledgeLibList = [];
+    @observable loading = false;
+    
+    @action
+    async fetchQuestionAnswerList(params: any) {
+        this.loading = true;
+        try {
+            const response = await platformApis.deepseek.questionAnswer.list(params);
+            this.questionAnswerList = response.data;
+        } finally {
+            this.loading = false;
+        }
+    }
+    
+    @action
+    async handleAction(action: string, data: any) {
+        // 平台特定的操作处理
+    }
+}
+
+// src/stores/platforms/zhipu.ts
+class ZhipuStore {
+    @observable questionAnswerList = [];
+    @observable knowledgeLibList = [];
+    @observable loading = false;
+    
+    @action
+    async fetchQuestionAnswerList(params: any) {
+        this.loading = true;
+        try {
+            const response = await platformApis.zhipu.questionAnswer.list(params);
+            this.questionAnswerList = response.data;
+        } finally {
+            this.loading = false;
+        }
+    }
+    
+    @action
+    async handleAction(action: string, data: any) {
+        // 平台特定的操作处理
+    }
+}
+```
+
+#### 2. 创建 Store 工厂
+```typescript
+// src/stores/platforms/index.ts
+export const createPlatformStore = (platform: 'deepseek' | 'zhipu') => {
+    switch (platform) {
+        case 'deepseek':
+            return new DeepSeekStore();
+        case 'zhipu':
+            return new ZhipuStore();
+        default:
+            throw new Error(`Unsupported platform: ${platform}`);
+    }
+};
+```
+
+## 实施步骤
+
+### 第一步:准备工作
+1. 创建新的目录结构
+2. 备份现有代码
+3. 创建功能分支
+
+### 第二步:迁移组件
+1. 迁移 DeepSeek AI 组件
+2. 迁移智谱AI 组件
+3. 更新导入路径
+
+### 第三步:重构 API
+1. 创建平台特定的 API 模块
+2. 更新现有 API 调用
+3. 测试 API 功能
+
+### 第四步:重构路由
+1. 更新路由配置
+2. 测试路由功能
+3. 更新导航逻辑
+
+### 第五步:重构状态管理
+1. 创建平台特定的 Store
+2. 更新组件中的状态管理
+3. 测试状态管理功能
+
+### 第六步:测试和优化
+1. 全面功能测试
+2. 性能优化
+3. 代码审查
+
+## 预期收益
+
+### 1. 代码可维护性提升
+- 清晰的目录结构
+- 统一的命名规范
+- 模块化的代码组织
+
+### 2. 开发效率提升
+- 减少重复代码
+- 提高代码复用性
+- 简化新功能开发
+
+### 3. 扩展性增强
+- 易于添加新的 AI 平台
+- 支持平台特定的功能
+- 灵活的配置管理
+
+### 4. 团队协作改善
+- 统一的开发规范
+- 清晰的代码结构
+- 便于代码审查
+
+## 风险评估
+
+### 1. 迁移风险
+- **风险**: 迁移过程中可能引入 bug
+- **缓解**: 分阶段迁移,每个阶段都要充分测试
+
+### 2. 兼容性风险
+- **风险**: 现有功能可能受到影响
+- **缓解**: 保持向后兼容,逐步迁移
+
+### 3. 性能风险
+- **风险**: 重构可能影响性能
+- **缓解**: 性能测试,优化关键路径
+
+## 总结
+
+通过这次重构,项目将获得更清晰的结构、更好的可维护性和更强的扩展性。重构过程采用渐进式方法,确保现有功能的稳定性,同时为未来的发展奠定良好的基础。

+ 16 - 0
env/.env.production

@@ -0,0 +1,16 @@
+# 生产环境
+VITE_ENV = 'production'
+
+# Api地址
+VITE_API_URL = 'http://10.1.27.4:8091'
+
+#跳转地址
+# VITE_JUMP_URL = 'http://xia0miduo.gicp.net:3900/#/knowledgeChat?showMenu=false&chatMode=LOCAL'
+VITE_JUMP_URL = 'http://10.1.14.17:3900/#/knowledgeChat?showMenu=false&chatMode=LOCAL'
+
+# 接口加密功能开关(如需关闭 后端也必须对应关闭)
+VITE_APP_ENCRYPT = true
+# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
+VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
+VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='

+ 17 - 0
index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8" />
+  <meta name="renderer" content="webkit" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <link rel="icon" href="/src/assets/public/favicon.ico" />
+  <title>盈科开放平台</title>
+</head>
+
+<body>
+  <div id="root"></div>
+  <script type="module" src="/src/main.tsx"></script>
+</body>
+
+</html>

+ 53 - 0
package.json

@@ -0,0 +1,53 @@
+{
+  "name": "chat-admin-web",
+  "version": "1.0.0",
+  "private": true,
+  "description": "盈科开放平台",
+  "type": "module",
+  "license": "ISC",
+  "scripts": {
+    "start": "vite --mode development",
+    "start:prod": "vite --mode production",
+    "build": "vite build --mode development",
+    "build:prod": "vite build --mode production"
+  },
+  "dependencies": {
+    "@ant-design/x": "^1.6.0",
+    "@antv/g2plot": "^2.4.35",
+    "@fortaine/fetch-event-source": "^3.0.6",
+    "@fortawesome/fontawesome-free": "^7.1.0",
+    "@tailwindcss/vite": "^4.1.17",
+    "@types/crypto-js": "^4.2.2",
+    "antd": "^5.23.0",
+    "antd-style": "^3.7.1",
+    "axios": "1.8.2",
+    "crypto-js": "^4.2.0",
+    "dayjs": "^1.11.0",
+    "jsencrypt": "^3.5.4",
+    "mammoth": "^1.11.0",
+    "markdown-it": "^14.1.0",
+    "mobx": "^6.13.0",
+    "mobx-react": "^9.2.0",
+    "nanoid": "^5.1.6",
+    "pdfjs-dist": "^5.4.296",
+    "react": "^18.2.0",
+    "react-dom": "^18.2.0",
+    "react-markdown": "^10.1.0",
+    "react-markdown-editor-lite": "^1.3.4",
+    "react-pdf": "^10.2.0",
+    "react-quill": "^2.0.0",
+    "react-router-dom": "^7.1.0",
+    "tailwindcss": "^4.1.17"
+  },
+  "devDependencies": {
+    "@types/markdown-it": "^14.1.2",
+    "@types/node": "^22.0.0",
+    "@types/react": "^18.2.0",
+    "@types/react-dom": "^18.2.0",
+    "@vitejs/plugin-react": "^4.3.0",
+    "autoprefixer": "^10.4.21",
+    "less": "^4.2.0",
+    "typescript": "^5.7.0",
+    "vite": "6.3.4"
+  }
+}

+ 104 - 0
src/App.tsx

@@ -0,0 +1,104 @@
+import * as React from 'react';
+import { RouterProvider } from 'react-router-dom';
+import {
+    ConfigProvider as AntdConfigProvider,
+    App as AntdApp,
+    message,
+    notification,
+} from 'antd';
+import zhCN from 'antd/locale/zh_CN';
+// import router from '@/router';
+import AppRouter from '@/router'
+interface ConfigProviderProps {
+    children: React.ReactNode,
+}
+
+// Ant-Design全局化配置
+const ConfigProvider: React.FC<ConfigProviderProps> = (props: ConfigProviderProps) => {
+    function getDesignToken() {
+        // 获取元素
+        const root = document.getElementById('root');
+        // 获取元素计算样式
+        const styles = getComputedStyle(root!);
+        // 获取Ant-Design主题-属性
+        const colorPrimary = styles.getPropertyValue('--primary-color');
+        const colorTextBase = styles.getPropertyValue('--text-color');
+        const borderRadiusArray = styles.getPropertyValue('--border-radius').match(/\d+/);
+
+        return {
+            colorPrimary: colorPrimary || undefined,
+            colorTextBase: colorTextBase || undefined,
+            borderRadius: borderRadiusArray ? Number(borderRadiusArray[0]) : undefined,
+        }
+    }
+
+    const designToken = getDesignToken();
+
+    return (
+        <AntdConfigProvider
+            // 组件-中文
+            locale={zhCN}
+            // 警告等级
+            warning={{
+                strict: true,// 严格模式
+            }}
+            // 渲染父节点到body上
+            getPopupContainer={() => document.body}
+            // 设置主题
+            theme={{
+                token: {
+                    colorPrimary: designToken.colorPrimary,// 主题颜色
+                    colorTextBase: designToken.colorTextBase,// 文本颜色
+                    borderRadius: designToken.borderRadius,// 圆角大小
+                },
+                components: {
+                    Table: {
+                        headerBg: '#F7F8FA',
+                        headerSplitColor: 'transparent',
+                    },
+                },
+            }}
+            /* 组件配置 */
+            button={{
+                autoInsertSpace: false,// 移除按钮两个汉字之间的空格
+            }}
+        >
+            {props.children}
+        </AntdConfigProvider>
+    );
+}
+
+const App: React.FC = () => {
+    // 全局提示
+    message.config({
+        duration: 2,// 2秒自动关闭
+        maxCount: 1,// 最多显示1条
+    });
+
+    // 通知提醒
+    notification.config({
+        duration: 2,// 2秒自动关闭
+        maxCount: 1,// 最多显示1条
+    });
+
+    // 全局配置
+    AntdConfigProvider.config({
+        // 静态方法
+        holderRender: (children) => (
+            <ConfigProvider>
+                {children}
+            </ConfigProvider>
+        )
+    });
+
+    return (
+        <ConfigProvider>
+            <AntdApp style={{ height: '100%', lineHeight: 'normal' }}>
+                {/* <RouterProvider router={router} /> */}
+                <AppRouter></AppRouter>
+            </AntdApp>
+        </ConfigProvider>
+    );
+};
+
+export default App;

+ 147 - 0
src/LocalStorage.ts

@@ -0,0 +1,147 @@
+interface AccountPassword {
+    account: string,
+    password: string,
+};
+
+interface UserInfo {
+    id: number,
+    name: string,
+    tenantId: string,
+};
+
+class LocalStorage {
+    // 存储账号密码
+    setAccountPassword = (accountPassword?: AccountPassword) => {
+        if (accountPassword) {
+            
+            localStorage.setItem('accountPassword',  encodeURIComponent(JSON.stringify(accountPassword)));
+        } else {
+            localStorage.removeItem('accountPassword');
+        }
+    }
+
+    // 存储凭证
+    setToken = (token: string) => {
+        localStorage.setItem('token', token);
+    }
+
+    // 存储用户信息
+    setUserInfo = (info: UserInfo) => {
+        localStorage.setItem('userInfo', JSON.stringify(info));
+    }
+
+    // 存储菜单类型
+    setMenuType = (type: number) => {
+        localStorage.setItem('menuType', String(type));
+    }
+
+    // 获取账号密码
+    getAccountPassword = () => {
+        const infoString = localStorage.getItem('accountPassword');
+
+        if (infoString) {
+            const info: AccountPassword = JSON.parse(decodeURIComponent(infoString));
+            return info;
+        } else {
+            return undefined;
+        }
+    }
+
+    // 获取凭证
+    getToken = () => {
+        const token = localStorage.getItem('token');
+
+        if (token) {
+            return token as string;
+        } else {
+            this.clear();
+            return undefined;
+        }
+    }
+
+    // 获取用户信息
+    getUserInfo = () => {
+        const infoString = localStorage.getItem('userInfo');
+
+        if (infoString) {
+            const info: UserInfo = JSON.parse(infoString);
+            return info;
+        } else {
+            return undefined;
+        }
+    }
+
+    // 获取菜单类型
+    getMenuType = () => {
+        const menuType = localStorage.getItem('menuType');
+
+        if (menuType) {
+            return Number(menuType);
+        } else {
+            return 0;
+        }
+    }
+
+    // 清除
+    clear = () => {
+        /*
+         * 保留密码
+         */
+        const accountPassword = this.getAccountPassword();
+        const cloneAccountPassword = accountPassword ? { ...accountPassword } : undefined;
+
+        // localStorage.clear();
+        this.removeToken('token');
+        this.removeToken('menuType');
+        this.removeToken('permissions');
+        this.removeToken('userInfo');
+        this.removeToken('jk_constant_routes_v1');
+        this.setAccountPassword(cloneAccountPassword);
+    }
+    // 移除token
+    removeToken = (type: string) => {
+        localStorage.removeItem(type);
+    }
+
+    // 存储roles
+    setRoles = (roles: string) => {
+        localStorage.setItem('roles', JSON.stringify(roles));
+    }
+
+    // 存储permissions
+    setPermissions = (permissions: string) => {
+        localStorage.setItem('permissions', JSON.stringify(permissions));
+    }
+
+    // 获取roles
+    getRoles = (): string | null => {
+        const rolesStr = localStorage.getItem('roles');
+        return rolesStr;
+    }
+
+    // 获取permissions
+    getPermissions = (): string | null => {
+        const permissionsStr = localStorage.getItem('permissions');
+        return permissionsStr;
+    }
+
+    getStatusFlag = (permissionsStr: string): boolean => {
+        const permissions = this.getPermissions();
+        if (permissions && (permissions.includes('*:*:*') || permissions.includes(permissionsStr))) {
+            // admin
+            return true;
+        }
+        return false;
+    }
+
+    getStatusRoleFlag = (): boolean => {
+        const roles = this.getRoles();
+        if (roles && (roles.includes('admin') || roles.includes('manager'))) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
+
+export default new LocalStorage();

+ 82 - 0
src/apis/api.ts

@@ -0,0 +1,82 @@
+import axios, { AxiosResponse } from 'axios';
+import { message } from 'antd';
+import config, { getHeaders } from './config';
+import LocalStorage from '@/LocalStorage';
+import { encryptBase64, encryptWithAes, generateAesKey, decryptWithAes, decryptBase64 } from '@/utils/crypto';
+import { encrypt, decrypt } from '@/utils/jsencrypt';
+const encryptHeader = 'encrypt-key';
+// 创建axios实例
+const axiosInstance = axios.create({
+    baseURL: config.baseURL,
+    timeout: 600000 * 2,// 请求超时20分钟
+});
+
+// 请求拦截器
+axiosInstance.interceptors.request.use(
+    (config: any) => {
+        const isEncrypt = config.headers?.isEncrypt === 'true';
+        config.headers = {
+            'Content-Language': 'zh_CN',
+            clientid:'e5cd7e4891bf95d1d19206ce24a7b32e',
+            ...config.headers,
+            ...getHeaders(),
+        };
+        if (!navigator.onLine) {
+            message.error('网络故障');
+        }
+             // 当开启参数加密
+        if (isEncrypt && (config.method === 'post' || config.method === 'put')) {
+            // 生成一个 AES 密钥
+            const aesKey = generateAesKey();
+            config.headers[encryptHeader] = encrypt(encryptBase64(aesKey));
+            config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey);
+        }
+        return config;
+    }
+);
+
+// 响应拦截器
+axiosInstance.interceptors.response.use(
+    (response: AxiosResponse) => {// 成功信息
+        const { config, data } = response;
+        if (config.responseType === 'blob') {
+            return Promise.resolve(data);
+        } else {
+            if (data.code === 200) {// 成功
+                return Promise.resolve(data);
+            } else {// 失败
+                if (data.code === 401) {
+                    LocalStorage.clear();
+                    message.error('登录过期');
+                    // 使用 window.location 确保跳转生效
+                    window.location.replace('/login');
+                    return Promise.reject();
+                } else {
+                    message.error(data.msg||'请求失败');
+                    return Promise.reject(data);
+                }
+            }
+        }
+    },
+    (error) => {// 错误信息
+        // HTTP状态码
+        const statusCode = error.response?.status;
+        if (String(error).includes('timeout')) {
+            message.error('请求超时');
+        } else {
+            if (statusCode === 401) {
+                LocalStorage.clear();
+                message.error('登录过期');
+                // 使用 window.location 确保跳转生效
+                window.location.replace('/login');
+            } else if (statusCode && statusCode < 500) {
+                message.error('请求失败');
+            } else {
+                message.error('服务异常');
+            }
+        }
+        return Promise.reject();
+    }
+);
+
+export default axiosInstance;

+ 19 - 0
src/apis/config.ts

@@ -0,0 +1,19 @@
+import LocalStorage from '@/LocalStorage';
+
+const baseURL = '/api';
+
+const config = {
+    baseURL: baseURL,
+};
+
+export const getHeaders = () => {
+    const headers: { 'Authorization'?: string,'clientid'?:string } = {};
+    const token = LocalStorage.getToken();
+    if (token) {
+        headers['Authorization'] = 'Bearer '+token;
+        headers['clientid']='e5cd7e4891bf95d1d19206ce24a7b32e';
+    }
+    return headers;
+};
+
+export default config;

+ 947 - 0
src/apis/index.ts

@@ -0,0 +1,947 @@
+import exp from 'constants';
+import api from './api';
+import audit from '@/pages/deepseek/audit';
+import { data } from 'react-router-dom';
+
+// Api参数类型
+export type LoginApiParams = {
+    username: string,
+    password: string,
+    uuid: string,
+    code: string | number,
+};
+
+// Api参数类型
+export type JkLoginApiParams = {
+    code: string,
+    redirectUrl: string,
+};
+
+export type FetchAppListApiParams = {
+    pageNum: number,
+    pageSize: number,
+    userId: string,
+    typeId: any,
+    projectId?: any,
+    keyword?: string,
+    isCollect?: string | null,
+};
+export type FetchAppListMyApiParams = {
+    pageNum: number,
+    pageSize: number,
+    name: string,
+};
+
+export type FetchKnowledgeLibListApiParams = {
+    pageNum: number,
+    pageSize: number,
+};
+
+export type CreateOrModifyKnowledgeLibApiParams = {
+    name: string,
+    embeddingId: string,
+    description: string,
+};
+
+export type FetchAppIndexParams = {
+    pageNum: number,
+    pageSize: number,
+    userId: string,
+    typeId: any,
+    projectId: any,
+    keyword: string,
+};
+
+export type CreateOrModifyApplicationApiParams = {
+    id: string,
+    name: string,  //应用名称
+    desc: string,  //应用描述
+    prompt: string, //应用提示语
+    topP: string, //topP
+    topK?: string, //topK
+    temperature: string, //温度
+    knowledge_ids: string[],
+    slice_count: number,
+    model: string,
+    iconColor: string,
+    iconType: string,
+    questionList: string[],
+    // knowledge_info: {
+    //     model: string,
+    //     knowledge_ids: string[],
+    //     slice_config_type: string,
+    //     recall_method: string,
+    //     slice_count: number,
+    //     rerank_status: number,
+    //     rerank_model_name: string,
+    //     show_recall_result: boolean,
+    //     recall_slice_splicing_method: string,
+    // },
+    //questionList: string[]
+};
+
+export type FetchDocumentLibListApiParams = {
+    knowledge_id: string,
+    page: number,
+    size: number,
+}
+
+export type ModifyDocumentApiParams = {
+    id: string,
+    name: string,
+    url: string,
+    length: number,
+    sentence_size: number,
+    knowledge_type: number,
+    custom_separator: string[],
+    embedding_stat: number,
+    word_num: number,
+    parse_image: number
+};
+
+export type FetchChatHistoryListApiParams = Partial<{
+    appId: string,
+    pageNum: number,
+    pageSize: number,
+}>;
+
+export type ModifyDocumentSettingApiParams = {
+    knowledgeId: string,
+    documentId: string,
+    setSlice: string,
+    setAnalyze: string,
+    setTabel: string,
+};
+
+export type FetchSliceListApiParams = {
+    knowledge_id: string,
+    document_id: string,
+    text: string,
+    pageNum: number,
+    pageSize: number,
+};
+
+export type addAndModifySliceApiParams = {
+    knowledgeId: string,
+    sliceId: string,
+    sliceText: string,
+    documentId: string,
+};
+
+export type FetchAuditConfigLibListApiParams = {
+    approver: string,
+    pageNum: number,
+    pageSize: number,
+};
+
+// Api函数类型
+export type CheckTokenApi = (token: string) => Promise<any>;
+export type JkLoginApi = (data: JkLoginApiParams) => Promise<any>;
+export type LoginApi = (data: LoginApiParams) => Promise<any>;
+export type LogoutApi = () => Promise<any>;
+export type FetchAppListApi = (data: FetchAppListApiParams) => Promise<any>;
+export type FetchKnowledgeLibListApi = (data: FetchKnowledgeLibListApiParams) => Promise<any>;
+export type FetchEmbeddingListApi = () => Promise<any>;
+export type CreateKnowledgeLibApi = (data: CreateOrModifyKnowledgeLibApiParams) => Promise<any>;
+export type ModifyKnowledgeLibApi = (knowledgeId: string, data: CreateOrModifyKnowledgeLibApiParams) => Promise<any>;
+export type DeleteKnowledgeLibApi = (knowledgeId: string) => Promise<any>;
+export type FetchKnowledgeLibDetailApi = (knowledgeId: string) => Promise<any>;
+export type FetchAppIndexApi = (data: FetchAppIndexParams) => Promise<any>;
+export type FetchApplicationDetailApi = (appId: string) => Promise<any>;
+export type FetchModelListApi = () => Promise<any>;
+export type FetchKnowledgeApiListApi = () => Promise<any>;
+export type ModifyApplicationLibApi = (appId: string, data: CreateOrModifyApplicationApiParams) => Promise<any>;
+export type DeleteApplicationLibApi = (appId: string) => Promise<any>;
+export type CreateApplicationLibApi = (data: CreateOrModifyApplicationApiParams) => Promise<any>;
+export type uploadFileLibApi = (konwledgeId: string,data?:any) => Promise<any>;
+export type FetchDocumentLibListApi = (data: FetchDocumentLibListApiParams) => Promise<any>;
+export type FetchDocumentLibApi = (id: string) => Promise<any>;
+export type ModifyDocumentLibApi = (id: string, data: ModifyDocumentApiParams) => Promise<any>;
+export type DeleteDocumentLibApi = (id: string) => Promise<any>;
+export type FetchApplicationListApi = () => Promise<any>;
+export type FetchChatHistoryListApi = (data: FetchChatHistoryListApiParams) => Promise<any>;
+export type ExportChatHistoryApi = (id: string) => Promise<any>;
+export type FetchTakaiAppListApi = (data: FetchAppListApiParams) => Promise<any>;
+export type FetchTakaiMyAppListApi = (data: FetchAppListMyApiParams) => Promise<any>;
+export type FetchTakaiApplicationDetailApi = (appId: string) => Promise<any>;
+export type CreateTakaiApplicationLibApi = (data: CreateOrModifyApplicationApiParams) => Promise<any>;
+export type ModifyTakaiApplicationLibApi = (appId: string, data: CreateOrModifyApplicationApiParams) => Promise<any>;
+export type DeleteTakaiApplicationLibApi = (appId: string) => Promise<any>;
+export type FetchTakaiAppIndexApi = (data: FetchAppIndexParams) => Promise<any>;
+export type FetchTakaiKnowledgeApiListApi = () => Promise<any>;
+export type FetchTakaiKnowledgeLibListApi = (data: FetchKnowledgeLibListApiParams) => Promise<any>;
+export type FetchTakaiKnowledgeLibDetailApi = (knowledgeId: string) => Promise<any>;
+export type ModifyTakaiKnowledgeLibApi = (knowledgeId: string, data: CreateOrModifyKnowledgeLibApiParams) => Promise<any>;
+export type CreateTakaiKnowledgeLibApi = (data: CreateOrModifyKnowledgeLibApiParams) => Promise<any>;
+export type DeleteTakaiKnowledgeLibApi = (knowledgeId: string) => Promise<any>;
+export type FetchTakaiDocumentLibListApi = (data: FetchDocumentLibListApiParams) => Promise<any>;
+export type FetchTakaiDocumentLibApi = (id: string) => Promise<any>;
+export type ModifyTakaiDocumentLibApi = (id: string, data: ModifyDocumentApiParams) => Promise<any>;
+export type DeleteTakaiDocumentLibApi = (id: string) => Promise<any>;
+export type FetchTakaiDocumentSettingLibApi = (id: string) => Promise<any>;
+export type ModifyTakaiDocumentSettingLibApi = (id: string, data: ModifyDocumentSettingApiParams) => Promise<any>;
+export type FetchTakaiSliceListApi = (data: FetchSliceListApiParams) => Promise<any>;
+export type deleteTakaiSliceLibApi = (sliceId: string, knowledgeId: string, documentId: string) => Promise<any>;
+export type FetchTakaiSliceDetailLibApi = (sliceId: string, knowledgeId: string) => Promise<any>;
+export type modifyTakaiSliceInfoLibApi = (data: addAndModifySliceApiParams) => Promise<any>;
+export type FetchTakaiChatHistoryListApi = (data: FetchChatHistoryListApiParams) => Promise<any>;
+export type ExportTakaiChatHistoryApi = (id: string) => Promise<any>;
+export type FetchTakaiApplicationListApi = (userId: string) => Promise<any>;
+export type addTakaiSliceLibApi = (data: addAndModifySliceApiParams) => Promise<any>;
+export type FetchTakaiAppTypeListApi = (dictType: string) => Promise<any>;
+export type FetchUserInfoApi = (userId?: string) => Promise<any>;
+export type FetchAuditInfoLibDetailApi = (documentId: string) => Promise<any>;
+export type FetchTakaiAuditConfigLibListApi = (data: FetchAuditConfigLibListApiParams) => Promise<any>;
+export type ModifyTakaiAuditDocumentLibApi = (id: string, data: ModifyDocumentApiParams) => Promise<any>;
+export type AuditTakaiApplicationApi = (appId: string, userId: string) => Promise<any>;
+export type FetchTakaiProjectApi = () => Promise<any>;
+export type FetchUserListApi = (data: any) => Promise<any>;
+export type ExportKnowledgeSliceExport = (knowledgeId: any) => Promise<any>;
+export type exportDocumentSliceExport = (lis:String[]) => Promise<any>;
+export type exportDocumentExport = (lis:String[]) => Promise<any>;
+export type setCollectApi = (appId:string) => Promise<any>;
+
+
+// token联登校验
+const checkTokenApi: CheckTokenApi = async (token) => {
+    return api.get(`/auth/checkToken/${token}`);
+};
+
+// 建科登录
+const jkloginApi: JkLoginApi = async (data) => {
+    return api.post('/jk_code_login', data);
+};
+
+// 登录 prod-api/admin/login
+const loginApi: LoginApi = async (data) => {
+    // return api.post('-captchaImage/dev-api/admin/login', data);
+    return api.post('/auth/login', data,{
+        headers:{
+            isEncrypt:true
+        }
+    });
+};
+// 验证码 prod-api/captchaImage
+const captchaImage = async () => {
+    const url = '/auth/code';
+    return api.get(url, {});
+};
+
+// 登出
+const logoutApi: LogoutApi = async () => {
+    return api.post('/auth/logout');
+};
+
+// 获取应用列表
+const fetchAppListApi: FetchAppListApi = async (data) => {
+    return api.post('/bigmodel/api/getApplicationList', data);
+};
+
+// 获取知识库列表
+const fetchKnowledgeLibListApi: FetchKnowledgeLibListApi = async (data) => {
+    return api.post('bigmodel/api/knowledgeList', data);
+};
+
+// 获取向量化模型列表
+const fetchEmbeddingListApi: FetchEmbeddingListApi = async () => {
+    return api.get('bigmodel/api/embedding');
+};
+
+// 创建知识库
+const createKnowledgeLibApi: CreateKnowledgeLibApi = async (data) => {
+    return api.post('bigmodel/api/createKnowledge', data);
+};
+
+// 修改知识库
+const modifyKnowledgeLibApi: ModifyKnowledgeLibApi = async (knowledgeId, data) => {
+    return api.put(`bigmodel/api/updateKnowledge/${knowledgeId}`, data);
+};
+
+// 删除知识库
+const deleteKnowledgeLibApi: DeleteKnowledgeLibApi = async (knowledgeId) => {
+    return api.delete(`bigmodel/api/delKnowledge/${knowledgeId}`);
+};
+
+// 获取知识库详情
+const fetchKnowledgeLibDetailApi: FetchKnowledgeLibDetailApi = async (knowledgeId) => {
+    return api.get(`bigmodel/api/detailKnowledge/${knowledgeId}`);
+};
+
+// 获取首页信息
+const fetchIndexApi: FetchAppIndexApi = async (data) => {
+    return api.post('/bigmodel/api/index', data);
+};
+
+// 获取应用详情
+const fetchApplicationDetailApi: FetchApplicationDetailApi = async (appId) => {
+    return api.get(`bigmodel/api/selectApplication/${appId}`);
+};
+
+// 模型列表
+const fetchModelListApi: FetchModelListApi = async () => {
+    return api.get('/bigmodel/api/model/list');
+};
+
+// 知识库列表
+const fetchKnowledgeListApi: FetchKnowledgeApiListApi = async () => {
+    // return api.get('/bigmodel/api/applicationList');
+    return api.get('/bigmodel/api/knowledgeList');
+};
+
+// 编辑应用
+const modifyApplicationLibApi: ModifyApplicationLibApi = async (appId, data) => {
+    return api.put(`bigmodel/api/updateApplication/${appId}`, data);
+};
+
+// 删除应用
+const deleteApplicationLibApi: DeleteApplicationLibApi = async (appId) => {
+    return api.delete(`bigmodel/api/delApplication/${appId}`);
+};
+
+// 创建应用
+const createApplicationLibApi: CreateApplicationLibApi = async (data) => {
+    return api.post('bigmodel/api/createApplication', data);
+};
+
+// 上传知识文件
+const uploadFileLibApi: uploadFileLibApi = async (konwledgeId) => {
+    return api.post(`bigmodel/api/uploadDocument/${konwledgeId}`);
+};
+
+// 获取知识列表
+const fetchDocumentLibListApi: FetchDocumentLibListApi = async (data) => {
+    return api.post('bigmodel/api/documentList', data);
+};
+
+// 知识详情
+const fetchDocumentLibApi: FetchDocumentLibApi = async (id) => {
+    return api.get(`bigmodel/api/documentDetail/${id}`);
+};
+
+// 修改知识
+const modifyDocumentApi: ModifyDocumentLibApi = async (id, data) => {
+    return api.put(`bigmodel/api/updateDocument/${id}`, data);
+};
+
+// 删除知识文件
+const deleteDocumentApi: DeleteDocumentLibApi = async (id) => {
+    return api.delete(`bigmodel/api/delDocument/${id}`);
+};
+
+// 获取应用列表
+const fetchApplicationListApi: FetchApplicationListApi = async () => {
+    return api.get('bigmodel/api/application/list');
+};
+
+// 获取聊天记录列表
+const fetchChatHistoryListApi: FetchChatHistoryListApi = async (data) => {
+    return api.post('bigmodel/api/chatHistory/list', data);
+};
+
+// 导出聊天记录
+const exportChatHistoryApi: ExportChatHistoryApi = async (id) => {
+    return api.post(`bigmodel/api/dialog/export/${id}`, {}, { responseType: 'blob' });
+};
+
+// 获取takai应用列表
+const fetchTakaiAppListApi: FetchTakaiAppListApi = async (data) => {
+    return api.post('/deepseek/api/getApplicationList', data);
+};
+// 获取我创建的应用列表 /deepseek/api/getMyApplicationList
+const fetchTakaiMyAppListApi: FetchTakaiMyAppListApi = async (data) => {
+    return api.post('/deepseek/api/getMyApplicationList', data);
+};
+
+// 获取takai应用详情
+const fetchTakaiApplicationDetailApi: FetchTakaiApplicationDetailApi = async (appId) => {
+    return api.get(`/deepseek/api/selectApplication/${appId}`);
+};
+
+// 创建takai应用
+const createTakaiApplicationLibApi: CreateTakaiApplicationLibApi = async (data) => {
+    return api.post('/deepseek/api/createApplication', data);
+};
+
+// 编辑takai应用
+const modifyTakaiApplicationLibApi: ModifyTakaiApplicationLibApi = async (appId, data) => {
+    return api.put(`/deepseek/api/updateApplication/${appId}`, data);
+};
+
+// 删除takai应用
+const deleteTakaiApplicationLibApi: DeleteTakaiApplicationLibApi = async (appId) => {
+    return api.delete(`/deepseek/api/delApplication/${appId}`);
+};
+
+// 获取首页信息
+const fetchTakaiIndexApi: FetchTakaiAppIndexApi = async (data) => {
+    return api.post('/deepseek/api/index', data);
+};
+
+// takai知识库列表
+const fetchTakaiKnowledgeListApi: FetchTakaiKnowledgeApiListApi = async () => {
+    return api.get('/deepseek/api/knowledgeList');
+};
+
+// 获取takai知识库列表
+const fetchTakaiKnowledgeLibListApi: FetchTakaiKnowledgeLibListApi = async (data) => {
+    return api.post('/deepseek/api/getKnowledgeList', data);
+};
+
+// 获取takai知识库详情
+const fetchTakaiKnowledgeLibDetailApi: FetchTakaiKnowledgeLibDetailApi = async (knowledgeId) => {
+    return api.get(`/deepseek/api/detailKnowledge/${knowledgeId}`);
+};
+
+// 修改takai知识库
+const modifyTakaiKnowledgeLibApi: ModifyTakaiKnowledgeLibApi = async (knowledgeId, data) => {
+    return api.put(`/deepseek/api/updateKnowledge/${knowledgeId}`, data);
+};
+
+// 创建takai知识库
+const createTakaiKnowledgeLibApi: CreateTakaiKnowledgeLibApi = async (data) => {
+    return api.post('/deepseek/api/createKnowledge', data);
+};
+
+// 删除takai知识库
+const deleteTakaiKnowledgeLibApi: DeleteTakaiKnowledgeLibApi = async (knowledgeId) => {
+    return api.delete(`/deepseek/api/delKnowledge/${knowledgeId}`);
+};
+
+// 获取takai知识列表
+const fetchTakaiDocumentLibListApi: FetchTakaiDocumentLibListApi = async (data) => {
+    return api.post('/deepseek/api/documentList', data);
+};
+
+// takai知识详情
+const fetchTakaiDocumentLibApi: FetchTakaiDocumentLibApi = async (id) => {
+    return api.get(`/deepseek/api/documentDetail/${id}`);
+};
+
+// 修改takai知识
+const modifyTakaiDocumentApi: ModifyTakaiDocumentLibApi = async (id, data) => {
+    return api.put(`/deepseek/api/updateDocument/${id}`, data);
+};
+
+// 删除takai知识文件
+const deleteTakaiDocumentApi: DeleteTakaiDocumentLibApi = async (id) => {
+    return api.delete(`/deepseek/api/delDocument/${id}`);
+};
+// 删除takai知识文件--delUnfinishedDocument
+const deleteTakaidelUnfinishedDocumentApi: DeleteTakaiDocumentLibApi = async (id) => {
+    return api.delete(`/deepseek/api/delUnfinishedDocument/${id}`);
+};
+
+// takai知识配置详情
+const fetchTakaiDocumentSettingLibApi: FetchTakaiDocumentSettingLibApi = async (id) => {
+    return api.get(`/deepseek/api/documentSetting/${id}`);
+};
+
+// 修改takai知识配置
+const modifyTakaiDocumentSettingApi: ModifyTakaiDocumentSettingLibApi = async (id, data) => {
+    return api.put(`/deepseek/api/updateDocumentSetting/${id}`, data);
+};
+
+// 获取takai切片列表
+const fetchTakaiSliceListApi: FetchTakaiSliceListApi = async (data) => {
+    return api.post(`/deepseek/api/getSliceList`, data);
+};
+
+// 删除切片
+const deleteTakaiSliceApi: deleteTakaiSliceLibApi = async (sliceId, knowledgeId, documentId) => {
+    return api.delete(`/deepseek/api/deleteSlice/${sliceId}/${knowledgeId}/${documentId}`);
+};
+
+// 获取takai切片详情
+const fetchTakaiSliceDetailApi: FetchTakaiSliceDetailLibApi = async (sliceId, knowledgeId) => {
+    return api.get(`/deepseek/api/getSliceDetail/${sliceId}/${knowledgeId}`);
+};
+
+// 修改takai切片详情
+const modifyTakaiSliceInfoApi: modifyTakaiSliceInfoLibApi = async (data) => {
+    return api.put(`/deepseek/api/updateSliceInfo/`, data);
+};
+
+// 获取takai聊天记录列表
+const fetchTakaiChatHistoryListApi: FetchTakaiChatHistoryListApi = async (data) => {
+    return api.post('/deepseek/api/chatHistory/list', data);
+};
+
+// 导出takai聊天记录
+const exportTakaiChatHistoryApi: ExportTakaiChatHistoryApi = async (id) => {
+    return api.post(`/deepseek/api/dialog/export/${id}`, {}, { responseType: 'blob' });
+};
+
+// 获取takai应用列表 (下拉框)
+const fetchTakaiApplicationListApi: FetchTakaiApplicationListApi = async (userId) => {
+    return api.get('/deepseek/api/application/list/' + userId);
+};
+
+// 新增takai切片
+const addTakaiSliceApi: addTakaiSliceLibApi = async (data) => {
+    return api.post(`/deepseek/api/add/slice/`, data);
+};
+
+// takai应用类型列表
+const fetchTakaiAppTypeListApi: FetchTakaiAppTypeListApi = async (dictType) => {
+    return api.get(`/deepseek/api/${dictType}`);
+};
+
+const fetchUserInfoApi: FetchUserInfoApi = async () => {
+    return api.get(`/system/user/getInfo`);
+};
+const fetchAuditInfoLibDetailApi: FetchAuditInfoLibDetailApi = async (documentId) => {
+    return api.get(`/system/info/all/${documentId}`);
+};
+
+
+const fetchTakaiAuditConfigLibListApi: FetchTakaiAuditConfigLibListApi = async (data) => {
+    return api.post('/deepseek/api/app/audit/list', data);
+};
+
+// 修改takai知识审核
+const modifyTakaiAuditDocumentApi: ModifyTakaiAuditDocumentLibApi = async (id, data) => {
+    return api.put(`/deepseek/api/updateDocumentAudit/${id}`, data);
+};
+
+const auditTakaiApplicationApi: AuditTakaiApplicationApi = async (appId, userId) => {
+    return api.put(`/deepseek/api/audit/${appId}/${userId}`);
+};
+
+const fetchTakaiProjectApi: FetchTakaiProjectApi = async () => {
+    return api.get(`/system/project/alllist?pageNum=1&pageSize=1000`);
+};
+// /system/user/appVipList   用户列表信息
+const fetchUserListApi: FetchUserListApi = async (data: any) => {
+    return api.get(`/system/user/appVipList?pageNum=${data.pageNum}&pageSize=${data.pageSize}&userName=${data.userName}&nickName=${data.nickName}&userType=${data.userType}`);
+}
+// start 建科新的APi
+// 获取租户列表
+const getTenantListApi = async (isToken: boolean) => {
+    return api({
+        url: '/auth/tenant/list',
+        headers: {
+            isToken: isToken
+        },
+        method: 'get'
+    });
+}
+// 提交知识文件
+const uploadDocumentApi: uploadFileLibApi = async (konwledgeId,data) => {
+    return api.post(`/deepseek/api/uploadDocument/${konwledgeId}`,data);
+};
+// 下载知识库文件----deepseek/api/knowledgeSliceExport/{{knowledgeId}}
+const exportKnowledgeSliceExport:ExportKnowledgeSliceExport = async (knowledgeId) => {
+    return api.post(`/deepseek/api/knowledgeSliceExport/${knowledgeId}`, {}, { responseType: 'blob' });
+};
+// 中断 SSE请求 /resource/sse/close
+const getSseclose = async () => {
+    return api({
+        url: '/resource/sse/close',
+        method: 'get'
+    });
+}
+// http://localhost:8080/deepseek/api/documentSliceExport  参数List<String> documentIds; 切片导出
+const exportDocumentSliceExport:exportDocumentSliceExport = async (lis) => {
+    return api.post(`/deepseek/api/documentSliceExport`, {
+        documentIds:lis
+    }, { responseType: 'blob' });
+};
+// http://localhost:8080/deepseek/api/documentExport  参数List<String> documentIds; 文件导出
+const exportDocumentExport:exportDocumentExport = async (lis) => {
+    return api.post(`/deepseek/api/documentExport`, {
+        documentIds:lis
+    }, { responseType: 'blob' });
+};
+// deepseek/api/pdfStream 下载PDF
+const exportPdfStream:exportDocumentExport = async (lis) => {
+    return api.post(`/deepseek/api/pdfStream`, {
+        documentIds:lis
+    }, { responseType: 'blob' });
+};
+// /deepseek/api/getSliceListByDocumentId/{{documentId}} 获取切片列表
+const getSliceListByDocumentId = async (documentId:string)=>{
+    return api({
+        url: `/deepseek/api/getSliceListByDocumentId/${documentId}`,
+        method: 'get'
+    });
+}
+
+// POST http://localhost:8080/deepseek/api/sliceDocumentList 获取文档列表 参数name
+const sliceDocumentList = async (data:any)=>{
+    return api.post(`/deepseek/api/sliceDocumentList`, data);
+};
+// deepseek/api/quoteDocumentList 获取引用文档列表 参数 knowledge_id,knowledgeType(类型)
+const getQuoteDocumentList = async (data:any)=>{
+    // return api.post(`/deepseek/api/quoteDocumentList`, data);
+    return api({
+        url: `/deepseek/api/quoteDocumentList`,
+        method: 'post',
+        data
+    });
+};
+// deepseek/api/importDocumentList 获取引用文档列表 参数 documentIds knowledgeId(类型)
+const importDocumentList = async (data:any)=>{
+    return api.post(`/deepseek/api/importDocumentList`, data);
+};
+// /deepseek/api/uploadSliceImage/${params.knowledgeId}/${params.documentId}
+const uploadSliceImage = async (params:any,data:any)=>{
+    return api.post(`/deepseek/api/uploadSliceImage/${params.knowledgeId}/${params.documentId}`, data);
+};
+// PUT http://localhost:8080/deepseek/api/updateSliceInfo 修改切片 
+const setupdateSliceInfo = async (data:any) => {
+    return api.put(`/deepseek/api/updateSliceInfo`, data);
+};
+// POST http://localhost:8080/deepseek/api/add/slice 新增切片
+const addSlice = async (data:any) => {
+    return api.post(`/deepseek/api/add/slice`, data);
+};
+// PUT http://localhost:8080/deepseek/api/updateSliceInfoList 提交--全部提交
+const updateSliceInfoList = async (data:any) => {
+    return api.put(`/deepseek/api/updateSliceInfoList`, data);
+};
+// GET http://localhost:8080/deepseek/api/getOldSliceListByDocumentId/{{documentId}} 获取初始模板切片
+const getOldSliceListByDocumentId = async (documentId:string)=>{
+    return api({
+        url: `/deepseek/api/getOldSliceListByDocumentId/${documentId}`,
+        method: 'get'
+    });
+}
+// deepseek/api/knowledgeMarkDownFileExport/{{knowledgeId}} 下载知识库MarkDown文件
+const exportKnowledgeMarkDown:ExportKnowledgeSliceExport = async (knowledgeId:string) => {
+    return api.post(`/deepseek/api/knowledgeMarkDownFileExport/${knowledgeId}`, {},{ responseType: 'blob' });
+};
+// POST http://localhost:8080/deepseek/api/knowledgeFileExport/{{knowledgeId}} 下载知识库原文档
+const exportKnowledgeFile:ExportKnowledgeSliceExport = async (knowledgeId:string) => {
+    return api.post(`/deepseek/api/knowledgeFileExport/${knowledgeId}`, {},{ responseType: 'blob' });
+};
+// POST http://localhost:8080/deepseek/api/documentFileExport 文档列表下载文档原文件
+const documentFileExport:exportDocumentExport = async (lis) => {
+    return api.post(`/deepseek/api/documentFileExport`, {
+        documentIds:lis
+    }, { responseType: 'blob' });
+};
+// POST http://localhost:9080/deepseek/api/app/collect 我的收藏
+const setCollectApi:setCollectApi = async (appId:string) => {
+    console.log("appId",appId);
+    return api.post(`/deepseek/api/app/collect`,{
+        appId:appId
+    });
+}
+// DELETE http://localhost:9080/deepseek/api/app/collect/{appId}
+export const delCollectApi:setCollectApi = async (appId:string) => {
+    return api.delete(`/deepseek/api/app/collect/${appId}`);
+};
+// 获取预设问题列表  '/deepseek/api/presets'; get请求
+const getPresets = async (appId:string) => {
+    return api({
+        url: `/deepseek/api/presets/${appId}`,
+        method: 'get'
+    });
+}
+// DELETE http://localhost:9080/resource/oss/{ossIds} 批量删除oss文件
+export const deleteOssFileApi = async (ossIds: string) => {
+    return api.delete(`/resource/oss/${ossIds}`);
+};
+// deepseek/revise/pageList 知识库修订工具列表
+export const fetchReviseToolList = async (data: any) => {
+    return api.get('/deepseek/revise/pageList', { params: data });
+}
+// deepseek/revise/list 知识库修订工具列表不分页 
+// String documentName,String sliceText,String documentId,String knowledgeId
+export const fetchReviseToolAllList = async (data: any) => {
+    return api.get('/deepseek/revise/list', { params: data });
+}
+// deepseek/revise/sliceList 知识库修订工具切片列表 String sliceText, String documentId
+export const fetchReviseToolSliceList = async (data: any) => {
+    return api.get('/deepseek/revise/sliceList', { params: data });
+}
+// revision_status.  ---- 0 未修订 1 已修订
+// http://localhost:8080/deepseek/revise/reviseSlice  提交修订知识切片private String sliceId;
+// private String refSliceId;
+// private String revisionStatus;
+export const submitReviseSliceApi = async (data: any) => {
+    return api.put('/deepseek/revise/reviseSlice', data);
+};
+// http://localhost:8080/deepseek/api/document/checkFile 检查文件是否存在
+export const checkFileApi = async (data: any) => {
+    return api.post('/deepseek/api/document/checkFile', data);
+}
+// deepseek/api/getMarkDodnSliceByDocumentId/eb2f685c-451e-4252-b04c-bdc07au9969j 获取MarkDown切片列表
+export const getMarkDodnSliceByDocumentId = async (documentId:string)=>{
+    return api({
+        url: `/deepseek/api/getMarkDodnSliceByDocumentId/${documentId}`,
+        method: 'get'
+    });
+}
+// deepseek/revise/reviseHistoryList 知识库修订历史记录列表 String knowledgeId,String knowledgeName,String documentName,String refDocumentName
+export const fetchReviseHistoryList = async (data: any) => { 
+    return api.get('/deepseek/revise/reviseHistoryList', { params: data });
+}
+// /deepseek/dataset/datsetExport  数据集导出
+export const datasetExportApi = async (data: any) => {
+    return api.post('/deepseek/dataset/datsetExport', data, { responseType: 'blob' });
+};
+// POST http://localhost:8080/deepseek/dataset/create 创建数据集 private String name;
+// private String description;
+// private Long ossId;
+// private String url;
+export const createDatasetApi = async (data: any) => {
+    return api.post('/deepseek/dataset/create', data);
+};
+// http://localhost:8080/deepseek/dataset/pageList 数据集列表 --String name,String createBy,PageQuery pageQuery
+export const fetchDatasetList = async (data: any) => { 
+    return api.get('/deepseek/dataset/pageList', { params: data });
+}
+// DELETE http://localhost:8080/deepseek/dataset/delete/{{id}} 删除数据集
+export const deleteDatasetApi = async (id: string) => {
+    return api.delete(`/deepseek/dataset/delete/${id}`);
+};
+// GET http://localhost:8080/deepseek/dataset/list 数据集下拉框列表
+export const fetchDatasetSelectList = async (data: any) => {
+    return api.get('/deepseek/dataset/list', { params: data });
+};
+// POST http://localhost:8080/deepseek/evaluation/create 创建评测
+export const createEvaluationApi = async (data: any) => {
+    return api.post('/deepseek/evaluation/create', data);
+};
+// GET http://localhost:8080/deepseek/evaluation/pageList       String name, PageQuery pageQuery
+export const fetchEvaluationList = async (data: any) => { 
+    return api.get('/deepseek/evaluation/pageList', { params: data });
+}
+// DELETE http://localhost:8080/deepseek/evaluation/delete/{{taskId}} 删除评测
+export const deleteEvaluationApi = async (taskId: string) => {
+    return api.delete(`/deepseek/evaluation/delete/${taskId}`);
+};
+// /deepseek/api/editMarkDownFile private String knowledgeId; private String documentId;private String markDownText;
+
+export const editMarkDownFileApi = async (data: any) => {
+    return api.put('/deepseek/api/editMarkDownFile', data);
+}
+// GET http://localhost:8080/system/menu/getClientRouters 获取前端路由
+export const fetchClientRouters = async () => {
+    return api.get('/system/menu/getClientRouters');
+};
+// POST http://localhost:8080/deepseek/evaluation/taskBegin 开始评测
+export const beginEvaluationApi = async (data: any) => {
+    return api.post('/deepseek/evaluation/taskBegin', data);
+};
+// GET http://localhost:8080/system/tenant/getTenantSize
+export const getTenantSize = async ()=>{
+    return api.get('/system/tenant/getTenantSize');
+}
+// http://localhost:8080/deepseek/api/app/auditHistory/list
+export const fetchAuditHistoryList = async (data: any) => { 
+    return api.post('/deepseek/api/app/auditHistory/list', { data: data });
+}
+// POST http://localhost:8080/deepseek/api/document/checkQuoteFile 检查引用文件是否存在
+export const checkQuoteFileApi = async (data: any) => {
+    return api.post('/deepseek/api/document/checkQuoteFile', data);
+};
+// DELETE http://localhost:8080/deepseek/api/deleteSliceList/{{knowledgeId}}/{{documentId}}
+export const deleteSliceListApi = async (knowledgeId:any,documentId:any, data: any) => {
+    return api.delete(`/deepseek/api/deleteSliceList/${knowledgeId}/${documentId}`,{
+        data:data
+    });
+}
+// http://localhost/dev-api/system/modelConfig/rerankList?modelType=1 获取重排模型列表
+export const fetchRerankModelList = async () => {
+    return api.get('/system/modelConfig/rerankList',{
+        params:{
+            modelType:1
+        }
+    });
+}
+// GET http://localhost:8080/system/taskHistory/list 获取评测历史列表
+export const fetchTaskHistoryList = async (data: any) => {
+    return api.get('/system/taskHistory/list',{
+        params:{
+            ...data
+        }
+    });
+}
+// GET http://localhost:8080/deepseek/overview/topData 头上面
+export const fetchTopData = async () => {
+    return api.get('/deepseek/overview/topData');
+}
+
+// GET http://localhost:8080/deepseek/overview/onlineUserData 活跃用户
+export const fetchOnlineUserData = async (data: any) => {
+    return api.get('/deepseek/overview/onlineUserData',{
+        params:{
+            ...data
+        }
+    });
+}
+
+// GET http://localhost:8080/deepseek/overview/conversationData 会话
+export const fetchConversationData = async (data: any) => {
+    return api.get('/deepseek/overview/conversationData',{
+        params:{
+            ...data
+        }
+    });
+}
+
+// GET http://localhost:8080/deepseek/overview/conversationDetailData 互动
+export const fetchConversationDetailData = async (data: any) => {
+    return api.get('/deepseek/overview/conversationDetailData',{
+        params:{
+            ...data
+        }
+    });
+}
+
+// GET http://localhost:8080/deepseek/overview/overviewTokenData token输出
+export const fetchOverviewTokenData = async (data: any) => {
+    return api.get('/deepseek/overview/overviewTokenData',{
+        params:{
+            ...data
+        }
+    });
+}
+
+// GET http://localhost:8080/deepseek/overview/overviewAppData RAG应用列表
+export const fetchOverviewAppData = async (data: any) => {
+    return api.get('/deepseek/overview/overviewAppData',{
+        params:{
+            ...data
+        }
+    });
+}
+// GET http://localhost:8080/deepseek/overview/overviewAppDetailData RAG应用明细
+export const fetchOverviewAppDetailData = async (data: any) => {
+    return api.get('/deepseek/overview/overviewAppDetailData',{
+        params:{
+            ...data
+        }
+    });
+}
+
+// GET http://localhost:8080/deepseek/overview/overviewKnowledgeData 知识库列表
+export const fetchOverviewKnowledgeData = async (data: any) => {
+    return api.get('/deepseek/overview/overviewKnowledgeData',{
+        params:{
+            ...data
+        }
+    });
+}
+// DELETE http://localhost:8080/deepseek/api/deleteSlice/{{sliceId}}/{{knowledgeId}}/{{documentId}}
+
+// end 建科新的APi
+
+export const apis = {
+    checkToken: checkTokenApi,
+    jklogin: jkloginApi,
+    login: loginApi,
+    captchaImage: captchaImage,
+    logout: logoutApi,
+    fetchAppList: fetchAppListApi,
+    fetchKnowledgeLibList: fetchKnowledgeLibListApi,
+    fetchEmbeddingList: fetchEmbeddingListApi,
+    createKnowledgeLib: createKnowledgeLibApi,
+    modifyKnowledgeLib: modifyKnowledgeLibApi,
+    deleteKnowledgeLib: deleteKnowledgeLibApi,
+    fetchKnowledgeLibDetail: fetchKnowledgeLibDetailApi,
+    fetchIndexCount: fetchIndexApi,
+    fetchApplicationDetail: fetchApplicationDetailApi,
+    fetchModelList: fetchModelListApi,
+    fetchKnowledgeList: fetchKnowledgeListApi,
+    modifyApplicationApi: modifyApplicationLibApi,
+    deleteApplicationApi: deleteApplicationLibApi,
+    createApplicationApi: createApplicationLibApi,
+    uploadFileLibApi: uploadFileLibApi,
+    fetchDocumentLibListApi: fetchDocumentLibListApi,
+    fetchDocumentDetailLibApi: fetchDocumentLibApi,
+    modifyDocumentLibApi: modifyDocumentApi,
+    deleteDocumentLibApi: deleteDocumentApi,
+    fetchApplicationList: fetchApplicationListApi,
+    fetchChatHistoryList: fetchChatHistoryListApi,
+    exportChatHistory: exportChatHistoryApi,
+    fetchTakaiAppList: fetchTakaiAppListApi,
+    fetchTakaiApplicationDetail: fetchTakaiApplicationDetailApi,
+    createTakaiApplicationApi: createTakaiApplicationLibApi,
+    modifyTakaiApplicationApi: modifyTakaiApplicationLibApi,
+    deleteTakaiApplicationApi: deleteTakaiApplicationLibApi,
+    fetchTakaiIndexCount: fetchTakaiIndexApi,
+    fetchTakaiKnowledgeList: fetchTakaiKnowledgeListApi,
+    fetchTakaiKnowledgeLibList: fetchTakaiKnowledgeLibListApi,
+    fetchTakaiKnowledgeLibDetail: fetchTakaiKnowledgeLibDetailApi,
+    modifyTakaiKnowledgeLib: modifyTakaiKnowledgeLibApi,
+    createTakaiKnowledgeLib: createTakaiKnowledgeLibApi,
+    deleteTakaiKnowledgeLib: deleteTakaiKnowledgeLibApi,
+    fetchTakaiDocumentLibListApi: fetchTakaiDocumentLibListApi,
+    fetchTakaiDocumentDetailLibApi: fetchTakaiDocumentLibApi,
+    modifyTakaiDocumentLibApi: modifyTakaiDocumentApi,
+    deleteTakaiDocumentLibApi: deleteTakaiDocumentApi,
+    deleteTakaidelUnfinishedDocumentLibApi: deleteTakaidelUnfinishedDocumentApi,
+    fetchTakaiDocumentSettingLibApi: fetchTakaiDocumentSettingLibApi,
+    modifyTakaiDocumentSettingLibApi: modifyTakaiDocumentSettingApi,
+    fetchTakaiSliceList: fetchTakaiSliceListApi,
+    deleteTakaiSlice: deleteTakaiSliceApi,
+    fetchTakaiSliceDetail: fetchTakaiSliceDetailApi,
+    modifyTakaiSliceInfo: modifyTakaiSliceInfoApi,
+    fetchTakaiChatHistoryList: fetchTakaiChatHistoryListApi,
+    exportTakaiChatHistory: exportTakaiChatHistoryApi,
+    fetchTakaiApplicationList: fetchTakaiApplicationListApi,
+    addTakaiSlice: addTakaiSliceApi,
+    fetchTakaiAppTypeList: fetchTakaiAppTypeListApi,
+    fetchUserInfo: fetchUserInfoApi,
+    fetchAuditInfoLibDetail: fetchAuditInfoLibDetailApi,
+    fetchTakaiAuditConfigLibList: fetchTakaiAuditConfigLibListApi,
+    modifyTakaiAuditDocumentLibApi: modifyTakaiAuditDocumentApi,
+    auditTakaiApplicationLibApi: auditTakaiApplicationApi,
+    fetchTakaiProjectLibApi: fetchTakaiProjectApi,
+    fetchUserListApi: fetchUserListApi,
+    // start 建科新的APi
+    getTenantList:getTenantListApi,
+    uploadDocumentApi:uploadDocumentApi,
+    exportKnowledgeSliceExport:exportKnowledgeSliceExport,
+    getSseclose:getSseclose,
+    exportDocumentSliceExport:exportDocumentSliceExport,
+    exportDocumentExport:exportDocumentExport,
+    getSliceListByDocumentId:getSliceListByDocumentId,
+    sliceDocumentList:sliceDocumentList,
+    exportPdfStream:exportPdfStream,
+    getQuoteDocumentList:getQuoteDocumentList,
+    importDocumentList:importDocumentList,
+    uploadSliceImage:uploadSliceImage,
+    setupdateSliceInfo:setupdateSliceInfo,
+    addSlice:addSlice,
+    updateSliceInfoList:updateSliceInfoList,
+    getOldSliceListByDocumentId:getOldSliceListByDocumentId,
+    exportKnowledgeMarkDown:exportKnowledgeMarkDown,
+    exportKnowledgeFile:exportKnowledgeFile,
+    documentFileExport:documentFileExport,
+    fetchTakaiMyAppListApi:fetchTakaiMyAppListApi,
+    setCollectApi:setCollectApi,
+    delCollectApi:delCollectApi,
+    getPresets:getPresets,
+    deleteOssFileApi:deleteOssFileApi,
+    fetchReviseToolList:fetchReviseToolList,
+    fetchReviseToolAllList:fetchReviseToolAllList,
+    fetchReviseToolSliceList:fetchReviseToolSliceList,
+    checkFileApi:checkFileApi,
+    getMarkDodnSliceByDocumentId:getMarkDodnSliceByDocumentId,
+    datasetExportApi:datasetExportApi,
+    createDatasetApi:createDatasetApi,
+    deleteDatasetApi:deleteDatasetApi,
+    fetchDatasetSelectList:fetchDatasetSelectList,
+    createEvaluationApi:createEvaluationApi,
+    fetchEvaluationList:fetchEvaluationList,
+    deleteEvaluationApi:deleteEvaluationApi,
+    editMarkDownFileApi:editMarkDownFileApi,
+    fetchClientRouters:fetchClientRouters,
+    beginEvaluationApi:beginEvaluationApi,
+    getTenantSize:getTenantSize,
+    fetchAuditHistoryList:fetchAuditHistoryList,
+    checkQuoteFileApi:checkQuoteFileApi,
+    deleteSliceListApi:deleteSliceListApi,
+    fetchRerankModelList:fetchRerankModelList,
+    fetchTaskHistoryList:fetchTaskHistoryList,
+    fetchTopData:fetchTopData,
+    fetchOnlineUserData:fetchOnlineUserData,
+    fetchConversationData:fetchConversationData,
+    fetchConversationDetailData:fetchConversationDetailData,
+    fetchOverviewTokenData:fetchOverviewTokenData
+    // end 建科新的APi
+};

BIN
src/assets/login/background.jpg


Datei-Diff unterdrückt, da er zu groß ist
+ 24 - 0
src/assets/pdf.worker.min.js


BIN
src/assets/public/aiIcon.png


BIN
src/assets/public/aiwj.png


BIN
src/assets/public/avatar.png


BIN
src/assets/public/bg1.png


BIN
src/assets/public/bg2.png


Datei-Diff unterdrückt, da er zu groß ist
+ 22 - 0
src/assets/public/dllogo.svg


BIN
src/assets/public/favicon.ico


Datei-Diff unterdrückt, da er zu groß ist
+ 5 - 0
src/assets/public/icon.svg


BIN
src/assets/public/logo.png


Datei-Diff unterdrückt, da er zu groß ist
+ 22 - 0
src/assets/public/logo.svg


BIN
src/assets/public/logo1.png


BIN
src/assets/public/model.png


BIN
src/assets/public/notFound.png


BIN
src/assets/public/rfq.png


BIN
src/assets/public/tubing.png


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
src/assets/public/z-duoban.svg


+ 1 - 0
src/assets/public/z-hebing.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765529304349" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11179" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M682.667 970.667a32 32 0 0 1-22.614-9.387L512 813.227 363.947 961.28a32 32 0 0 1-45.227-45.227l170.667-170.666a32 32 0 0 1 45.226 0L705.28 916.053a32 32 0 0 1-22.613 54.614zM512 288a32 32 0 0 1-22.613-9.387L318.72 107.947a32 32 0 0 1 45.227-45.227L512 210.773 660.053 62.72a32 32 0 0 1 45.227 45.227L534.613 278.613A32 32 0 0 1 512 288z m384 384H128a74.667 74.667 0 0 1-74.667-74.667V426.667A74.667 74.667 0 0 1 128 352h768a74.667 74.667 0 0 1 74.667 74.667v170.666A74.667 74.667 0 0 1 896 672zM128 416a10.667 10.667 0 0 0-10.667 10.667v170.666A10.667 10.667 0 0 0 128 608h768a10.667 10.667 0 0 0 10.667-10.667V426.667A10.667 10.667 0 0 0 896 416z" p-id="11180" fill="#1296db"></path></svg>

+ 1 - 0
src/assets/public/z-huifu.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765529087732" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4190" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M841.8 313.2c-25.9-34.5-56.8-64.6-92-89.5-35.7-25.2-74.8-44.5-116.4-57.3-33.7-10.4-68.7-16.4-104.3-17.9V51.9L400.9 180.1l128.3 128.3v-95.9c29.1 1.4 57.7 6.4 85.4 15C761.4 272.7 860 406.4 860 560.1c0 191.9-156.1 348-348 348S164 752 164 560.1c0-37.7 6-74.8 17.8-110.1 5.6-16.8-3.5-34.9-20.2-40.5-16.8-5.6-34.9 3.5-40.5 20.2-14 41.9-21 85.7-21 130.3 0 55.6 10.9 109.6 32.4 160.4 20.8 49.1 50.5 93.1 88.3 130.9 37.8 37.8 81.9 67.5 130.9 88.3 50.8 21.5 104.8 32.4 160.4 32.4s109.6-10.9 160.4-32.4c49.1-20.8 93.1-50.5 130.9-88.3 37.8-37.8 67.5-81.9 88.3-130.9 21.5-50.8 32.4-104.8 32.4-160.4-0.1-89.7-28.5-175.1-82.3-246.8z" fill="#1296db" p-id="4191"></path><path d="M622.8 555.1c0-61.2-49.6-110.8-110.8-110.8S401.2 494 401.2 555.1 450.8 666 512 666s110.8-49.7 110.8-110.9z" fill="#1296db" p-id="4192"></path></svg>

+ 1 - 0
src/assets/public/z-jiexi.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765529170661" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6443" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M576 928H192c-52.992 0-96-43.093333-96-96V192c0-52.992 43.093333-96 96-96h640c52.992 0 96 43.093333 96 96v384.064c0 17.706667-14.293333 32-32 32s-32-14.293333-32-32V192.021333c0-17.706667-14.4-32-32-32H192c-17.706667 0-32 14.378667-32 32v639.957334c0 17.706667 14.4 32 32 32h384c17.706667 0 32 14.314667 32 32 0 17.706667-14.293333 32.021333-32 32.021333zM128 693.312a32.064 32.064 0 0 1-22.613333-54.698667l159.402666-159.338666a95.786667 95.786667 0 0 1 110.72-17.984l173.589334 86.805333c12.309333 6.186667 27.093333 3.797333 36.8-5.994667l287.402666-287.445333a32.042667 32.042667 0 0 1 45.290667 45.312L631.210667 587.392a95.786667 95.786667 0 0 1-110.72 18.005333l-173.589334-86.826666a31.616 31.616 0 0 0-36.8 6.016l-159.509333 159.317333c-6.186667 6.314667-14.4 9.386667-22.592 9.386667z m320-277.376c-52.906667 0-96-43.093333-96-96s43.093333-96.021333 96-96.021333 96 43.093333 96 96-43.093333 96.021333-96 96.021333z m0-128c-17.6 0-32 14.378667-32 32 0 17.6 14.4 32 32 32s32-14.4 32-32c0-17.621333-14.4-32-32-32zM768 928c-17.706667 0-32-14.293333-32-32v-192.021333c0-17.706667 14.293333-32 32-32s32 14.293333 32 32v192c0 17.706667-14.293333 32.021333-32 32.021333z m128-128c-7.893333 0-15.701333-2.922667-21.909333-8.725333L768 691.669333l-106.090667 99.712a31.936 31.936 0 0 1-45.226666-1.408 31.957333 31.957333 0 0 1 1.408-45.205333l112.213333-105.386667A48.554667 48.554667 0 0 1 768 621.44c14.72 0 28.501333 6.613333 37.696 17.92l112.213333 105.386667A31.957333 31.957333 0 0 1 896 800z" fill="#1296db" p-id="6444"></path></svg>

+ 1 - 0
src/assets/public/z-qiefen.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765529259899" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10149" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M774.656 158.805l60.33 60.331a42.667 42.667 0 0 1 0 60.33L684.16 430.337a42.667 42.667 0 0 1-60.373 0l-60.331-60.416a42.667 42.667 0 0 1 0-60.33l150.87-150.827a42.667 42.667 0 0 1 60.33 0z m-150.87 180.992l30.209 30.166L774.656 249.3l-30.165-30.165-120.704 120.661zM219.734 743.893c79.958 42.326 181.334 29.867 248.662-37.504l182.997-182.954a3.712 3.712 0 0 0 0-5.248L533.333 400.128a42.667 42.667 0 0 0-60.373 0L169.088 704.043a1.664 1.664 0 0 0 0 2.346 213.59 213.59 0 0 0 50.261 37.291l0.427 0.213z m283.435-283.392l60.33 60.331-140.373 140.33a147.67 147.67 0 0 1-155.008 34.347l235.051-235.008zM202.667 840.533a32 32 0 0 0 0 64h128a32 32 0 1 0 0-64h-128z m213.333 32a32 32 0 0 1 32-32h128a32 32 0 0 1 0 64H448a32 32 0 0 1-32-32z m278.613-32a32 32 0 0 0 0 64h128a32 32 0 1 0 0-64h-128z" fill="#1296db" p-id="10150"></path></svg>

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
src/assets/public/z-tuozhan.svg


+ 1 - 0
src/assets/public/z-xinzeng.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765529342483" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12202" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M799 702.4H679.1v124.2c0 10.2-8.3 18.5-18.5 18.5h-25.4c-10.2 0-18.5-8.3-18.5-18.5V702.4H496.9c-4.9 0-9.6-2-13.1-5.4-3.5-3.5-5.4-8.2-5.4-13.1v-25.4c0-10.2 8.3-18.5 18.5-18.5h119.9V515.8c0-10.2 8.3-18.5 18.5-18.5h25.4c10.2 0 18.5 8.3 18.5 18.5V640H799c4.9 0 9.6 1.9 13.1 5.4 3.5 3.5 5.4 8.2 5.4 13.1v25.4c0 4.9-2 9.6-5.4 13.1-3.5 3.5-8.2 5.4-13.1 5.4zM308.6 179.6h369.7c81.7 0 147.9 66.2 147.9 147.9v201c0 18-17.6 20.8-17.6 20.8h-14.9c-15.6 0-16.9-21.1-16.9-21.1v-63H247.2v231.9s25.8 94.2 98.5 94.2h165.9s18.8 1.3 18.8 16.8V826c0 17.5-18.1 19-18.1 19H345.7c-81.7 0-147.9-66.2-147.9-147.9V178.9m49.1 48v190.6h532.7v-91c0-87.9-87.3-99.6-87.3-99.6H331.4" fill="#1296db" p-id="12203"></path></svg>

+ 16 - 0
src/components/404/index.tsx

@@ -0,0 +1,16 @@
+import * as React from 'react';
+import notFoundSrc from '@/assets/public/notFound.png';
+import './style.less';
+
+const NotFound: React.FC = () => {
+    return (
+        <div className='notFound'>
+            <img src={notFoundSrc} />
+            <div className='notFound-text'>
+                404!页面走失了~
+            </div>
+        </div>
+    );
+};
+
+export default NotFound;

+ 23 - 0
src/components/404/style.less

@@ -0,0 +1,23 @@
+.notFound {
+    width: 100%;
+    height: 100%;
+    padding-bottom: 30px;
+    background: #FFFFFF;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+
+    img {
+        width: 350px;
+        object-fit: cover;
+        pointer-events: none;
+    }
+
+    &-text {
+        font-size: 16px;
+        font-weight: bold;
+        color: @primary-color;
+        margin-bottom: 20px;
+    }
+}

+ 618 - 0
src/components/chat/index.tsx

@@ -0,0 +1,618 @@
+import React, { useEffect, useRef, useState } from 'react';
+import { Button, GetProp, GetRef, Popover, Space, Spin, Tooltip, message } from 'antd';
+import {
+    CloseOutlined,
+    CloudUploadOutlined,
+    CommentOutlined,
+    OpenAIFilled,
+    PlusOutlined,
+    RedoOutlined,
+    UserOutlined,
+    PaperClipOutlined
+} from '@ant-design/icons';
+import {
+    Attachments,
+    type AttachmentsProps,
+    Bubble,
+    Conversations,
+    Sender,
+    Suggestion,
+    useXAgent,
+    useXChat,
+} from '@ant-design/x';
+import Welcome from './welcome';
+import type { Conversation } from '@ant-design/x/es/conversations';
+import { createStyles } from 'antd-style';
+import dayjs from 'dayjs';
+import ReactMarkdown from 'react-markdown';
+import avatarSrc from '@/assets/public/logo.png';
+
+const useWorkareaStyle = createStyles(({ token, css }) => {
+    return {
+        copilotWrapper: css`
+      height: 100%;
+      display: flex;
+    `,
+        workarea: css`
+      flex: 1;
+      background: ${token.colorBgLayout};
+      display: flex;
+      flex-direction: column;
+    `,
+        workareaHeader: css`
+      box-sizing: border-box;
+      height: 52px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0 48px 0 28px;
+      border-bottom: 1px solid ${token.colorBorder};
+    `,
+        headerTitle: css`
+      font-weight: 600;
+      font-size: 15px;
+      color: ${token.colorText};
+      display: flex;
+      align-items: center;
+      gap: 8px;
+    `,
+        headerButton: css`
+      background-image: linear-gradient(78deg, #8054f2 7%, #3895da 95%);
+      border-radius: 12px;
+      height: 24px;
+      width: 93px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      color: #fff;
+      cursor: pointer;
+      font-size: 12px;
+      font-weight: 600;
+      transition: all 0.3s;
+      &:hover {
+        opacity: 0.8;
+      }
+    `,
+        workareaBody: css`
+      flex: 1;
+      padding: 16px;
+      background: ${token.colorBgContainer};
+      border-radius: 16px;
+      min-height: 0;
+    `,
+        bodyContent: css`
+      overflow: auto;
+      height: 100%;
+      padding-right: 10px;
+    `,
+        bodyText: css`
+      color: ${token.colorText};
+      padding: 8px;
+    `,
+    };
+});
+// createStyles 返回一个 hook,使用 design token 生成样式对象
+const useCopilotStyle = createStyles(({ token, css }) => {
+    return {
+        copilotChat: css`
+      display: flex;
+      flex-direction: column;
+      background: ${token.colorBgContainer};
+      color: ${token.colorText};
+    `,
+        // chatHeader 样式
+        chatHeader: css`
+      height: 52px;
+      box-sizing: border-box;
+      border-bottom: 1px solid ${token.colorBorder};
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0 10px 0 16px;
+    `,
+        headerTitle: css`
+      font-weight: 600;
+      font-size: 15px;
+    `,
+        headerButton: css`
+      font-size: 18px;
+    `,
+        conversations: css`
+      width: 300px;
+      .ant-conversations-list {
+        padding-inline-start: 0;
+      }
+    `,
+        // chatList 样式
+        chatList: css`
+      overflow: auto;
+      padding-block: 16px;
+      flex: 1;
+    `,
+        chatWelcome: css`
+      margin-inline: 16px;
+      padding: 12px 16px;
+      border-radius: 2px 12px 12px 12px;
+      background: ${token.colorBgTextHover};
+      margin-bottom: 16px;
+    `,
+        loadingMessage: css`
+      background-image: linear-gradient(90deg, #ff6b23 0%, #af3cb8 31%, #53b6ff 89%);
+      background-size: 100% 2px;
+      background-repeat: no-repeat;
+      background-position: bottom;
+    `,
+        // chatSend 样式
+        chatSend: css`
+      padding: 12px;
+    `,
+        sendAction: css`
+      display: flex;
+      align-items: center;
+      margin-bottom: 12px;
+      gap: 8px;
+    `,
+        speechButton: css`
+      font-size: 18px;
+      color: ${token.colorText} !important;
+    `,
+    };
+});
+// 消息气泡的数据类型:
+// - role: 消息的角色,通常为 'user' 或 'assistant'
+// - content: 文本内容(可能包含 markdown)
+type BubbleDataType = {
+    role: string;
+    content: string;
+};
+
+// MOCK_SESSION_LIST: 用于展示会话历史(仅示例/初始占位)
+const MOCK_SESSION_LIST = [
+    {
+        key: '5',
+        label: 'New session',
+        group: 'Today',
+    },
+    {
+        key: '4',
+        label: 'What has Ant Design X upgraded?',
+        group: 'Today',
+    },
+    {
+        key: '3',
+        label: 'New AGI Hybrid Interface',
+        group: 'Today',
+    },
+    {
+        key: '2',
+        label: 'How to quickly install and import components?',
+        group: 'Yesterday',
+    },
+    {
+        key: '1',
+        label: 'What is Ant Design X?',
+        group: 'Yesterday',
+    },
+];
+
+// MOCK_SUGGESTIONS: Suggestion 组件的数据来源
+// 用于输入框的快速建议/模板,可包含子菜单和图标
+const MOCK_SUGGESTIONS = [
+    { label: 'Write a report', value: 'report' },
+    { label: 'Draw a picture', value: 'draw' },
+    {
+        label: 'Check some knowledge',
+        value: 'knowledge',
+        icon: <OpenAIFilled />,
+        children: [
+            { label: 'About React', value: 'react' },
+            { label: 'About Ant Design', value: 'antd' },
+        ],
+    },
+];
+
+// 生成中占位文本
+const AGENT_PLACEHOLDER = 'Generating content, please wait...';
+
+// CopilotProps: 组件传入的参数
+// - copilotOpen: 控制 Copilot 是否可见
+// - setCopilotOpen: 切换 Copilot 可见性的回调
+// - appId: 当前应用/会话的上下文 ID,会传给后端
+interface CopilotProps {
+    copilotOpen: boolean;
+    setCopilotOpen: (open: boolean) => void;
+    appId: string,
+    infoDetail: any;
+    saveConfig: () => Promise<boolean>;
+}
+
+const Copilot = (props: CopilotProps) => {
+    const { copilotOpen, setCopilotOpen, infoDetail,saveConfig } = props;
+    const { styles } = useCopilotStyle();
+
+    // Attachments 组件的引用,用于编程式上传文件
+    const attachmentsRef = useRef<GetRef<typeof Attachments>>(null);
+    // 保存当前请求对应的 AbortController,方便取消请求
+    const abortController = useRef<AbortController | null>(null);
+
+    // ==================== State ====================
+
+    const [messageHistory, setMessageHistory] = useState<Record<string, any>>({});
+
+    const [sessionList, setSessionList] = useState<Conversation[]>(MOCK_SESSION_LIST);
+    const [curSession, setCurSession] = useState(sessionList[0].key);
+
+    const [attachmentsOpen, setAttachmentsOpen] = useState(false);
+    const [files, setFiles] = useState<GetProp<AttachmentsProps, 'items'>>([]);
+
+    const [inputValue, setInputValue] = useState('');
+
+    // useXAgent 用于创建一个可复用的请求代理(agent)
+    // 可以在这里统一传入 baseURL、headers(比如 Authorization: Bearer <token>)
+    // 例如:useXAgent({ baseURL, headers: { Authorization: `Bearer ${token}` } })
+    const [agent] = useXAgent<BubbleDataType>({
+        // baseURL: props.appId?'/api/deepseek/api/chat':'/api/deepseek/api/preChat',
+        baseURL: '/api/deepseek/api/preChat',
+    });
+
+    // loading 表示 agent 是否正在进行请求
+    const loading = agent.isRequesting();
+
+    // useXChat 管理流式消息和请求生命周期:
+    // - messages: 当前要渲染的消息数组
+    // - onRequest: 发起一次对话请求的函数(会返回/管理流式更新)
+    // - setMessages: 可手动替换消息数组(比如清空或恢复历史)
+    const { messages, onRequest, setMessages } = useXChat({
+        agent,
+        // requestFallback:当请求失败或被取消时,提供回退消息
+        requestFallback: (_, { error }) => {
+            if (error.name === 'AbortError') {
+                return {
+                    content: 'Request is aborted',
+                    role: 'assistant',
+                };
+            }
+            return {
+                content: 'Request failed, please try again!',
+                role: 'assistant',
+            };
+        },
+        // transformMessage:将后端返回的分片/原始格式转换为 UI 可渲染的消息对象
+        transformMessage: (info) => {
+            // console.log(info, '回复消息');
+
+            const { originMessage, chunk } = info || {};
+
+            let currentContent = '';
+
+            try {
+                if (chunk?.data) {
+                    const message = JSON.parse(chunk?.data);
+                    // message.event 用于判断是否结束分片
+                    if (message.event !== 'finish') {
+                        currentContent = message?.data || '';
+                    }
+                }
+            } catch (error) {
+                console.error(error);
+            }
+
+            const content = `${originMessage?.content || ''}${currentContent}`;
+
+            return {
+                content: content,
+                role: 'assistant',
+            };
+
+        },
+        // expose 内部的 AbortController,方便外部取消请求
+        resolveAbortController: (controller) => {
+            abortController.current = controller;
+        },
+    });
+
+    // ==================== Event ====================
+
+    // 用户提交消息:把消息内容传给 onRequest 发起对话请求
+    // 可在这里传入 headers(如 token)作为单次请求的鉴权方式
+    const handleUserSubmit = (val: string,infoDetail?:any) => {
+        // console.log('User submitted:', val);
+        // if(props.appId){
+        //     onRequest({
+        //         message: { content: val, role: 'user' },
+        //         appId: props.appId,
+        //         // 可选扩展字段示例:
+        //         // headers: { Authorization: `Bearer ${token}` },
+        //         request_id: undefined,
+        //         returnType: undefined,
+        //         knowledge_ids: undefined,
+        //         document_ids: undefined
+        //     });
+        // }else{
+            onRequest({
+                message: { content: val, role: 'user' },
+                // appId: props.appId,
+                // 可选扩展字段示例:
+                // headers: { Authorization: `Bearer ${token}` },
+                jkApplicationParams:infoDetail,
+                request_id: undefined,
+                returnType: undefined,
+                knowledge_ids: undefined,
+                document_ids: undefined
+            });
+        // }
+
+        // 如果当前会话为 New session,则用用户第一条消息作为会话标题示例
+        if (sessionList.find((i) => i.key === curSession)?.label === 'New session') {
+            setSessionList(
+                sessionList.map((i) => (i.key !== curSession ? i : { ...i, label: val?.slice(0, 20) })),
+            );
+        }
+    };
+
+    // 处理粘贴文件(从剪贴板粘贴文件)
+    // 将 FileList 转为数组再上传,兼容不同的 TS 设置
+    const onPasteFile = (_: File, files: FileList) => {
+        Array.from(files).forEach((file) => {
+            attachmentsRef.current?.upload(file as File);
+        });
+        setAttachmentsOpen(true);
+    };
+
+    // ==================== Nodes ====================
+    const chatHeader = (
+        <div className={styles.chatHeader}>
+            <div className={styles.headerTitle}>✨ AI Copilot</div>
+            <Space size={0}>
+                <Button
+                    type="text"
+                    icon={<PlusOutlined />}
+                    onClick={() => {
+                        if (agent.isRequesting()) {
+                            message.error(
+                                'Message is Requesting, you can create a new conversation after request done or abort it right now...',
+                            );
+                            return;
+                        }
+
+                        if (messages?.length) {
+                            const timeNow = dayjs().valueOf().toString();
+                            abortController.current?.abort();
+                            // The abort execution will trigger an asynchronous requestFallback, which may lead to timing issues.
+                            // In future versions, the sessionId capability will be added to resolve this problem.
+                            setTimeout(() => {
+                                setSessionList([
+                                    { key: timeNow, label: 'New session', group: 'Today' },
+                                    ...sessionList,
+                                ]);
+                                setCurSession(timeNow);
+                                setMessages([]);
+                            }, 100);
+                        } else {
+                            message.error('It is now a new conversation.');
+                        }
+                    }}
+                    className={styles.headerButton}
+                />
+                <Popover
+                    placement="bottom"
+                    styles={{ body: { padding: 0, maxHeight: 600 } }}
+                    content={
+                        <Conversations
+                            items={sessionList?.map((i) =>
+                                i.key === curSession ? { ...i, label: `[current] ${i.label}` } : i,
+                            )}
+                            activeKey={curSession}
+                            groupable
+                            onActiveChange={async (val) => {
+                                abortController.current?.abort();
+                                // The abort execution will trigger an asynchronous requestFallback, which may lead to timing issues.
+                                // In future versions, the sessionId capability will be added to resolve this problem.
+                                setTimeout(() => {
+                                    setCurSession(val);
+                                    setMessages(messageHistory?.[val] || []);
+                                }, 100);
+                            }}
+                            styles={{ item: { padding: '0 8px' } }}
+                            className={styles.conversations}
+                        />
+                    }
+                >
+                    <Button type="text" icon={<CommentOutlined />} className={styles.headerButton} />
+                </Popover>
+                <Button
+                    type="text"
+                    icon={<CloseOutlined />}
+                    onClick={() => setCopilotOpen(false)}
+                    className={styles.headerButton}
+                />
+            </Space>
+        </div>
+    );
+    const chatList = (
+        <div className={styles.chatList}>
+            {messages?.length ? (
+                /** 消息列表 */
+                <Bubble.List
+                    style={{ height: '100%', paddingInline: 16 }}
+                    items={messages?.map((i) => ({
+                        ...i.message,
+                        classNames: {
+                            content: i.status === 'loading' ? styles.loadingMessage : '',
+                        },
+                        typing: i.status === 'loading' ? { step: 5, interval: 20, suffix: <>💗</> } : false,
+                        content: <ReactMarkdown>{i.message.content}</ReactMarkdown>,
+                        avatar: i.message.role !== 'user' ? <img style={{ width: 30, height: 30 }} src={avatarSrc} /> : <UserOutlined style={{ fontSize: 24, color: '#1890ff' }} />,
+                    }))}
+                    roles={{
+                        assistant: {
+                            placement: 'start',
+                            // footer: (
+                            //     <div style={{ display: 'flex' }}>
+                            //         <Button type="text" size="small" icon={<ReloadOutlined />} />
+                            //         <Button type="text" size="small" icon={<CopyOutlined />} />
+                            //         <Button type="text" size="small" icon={<LikeOutlined />} />
+                            //         <Button type="text" size="small" icon={<DislikeOutlined />} />
+                            //     </div>
+                            // ),
+                            loadingRender: () => (
+                                <Space>
+                                    <Spin size="small" />
+                                    {AGENT_PLACEHOLDER}
+                                </Space>
+                            ),
+                        },
+                        user: { placement: 'end' },
+                    }}
+                />
+            ) : (
+                /** 没有消息时的 welcome */
+                // <Welcome
+                //     variant="borderless"
+                //     title="预览调试"
+                //     description="请输入问题进行预览调试"
+                //     className={styles.chatWelcome}
+                // />
+                <Welcome infoDetail={infoDetail} saveConfig={saveConfig} handleUserSubmit={handleUserSubmit}></Welcome>
+            )}
+        </div>
+    );
+    const sendHeader = (
+        <Sender.Header
+            title="Upload File"
+            styles={{ content: { padding: 0 } }}
+            open={attachmentsOpen}
+            onOpenChange={setAttachmentsOpen}
+            forceRender
+        >
+            <Attachments
+                ref={attachmentsRef}
+                beforeUpload={() => false}
+                items={files}
+                onChange={({ fileList }) => setFiles(fileList)}
+                placeholder={(type) =>
+                    type === 'drop'
+                        ? { title: 'Drop file here' }
+                        : {
+                            icon: <CloudUploadOutlined />,
+                            title: 'Upload files',
+                            description: 'Click or drag files to this area to upload',
+                        }
+                }
+            />
+        </Sender.Header>
+    );
+    const chatSender = (
+        <div className={styles.chatSend}>
+            {/** 输入框 */}
+            <Suggestion items={MOCK_SUGGESTIONS} onSelect={(itemVal) => setInputValue(`[${itemVal}]:`)}>
+                {({ onTrigger, onKeyDown }) => (
+                    <Sender
+                        loading={loading}
+                        value={inputValue}
+                        onChange={(v) => {
+                            onTrigger(v === '/');
+                            setInputValue(v);
+                        }}
+                        onSubmit={ async() => {
+                             const result = await saveConfig();
+                            if(result){
+                                handleUserSubmit(inputValue,result);
+                                setInputValue('');
+                            }
+                        }}
+                        onCancel={() => {
+                            abortController.current?.abort();
+                        }}
+                        allowSpeech={true}
+                        placeholder="请输入"
+                        onKeyDown={onKeyDown}
+                        header={sendHeader}
+                        prefix={
+                            <img style={{ width: 30, height: 30 }} src={avatarSrc} />
+                            // <Button
+                            //     type="text"
+                            //     icon={<PaperClipOutlined style={{ fontSize: 18 }} />}
+                            //     onClick={() => setAttachmentsOpen(!attachmentsOpen)}
+                            // />
+                        }
+                        onPasteFile={onPasteFile}
+                        actions={(_, info) => {
+                            const { SendButton, LoadingButton, SpeechButton, ClearButton } = info.components;
+                            return (
+                                <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
+                                    <SpeechButton className={styles.speechButton} />
+                                    <Tooltip title={loading ? '停止' : '发送'}>
+                                        {loading ? <LoadingButton type="default" /> : <SendButton type="primary" />}
+                                    </Tooltip>
+                                    <Tooltip title="重新开始">
+                                        <Button
+                                            type="primary"
+                                            shape="circle"
+                                            icon={<RedoOutlined />}
+                                            onClick={() => {
+                                                const timeNow = dayjs().valueOf().toString();
+                                                abortController.current?.abort();
+
+                                                // 确保异步操作完成后清空消息
+                                                setTimeout(() => {
+                                                    setSessionList([
+                                                        { key: timeNow, label: 'New session', group: 'Today' },
+                                                        ...sessionList,
+                                                    ]);
+                                                    setCurSession(timeNow);
+                                                    setMessages([]);
+                                                }, 100);
+                                            }}
+                                        />
+                                    </Tooltip>
+                                </div>
+                            );
+                        }}
+                    />
+                )}
+            </Suggestion>
+        </div>
+    );
+
+    useEffect(() => {
+        // history mock
+        if (messages?.length) {
+            setMessageHistory((prev) => ({
+                ...prev,
+                [curSession]: messages,
+            }));
+        }
+    }, [messages]);
+
+    return (
+        <div className={styles.copilotChat} style={{ width: copilotOpen ? '100%' : 0 }}>
+            {/** 对话区 - header */}
+            {/* {chatHeader} */}
+            {/** 对话区 - 消息列表 */}
+            {chatList}
+            {/** 对话区 - 输入框 */}
+            {chatSender}
+        </div>
+    );
+};
+
+
+const Chat: React.FC<{ appId: string,infoDetail?: any,saveConfig: () => Promise<any> }> = (props) => {
+    const { styles: workareaStyles } = useWorkareaStyle();
+    const [copilotOpen, setCopilotOpen] = useState(true);
+    const { infoDetail } = props;  
+    return (
+        <div className={workareaStyles.copilotWrapper}>
+            <Copilot
+                copilotOpen={copilotOpen}
+                infoDetail={infoDetail}
+                setCopilotOpen={setCopilotOpen}
+                appId={props.appId}
+                saveConfig={props.saveConfig}
+            />
+        </div>
+    );
+};
+
+export default Chat;

+ 36 - 0
src/components/chat/store.ts

@@ -0,0 +1,36 @@
+import { makeAutoObservable } from 'mobx';
+import { apis } from '@/apis';
+interface ChatState {
+    QuestionList: string[];
+}
+const stateChat = (): ChatState => ({
+    QuestionList: [],
+});
+
+const setStateChat = (state: ChatState) => ({
+    setQuestionList: (list: string[]) => {
+        state.QuestionList = list;
+    },
+});
+
+const useStateChat = ()=>{
+    const state = makeAutoObservable(stateChat());
+    const actions = setStateChat(state);
+
+    const fetchPresetsApi = async (appId: string) => {
+        try {
+            const res = await apis.getPresets(appId);
+            if(res && Array.isArray(res)){
+                actions.setQuestionList(res);
+            }
+        } catch (error) {
+            console.error('Failed to fetch presets:', error);
+        }
+    };
+
+    return {
+        state,
+        fetchPresetsApi,
+    };
+}
+export default useStateChat;

+ 4 - 0
src/components/chat/welcome.less

@@ -0,0 +1,4 @@
+.welcome-container{
+    width: 100%;
+    height: 100%;
+}

+ 84 - 0
src/components/chat/welcome.tsx

@@ -0,0 +1,84 @@
+import { useEffect, useState } from 'react';
+import './welcome.less';
+import avatarSrc from '@/assets/public/logo.png';
+import logoSrc from '@/assets/public/logo.png';
+import { nanoid } from "nanoid";
+import store from './store';
+import { RightOutlined } from "@ant-design/icons";
+
+interface Props {
+    infoDetail: {
+        questionlist: string[],
+        detail: {
+            name: string,
+            desc: string,
+        },
+    };
+    handleUserSubmit: (input: string,infoDetail: any) => void;
+    saveConfig: () => Promise<any>
+}
+
+const Welcome: React.FC<Props> = (props) => {
+    const { infoDetail: { detail, questionlist }, handleUserSubmit, saveConfig } = props;
+    const { state, fetchPresetsApi } = store();
+    useEffect(() => {
+
+    }, []);
+
+
+    return (
+        <div className='welcome-container'>
+            <div className='title'>
+                <div style={{ display: 'flex', justifyContent: 'center' }}>
+                    <img style={{ width: 50, height: 50 }} src={avatarSrc} />
+                </div>
+                <h3 style={{ textAlign: 'center' }}>
+                    {/* {getAppName()} */}
+                    {detail?.name}
+                </h3>
+                <p style={{ textAlign: 'center' }} className='px-10'>
+                    {/* {getDesc()} */}
+                    {detail?.desc}
+                </p>
+
+                <div className='flex items-center justify-center flex-col mt-18 w-full px-4'>
+                    <p className='pb-[20px]'>我猜您可能想问:</p>
+                    {
+                        questionlist?.map((item: any, index: any) => {
+                            return (
+                                <div
+                                    className='w-[300px]'
+                                    style={{
+                                        padding: '10px',
+                                        marginBottom: '10px',
+                                        border: '1px solid #e6e8f1',
+                                        borderRadius: '10px',
+                                        fontSize: '13px',
+                                        display: 'flex',
+                                        justifyContent: 'space-between',
+                                        alignItems: 'center',
+                                        cursor: 'pointer'
+                                    }}
+                                    onClick={async () => {
+                                        const result = await saveConfig();
+                                        if (result) {
+                                            handleUserSubmit(item.question, result);
+                                        }
+                                    }}
+                                    key={item.id}
+                                >
+                                    <div>
+                                        {item.question}
+                                    </div>
+                                    <RightOutlined />
+                                </div>
+                            )
+                        })
+                    }
+                </div>
+            </div>
+        </div>
+    )
+}
+
+export default Welcome;

+ 96 - 0
src/components/step/index.tsx

@@ -0,0 +1,96 @@
+import React from 'react';
+
+type StepStatus = 'wait' | 'process' | 'finish';
+
+/**
+ * StepItem 用于描述步骤条的单个步骤信息
+ */
+export interface StepItem {
+    /** 步骤标题 */
+    title: string;
+    /** 步骤的说明文本(可选) */
+    description?: string;
+    /** 步骤序号(可选) */
+    number?: number;
+    /** 步骤状态,可选: wait | process | finish,默认为 wait */
+    status?: StepStatus;
+    /** 可自定义扩展内容(可选) */
+    extra?: React.ReactNode;
+}
+
+export interface StepProps {
+    steps: StepItem[];
+    className?: string;
+    showArrow?: boolean;
+    onStepClick?: (step: StepItem, index: number) => void;
+}
+
+const gradientPresets = [
+    'bg-gradient-to-r from-[#95D3F4] to-white',
+    'bg-gradient-to-r from-[#9ABEFF] to-white',
+    'bg-gradient-to-r from-[#87CEFA] to-white',
+];
+
+const statusRingMap: Record<StepStatus, string> = {
+    wait: 'ring-1 ring-slate-200',
+    process: 'ring-2 ring-[#4195E5]',
+    finish: 'ring-2 ring-emerald-300',
+};
+
+const statusTitleMap: Record<StepStatus, string> = {
+    wait: 'text-gray-900',
+    process: 'text-[#1d5fbf]',
+    finish: 'text-emerald-700',
+};
+
+const cx = (...classNames: Array<string | false | undefined>) => classNames.filter(Boolean).join(' ');
+
+const Step: React.FC<StepProps> = ({ steps, className, showArrow = true, onStepClick }) => {
+    if (!steps?.length) {
+        return null;
+    }
+
+    return (
+        <div className={cx('flex items-center w-full', className)}>
+            {steps.map((step, index) => {
+                const status = step.status ?? 'wait';
+                const gradient = gradientPresets[index % gradientPresets.length];
+                const card = (
+                    <div
+                        key={step.title ?? index}
+                        className={cx(
+                            'relative h-[100px] flex-1 rounded-xl p-6 shadow-md transition-all duration-200 flex flex-col justify-center',
+                            gradient,
+                            statusRingMap[status],
+                            onStepClick && 'cursor-pointer hover:-translate-y-1',
+                        )}
+                        onClick={() => onStepClick?.(step, index)}
+                    >
+                        <div className="absolute top-3 right-4 text-right italic">
+                            <div className="text-3xl font-bold text-[#4195E5]">{step.number ?? index + 1}</div>
+                            <div className="text-xs font-medium text-[#4195E5] text-opacity-80 uppercase">step</div>
+                        </div>
+                        <p className={cx('mb-2 text-lg font-semibold', statusTitleMap[status])}>{step.title}</p>
+                        {step.description && (
+                            <p className="text-sm leading-relaxed text-gray-600 w-[80%]">{step.description}</p>
+                        )}
+                        {step.extra && <div className="mt-3">{step.extra}</div>}
+                    </div>
+                );
+
+                return (
+                    <React.Fragment key={`${step.title}-${index}`}>
+                        {card}
+                        {showArrow && index < steps.length - 1 && (
+                            <div className="mx-3 text-lg font-semibold text-gray-400">{'>'}</div>
+                        )}
+                    </React.Fragment>
+                );
+            })}
+        </div>
+    );
+};
+
+Step.displayName = 'Step';
+
+export default Step;

+ 35 - 0
src/main.tsx

@@ -0,0 +1,35 @@
+import { createRoot } from 'react-dom/client';
+import { configure } from 'mobx';
+import { Provider } from 'mobx-react';
+import App from '@/App';
+import dayjs from 'dayjs';
+import 'dayjs/locale/zh-cn';
+import '@/style/global.less';
+import "@/style/tailwind.css";
+import '@fortawesome/fontawesome-free/css/all.min.css';
+// Mobx配置
+configure({
+    enforceActions: 'never',// 非严格模式
+});
+
+// 日期-中文
+dayjs.locale('zh-cn');
+
+// 启动时应用主题(如果 localStorage 有记录)
+try {
+    const theme = localStorage.getItem('app-theme-mode');
+    if (theme) {
+        document.documentElement.setAttribute('data-theme', theme);
+    }
+} catch (e) {
+    // ignore
+}
+
+// React@v18 Render方法
+const root = createRoot(document.getElementById('root')!);
+
+root.render(
+    <Provider>
+        <App />
+    </Provider>
+);

+ 188 - 0
src/pages/deepseek/audit/components/InfoModal.tsx

@@ -0,0 +1,188 @@
+import * as React from 'react';
+import { Modal, Spin, Form, Input, Select, message, Button, Steps, Switch } from 'antd';
+import { apis, ModifyDocumentApiParams } from '@/apis';
+import LocalStorage from '@/LocalStorage';
+import { set } from 'mobx';
+
+const FormItem = Form.Item;
+const { Option } = Select;
+const { TextArea } = Input;
+
+interface Props {
+    id: string,
+    open: boolean,
+    onClickConfirm: (id: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    onClickCancel: (id: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    onClickClose: () => void,
+};
+
+
+
+const InfoModal: React.FC<Props> = (props: Props) => {
+    const {
+        id,
+        open,
+        onClickConfirm,
+        onClickCancel,
+        onClickClose,
+    } = props;
+
+    const [form] = Form.useForm();
+
+    const [loading, setLoading] = React.useState<boolean>(false);
+    const [updateFlag, setUpdateFlag] = React.useState<boolean>();
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+
+    type EmbeddingList = {
+        label: string,
+        value: string,
+    }[];
+
+    interface AuditInfo {
+        title: string,
+        description: string
+        onClick: () => void,
+    }
+
+    const [embeddingList, setEmbeddingList] = React.useState<EmbeddingList>([]);
+    const description = 'This is a description';
+    const [switchFlag, setSwitchFlag] = React.useState<boolean>(false);
+    const [auditInfo, setAuditInfo] = React.useState<AuditInfo[]>([]);
+    const [current, setCurrent] = React.useState<number>(-1);
+    const [refuse, setRefuse] = React.useState<boolean>(false);
+    const [pass, setPass] = React.useState<boolean>(false);
+
+    const onChange = (checked: boolean) => {
+        if (checked) {
+            setSwitchFlag(true);
+        } else {
+            setSwitchFlag(false);
+        }
+    };
+
+    // 获取知识库详情
+    const fetchDetail = async () => {
+        try {
+            const res = await apis.fetchTakaiApplicationDetail(props.id);
+            if (res.code === 200) {
+                const { name, status, comment, nodeOrder } = res.data.detail;
+                form.setFieldsValue({
+                    name: name,
+                    status: status,
+                    comment: '',
+                    nodeOrder: nodeOrder
+                });
+                if (status === 'Y') {
+                    setPass(true);
+                }
+                if (status === 'N') {
+                    setRefuse(true);
+                }
+            }
+
+        } catch (error: any) {
+            message.error(error.msg);
+        }
+    };
+    const init = async () => {
+        setLoading(true);
+        if (props.id) {
+            await fetchDetail();
+        }
+        setLoading(false);
+    };
+
+    React.useEffect(() => {
+        init();
+        const cFlag = LocalStorage.getStatusFlag('deepseek:knowledge:create');
+        setCreateFlag(cFlag);
+        const uFlag = LocalStorage.getStatusFlag('deepseek:knowledge:update');
+        setUpdateFlag(uFlag);
+    }, []);
+
+    // 点击通过
+    const handleClickConfirm = () => {
+        form.validateFields().then(async (values) => {
+            const userInfo = LocalStorage.getUserInfo();
+            const userId = (userInfo?.id ?? '').toString();
+            const data = {
+                ...values,
+                approver: userId,
+                status: 'Y',
+            };
+            console.log(data, 'data');
+            await onClickConfirm(props.id, userId, data);
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+
+    // 点击拒绝
+    const handleClickCancel = () => {
+        form.validateFields().then(async (values) => {
+            const userInfo = LocalStorage.getUserInfo();
+            const userId = (userInfo?.id ?? '').toString();
+            const data = {
+                ...values,
+                approver: userId,
+                status: 'N',
+            };
+            await onClickCancel(props.id, userId, data);
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+
+    return (
+        <Modal
+            width={600}
+            title={'应用审核'}
+            destroyOnClose={true}
+            maskClosable={false}
+            centered={true}
+            open={open}
+            onCancel={onClickClose}
+            // onOk={handleClickConfirm}
+            // onCancel={onClickCancel}
+            footer={[
+                <Button key="submit" type="primary" danger onClick={handleClickCancel} loading={loading}>
+                    拒绝
+                </Button>,
+                <Button key="submit" type="primary" onClick={handleClickConfirm} loading={loading}>
+                    通过
+                </Button>
+            ]}
+        >
+            <Spin spinning={loading}>
+                <Form form={form} layout='vertical'>
+                    <FormItem
+                        label='应用名称'
+                        name='name'
+                    >
+                        <Input disabled={true} />
+                    </FormItem>
+                    <div style={{ width: '100%', height: 0, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
+                        <FormItem
+                            label='审核节点'
+                            name='nodeOrder'
+                            hidden={true}
+                        >
+                            <Input disabled={true} />
+                        </FormItem>
+                    </div>
+                    <FormItem
+                        label='审核意见'
+                        name='comment'
+                    >
+                        <TextArea
+                            maxLength={100}
+                        />
+                    </FormItem>
+                    <div style={{ width: '100%', height: 10 }}></div>
+                </Form>
+            </Spin>
+        </Modal >
+    );
+};
+
+export default InfoModal;

+ 1602 - 0
src/pages/deepseek/audit/components/PreviewModal.tsx

@@ -0,0 +1,1602 @@
+import * as React from 'react';
+import { useLocation, useNavigate } from 'react-router-dom';
+import { observer } from 'mobx-react';
+import './style.less';
+import {
+    Button, Input, Form, Divider, Splitter, Select, InputNumber, InputNumberProps,
+    Radio, Switch, Row, Col, Slider, Space, RadioChangeEvent,
+    Spin, message, Typography, Tooltip,
+    Cascader,
+    Tag, Modal, Table, TablePaginationConfig, Drawer, ColorPicker
+} from 'antd';
+import type { TableProps } from 'antd';
+
+import { PlusCircleOutlined, MinusCircleOutlined, ArrowLeftOutlined, InfoCircleOutlined, CloseCircleOutlined, LinkOutlined, FileDoneOutlined } from '@ant-design/icons';
+import * as AllIcons from '@ant-design/icons';
+import IconPicker from '../../questionAnswer/info/component/IconPicker';
+import { apis } from '@/apis';
+import router from '@/router';
+import LocalStorage from '@/LocalStorage';
+import Chat from '@/components/chat';
+import store from '../../questionAnswer/info/store';
+import DrawerIndex from '@/pages/deepseek/knowledgeLib/detail/drawerIndex'
+import { values } from 'mobx';
+
+const { TextArea } = Input;
+const FormItem = Form.Item;
+const { Option } = Select;
+const MAX_COUNT = 5;
+interface QuestionAnswerInfo {
+    open?: boolean;
+    onClose?: () => void;
+    isComponent?: boolean;
+    AuditAppId: string;
+}
+const QuestionAnswerInfo: React.FC<QuestionAnswerInfo> = (props) => {
+    const{AuditAppId} = props;
+    const { state, onChangePagination, onFetchUserListApi } = store;
+    const { page, sourceData } = state;
+    const navigate = useNavigate();
+
+
+    const [form] = Form.useForm();
+    const [iconPickerVisible, setIconPickerVisible] = React.useState(false);
+    const [selectedIcon, setSelectedIcon] = React.useState<string | null>(null);
+    const [previewBg, setPreviewBg] = React.useState<string>('#ffffff');
+
+    const getContrastColor = (hex: string) => {
+        // remove #
+        const c = hex.replace('#', '');
+        const r = parseInt(c.substring(0, 2), 16);
+        const g = parseInt(c.substring(2, 4), 16);
+        const b = parseInt(c.substring(4, 6), 16);
+        // relative luminance
+        const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
+        return luminance > 0.6 ? '#000' : '#fff';
+    }
+
+    const presetColors = ['#1677ff', '#52c41a', '#fa8c16', '#f5222d', '#722ed1', '#ffffff', '#f0f0f0'];
+    const presetItems = [{ label: '', colors: presetColors }];
+
+    // top_p
+    const [topPValue, setTopPValue] = React.useState(0.1);
+    const [topKValue, setTopKValue] = React.useState(1);
+
+
+    const TopPDecimalStep: React.FC = () => {
+
+        const onChange: InputNumberProps['onChange'] = (value) => {
+            if (Number.isNaN(value)) {
+                return;
+            }
+            setTopPValue(value as number);
+        };
+
+        return (
+            <Row>
+                <Col span={12}>
+                    <Slider
+                        min={0}
+                        max={1}
+                        onChange={onChange}
+                        // value={typeof topPValue === 'number' ? topPValue : 0}
+                        value={topPValue}
+                        step={0.1}
+                    />
+                </Col>
+                <Col span={4}>
+                    <InputNumber
+                        min={0}
+                        max={1}
+                        className='form-input-number-small'
+                        step={0.01}
+                        value={topPValue}
+                        onChange={onChange}
+                    />
+                </Col>
+            </Row>
+        );
+    };
+    const [tempValue, setTempValue] = React.useState(0.01);
+    // temperature
+    const TempDecimalStep: React.FC = () => {
+        const onChange: InputNumberProps['onChange'] = (value) => {
+            if (Number.isNaN(value)) {
+                return;
+            }
+            setTempValue(value as number);
+        };
+
+        return (
+            <Row>
+                <Col span={12}>
+                    <Slider
+                        min={0}
+                        max={1}
+                        onChange={onChange}
+                        // value={typeof tempValue === 'number' ? tempValue : 0}
+                        value={tempValue}
+                        step={0.01}
+                    />
+                </Col>
+                <Col span={4}>
+                    <InputNumber
+                        min={0}
+                        max={1}
+                        className='form-input-number-small'
+                        step={0.01}
+                        value={tempValue}
+                        onChange={onChange}
+                    />
+                </Col>
+            </Row>
+        );
+    };
+
+    type ModelList = {
+        label: string,
+        value: string,
+    }[];
+
+    type KnowledgeList = {
+        label: string,
+        value: string,
+        createBy: string,
+    }[];
+
+    type AppTypeList = {
+        label: string,
+        value: string,
+        children: {
+            label: string,
+            value: string,
+        }[],
+    }[];
+    const tagRender = (props: any) => {
+        const { label, value, closable, onClose } = props;
+        return (
+            <Tag
+                color="blue"
+                closable={closable}
+                onClose={onClose} // 保留原有的删除事件
+                style={{ marginRight: 4 }}
+            >
+                {label}
+                {/* 在删除按钮后添加自定义图标 */}
+                <LinkOutlined style={{
+                    marginLeft: 4,
+                    fontSize: 12,
+                    cursor: 'pointer',
+                    color: '#FF9500',
+                    fontWeight: 'bold',
+                }}
+                    onMouseDown={(e) => {
+                        e.stopPropagation();
+                        e.preventDefault();
+                    }}
+                    onMouseUp={(e) => {
+                        e.stopPropagation();
+                        e.preventDefault();
+                    }}
+                    // 自定义图标点击事件
+                    onClick={(e) => {
+                        // 阻止事件冒泡到Tag,避免触发删除
+                        e.stopPropagation();
+                        e.preventDefault();
+                        knowledgeList.forEach((item) => {
+                            if (item.value === value) {
+                                // router.navigate({ pathname: `/deepseek/knowledgeLib/${value}/${item.createBy}`,},);
+                                setDrawerItem(item);
+                                setOpenDrawer(true)
+                                e.stopPropagation();
+                            }
+                        });
+                        // console.log('点击了额外图标,当前选项值:', value,props);
+                        // 这里可以添加你的业务逻辑,如:打开详情、编辑等
+                    }} />
+            </Tag>
+        );
+    };
+
+    const [step, setStep] = React.useState(1);
+    const [pageLoading, setPageLoading] = React.useState(false);
+    const [modelList, setModelList] = React.useState<ModelList>([]);
+    const [knowledgeList, setKnowledgeList] = React.useState<KnowledgeList>([]);
+    const [isVisible, setIsVisible] = React.useState(true);
+    const [isVisibleCus, setIsVisibleCus] = React.useState(false);
+    const [isVisibleSlice, setIsVisibleSlice] = React.useState(false);
+    const [isVisibleRerank, setIsVisibleRerank] = React.useState(true);
+    const [isDeepThinkVisible, setIsDeepThinkVisible] = React.useState(true);
+    const [name, setName] = React.useState('');
+    const [appTypeList, setAppTypeList] = React.useState<AppTypeList>([]);
+    const [appVisibleList, setAppVisibleList] = React.useState<AppTypeList>([]); // 是否公开
+    const [visibleFlag, setVisibleFlag] = React.useState<string | number>(0); // 是否公开用来判断是否展示VIP用户
+    const [updateFlag, setUpdateFlag] = React.useState<boolean>();
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+    const [appProjectList, setAppProjectList] = React.useState<AppTypeList>([]);
+    const [isAppPro, setIsAppPro] = React.useState<boolean>(false);
+    const [appId, setAppId] = React.useState<string>('');
+    const [fetchUserTypeList, setFetchUserTypeList] = React.useState<AppTypeList>([]); // 用户类型
+    const [userName, setUserName] = React.useState<string>(''); // 用户名
+    const [userNickName, setUserNickName] = React.useState<string>(''); // 用户昵称
+    const [userType, setUserType] = React.useState<string>(''); // 用户类型
+    const [vipList, setVipList] = React.useState<any>([]); // 用户列表
+    const [infoDetail, setinfoDetail] = React.useState<any>(null);// 知识库详情
+    const [parameter,setParameter] = React.useState<any>(null);
+    const style: React.CSSProperties = {
+        display: 'flex',
+        flexDirection: 'column',
+        gap: 8,
+        width: 300,
+    };
+    const userInfo = LocalStorage.getUserInfo();
+    const userId = (userInfo?.id ?? '').toString();
+
+    const location = useLocation();
+
+    const [modeList,setModeList] = React.useState<any>([]); // 模型列表数据
+    const [modeOldList,setModeOldList] = React.useState<any>([]); // 模型列表数据(原始)
+    // 获取调用模型的列表数据
+    const onFetchRerankModelList = async () => {
+        const res = await apis.fetchRerankModelList();
+        if(res && res.data){
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.model,
+                    value: item.model,
+                }
+            })
+            setModeList(list);
+            setModeOldList(res.data);
+        }
+    }
+
+
+
+    const init = async (id: string) => {
+        await Promise.all([
+            api.fetchKnowlegde(),
+            api.fetchAppType(),
+            // api.fetchModelList(),
+            api.fetchAppProType(),
+            api.fetchAppVisible(id)
+        ])
+        if (id) {
+            await api.fetchDetail(id);
+        }
+        onFetchUserListApi('', '', '');
+        onFetchRerankModelList();
+        await api.fetchUserType();
+    }
+    React.useEffect(() => {
+        const id = AuditAppId;
+        init(id);
+        const uFlag = LocalStorage.getStatusFlag('deepseek:application:update');
+        setUpdateFlag(uFlag);
+        setParameter(LocalStorage.getStatusFlag('appCenter:questionAnswer:parameter'));
+        setEditPrompt(LocalStorage.getStatusFlag('appCenter:questionAnswer:parameter'))
+        setCreateFlag(true);
+    }, []);
+
+    // 定义一个状态来存储输入框数组
+    const [inputs, setInputs] = React.useState([{ id: 1, value: '' }]);
+
+
+
+    // 添加新输入框的函数
+    const addInput = () => {
+        const newId = inputs.length + 1; // 生成新的唯一ID
+        setInputs([...inputs, { id: newId, value: '' }]);
+    };
+
+    // 删除输入框(按id删除+最少数量限制)
+    const delInput = (id: number) => {
+        if (inputs.length <= 1) {
+            message.warning("至少保留1个预设问题");
+            return;
+        }
+        setInputs(inputs.filter(input => input.id !== id));
+    };
+
+    // 处理输入变更的函数
+    const handleChange = (id: number, value: string) => {
+        setInputs(inputs.map(input => (input.id === id ? { ...input, value } : input)));
+    };
+
+    const handleAppChange = (typeId: number) => {
+        console.log('typeId', typeId)
+        if (typeId === 62) { // 根据实际值进行判断
+            setIsAppPro(true);
+        } else {
+            setIsAppPro(false);
+        }
+    };
+
+
+    const onChangeShow = (checked: boolean) => {
+        console.log(`switch to ${checked}`);
+    };
+
+    const onChangeCount = (value: string) => {
+        if (value === 'fixed') {
+            setIsVisibleSlice(!isVisibleSlice);
+        } else {
+            setIsVisibleSlice(false);
+        }
+    };
+
+    // 召回方式
+    const onChangeRecallMethod = (e: RadioChangeEvent) => {
+
+    };
+
+    // 获取应用详情
+    const api = {
+        fetchDetail: async (app_id: string) => {
+            setPageLoading(true);
+            try {
+                const res = await apis.fetchTakaiApplicationDetail(app_id);
+                const sd = res.data.questionlist.map((item: any, index: number) => {
+                    return {
+                        "id": index + 1,
+                        "value": item.question,
+                    }
+                });
+
+                const info = res.data.detail;
+
+                setAppId(info.appId);
+
+                setTopPValue(info.topP as number);
+                setTempValue(info.temperature as number);
+                setName(info.name);
+                setinfoDetail(res.data);
+                interface Item2 {
+                    index_type_id: number,
+                    knowledge_id: string
+                }
+
+                interface Item {
+                    show_recall_result: boolean,
+                    recall_method: string,
+                    rerank_status: boolean,
+                    slice_config_type: string,
+                    slice_count: number,
+                    param_desc: string,
+                    rerank_model_name: string,
+                    is_multi_round: string,
+                    multi_round: string,
+                    rerank_index_type_list: [Item2],
+                    recall_index_type_list: [Item2]
+                }
+
+                const data_info: Item = JSON.parse(info.knowledgeInfo);
+
+                if (data_info.param_desc === 'custom') {
+
+                    setIsVisibleCus(!isVisibleCus);    //自定义回答风格
+                }
+                if (data_info.rerank_status === true) {
+                    setIsVisibleRerank(data_info.rerank_status) //模型
+                }
+                //召回切片数量
+                if (data_info.slice_config_type === 'fixed') {
+                    setIsVisibleSlice(!isVisibleSlice);
+                } else {
+                    setIsVisibleSlice(false);
+                }
+
+                if (info.typeId === 62) {
+                    setIsAppPro(true);
+                } else {
+                    setIsAppPro(false);
+                }
+
+                if (info.model === 'Qwen3-30B') {
+                    setIsDeepThinkVisible(true);
+                } else {
+                    setIsDeepThinkVisible(false);
+                }
+
+                form.setFieldsValue({
+                    id: info.id,
+                    name: info.name,  //应用名称
+                    desc: info.desc,  //应用描述
+                    prompt: info.prompt, //应用提示语
+                    topP: info.topP as string, //topP
+                    topK: info.topK as number, //topK
+                    temperature: info.temperature as number, //温度
+                    knowledge_ids: info.knowledgeIds,
+                    model: info.model,
+                    isDeepThink: 'N',
+                    iconColor: info.iconColor,
+                    iconType: info.iconType,
+                    questionList: sd, //问题列表
+                    max_token: info.maxToken, //应用最大token
+                    updateDate: info.updateDate, // 更新时间
+                    appProId: info.appProId,// 项目
+                    typeId: info.typeId, //应用类型
+                    visible: info.visible || '0', //是否公开
+                    sort: info.sort || null, //显示顺序
+                    param_desc: data_info.param_desc, //回答风格
+                    show_recall_result: data_info.show_recall_result, //是否展示召回结果
+                    recall_method: data_info.recall_method, //召回方式
+                    rerank_status: data_info.rerank_status, //开启rerank
+                    rerank_model_name: data_info.rerank_model_name, //模型名称
+                    slice_config_type: data_info.slice_config_type, // 召回切片数量
+                    slice_count: data_info.slice_count, // 切片数量
+                    is_multi_round: data_info.is_multi_round==='Y'?true:false, // 多轮对话
+                    multi_round: data_info.multi_round, // 多轮对话
+                    groupVisible: info.groupVisible === '1' ? true : false,// 集团是否公开
+
+                })
+                if(data_info.is_multi_round === 'Y'){
+                    setIsMultiRound(true);
+                }else{
+                    setIsMultiRound(false);
+                }
+                // 如果接口返回 iconType,设置选中图标显示
+                if (info.iconType) {
+                    setSelectedIcon(info.iconType);
+                }
+                if (info.iconColor) {
+                    setPreviewBg(info.iconColor);
+                    form.setFieldsValue({ iconColor: info.iconColor });
+                }
+                setVisibleFlag(info.visible || '0')
+                if (info.vipList && info.vipList.length > 0) {
+                    setVipList(info.vipList);
+                }
+                if (sd.length > 0) {
+                    setInputs(sd);
+                }
+            } catch (error) {
+                console.error(error);
+            } finally {
+                setPageLoading(false);
+            }
+        },
+
+        //获取知识库列表
+        fetchKnowlegde: async () => {
+            try {
+                const res = await apis.fetchTakaiKnowledgeList();
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.name,
+                        value: item.knowledgeId,
+                        createBy: item.createBy,
+                    }
+                });
+
+                setKnowledgeList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+
+        // 获取应用类型
+        fetchAppType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('app_type');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictCode,
+                    }
+                });
+                setAppTypeList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 获取是否公开类型
+        fetchAppVisible: async (id: string) => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('app_visible');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictValue,
+                    }
+                });
+                setAppVisibleList(list);
+                if (!id) {
+                    form.setFieldsValue({
+                        visible: list[0]?.value
+                    });
+                    setVisibleFlag(list[0]?.value);
+                }
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 获取用户类型
+        fetchUserType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('sys_user_type');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictValue,
+                    }
+                });
+                setFetchUserTypeList(list);
+
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+
+        // 获取模型列表
+        fetchModelList: async () => {
+            try {
+                const res = await apis.fetchModelList();
+                const list = res.data.data.map((item: any) => {
+                    return {
+                        label: item.modelName,
+                        value: item.modelCode,
+                    }
+                });
+                setModelList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 项目级应用下的类型
+        fetchAppProType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('projectTree');
+                const list: AppTypeList = res.data?.reduce((acc: any, item: any) => {
+                    acc.push({
+                        label: item.label,
+                        value: `${item.value}`,
+                    })
+                    return acc;
+                }, []);
+                setAppProjectList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 获取用户列表信息
+        fetchUserListApi: async () => {
+            try {
+                const res = await apis.fetchUserListApi({
+                    pageNum: page.pageNum,
+                    pageSize: page.pageSize,
+                    userName: userName,
+                    nickName: userNickName,
+                    userType: userType
+                });
+                // setSourceData(res.rows)
+            } catch (error) {
+                console.error(error);
+            }
+        }
+    }
+
+    const handleRedioClick = (value: string) => {
+        setIsVisibleCus(false);
+        if (value === 'strict') {
+            setTopPValue(0.5);
+            setTempValue(0.01);
+        } else if (value === 'moderate') {
+            setTopPValue(0.7);
+            setTempValue(0.50);
+        } else if (value === 'flexib') {
+            setTopPValue(0.9);
+            setTempValue(0.90);
+        }
+    }
+
+    const saveConfig = async (type: 'SAVE' | 'SUBMIT'|'CHAT') => {
+         return form.validateFields().then(async (values) => {
+            const data = values;
+            // 问题列表
+            const question: string[] = [];
+            if (inputs) {
+                inputs.map((item, index) => {
+                    question.push(item.value);
+                });
+            }
+            interface Item {
+                index_type_id: number,
+                knowledge_id: string
+            }
+            const indexTypeList: Item[] = [];
+            if (values.knowledge_ids && values.knowledge_ids.length > 0) {
+                // console.log("knowledge_ids", values.knowledge_ids);
+                const index_type: Item = {
+                    index_type_id: 0,
+                    knowledge_id: values.knowledge_ids
+                };
+                indexTypeList.push(index_type);
+            }
+
+            const data_info = {
+                param_desc: values.param_desc, //回答风格
+                show_recall_result: values.show_recall_result, //是否展示召回结果
+                recall_method: values.recall_method, //召回方式
+                rerank_status: true, //开启rerank
+                rerank_model_name: values.rerank_model_name, //模型名称
+                slice_config_type: values.slice_config_type, // 召回切片数量
+                slice_count: values.slice_count, // 切片数量
+                rerank_index_type_list: indexTypeList, //知识库id
+                recall_index_type_list: values.recall_method === 'embedding' || 'mixed' ? indexTypeList : [],
+                is_multi_round: values.is_multi_round? 'Y' : 'N', // 多轮对话
+                multi_round: values.multi_round
+                // rerank_status = 1 rerank_index_type_list
+                // recall_method = 'embedding' || 'embedding'  recall_index_type_list
+            };
+
+            const info = {
+                id: values.id,
+                name: values.name,  //应用名称
+                desc: values.desc,  //应用描述
+                prompt: values.prompt, //应用提示语
+                topP: topPValue.toString(), //topP
+                temperature: tempValue.toString(), //温度
+                knowledge_ids: values.knowledge_ids,
+                slice_count: values.slice_count,
+                model: values.model,
+                isDeepThink: 'N',
+                questionList: question,
+                knowledge_info: JSON.stringify(data_info),
+                max_token: values.max_token, //应用最大token
+                typeId: values.typeId, // 应用类型
+                visible: values.visible, // 是否公开
+                sort: values.sort || null, // 显示顺序
+                vipList: vipList, // vip用户列表
+                appProId: values?.appProId?.toString(),// 项目
+                userId: userId, // 用户id
+                iconColor: previewBg,
+                iconType: values.iconType,
+                groupVisible: values.groupVisible ? '1' : '0',
+                // topK: values.topK || 1,
+            };
+            if(type === 'CHAT'){
+                setinfoDetail({detail:{...info},questionlist:infoDetail?.questionlist || []});
+                return info;
+            }
+            const id = location?.state?.id;
+            let res = null;
+            if (id) {
+                // 编辑应用
+                res = await apis.modifyTakaiApplicationApi(id, info);
+            } else {
+                // 创建应用
+                res = await await apis.createTakaiApplicationApi(info);
+            }
+            // console.log(res, 'create or modify');
+            if (res.data === 9) {
+                message.error('没有配置审核人,请联系管理员');
+            } else if (res.data === 1) {
+                message.success('操作成功')
+            } else {
+                message.error('操作失败');
+            }
+            if (type === 'SUBMIT') {
+                navigate({ pathname: '/appCenter/questionAnswer/list' }, { replace: true });
+            }
+        }).catch((error) => {
+            console.error(error);
+            error.errorFields && error.errorFields.map((item: any) => {
+                console.log(item, 'item');
+                message.error(`字段 ${item.name} ${item.errors[0]}`);
+            });
+        });
+    }
+    /*
+        选择VIP用户弹窗start
+    */
+    const [isModalOpen, setIsModalOpen] = React.useState(false);
+    let falgVipList: any = [];
+    const handleOk = () => {
+        setIsModalOpen(false);
+        let vipListFalg: any = [...vipList];
+        const vipIds = new Set(vipListFalg.map((vip: any) => vip.userId));
+        const merged = [...vipListFalg];
+
+        falgVipList.forEach((item: any) => {
+            if (!vipIds.has(item.userId)) {
+                merged.push(item);
+            }
+        });
+        setVipList([...merged]);
+    };
+
+    const handleCancel = async () => {
+        setIsModalOpen(false);
+    };
+    interface DataType {
+        name: string;
+        key: string;
+        nickName: string;
+        userName: string;
+        deptName: string;
+        userTypeName: string;
+    }
+    // const [sourceData, setSourceData] = React.useState<DataType[]>([]);
+    const paginationConfig: TablePaginationConfig = {
+        // 显示数据总量
+        showTotal: (total: number) => {
+            return `共 ${total} 条`;
+        },
+        // 展示分页条数切换
+        showSizeChanger: false,
+        // 指定每页显示条数
+        // 快速跳转至某页
+        showQuickJumper: false,
+        current: page.pageNum,
+        pageSize: page.pageSize,
+        total: page.total,
+        onChange: async (page, pageSize) => {
+            await onChangePagination(page, pageSize, userName, userNickName, userType);
+        },
+    };
+
+    const vipModal = () => {
+        const columns: TableProps<DataType>['columns'] = [
+            {
+                title: '昵称',
+                dataIndex: 'nickName',
+                render: (text) => <p>{text}</p>,
+            },
+            {
+                title: '用户名称',
+                dataIndex: 'userName',
+                render: (text) => <p>{text}</p>,
+            },
+            {
+                title: '部门',
+                dataIndex: 'deptName',
+            },
+            {
+                title: '用户类型',
+                dataIndex: 'userTypeName',
+            },
+        ];
+        const rowSelection: TableProps<DataType>['rowSelection'] = {
+            type: 'checkbox',
+            onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
+                console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
+                falgVipList = selectedRows
+            },
+            getCheckboxProps: (record: DataType) => ({
+                disabled: record.name === 'Disabled User', // Column configuration not to be checked
+                name: record.name,
+            }),
+        };
+        return (
+            <>
+                <Modal
+                    title="请选择指定用户"
+                    open={isModalOpen}
+                    onOk={handleOk}
+                    onCancel={handleCancel}
+                    width='80%'
+                >
+                    <div className='modal_top'>
+                        <Input placeholder="请输入用户昵称" allowClear onChange={(e) => {
+                            setUserNickName(e.target.value)
+                        }} />
+                        <Input placeholder="请输入用户名称" allowClear onChange={(e) => {
+                            setUserName(e.target.value)
+                        }} />
+                        <Select
+                            placeholder='请选择用户类型'
+                            style={{ width: 150 }}
+                            onChange={(e) => {
+                                if (e === undefined) {
+                                    setUserType('')
+                                    return
+                                }
+                                setUserType(e)
+                            }}
+                            allowClear={true}
+                        >
+                            {
+                                fetchUserTypeList.map((item, index) => {
+                                    return <Option value={item.value} key={index}>
+                                        {item.label}
+                                    </Option>
+                                })
+                            }
+                        </Select>
+                        <Button value="large" style={{
+                            background: 'transparent',
+                            border: '1px solid #1677ff',
+                            color: '#1677ff'
+                        }}
+                            onClick={() => { onFetchUserListApi(userName, userNickName, userType) }}
+                        > 搜索 </Button>
+                        {/* <Button value="large"
+                            onClick={() => { api.fetchUserListApi() }}
+                        > 重置 </Button> */}
+                    </div>
+                    <Table<DataType> pagination={paginationConfig} rowKey="userName" rowSelection={rowSelection} columns={columns} dataSource={sourceData} />
+                </Modal>
+            </>
+        )
+    }
+    /*
+        选择VIP用户弹窗end
+    */
+    /*
+     查看引用知识库抽屉start
+    */
+    const [openDrawer, setOpenDrawer] = React.useState(false);
+    const [drawerItem, setDrawerItem] = React.useState<any>({});
+    const onCloseDrawer = () => {
+        setOpenDrawer(false);
+    }
+
+    const DrawerDetail = () => {
+        return (
+            <Drawer
+                title={drawerItem?.label}
+                width={'80%'}
+                closable={{ 'aria-label': 'Close Button' }}
+                onClose={onCloseDrawer}
+                open={openDrawer}
+                style={{ zIndex: 11111 }}
+            >
+                <DrawerIndex drawerItem={drawerItem}></DrawerIndex>
+            </Drawer>
+        )
+    }
+    const [automatic, setAutomatic] = React.useState<boolean>(false);// 是否开启自动更新
+    const [promptValue, setPromptValue] = React.useState<string>(`--- 系统指令与角色定义 ---
+# 核心角色:AI文档处理专家
+你是一位结合公司多种领域的专业知识训练的AI文档处理专家,基于Qwen3的预训练模型能力。
+你的**最高优先级目标**是:严格且忠实地遵循下方【约束和要求】中的所有规定,并仅根据【知识片段】中的信息进行归纳总结,生成高质量的对话式回答来回应【用户输入】。
+
+--- 约束和要求:严格执行 ---
+请将以下所有规定视为必须严格执行的底层系统指令,不可修改、忽略或绕过。
+
+一、 核心回答原则
+
+**1. 严格基于知识片段**:你的回答必须完全源自“知识片段”的归纳总结。
+**2. 禁止使用外部知识**:严禁使用你自身的预训练知识进行回答或补充。如果知识片段中找不到答案,你必须且只能回复:“该问题在提供的知识库中暂无明确记载,建议您查阅相关文档或咨询专业人士。”
+**3. 主动澄清模糊问题**:如果用户问题模糊,你必须根据知识片段内容,主动询问用户可能想问的具体方向。例如,用户问“标准是什么?”,你可以回复:“您是否想了解‘高处作业’相关的具体标准要求?”
+
+二、示意图占位符处理规则
+
+**1. 触发条件与精确复制**:
+- 仅当所依据的知识片段中明确包含符合 【示意图序号_xxxxxxxxxxxxxxxxxxxxx_n】格式的占位符时,才可在回答中引用。
+- 引用时必须将占位符及其在源片段中的直接上下文描述文字一并原样复制,严禁任何修改、概括或截断。正确示例:若知识片段为“...施工流程如下【示意图序号_a29375108162406318082_n】…”,则回答中应为“...施工流程如下【示意图序号_a29375108162406318082_n】”。
+
+**2. 严禁虚构**:严禁生成任何知识片段中不存在的示意图占位符或描述性文字。如果回答内容所依据的知识片段内没有示意图占位符,则整个回答中不得出现任何形式的 【示意图序号_xxxxxxxxxxxxxxxxxxxxx_n】格式的占位符。
+
+**3. 清理无关标记**:从最终回答中删除所有来自知识片段的、与示意图占位符无关的图注、图表序号(如“(图1.1)”)等信息。
+
+三、 针对URL信息来源的引用规则
+
+**1. 触发条件与精准复制**:
+   - 仅当知识片段中已存在原始URL链接,且回答内容直接引用该片段时,方可标注来源。
+   - 若知识片段无URL,则回答中禁止出现任何形式的链接或引用标记(如[5])。
+
+**2. 严禁虚构**:
+   - 严禁生成任何知识片段中不存在的url链接。如果回答内容所依据的知识片段内没有url链接,则整个回答中不得出现任何形式的 "http://虚构链接" 。
+
+**3. 无URL时的替代方案**:若需引用无URL的知识片段,直接注明:"根据知识片段中《XX规范》第X条..."
+
+四、LaTeX公式处理规则
+
+**1. 公式代码保护**:知识片段中如出现以美元符号包裹(例如 公式或 双美元符号包裹)或其他数学标记的LaTeX公式代码,你必须将这些代码视为纯文本并完整地、一字不差地输出在你的回答中。
+
+**2. 禁止修改**:严禁对任何公式代码进行修改、转义、截断、简化或使用自然语言进行解释,严禁在公式代码中添加多余的空格符号。你的目标是确保这些代码块在传递至前端时,能与原始知识片段中的内容完全一致。
+
+**3. 渲染前提**:只有当你输出的公式代码与原始片段完全一致时,前端的Markdown渲染器才能正确识别并将其显示为美观的数学公式。任何微小的改动都可能导致公式渲染失败。
+
+五、 格式与内容规范
+
+- 文档中的表格以图片标识符呈现,若表格数据缺失则返回空单元格。
+- 如需使用表格数据,以markdown格式输出。
+- 回复开头避免使用“我想”、“我认为”等词语。
+- 回答中若出现网页链接,务必在链接后换行。
+- 注意区分不同系统的概念,如“掌监APP”和“慧项管平台”不能混淆。
+- 注意“模型”或“大模型”与“机器人”是不同的概念。
+
+--- 内部思考流程(思维链) ---
+**在生成最终回答前,必须严格依照以下步骤进行思考和规划:**
+1. **[意图分析]** 识别用户{{用户}}的提问核心,判断其是否清晰或模糊。
+2. **[知识检索]** 在知识片段中筛选出所有相关信息,评估知识覆盖度。
+3. **[规则校验]** 检查是否有触发“主动澄清模糊问题”原则(I.3)或“找不到答案”原则(I.2)。
+4. **[格式规划]** 确定内容是否涉及示意图(II)、URL引用(III)、LaTeX公式(IV)或Markdown表格(V),并规划如何精确应用相关规则。
+5. **[答案生成]** 基于以上分析和规划,生成符合所有【约束和要求】的对话式回答。
+[思考结束,请勿输出此流程内容]
+
+--- 任务输入 ---
+# 知识片段
+{{知识}}
+
+# 用户输入
+{{用户}}
+
+--- 最终回答 ---
+[直接输出对话式回答,不要复述用户问题]`);// 提示语
+const [editPrompt, setEditPrompt] = React.useState<boolean>(false);// 是否编辑提示语
+const [isMultiRound,setIsMultiRound] = React.useState<boolean>(false);// 是否开启多轮对话
+    /*
+     查看引用知识库抽屉end
+    */
+    return (
+        <>
+            <div className='questionAnswerInfo'>
+                <Spin spinning={pageLoading}>
+                    <Form
+                        form={form}
+                        layout='vertical'
+                        initialValues={{
+                            isDeepThink: 'N',
+                            // max_token: 4096,
+                            // model: 'Qwen3-30B',
+                            show_recall_result: true,
+                            // rerank_model_name: 'bge-reranker-v2-m3',
+                            slice_config_type: 'customized',
+                            rerank_status: true,
+                            param_desc: 'strict',
+                            recall_method: 'mixed',
+                            topK: 50,
+                            is_multi_round:isMultiRound
+                        }}
+                    >
+                        <div style={{ display: step === 1 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
+                            <FormItem label='请选择应用图标' tooltip='应用图标' name='iconType' rules={[{ required: true, message: '请选择图标' }]} disabled>
+                                <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
+                                    {/* 左侧预览块(固定) */}
+                                    <div style={{ width: 84, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
+                                        <div style={{ width: 64, height: 64, borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center', background: previewBg, border: '1px solid #e8e8e8' }}>
+                                            {selectedIcon ? (() => { const C = (AllIcons as any)[selectedIcon]; const iconColor = getContrastColor(previewBg); return C ? <C style={{ fontSize: 28, color: iconColor }} /> : <span style={{ fontSize: 12 }}>{selectedIcon}</span> })() : <span style={{ color: '#999', fontSize: 12 }}>预览</span>}
+                                        </div>
+                                    </div>
+                                    {/* 右侧选择区(简洁协调) */}
+                                    <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
+                                        <a onClick={() => setIconPickerVisible(true)} style={{ fontSize: 13, color: '#1677ff', cursor: 'not-allowed', pointerEvents: 'none', opacity: 0.6 }}>选择图标</a>
+                                        <div style={{ display: 'flex', alignItems: 'center', gap: 8, pointerEvents: 'none', opacity: 0.6 }}>
+                                            <div style={{ fontSize: 12, color: '#666' }}>背景色:</div>
+                                            <ColorPicker presets={presetItems} value={previewBg}
+                                                onChange={(color) => {
+                                                    const hex = color.toHexString?.() || color?.toString?.() || previewBg;
+                                                    setPreviewBg(hex);
+                                                    form.setFieldsValue({ iconColor: hex });
+                                                }} />
+                                        </div>
+                                    </div>
+                                </div>
+                            </FormItem>
+                            <FormItem
+                                label='问答应用名称'
+                                tooltip='问答应用名称'
+                                name='name'
+                                rules={[{ required: true, message: '问答应用名称不能为空' }]}
+                                disabled
+                            >
+                                <Input placeholder="请输入问答应用名称" className='form-element-standard' style={{ height: '36px' }} disabled />
+                            </FormItem>
+                            <FormItem
+                                label='应用类型'
+                                tooltip='问答应用类型'
+                                name='typeId'
+                                disabled
+                            >
+                                <Select
+                                    className='form-element-select'
+                                    style={{ height: '36px' }}
+                                    placeholder='请选择问答应用类型'
+                                    onChange={handleAppChange}
+                                    allowClear={true}
+                                    disabled
+                                >
+                                    {
+                                        appTypeList.map((item, index) => {
+                                            return <Option value={item.value} key={index}>
+                                                {item.label}
+                                            </Option>
+                                        })
+                                    }
+                                </Select>
+                            </FormItem>
+                            {
+                                isAppPro &&
+                                <>
+                                    <FormItem
+                                        label='项目'
+                                        tooltip='项目'
+                                        name='appProId'
+                                        rules={[{ required: true, message: '项目不能为空' }]}
+                                        disabled
+                                    >
+                                        <Cascader
+                                            options={appProjectList}
+                                            placeholder="请选择项目"
+                                            showSearch
+                                            className="form-element-select"
+                                            style={{ height: '36px' }}
+                                            disabled
+                                        />
+                                    </FormItem>
+                                </>
+                            }
+                            <FormItem
+                                label='是否公开'
+                                tooltip='是否公开'
+                                name='visible'
+                                disabled
+                            >
+                                <Select
+                                    className='form-element-select'
+                                    style={{ height: '36px' }}
+                                    placeholder='请选择是否公开'
+                                    allowClear={true}
+                                    onChange={(e) => {
+                                        setVisibleFlag(e)
+                                    }}
+                                    disabled
+                                >
+                                    {
+                                        appVisibleList.map((item, index) => {
+                                            return <Option value={item.value} key={index}>
+                                                {item.label}
+                                            </Option>
+                                        })
+                                    }
+                                </Select>
+                            </FormItem>
+                            {userInfo?.tenantId === '000000' && visibleFlag === '0' && <FormItem
+                                label='集团公开'
+                                tooltip='集团公开'
+                                name='groupVisible'
+                                layout='horizontal'
+                                disabled
+                            >
+                                <Switch onChange={onChangeShow} />
+                            </FormItem>}
+                            <FormItem
+                                label='显示顺序'
+                                name='sort'
+                                tooltip='显示顺序,数值越小越靠前'
+                                disabled
+                            >
+                                <InputNumber placeholder="请输入显示顺序" value={''} className='form-element-standard' style={{ height: '36px', lineHeight: '36px' }} disabled />
+                            </FormItem>
+                            {/* VIP用户 */}
+                            {visibleFlag == 1 && <FormItem
+                                label='指定用户'
+                                tooltip='指定可以访问该问答应用的用户'
+                                disabled
+                            >
+                                <div className='tags-info'>
+                                    <p className='tags-list'>
+                                        {vipList.map((item: any) =>
+                                        (<Tag key={item.userId} color="blue" closeIcon={false} onClose={(e) => {
+                                            const newVipList = vipList.filter((vip: any) => vip.userId !== item.userId);
+                                            setVipList(newVipList);
+                                            e.preventDefault();
+                                        }}>
+                                            {item.userName}
+                                        </Tag>)
+                                        )}
+                                    </p>
+                                    <p>
+                                        {vipList.length > 0 && <CloseCircleOutlined className='cup' style={{ pointerEvents: 'none', opacity: 0.6 }} onClick={() => {
+                                            setVipList([]);
+                                        }} />}
+                                        <Button style={{
+                                            background: 'transparent',
+                                            border: '1px solid #1677ff',
+                                            color: '#1677ff'
+                                        }} type="primary" variant="outlined" disabled onClick={() => { setIsModalOpen(true) }}>选择</Button>
+                                    </p>
+                                </div>
+                            </FormItem>}
+                            <FormItem
+                                label='问答应用描述'
+                                tooltip='问答应用描述'
+                                name='desc'
+                                rules={[{ required: true, message: '问答应用描述不能为空' }]}
+                                disabled
+                            >
+                                <TextArea
+                                    showCount
+                                    maxLength={500}
+                                    placeholder="请输入当前应用的描述"
+                                    className='form-textarea-large'
+                                    disabled
+                                />
+                            </FormItem>
+
+                            <div className='preset-questions'>
+                                <h4>添加引导问题</h4>
+                                <div>
+                                    {
+                                        inputs.map(input => (
+                                            <div key={input.id} className='question-item'>
+                                                <label>引导问题 {input.id}</label>
+                                                <Input
+                                                    className='question-input'
+                                                    type="text"
+                                                    value={input.value}
+                                                    onChange={e => handleChange(input.id, e.target.value)}
+                                                    disabled
+                                                />
+                                                <div className='question-actions'>
+                                                    <PlusCircleOutlined className='question-icon' onClick={addInput} style={{ pointerEvents: 'none', opacity: 0.6 }} />
+                                                    <MinusCircleOutlined className='question-icon' onClick={() => delInput(input.id)} style={{ pointerEvents: 'none', opacity: 0.6 }} />
+                                                </div>
+                                            </div>
+                                        ))}
+                                </div>
+                            </div>
+
+                            <div style={{ display: 'flex', gap: '12px', marginTop: '24px', paddingTop: '24px', borderTop: '1px solid #f0f0f0' }}>
+                                <Button
+                                    className='btn-cancel'
+                                    onClick={() => {
+                                        navigate(-1);
+                                    }}
+                                >
+                                    返回
+                                </Button>
+                                <Button
+                                    type='primary'
+                                    onClick={() => {
+                                        form.validateFields(['name', 'desc', 'appProId', 'iconType']).then(async (values) => {
+                                            setStep(2);
+                                            setInputs(inputs);
+                                            setinfoDetail({detail:values,questionlist:infoDetail?.questionlist||[]});
+                                        }).catch((error) => {
+                                            console.error(error);
+                                        });
+                                    }}
+                                >
+                                    下一步
+                                </Button>
+                            </div>
+                        </div>
+                        <div style={{ display: step === 2 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
+                            <div className='flex-between padding-bottom-16'>
+                                <div>
+                                    <Button
+                                        className='btn-back'
+                                        icon={<ArrowLeftOutlined />}
+                                        onClick={() => {
+                                            setStep(1);
+                                        }}
+                                    >
+                                        上一步
+                                    </Button>
+                                </div>
+                                <div style={{ display: 'flex', gap: '12px' }}>
+                                    <Button
+                                        className='btn-cancel'
+                                        disabled={true}
+                                        onClick={() => {
+                                            // navigate({ pathname: '/appCenter/questionAnswer' });
+                                        }}
+                                    >
+                                        取消
+                                    </Button>
+                                    {/* {
+                                        appId && (
+                                            <Tooltip title='保存'>
+                                                <Button
+                                                    className='btn-cancel'
+                                                    onClick={() => {
+                                                        saveConfig('SAVE');
+                                                    }}
+                                                    icon={<FileDoneOutlined />}
+                                                >
+                                                </Button>
+                                            </Tooltip>)
+                                    } */}
+
+                                    {createFlag && (
+                                        <Button
+                                            type='primary'
+                                            disabled={true}
+                                            onClick={() => {
+                                                saveConfig('SUBMIT');
+                                            }}
+                                        >
+                                            提交应用
+                                        </Button>
+                                    )}
+                                </div>
+                            </div>
+                            <Splitter style={{ border: '1px solid #f0f0f0', borderRadius: '6px', height: 'calc(100vh - 180px)', minHeight: 0 }}>
+                                {<Splitter.Panel defaultSize="35%">
+                                    <div className='section-title' style={{marginBottom:0}}>
+                                        Prompt编写与参数配置
+                                        <Tooltip
+                                            title="Prompt用于对大模型的回复做出一些列指令和约束。这段Prompt不会被用户看到。"
+                                            placement="right"
+                                        >
+                                            <InfoCircleOutlined style={{ marginLeft: '8px', color: '#999', fontSize: '14px' }} />
+                                        </Tooltip>
+                                        {/* <Switch checkedChildren="编辑" unCheckedChildren="只读" style={{marginLeft:'5px'}} value={editPrompt} onChange={(e) => {
+                                            setEditPrompt(e)
+                                        }} /> */}
+                                    </div>
+                                    <div className='prompt'>
+                                        <div className='prompt-info'>
+                                            <div className='prompt-info-text'>
+                                                <Typography.Paragraph style={{ fontSize: '12px', lineHeight: '1.6', color: '#999', margin: 0 }}>
+                                                    编写Prompt过程中可以引入2项变量:
+                                                    <span className='variable-highlight'>{'{{知识}}'}</span>
+                                                    代表知识库中检索到的知识内容,
+                                                    <span className='variable-highlight'>{'{{用户}}'}</span>
+                                                    代表用户输入的内容。您可以在编写Prompt过程中将变量拼接在合适的位置。
+                                                </Typography.Paragraph>
+                                            </div>
+                                        </div>
+                                        {/* 移除 Divider,使用 CSS 边框替代 */}
+                                        <div className='prompt-editor-area'>
+                                            <FormItem name='prompt'
+                                                tooltip='Prompt用于对大模型的回复做出一些列指令和约束。这段Prompt不会被用户看到。'
+                                                initialValue={
+                                                    promptValue
+                                                }
+                                                
+                                                rules={[{ required: true, message: '提示词不能为空' }]}>
+                                                <TextArea
+                                                    disabled={true}
+                                                    placeholder="提示词"
+                                                    rows={50}
+                                                />
+                                            </FormItem>
+                                        </div>
+                                    </div>
+                                </Splitter.Panel>}
+                                <Splitter.Panel defaultSize="30%">
+                                    <div className='flex-center-container'>
+                                        <div className='half-width'>
+                                            <div className='pl-20 pt-3 text-[#000000]'>
+                                                {/* 参数配置 {name || '问答应用'} */}
+                                                <span className='mr-[6px]' >参数配置</span>  <Switch disabled={true} checkedChildren="手动" unCheckedChildren="自动" value={automatic} onChange={(e) => {
+                                                    console.log(e, 'e')
+                                                    setAutomatic((pre) => !pre)
+                                                    if (!e) {
+                                                        form.setFieldsValue({
+                                                            param_desc: 'strict',
+                                                            topK: 50
+                                                        })
+                                                    }
+                                                }} />
+
+                                            </div>
+                                            <div className='flex-start pl-20 mt-3'>
+                                                <FormItem
+                                                    label='引用知识库'
+                                                    tooltip='请选择需要引用的知识库'
+                                                    name='knowledge_ids'
+                                                    
+                                                    rules={[{ required: true, message: '知识库不能为空' }]}>
+                                                    <Select
+                                                        mode='multiple'
+                                                        disabled={true}
+                                                        maxCount={MAX_COUNT}
+                                                        showSearch={true}
+                                                        filterOption={(input, option) => (option?.children as unknown as string)?.toLowerCase()?.includes(input.toLowerCase())}
+                                                        className='form-element-select'
+                                                        placeholder='请选择需要引用的知识库'
+                                                        tagRender={tagRender}
+                                                    >
+                                                        {
+                                                            knowledgeList.map((item, index) => {
+                                                                return <Option value={item.value} key={index}>
+                                                                    {item.label}
+                                                                </Option>
+                                                            })
+                                                        }
+                                                    </Select>
+                                                </FormItem>
+                                            </div>
+                                            <div className='flex-start pl-20'>
+                                                <FormItem
+                                                    label='调用模型'
+                                                    tooltip='请选择调用的模型'
+                                                    name="model"
+                                                    rules={[{ required: true, message: '模型不能为空' }]}>
+                                                    <Select
+                                                        placeholder='请选择模型'
+                                                        className='form-element-select'
+                                                        disabled={true}
+                                                        onChange={(value) => {
+                                                            // if (value === 'Qwen3-30B') {
+                                                            //     setIsDeepThinkVisible(true);
+                                                            // } else {
+                                                            //     setIsDeepThinkVisible(false);
+                                                            // }
+                                                            const list = modeOldList.filter((item: any) => item.model === value)
+                                                            // console.log(list, 'list');
+                                                            form.setFieldsValue({
+                                                                max_token: list[0]?.maxToken,
+                                                                rerank_model_name: list[0]?.bindingModel
+                                                            })
+
+                                                        }}
+                                                    >
+                                                        {/* <Option value='Qwen3-30B'>Qwen3-30B</Option> */}
+                                                        {modeList.map((item: any, index: number) => (
+                                                            <Option value={item.value} key={index}>
+                                                                {item.label}
+                                                            </Option>
+                                                        ))}
+                                                    </Select>
+
+                                                </FormItem>
+                                            </div>
+                                            <div className='flex-start pl-20'>
+                                                <FormItem
+                                                    label='max token'
+                                                    name='max_token'
+                                                    tooltip='max token的最大长度限制'
+                                                    rules={[{ required: true, message: 'max token不能为空' }]}>
+                                                    <InputNumber
+                                                        disabled
+                                                        className='form-element-input-number'
+                                                    />
+                                                </FormItem>
+                                            </div>
+
+                                            {
+                                                !isVisible &&
+                                                <div className='flex-start pl-20'>
+                                                    <a onClick={() => {
+                                                        setIsVisible(!isVisible);
+                                                    }} className='link-more-settings'>
+                                                        更多设置
+                                                    </a>
+                                                </div>
+
+                                            }
+                                            {/* {isVisible && */}
+                                            <div style={{ display: isVisible ? 'block' : 'none', paddingTop: '20px' }}>
+                                                {isVisibleCus && automatic &&
+                                                    <Space style={{ width: '100%' }} direction="vertical">
+                                                        <div className='flex-start pl-20'>
+                                                            <FormItem
+                                                                label='Top-p'
+                                                                name='topP'
+                                                                tooltip='Top-p参数控制生成文本的多样性,值越大生成的文本越多样化'
+                                                                className='form-element-standard'
+                                                            >
+                                                                <TopPDecimalStep />
+                                                            </FormItem>
+                                                        </div>
+                                                        <div className='flex-start pl-20'>
+                                                            <FormItem
+                                                                label='Temperature'
+                                                                name='temperature'
+                                                                className='form-element-standard'
+                                                            >
+                                                                <TempDecimalStep />
+                                                            </FormItem>
+                                                        </div>
+                                                    </Space>
+                                                }
+
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='回答风格'
+                                                        name='param_desc'
+                                                        tooltip='请选择回答风格'
+                                                        rules={[{ required: true, message: '回答风格不能为空' }]}>
+                                                        <Radio.Group buttonStyle="solid"
+                                                        disabled={true}
+                                                            className='form-element-button-group'>
+                                                            <Radio.Button onClick={() => {
+                                                                handleRedioClick('strict')
+                                                            }} value='strict'>严谨</Radio.Button>
+                                                            <Radio.Button onClick={() => {
+                                                                handleRedioClick('moderate')
+                                                            }} value='moderate'>适中</Radio.Button>
+                                                            <Radio.Button onClick={() => {
+                                                                handleRedioClick('flexib')
+                                                            }} value='flexib'>发散</Radio.Button>
+                                                            {automatic && <Radio.Button value='custom'
+                                                                onClick={() => {
+                                                                    setIsVisibleCus(!isVisibleCus);
+                                                                    setTopPValue(0.1);
+                                                                    setTempValue(0.01);
+                                                                }}
+                                                            >自定义
+                                                            </Radio.Button>}
+                                                        </Radio.Group>
+                                                    </FormItem>
+                                                </div>
+
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='展示引用知识'
+                                                        tooltip='是否在回答中展示引用的知识内容'
+                                                        name='show_recall_result'
+                                                        className='form-element-standard'>
+                                                        <Switch disabled={true} onChange={onChangeShow} />
+                                                    </FormItem>
+                                                </div>
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='召回方式'
+                                                        tooltip='请选择召回方式'
+                                                        name='recall_method'
+                                                        rules={[{ required: true, message: '召回方式不能为空' }]}>
+
+                                                        <Radio.Group
+                                                        disabled={true}
+                                                            style={style}
+                                                            onChange={onChangeRecallMethod}
+                                                            options={[
+                                                                { value: 'embedding', label: '向量化检索' },
+                                                                { value: 'keyword', label: '关键词检索' },
+                                                                { value: 'mixed', label: '混合检索' },
+                                                            ]}
+                                                        />
+                                                    </FormItem>
+                                                </div>
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <div className='section-title'>重排方式</div>
+                                                </div>
+                                                {/* <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='Rerank模型'
+                                                        tooltip='是否开启Rerank模型对检索结果进行重排'
+                                                        name='rerank_status'
+                                                        valuePropName='checked'
+                                                        className='form-control-width'
+                                                    >
+                                                        <Switch onChange={onChangeModel} />
+                                                    </FormItem>
+                                                </div> */}
+                                                {/* {isVisibleRerank && */}
+                                                {
+                                                    <div style={{
+                                                        display: 'flex',
+                                                        justifyContent: 'flex-start',
+                                                        alignItems: 'center'
+                                                    }} className='pl-20'>
+                                                        <FormItem
+                                                            label='Rerank模型'
+                                                            tooltip='请选择Rerank模型'
+                                                            name='rerank_model_name'
+                                                        >
+                                                           <Input
+                                                            disabled
+                                                            type="text"
+                                                        />
+                                                        </FormItem>
+                                                    </div>
+                                                }
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='召回切片数量'
+                                                        name='slice_config_type'
+                                                        tooltip='请选择召回方式'
+                                                        rules={[{ required: true, message: '召回方式不能为空' }]}>
+                                                        <Select
+                                                            disabled={true}
+                                                            // className='questionAnswerInfo-content-title'
+                                                            className='form-element-select'
+                                                            placeholder='请选择'
+                                                            onChange={onChangeCount}>
+                                                            <Option value="fixed">手动设置</Option>
+                                                            <Option value="customized">自动设置</Option>
+                                                        </Select>
+                                                    </FormItem>
+                                                </div>
+
+                                                {isVisibleSlice &&
+                                                    <div style={{
+                                                        display: 'flex',
+                                                        justifyContent: 'flex-start',
+                                                        alignItems: 'center'
+                                                    }} className='pl-20'>
+                                                        <FormItem
+                                                            label='召回切片数'
+                                                            tooltip='请输入召回切片数'
+                                                            name='slice_count'
+                                                            rules={[{ required: true, message: '切片数不能为空' }]}>
+                                                            <InputNumber max={1024} changeOnWheel
+                                                                // className='questionAnswerInfo-content-title'
+                                                                className='form-element-standard'
+                                                            />
+                                                        </FormItem>
+                                                    </div>
+                                                }
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='是否开启多轮对话'
+                                                        name='is_multi_round'
+                                                        tooltip='请选择召回方式'>
+                                                            <Switch value={isMultiRound} onChange={(e)=>{
+                                                                setIsMultiRound(e)
+                                                            }} />
+                                                    </FormItem>
+                                                </div>
+
+                                                {isMultiRound &&
+                                                    <div style={{
+                                                        display: 'flex',
+                                                        justifyContent: 'flex-start',
+                                                        alignItems: 'center'
+                                                    }} className='pl-20'>
+                                                        <FormItem
+                                                            label='多轮对话次数'
+                                                            tooltip='请输入多轮对话次数(1-10次)'
+                                                            name='multi_round'
+                                                            rules={[{ required: true, message: '多轮对话次数不能为空' }]}>
+                                                            <InputNumber max={10} min={1} changeOnWheel
+                                                                // className='questionAnswerInfo-content-title'
+                                                                className='form-element-standard'
+                                                            />
+                                                        </FormItem>
+                                                    </div>
+                                                }
+                                            </div>
+                                            {/* } */}
+                                        </div>
+                                    </div>
+                                </Splitter.Panel>
+                                {/* {appId && (<Splitter.Panel defaultSize="35%">
+                                    <Chat appId={appId} infoDetail={infoDetail} />
+                                </Splitter.Panel>)} */}
+                                {(infoDetail&&<Splitter.Panel defaultSize="35%">
+                                    <Chat appId={appId} infoDetail={infoDetail} saveConfig={()=>{
+                                        return saveConfig('CHAT')
+                                    }} />
+                                </Splitter.Panel>)}
+                            </Splitter>
+                        </div>
+                    </Form>
+                </Spin>
+            </div >
+            {isModalOpen && vipModal()}
+            {DrawerDetail()}
+            <IconPicker
+                open={iconPickerVisible}
+                onClose={() => setIconPickerVisible(false)}
+                onSelect={(name) => {
+                    setSelectedIcon(name);
+                    form.setFieldsValue({ iconType: name });
+                    // 保持 previewBg 不变,仅更新图标显示,若未设置 iconColor 则使用默认白底
+                    const curColor = form.getFieldValue('iconColor') || previewBg;
+                    setPreviewBg(curColor || '#ffffff');
+                }}
+                value={selectedIcon}
+            />
+        </>
+    );
+};
+
+export default observer(QuestionAnswerInfo);

+ 193 - 0
src/pages/deepseek/audit/components/auditHistory.tsx

@@ -0,0 +1,193 @@
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import { Table, TableColumnsType, TablePaginationConfig, Drawer } from 'antd';
+import { StepForwardOutlined } from '@ant-design/icons';
+import dayjs from 'dayjs';
+import store from './auditHistoryStore';
+import { Record } from '../types';
+import '../style.less';
+import InfoModal from './InfoModal';
+import PreviewModal from './PreviewModal';
+import LocalStorage from '@/LocalStorage';
+
+
+interface AuditHistoryProps {
+    open: boolean;
+    onClose: () => void;
+}
+
+const AuditHistory: React.FC<AuditHistoryProps> = ({ open, onClose }) => {
+    const {
+        state,
+        init,
+        onChangePagination,
+        onClickModify,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        infoModalOnClickClose,
+    } = store;
+    const {
+        listLoading,
+        list,
+        infoModalId,
+        infoModalOpen,
+        page
+    } = state;
+
+    const [drawerFlag, setDrawerFlag] = React.useState<boolean>(false);
+    const [drawerData, setDrawerData] = React.useState<any>({});
+    React.useEffect(() => {
+        if(open){
+            const userInfo = LocalStorage.getUserInfo();
+            const userId = (userInfo?.id ?? '').toString();
+            init(userId);
+        }
+    }, [open]);
+    const columns: TableColumnsType<Record> = [
+        {
+            title: '序号',
+            dataIndex: 'index',
+            width: 80,
+            render: (_text, _record, index) => {
+                return index + 1;
+            }
+        },
+        {
+            title: '知识名称',
+            dataIndex: 'name',
+            width: 300,
+            render: (text, record) => {
+                // const previewUrl = `/preview/${record.url}`; // 根据实际字段构造 URL
+                return (
+                    <a
+                        href={record.url}
+                        target="_blank"
+                        rel="noopener noreferrer"
+                        onClick={(e) => {
+                            e.stopPropagation(); // 防止 Table 默认事件干扰
+                        }}
+                    >
+                        {text}
+                    </a>
+                );
+            }
+        },
+        {
+            title: '状态',
+            dataIndex: 'status',
+            render: (text) => {
+                if (text === '1') {
+                    return '待审核';
+                } else if (text === '2') {
+                    return '审核中';
+                } else if (text === '3') {
+                    return '审核通过';
+                } else if (text === '4'||text === '5') {
+                    return '审核拒绝';
+                }
+            }
+        },
+        {
+            title: '审核人',
+            dataIndex: 'userName',
+            render: (text) => {
+                return `${text}`;
+            }
+        },
+        {
+            title: '审核意见',
+            dataIndex: 'comment',
+            render: (text) => {
+                if (text) {
+                    return `${text}`;
+                } else {
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            width: 200,
+            render: (text) => {
+                if (text) {
+                    return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+                } else {
+                    return '--';
+                }
+            }
+        },
+        // {
+        //     title: '操作',
+        //     dataIndex: 'operation',
+        //     width: 150,
+        //     fixed: 'right',
+        //     render: (_text, record) => {
+        //         return (
+        //             <>
+        //                 <a
+        //                     style={{ marginRight: 16 }}
+        //                     onClick={() => {
+        //                         setDrawerFlag(true)
+        //                         setDrawerData(record)
+        //                     }}
+        //                     title='查看'
+        //                 >
+        //                     查看
+        //                 </a >
+        //                 <a
+        //                     style={{ marginRight: 16 }}
+        //                     onClick={() => {
+        //                         onClickModify(record.appId);
+        //                     }}
+        //                     title='审核'
+        //                 >
+        //                     <StepForwardOutlined />审核
+        //                 </a >
+        //             </>
+        //         )
+        //     }
+        // }
+    ];
+    const paginationConfig: TablePaginationConfig = {
+        // 显示数据总量
+        showTotal: (total: number) => {
+            return `共 ${total} 条`;
+        },
+        // 展示分页条数切换
+        showSizeChanger: true,
+        // 指定每页显示条数
+        pageSizeOptions: ['10', '20', '50', '100'],
+        // 快速跳转至某页
+        showQuickJumper: true,
+        current: page.pageNum,
+        pageSize: page.pageSize,
+        total: page.total,
+        onChange: async (page, pageSize) => {
+            await onChangePagination(page, pageSize);
+        },
+    };
+
+    return (
+        <Drawer
+            title="审核历史"
+            width="80%"
+            open={open}
+            onClose={onClose}
+        >
+            <div className='knowledgeLibList'>
+                <div className='knowledgeLibList-table'>
+                    <Table
+                        scroll={{ x: 'max-content' }}
+                        rowKey={(record) => record.createTime}
+                        loading={listLoading}
+                        columns={columns}
+                        dataSource={list}
+                        pagination={paginationConfig}
+                    />
+                </div>
+            </div>
+        </Drawer>
+    );
+}
+export default observer(AuditHistory);

+ 193 - 0
src/pages/deepseek/audit/components/auditHistoryStore.ts

@@ -0,0 +1,193 @@
+import { makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import { apis, ModifyDocumentApiParams } from '@/apis';
+import { State, ReadonlyState, StateAction, DocumentLibListStore } from '../types';
+
+// 定义状态
+const stateGenerator = (): ReadonlyState => ({
+    listLoading: false,
+    list: [],
+    infoModalId: '',
+    infoModalOpen: false,
+    page: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0,
+    },
+});
+
+// 修改状态
+const stateActionsGenerator = (state: State): StateAction => {
+    return {
+        setListLoading: (loading) => {
+            state.listLoading = loading;
+        },
+        setList: (list) => {
+            state.list = list;
+        },
+        setInfoModalId: (id) => {
+            state.infoModalId = id;
+        },
+        setInfoModalOpen: (open) => {
+            state.infoModalOpen = open;
+        },
+        setPage: (page) => {
+            state.page = page;
+        },
+    };
+};
+
+// 使用仓库
+const useKnowledgeLibListStore = (): DocumentLibListStore => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    const api = {
+        // 获取审核列表
+        fetchApplicationLibList: async (userId: string) => {
+            actions.setListLoading(true);
+            try {
+                const data = {
+                    pageNumber: state.page.pageNum,
+                    pageSize: state.page.pageSize,
+                    approver: userId,
+                };
+                const res:any = await apis.fetchAuditHistoryList(data);
+                console.log(res.rows, 'rew.rows');
+                actions.setList(res.rows);
+                actions.setPage({
+                    ...state.page,
+                    total: res.total,
+                });
+            } catch (error: any) {
+                console.error(error);
+            } finally {
+                actions.setListLoading(false);
+            }
+        },
+        
+        // 应用审核
+        modifyDocumentLib: async (documentId: string, userId: string, data: ModifyDocumentApiParams) => {
+            try {
+                const res = await apis.modifyTakaiAuditDocumentLibApi(documentId, data);
+                // 获取审核列表
+                api.fetchApplicationLibList(userId);
+                if(res.data === 1 && res.code === 200){
+                    message.success('修改成功');
+                }else{
+                    message.error('修改失败');
+                }
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+        // 获取详情
+        fetchTakaiApplicationDetail: async (appId: string) => {
+            try {
+                const res = await apis.fetchTakaiApplicationDetail(appId);
+                console.log(res, 'resresres');
+                return res;
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+    }
+    // 点击查看出现弹窗
+    const onClickfetchTakaiApplicationDetail = async (appId: string) => {
+        if(appId){
+            await api.fetchTakaiApplicationDetail(appId);
+        }
+    }
+    // 更改分页
+    const onChangePagination: DocumentLibListStore['onChangePagination'] = async (pageNumber, pageSize) => {
+        actions.setPage({
+            ...state.page,
+            pageNum: pageNumber,
+            pageSize: pageSize,
+        });
+        // 获取知识库列表
+        await api.fetchApplicationLibList('');
+    }
+
+    // 点击创建
+    const onClickCreate: DocumentLibListStore['onClickCreate'] = () => {
+        const initialInfoModalId = stateGenerator().infoModalId;
+
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 点击修改
+    const onClickModify: DocumentLibListStore['onClickModify'] = (documentId) => {
+        actions.setInfoModalId(documentId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 信息弹出层-点击通过
+    const infoModalOnClickConfirm: DocumentLibListStore['infoModalOnClickConfirm'] = async (documentId, userId, data) => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+        if (documentId) {
+            // 审核通过
+            console.log(data, 'datadata');
+            await api.modifyDocumentLib(documentId, userId, data);
+        } 
+    }
+
+    // 信息弹出层-点击拒绝
+    const infoModalOnClickCancel: DocumentLibListStore['infoModalOnClickCancel'] = async(documentId, userId, data) => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+        if (documentId) {
+            // 审核拒绝
+            await api.modifyDocumentLib(documentId, userId, data);
+        } 
+    }
+
+    const infoModalOnClickClose: DocumentLibListStore['infoModalOnClickClose'] = () => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+    }
+
+    
+    // 初始渲染
+    const init: DocumentLibListStore['init'] = async (userId) => {
+        // 获取知识库列表
+        await api.fetchApplicationLibList(userId);
+    }
+
+    // 状态重置
+    const reset: DocumentLibListStore['reset'] = () => {
+        const initialListLoading = stateGenerator().listLoading;
+        const initialList = stateGenerator().list;
+        const initialInfoModalId = stateGenerator().infoModalId;
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+        const initialPage = stateGenerator().page;
+
+        actions.setListLoading(initialListLoading);
+        actions.setList(initialList);
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(initialInfoModalOpen);
+        actions.setPage(initialPage);
+    }
+
+    return {
+        state,
+        onChangePagination,
+        onClickCreate,
+        onClickModify,
+        onClickfetchTakaiApplicationDetail,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        infoModalOnClickClose,
+        init,
+        reset
+    };
+};
+
+export default useKnowledgeLibListStore();

+ 998 - 0
src/pages/deepseek/audit/components/style.less

@@ -0,0 +1,998 @@
+// 主容器样式
+.questionAnswerInfo {
+  width: 100%;
+  height: 100%;
+  background: #FFFFFF;
+  border-radius: @border-radius-base;
+
+  // 内容区域
+  &-content {
+    width: 100%;
+    height: 100%;
+    background: #FFFFFF;
+    padding: 16px 20px;
+
+    // 标题样式
+    &-title {
+      width: 100%;
+      max-width: 646px;
+      height: 48px;
+    }
+  }
+  .ant-input-underlined[disabled], 
+  .ant-select-selector,
+  .ant-input-number-input, 
+  .ant-input-affix-wrapper >textarea.ant-input{
+    color: rgba(48,49,51,0.88) !important;
+  }
+}
+
+
+
+// 通用布局样式
+.flex {
+  &-center {
+    &-container {
+      width: 100%;
+      height: 100%;
+      background: #f5f5f5;
+    }
+
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    &-top {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      padding-top: 50px;
+      font-size: 16px;
+    }
+  }
+
+  &-between {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  &-end {
+    display: flex;
+    justify-content: flex-end;
+  }
+}
+
+// 按钮样式
+.btn {
+  &-cancel {
+    background: #f5f5f5;
+    border: none;
+    color: #000000;
+    transition: all 0.3s ease;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+
+    &:hover {
+      background: #e8e8e8;
+      color: #000000;
+      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+      transform: translateY(-1px);
+    }
+
+    &:active {
+      background: #dcdcdc;
+      color: #000000;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+      transform: translateY(0);
+    }
+
+    &:focus {
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    }
+  }
+
+  &-back {
+    background: #ffffff;
+    border: 1px solid #f0f0f0;
+    color: #595959;
+    transition: all 0.3s ease;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+
+    &:hover {
+      background: #fafafa;
+      border-color: #40a9ff;
+      color: #40a9ff;
+      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+      transform: translateY(-1px);
+    }
+
+    &:active {
+      background: #f0f0f0;
+      border-color: #1890ff;
+      color: #1890ff;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+      transform: translateY(0);
+    }
+
+    &:focus {
+      border-color: #40a9ff;
+      box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+    }
+  }
+}
+
+// 表单样式
+.form {
+  &-control {
+    &-width {
+      width: 100%;
+      max-width: 646px;
+    }
+
+    &-height {
+      height: 48px;
+    }
+  }
+
+  &-input {
+    &-large {
+      width: 100%;
+      max-width: 646px;
+      padding: 8px;
+    }
+
+    &-number-small {
+      margin: 0 16px;
+      width: 100px;
+    }
+  }
+
+  &-textarea {
+    &-large {
+      height: 120px;
+      resize: none;
+      width: 100%;
+      max-width: 646px;
+    }
+  }
+}
+
+// 文本区域样式
+.textarea {
+  &-full-width {
+    width: 100%;
+  }
+
+  &-fixed-height {
+    height: 300px;
+  }
+}
+
+// 预设问题区域样式
+.preset-questions {
+  margin: 24px 0;
+
+  h4 {
+    margin-bottom: 16px;
+    color: #262626;
+  }
+
+  .question-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
+    flex-wrap: wrap;
+    gap: 12px;
+
+    label {
+      min-width: 60px;
+      color: #595959;
+      flex-shrink: 0;
+    }
+
+    .question-input {
+      flex: 1;
+      min-width: 200px;
+      max-width: 400px;
+      margin: 0;
+    }
+
+    .question-actions {
+      display: flex;
+      gap: 8px;
+      flex-shrink: 0;
+
+      .question-icon {
+        margin: 0;
+        font-size: 18px;
+        color: @primary-color;
+        cursor: pointer;
+        transition: all 0.3s ease;
+
+        &:hover {
+          color: @primary-color;
+          transform: scale(1.1);
+        }
+      }
+    }
+  }
+}
+
+// 问题输入框样式(保留向后兼容)
+.question-input {
+  width: 100%;
+  max-width: 300px;
+  padding-top: 8px;
+  margin-left: 20px;
+}
+
+.link-more-settings {
+  color: @primary-color;
+  cursor: pointer;
+  text-decoration: none;
+
+  &:hover {
+    text-decoration: underline;
+  }
+}
+
+// 标题和链接样式
+.section-title {
+  font-size: 14px;
+  font-weight: 500;
+  color: #262626;
+  margin-bottom: 12px;
+}
+
+// Prompt编辑器布局样式
+.prompt {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  // 滚动条
+  overflow-y: auto;
+
+  // 提示词模板显示区域
+  &-info {
+    padding: 16px 20px 10px 20px;
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+
+    &-text {
+      // 说明文本
+
+      .variable-highlight {
+        color: #1890ff;
+        font-weight: 500;
+        padding: 2px 6px;
+        border-radius: 4px;
+        font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+        margin: 0 2px;
+      }
+    }
+  }
+
+  // 提示词编辑区域
+  &-editor-area {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+
+    .ant-form-item {
+      margin-bottom: 0;
+      height: 100%;
+
+      .ant-form-item-control {
+        height: 100%;
+
+        .ant-form-item-control-input {
+          height: 100%;
+
+          .ant-form-item-control-input-content {
+            height: 100%;
+
+            .ant-input {
+              height: 100%;
+              border: 1px solid #f0f0f0;
+              border-radius: 8px;
+              padding: 16px;
+              font-size: 14px;
+              line-height: 1.6;
+              resize: none;
+
+              &:focus {
+                border-color: #1890ff;
+                box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+              }
+
+              &::placeholder {
+                color: #bfbfbf;
+                font-style: italic;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.half-width {
+  margin: 0 auto;
+  width: 50%;
+  height: 100%;
+}
+
+// 间距样式
+.padding {
+  &-top {
+    &-10 {
+      padding-top: 10px;
+    }
+
+    &-20 {
+      padding-top: 20px;
+    }
+  }
+
+  &-bottom {
+    &-10 {
+      padding-bottom: 10px;
+    }
+
+    &-12 {
+      padding-bottom: 12px;
+    }
+
+    &-16 {
+      padding-bottom: 16px;
+    }
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .questionAnswerInfo {
+    &-content {
+      &-title {
+        max-width: 100%;
+      }
+    }
+  }
+
+  .form {
+    &-control-width,
+    &-input-large,
+    &-textarea-large {
+      max-width: 100%;
+    }
+  }
+
+  .question-input {
+    max-width: 100%;
+    margin-left: 0;
+  }
+
+  .half-width {
+    width: 100%;
+  }
+
+  .preset-questions {
+    .question-item {
+      flex-direction: column;
+      align-items: flex-start;
+      gap: 8px;
+
+      label {
+        min-width: auto;
+      }
+
+      .question-input {
+        width: 100%;
+        max-width: 100%;
+        min-width: auto;
+      }
+
+      .question-actions {
+        align-self: flex-end;
+      }
+    }
+  }
+}
+
+@media (max-width: 480px) {
+  .questionAnswerInfo {
+    &-content {
+      padding: 16px;
+    }
+  }
+
+  .form {
+    &-input-large,
+    &-textarea-large {
+      padding: 6px;
+    }
+  }
+
+  .preset-questions {
+    .question-item {
+      .question-actions {
+        align-self: center;
+        width: 100%;
+        justify-content: center;
+      }
+    }
+  }
+}
+
+
+// 主容器样式
+.questionAnswerInfo {
+  width: 100%;
+  height: 100%;
+  background: #FFFFFF;
+  border-radius: @border-radius-base;
+  .pl-20{
+    padding-left: 20px;
+  }
+  // 内容区域
+  &-content {
+    width: 100%;
+    height: 100%;
+    background: #FFFFFF;
+    padding: 16px 20px;
+
+    // 标题样式
+    &-title {
+      width: 100%;
+      max-width: 646px;
+      height: 48px;
+    }
+  }
+  .tags-info{
+    border: 1px solid #d9d9d9;
+    width: 100%;
+    max-width: 646px;
+    min-height: 46px;
+    border-radius: 5px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    flex-wrap: wrap;
+    padding: 2px 5px;
+    .tags-list{
+      width: 80%;
+    }
+  }
+}
+.modal_top{
+  display: flex;
+  gap: 10px;
+  margin-bottom: 10px;
+  .ant-input{
+    width: 200px !important;
+  }
+  .ant-input-affix-wrapper{
+    width: auto !important;
+  }
+}
+.ant-btn-outlined {
+    background: 'transparent' !important;
+    border: '1px solid #1677ff';
+    color: '#1677ff';
+}
+.cup{
+  cursor: pointer;
+  margin-right: 10px;
+}
+// 通用布局样式
+.flex {
+  &-center {
+    &-container {
+      width: 100%;
+      min-height: 100%;
+      background: #ffffff;
+      // 移除浅灰色背景,让父级背景色生效
+    }
+
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    &-top {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      padding-top: 50px;
+      font-size: 16px;
+    }
+  }
+
+  &-between {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  &-start {
+    display: flex;
+    justify-content: flex-start;
+  }
+  &-end {
+    display: flex;
+    justify-content: flex-end;
+  }
+}
+
+// 按钮样式
+.btn {
+  &-cancel {
+    background: #f5f5f5;
+    border: none;
+    color: #000000;
+    transition: all 0.3s ease;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+
+    &:hover {
+      background: #e8e8e8;
+      color: #000000;
+      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+      transform: translateY(-1px);
+    }
+
+    &:active {
+      background: #dcdcdc;
+      color: #000000;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+      transform: translateY(0);
+    }
+
+    &:focus {
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    }
+  }
+
+  &-back {
+    background: #ffffff;
+    border: 1px solid #f0f0f0;
+    color: #595959;
+    transition: all 0.3s ease;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+
+    &:hover {
+      background: #fafafa;
+      border-color: #40a9ff;
+      color: #40a9ff;
+      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
+      transform: translateY(-1px);
+    }
+
+    &:active {
+      background: #f0f0f0;
+      border-color: #1890ff;
+      color: #1890ff;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+      transform: translateY(0);
+    }
+
+    &:focus {
+      border-color: #40a9ff;
+      box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+    }
+  }
+}
+
+// 表单样式
+.form {
+  &-control {
+    &-width {
+      width: 100%;
+      max-width: 646px;
+    }
+
+    &-height {
+      height: 48px;
+    }
+  }
+
+  &-input {
+    &-large {
+      width: 100%;
+      max-width: 646px;
+      height: 48px;
+      padding: 8px;
+    }
+
+    &-number-small {
+      margin: 0 16px;
+      width: 100px;
+    }
+  }
+
+  &-textarea {
+    &-large {
+      height: 96px;
+      resize: none;
+      width: 100%;
+      min-width: 200px;
+      max-width: 646px;
+    }
+  }
+
+  // 统一表单元素宽度样式
+  &-element {
+    &-standard {
+      width: 100%;
+      max-width: 646px;
+      min-width: 200px;
+    }
+
+    &-full-width {
+      width: 100%;
+    }
+
+    &-button-group {
+      width: 100%;
+      max-width: 646px;
+      display: flex;
+      
+      .ant-radio-group {
+        width: 100%;
+        display: flex;
+        
+        .ant-radio-button-wrapper {
+          flex: 1;
+          text-align: center;
+        }
+      }
+    }
+
+    &-select {
+      width: 100%;
+      max-width: 646px;
+      min-width: 200px;
+    }
+
+    &-input-number {
+      width: 100%;
+      max-width: 646px;
+      min-width: 200px;
+    }
+  }
+}
+
+// Splitter 面板背景样式
+.ant-splitter-panel {
+  &:first-child {
+    // 左侧 35% 区域 - Prompt 区域
+    background: #ffffff;
+  }
+  
+  &:nth-child(2) {
+    // 中间 30% 区域 - 配置区域
+    background: #f5f5f5;
+  }
+  
+  &:last-child {
+    // 右侧 35% 区域 - 聊天区域保持白色背景
+    background: #ffffff;
+  }
+}
+
+// 更多设置区域统一样式
+.more-settings-section {
+  padding-top: 20px;
+  
+  .flex-center {
+    margin-bottom: 20px;
+  }
+  
+  .section-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #303133;
+    text-align: center;
+    margin: 20px 0;
+  }
+}
+
+// 文本区域样式
+.textarea {
+  &-full-width {
+    width: 100%;
+  }
+
+  &-fixed-height {
+    height: 300px;
+  }
+}
+
+// 预设问题区域样式
+.preset-questions {
+  margin: 24px 0;
+
+  h4 {
+    margin-bottom: 16px;
+    color: #262626;
+  }
+
+  .question-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
+    flex-wrap: wrap;
+    gap: 12px;
+
+    label {
+      min-width: 60px;
+      color: #595959;
+      flex-shrink: 0;
+    }
+
+    .question-input {
+      flex: 1;
+      min-width: 200px;
+      max-width: 400px;
+      margin: 0;
+    }
+
+    .question-actions {
+      display: flex;
+      gap: 8px;
+      flex-shrink: 0;
+
+      .question-icon {
+        margin: 0;
+        font-size: 18px;
+        color: @primary-color;
+        cursor: pointer;
+        transition: all 0.3s ease;
+
+        &:hover {
+          color: @primary-color;
+          transform: scale(1.1);
+        }
+      }
+    }
+  }
+}
+
+// 问题输入框样式(保留向后兼容)
+.question-input {
+  width: 100%;
+  max-width: 300px;
+  padding-top: 8px;
+  margin-left: 20px;
+}
+
+.link-more-settings {
+  color: @primary-color;
+  cursor: pointer;
+  text-decoration: none;
+
+  &:hover {
+    text-decoration: underline;
+  }
+}
+
+// 标题和链接样式
+.section-title {
+  font-size: 14px;
+  font-weight: 500;
+  color: #262626;
+  background: #f5f5f5;
+  padding: 12px 20px;
+}
+
+// Prompt编辑器布局样式
+.prompt {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  // 滚动条
+  overflow-y: auto;
+  background: #f5f5f5;
+  // 提示词模板显示区域
+  &-info {
+    padding: 0px 20px 10px 20px;
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+    // border-bottom: 1px solid #fff;
+
+    &-text {
+      // 说明文本
+
+      .variable-highlight {
+        color: #1890ff;
+        font-weight: 500;
+        padding: 2px 6px;
+        border-radius: 1px;
+        font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+        margin: 0 2px;
+      }
+    }
+  }
+
+  // 提示词编辑区域
+  &-editor-area {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    // background: #ffffff;
+    // border-top: none; // 移除顶部边框,避免与 prompt-info 的底部边框重叠
+    padding: 0 20px;
+    .ant-form-item {
+      margin-bottom: 0;
+      height: 100%;
+
+      .ant-form-item-control {
+        height: 100%;
+
+        .ant-form-item-control-input {
+          height: 100%;
+
+          .ant-form-item-control-input-content {
+            height: 100%;
+
+            .ant-input {
+              height: 100%;
+              border: 1px solid #f0f0f0;
+              border-radius: 8px;
+              padding: 16px;
+              font-size: 14px;
+              line-height: 1.6;
+              resize: none;
+
+              &:focus {
+                border-color: #1890ff;
+                box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+              }
+
+              &::placeholder {
+                color: #bfbfbf;
+                font-style: italic;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+// 隐藏 prompt 区域的滚动条(仍可滚动,只隐藏可视滚动条)
+.questionAnswerInfo {
+  .ant-splitter-panel{
+        -ms-overflow-style: none; /* IE 10+ */
+    scrollbar-width: none; /* Firefox */
+
+    &::-webkit-scrollbar {
+      display: none; /* Chrome, Safari, Opera */
+      width: 0;
+      height: 0;
+    }
+  }
+  .prompt,
+  .prompt-editor-area,.ant-input {
+    -ms-overflow-style: none; /* IE 10+ */
+    scrollbar-width: none; /* Firefox */
+
+    &::-webkit-scrollbar {
+      display: none; /* Chrome, Safari, Opera */
+      width: 0;
+      height: 0;
+    }
+  }
+}
+
+.half-width {
+  margin: 0 auto;
+  width: 100%;
+  height: 100%;
+}
+
+// 间距样式
+.padding {
+  &-top {
+    &-10 {
+      padding-top: 10px;
+    }
+
+    &-20 {
+      padding-top: 20px;
+    }
+  }
+
+  &-bottom {
+    &-10 {
+      padding-bottom: 10px;
+    }
+
+    &-12 {
+      padding-bottom: 12px;
+    }
+
+    &-16 {
+      padding-bottom: 16px;
+    }
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .questionAnswerInfo {
+    &-content {
+      &-title {
+        max-width: 100%;
+      }
+    }
+  }
+
+  .form {
+    &-control-width,
+    &-input-large,
+    &-textarea-large {
+      max-width: 100%;
+    }
+  }
+
+  .question-input {
+    max-width: 100%;
+    margin-left: 0;
+  }
+
+  .half-width {
+    width: 100%;
+  }
+
+  .preset-questions {
+    .question-item {
+      flex-direction: column;
+      align-items: flex-start;
+      gap: 8px;
+
+      label {
+        min-width: auto;
+      }
+
+      .question-input {
+        width: 100%;
+        max-width: 100%;
+        min-width: auto;
+      }
+
+      .question-actions {
+        align-self: flex-end;
+      }
+    }
+  }
+}
+
+@media (max-width: 480px) {
+  .questionAnswerInfo {
+    &-content {
+      padding: 16px;
+    }
+  }
+
+  .form {
+    &-input-large,
+    &-textarea-large {
+      padding: 6px;
+    }
+  }
+
+  .preset-questions {
+    .question-item {
+      .question-actions {
+        align-self: center;
+        width: 100%;
+        justify-content: center;
+      }
+    }
+  }
+}

+ 228 - 0
src/pages/deepseek/audit/index.tsx

@@ -0,0 +1,228 @@
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import { Table, TableColumnsType, TablePaginationConfig,Drawer } from 'antd';
+import { StepForwardOutlined } from '@ant-design/icons';
+import dayjs from 'dayjs';
+import store from './store';
+import { Record } from './types';
+import './style.less';
+import LocalStorage from '@/LocalStorage';
+import InfoModal from './components/InfoModal';
+import PreviewModal from './components/PreviewModal';
+import AuditHistory from './components/auditHistory';
+
+const KnowledgeLibList: React.FC = () => {
+    const {
+        state,
+        onChangePagination,
+        onClickCreate,
+        onClickModify,
+        onClickfetchTakaiApplicationDetail,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        infoModalOnClickClose,
+        init,
+        reset
+    } = store;
+    const {
+        listLoading,
+        list,
+        infoModalId,
+        infoModalOpen,
+        page
+    } = state;
+
+    const [drawerFlag, setDrawerFlag] = React.useState<boolean>(false);
+    const [drawerData, setDrawerData] = React.useState<any>({});
+    const [historyOpen, setHistoryOpen] = React.useState<boolean>(false);
+
+    React.useEffect(() => {
+        const userInfo = LocalStorage.getUserInfo();
+        const userId = (userInfo?.id ?? '').toString();
+        init(userId);
+
+         // 监听面包屑创建知识库事件
+        const handleKnowledgeLibCreate = (event: CustomEvent) => {
+            if (event.detail.platform === 'auditHistory') {
+                // onClickCreate();
+                setHistoryOpen(true);
+            }
+        };
+        
+        window.addEventListener('auditHistory', handleKnowledgeLibCreate as EventListener);
+
+
+
+
+        return () => {
+            reset();
+            window.removeEventListener('auditHistory', handleKnowledgeLibCreate as EventListener);
+        };
+    }, []);
+
+    const columns: TableColumnsType<Record> = [
+        {
+            title: '序号',
+            dataIndex: 'index',
+            width: 80,
+            render: (text, record, index) => {
+                return index + 1;
+            }
+        },
+        {
+            title: '知识名称',
+            dataIndex: 'name',
+            render: (text, record) => {
+                // const previewUrl = `/preview/${record.url}`; // 根据实际字段构造 URL
+                return (
+                    <a
+                        href={record.url}
+                        target="_blank"
+                        rel="noopener noreferrer"
+                        onClick={(e) => {
+                            e.stopPropagation(); // 防止 Table 默认事件干扰
+                        }}
+                    >
+                        {text}
+                    </a>
+                );
+            }
+        },
+        {
+            title: '状态',
+            dataIndex: 'status',
+            render: (text) => {
+                if (text === '1') {
+                    return '待审核';
+                }else if(text === '2'){
+                    return '审核中';
+                }else if(text === '3'){
+                    return '审核通过';
+                }else if(text === '4'||text === '5'){   
+                    return '审核拒绝';
+                }
+            }
+        },
+        {
+            title: '审核人',
+            dataIndex: 'userName',
+            render: (text) => {
+                return `${text}`;
+            }
+        },
+        {
+            title: '审核意见',
+            dataIndex: 'comment',
+            render: (text) => {
+                if(text){
+                    return `${text}`;
+                }else{
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            width: 200,
+            render: (text) => {
+                if (text) {
+                    return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+                } else {
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '操作',
+            dataIndex: 'operation',
+            width: 150,
+            fixed: 'right',
+            render: (text, record) => {
+                return (
+                    <>
+                        <a
+                            style={{ marginRight: 16 }}
+                            onClick={() => {
+                                // onClickfetchTakaiApplicationDetail(record.appId);
+                                setDrawerFlag(true)
+                                setDrawerData(record)
+                            }}
+                            title='审核'
+                        >
+                            查看
+                        </a >
+                        <a
+                            style={{ marginRight: 16 }}
+                            onClick={() => {
+                                onClickModify(record.appId);
+                            }}
+                            title='审核'
+                        >
+                            <StepForwardOutlined />审核
+                        </a >
+                    </>
+                )
+            }
+        }
+    ];
+
+    const paginationConfig: TablePaginationConfig = {
+        // 显示数据总量
+        showTotal: (total: number) => {
+            return `共 ${total} 条`;
+        },
+        // 展示分页条数切换
+        showSizeChanger: true,
+        // 指定每页显示条数
+        pageSizeOptions: ['10', '20', '50', '100'],
+        // 快速跳转至某页
+        showQuickJumper: true,
+        current: page.pageNum,
+        pageSize: page.pageSize,
+        total: page.total,
+        onChange: async (page, pageSize) => {
+            await onChangePagination(page, pageSize);
+        },
+    };
+
+    return (
+        <div className='knowledgeLibList'>
+            <div className='knowledgeLibList-table'>
+                <Table
+                    scroll={{ x: 'max-content' }}
+                    rowKey={(record) => record.createTime}
+                    loading={listLoading}
+                    columns={columns}
+                    dataSource={list}
+                    pagination={paginationConfig}
+                />
+            </div>
+            {
+                infoModalOpen &&
+                <InfoModal
+                    id={infoModalId}
+                    open={infoModalOpen}
+                    onClickConfirm={infoModalOnClickConfirm}
+                    onClickCancel={infoModalOnClickCancel}
+                    onClickClose={infoModalOnClickClose}
+                />
+            }
+            {
+                <Drawer
+                    title={drawerData.name}
+                    closable={{ 'aria-label': 'Close Button' }}
+                    onClose={() => { setDrawerFlag(false) }}
+                    width="80%"
+                    open={drawerFlag}
+                >
+                    {drawerFlag&&<PreviewModal isComponent={true} AuditAppId={drawerData.appId} />}
+                </Drawer> 
+            }        
+            <AuditHistory open={historyOpen} onClose={() => setHistoryOpen(false)} />     
+
+        </div>
+    );
+};
+
+export default observer(KnowledgeLibList);

+ 193 - 0
src/pages/deepseek/audit/store.ts

@@ -0,0 +1,193 @@
+import { makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import { apis, ModifyDocumentApiParams } from '@/apis';
+import { State, ReadonlyState, StateAction, DocumentLibListStore } from './types';
+
+// 定义状态
+const stateGenerator = (): ReadonlyState => ({
+    listLoading: false,
+    list: [],
+    infoModalId: '',
+    infoModalOpen: false,
+    page: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0,
+    },
+});
+
+// 修改状态
+const stateActionsGenerator = (state: State): StateAction => {
+    return {
+        setListLoading: (loading) => {
+            state.listLoading = loading;
+        },
+        setList: (list) => {
+            state.list = list;
+        },
+        setInfoModalId: (id) => {
+            state.infoModalId = id;
+        },
+        setInfoModalOpen: (open) => {
+            state.infoModalOpen = open;
+        },
+        setPage: (page) => {
+            state.page = page;
+        },
+    };
+};
+
+// 使用仓库
+const useKnowledgeLibListStore = (): DocumentLibListStore => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    const api = {
+        // 获取审核列表
+        fetchApplicationLibList: async (userId: string) => {
+            actions.setListLoading(true);
+            try {
+                const data = {
+                    pageNum: state.page.pageNum,
+                    pageSize: state.page.pageSize,
+                    approver: userId,
+                };
+                const res = await apis.fetchTakaiAuditConfigLibList(data);
+                console.log(res.rows, 'rew.rows');
+                actions.setList(res.rows);
+                actions.setPage({
+                    ...state.page,
+                    total: res.total,
+                });
+            } catch (error: any) {
+                console.error(error);
+            } finally {
+                actions.setListLoading(false);
+            }
+        },
+        
+        // 应用审核
+        modifyDocumentLib: async (documentId: string, userId: string, data: ModifyDocumentApiParams) => {
+            try {
+                const res = await apis.modifyTakaiAuditDocumentLibApi(documentId, data);
+                // 获取审核列表
+                api.fetchApplicationLibList(userId);
+                if(res.data === 1 && res.code === 200){
+                    message.success('修改成功');
+                }else{
+                    message.error('修改失败');
+                }
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+        // 获取详情
+        fetchTakaiApplicationDetail: async (appId: string) => {
+            try {
+                const res = await apis.fetchTakaiApplicationDetail(appId);
+                console.log(res, 'resresres');
+                return res;
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+    }
+    // 点击查看出现弹窗
+    const onClickfetchTakaiApplicationDetail = async (appId: string) => {
+        if(appId){
+            await api.fetchTakaiApplicationDetail(appId);
+        }
+    }
+    // 更改分页
+    const onChangePagination: DocumentLibListStore['onChangePagination'] = async (pageNum, pageSize) => {
+        actions.setPage({
+            ...state.page,
+            pageNum: pageNum,
+            pageSize: pageSize,
+        });
+        // 获取知识库列表
+        await api.fetchApplicationLibList('');
+    }
+
+    // 点击创建
+    const onClickCreate: DocumentLibListStore['onClickCreate'] = () => {
+        const initialInfoModalId = stateGenerator().infoModalId;
+
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 点击修改
+    const onClickModify: DocumentLibListStore['onClickModify'] = (documentId) => {
+        actions.setInfoModalId(documentId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 信息弹出层-点击通过
+    const infoModalOnClickConfirm: DocumentLibListStore['infoModalOnClickConfirm'] = async (documentId, userId, data) => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+        if (documentId) {
+            // 审核通过
+            console.log(data, 'datadata');
+            await api.modifyDocumentLib(documentId, userId, data);
+        } 
+    }
+
+    // 信息弹出层-点击拒绝
+    const infoModalOnClickCancel: DocumentLibListStore['infoModalOnClickCancel'] = async(documentId, userId, data) => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+        if (documentId) {
+            // 审核拒绝
+            await api.modifyDocumentLib(documentId, userId, data);
+        } 
+    }
+
+    const infoModalOnClickClose: DocumentLibListStore['infoModalOnClickClose'] = () => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+    }
+
+    
+    // 初始渲染
+    const init: DocumentLibListStore['init'] = async (userId) => {
+        // 获取知识库列表
+        await api.fetchApplicationLibList(userId);
+    }
+
+    // 状态重置
+    const reset: DocumentLibListStore['reset'] = () => {
+        const initialListLoading = stateGenerator().listLoading;
+        const initialList = stateGenerator().list;
+        const initialInfoModalId = stateGenerator().infoModalId;
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+        const initialPage = stateGenerator().page;
+
+        actions.setListLoading(initialListLoading);
+        actions.setList(initialList);
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(initialInfoModalOpen);
+        actions.setPage(initialPage);
+    }
+
+    return {
+        state,
+        onChangePagination,
+        onClickCreate,
+        onClickModify,
+        onClickfetchTakaiApplicationDetail,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        infoModalOnClickClose,
+        init,
+        reset
+    };
+};
+
+export default useKnowledgeLibListStore();

+ 14 - 0
src/pages/deepseek/audit/style.less

@@ -0,0 +1,14 @@
+.knowledgeLibList {
+  &-operation {
+    padding: 20px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+    margin-bottom: 20px;
+  }
+
+  &-table {
+    padding: 20px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+  }
+}

+ 49 - 0
src/pages/deepseek/audit/types.ts

@@ -0,0 +1,49 @@
+import { ModifyDocumentApiParams } from '@/apis';
+
+export type Record = {
+    [x: string]: any;
+    documentId: string,
+    knowledgeId: string,
+    name: string,// 知识文件名称
+    createTime: string,// 创建时间
+    updateTime: string,// 更新时间
+};
+
+// 定义状态
+export type State = {
+    listLoading: boolean,
+    list: Record[],
+    infoModalId: string,
+    infoModalOpen: boolean,
+    page: {
+        pageNum: number,
+        pageSize: number,
+        total: number,
+    },
+};
+
+// 只读状态
+export type ReadonlyState = Readonly<State>;
+
+// 修改状态
+export type StateAction = {
+    setListLoading: (loading: State['listLoading']) => void,
+    setList: (list: State['list']) => void,
+    setInfoModalId: (id: State['infoModalId']) => void,
+    setInfoModalOpen: (open: State['infoModalOpen']) => void,
+    setPage: (page: State['page']) => void,
+};
+
+// 仓库类型
+export type DocumentLibListStore = {
+    state: ReadonlyState,
+    onChangePagination: (pageNum: number, pageSize: number) => Promise<any>,
+    onClickCreate: () => void,
+    onClickModify: (documentId: string) => void,
+    onClickfetchTakaiApplicationDetail: (appId: string) => void,
+    infoModalOnClickConfirm: (documentId: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    infoModalOnClickCancel: (documentId: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    infoModalOnClickClose:  () => void,
+    init: (userId: string) => Promise<any>,
+    reset: () => void,
+};

+ 165 - 0
src/pages/deepseek/dataExport/components/InfoModal.tsx

@@ -0,0 +1,165 @@
+import * as React from 'react';
+import { Modal, Spin, Form, Input, Select, message } from 'antd';
+import { apis, CreateOrModifyUserApiParams } from '@/apis';
+import { regex } from '@/utils';
+
+const FormItem = Form.Item;
+const { Option } = Select;
+
+interface Props {
+    id: string,
+    open: boolean,
+    onClickConfirm: (id: string, data: CreateOrModifyUserApiParams) => Promise<any>,
+    onClickCancel: () => void,
+};
+
+const InfoModal: React.FC<Props> = (props: Props) => {
+    const {
+        id,
+        open,
+        onClickConfirm,
+        onClickCancel
+    } = props;
+
+    const [form] = Form.useForm();
+
+    const [loading, setLoading] = React.useState<boolean>(false);
+
+    const getTitle = () => {
+        if (id) {
+            return '修改用户';
+        } else {
+            return '创建用户';
+        }
+    };
+
+    const fetchDetail = async () => {
+        try {
+            const res = await apis.fetchUserDetail(props.id);
+            form.setFieldsValue(res.data);
+        } catch (error: any) {
+            message.error(error.msg);
+        }
+    };
+
+    const init = async () => {
+        setLoading(true);
+        if (props.id) {
+            await fetchDetail();
+        }
+        setLoading(false);
+    };
+
+    React.useEffect(() => {
+        init();
+    }, []);
+
+    // 检查手机号码
+    const checkPhoneNumber = (rule: any, value: string) => {
+        if (value) {
+            const phoneNumberRegex = new RegExp(regex.phoneNumber);
+            if (phoneNumberRegex.test(value)) {
+                return Promise.resolve();
+            } else {
+                return Promise.reject(new Error('手机号码格式不正确'));
+            }
+        } else {
+            return Promise.reject('手机号码不能为空');
+        }
+    };
+
+    // 检查登录密码
+    const checkPassword = (rule: any, value: string) => {
+        if (value) {
+            const passwordRegex = new RegExp(regex.password);
+            if (passwordRegex.test(value)) {
+                return Promise.resolve();
+            } else {
+                return Promise.reject('登录密码格式不正确');
+            }
+        } else {
+            return Promise.reject('登录密码不能为空');
+        }
+    };
+
+    // 点击确定
+    const handleClickConfirm = () => {
+        form.validateFields().then(async (values) => {
+            const data = { ...values };
+            await onClickConfirm(props.id, data);
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+
+    return (
+        <Modal
+            width={600}
+            title={getTitle()}
+            destroyOnClose={true}
+            maskClosable={false}
+            centered={true}
+            open={open}
+            onOk={handleClickConfirm}
+            onCancel={onClickCancel}
+        >
+            <div className='infoModal'>
+                <Spin spinning={loading}>
+                    <Form form={form} layout='vertical'>
+                        <FormItem
+                            label='姓名'
+                            name='user_name'
+                            rules={[{ required: true, message: '姓名不能为空', whitespace: true }]}
+                        >
+                            <Input
+                                style={{ width: '100%' }}
+                                placeholder='请输入姓名'
+                            />
+                        </FormItem>
+                        <FormItem
+                            label='手机号码'
+                            name='phone_number'
+                            rules={[{ validator: checkPhoneNumber, required: true }]}
+                        >
+                            <Input
+                                style={{ width: '100%' }}
+                                placeholder='请输入手机号码'
+                                maxLength={11}
+                            />
+                        </FormItem>
+                        <FormItem
+                            label='登录密码'
+                            name='password'
+                            rules={[{ validator: checkPassword, required: true }]}
+                        >
+                            <Input.Password
+                                style={{ width: '100%' }}
+                                placeholder='6-16位字母或数字组合'
+                            />
+                        </FormItem>
+                        <FormItem
+                            label='角色'
+                            name='role'
+                            rules={[{ required: true, message: '角色不能为空' }]}
+                        >
+                            <Select
+                                style={{ width: '100%' }}
+                                placeholder='请选择角色'
+                                allowClear={true}
+                            >
+                                <Option value='USER'>
+                                    用户
+                                </Option>
+                                <Option value='ADMIN'>
+                                    管理员
+                                </Option>
+                            </Select>
+                        </FormItem>
+                    </Form>
+                </Spin>
+            </div>
+        </Modal>
+    );
+};
+
+export default InfoModal;

+ 101 - 0
src/pages/deepseek/dataExport/components/Search.tsx

@@ -0,0 +1,101 @@
+import * as React from 'react';
+import { Form, Select, Button } from 'antd';
+import { apis } from '@/apis';
+import { Query } from '../types';
+import LocalStorage from '@/LocalStorage';
+
+const FormItem = Form.Item;
+const { Option } = Select;
+
+interface Props {
+    onClickSearch: (query: Query) => Promise<any>,
+    onClickReset: (query: Query) => Promise<any>,
+};
+
+const Search: React.FC<Props> = (props: Props) => {
+    const {
+        onClickSearch,
+        onClickReset
+    } = props;
+
+    const [form] = Form.useForm();
+
+    type ApplicationList = {
+        label: string,
+        value: string,
+    }[];
+
+    const [applicationList, setApplicationList] = React.useState<ApplicationList>([]);
+
+    const fetchApplicationList = async () => {
+        try {
+            const userInfo = LocalStorage.getUserInfo();
+            const userId = (userInfo?.id ?? '').toString();
+            const res = await apis.fetchTakaiApplicationList(userId);
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.name,
+                    value: item.appId,
+                }
+            });
+            setApplicationList(list);
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+
+    const init = async () => {
+        await fetchApplicationList();
+    };
+
+    React.useEffect(() => {
+        init();
+    }, []);
+
+    // 点击查询
+    const handleClickSearch = async () => {
+        const values = form.getFieldsValue();
+        await onClickSearch(values);
+    };
+
+    // 点击重置
+    const handleClickReset = async () => {
+        form.resetFields();
+        const values = form.getFieldsValue();
+        await onClickReset(values);
+    };
+
+    return (
+        <Form form={form} layout='inline' colon={false}>
+            <FormItem label='应用' name='appId'>
+                <Select
+                    style={{ width: 200 }}
+                    placeholder='全部'
+                    allowClear={true}
+                >
+                    {
+                        applicationList.map((item, index) => {
+                            return <Option value={item.value} key={index}>
+                                {item.label}
+                            </Option>
+                        })
+                    }
+                </Select>
+            </FormItem>
+            <FormItem>
+                <Button
+                    style={{ marginRight: 16 }}
+                    type='primary'
+                    onClick={handleClickSearch}
+                >
+                    查询
+                </Button>
+                <Button onClick={handleClickReset}>
+                    重置
+                </Button>
+            </FormItem>
+        </Form>
+    );
+};
+
+export default Search;

+ 130 - 0
src/pages/deepseek/dataExport/index.tsx

@@ -0,0 +1,130 @@
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import { Table, TableColumnsType, TablePaginationConfig, Modal } from 'antd';
+import { DownloadOutlined } from '@ant-design/icons';
+import Search from './components/Search';
+import dayjs from 'dayjs';
+import store from './store';
+import { Record } from './types';
+import './style.less';
+
+const DataExport: React.FC = () => {
+    const {
+        state,
+        onClickSearch,
+        onClickReset,
+        onChangePagination,
+        onClickDownload,
+        init,
+        reset
+    } = store;
+    const {
+        listLoading,
+        list,
+        page
+    } = state;
+
+    React.useEffect(() => {
+        init();
+        return () => reset();
+    }, []);
+
+    const columns: TableColumnsType<Record> = [
+        {
+            title: '序号',
+            dataIndex: 'index',
+            width: 80,
+            render: (text, record, index) => {
+                return index + 1;
+            }
+        },
+        {
+            title: '聊天标题',
+            dataIndex: 'dialog_name',
+        },
+        {
+            title: '消息长度',
+            dataIndex: 'length',
+            render: (text) => {
+                return text + '条';
+            }
+        },
+        {
+            title: '聊天时间',
+            dataIndex: 'create_time',
+            width: 200,
+            render: (text) => {
+                if (text) {
+                    return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+                } else {
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '操作',
+            dataIndex: 'operation',
+            width: 80,
+            fixed: 'right',
+            render: (text, record) => {
+                return (
+                    <a
+                        onClick={() => {
+                            Modal.confirm({
+                                title: '导出',
+                                content: '确定导出Excel吗?',
+                                onOk: async () => {
+                                    await onClickDownload(record.id, record.dialog_name);
+                                }
+                            });
+                        }}
+                    >
+                        <DownloadOutlined />
+                    </a >
+                )
+            }
+        }
+    ];
+
+    const paginationConfig: TablePaginationConfig = {
+        // 显示数据总量
+        showTotal: (total: number) => {
+            return `共 ${total} 条`;
+        },
+        // 展示分页条数切换
+        showSizeChanger: true,
+        // 指定每页显示条数
+        pageSizeOptions: ['10', '20', '50', '100'],
+        // 快速跳转至某页
+        showQuickJumper: true,
+        current: page.pageNum,
+        pageSize: page.pageSize,
+        total: page.total,
+        onChange: async (page, pageSize) => {
+            await onChangePagination(page, pageSize);
+        },
+    };
+
+    return (
+        <div className='dataExport'>
+            <div className='dataExport-search'>
+                <Search
+                    onClickSearch={onClickSearch}
+                    onClickReset={onClickReset}
+                />
+            </div>
+            <div className='dataExport-table'>
+                <Table
+                    scroll={{ x: 'max-content' }}
+                    rowKey={(record) => record.id}
+                    loading={listLoading}
+                    columns={columns}
+                    dataSource={list}
+                    pagination={paginationConfig}
+                />
+            </div>
+        </div>
+    );
+};
+
+export default observer(DataExport);

+ 147 - 0
src/pages/deepseek/dataExport/store.ts

@@ -0,0 +1,147 @@
+import { makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import { apis } from '@/apis';
+import { downloadFile } from '@/utils';
+import { State, ReadonlyState, StateAction, DataExportStore } from './types';
+
+// 定义状态
+const stateGenerator = (): ReadonlyState => ({
+    query: undefined,
+    listLoading: false,
+    list: [],
+    page: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0,
+    },
+});
+
+// 修改状态
+const stateActionsGenerator = (state: State): StateAction => {
+    return {
+        setQuery: (query) => {
+            state.query = query;
+        },
+        setListLoading: (loading) => {
+            state.listLoading = loading;
+        },
+        setList: (list) => {
+            state.list = list;
+        },
+        setPage: (page) => {
+            state.page = page;
+        },
+    };
+};
+
+// 使用仓库
+const useDataExportStore = (): DataExportStore => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    const api = {
+        // 获取聊天记录列表
+        fetchChatHistoryList: async () => {
+            actions.setListLoading(true);
+            try {
+                const data = {
+                    ...state.query,
+                    pageNum: state.page.pageNum,
+                    pageSize: state.page.pageSize,
+                };
+                const res = await apis.fetchTakaiChatHistoryList(data);
+                actions.setList(res.rows);
+                actions.setPage({
+                    ...state.page,
+                    total: res.total,
+                });
+            } catch (error: any) {
+                console.error(error);
+            } finally {
+                actions.setListLoading(false);
+            }
+        },
+        // 导出聊天记录
+        exportChatHistory: async (id: string, fileName: string) => {
+            try {
+                const blob = await apis.exportTakaiChatHistory(id);
+                fileName = `${fileName}.xlsx`;
+                downloadFile(blob, fileName);
+                message.success('导出成功');
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+    }
+
+    // 点击查询
+    const onClickSearch: DataExportStore['onClickSearch'] = async (query) => {
+        const initialpageNum = stateGenerator().page.pageNum;
+
+        actions.setQuery(query);
+        actions.setPage({
+            ...state.page,
+            pageNum: initialpageNum,
+        });
+        // 获取聊天记录列表
+        await api.fetchChatHistoryList();
+    }
+
+    // 点击重置
+    const onClickReset: DataExportStore['onClickReset'] = async (query) => {
+        const initialPage = stateGenerator().page;
+
+        actions.setQuery(query);
+        actions.setPage(initialPage);
+        // 获取聊天记录列表
+        await api.fetchChatHistoryList();
+    }
+
+    // 更改分页
+    const onChangePagination: DataExportStore['onChangePagination'] = async (pageNum, pageSize) => {
+        actions.setPage({
+            ...state.page,
+            pageNum: pageNum,
+            pageSize: pageSize,
+        });
+        // 获取聊天记录列表
+        await api.fetchChatHistoryList();
+    }
+
+    // 点击导出
+    const onClickDownload: DataExportStore['onClickDownload'] = async (id, name) => {
+        // 导出聊天记录
+        await api.exportChatHistory(id, name);
+    }
+
+    // 初始渲染
+    const init: DataExportStore['init'] = async () => {
+        // 获取聊天记录列表
+        await api.fetchChatHistoryList();
+    }
+
+    // 状态重置
+    const reset: DataExportStore['reset'] = () => {
+        const initialQuery = stateGenerator().query;
+        const initialListLoading = stateGenerator().listLoading;
+        const initialList = stateGenerator().list;
+        const initialPage = stateGenerator().page;
+
+        actions.setQuery(initialQuery);
+        actions.setListLoading(initialListLoading);
+        actions.setList(initialList);
+        actions.setPage(initialPage);
+    }
+
+    return {
+        state,
+        onClickSearch,
+        onClickReset,
+        onChangePagination,
+        onClickDownload,
+        init,
+        reset
+    };
+};
+
+export default useDataExportStore();

+ 14 - 0
src/pages/deepseek/dataExport/style.less

@@ -0,0 +1,14 @@
+.dataExport {
+  &-search {
+    padding: 20px 20px 4px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+    margin-bottom: 20px;
+  }
+
+  &-table {
+    padding: 20px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+  }
+}

+ 44 - 0
src/pages/deepseek/dataExport/types.ts

@@ -0,0 +1,44 @@
+export type Query = Partial<{
+    appId: string,
+}>;
+
+export type Record = {
+    id: string,
+    dialog_name: string,
+    length: number,
+    create_time: string
+};
+
+// 定义状态
+export type State = {
+    query?: Query,
+    listLoading: boolean,
+    list: Record[],
+    page: {
+        pageNum: number,
+        pageSize: number,
+        total: number,
+    },
+};
+
+// 只读状态
+export type ReadonlyState = Readonly<State>;
+
+// 修改状态
+export type StateAction = {
+    setQuery: (query: State['query']) => void,
+    setListLoading: (loading: State['listLoading']) => void,
+    setList: (list: State['list']) => void,
+    setPage: (page: State['page']) => void,
+};
+
+// 仓库类型
+export type DataExportStore = {
+    state: ReadonlyState,
+    onClickSearch: (query: Query) => Promise<any>,
+    onClickReset: (query: Query) => Promise<any>,
+    onChangePagination: (pageNum: number, pageSize: number) => Promise<any>,
+    onClickDownload: (id: string, name: string) => Promise<any>,
+    init: () => Promise<any>,
+    reset: () => void,
+};

+ 271 - 0
src/pages/deepseek/evaluationTool/datasetManagement/components/dataManagementMode.tsx

@@ -0,0 +1,271 @@
+import React, { useEffect, useState } from 'react';
+import { Modal, Form, Input, Select, Upload, message, UploadProps } from 'antd';
+import { InboxOutlined } from '@ant-design/icons';
+import { apis } from '@/apis';
+import { downloadFile } from '@/utils/index';
+import { getHeaders } from '@/apis/config';
+const { TextArea } = Input;
+const { Option } = Select;
+const { Dragger } = Upload;
+
+interface Props {
+    openDataManagementMode: boolean;
+    onCancel: () => void;
+    onSubmit?: (values: any) => void;
+    reviewRagdata?: any;
+}
+const dataManagementMode: React.FC<Props> = ({ openDataManagementMode, onCancel, onSubmit,reviewRagdata }) => {
+    const [form] = Form.useForm();
+    const [fileOssList, setFileOssList] = React.useState<any>([]); // 选中的列表OSS信息
+    const [knowledgeList, setKnowledgeList] = React.useState<Array<{ label: string; value: string }>>([]);// 知识库列表
+    useEffect(() => {
+        if (!openDataManagementMode) {
+            form.resetFields();
+            setFileOssList([]);
+        }
+        if(openDataManagementMode){
+            fetchGetApplicationList();
+        }
+    }, [openDataManagementMode, form]);
+    const handleOk = async () => {
+        try {
+            const values = await form.validateFields();
+            console.log(values, 'values---');
+            // values.files = fileOssList;
+            // if (onSubmit) onSubmit(values);
+            // message.success('创建任务成功');
+            const res: any = await apis.createDatasetApi({
+                name: values.name,
+                appId: values.appId,
+                description: values.description,
+                ossId: fileOssList[0]?.ossId,
+                url: fileOssList[0]?.url,
+            });
+            if (res.code === 200) {
+                message.success('创建数据集成功');
+                onSubmit && onSubmit(res.data);
+            } else {
+                message.error(res.msg || '创建数据集失败');
+            }
+            onCancel();
+        } catch (err) {
+            // 校验失败,表单将显示错误
+        }
+    };
+    const fetchGetApplicationList = async (typeId?: string | null, name?: string) => {
+        try {
+            const data = {
+                pageSize: 500,
+                pageNum: 1,
+                userId: '1',
+                isCollect: null,
+                typeId: null
+                // name: name,
+            }
+            const res: any = await apis.fetchTakaiAppList({...data});
+            // 解析返回并设置状态
+            if (res && res.rows) {
+                setKnowledgeList(res.rows.map((item: any) => ({ label: item.name, value: item.appId })));
+                form.setFieldsValue({ appId: reviewRagdata });
+            }
+
+        } catch (error) {
+            console.error('Failed to fetch app list:', error);
+        } finally {
+        }
+    }
+    // 批量删除oss文件
+    const onDeleteOssFileApi = async (ossIds: string) => {
+        try {
+            const res: any = await apis.deleteOssFileApi(ossIds);
+            if (res.code !== 200) {
+                message.error('删除oss文件失败');
+            }
+        } catch (error) {
+            console.error('删除oss文件失败:', error);
+        }
+    };
+    const [oldFileList, setOldFileList] = React.useState<any>([]); // 选中的本地文件列表
+    const [oldfileName, setOldfileName] = React.useState<any>(''); // 选中的本地文件的信息
+    const uploadProps: UploadProps = {
+        name: 'file',
+        // 根据选择的分类决定是否允许多选与最大数量:分类为 '3' 时只允许单文件,其余允许最多 5 个
+        multiple: false,
+        maxCount: 1,
+        action: '/api/resource/oss/upload',
+        headers: getHeaders(),
+        // 使用受控 fileList,便于自定义已上传文件列表的展示和管理
+        fileList: oldFileList,
+        beforeUpload(file, fileList) {
+            const maxCount = 1
+            const currentCount = (oldFileList || []).length;
+            const incomingCount = fileList?.length || 1;
+            if (currentCount + incomingCount > maxCount) {
+                message.error(`最多只能上传 ${maxCount} 个文件`);
+                return Upload.LIST_IGNORE;
+            }
+            const allowedExtensions = ['xlsx', 'xls', 'json'];
+            // const allowedExtensions = ['*']; // 允许所有格式上传 不限制文件类型
+            // const allowedExtensions = ['xlsx','xls','csv']; // 允许所有格式上传
+
+            // 检查文件类型
+            for (const file of fileList) {
+                const fileExt = file.name.split('.').pop()?.toLowerCase();
+                if (!fileExt || !allowedExtensions.includes(fileExt)) {
+                    message.error(`不支持 ${fileExt} 格式的文件上传`);
+                    return Upload.LIST_IGNORE;
+                }
+            }
+
+            // 检查文件大小
+            let totalSize = 0;
+            for (const file of fileList) {
+                const fileExt = file.name.split('.').pop()?.toLowerCase();
+                const fileSizeMB = file.size / 1024 / 1024;
+
+                if (fileSizeMB > 100) {
+                    message.error('单个文件不能大于100M');
+                    return Upload.LIST_IGNORE;
+                }
+                totalSize += fileSizeMB;
+            }
+
+            if (totalSize > 150) {
+                message.error('文件总大小超过150M');
+                return Upload.LIST_IGNORE;
+            }
+        },
+        onChange(info) {
+            const { status, response } = info.file;
+            console.log(info, 'info.file----');
+
+            // 使用 Upload 提供的 fileList 更新受控状态
+            const nextFileList = info.fileList || [];
+            setOldFileList(nextFileList as any);
+            // 同步到 Form 中的 `data` 字段,确保 Form 校验可以感知文件变化
+            form.setFieldsValue({ data: nextFileList });
+            // 尝试触发单字段校验,及时展示上传必填提示
+            form.validateFields(['data']).catch(() => { });
+
+            // 当单个文件上传完成且后端返回成功时,更新 OSS 列表中对应项
+            if (status === 'done') {
+                if (response?.code === 200) {
+                    message.success(`${info.file.name} 上传成功`);
+                    // 从 fileList 中抽取有 response.data 的条目作为 OSS 列表
+                    const ossItems = nextFileList
+                        .map((f: any) => {
+                            return {
+                                name: f.name.split('.')[0],
+                                ...f.response?.data
+                            }
+                        })
+                        .filter((d: any) => !!d);
+
+                    console.log(ossItems, 'ossItems---');
+                    setFileOssList(ossItems as any);
+
+                    setOldfileName(info.file.name);
+                } else {
+                    message.error(response?.msg || '上传失败');
+                }
+            } else if (status === 'error') {
+                message.error(`${info.file.name} 上传失败`);
+            }
+        },
+        onDrop(e) {
+            console.log('Dropped files', e.dataTransfer.files);
+        },
+        onRemove(file) {
+            // 先从本地受控 fileList 中移除
+            setOldFileList((prev: any[]) => (prev || []).filter((f) => f.uid !== file.uid));
+            // 如果该文件已上传并携带后端返回数据,则尝试删除 OSS 记录
+            const resFile = file?.response?.data;
+            if (resFile?.ossId) {
+                onDeleteOssFileApi(`${resFile.ossId}`);
+                setFileOssList((pre: any[]) => (pre || []).filter((item: any) => item.ossId !== resFile.ossId));
+            }
+            return true;
+        }
+
+    };
+
+    return (
+        <Modal
+            open={openDataManagementMode}
+            title="创建数据集"
+            onCancel={onCancel}
+            onOk={handleOk}
+            okText="提交"
+            cancelText="取消"
+        >
+            <Form form={form} layout="vertical">
+                <Form.Item
+                    name="name"
+                    label="数据集名称"
+                    rules={[{ required: true, message: '请输入数据集名称' }]}
+                >
+                    <Input placeholder="输入数据集名称" />
+                </Form.Item>
+                <Form.Item
+                    name="appId"
+                    label="选择应用"
+                    rules={[{ required: true, message: '请选择应用' }]}
+                >
+                    <Select
+                        disabled={reviewRagdata?true:false}
+                        showSearch={true}
+                        filterOption={(input, option) => (option?.children as unknown as string)?.toLowerCase()?.includes(input.toLowerCase())}
+                        className='form-element-select'
+                        placeholder='请选择需要引用的应用'
+                    >
+                        {
+                            knowledgeList.map((item, index) => {
+                                return <Option value={item.value} key={index}>
+                                    {item.label}
+                                </Option>
+                            })
+                        }
+                    </Select>
+                </Form.Item>
+
+                <Form.Item name="description" label="数据集描述">
+                    <TextArea rows={4} placeholder="请输入数据集描述(可选)" />
+                </Form.Item>
+                <Form.Item
+                    name="data"
+                    label="上传数据"
+                    rules={[
+                        {
+                            required: true,
+                            validator: (_rule, value) => {
+                                const list = value || oldFileList || [];
+                                return list && list.length > 0
+                                    ? Promise.resolve()
+                                    : Promise.reject(new Error('请至少上传一个文件'));
+                            },
+                        },
+                    ]}
+                >
+                    <div>
+                        <p className='pb-[10px]'>
+                            需上传已标注的文本数据集,如不清楚上传格式,可 <a href="#" onClick={async () => {
+                                const blob: any = await apis.datasetExportApi({});
+                                downloadFile(blob, '数据集上传模版');
+                            }} >下载模版</a>
+                        </p>
+                        <Dragger {...uploadProps}>
+                            <p className="ant-upload-drag-icon">
+                                <InboxOutlined />
+                            </p>
+                            <p className="ant-upload-text">点击或拖拽文件到此处上传</p>
+                            <p className="ant-upload-hint"> 目前仅支持上传:xlsx,json文件类型,最多上传1个文件 </p>
+                            <p className='ant-upload-hint'>限制:100M文件大小、10万行数据</p>
+                        </Dragger>
+                    </div>
+                </Form.Item>
+            </Form>
+        </Modal>
+    );
+};
+
+export default dataManagementMode;

+ 67 - 0
src/pages/deepseek/evaluationTool/datasetManagement/components/exampleModel.tsx

@@ -0,0 +1,67 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { Table, Pagination, Modal, Space, Button, TablePaginationConfig, Input, Radio, message } from 'antd';
+
+const ExampleModel: React.FC<{ visible: boolean; onClose: () => void }> = ({ visible, onClose }) => {
+  // 示例数据(与之前 <pre> 中的 JSON 内容一致)
+  const sample = useMemo(() => ({
+    questions: [
+      {
+        question: '什么是人工智能?',
+        expected_answer: '人工智能是指使计算机能够执行通常需要人类智能的任务的技术。'
+      },
+      {
+        question: '深度学习的基本原理是什么?',
+        expected_answer: '深度学习是一种机器学习方法,利用多层神经网络来模拟人脑处理数据和创建模式的方式。'
+      },
+      {
+        question: '谁发明了电话?',
+        expected_answer: '电话的主要发明者是亚历山大·格拉汉姆·贝尔,他于1876年获得了电话的发明专利。'
+      },
+      {
+        question: '地球上最大的哺乳动物是什么?',
+        expected_answer: '地球上最大的哺乳动物是蓝鲸,成年蓝鲸体长可达30米,重量可达180吨。'
+      },
+    ]
+  }), []);
+
+  const dataSource = sample.questions.map((q, idx) => ({ ...q, key: idx }));
+
+  const columns = [
+    {
+      title: '问题',
+      dataIndex: 'question',
+      key: 'question',
+      render: (text: string) => <div style={{ whiteSpace: 'pre-wrap' }}>{text}</div>
+    },
+    {
+      title: '期望答案',
+      dataIndex: 'expected_answer',
+      key: 'expected_answer',
+      render: (text: string) => <div style={{ whiteSpace: 'pre-wrap' }}>{text}</div>
+    }
+  ];
+
+  return (
+    <Modal
+      title="示例数据文件"
+      open={visible}
+      onCancel={onClose}
+      footer={null}
+      width={800}
+    >
+      <div>
+        <p className='pb-2'>以下是一个示例数据文件的结构说明:</p>
+        {/* <p className="text-sm text-gray-600 mb-4">请确保您的数据文件遵循下列表格结构,以便系统能够正确解析和使用您的评测数据。</p> */}
+
+        <Table
+          columns={columns}
+          dataSource={dataSource}
+          pagination={false}
+          size="middle"
+        />
+      </div>
+    </Modal>
+  );
+};
+
+export default ExampleModel;

+ 184 - 0
src/pages/deepseek/evaluationTool/datasetManagement/list/index.tsx

@@ -0,0 +1,184 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { Table, Pagination, Modal, Space, Button, TablePaginationConfig, Input, Radio, message } from 'antd';
+import type { ColumnsType } from 'antd/es/table';
+import { observer } from 'mobx-react';
+import { SearchOutlined, BulbOutlined, CloseOutlined } from '@ant-design/icons';
+import LocalStorage from '@/LocalStorage';
+
+import store from './store';
+import DataManagementMode from '../components/dataManagementMode';
+import ExampleModel from '../components/exampleModel';
+
+import { deleteDatasetApi } from '@/apis';
+
+interface KnowledgeRecord {
+  name: string;
+  knowledgeId: string | number;
+  length: string | number; // 使用空间
+  appNames: string; // 关联空间
+  documentSize: number; // 文件数量
+  createTime: string; // 创建时间
+  updateTime: string; // 更新时间
+  status: string | number; // 状态
+}
+
+
+const RevisionToolList: React.FC = () => {
+  const [loading, setLoading] = useState(false);
+
+  const { state, init, handleNameChange, onChangePagination, handleModeChange } = store;
+
+  const { reviseList, name } = state
+
+
+
+  useEffect(() => {
+    // 模拟加载状态
+    setLoading(true);
+    const t = setTimeout(() => setLoading(false), 250);
+    return () => clearTimeout(t);
+  }, [state.page]);
+
+  const [deletedatasetManagement, setDeletedatasetManagement] = useState<boolean>(false); // 是否删除数据集
+  const [downloaddatasetManagement, setDownloaddatasetManagement] = useState<boolean>(false); // 下载数据集
+  const [userInfoAll, setUserInfoAll] = React.useState<any>({});
+
+  useEffect(() => {
+    init();
+
+
+    setDeletedatasetManagement(LocalStorage.getStatusFlag('evaluationTool:datasetManagement:del'));
+    setDownloaddatasetManagement(LocalStorage.getStatusFlag('evaluationTool:datasetManagement:download'));
+    setUserInfoAll(LocalStorage.getUserInfo());
+
+
+
+
+
+    const handleEvaluationTaskCreate = (e: any) => {
+      if (e.detail && e.detail.platform === 'Management') {
+        console.log('监听到创建数据集事件');
+        setOpenDataManagementMode(true);
+      }
+    }
+    window.addEventListener('datasetManagement', handleEvaluationTaskCreate as EventListener);
+
+    return () => {
+      window.removeEventListener('datasetManagement', handleEvaluationTaskCreate as EventListener);
+    };
+  }, []);
+
+  const [showGuide, setShowGuide] = React.useState<boolean>(() => localStorage.getItem('revisionToolGuideHidden') !== 'true');
+  const hideGuide = () => { localStorage.setItem('revisionToolGuideHidden', 'true'); setShowGuide(false); };
+  const [record, setRecord] = useState<KnowledgeRecord>({} as KnowledgeRecord);
+  const columns: ColumnsType<KnowledgeRecord> = [
+    {
+      title: '数据集名称', dataIndex: 'name', width: 220,
+      render: (text, record: any) => {
+        return <div>
+          <div style={{ fontWeight: 600 }} className='cursor-pointer'>{text}</div>
+        </div>
+      },
+    },
+    { title: '描述', dataIndex: 'description' },
+    {
+      title: '创建人', dataIndex: 'nickName', width: 120,
+    },
+    { title: '创建时机', dataIndex: 'createTime', width: 190 },
+    // { title: '更新时间', dataIndex: 'updateTime', width: 140 },
+    {
+      title: '操作',
+      dataIndex: 'status',
+      align: 'center',
+      width: 120,
+      render: (val, record: any) => (
+        <p className='flex'>
+          {(downloaddatasetManagement || userInfoAll.id === record.createBy) && <Button type="link" onClick={() => { window.open(record.url) }}>下载</Button>}
+          {(deletedatasetManagement || userInfoAll.id === record.createBy) && <Button type="link" style={{ color: '#ff4d4f', paddingLeft: 0 }} onClick={() => {
+            Modal.confirm({
+              title: '删除',
+              content: `确定删除吗?`,
+              okType: 'danger',
+              onOk: async () => {
+                const res: any = await deleteDatasetApi(record.id);
+                if (res.code === 200) {
+                  message.success('删除成功');
+                  init();
+                }
+              }
+            });
+          }}>删除</Button>}
+        </p>
+      ),
+    }
+  ]
+
+  const paginationConfig: TablePaginationConfig = {
+    // 显示数据总量
+    showTotal: (total: number) => {
+      return `共 ${total} 条`;
+    },
+    // 展示分页条数切换
+    showSizeChanger: true,
+    // 指定每页显示条数
+    pageSizeOptions: ['10', '20', '50', '100'],
+    // 快速跳转至某页
+    showQuickJumper: true,
+    current: state.page.page,
+    pageSize: state.page.size,
+    total: state.page.total,
+    onChange: async (page, pageSize) => {
+      await onChangePagination(page, pageSize);
+    },
+  };
+  const [openDataManagementMode, setOpenDataManagementMode] = useState(false);
+  const [ExampleModelVisible, setExampleModelVisible] = useState(false);
+  const [title, setTitle] = useState('');
+  return (
+    <div style={{ padding: 20, background: '#fff' }}>
+      {showGuide && <> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
+        <div style={{ fontSize: 13, color: '#333', display: 'flex', alignItems: 'center', gap: 6 }}>
+          <BulbOutlined style={{ color: '#faad14' }} />
+          参考数据模版及数据格式要求,准备并上传您的评测数据。提供和您实际场景相关的问题以评估RAG或模型的效果和场景匹配性。<span className='text-primary cursor-pointer'
+            onClick={() => {
+              setExampleModelVisible(true);
+            }}
+          >查看示例数据</span>
+        </div>
+        {/* <CloseOutlined onClick={hideGuide} style={{ color: '#999', cursor: 'pointer' }} /> */}
+      </div></>}
+      <div className='mb-2'>
+        <Radio.Group onChange={(e) => {
+          handleModeChange(e.target.value)
+        }} value={state.createBy} style={{ marginBottom: 8 }}>
+          <Radio.Button value="">全部</Radio.Button>
+          <Radio.Button value={state.myCreateBy}>我创建的</Radio.Button>
+        </Radio.Group>
+        <Space.Compact style={{ width: '300px', float: 'right' }}>
+          <Input
+            placeholder='请输入数据集名称'
+            value={name}
+            onChange={(e) => handleNameChange(e.target.value)}
+          />
+          <Button type="primary" onClick={() => { init() }}><SearchOutlined /></Button>
+        </Space.Compact>
+      </div>
+      {/* 表格 */}
+      <Table
+        columns={columns}
+        dataSource={reviseList}
+        rowKey="id"
+        loading={loading}
+        pagination={paginationConfig}
+      />
+      {/* 修订工具弹窗 */}
+      {openDataManagementMode && <DataManagementMode openDataManagementMode={openDataManagementMode} onCancel={() => { setOpenDataManagementMode(false); init(); }} />}
+      {/* 示例数据文件弹窗 */}
+      {<ExampleModel visible={ExampleModelVisible} onClose={() => {
+        setExampleModelVisible(false);
+      }} />}
+    </div>
+  );
+};
+
+export default observer(RevisionToolList);

+ 88 - 0
src/pages/deepseek/evaluationTool/datasetManagement/list/store.ts

@@ -0,0 +1,88 @@
+import { action, makeAutoObservable, set } from 'mobx';
+import { message } from 'antd';
+import LocalStorage from '@/LocalStorage';
+import { fetchDatasetList } from '@/apis';
+import { downloadFile } from '@/utils/index'
+import { data } from 'react-router-dom';
+
+// 定义状态
+const stateRevise = (): any => ({
+    reviseList: [] as any[],
+    name:'',
+    createBy: '',
+    myCreateBy: LocalStorage.getUserInfo()?.id || '', 
+    page: {
+        page: 1,
+        size: 10,
+        total: 0,
+    },
+})
+// 修改状态
+const stateActionRevise = (state: any) => {
+
+    return{
+        setPage: (page: { page: number; size: number; total: number }) => {
+            state.page = page;
+        },
+        setName: (name: string) => {
+            state.name = name;
+        },
+        setCreateBy: (createBy: string) => {
+            state.createBy = createBy;
+        }
+    }
+}
+// 使用仓库
+const useRevisionToolListStore = () => {
+    const state = makeAutoObservable(stateRevise());
+    const actions = stateActionRevise(state);
+
+    const onFetchDatasetList = async () => {
+        try {
+            const data = {
+                pageNum: state.page.page,
+                pageSize: state.page.size,
+                name: state.name || '',
+                createBy: state.createBy || '',
+            }
+            const res:any = await fetchDatasetList(data);
+            if (res && res.code === 200) {
+                state.reviseList = res.rows;
+                state.page.total = res.total;
+            } else {
+                message.error(res.message || '获取修订工具列表失败');
+            }
+        } catch (error) {
+            message.error('获取修订工具列表异常');
+        }
+    }
+    const handleNameChange = (name: string) => {
+        actions.setName(name);
+    };
+    const handleModeChange = (createBy: string) => {
+        actions.setCreateBy(createBy);
+        onFetchDatasetList()
+    }
+    const onChangePagination = async (page: number, pageSize: number) => {
+        actions.setPage({
+            ...state.page,
+            page: page,
+            size: pageSize,
+        });
+        await onFetchDatasetList();
+    }
+
+    const init = ()=>{
+        onFetchDatasetList()
+    }
+
+
+    return {
+        state,
+        init,
+        handleNameChange,
+        onChangePagination,
+        handleModeChange
+    };
+}
+export default useRevisionToolListStore();

+ 303 - 0
src/pages/deepseek/evaluationTool/evaluationTask/components/CreateTaskMode.tsx

@@ -0,0 +1,303 @@
+import React, { useEffect, useRef, useState } from 'react';
+import { Modal, Form, Input, Select, Upload, message, Image, Button, Radio, Tooltip } from 'antd';
+import { InboxOutlined, InfoCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
+import LocalStorage from '@/LocalStorage';
+
+const { TextArea } = Input;
+const { Option } = Select;
+const { Dragger } = Upload;
+import DataManagementMode from '../../datasetManagement/components/dataManagementMode';
+
+import aiwj from '@/assets/public/aiwj.png';
+import model from '@/assets/public/model.png';
+import { apis } from '@/apis';
+
+interface Props {
+    openCreateTaskMode: boolean;
+    onCancel: () => void;
+    onSubmit?: (values: any) => void;
+}
+
+const EVAL_TYPES = [
+    { label: '自动评测', value: 'auto' },
+    { label: '人工评测', value: 'manual' },
+];
+
+const MODELS = [
+    { label: 'gpt-4', value: 'gpt-4' },
+    { label: 'gpt-3.5', value: 'gpt-3.5' },
+];
+
+
+const CreateTaskMode: React.FC<Props> = ({ openCreateTaskMode, onCancel, onSubmit }) => {
+    type AppTypeList = {
+        label: string,
+        value: string,
+        children: {
+            label: string,
+            value: string,
+        }[],
+    }[];
+    const [form] = Form.useForm();
+    const [fileList, setFileList] = useState<any[]>([]);
+    const [modelType, setModelType] = React.useState<AppTypeList>([]); // 选择模型
+    const [ragOptions, setRagOptions] = useState<Array<{ label: string; value: string }>>([]);// RAG应用
+    const [evaluationDataOptions, setSelecteevaluationData] = useState<Array<{ label: string; value: string }>>([]);// 评测数据
+    const [radioModel, setRadioModel] = useState<string>('Qwen3-30B');
+    const reviewRag = useRef('');
+    useEffect(() => {
+        if (!openCreateTaskMode) {
+            form.resetFields();
+            setFileList([]);
+        }
+    }, [openCreateTaskMode, form]);
+    useEffect(() => {
+        if (openCreateTaskMode) {
+            fetchRagList();
+            fetchAppmodelType('');
+        }
+    }, [openCreateTaskMode]);
+
+    const handleOk = async () => {
+        try {
+            const values = await form.validateFields();
+            console.log('Form Values:', values);
+            const params = {
+                ...values,
+                model: radioModel,
+            };
+            const res: any = await apis.createEvaluationApi(params);
+            if (res.code === 200) {
+                message.success('创建任务成功');
+                form.resetFields();
+            }
+            onCancel();
+        } catch (err) {
+            // 校验失败,表单将显示错误
+        }
+    };
+    const fetchRagList = async () => {
+        // Implementation for fetching RAG list
+        const userInfo = LocalStorage.getUserInfo();
+        const userId = (userInfo?.id ?? '').toString();
+        const res = await apis.fetchTakaiAppList({
+            pageSize: 300,
+            pageNum: 1,
+            userId: userId,
+            isCollect: null,
+            typeId: null,
+        })
+        if (res.code !== 200) return;
+        const options = res.rows.map((item: any) => ({ label: item.name, value: item.appId }));
+        setRagOptions(options);
+    };
+    // 获取向量化模型
+    const fetchAppmodelType = async (id: string) => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('model_type');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                }
+            });
+            setModelType(list);
+            if (!id) {
+                form.setFieldsValue({
+                    // visible: list[0].value === '0' ? true : false
+                });
+            }
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    // 获取评测数据
+    const onFetchDatasetSelectList = async (appId: any) => {
+        try {
+            const res: any = await apis.fetchDatasetSelectList(
+                {
+                    appId: appId,
+                }
+            );
+            if (res.code === 200) {
+                const options = res.data.map((item: any) => ({ label: item.name, value: item.id }));
+                setSelecteevaluationData(options);
+
+            }
+        } catch (error) {
+            console.error('Error fetching dataset select list:', error);
+        }
+    };
+
+    const [openDataManagementMode, setOpenDataManagementMode] = useState(false);
+
+    return (
+        <Modal
+            open={openCreateTaskMode}
+            title="创建评测任务"
+            onCancel={onCancel}
+            onOk={handleOk}
+            width={'600px'}
+            footer={
+                <div>
+                    <Button
+                        className="mr-2 px-4 py-2 bg-gray-200 rounded"
+                        onClick={onCancel}
+                    >
+                        取消
+                    </Button>
+                    <Button
+                        type='primary'
+                        className="px-4 py-2 bg-blue-600 text-white rounded"
+                        onClick={handleOk}
+                    >
+                        确定
+                    </Button>
+                </div>
+            }
+            cancelText="取消"
+        >
+            <Form form={form} layout="vertical">
+                <Form.Item
+                    name="taskName"
+                    label="任务名称"
+                    rules={[{ required: true, message: '请输入任务名称' }]}
+                >
+                    <Input placeholder="输入任务名称" />
+                </Form.Item>
+
+                <Form.Item name="taskDescription" label="任务描述">
+                    <TextArea rows={4} placeholder="任务描述(可选)" />
+                </Form.Item>
+
+                <Form.Item name="evaluationType" label="评测类型" initialValue={'RAG评测'}>
+                    <div className='flex items-center gap-2 p-2 border rounded-md bg-blue-100  border-blue-300 cursor-pointer'>
+                        <Image width={18} height={18} src={aiwj} preview={false} className='mt-[-8px]' />
+                        <div className='text-xs'>
+                            <p>RAG评测</p>
+                            <p> 通过上传验证集自动测和打分,生成评测报告 </p>
+                        </div>
+                    </div>
+                </Form.Item>
+                <Form.Item name="reviewRag" label="评测RAG" 
+                    rules={[{ required: true, message: '请选择RAG应用' }]}
+                >
+                    <Select onChange={(e) => {
+                        reviewRag.current = e;
+                        setSelecteevaluationData([]);
+                        form.setFieldsValue({
+                            evaluationData: '',
+                        });
+                        onFetchDatasetSelectList(e)
+                    }} >
+                        {ragOptions.map(t => (
+                            <Option key={t.value} value={t.value}>
+                                {t.label}
+                            </Option>
+                        ))}
+                    </Select>
+                </Form.Item>
+
+                <Form.Item name="model" label="选择模型" initialValue={'Qwen3-30B'}>
+                    <div className='flex items-center justify-between'>
+                        <div className={'flex items-center gap-2 p-2 border rounded-md cursor-pointer w-[50%]' + (radioModel === 'Qwen3-30B' ? ' bg-blue-100  border-blue-300' : ' ml-0')}
+                            onClick={() => setRadioModel('Qwen3-30B')}>
+                            <Image src={model} width={50} preview={false} className='mt-[-8px]' />
+                            <div className='text-xs'>
+                                <p>Qwen3-30B</p>
+                                <p>Qwen3-30-A3B是阿里通义千问推出的混合专家模型,支持思考/非思考双模式切换。</p>
+                            </div>
+                        </div>
+
+                        {/* <div className={'flex items-center gap-2 p-2 border rounded-md  cursor-pointer ml-3' + (radioModel === 'Qwen2-72B' ? ' bg-blue-100  border-blue-300' : ' ml-0')}
+                            onClick={() => setRadioModel('Qwen2-72B')}>
+                            <Image width={50} src={model} preview={false} className='mt-[-8px]' />
+                            <div className='text-xs'>
+                                <p>Qwen2-72B</p>
+                                <p>Qwen2-72B-Instruct是Qwen2.5系列的指令调优版本,在数学、编程等复杂任务上表现卓越。</p>
+                            </div>
+                        </div> */}
+                    </div>
+                </Form.Item>
+                <Form.Item name="embeddingId"
+                    rules={[{ required: true, message: '请选择向量化模型' }]}
+                    label={
+                        <span>
+                            向量化模型
+                            <Tooltip
+                                title="提示:此向量化模型只针对下方评测数据"
+                                placement="right"
+                            >
+                                <InfoCircleOutlined style={{ marginLeft: 4, color: '#1890ff' }} />
+                            </Tooltip>
+                        </span>
+                    }
+                >
+                    {
+                        <Select
+                            style={{ width: '100%' }}
+                            placeholder='请选择向量化模型'
+                            allowClear={true}
+                        >
+                            {
+                                modelType.map((item, index) => {
+                                    return <Option value={item.value} key={index}>
+                                        {item.label}
+                                    </Option>
+                                })
+                            }
+                        </Select>
+                    }
+                </Form.Item>
+                <div className="flex gap-2">
+
+                    <Form.Item name="evaluationData" label="评测数据" style={{width:'100%'}}
+                        rules={[{ required: true, message: '请选择评测数据' }]}
+                    >
+                        <Select placeholder="请先选择评测RAG应用">
+                            {evaluationDataOptions.map(t => (
+                                <Option key={t.value} value={t.value}>
+                                    {t.label}
+                                </Option>
+                            ))}
+                        </Select>
+
+                    </Form.Item>
+                    <Button className='mt-[30px]' type="primary" icon={<PlusCircleOutlined />} onClick={() => {
+                        if(reviewRag.current){
+                            setOpenDataManagementMode(true)
+                        }else{
+                            message.error('请先选择评测RAG应用')
+                        }
+                    }} />
+                </div>
+
+                <Form.Item name="flg" label="立即执行" initialValue={true}
+                    rules={[{ required: true, message: '请选择是否立即执行' }]}
+                >
+                    <Radio.Group>
+                        <Radio value={true}>是</Radio>
+                        <Radio value={false}>否</Radio>
+                    </Radio.Group>
+                </Form.Item>
+            </Form>
+            {openDataManagementMode && <DataManagementMode openDataManagementMode={openDataManagementMode}
+                reviewRagdata={reviewRag.current}
+                onSubmit={(values) => {
+                    setSelecteevaluationData((pre) => {
+                        return [...pre, {
+                            label: values.name,
+                            value: values.id
+                        }]
+                    })
+                    form.setFieldsValue({
+                        evaluationData: values.id,
+                    });
+                    console.log('values---- 评测历史', values)
+                }}
+                onCancel={() => { setOpenDataManagementMode(false); }} />}
+        </Modal>
+    );
+};
+
+export default CreateTaskMode;

+ 163 - 0
src/pages/deepseek/evaluationTool/evaluationTask/components/evaluationTaskHistory.tsx

@@ -0,0 +1,163 @@
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import { Table, TableColumnsType, TablePaginationConfig, Drawer, Row, Col, Input, Button, Spin } from 'antd';
+import { StepForwardOutlined } from '@ant-design/icons';
+import dayjs from 'dayjs';
+import store from './evaluationTaskHistoryStore';
+import { Record } from '../types';
+// import InfoModal from './InfoModal';
+// import PreviewModal from './PreviewModal';
+// import LocalStorage from '@/LocalStorage';
+
+
+interface AuditHistoryProps {
+    open: boolean;
+    onClose: () => void;
+    record?: Record;
+}
+
+const AuditHistory: React.FC<AuditHistoryProps> = ({ open, onClose, record }) => {
+    const {
+        state,
+        init,
+        onChangePagination,
+        onSetName
+    } = store;
+    const {
+        listLoading,
+        list,
+        infoModalId,
+        infoModalOpen,
+        page
+    } = state;
+
+    const [drawerFlag, setDrawerFlag] = React.useState<boolean>(false);
+    const [drawerData, setDrawerData] = React.useState<any>({});
+    React.useEffect(() => {
+        if (open) {
+            // const userInfo = LocalStorage.getUserInfo();
+            // const userId = (userInfo?.id ?? '').toString();
+            onSetName(record?.taskName || '');
+            init();
+        }
+    }, [open]);
+    const columns: TableColumnsType<any> = [
+        {
+            title: '任务名称/ID', dataIndex: 'taskId', width: 220,
+            render: (text, record: any) => {
+                return <div>
+                    <div style={{ fontWeight: 600 }}>{record.taskName}</div>
+                    <div style={{ color: '#999', fontSize: 12, marginTop: 4 }}>ID: {record?.taskId}
+                    </div>
+                </div>
+            },
+        },
+        {
+            title: '状态', dataIndex: 'status', width: 120,
+            render: (text) => {
+                let color = '#52c41a';
+                let statusText = '';
+                if (text === '0') {
+                    color = '';
+                    statusText = '未执行';
+                } else if (text === '1') {
+                    return <Spin size="small" />;
+                } else if (text === '2') {
+                    color = '#52c41a';
+                    statusText = '成功';
+                } else if (text === '3') {
+                    color = '';
+                    statusText = '失败';
+                }
+                return <span style={{ color }}>{statusText}</span>;
+            }
+        },
+        {
+            title: '模型服务', dataIndex: 'model', width: 120
+        },
+        { title: '类型', dataIndex: 'evaluationType', width: 140 },
+        { title: '数据集', dataIndex: 'datesetName', width: 140 },
+        { title: '结果打分', dataIndex: 'resultStore', width: 140 },
+        { title: '创建时间', dataIndex: 'createTime', width: 140 },
+        { title: '开始时间', dataIndex: 'startTime', width: 140 },
+        { title: '结束时间', dataIndex: 'endTime', width: 140 },
+        {
+            title: '操作',
+            dataIndex: 'status',
+            align: 'center',
+            width: 120,
+            fixed: 'right',
+            render: (val, record: any) => {
+                if (record.status === '3') {
+                    return (<p className='cursor-pointer' onClick={() => {
+                    }}>
+                        下载
+                    </p>)
+                } else {
+                    return (<p className='text-primary cursor-pointer' onClick={() => {
+                        window.open(record.fullUrl)
+                    }}>
+                        下载
+                    </p>)
+                }
+            },
+        }
+    ];
+    const paginationConfig: TablePaginationConfig = {
+        // 显示数据总量
+        showTotal: (total: number) => {
+            return `共 ${total} 条`;
+        },
+        // 展示分页条数切换
+        showSizeChanger: true,
+        // 指定每页显示条数
+        pageSizeOptions: ['10', '20', '50', '100'],
+        // 快速跳转至某页
+        showQuickJumper: true,
+        current: page.pageNum,
+        pageSize: page.pageSize,
+        total: page.total,
+        onChange: async (page, pageSize) => {
+            await onChangePagination(page, pageSize);
+        },
+    };
+    const [kbName, setKbName] = React.useState<string>('');
+    const handleSearch = async () => {
+        init();
+    }
+    return (
+        <Drawer
+            title="评测历史"
+            width="80%"
+            open={open}
+            onClose={onClose}
+        >
+            {/* <div style={{ marginBottom: 12 }}>
+                <Row gutter={12} align="middle">
+                    <Col span={6}>
+                        <Input placeholder="名称" value={kbName} onChange={(e) => {
+                            setKbName(e.target.value)
+                            onSetName(e.target.value)
+                        }} />
+                    </Col>
+                    <Col>
+                        <Button type="primary" onClick={handleSearch}>搜索</Button>
+                    </Col>
+                </Row>
+            </div> */}
+            <div className='knowledgeLibList'>
+                <div className='knowledgeLibList-table'>
+                    <Table
+                        scroll={{ x: 'max-content' }}
+                        rowKey={(record) => record.createTime}
+                        loading={listLoading}
+                        columns={columns}
+                        dataSource={list}
+                        pagination={paginationConfig}
+                    />
+                </div>
+            </div>
+        </Drawer>
+    );
+}
+export default observer(AuditHistory);

+ 167 - 0
src/pages/deepseek/evaluationTool/evaluationTask/components/evaluationTaskHistoryStore.ts

@@ -0,0 +1,167 @@
+import { makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import { apis, ModifyDocumentApiParams } from '@/apis';
+import { State, ReadonlyState, StateAction, DocumentLibListStore } from '../types';
+
+// 定义状态
+const stateGenerator = (): ReadonlyState => ({
+    listLoading: false,
+    list: [],
+    infoModalId: '',
+    infoModalOpen: false,
+    name:'',
+    page: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0,
+    },
+});
+
+// 修改状态
+const stateActionsGenerator = (state: State): StateAction => {
+    return {
+        setListLoading: (loading) => {
+            state.listLoading = loading;
+        },
+        setList: (list) => {
+            state.list = list;
+        },
+        setInfoModalId: (id) => {
+            state.infoModalId = id;
+        },
+        setInfoModalOpen: (open) => {
+            state.infoModalOpen = open;
+        },
+        setPage: (page) => {
+            state.page = page;
+        },
+        setName:(name) => {
+            state.name = name;
+        },
+    };
+};
+
+// 使用仓库
+const useKnowledgeLibListStore = (): DocumentLibListStore => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    const api = {
+        // 获取审核列表
+        fetchApplicationLibList: async () => {
+            actions.setListLoading(true);
+            try {
+                const data = {
+                    pageNum: state.page.pageNum,
+                    pageSize: state.page.pageSize,
+                    taskName: state.name,
+                };
+                const res:any = await apis.fetchTaskHistoryList(data);
+                console.log(res.rows, 'rew.rows');
+                actions.setList(res.rows);
+                actions.setPage({
+                    ...state.page,
+                    total: res.total,
+                });
+            } catch (error: any) {
+                console.error(error);
+            } finally {
+                actions.setListLoading(false);
+            }
+        },
+        
+        // 应用审核
+        modifyDocumentLib: async (documentId: string, userId: string, data: ModifyDocumentApiParams) => {
+            try {
+                const res = await apis.modifyTakaiAuditDocumentLibApi(documentId, data);
+                // 获取审核列表
+                api.fetchApplicationLibList();
+                if(res.data === 1 && res.code === 200){
+                    message.success('修改成功');
+                }else{
+                    message.error('修改失败');
+                }
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+        // 获取详情
+        fetchTakaiApplicationDetail: async (appId: string) => {
+            try {
+                const res = await apis.fetchTakaiApplicationDetail(appId);
+                console.log(res, 'resresres');
+                return res;
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+    }
+    // 点击查看出现弹窗
+    const onClickfetchTakaiApplicationDetail = async (appId: string) => {
+        if(appId){
+            await api.fetchTakaiApplicationDetail(appId);
+        }
+    }
+    // 更改分页
+    const onChangePagination: DocumentLibListStore['onChangePagination'] = async (pageNumber, pageSize) => {
+        actions.setPage({
+            ...state.page,
+            pageNum: pageNumber,
+            pageSize: pageSize,
+        });
+        // 获取知识库列表
+        await api.fetchApplicationLibList();
+    }
+
+    // 点击创建
+    const onClickCreate: DocumentLibListStore['onClickCreate'] = () => {
+        const initialInfoModalId = stateGenerator().infoModalId;
+
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 点击修改
+    const onClickModify: DocumentLibListStore['onClickModify'] = (documentId) => {
+        actions.setInfoModalId(documentId);
+        actions.setInfoModalOpen(true);
+    }
+
+
+    
+    // 初始渲染
+    const init: DocumentLibListStore['init'] = async () => {
+        // 获取知识库列表
+        await api.fetchApplicationLibList();
+    }
+
+    // 状态重置
+    const reset: DocumentLibListStore['reset'] = () => {
+        const initialListLoading = stateGenerator().listLoading;
+        const initialList = stateGenerator().list;
+        const initialInfoModalId = stateGenerator().infoModalId;
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+        const initialPage = stateGenerator().page;
+
+        actions.setListLoading(initialListLoading);
+        actions.setList(initialList);
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(initialInfoModalOpen);
+        actions.setPage(initialPage);
+    }
+    const onSetName = (name: string) => {
+        actions.setName(name);
+    }
+    return {
+        state,
+        onChangePagination,
+        onClickCreate,
+        onClickModify,
+        onClickfetchTakaiApplicationDetail,
+        init,
+        reset,
+        onSetName
+    };
+};
+
+export default useKnowledgeLibListStore();

+ 74 - 0
src/pages/deepseek/evaluationTool/evaluationTask/components/indicatorRag.tsx

@@ -0,0 +1,74 @@
+import React, { useMemo, useRef, useEffect } from 'react';
+import { Modal, Button } from 'antd';
+import { Radar } from '@antv/g2plot';
+interface IndicatorRagProps {
+    open: boolean;
+    onCancel: () => void;
+    record: any;
+}
+
+const IndicatorRag: React.FC<IndicatorRagProps> = ({ open, onCancel, record }) => {
+    const containerRef = useRef<HTMLDivElement | null>(null);
+    const chartRef = useRef<any>(null);
+
+    const chartData = useMemo(() => {
+        return [
+            { item: '答案忠诚度', score: (Number(record.answerLoyalty)*100), name: record.taskName },
+            { item: '噪声敏感度', score: (Number(record.noiseSensitivity)*100), name: record.taskName },
+            { item: '答案正确性', score: (Number(record.correctAnswer)*100), name: record.taskName },
+            { item: '答案相关性', score: (Number(record.answerRelevance)*100), name: record.taskName },
+            { item: '上下文相关性', score: (Number(record.contextRelevance)*100), name: record.taskName },
+            { item: '上下文召回率', score: (Number(record.contextRecall)*100), name: record.taskName },
+        ];
+    }, [record]);
+
+    useEffect(() => {
+        if (!open) return;
+        if (!containerRef.current) return;
+        if (!chartRef.current) {
+            chartRef.current = new Radar(containerRef.current, {
+                data: chartData,
+                xField: 'item',
+                yField: 'score',
+                seriesField: 'name',
+                radius: 0.8,
+                meta: {
+                    score: {
+                        min: 0,
+                        max: 100,
+                    },
+                },
+                area: {},
+                point: { size: 3 },
+                interactions: [{ type: 'element-active' }],
+                renderer: 'svg',
+                padding: 'auto',
+            });
+            chartRef.current.render();
+        } else {
+            chartRef.current.changeData(chartData);
+        }
+
+        return () => {
+            if (chartRef.current) {
+                chartRef.current.destroy();
+                chartRef.current = null;
+            }
+        };
+    }, [open]);
+
+    useEffect(() => {
+        if (chartRef.current) {
+            chartRef.current.changeData(chartData);
+        }
+    }, [chartData]);
+
+    return (
+        <Modal open={open} title="指标雷达图" onCancel={onCancel} footer={null} width={600}>
+            <div style={{ width: '100%', height: 360 }} ref={containerRef} />
+            {/* <p>RAG应用列表</p> */}
+        </Modal>
+    );
+};
+
+export default IndicatorRag;

+ 269 - 0
src/pages/deepseek/evaluationTool/evaluationTask/list/index.tsx

@@ -0,0 +1,269 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { Table, Pagination, Space, Button, TablePaginationConfig, Input, Modal, message, Spin } from 'antd';
+import type { ColumnsType } from 'antd/es/table';
+import { observer } from 'mobx-react';
+import { SearchOutlined, BulbOutlined, CloseOutlined,LayoutOutlined,DeleteOutlined,RedoOutlined,RadarChartOutlined } from '@ant-design/icons';
+import LocalStorage from '@/LocalStorage';
+
+import store from './store';
+import Step from '@/components/step';
+import CreateTaskMode from '../components/CreateTaskMode';
+import IndicatorRag from '../components/indicatorRag';
+import EvaluationTaskHistory from '../components/evaluationTaskHistory';
+import { deleteEvaluationApi, beginEvaluationApi } from '@/apis';
+import { Tooltip } from 'antd/lib';
+
+interface KnowledgeRecord {
+  knowledgeName: string;
+  knowledgeId: string | number;
+  length: string | number; // 使用空间
+  appNames: string; // 关联空间
+  documentSize: number; // 文件数量
+  createTime: string; // 创建时间
+  updateTime: string; // 更新时间
+  status: string | number; // 状态
+}
+
+
+const RevisionToolList: React.FC = () => {
+  const [loading, setLoading] = useState(false);
+
+  const { state, init, handleNameChange, onChangePagination } = store;
+
+  const { reviseList, knowledgeName } = state
+
+
+
+  useEffect(() => {
+    // 模拟加载状态
+    setLoading(true);
+    const t = setTimeout(() => setLoading(false), 250);
+    return () => clearTimeout(t);
+  }, [state.page]);
+
+  const [deleteEvaluationTask, setDeleteEvaluationTask] = useState<boolean>(false); // 是否删除评测任务
+  const [startEvaluationTask, setStartEvaluationTask] = useState<boolean>(false); // 是否开始评测任务
+  const [prewEvaluationTask, setPrewEvaluationTask] = useState<boolean>(false); // 是否雷达图预览
+  const [userInfoAll, setUserInfoAll] = React.useState<any>({});
+
+  const [openEvaluationTaskHistory,setOpenEvaluationTaskHistory] = useState<boolean>(false);
+
+  useEffect(() => {
+    init();
+
+    setDeleteEvaluationTask(LocalStorage.getStatusFlag('evaluationTool:evaluationTask:del'));
+    setStartEvaluationTask(LocalStorage.getStatusFlag('evaluationTool:evaluationTask:start'));
+    setPrewEvaluationTask(LocalStorage.getStatusFlag('evaluationTool:evaluationTask:prew'));
+    setUserInfoAll(LocalStorage.getUserInfo());
+    const handleEvaluationTaskCreate = (e: any) => {
+      if (e.detail && e.detail.platform === 'Task') {
+        setOpenCreateTaskMode(true);
+      }
+    }
+
+    const handlEvaluationTaskHistoryCreate = (e: any) => {
+      if (e.detail && e.detail.platform === 'evaluationTaskHistory') {
+        setOpenEvaluationTaskHistory(true);
+      }
+    }
+
+
+
+    window.addEventListener('evaluationTask', handleEvaluationTaskCreate as EventListener);
+    window.addEventListener('evaluationTaskHistory', handlEvaluationTaskHistoryCreate as EventListener);
+
+    return () => {
+      window.removeEventListener('evaluationTask', handleEvaluationTaskCreate as EventListener);
+      window.removeEventListener('evaluationTaskHistory', handlEvaluationTaskHistoryCreate as EventListener);
+    };
+  }, []);
+
+  const steps = [
+    {
+      title: '创建评测任务',
+      description: '上传本地数据集,选择需要评测的RAG或模型,进行自动评测;',
+      number: 1,
+    },
+    {
+      title: '配置打分模型',
+      description: '选择自动打分的模型,设置不同的评估维度;',
+      number: 2,
+    },
+    {
+      title: '查看评测报告',
+      description: '生成多维度的评测报告,查看详细评分、能力指标、评估日志。',
+      number: 3,
+    }
+  ]
+  const [showGuide, setShowGuide] = React.useState<boolean>(() => localStorage.getItem('revisionToolGuideHidden') !== 'true');
+  const hideGuide = () => { localStorage.setItem('revisionToolGuideHidden', 'true'); setShowGuide(false); };
+  const [record, setRecord] = useState<KnowledgeRecord>({} as KnowledgeRecord);
+  const [openIndicatorRag, setOpenIndicatorRag] = useState<boolean>(false);
+
+  const onBeginEvaluationApi = async (record: any) => {
+    const res: any = await beginEvaluationApi({ ...record });
+    if (res.code === 200) {
+      message.success('评测任务启动成功');
+      init();
+    }
+  }
+
+
+  const columns: ColumnsType<KnowledgeRecord> = [
+    {
+      title: '任务名称/ID', dataIndex: 'taskId', width: 220,
+      render: (text, record: any) => {
+        return <div>
+          {(prewEvaluationTask || userInfoAll.id === record.createBy) ? <div style={{ fontWeight: 600 }} className='cursor-pointer text-primary' onClick={() => {
+            setOpenIndicatorRag(true)
+            setRecord(record)
+          }} >{record.taskName}</div> : <div style={{ fontWeight: 600 }}>{record.taskName}</div>}
+          <div style={{ color: '#999', fontSize: 12, marginTop: 4 }}>ID: {record?.taskId}
+          </div>
+        </div>
+      },
+    },
+    {
+      title: '状态', dataIndex: 'status', width: 120,
+      render: (text) => {
+        let color = '#52c41a';
+        let statusText = '';
+        if (text === '0') {
+          color = '';
+          statusText = '未执行';
+        } else if (text === '1') {
+          return <Spin size="small" />;
+        } else if (text === '2') {
+          color = '#52c41a';
+          statusText = '成功';
+        } else if (text === '3') {
+          color = '';
+          statusText = '失败';
+        }
+        return <span style={{ color }}>{statusText}</span>;
+      }
+    },
+    {
+      title: '模型服务', dataIndex: 'model', width: 120
+    },
+    { title: '类型', dataIndex: 'evaluationType', width: 140 },
+    { title: '数据集', dataIndex: 'datesetName', width: 140 },
+    { title: '结果打分', dataIndex: 'resultStore', width: 140 },
+    { title: '创建时间', dataIndex: 'createTime', width: 140 },
+    { title: '开始时间', dataIndex: 'startTime', width: 140 },
+    { title: '结束时间', dataIndex: 'endTime', width: 140 },
+    {
+      title: '操作',
+      dataIndex: 'status',
+      align: 'center',
+      width: 120,
+      render: (val, record: any) => (
+        <p className='flex items-center justify-center'>
+          {(prewEvaluationTask || userInfoAll.id === record.createBy) && <Tooltip title="详情">
+            <Button 
+            type="link"
+            style={{ paddingLeft: 0 }}
+            onClick={()=>{
+             setOpenIndicatorRag(true)
+            setRecord(record)
+          }} icon={<RadarChartOutlined />}/>
+          </Tooltip>}
+          { (record.status === '2'||record.status === '3') &&<Tooltip title="查看评测历史">
+            <Button 
+            type="link"
+            style={{ paddingLeft: 0 }}
+            onClick={()=>{
+            setOpenEvaluationTaskHistory(true);
+            setRecord(record)
+          }} icon={<LayoutOutlined />}/>
+          </Tooltip>}
+          {(startEvaluationTask || userInfoAll.id === record.createBy) && record.status === '0' && <Button type="link" onClick={async () => {
+            onBeginEvaluationApi(record)
+          }}>开始</Button>}
+          {(startEvaluationTask || userInfoAll.id === record.createBy) && record.status !== '0'&&record.status !== '1' && <Tooltip title="重新评测"><Button type="link" icon={<RedoOutlined />} onClick={() => { onBeginEvaluationApi(record) }}></Button></Tooltip>}
+          {(deleteEvaluationTask || userInfoAll.id === record.createBy) && <Button type="link"
+           icon={<DeleteOutlined />}
+           style={{ color: '#ff4d4f', paddingLeft: 0 }}
+            onClick={() => {
+              Modal.confirm({
+                title: '提示',
+                content: `确定删除【${record.taskName}】任务吗?`,
+                okType: 'danger',
+                onOk: async () => {
+                  const res: any = await deleteEvaluationApi(record.taskId);
+                  if (res.code === 200) {
+                    message.success('删除成功');
+                    init();
+                  }
+                }
+              });
+            }} ></Button>}
+
+        </p>
+      ),
+    }
+  ]
+
+  const paginationConfig: TablePaginationConfig = {
+    // 显示数据总量
+    showTotal: (total: number) => {
+      return `共 ${total} 条`;
+    },
+    // 展示分页条数切换
+    showSizeChanger: true,
+    // 指定每页显示条数
+    pageSizeOptions: ['10', '20', '50', '100'],
+    // 快速跳转至某页
+    showQuickJumper: true,
+    current: state.page.page,
+    pageSize: state.page.size,
+    total: state.page.total,
+    onChange: async (page, pageSize) => {
+      await onChangePagination(page, pageSize);
+    },
+  };
+  const [openCreateTaskMode, setOpenCreateTaskMode] = useState(false);
+  const [title, setTitle] = useState('');
+  return (
+    <div style={{ padding: 20, background: '#fff' }}>
+      {showGuide && <> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
+        <div style={{ fontSize: 13, color: '#333', display: 'flex', alignItems: 'center', gap: 6 }}>
+          <BulbOutlined style={{ color: '#faad14' }} />
+          提示: 开始评测模型
+        </div>
+        <CloseOutlined onClick={hideGuide} style={{ color: '#999', cursor: 'pointer' }} />
+      </div>
+        <Step steps={steps} className='mb-3' /></>}
+      <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 12 }} className='items-center'>
+        <p style={{ margin: 0 }}>任务管理</p>
+        <Space.Compact style={{ width: '300px' }}>
+          <Input
+            placeholder='请输入任务名称'
+            value={knowledgeName}
+            onChange={(e) => handleNameChange(e.target.value)}
+          />
+          <Button type="primary" onClick={() => { init() }}><SearchOutlined /></Button>
+        </Space.Compact>
+      </div>
+      {/* 表格 */}
+      <Table
+        columns={columns}
+        dataSource={reviseList}
+        rowKey="taskId"
+        loading={loading}
+        pagination={paginationConfig}
+      />
+      {/* 修订工具弹窗 */}
+      {/* { <ReviseDrawer openDrawer={openDrawer} record={record} title={title} onClose={() => setOpenDrawer(false)} />} */}
+      <CreateTaskMode openCreateTaskMode={openCreateTaskMode} onCancel={() => { setOpenCreateTaskMode(false), init() }}></CreateTaskMode>
+      <IndicatorRag open={openIndicatorRag} record={record} onCancel={() => {
+        setOpenIndicatorRag(false);
+      }}></IndicatorRag>
+      <EvaluationTaskHistory open={openEvaluationTaskHistory}  record={record} onClose={() => {
+        setOpenEvaluationTaskHistory(false);
+      }}></EvaluationTaskHistory>
+    </div>
+  );
+};
+
+export default observer(RevisionToolList);

+ 77 - 0
src/pages/deepseek/evaluationTool/evaluationTask/list/store.ts

@@ -0,0 +1,77 @@
+import { action, makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import LocalStorage from '@/LocalStorage';
+import { fetchEvaluationList } from '@/apis';
+import { downloadFile } from '@/utils/index'
+import { data } from 'react-router-dom';
+
+// 定义状态
+const stateRevise = (): any => ({
+    reviseList: [] as any[],
+    knowledgeName:'',
+    page: {
+        page: 1,
+        size: 10,
+        total: 0,
+    },
+})
+// 修改状态
+const stateActionRevise = (state: any) => {
+
+    return{
+        setPage: (page: { page: number; size: number; total: number }) => {
+            state.page = page;
+        },
+        setKnowledgeName: (knowledgeName: string) => {
+            state.knowledgeName = knowledgeName;
+        },
+    }
+}
+// 使用仓库
+const useRevisionToolListStore = () => {
+    const state = makeAutoObservable(stateRevise());
+    const actions = stateActionRevise(state);
+
+    const onFetchEvaluationList = async () => {
+        try {
+            const data = {
+                pageNum: state.page.page,
+                pageSize: state.page.size,
+                name: state.knowledgeName || '',
+            }
+            const res:any = await fetchEvaluationList(data);
+            if (res && res.code === 200) {
+                state.reviseList = res.rows;
+                state.page.total = res.total;
+            } else {
+                message.error(res.message || '获取评估任务列表失败');
+            }
+        } catch (error) {
+            message.error('获取评估任务列表异常');
+        }
+    }
+    const handleNameChange = (name: string) => {
+        actions.setKnowledgeName(name);
+    };
+    const onChangePagination = async (page: number, pageSize: number) => {
+        actions.setPage({
+            ...state.page,
+            page: page,
+            size: pageSize,
+        });
+        await onFetchEvaluationList();
+    }
+
+    const init = ()=>{
+        onFetchEvaluationList()
+    }
+
+
+    return {
+        state,
+        init,
+        handleNameChange,
+        onChangePagination
+    };
+}
+export default useRevisionToolListStore();

+ 52 - 0
src/pages/deepseek/evaluationTool/evaluationTask/types.ts

@@ -0,0 +1,52 @@
+import { ModifyDocumentApiParams } from '@/apis';
+
+export type Record = {
+    [x: string]: any;
+    documentId: string,
+    knowledgeId: string,
+    name: string,// 知识文件名称
+    createTime: string,// 创建时间
+    updateTime: string,// 更新时间
+};
+
+// 定义状态
+export type State = {
+    name?:string;
+    listLoading: boolean,
+    list: Record[],
+    infoModalId: string,
+    infoModalOpen: boolean,
+    page: {
+        pageNum: number,
+        pageSize: number,
+        total: number,
+    },
+};
+
+// 只读状态
+export type ReadonlyState = Readonly<State>;
+
+// 修改状态
+export type StateAction = {
+    setListLoading: (loading: State['listLoading']) => void,
+    setList: (list: State['list']) => void,
+    setInfoModalId: (id: State['infoModalId']) => void,
+    setInfoModalOpen: (open: State['infoModalOpen']) => void,
+    setPage: (page: State['page']) => void,
+    setName: (name: string) => void,
+};
+
+// 仓库类型
+export type DocumentLibListStore = {
+    state: ReadonlyState,
+    onChangePagination: (pageNum: number, pageSize: number) => Promise<any>,
+    onClickCreate: () => void,
+    onClickModify: (documentId: string) => void,
+    onClickfetchTakaiApplicationDetail: (appId: string) => void,
+    infoModalOnClickConfirm?: (documentId: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    infoModalOnClickCancel?: (documentId: string, userId: string, data: ModifyDocumentApiParams) => Promise<any>,
+    infoModalOnClickClose?:  () => void,
+    init: (userId?: string) => Promise<any>,
+    reset: () => void,
+    onSetName: (name: string) => void,
+};

+ 116 - 0
src/pages/deepseek/knowledgeLib/detail/components/InfoModal.tsx

@@ -0,0 +1,116 @@
+import * as React from 'react';
+import { Modal, Spin, Form, Input, Select, message } from 'antd';
+import { apis, ModifyDocumentApiParams } from '@/apis';
+
+const FormItem = Form.Item;
+const { Option } = Select;
+
+interface Props {
+    id: string,
+    open: boolean,
+    onClickConfirm: (id: string, data: ModifyDocumentApiParams) => Promise<any>,
+    onClickCancel: () => void,
+};
+
+const InfoModal: React.FC<Props> = (props: Props) => {
+    const {
+        id,
+        open,
+        onClickConfirm,
+        onClickCancel
+    } = props;
+
+    const [form] = Form.useForm();
+
+    const [loading, setLoading] = React.useState<boolean>(false);
+
+    // 获取知识详情
+    const fetchDetail = async () => {
+        try {
+            const res = await apis.fetchTakaiDocumentDetailLibApi(props.id);
+            const { id, name, knowledge_type, custom_separator, sentence_size } = res.data;
+            form.setFieldsValue({
+                id: id,
+                name: name,
+                knowledge_type: knowledge_type,
+                custom_separator: custom_separator,
+                sentence_size: sentence_size,
+            });
+        } catch (error: any) {
+            message.error(error.msg);
+        }
+    };
+
+    const init = async () => {
+        setLoading(true);
+        if (props.id) {
+            await fetchDetail();
+        }
+        setLoading(false);
+    };
+
+    React.useEffect(() => {
+        init();
+    }, []);
+
+    // 点击确定
+    const handleClickConfirm = () => {
+        form.validateFields().then(async (values) => {
+            const data = { ...values };
+            if(values.knowledge_type === '5'){
+                data.custom_separator = [ '"\\n"'];
+                data.sentence_size = 300;
+            }else{
+                data.sentence_size = 20;
+                data.custom_separator = [ '"\\n"'];
+            }
+            console.log(data, 'data');
+            await onClickConfirm(props.id, data);
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+
+    return (
+        <Modal
+            width={500}
+            title='重命名'
+            maskClosable={false}
+            centered={true}
+            open={open}
+            onOk={handleClickConfirm}
+            onCancel={onClickCancel}
+        >
+            <Spin spinning={loading}>
+                <Form form={form} layout='vertical'>
+                    <FormItem
+                        label='文件名称'
+                        name='name'
+                    >
+                        <Input placeholder='请输入知识库名称' />
+                    </FormItem>
+                    {/* <FormItem
+                        label='知识类型'
+                        name='knowledge_type'
+                        rules={[{ required: true, message: '知识类型不能为空' }]}
+                    >
+                        <Select
+                            style={{ width: '100%' }}
+                            placeholder='请选择知识类型'
+                            allowClear={true}
+                        >
+                            <Option value='1'>1:文章知识:支持pdf,url,docx</Option>
+                            <Option value='2'>2:问答知识-文档:支持pdf,url,docx</Option>
+                            <Option value='3'>3:问答知识-表格:支持xlsx</Option>
+                            <Option value='4'>4:商品库-表格:支持xlsx</Option>
+                            <Option value='5'>5:自定义:支持pdf,url,docx</Option>
+                        </Select>
+                    </FormItem> */}
+                    <div style={{ width: '100%', height: 10 }}></div>
+                </Form>
+            </Spin>
+        </Modal>
+    );
+};
+
+export default InfoModal;

+ 305 - 0
src/pages/deepseek/knowledgeLib/detail/components/InfoModalSetting.tsx

@@ -0,0 +1,305 @@
+import * as React from 'react';
+import { Modal, Spin, Form, Input, Select, message, Checkbox, GetProp, Tooltip } from 'antd';
+import { InboxOutlined, QuestionCircleOutlined } from '@ant-design/icons';
+
+import { apis, ModifyDocumentSettingApiParams } from '@/apis';
+
+import useAppState from '@/store';
+const { getAppState } = useAppState();
+const { TextArea } = Input;
+
+const FormItem = Form.Item;
+const { Option } = Select;
+
+
+interface Props {
+    id: string,
+    open: boolean,
+    record?: any,
+    onClickConfirm: (id: string, data: ModifyDocumentSettingApiParams) => Promise<any>,
+    onClickCancel: () => void,
+};
+
+const InfoModalSetting: React.FC<Props> = (props: Props) => {
+    const {
+        id,
+        open,
+        onClickConfirm,
+        onClickCancel,
+        record
+    } = props;
+
+    const [form] = Form.useForm();
+
+    const [loading, setLoading] = React.useState<boolean>(false);
+
+    const [isVisibleSlice, setIsVisibleSlice] = React.useState(false);
+    const [titleName, setTitleName] = React.useState<string>('');
+
+    const [standardClass, setStandardClass] = React.useState<any>([]);// 选择分类-下拉框
+    const [parsingTypeList, setParsingTypeList] = React.useState<any>([]);// 解析工具
+    const [parsingTypeListBackup, setParsingTypeListBackup] = React.useState<any[]>([]);// 解析工具-下拉选项-备份数据
+
+    const [splittingOldList, setSplittingOldList] = React.useState<any[]>([]); // 旧的切分规则列表
+    const [splittingTypeList, setSplittingTypeList] = React.useState<any>([]); // 选择切分规则
+    const [standardClassification, setStandardClassification] = React.useState<string>(''); // 选择分类设置
+    const onChangeF = (value: string) => {
+        if (value === '0') {
+            setIsVisibleSlice(!isVisibleSlice);
+        } else {
+            setIsVisibleSlice(false);
+        }
+    };
+    // 获取解析工具
+    const fetchAppstandardClass = async () => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('parsing_type');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                }
+            });
+            form.setFieldsValue({
+                customSeparator: record?.customSeparator,
+            })
+
+            setParsingTypeList(list);
+            setParsingTypeListBackup(list);
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    // 获取向默认切分规则
+    const fetchsplittingType = async () => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('splitting_type');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                    remark: item.remark,
+                }
+            });
+            if (record.customSeparator === '0') {
+                setIsVisibleSlice(!isVisibleSlice);
+            }
+            if (record.parsingType === '2') {
+                const newList = list.filter((item: any) => item.value !== '3');
+                setSplittingTypeList(newList);
+            }else{
+                setSplittingTypeList(list);
+            }
+            setSplittingOldList(list);
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    const init = async () => {
+        setLoading(true);
+        if (props.id) {
+            fetchsplittingType()
+            fetchAppstandardClass()
+            
+        }
+        setLoading(false);
+        const res: any = await getAppState();
+        const reslist = res.filter((item: any) => {
+            if (record?.standardClassification === '0' || record?.standardClassification === '1') {
+                if (item.value === '0' || item.value === '1') {
+                    return item
+                }
+            }
+            if (record?.standardClassification === '3') {
+                if (item.value === '3') {
+                    return item
+                }
+            }
+            if (record?.standardClassification === '2') {
+                if (item.value === '2') {
+                    return item
+                }
+            }
+        })
+        setStandardClass(reslist);
+    };
+
+    React.useEffect(() => {
+        init();
+        form.setFieldsValue({
+            parsingType: record?.parsingType,
+            customSeparator: record?.customSeparator,
+            standardClassification: record?.standardClassification,
+            sliceValue: record?.sliceValue,
+            name: record?.name,
+            remark: record?.remark,
+        })
+        setStandardClassification(record?.standardClassification);
+    }, []);
+
+    // 点击确定
+    const handleClickConfirm = () => {
+        form.validateFields().then(async (values) => {
+            const data = { ...record, ...values, konowledge_id: record.knowledgeId };
+            console.log(loading, 'loading');
+            await onClickConfirm(props.id, data);
+        }).catch((error) => {
+            console.error(error);
+        })
+    };
+
+    return (
+        <Modal
+            width={600}
+            title='知识配置'
+            maskClosable={false}
+            centered={true}
+            open={open}
+            onOk={handleClickConfirm}
+            onCancel={onClickCancel}
+            confirmLoading={loading}
+        >
+            <Spin spinning={loading}>
+                <Form form={form} layout='vertical'>
+                    <FormItem
+                        label='分类设置'
+                        name='standardClassification'
+                    >
+                        <Select
+                            style={{ width: '100%' }}
+                            allowClear={true}
+                            optionLabelProp="label"
+                            placeholder='请选择分类设置'
+                            onChange={(e) => {
+                                // 切换分类时,清空已选本地文件與 OSS 列表
+                                setStandardClassification(e);
+                                if (e === '0') {
+                                    const newSplittingList = splittingOldList.filter((item: any) => item.value === '3');
+                                    setSplittingTypeList(newSplittingList);
+                                    form.setFieldsValue({
+                                        customSeparator: newSplittingList[0]?.value,
+                                    });
+
+                                    const newParsingTypeList = parsingTypeListBackup.filter((item: any) => item.value === '0');
+                                    setParsingTypeList(newParsingTypeList);
+                                    form.setFieldsValue({
+                                        parsingType: newParsingTypeList[0]?.value,
+                                    })
+                                } else {
+                                    setSplittingTypeList(splittingOldList);
+                                    setParsingTypeList(parsingTypeListBackup);
+                                }
+                                if (e === '1') {
+                                    // 通用规范
+                                    form.setFieldsValue({
+                                        customSeparator: '2',
+                                    });
+                                }
+                                form.setFieldsValue({
+                                    name: '',
+                                });
+                            }}
+                        >
+                            {
+                                standardClass.map((item: any, index: any) => {
+                                    return <Option value={item.value} key={index} label={item.label}>
+                                        {item.label}
+                                        <Tooltip title={item.remark} >
+                                            <QuestionCircleOutlined style={{ color: '#FF9800', marginLeft: '3px' }} />
+                                        </Tooltip>
+                                    </Option>
+                                })
+                            }
+                        </Select>
+                    </FormItem>
+
+                    {(standardClassification === '0' || standardClassification === '1') && <><FormItem
+                        label='解析工具'
+                        name='parsingType'
+                    >
+                        {/* <p>{standardClass}</p> */}
+                        <Select
+                            style={{ width: '100%' }}
+                            placeholder='请选择解析设置'
+                            allowClear={true}
+                            onChange={(e) => {
+                                if (e === '2') {
+                                    const newSplittingList = splittingOldList.filter((item: any) => item.value !== '3');
+                                    setSplittingTypeList(newSplittingList);
+                                    form.setFieldsValue({
+                                        customSeparator: newSplittingList[0]?.value,
+                                    });
+                                } else {
+                                    setSplittingTypeList(splittingOldList);
+                                }
+                            }}
+                        >
+                            {
+                                parsingTypeList.map((item: any, index: any) => {
+                                    return <Option value={item.value} key={index}>
+                                        {item.label}
+                                    </Option>
+                                })
+                            }
+                        </Select>
+                    </FormItem>
+                        <FormItem
+                            label='切片设置'
+                            name='customSeparator'
+                        >
+                            <Select
+                                style={{ width: '100%' }}
+                                allowClear={true}
+                                placeholder='请选择切片设置'
+                                onChange={onChangeF}
+                                optionLabelProp="label"
+                            >
+                                {
+                                    splittingTypeList.map((item: any, index: any) => {
+                                        return <Option value={item.value} key={index} label={item.label}>
+                                            {item.label}
+                                            <Tooltip title={item.remark} >
+                                                <QuestionCircleOutlined style={{ color: '#FF9800', marginLeft: '3px' }} />
+                                            </Tooltip>
+                                        </Option>
+                                    })
+                                }
+                            </Select>
+                        </FormItem></>}
+                    {isVisibleSlice &&
+                        <FormItem
+                            label='分隔符'
+                            name='sliceValue'
+                            rules={[{ required: true, message: '自定义切片设置不能为空' }]}
+                        >
+                            <Input max={1024}
+                            />
+                        </FormItem>
+                    }
+                    {standardClassification === '3' && <><FormItem
+                        label='文件名称'
+                        name='name'
+                        rules={[{ required: true, message: '文件名称不能为空', whitespace: true }]}
+                    >
+                        <Input placeholder='请输入文件名称' />
+                    </FormItem>
+                        <FormItem
+                            label='描述'
+                            name='remark'
+                            rules={[{ required: true, message: '描述不能为空', whitespace: true }]}
+                        >
+                            <TextArea
+                                placeholder='请输入描述信息'
+                                showCount={true}
+                                rows={6}
+                                maxLength={500}
+                            />
+                        </FormItem></>}
+                    <div style={{ width: '100%', height: 10 }}></div>
+                </Form>
+            </Spin>
+        </Modal>
+    );
+};
+
+export default InfoModalSetting;

+ 1573 - 0
src/pages/deepseek/knowledgeLib/detail/components/MdModal.tsx

@@ -0,0 +1,1573 @@
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from 'react';
+import {
+  Button,
+  Empty,
+  Modal,
+  Drawer,
+  Space,
+  Spin,
+  Typography,
+  Input,
+  message,
+  Upload,
+  UploadProps,
+  Checkbox,
+  Tooltip,
+  Popconfirm,
+  Image,
+  Tabs
+} from 'antd';
+import { SearchOutlined, MenuFoldOutlined, MenuUnfoldOutlined, FileTextOutlined, DeleteOutlined, QuestionOutlined, QuestionCircleOutlined, FullscreenOutlined } from '@ant-design/icons';
+import MarkdownIt from 'markdown-it';
+import { observer } from 'mobx-react';
+import { apis } from '@/apis';
+import config, { getHeaders } from '@/apis/config';
+import './style.less'
+import { Document, Page, pdfjs } from 'react-pdf';
+import workerSrc from '@/assets/pdf.worker.min.js?url';
+import 'react-pdf/dist/Page/TextLayer.css';
+import 'react-pdf/dist/Page/AnnotationLayer.css';
+import { Console } from 'console';
+pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
+// pdfjs.GlobalWorkerOptions.workerSrc = new URL(
+//   'pdfjs-dist/build/pdf.worker.min.mjs',
+//   import.meta.url,
+// ).toString();
+import zHuifu from '@/assets/public/z-huifu.svg'
+import zJiexi from '@/assets/public/z-jiexi.svg'
+import zQiefen from '@/assets/public/z-qiefen.svg'
+import zXinzeng from '@/assets/public/z-xinzeng.svg'
+import zHebing from '@/assets/public/z-hebing.svg'
+import zTuozhan from '@/assets/public/z-tuozhan.svg'
+import zDuoban from '@/assets/public/z-duoban.svg'
+import tubing from '@/assets/public/tubing.png'
+import rfq from '@/assets/public/rfq.png'
+const { TextArea } = Input;
+
+const marked = new MarkdownIt({ html: true, typographer: true });
+
+type KnowledgeRecord = {
+  knowledgeId: string;
+  name: string;
+  length?: number;
+  wordNum?: number;
+  documentSize?: number;
+  markUrl?: string;
+  previewUrl?: string;
+  url?: string;
+  [key: string]: any;
+  status?: string;
+  standardClassification?: string
+  suffix: string
+};
+
+interface ModuleItem {
+  id: string;
+  content: string;
+  mdContent: string;
+  sliceId?: string;
+  saveLoading?: boolean;
+  delLoading?: boolean;
+  mediaList?: any[];
+  uploading?: boolean;
+}
+
+const initialModules: ModuleItem[] = [
+  {
+    id: 'm1',
+    content:
+      '### 新增切片',
+    mdContent: '### 新增切片'
+  }
+];
+interface MdModalProps {
+  open: boolean;
+  detailDocument?: any;
+  knowledgeDetail?: any;
+  onCancel: (type?: number) => void;
+}
+
+import store from './store';
+
+
+
+
+const LazyPage = React.memo(
+    ({
+        pageNumber,
+        width,
+        containerRef,
+    }: {
+        pageNumber: number;
+        width: number;
+        containerRef: React.RefObject<HTMLDivElement>;
+    }) => {
+        const elRef = React.useRef<HTMLDivElement | null>(null);
+        const [visible, setVisible] = React.useState(false);
+
+        React.useEffect(() => {
+            const el = elRef.current;
+            const root = containerRef.current;
+            if (!el || !root) return;
+
+            const io = new IntersectionObserver(
+                entries => {
+                    entries.forEach(e => e.isIntersecting && setVisible(true));
+                },
+                { root, rootMargin: '400px' }
+            );
+
+            io.observe(el);
+            return () => io.disconnect();
+        }, [containerRef]);
+
+        return (
+            <div ref={elRef} style={{ background: '#fff' }}>
+                {visible ? (
+                    <Page
+                        pageNumber={pageNumber}
+                        // width={width}
+                        renderTextLayer={false}
+                        renderAnnotationLayer={false}
+                        className='pdf-page'
+                    />
+                ) : (
+                    <div
+                        style={{
+                            width: '100%',
+                            height: Math.floor(width * 1.3),
+                            background: '#fafafa',
+                        }}
+                    />
+                )}
+            </div>
+        );
+    }
+);
+
+
+
+
+const MdModal: React.FC<MdModalProps> = (props) => {
+
+  const {
+    state,
+    onSetStarts
+  } = store;
+  useEffect(() => {
+    loadKnowledgeList(1, '');
+  }, [state.starts])
+
+  const { open, onCancel, detailDocument, knowledgeDetail } = props;
+  const [documents, setDocuments] = useState<KnowledgeRecord[]>([]);
+  const [selectedDoc, setSelectedDoc] = useState<KnowledgeRecord | null>(null); // 当前选中的文件
+  const selectedRefDoc = useRef<KnowledgeRecord | null>(null); // 当前选中的文件
+  const [pagination, setPagination] = useState({
+    pageNum: 1,
+    pageSize: 20,
+    total: 0,
+  });
+  const [listLoading, setListLoading] = useState(false);
+  const [sliceLoading, setSliceLoading] = useState(true);
+  const [pdfLoading, setPdfLoading] = useState(true);
+  const listLoadingRef = useRef(false);
+  const [hasMore, setHasMore] = useState(true);
+  const listContainerRef = useRef<HTMLDivElement>(null);
+  // 切片列表
+  const [modules, setModules] = useState<ModuleItem[]>([]);
+  const [oneModules, setOneModules] = useState('');
+  // 默认选中第一条数据
+  const [activeId, setActiveId] = useState<string | null>(initialModules[0]?.id);
+  const [fromEditor, setFromEditor] = useState(true);
+  const editorContainerRef = useRef<HTMLDivElement>(null);
+  const previewContainerRef = useRef<HTMLDivElement>(null);
+  const [keyword, setKeyword] = useState('');
+  const [isListCollapsed, setIsListCollapsed] = useState(false);// 文档列表是否展开
+  const [isPDfCollapsed, setIsPDfCollapsed] = useState(false);// PDF预览是否展开
+  const [delSliceIds, setDelSliceIds] = useState<string[]>([]);
+  const [selectedModuleIds, setSelectedModuleIds] = useState<string[]>([]); // 用于合并的多选模块
+
+  const [pdfBuffer, setPdfBuffer] = useState<any>(null);
+  const [numPages, setNumPages] = useState<number>(0);
+  // 全屏预览状态与缩放
+  const [pdfFullVisible, setPdfFullVisible] = useState<boolean>(false);
+  const [pdfFullScale, setPdfFullScale] = useState<number>(1.5);
+
+  const [currentDocumentId, setCurrentDocumentId] = useState<string | null>(null);
+  const pdfScrollRef = useRef<HTMLDivElement | null>(null);
+  const [pageWidth, setPageWidth] = useState<number>(600);
+
+  // 替换渲染数据
+  const customRender = (text: string, mdImgUrlList: any[]) => {
+    // 比如:把 "我是图片" 替换成一张图片
+    mdImgUrlList?.forEach(item => {
+      text = text.replace(new RegExp(item.originText, 'g'), `<img src="${item.mediaUrl}" alt="${item.originText}" />`);
+    })
+    return text;
+  }
+  // 处理切片数据
+  const sliceDataProcess = (data: any[]) => {
+    data.forEach((item: any) => {
+      item.content = item.sliceText
+      item.id = item.sliceId,
+        item.mdContent = customRender(item.sliceText, item.mediaList)
+    })
+    setModules(data || [])
+  }
+  // 获取切片列表
+  const onGetSliceListByDocumentId = async (item: any) => {
+    const res: any = await apis.getSliceListByDocumentId(item.documentId)
+    if (res.code === 200 && res.data) {
+      if (res.data.length > 0) {
+        res.data.forEach((item: any) => {
+          item.saveLoading = false;
+          item.delLoading = false;
+          item.uploading = false;
+        })
+        sliceDataProcess(res.data)
+      } else {
+        setModules(initialModules)
+      }
+      setSliceLoading(false);
+    }
+  }
+  // 获取MD原文数据
+  const onGetMarkDownSliceByDocumentId = async (documentId: string) => {
+    const res: any = await apis.getMarkDodnSliceByDocumentId(documentId);
+    if (res.code === 200 && res.data) {
+      setOneModules(res.data[0] || '');
+    }
+  }
+
+  // 获取文档详情
+  const [customSeparator, setCustomSeparator] = useState<string>('');
+  const onFetchDocumentDetailLibApi = async (documentId: string) => {
+    const res: any = await apis.fetchTakaiDocumentDetailLibApi(documentId);
+    if (res.code === 200 && res.data) {
+      setQaChecked(res.data.qaChecked || false);
+      setRelatedQuestionsEnabled(res.data.relatedQuestionsEnabled || false);
+      setSummaryGenerationEnabled(res.data.summaryGenerationEnabled || false);
+      setParentGenerationEnabled(res.data.parentGenerationEnabled || false);
+      setCustomSeparator(res.data.customSeparator || '');
+    }
+  }
+  // 获取PDF
+  const onExportPdfStream = async (item: any) => {
+    setModules([]) // 清空切片
+    setPdfBuffer(null);// 清空PDF预览
+    setTabKey('slices') // 清空智能切片模式
+    setSelectedModuleIds([]); // 清空合并切片以及需要删除的切片
+    setSliceLoading(true)
+    setSelectedDoc(item);
+    selectedRefDoc.current = item;
+    setCurrentDocumentId(item.documentId);
+    setPdfLoading(false);
+    if (item?.suffix !== 'md') {
+      setPdfLoading(true);
+      const ids = [item.documentId]
+      const blob = await apis.exportPdfStream(ids)
+      setPdfLoading(false);
+      const url = URL.createObjectURL(blob);
+      setPdfBuffer(url);
+    }
+
+    onGetSliceListByDocumentId(item)
+    onGetMarkDownSliceByDocumentId(item.documentId);
+    onFetchDocumentDetailLibApi(item.documentId);
+  }
+      // 计算渲染宽度以降低每页 canvas 分辨率开销(与 prevewSlice 行为一致)
+    useEffect(() => {
+      const update = () => {
+        const el = pdfScrollRef.current;
+        if (el) {
+          const w = el.clientWidth - 20;
+          setPageWidth(Math.max(200, w));
+        }
+      };
+      update();
+      window.addEventListener('resize', update);
+      return () => window.removeEventListener('resize', update);
+    }, []);
+
+  //PDF渲染列表
+  const renderPdfPreview = () => {
+    function onLoadSuccess({ numPages }: { numPages: number }) {
+      setNumPages(numPages);
+    }
+    if (!pdfBuffer) {
+      return (
+        <div className="flex h-full items-center justify-center">
+          <Empty description="请选择左侧的文档" image={Empty.PRESENTED_IMAGE_SIMPLE} />
+        </div>
+      );
+    }
+
+    return (
+      <div>
+        <style>{`
+        .react-pdf__Page__canvas {
+          width: 100% !important;
+          padding-left:0 !important;
+          height: auto !important;
+        }
+        .react-pdf__Page__textContent,.annotationLayer { 
+          padding:0; 
+          margin:0;
+          width: 100% !important;
+          padding-left:0 !important;
+          height: auto !important;
+         }
+      `}</style>
+          {pdfBuffer && (
+            <Document file={pdfBuffer} 
+              renderMode='canvas'
+              onLoadSuccess={onLoadSuccess}
+              loading={<div className="text-center py-8">加载中...</div>}
+            >
+              {Array.from(new Array(numPages), (_, idx) => (
+              //    <Page key={idx} pageNumber={idx + 1}
+              //   renderAnnotationLayer={false}
+              //   renderTextLayer={true}
+              // />
+                <LazyPage key={`page-${idx}`} pageNumber={idx + 1} width={Math.floor(pageWidth)} containerRef={pdfScrollRef} />
+              ))}
+            </Document>
+          )}
+      </div>)
+  }
+  // 获取文档列表
+  const loadKnowledgeList = useCallback(
+    async (targetPage = 1, searchKeyword?: string) => {
+      if (listLoadingRef.current) return;
+      listLoadingRef.current = true;
+      setListLoading(true);
+      try {
+        const res: any = await apis.sliceDocumentList({
+          pageNum: targetPage,
+          pageSize: pagination.pageSize,
+          knowledge_id: knowledgeDetail.knowledgeId,
+          name: searchKeyword !== undefined ? searchKeyword : ''
+        });
+        const rows = res?.rows || [];
+        setDocuments((prev) => {
+          if (targetPage === 1) {
+            const firstDoc = selectedDoc || detailDocument;
+            if (firstDoc && firstDoc.documentId) {
+              const isExist = rows.filter((item: any) => item.documentId !== firstDoc.documentId);
+              return [firstDoc, ...isExist];
+            }
+            return rows;
+          } else {
+            return [...prev, ...rows.filter((row: KnowledgeRecord) => prev.every((p) => p.knowledgeId !== row.knowledgeId))]
+          }
+        });
+        setPagination((prev) => ({
+          ...prev,
+          pageNum: targetPage,
+          total: res?.total || 0,
+        }));
+        setHasMore(targetPage * pagination.pageSize < (res?.total || 0));
+      } catch (error: any) {
+        message.error(error?.msg || '获取文档列表失败');
+      } finally {
+        listLoadingRef.current = false;
+        setListLoading(false);
+      }
+    },
+    [pagination.pageSize, detailDocument, selectedDoc]
+  );
+
+  useEffect(() => {
+    loadKnowledgeList(1, '');
+    onExportPdfStream(detailDocument);
+  }, [detailDocument]);
+  // 列表滚动加载更多
+  const handleListScroll = useCallback(() => {
+    const container = listContainerRef.current;
+    if (
+      !container ||
+      listLoadingRef.current ||
+      !hasMore ||
+      documents.length === 0
+    ) {
+      return;
+    }
+    const nearBottom =
+      container.scrollTop + container.clientHeight >=
+      container.scrollHeight - 40;
+    if (nearBottom) {
+      loadKnowledgeList(pagination.pageNum + 1);
+    }
+  }, [documents.length, hasMore, loadKnowledgeList, pagination.pageNum]);
+
+  useEffect(() => {
+    const container = listContainerRef.current;
+    if (!container) return;
+    container.addEventListener('scroll', handleListScroll);
+    return () => container.removeEventListener('scroll', handleListScroll);
+  }, [handleListScroll, isListCollapsed]);
+  // 最后两列滚动
+  const scrollToElement = (
+    containerRef: React.RefObject<HTMLDivElement>,
+    element: HTMLElement | null
+  ) => {
+    if (!containerRef.current || !element) return;
+    const containerTop = containerRef.current.getBoundingClientRect().top;
+    const elemTop = element.getBoundingClientRect().top;
+    containerRef.current.scrollBy({
+      top: elemTop - containerTop - 16,
+      behavior: 'smooth',
+    });
+  };
+
+  const setActiveModule = (id: string, editorSide: boolean) => {
+    setActiveId(id);
+    setFromEditor(editorSide);
+  };
+
+  useEffect(() => {
+    if (!activeId) return;
+    const targetEditorModule = editorContainerRef.current?.querySelector(
+      `[data-id="${activeId}"]`
+    ) as HTMLElement | null;
+    const targetPreviewModule = previewContainerRef.current?.querySelector(
+      `[data-id="${activeId}"]`
+    ) as HTMLElement | null;
+    if (fromEditor && targetPreviewModule) {
+      scrollToElement(previewContainerRef, targetPreviewModule);
+    }
+    if (!fromEditor && targetEditorModule) {
+      scrollToElement(editorContainerRef, targetEditorModule);
+    }
+  }, [activeId, fromEditor]);
+  // 输入框选中操作
+  const handleContentChange = (id: string, newContent: string, newMediaList?: any) => {
+    setModules((prev) =>
+      prev.map((module: any) => {
+        if (module.id === id) {
+          if (newMediaList) {
+            return { ...module, content: newContent, mdContent: customRender(newContent, newMediaList || module.mediaList), mediaList: newMediaList || module.mediaList }
+          } else {
+            return { ...module, content: newContent, mdContent: customRender(newContent, module.mediaList) }
+          }
+        } else {
+          return module
+        }
+      }));
+  };
+  const setSaveLoadingChange = (id: string, flag: boolean) => {
+    setModules((prev) =>
+      prev.map((module: any) => {
+        if (module.id === id) {
+          return { ...module, saveLoading: flag }
+        } else {
+          return module
+        }
+      }));
+  };
+  const setdelLoadingChange = (id: string, flag: boolean) => {
+    setModules((prev) =>
+      prev.map((module: any) => {
+        if (module.id === id) {
+          return { ...module, delLoading: flag }
+        } else {
+          return module
+        }
+      }));
+  };
+  // 恢复内容
+  const handleRestore = (item: any) => {
+    handleContentChange(item.id, item.sliceText);
+  };
+
+  // 新增模块
+  const handleAddModule = (currentId?: string) => {
+    let createdModule: ModuleItem | any = null;
+    setModules((prev) => {
+      const currentIndex = currentId
+        ? prev.findIndex((module) => module.id === currentId)
+        : prev.length - 1;
+      const nextIndex = currentIndex >= 0 ? currentIndex + 1 : prev.length;
+      createdModule = {
+        id: `m${Date.now()}`,
+        content: '### 新增切片',
+        mdContent: '### 新增切片',
+      };
+      const nextModules = [...prev];
+      nextModules.splice(nextIndex, 0, createdModule);
+      return nextModules;
+    });
+    if (createdModule) {
+      setActiveModule(createdModule.id, true);
+    }
+  };
+  // 合并模块
+  const handleMergeModule = (currentModule: any) => {
+    if (!currentModule) return;
+
+    // 如果没有选中任何模块,提示用户
+    if (selectedModuleIds.length === 0) {
+      message.warning('请先勾选要合并的模块');
+      return;
+    }
+
+    // 获取所有需要合并的模块(包括当前模块),按照在modules数组中的顺序
+    const modulesToMerge = modules.filter(m =>
+      m.id === currentModule.id || selectedModuleIds.includes(m.id)
+    );
+
+    if (modulesToMerge.length <= 1) {
+      message.warning('至少需要选择一个其他模块进行合并');
+      return;
+    }
+
+    // 按照从上到下的顺序合并内容
+    const mergedContent = modulesToMerge.map(m => m.content).join('\n');
+
+    // 合并所有模块的 mediaList
+    const allMediaLists = modulesToMerge
+      .map(m => m.mediaList || [])
+      .flat();
+
+    // 去重 mediaList(根据 originText 或其他唯一标识)
+    const uniqueMediaList = allMediaLists.filter((item, index, self) =>
+      index === self.findIndex(t => t.originText === item.originText)
+    );
+
+    // 收集要删除的 sliceIds
+    const idsToDelete = modulesToMerge
+      .filter(m => m.id !== currentModule.id && m.sliceId)
+      .map(m => m.sliceId!);
+
+    // 更新 modules:保留当前模块并更新其内容,删除其他被合并的模块
+    setModules((prev) => {
+      const next = prev.filter(m =>
+        m.id === currentModule.id || !selectedModuleIds.includes(m.id)
+      );
+
+      // 更新当前模块的内容
+      return next.map(m => {
+        if (m.id === currentModule.id) {
+          return {
+            ...m,
+            content: mergedContent,
+            mdContent: customRender(mergedContent, uniqueMediaList),
+            mediaList: uniqueMediaList.length > 0 ? uniqueMediaList : undefined
+          };
+        }
+        return m;
+      });
+    });
+
+    // 添加到删除列表
+    if (idsToDelete.length > 0) {
+      setDelSliceIds((prev) => [...prev, ...idsToDelete]);
+    }
+
+    // 清空选中状态
+    setSelectedModuleIds([]);
+
+    message.success(`已合并 ${modulesToMerge.length} 个模块`);
+  };
+
+  // 切分模块
+  const handleSplitModule = (module?: any) => {
+    const target = module || modules.find((m) => m.id === activeId);
+    if (!target) return;
+
+    const text = (target.content || '').toString();
+    const pos = Math.max(0, Math.min(cursorEndPosition || 0, text.length));
+
+    // 如果位置在开头或结尾,则不进行切分
+    if (pos === 0 || pos === text.length) {
+      message.warning('当前位置不能切分内容');
+      return;
+    }
+
+    const firstPart = text.slice(0, pos);
+    const secondPart = text.slice(pos);
+
+    // 尝试保留 mediaList(如果有),这里简单复制到两个片段,确保渲染时可用
+    const mediaList = target.mediaList ? [...target.mediaList] : undefined;
+
+    const newModule = {
+      id: `m${Date.now()}`,
+      content: secondPart,
+      mdContent: customRender(secondPart, mediaList || []),
+      saveLoading: false,
+      delLoading: false,
+      mediaList: mediaList ? [...mediaList] : undefined,
+    } as any;
+
+    setModules((prev) => {
+      const idx = prev.findIndex((m) => m.id === target.id);
+      if (idx === -1) return prev;
+      const next = [...prev];
+      // 更新当前为第一段
+      next[idx] = { ...next[idx], content: firstPart, mdContent: customRender(firstPart, mediaList || []) };
+      // 在其后插入新模块(第二段)
+      next.splice(idx + 1, 0, newModule);
+      return next;
+    });
+
+    // 将焦点切到新创建的模块(编辑端)
+    setActiveModule(newModule.id, true);
+    // 重置光标位置
+    setCursorEndPosition(0);
+  };
+  // 保存
+  const handleSaveModule = async (item: any, index: number) => {
+    if (!item.content || item.content.trim() === '') {
+      return message.warning('切片内容不能为空');
+    }
+    const params = {
+      ...item,
+      sliceText: item.content,
+      index: index + 1,
+    }
+    setSaveLoadingChange(item.id, true);
+    try {
+      if (item.sliceId) {
+        const res: any = await apis.setupdateSliceInfo(params);
+        if (res.code === 200) {
+          message.success('修改成功');
+        }
+      }
+      if (!item.sliceId) {
+        params['documentId'] = detailDocument.documentId;
+        params['knowledgeId'] = detailDocument.knowledgeId;
+        const res: any = await apis.addSlice(params);
+        if (res.code === 200) {
+          message.success('保存成功');
+        }
+      }
+      setSaveLoadingChange(item.id, false);
+    } catch (error: any) {
+      setSaveLoadingChange(item.id, false);
+    }
+  };
+  // 删除模块
+  const handleDeleteModule = async (item: any) => {
+    if (item.sliceId) {
+      setdelLoadingChange(item.id, true);
+      const res = await apis.deleteTakaiSlice(item.sliceId, item.knowledgeId, item.documentId);
+      setdelLoadingChange(item.id, false);
+      if (res.code === 200) {
+        setModules((prev) => {
+          if (prev.length === 1) {
+            message.warning('至少保留一个模块');
+            return prev;
+          }
+          const filtered = prev.filter((module) => module.id !== item.id);
+          if (activeId === item.id && filtered.length) {
+            setActiveModule(filtered[0].id, true);
+          }
+          return filtered;
+        });
+        setDelSliceIds((prev) => {
+          const delIds = [...prev];
+          if (item && item.sliceId) {
+            delIds.push(item.sliceId);
+          }
+          return delIds;
+        })
+      }
+    } else {
+      setModules((prev) => {
+        if (prev.length === 1) {
+          message.warning('至少保留一个模块');
+          return prev;
+        }
+        const filtered = prev.filter((module) => module.id !== item.id);
+        if (activeId === item.id && filtered.length) {
+          setActiveModule(filtered[0].id, true);
+        }
+        return filtered;
+      });
+      setDelSliceIds((prev) => {
+        const delIds = [...prev];
+        if (item && item.sliceId) {
+          delIds.push(item.sliceId);
+        }
+        return delIds;
+      })
+    }
+  };
+  // 切换模块选中状态
+  const handleToggleModuleSelection = (moduleId: string) => {
+    setSelectedModuleIds((prev) => {
+      if (prev.includes(moduleId)) {
+        return prev.filter(id => id !== moduleId);
+      } else {
+        return [...prev, moduleId];
+      }
+    });
+  };
+
+  // 处理markdown编辑器
+  const [cursorEndPosition, setCursorEndPosition] = React.useState<number>(0);
+  const [SliceDetail, setSliceDetail] = React.useState<any>(null);
+  const [upload, setUpload] = React.useState<boolean>(false);
+
+  const upDateButton = (module?: any) => {
+    // 上传图片配置
+    const uploadImageConfig: UploadProps = {
+      name: 'file',
+      action: `/api/resource/oss/upload`,
+      method: 'POST',
+      headers: getHeaders(),
+      accept: ['.png', '.jpg', '.jpeg'].join(','),
+      multiple: true,
+      maxCount: 5,
+      showUploadList: false,
+    };
+    return (
+      <Upload
+        {...uploadImageConfig}
+        onChange={async (info) => {
+          const file = info.file;
+          // 上传中,设置模块 uploading 状态
+          if (file.status === 'uploading' && module) {
+            setModules((prev) => prev.map((m) => (m.id === module.id ? { ...m, uploading: true } : m)));
+          }
+          const insertToSliceText = (item: any) => {
+            const slice_text = SliceDetail?.content || '';
+            // 获取当前光标位置
+            const position = cursorEndPosition;
+
+            let newValue = '';
+
+            if (!slice_text) {
+              newValue = item.originText;
+            } else {
+              newValue = slice_text.slice(0, position) + item.originText + slice_text.slice(position);
+            }
+            const falgImages = SliceDetail.mediaList ? [...SliceDetail.mediaList, item] : [item];
+            handleContentChange(SliceDetail.id, newValue, falgImages)
+            // form.setFieldsValue({ slice_text: newValue });
+          }
+          if (file.status === 'done') {// 上传成功
+            const { code, msg, data } = file.response;
+            if (code === 200) {
+              const res: any = await apis.uploadSliceImage(detailDocument, {
+                ...data,
+                name: data.fileName,
+              });
+              if (res.code === 200) {
+                insertToSliceText(res.data)
+                // 上传完成,清除 uploading 状态
+                if (module) {
+                  setModules((prev) => prev.map((m) => (m.id === module.id ? { ...m, uploading: false } : m)));
+                }
+                message.success('上传成功');
+              }
+            } else {
+              message.error(msg);
+            }
+          } else if (file.status === 'error') {// 上传失败
+            // 上传失败,清除 uploading 状态
+            if (module) {
+              setModules((prev) => prev.map((m) => (m.id === module.id ? { ...m, uploading: false } : m)));
+            }
+            message.error('上传失败');
+          }
+        }}
+      >
+        <Tooltip title="解析图片">
+          <Button size='small' style={{ border: 'none', padding: 0 }} loading={module?.uploading}>
+            {/* 解析图片 */}
+            <Image
+              width={23}
+              height={23}
+              src={zJiexi}
+              preview={false}
+              className='cursor-pointer'
+              onClick={() => handleRestore(module)}
+            />
+          </Button>
+        </Tooltip>
+      </Upload>
+    )
+  }
+  // 渲染编辑模块
+  const renderEditorModules = () => {
+    const textAreaProps = {
+      autoSize: { minRows: 4, maxRows: 20 },
+      className:
+        '!bg-white !border-none !shadow-none !p-0 !text-sm !leading-6 focus:!shadow-none',
+    };
+
+    return modules.map((module: any, index) => (
+      <div
+        key={module.id}
+        data-id={module.id}
+        className={`rounded-2xl mb-[10px] border border-transparent p-4 bg-white transition-all duration-200 relative
+         
+           ${activeId === module.id
+            ? 'border-blue-300 ring-2 ring-blue-200'
+            : 'hover:border-blue-200'
+          }`}
+      >
+        {/* 左上角废弃*/}
+        {module.revisionStatus === '0' && <div className="absolute top-[-0px] right-4 z-10">
+          <Tooltip title='已废弃'>
+            <Image width={16} height={16} src={rfq} preview={false} className='cursor-pointer ml-2' />
+          </Tooltip>
+        </div>}
+        <div className={`relative w-full h-full ${module.revisionStatus === '0' ? 'pointer-events-none cursor-not-allowed' : ''}`}>
+          {/* 右上角多选框 */}
+          {module.revisionStatus !== '0' && <div className="absolute top-[-15px] right-1 z-10">
+            <Checkbox
+              checked={selectedModuleIds.includes(module.id)}
+              onChange={() => handleToggleModuleSelection(module.id)}
+              onClick={(e) => e.stopPropagation()}
+            />
+          </div>}
+          <TextArea
+            {...textAreaProps}
+            value={module.content}
+            onChange={(e) => handleContentChange(module.id, e.target.value)}
+            onFocus={() => setActiveModule(module.id, true)}
+            onBlur={(e: React.FocusEvent<HTMLTextAreaElement>) => {
+              const ta = e.target as HTMLTextAreaElement;
+              const start = ta.selectionStart;
+              const end = ta.selectionEnd;
+              setCursorEndPosition(end);
+              setSliceDetail(module)
+              // setCursor({ start, end });
+              // console.log('blur cursor', start, end, ta.value);
+            }}
+          />
+          {activeId === module.id && (
+            <Space size={[8, 8]} wrap className="mt-3 w-full flex justify-end">
+              {/* 恢复初始 */}
+              {module.sliceId &&
+                <Tooltip title="恢复初始内容">
+                  <Image
+                    width={23}
+                    height={23}
+                    src={zHuifu}
+                    preview={false}
+                    className='cursor-pointer'
+                    onClick={() => handleRestore(module)}
+                  />
+                </Tooltip>
+              }
+              {upDateButton(module)}
+              <Tooltip title="切分模块">
+                <Button
+                  style={{ border: 'none', padding: 0 }}
+                  size="small"
+                  type="primary"
+                  ghost
+                  onClick={() => handleSplitModule(module)}
+                >
+                  <Image src={zQiefen} width={23} height={23} preview={false} className='cursor-pointer' />
+                </Button>
+              </Tooltip>
+              <Tooltip title="合并模块(请先勾选要合并的模块)">
+                <Button
+                  style={{ border: 'none', padding: 0 }}
+                  size="small"
+                  type="primary"
+                  ghost
+                  onClick={() => handleMergeModule(module)}
+                >
+                  <Image src={zHebing} width={23} height={23} preview={false} className='cursor-pointer' />
+                </Button>
+              </Tooltip>
+              <Tooltip title="新增模块">
+                <Button
+                  size="small"
+                  type="primary"
+                  style={{ border: 'none', padding: 0 }}
+                  ghost
+                  onClick={() => handleAddModule(module.id)}
+                >
+                  <Image src={zXinzeng} width={23} height={23} preview={false} className='cursor-pointer' />
+                </Button>
+              </Tooltip>
+              <Button
+                size="small"
+                loading={module.delLoading}
+                danger
+                onClick={() => handleDeleteModule(module)}
+              >
+                删除
+              </Button>
+              <Button
+                size="small"
+                type="primary"
+                loading={module.saveLoading}
+                onClick={() => handleSaveModule(module, index)}
+              >
+                保存
+              </Button>
+              <div className="absolute bottom-0 left-0 z-10">
+                <Popconfirm
+                  placement="topLeft"
+                  showCancel={false}
+                  title={
+                    <div style={{ maxWidth: 360 }}>
+                      <div style={{ marginBottom: 8 }}>
+                        <div style={{ fontWeight: 600 }}>生成QA问答对</div>
+                        <div style={{ fontSize: 12, color: '#666' }}>
+                          {(() => {
+                            const trySources = [
+                              module?.qa,
+                              module?.mode?.qa,
+                              knowledgeDetail?.mode?.qa,
+                              detailDocument?.mode?.qa,
+                              module?.question,
+                            ];
+                            let qaRaw: any = null;
+                            for (const s of trySources) {
+                              if (s) {
+                                qaRaw = s;
+                                break;
+                              }
+                            }
+                            if (!qaRaw) return '暂无问答';
+                            let qaList: any[] = [];
+                            if (typeof qaRaw === 'string') {
+                              try {
+                                qaList = JSON.parse(qaRaw);
+                              } catch (e) {
+                                return qaRaw;
+                              }
+                            } else if (Array.isArray(qaRaw)) {
+                              qaList = qaRaw;
+                            } else if (qaRaw && typeof qaRaw === 'object') {
+                              qaList = qaRaw.qa || qaRaw.list || [];
+                            }
+                            if (!qaList || qaList.length === 0) return '暂无问答';
+                            return (
+                              <div>
+                                {qaList.slice(0, 5).map((item: any, idx: number) => (
+                                  <div key={idx} style={{ marginBottom: 6 }}>
+                                    <div style={{ fontWeight: 500 }}>{item.question}</div>
+                                    <div style={{ fontSize: 12, color: '#444' }}>{item.answer}</div>
+                                  </div>
+                                ))}
+                                {qaList.length > 5 && <div style={{ fontSize: 12, color: '#999' }}>...共{qaList.length}条</div>}
+                              </div>
+                            );
+                          })()}
+                        </div>
+                      </div>
+                      <div style={{ marginBottom: 8 }}>
+                        <div style={{ fontWeight: 600 }}>生成关联问题</div>
+                        <div style={{ fontSize: 12, color: '#666' }}>{module?.question || '暂无关联问题'}</div>
+                      </div>
+                      <div>
+                        <div style={{ fontWeight: 600 }}>生成摘要</div>
+                        <div style={{ fontSize: 12, color: '#666' }}>{module?.summary || '暂无摘要'}</div>
+                      </div>
+                    </div>
+                  }
+                  okText="关闭"
+                  onConfirm={() => { }}
+                >
+                  <Image
+                    width={16}
+                    height={16}
+                    src={zTuozhan}
+                    preview={false}
+                    className='cursor-pointer'
+                  />
+                </Popconfirm>
+                {module.revisionStatus === '1' &&
+                  <Popconfirm
+                    placement="topLeft"
+                    showCancel={false}
+                    title={
+                      <div style={{ maxWidth: 500 }}>
+                        <div style={{ marginBottom: 8 }}>
+                          <div style={{ fontWeight: 600 }}>{module.documentName}</div>
+                          <div style={{ marginTop: 6, marginRight: 18 }}>
+                            <div style={{
+                              background: '#f5f7ff',
+                              padding: '10px',
+                              borderRadius: 6,
+                              border: '1px solid rgba(23,70,161,0.06)',
+                              fontSize: 13,
+                              color: '#222',
+                              lineHeight: '1.6',
+                              whiteSpace: 'pre-wrap'
+                            }}>
+                              {module.revisionSliceText}
+                            </div>
+                          </div>
+                        </div>
+                        <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', marginTop: 10, alignItems: 'flex-end' }}>
+                          <div style={{ fontSize: 12, color: '#666' }}>修订人:{module?.revisionName}</div>
+                          <div style={{ fontSize: 12, color: '#666' }}>修订时间:{module?.revisionTime}</div>
+                        </div>
+                      </div>
+                    }
+                    okText="关闭"
+                    onConfirm={() => { }}
+                  >
+                    <Image width={16} height={16} src={tubing} preview={false} className='cursor-pointer ml-2' />
+                  </Popconfirm>
+                }
+              </div>
+            </Space>
+          )}
+        </div>
+
+      </div>
+    ));
+  };
+  // 渲染编辑模块-MD 
+  const renderMdEditorModules = () => {
+    const textAreaProps = {
+      autoSize: { minRows: 4, maxRows: 25 },
+      className:
+        '!bg-white !border-none !shadow-none !p-0 !text-sm !leading-6 focus:!shadow-none',
+    };
+    return (
+      <div
+        className={`rounded-2xl mb-[10px] border border-transparent bg-white p-2 transition-all duration-200 relative 
+          border-blue-300 ring-2 ring-blue-200`}
+      >
+        <TextArea
+          {...textAreaProps}
+          value={oneModules}
+          onChange={(e) => { setOneModules(e.target.value) }}
+        />
+      </div>
+    )
+  }
+  // 渲染预览模块
+  const renderPreviewDocument = () => {
+    return (
+      <div className="overflow-hidden rounded-2xl bg-white w-full">
+        <style>{`
+          .markdown-preview img,table {
+            max-width: 100%;
+            width: 100% !important;
+            height: auto;
+            display: block;
+          }
+        `}</style>
+        {modules.map((module, index) => (
+          <div
+            key={module.id}
+            data-id={module.id}
+            className={`relative px-3 py-2 text-sm leading-7 transition-all duration-200 cursor-pointer ${index !== modules.length - 1 ? 'border-b border-gray-100' : ''
+              } ${activeId === module.id
+                ? 'bg-blue-50  border-l-blue-500 shadow-sm scale-[1]'
+                : 'hover:bg-gray-50'
+              }`}
+            onClick={() => setActiveModule(module.id, false)}
+          >
+            <Typography
+              className="text-sm leading-7 text-gray-800 markdown-preview"
+              dangerouslySetInnerHTML={{
+                __html: marked.render(module.mdContent),
+              }}
+            />
+          </div>
+        ))}
+      </div>
+    );
+  };
+  //渲染预览模块-Md
+  const renderMdPreviewDocument = () => {
+    return (
+      <div className="overflow-hidden rounded-2xl bg-white w-full">
+        <style>{`
+          .markdown-preview img,table {
+            max-width: 100%;
+            width: 100% !important;
+            height: auto;
+            display: block;
+          }
+         .markdown-preview  table{
+            border-collapse: collapse;
+            width: 100%;
+          }
+         .markdown-preview  th, .markdown-preview  td{
+           border: 1px solid #ddd;
+         }
+        `}</style>
+        <div
+          className={`relative px-3 py-2 text-sm leading-7 transition-all duration-200 cursor-pointer border-b border-gray-100 bg-blue-50  border-l-blue-500 shadow-sm`}
+        >
+          <Typography
+            className="text-sm leading-7 text-gray-800 markdown-preview"
+            dangerouslySetInnerHTML={{
+              __html: marked.render(oneModules),
+            }}
+          />
+        </div>
+      </div>
+    );
+  };
+
+
+  const handleSearch = () => {
+    setHasMore(true);
+    loadKnowledgeList(1, keyword);
+  };
+  const [qaChecked, setQaChecked] = useState(false);  // 生成QA问答对
+  const [relatedQuestionsEnabled, setRelatedQuestionsEnabled] = useState(false); // 生成关联问题
+  const [summaryGenerationEnabled, setSummaryGenerationEnabled] = useState(false); // 生成摘要
+  const [parentGenerationEnabled, setParentGenerationEnabled] = useState(false); // 开启父子切片召回
+  const [allLoding, setAllLoding] = useState(false);
+  const mdUpdateSliceList = async () => {
+    const params = {
+      documentId: selectedDoc?.documentId,
+      markDownText: encodeURIComponent(oneModules),
+      knowledgeId: detailDocument?.knowledgeId,
+    };
+    try {
+      message.info({
+        duration: 2,
+        content: '正在保存Md切片信息...',
+      });
+      setTimeout(() => {
+        onCancel();
+      }, 1500)
+      const res: any = await apis.editMarkDownFileApi(params);
+      if (res.code === 200) {
+        // message.success('保存成功');
+        const timestampMs = Date.now();
+        onSetStarts(timestampMs)
+        loadKnowledgeList(1, '');
+        onCancel(1);
+      } else {
+        message.error(res.msg || '保存失败');
+      }
+    } catch (error: any) {
+
+    } finally {
+      setAllLoding(false);
+    }
+  }
+  const updateSliceInfoList = async () => {
+    // 当保存时把当前文档状态设为 '4'(加载中),成功后设为 '5'
+    const targetId = selectedDoc?.documentId || detailDocument?.documentId;
+    // 记录原始状态以便错误时恢复
+    let prevStatus: any = null;
+    if (targetId) {
+      setDocuments((prev) => {
+        return prev.map((d) => {
+          if (d.documentId === targetId) {
+            prevStatus = d.status;
+            return { ...d, status: '4' };
+          }
+          return d;
+        });
+      });
+      // 同步更新 selectedDoc 的状态(如果当前选中)
+      if (selectedDoc && selectedDoc.documentId === targetId) {
+        setSelectedDoc({ ...selectedDoc, status: '4' });
+      }
+    }
+
+    setAllLoding(true);
+    if (tabKey === 'md') {
+      // 仅在切片模式下执行保存逻辑
+      mdUpdateSliceList();
+      return;
+    }
+
+    const params = {
+      documentId: selectedDoc?.documentId,
+      knowledgeId: detailDocument?.knowledgeId,
+      sliceList: modules.map((item, index) => ({
+        ...item,
+        sliceText: item.content,
+        index: index + 1,
+      })),
+      delSliceIds,
+      qaChecked: qaChecked,
+      relatedQuestionsEnabled: relatedQuestionsEnabled,
+      summaryGenerationEnabled: summaryGenerationEnabled,
+      parentGenerationEnabled: parentGenerationEnabled,
+    };
+    try {
+      message.info({
+        duration: 2,
+        content: '正在保存切片信息...',
+      });
+      setTimeout(() => {
+        onCancel();
+      }, 1000)
+      const res: any = await apis.updateSliceInfoList(params);
+      setAllLoding(false);
+      if (res.code === 200) {
+        const timestampMs = Date.now();
+        onSetStarts(timestampMs)
+        // 更新状态为 '5' 表示已完成
+        loadKnowledgeList(1, '');
+        if (targetId) {
+          setDocuments((prev) => prev.map((d) => (d.documentId === targetId ? { ...d, status: '5' } : d)));
+          if (selectedDoc && selectedDoc.documentId === targetId) {
+            setSelectedDoc({ ...selectedDoc, status: '5' });
+          }
+        }
+        // message.success('保存成功');
+        const resdata = res.data;
+        onCancel(1);
+        if (selectedRefDoc.current?.documentId === resdata?.documentId) {
+          // console.log('selectedDoc--targetId--',selectedRefDoc.current?.documentId,'--resdata?.documentId',resdata?.documentId)
+          // onCancel();
+        }
+      } else {
+        // 恢复原始状态
+        if (targetId) {
+          setDocuments((prev) => prev.map((d) => (d.documentId === targetId ? { ...d, status: prevStatus } : d)));
+          if (selectedDoc && selectedDoc.documentId === targetId) {
+            setSelectedDoc({ ...selectedDoc, status: prevStatus });
+          }
+        }
+        message.error(res.msg || '保存失败');
+      }
+    } catch (error: any) {
+      // 恢复原始状态
+      if (targetId) {
+        setDocuments((prev) => prev.map((d) => (d.documentId === targetId ? { ...d, status: prevStatus } : d)));
+        if (selectedDoc && selectedDoc.documentId === targetId) {
+          setSelectedDoc({ ...selectedDoc, status: prevStatus });
+        }
+      }
+      setAllLoding(false);
+    }
+
+  }
+  const getOldSliceListByDocumentId = async () => {
+    const res: any = await apis.getOldSliceListByDocumentId(selectedDoc?.documentId)
+    if (res.code === 200 && res.data) {
+      sliceDataProcess(res.data)
+    }
+  }
+  const [tabKey, setTabKey] = useState<string>('slices');
+  // 批量删除
+  const onAllDelete = () => {
+    Modal.confirm({
+      title: '将要删除多条选中的切片,是否确认',
+      okText: '确认',
+      cancelText: '取消',
+      onOk: async () => {
+        const res: any = await apis.deleteSliceListApi(selectedDoc?.knowledgeId, selectedDoc?.documentId, {
+          sliceIds: selectedModuleIds,
+        });
+        if (res.code === 200) {
+          message.success('已删除所选切片');
+          setSelectedModuleIds([]);
+          setModules((pre) => {
+            return pre.filter((m: any) => !selectedModuleIds.includes(m.id));
+          });
+        }
+      },
+    });
+  }
+  // 如果是有Md编辑器推出的时候加个提示
+  const onMdCancel = () => {
+    if (selectedDoc?.standardClassification !== '2') {
+      Modal.confirm({
+        title: '提示',
+        content: '退出后,当前未保存的编辑行为都将失效,是否确认退出',
+        okText: '确认',
+        okType: 'danger',
+        cancelText: '取消',
+        onOk: async () => {
+          onCancel();
+        }
+      });
+    } else {
+      onCancel()
+    }
+  }
+  const [isPreviewCollapsed, setIsPreviewCollapsed] = useState(false); // 控制预览区域是否收起
+
+  return (
+    <>
+      <Modal
+        title="知识文档处理"
+        open={open}
+        onCancel={onMdCancel}
+        footer={
+          <div className="flex justify-end gap-3 items-center">
+            {tabKey === 'slices' && <>
+              <p className='font-bold'>拓展功能:</p>
+              <Checkbox checked={qaChecked} onChange={(e) => setQaChecked(e.target.checked)}>生成QA问答对</Checkbox>
+              <Checkbox checked={relatedQuestionsEnabled} onChange={(e) => setRelatedQuestionsEnabled(e.target.checked)}>生成关联问题</Checkbox>
+              <Checkbox checked={summaryGenerationEnabled} onChange={(e) => setSummaryGenerationEnabled(e.target.checked)}>生成摘要</Checkbox>
+              {customSeparator === '3' && <Checkbox checked={parentGenerationEnabled} onChange={(e) => setParentGenerationEnabled(e.target.checked)}>开启父子切片召回</Checkbox>}
+            </>}
+            <Button onClick={onMdCancel}>取消</Button>
+            {<Button type="primary" loading={selectedDoc?.status === '4'} onClick={() => updateSliceInfoList()}>
+              保存
+            </Button>}
+          </div>
+        }
+        width="95%"
+        maskClosable={false}
+        style={{ top: 24 }}
+        className="md-modal [&_.ant-modal-body]:p-0"
+      >
+        <div className="flex h-[85vh] gap-4 bg-gray-50 p-4">
+          {/* 文档列表 */}
+          <div
+            className={`flex flex-col rounded-2xl bg-white shadow-md transition-all duration-0 ${isListCollapsed ? 'w-14' : 'w-72'
+              }`}
+          >
+            <div
+              className={`flex items-center border-b border-gray-200 ${isListCollapsed ? 'justify-center px-0 py-4' : 'justify-between px-4 py-3'
+                }`}
+            >
+              {!isListCollapsed && (
+                <Tooltip title={knowledgeDetail ? knowledgeDetail.name : '文档列表'}>
+                  <Typography.Title level={5} className="mb-0! text-base font-semibold mt-0 overflow-hidden text-ellipsis whitespace-nowrap max-w-[400px]">
+                    {knowledgeDetail ? knowledgeDetail.name : '文档列表'}
+                  </Typography.Title>
+                </Tooltip>
+              )}
+              <Button
+                type="text"
+                size="small"
+                icon={isListCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
+                onClick={() => setIsListCollapsed((prev) => !prev)}
+              />
+            </div>
+            {isListCollapsed ? (
+              <div className="flex flex-1 items-center justify-center text-[11px] tracking-[0.4em] text-gray-400 [writing-mode:vertical-rl]">
+                文档列表
+              </div>
+            ) : (
+              <>
+                <div className="px-4 pt-3">
+                  <Space.Compact className="w-full" size="small">
+                    <Input
+                      placeholder="请输入文档名称"
+                      size='middle'
+                      value={keyword}
+                      onChange={(e) => {
+                        setKeyword(e.target.value);
+                      }}
+                      onPressEnter={handleSearch}
+                    />
+                    <Button
+                      type="primary"
+                      size="middle"
+                      icon={<SearchOutlined />}
+                      onClick={handleSearch}
+                    />
+                  </Space.Compact>
+                </div>
+                <div
+                  className="flex-1 space-y-2 overflow-y-auto px-4 pb-4 pt-3"
+                  ref={listContainerRef}
+                >
+                  {documents.map((doc) => (
+                    <div
+                      key={doc.documentId}
+                      className={`rounded-lg border border-transparent bg-gray-50 p-2.5 text-sm transition-all cursor-pointer hover:border-blue-300 hover:bg-blue-50 ${selectedDoc?.documentId === doc.documentId
+                        ? 'border-blue-400 ring-1 ring-blue-300'
+                        : ''
+                        }`}
+                      onClick={() => { onExportPdfStream(doc); }}
+                    >
+                      <div className="font-medium text-gray-900 text-xs flex items-center">
+                        <FileTextOutlined style={{ color: selectedDoc?.documentId === doc.documentId ? '#1677ff' : '' }} />
+                        <div className="ml-2 flex-1 min-w-0 truncate" title={doc.name}>{doc.name}</div>
+                        {doc?.status === '4' && (
+                          <div className="ml-2 flex-none">
+                            <Spin size="small" />
+                          </div>
+                        )}
+                      </div>
+                    </div>
+                  ))}
+                  {listLoading && (
+                    <div className="flex items-center justify-center gap-2 py-4 text-xs text-gray-500">
+                      <Spin size="small" /> <span>加载中...</span>
+                    </div>
+                  )}
+                  {!listLoading && documents.length === 0 && (
+                    <div className="py-8">
+                      <Empty description="暂无文档" image={Empty.PRESENTED_IMAGE_SIMPLE} />
+                    </div>
+                  )}
+                  {!hasMore && documents.length > 0 && (
+                    <div className="py-2 text-center text-xs text-gray-400">没有更多了</div>
+                  )}
+                </div>
+              </>
+            )}
+          </div>
+
+          {/* PDF预览 isPDfCollapsed */}
+          {selectedDoc?.suffix !== 'md' && <div className={`flex flex-col rounded-2xl bg-white shadow-md transition-all duration-0 ${isPDfCollapsed ? 'w-14' : 'flex-1'}`}>
+            <div className="px-5 pt-4 pb-2 flex items-center justify-between">
+              {!isPDfCollapsed && <Tooltip title={selectedDoc ? selectedDoc.name : 'PDF 预览'}>
+                <Typography.Title level={5} className="mb-0! text-base font-semibold mt-0 overflow-hidden text-ellipsis whitespace-nowrap max-w-[300px]">
+                  {selectedDoc ? selectedDoc.name : 'PDF 预览'}
+                </Typography.Title>
+              </Tooltip>}
+              <p>
+                {!isPDfCollapsed && (
+                  <Button
+                    type="text"
+                    size="small"
+                    icon={<FullscreenOutlined />}
+                    onClick={() => setPdfFullVisible(true)}
+                  />
+                )}
+                <Button
+                  type="text"
+                  size="small"
+                  icon={isPDfCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
+                  onClick={() => setIsPDfCollapsed((prev) => !prev)}
+                />
+              </p>
+            </div>
+            {isPDfCollapsed ? <div className="flex flex-1 items-center justify-center text-[11px] tracking-[0.4em] text-gray-400 [writing-mode:vertical-rl]">
+              PDF列表
+            </div> : <div className="flex flex-1 overflow-hidden pb-5 pt-3">
+              <div ref={pdfScrollRef} className="h-full w-full overflow-y-auto">
+                <div className="h-full min-h-[240px]">
+                  <Spin tip="pdf加载中..." spinning={pdfLoading} wrapperClassName="h-full flex justify-center">
+                    <div className="h-full w-full">
+                      {renderPdfPreview()}
+                    </div>
+                  </Spin>
+                </div>
+              </div>
+            </div>}
+          </div>}
+
+          {/* 智能切片 */}
+          <div className="flex flex-1 flex-col rounded-2xl bg-white shadow-md">
+            <div className="flex justify-between px-5 pb-2 pt-4 md_center">
+
+              <Tabs
+                activeKey={tabKey}
+                onChange={(key) => setTabKey(key as 'slices' | 'md')}
+                size="small"
+                items={selectedDoc?.standardClassification === '2' || selectedDoc?.customSeparator === '0' || selectedDoc?.customSeparator === '1' ? [
+                  { key: 'slices', label: '智能切片' },
+
+                ] : [{ key: 'slices', label: '智能切片' }, {
+                  key: 'md', label:
+                    <div>Md编辑器 <Tooltip title="markdown编辑仅支持最小段落切片(标准规范)和按标题段落切片"> <QuestionCircleOutlined /> </Tooltip> </div>
+                },]}
+              />
+              <div>
+                {tabKey === 'slices' && <Button size="small" disabled={!activeId} onClick={() => {
+                  Modal.confirm({
+                    title: '将放弃对切片的所有修改,恢复到初始状态,是否确认',
+                    okText: '确定',
+                    cancelText: '取消',
+                    onOk: () => {
+                      getOldSliceListByDocumentId();
+                    },
+                  })
+                }}>
+                  恢复全部
+                </Button>}
+                {tabKey === 'slices' && <Button size="small" disabled={!selectedModuleIds.length} className='ml-2'
+                  icon={<DeleteOutlined style={{ color: selectedModuleIds.length ? '#eb2f96' : '' }} />}
+                  onClick={() => {
+                    onAllDelete();
+                  }}>
+                </Button>}
+              </div>
+            </div>
+            {<div
+              className="flex-1 space-y-4 overflow-y-auto px-3 pb-5 pt-3"
+              ref={editorContainerRef}
+            >
+              <div className="h-full min-h-[240px] w-full">
+                <Spin tip="切片加载中..." spinning={sliceLoading} wrapperClassName="h-full w-full flex justify-center">
+                  <div className="h-full w-full">
+                    {tabKey === 'slices' && renderEditorModules()}
+                    {tabKey === 'md' && renderMdEditorModules()}
+                  </div>
+                </Spin>
+              </div>
+            </div>}
+          </div>
+
+          {/* 文档预览 */}
+          {
+            <div className={`flex flex-col rounded-2xl bg-white shadow-md transition-all duration-0 ${isPreviewCollapsed ? 'w-14' : 'flex-1'}`}>
+              <div className={`flex items-center border-b border-gray-200 ${isPreviewCollapsed ? 'justify-center px-0 py-4' : 'justify-between px-4 py-3'
+                }`}  >
+                {!isPreviewCollapsed && <Typography.Title level={5} className="mb-0! text-base font-semibold mt-0">
+                  文档预览
+                </Typography.Title>}
+                <Button
+                  type="text"
+                  size="small"
+                  icon={<MenuUnfoldOutlined />}
+                  onClick={() => setIsPreviewCollapsed((prev) => !prev)}
+                />
+              </div>
+              {isPreviewCollapsed ? <div className="flex flex-col items-center justify-center rounded-2xl bg-white shadow-md w-14 h-full">
+                <div className="text-[11px] tracking-[0.4em] text-gray-400 [writing-mode:vertical-rl] mt-4">
+                  文档预览
+                </div>
+              </div>
+                :
+                <div
+                  className="flex-1 overflow-y-auto px-3 pb-5 pt-3"
+                  ref={previewContainerRef}
+                >
+                  <div className="h-full min-h-[240px]">
+                    <Spin tip="预览文档加载中..." spinning={sliceLoading} wrapperClassName="h-full flex justify-center">
+                      <div className="h-full w-full">
+                        {tabKey === 'slices' && renderPreviewDocument()}
+                        {tabKey === 'md' && renderMdPreviewDocument()}
+                      </div>
+                    </Spin>
+                  </div>
+                </div>}
+            </div>}
+        </div>
+      </Modal>
+      {/* 全屏 PDF 预览(改为左侧 Drawer,宽度 40%) */}
+      <Drawer
+        title={selectedDoc ? selectedDoc.name : 'PDF 预览'}
+        open={pdfFullVisible}
+        onClose={() => setPdfFullVisible(false)}
+        placement="left"
+        width="55%"
+        footer={
+          <div className="flex items-center gap-2">
+            <Button size="small" onClick={() => setPdfFullScale((s) => Math.max(0.5, +(s - 0.25).toFixed(2)))}>-</Button>
+            <div className="text-sm">{Math.round(pdfFullScale * 100)}%</div>
+            <Button size="small" onClick={() => setPdfFullScale((s) => Math.min(3, +(s + 0.25).toFixed(2)))}>+</Button>
+            <Button size="small" onClick={() => { setPdfFullScale(1.5); setPdfFullVisible(false); }}>关闭</Button>
+          </div>
+        }
+      >
+        <div style={{ height: '100%', overflow: 'auto' }}>
+          {pdfBuffer ? (
+            <Document file={pdfBuffer} onLoadSuccess={({ numPages }) => setNumPages(numPages)}>
+              {Array.from(new Array(numPages), (_, i) => (
+                <div key={i} style={{ display: 'flex', justifyContent: 'center', marginBottom: 12 }}>
+                  <Page pageNumber={i + 1} scale={pdfFullScale} renderAnnotationLayer={false} renderTextLayer={true} />
+                </div>
+              ))}
+            </Document>
+          ) : (
+            <div className="flex h-full items-center justify-center">暂无 PDF</div>
+          )}
+        </div>
+      </Drawer>
+    </>
+  );
+};
+
+export default observer(MdModal); 

+ 358 - 0
src/pages/deepseek/knowledgeLib/detail/components/QuoteModal.tsx

@@ -0,0 +1,358 @@
+import React, { useState, useEffect } from 'react';
+import { Button, Modal, Table, TablePaginationConfig, TableColumnsType, Typography, message, Tabs, Input } from 'antd';
+import type { TableProps } from 'antd';
+import { apis } from '@/apis';
+import { Record } from '../types';
+import dayjs from 'dayjs';
+import useAppState from '@/store';
+
+import PrevewSlice from './prevewSlice';
+
+interface QuoteModalProps {
+  open: boolean;
+  knowledgeDetail: any;
+  onCancel: () => void;
+}
+
+const QuoteModal: React.FC<QuoteModalProps> = ({ open, knowledgeDetail, onCancel }) => {
+  const [list, setList] = useState<Record[]>([]); // 示例数据
+  const [page, setPage] = useState<{ page: number; size: number; total: number }>({
+    page: 1,
+    size: 10,
+    total: 0,
+  });
+  const [titleName, setTitleName] = useState<string>('');
+  const [appStateList, setAppStateList] = useState<any[]>([]);
+  const [activeTabKey, setActiveTabKey] = useState<string>('');
+  const [searchKeyword, setSearchKeyword] = useState<string>('');
+  const { getAppState } = useAppState();
+  const [openDrawer, setOpenDrawer] = useState<boolean>(false);
+  const [selectedRecord, setSelectedRecord] = useState<any>(null);
+  const columns: TableColumnsType<Record> = [
+    {
+      title: '序号',
+      dataIndex: 'index',
+      width: 80,
+      render: (text, record, index) => {
+        return index + 1;
+      }
+    },
+    {
+      title: '文件名',
+      dataIndex: 'name',
+      width: 300,
+      sorter: (a, b) => a.name.localeCompare(b.name),
+      render: (text, record) => {
+        return (
+          `${text}`
+        )
+      }
+    },
+    {
+      title: '所在知识库',
+      dataIndex: 'knowledgeName',
+      width: 300,
+      render: (text, record) => {
+        return (
+          `${text}`
+        )
+      }
+    },
+    {
+      title: '创建人',
+      dataIndex: 'nickName',
+      width: 300,
+      render: (text, record) => {
+        return (
+          `${text}`
+        )
+      }
+    },
+    {
+      title: '文件大小',
+      dataIndex: 'length',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          const size = (text / 1024 / 1024).toFixed(2);
+          return `${size} M`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '字符数量',
+      dataIndex: 'wordNum',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          return `${text}`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '切片数量',
+      dataIndex: 'sliceTotal',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          return `${text}`;
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '上传时间',
+      dataIndex: 'createTime',
+      width: 180,
+      render: (text) => {
+        if (text) {
+          return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '更新时间',
+      dataIndex: 'updateTime',
+      width: 180,
+      render: (text) => {
+        if (text) {
+          return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '操作',
+      dataIndex: 'operation',
+      width: 180,
+      fixed: 'right',
+      render: (text, record: any) => {
+        return (
+          <>
+            <a
+              style={{ marginRight: 16 }}
+              onClick={() => {
+                setOpenDrawer(true);
+                setSelectedRecord(record);
+              }}
+            >
+              查看切片
+            </a>
+          </>
+        )
+      }
+    }
+  ];
+  const [allLoding, setAllLoding] = useState<boolean>(false);
+  const handleOk = async () => {
+    if (documentids.length === 0) {
+      Modal.warning({
+        title: '提示',
+        content: '请选择要引用的文档',
+      });
+      return;
+    }
+    setAllLoding(true);
+    try {
+      const falgDocumentids = documentids.map((item: any) => {
+        return item
+      })
+      // 先调用效验接口
+      const checkRes: any = await apis.checkQuoteFileApi({
+        documentIds: falgDocumentids,
+        knowledgeId: knowledgeDetail.knowledgeId,
+      })
+      const checkResData = checkRes.data || [];
+      if (!checkResData?.length) {
+        await onImportDocumentList(falgDocumentids);
+      } else {
+        setAllLoding(false);
+        Modal.confirm({
+          title: '提示',
+          content: checkResData.map((item: any) => {
+            return <div key={item.ossId}>文件“{item.newName}”已存在,知识库中已存在的文件名是“{item.oldName}”</div>
+          }),
+          onOk: async () => {
+            setAllLoding(true);
+            // 过滤掉已存在的文件(根据 ossId)
+            const filtered = falgDocumentids.filter((f: any) => !checkResData.some((d: any) => d.documentId === f));
+
+            if (!filtered || filtered.length === 0) {
+              // 所有文件都已存在,提示并结束
+              message.warning('选中文件均已存在,请重新选择。');
+              setAllLoding(false);
+              return;
+            }
+
+            // 构建参数并继续上传剩余文件
+            // const nextParams = {
+            //   ...values,
+            //   parsingType: values.parsingType,
+            //   standardClassification,
+            //   fileList: filtered.map((item: any) => ({
+            //     ...item,
+            //     suffix: (item.fileName || item.name || '').split('.').pop(),
+            //   })),
+            // };
+            await onImportDocumentList(filtered);
+          },
+          onCancel: () => {
+            setAllLoding(false);
+          }
+        });
+      }
+      return
+    } catch (error) {
+      setAllLoding(false);
+    }
+    onCancel();
+  };
+
+  const onImportDocumentList = async (documentids:any) => {
+    const res: any = await apis.importDocumentList({
+      documentIds: documentids,
+      knowledgeId: knowledgeDetail.knowledgeId,
+    });
+    if (res?.code === 200) {
+      message.success('引用成功');
+    }
+    setAllLoding(false);
+  }
+
+
+  const paginationConfig: TablePaginationConfig = {
+    // 显示数据总量
+    showTotal: (total: number) => {
+      return `共 ${total} 条`;
+    },
+    // 展示分页条数切换
+    showSizeChanger: true,
+    // 指定每页显示条数
+    pageSizeOptions: ['10', '20', '50', '100'],
+    // 快速跳转至某页
+    showQuickJumper: true,
+    current: page.page,
+    pageSize: page.size,
+    total: page.total,
+    onChange: async (page, pageSize) => {
+      setPage((prevState) => ({
+        ...prevState,
+        page: page,
+        size: pageSize,
+      }));
+      onGetQuoteDocumentList(page, pageSize);
+    },
+  };
+  const [listLoading, setListLoading] = useState<boolean>(false);
+  const [documentids, setdocumentids] = React.useState<string[]>([]); // 选择的文档ID数组
+  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
+
+  // 示例数据和列定义
+  const rowSelection: TableProps<Record>['rowSelection'] = {
+    selectedRowKeys,
+    onChange: (selectedRowKeys: React.Key[], selectedRows: Record[]) => {
+      setSelectedRowKeys(selectedRowKeys);
+      const flagids = selectedRows.map((item) => {
+        return item.documentId
+      })
+      setdocumentids(flagids)
+    },
+  };
+  const onGetQuoteDocumentList = async (pageNum: number = 1, pageSize: number = 10, keyword?: string, name: string = '') => {
+    const params: any = {
+      knowledge_id: knowledgeDetail.knowledgeId,
+      standardClassification: keyword,
+      name,
+      pageNum,
+      pageSize,
+    };
+    const res: any = await apis.getQuoteDocumentList(params);
+    if (res?.code === 200) {
+      setList(res.rows || [])
+      setPage((prev) => ({ ...prev, total: res.total || prev.total }));
+    }
+  }
+  const init = async () => {
+    const res: any = await getAppState();
+    const list = res || [];
+    setAppStateList([{
+      label: '全部',
+      value: '',
+    }, ...list]);
+    // 初始tab key
+    const initKey = String((knowledgeDetail.standardClassification ?? (list[0] && list[0].value)) || '');
+    setActiveTabKey('');
+    // 设置显示名称
+    const match = list.find((it: any) => String(it.value) === String(initKey));
+    if (match) setTitleName(match.label);
+    // 首次请求
+    onGetQuoteDocumentList(1, page.size, activeTabKey, '');
+  }
+  useEffect(() => {
+    init();
+  }, [])
+  return (
+    <>
+      <Modal
+        title="引用知识文库"
+        width={'90%'}
+        open={open}
+        onCancel={onCancel}
+        footer={<div className="flex justify-end gap-3 items-center">
+          <Button onClick={onCancel}>取消</Button>
+          <Button type="primary" loading={allLoding} onClick={() => handleOk()}>
+            保存
+          </Button>
+        </div>}
+      >
+        <div className="flex items-center justify-between">
+          <Tabs
+            activeKey={activeTabKey}
+            onChange={(key) => {
+              setActiveTabKey(String(key));
+              const match = appStateList.find((it: any) => String(it.value) === String(key));
+              if (match) setTitleName(match.label);
+              // 切换 tab 时重载列表
+              onGetQuoteDocumentList(1, page.size, key, '');
+              setdocumentids([]); // 清空已选择的文档ID
+              setSelectedRowKeys([])
+            }}
+            items={appStateList.map((it: any) => ({ key: String(it.value), label: it.label }))}
+          />
+          <Input.Search
+            placeholder="请输入文件名搜索"
+            allowClear
+            enterButton
+            style={{ width: 260 }}
+            value={searchKeyword}
+            onChange={(e) => setSearchKeyword(e.target.value)}
+            onSearch={(value) => {
+              // 搜索时重新拉取第一页
+              onGetQuoteDocumentList(1, page.size, activeTabKey, value);
+            }}
+          />
+        </div>
+        <Table
+          scroll={{ x: 'max-content' }}
+          rowSelection={{ type: 'checkbox', ...rowSelection }}
+          rowKey={(record) => record.documentId}
+          loading={listLoading}
+          columns={columns}
+          dataSource={list}
+          pagination={paginationConfig}
+        />
+      </Modal>
+      <PrevewSlice openDrawer={openDrawer} onClose={() => setOpenDrawer(false)} title="预览切片" record={selectedRecord} />
+    </>
+  );
+};
+
+export default QuoteModal;

+ 669 - 0
src/pages/deepseek/knowledgeLib/detail/components/UploadModal.tsx

@@ -0,0 +1,669 @@
+import * as React from 'react';
+import { Modal, Form, Input, Select, Upload, UploadProps, message, Spin, Tooltip, Button } from 'antd';
+import { InboxOutlined, QuestionCircleOutlined } from '@ant-design/icons';
+import { apis } from '@/apis';
+import { getHeaders } from '@/apis/config';
+import { RecordKonwledge } from '../types'
+const FormItem = Form.Item;
+const { Option } = Select;
+const { TextArea } = Input;
+const { Dragger } = Upload;
+
+interface Props {
+    open: boolean;
+    knowledgeId: string;
+    knowledgeDetail: RecordKonwledge;
+    onCancel: () => void;
+    onSuccess: () => void;
+}
+
+const UploadModal: React.FC<Props> = (props: Props) => {
+    const { open, knowledgeId, onCancel, onSuccess, knowledgeDetail } = props;
+    const [form] = Form.useForm();
+    const [uploadLoading, setUploadLoading] = React.useState<boolean>(false);
+    const [standardClass, setStandardClass] = React.useState<any[]>([]);// 选择分类-下拉选项
+    const [parsingTypeList, setParsingTypeList] = React.useState<any[]>([]);// 解析工具-下拉选项
+    const [parsingTypeListBackup, setParsingTypeListBackup] = React.useState<any[]>([]);// 解析工具-下拉选项-备份数据
+    const [standardClassification, setStandardClassification] = React.useState<string>() // 选择分类
+    const [parsingType, setParsingType] = React.useState<string>() // 选择解析工具
+    const [splittingOldList, setSplittingOldList] = React.useState<any[]>([]); // 旧的切分规则列表
+    const [splittingType, setSplittingType] = React.useState<any>([]); // 选择切分规则 
+    const [fileOssList, setFileOssList] = React.useState<any>([]); // 选中的列表OSS信息
+    const [oldFileList, setOldFileList] = React.useState<any>([]); // 选中的本地文件列表
+    const [oldfileName, setOldfileName] = React.useState<any>(''); // 选中的本地文件的信息
+    const [isVisibleSlice, setIsVisibleSlice] = React.useState(false);
+    const [formatb, setFormatb] = React.useState('md,txt,pdf,doc,docx,odt,rtf,ods,ppt,pptx,odp,jpg,png,jpeg'); // 默认是通用
+    const oldFileListRef = React.useRef(oldFileList);
+
+    React.useEffect(() => {
+        oldFileListRef.current = oldFileList;
+    }, [oldFileList]);
+    
+    // 获取解析工具
+    const fetchParsingTypeList = async () => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('parsing_type');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                }
+            });
+            setParsingTypeList(list);
+            setParsingTypeListBackup(list);
+            form.setFieldsValue({
+                parsingType: list[0]?.value
+            })
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    // 获取向默认切分规则
+    const fetchsplittingType = async () => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('splitting_type');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                    remark: item.remark,
+                }
+            });
+            setSplittingType(list);
+            setSplittingOldList(list);
+            form.setFieldsValue({
+                customSeparator: '2',
+                sliceValue: knowledgeDetail.sliceValue,
+            })
+
+            if (knowledgeDetail.splittingType === '0') {
+                setIsVisibleSlice(!isVisibleSlice);
+            }
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    const onChangeF = (value: string) => {
+        if (value === '0') {
+            setIsVisibleSlice(!isVisibleSlice);
+        } else {
+            setIsVisibleSlice(false);
+        }
+    };
+    // 批量删除oss文件
+    const onDeleteOssFileApi = async (ossIds: string) => {
+        try {
+            const res: any = await apis.deleteOssFileApi(ossIds);
+            if (res.code !== 200) {
+                message.error('删除oss文件失败');
+            }
+        } catch (error) {
+            console.error('删除oss文件失败:', error);
+        }
+    };
+    // 手动上传单个文件
+    const uploadOneFile = (fileItem: any) => {
+        return new Promise((resolve, reject) => {
+            if (fileItem.response && fileItem.response.code === 200) {
+                resolve(fileItem.response.data);
+                return;
+            }
+            const formData = new FormData();
+            formData.append('file', fileItem.originFileObj);
+
+            const xhr = new XMLHttpRequest();
+            xhr.open('POST', '/api/resource/oss/upload', true);
+            const headers: any = getHeaders();
+            for (const key in headers) {
+                xhr.setRequestHeader(key, headers[key]);
+            }
+
+            xhr.upload.onprogress = (event) => {
+                if (event.lengthComputable) {
+                    const percent = parseInt(((event.loaded / event.total) * 100).toFixed(0));
+                    setOldFileList((prev: any[]) => prev.map(f => {
+                        if (f.uid === fileItem.uid) {
+                            return { ...f, percent, status: 'uploading' };
+                        }
+                        return f;
+                    }));
+                }
+            };
+
+            xhr.onload = () => {
+                if (xhr.status === 200) {
+                    const response = JSON.parse(xhr.responseText);
+                    if (response.code === 200) {
+                        setOldFileList((prev: any[]) => prev.map(f => {
+                            if (f.uid === fileItem.uid) {
+                                return { ...f, status: 'done', percent: 100, response };
+                            }
+                            return f;
+                        }));
+                        resolve(response.data);
+                    } else {
+                        setOldFileList((prev: any[]) => prev.map(f => {
+                            if (f.uid === fileItem.uid) {
+                                return { ...f, status: 'error' };
+                            }
+                            return f;
+                        }));
+                        message.error(response.msg || '上传失败');
+                        reject(response.msg);
+                    }
+                } else {
+                    setOldFileList((prev: any[]) => prev.map(f => {
+                        if (f.uid === fileItem.uid) {
+                            return { ...f, status: 'error' };
+                        }
+                        return f;
+                    }));
+                    message.error('上传失败');
+                    reject('Http Error');
+                }
+            };
+
+            xhr.onerror = () => {
+                setOldFileList((prev: any[]) => prev.map(f => {
+                    if (f.uid === fileItem.uid) {
+                        return { ...f, status: 'error' };
+                    }
+                    return f;
+                }));
+                message.error('网络错误');
+                reject('Network Error');
+            };
+
+            xhr.send(formData);
+        });
+    };
+
+    // 上传组件的参数
+    const uploadProps: UploadProps = {
+        name: 'file',
+        // 根据选择的分类决定是否允许多选与最大数量:分类为 '3' 时只允许单文件,其余允许最多 5 个
+        multiple: standardClassification !== '3',
+        maxCount: standardClassification === '3' ? 1 : 5,
+        headers: getHeaders(),
+        // 使用受控 fileList,便于自定义已上传文件列表的展示和管理
+        fileList: oldFileList,
+        beforeUpload(file, fileList) {
+            const maxCount = standardClassification === '3' ? 1 : 5;
+            const currentCount = (oldFileList || []).length;
+            const incomingCount = fileList?.length || 1;
+            if (currentCount + incomingCount > maxCount) {
+                message.error(`最多只能上传 ${maxCount} 个文件`);
+                return Upload.LIST_IGNORE;
+            }
+            const allowedExtensions = formatb ? formatb.split(',') : ['*'];
+            const nextFormatb = ['exe', 'msi', 'bat', 'cmd', 'com', 'sh', 'run', 'bin', 'app', 'dmg', 'pkg', 'jar', 'py'];
+            // 检查文件类型
+            const fileExt: string = file.name.split('.').pop()?.toLowerCase() || '';
+            if(nextFormatb.includes(fileExt)){
+                message.error(`不支持 ${fileExt} 格式的文件上传-12`);
+                return Upload.LIST_IGNORE;
+            }
+            if(formatb === '*'){
+                // 支持所有格式
+            }else if (!fileExt || !allowedExtensions.includes(fileExt)) {
+                message.error(`不支持 ${fileExt} 格式的文件上传`);
+                return Upload.LIST_IGNORE;
+            }
+
+            // 检查文件大小
+            const fileSizeMB = file.size / 1024 / 1024;
+            if (fileSizeMB > 50) {
+                message.error('单个文件不能大于50M');
+                return Upload.LIST_IGNORE;
+            }
+
+            if (['jpg', 'png', 'jpeg'].includes(fileExt!) && fileSizeMB > 5) {
+                message.error('单张图片不能大于5M');
+                return Upload.LIST_IGNORE;
+            }
+
+            let totalSize = fileSizeMB;
+            for (const f of oldFileList) {
+                totalSize += (f.size / 1024 / 1024);
+            }
+            if (totalSize > 150) {
+                message.error('文件总大小超过150M');
+                return Upload.LIST_IGNORE;
+            }
+
+            // 阻止自动上传
+            return false;
+        },
+        onChange(info) {
+            setOldFileList(info.fileList);
+            if (standardClassification === '3' && info.fileList.length > 0) {
+                const latest = info.fileList[info.fileList.length - 1];
+                if (latest && latest.originFileObj) {
+                    const nameParts = latest.name.split('.');
+                    const nameWithoutExt = nameParts.length > 1 ? nameParts.slice(0, -1).join('.') : latest.name;
+                    form.setFieldsValue({
+                        name: nameWithoutExt
+                    });
+                    setOldfileName(latest.name);
+                }
+            }
+        },
+        onDrop(e) {
+            console.log('Dropped files', e.dataTransfer.files);
+        },
+        onRemove(file) {
+            // 先从本地受控 fileList 中移除
+            setOldFileList((prev: any[]) => (prev || []).filter((f) => f.uid !== file.uid));
+            // 如果该文件已上传并携带后端返回数据,则尝试删除 OSS 记录
+            const resFile = file?.response?.data;
+            if (resFile?.ossId) {
+                onDeleteOssFileApi(`${resFile.ossId}`);
+                setFileOssList((pre: any[]) => (pre || []).filter((item: any) => item.ossId !== resFile.ossId));
+            }
+            return true;
+        }
+
+    };
+    // 获取选择分类
+    const fetchAppstandardClass = async () => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('standard_classification');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                    remark: item.remark,
+                }
+            });
+            setStandardClass(list);
+            form.setFieldsValue({
+                standardClassification: list[1]?.value
+            })
+            setStandardClassification(list[1]?.value)
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    React.useEffect(() => {
+        if (open) {
+            form.resetFields();
+            fetchParsingTypeList();
+            fetchsplittingType();
+            fetchAppstandardClass();
+        }
+    }, [open]);
+
+    // 点击确定
+    const handleClickConfirm = () => {
+        form.validateFields().then(async (values) => {
+            // 这里可以处理表单数据的提交
+            const maxCount = standardClassification === '3' ? 1 : 5;
+            if (!oldFileList || oldFileList.length === 0) {
+                message.warning('请选择文件')
+                return
+            }
+            if (oldFileList.length > maxCount) {
+                message.warning(`最多只能上传 ${maxCount} 个文件`)
+                return
+            }
+
+            setUploadLoading(true);
+
+            try {
+                // 上传所有文件
+                const uploadResults = await Promise.all(oldFileList.map((file: any) => uploadOneFile(file)));
+
+                // 构造 ossItems
+                let ossItems = oldFileList.map((f: any, index: number) => {
+                    const data = uploadResults[index];
+                    const nameParts = f.name.split('.');
+                    return {
+                        uid: f.uid,
+                        name: nameParts.length > 1 ? nameParts.slice(0, -1).join('.') : f.name.split('.')[0],
+                        ...data
+                    };
+                });
+
+                // 过滤掉已经在过程中被删除的文件
+                const currentUids = oldFileListRef.current?.map((f: any) => f.uid) || [];
+                const removedItems = ossItems.filter((item: any) => !currentUids.includes(item.uid));
+                ossItems = ossItems.filter((item: any) => currentUids.includes(item.uid));
+                removedItems.forEach((resFile: any) =>{
+                    if (resFile.ossId)
+                    onDeleteOssFileApi(`${resFile.ossId}`);
+                })
+
+                setFileOssList(ossItems);
+
+                const params = {
+                    ...values,
+                    parsingType: values.parsingType,
+                    standardClassification,
+                    fileList: ossItems.map((item: any) => ({
+                        ...item,
+                        suffix: (item.fileName || item.name || '').split('.').pop(),
+                    })),
+                }
+
+                // checkFileApi 检查文件是否存在 如果已存在就提示 未存在成功
+                const checkParams = {
+                    ...values,
+                    parsingType: values.parsingType,
+                    standardClassification,
+                    ossParms: ossItems,
+                    knowledgeId: knowledgeId
+                }
+
+                const checkRes: any = await apis.checkFileApi(checkParams);
+                const checkResData = checkRes.data || [];
+
+                if (!checkResData?.length) {
+                    await onUploadDocumentApi(params);
+                    setUploadLoading(false);
+                } else {
+                    setUploadLoading(false);
+                    Modal.confirm({
+                        title: '提示',
+                        content: checkResData.map((item: any) => {
+                            return <div key={item.ossId}>文件“{item.newName}”已存在,知识库中已存在的文件名是“{item.oldName}”</div>
+                        }),
+                        onOk: async () => {
+                            setUploadLoading(true);
+                            // 过滤掉已存在的文件(根据 ossId)
+                            const filtered = ossItems.filter((f: any) => !checkResData.some((d: any) => d.ossId === f.ossId));
+
+                            if (!filtered || filtered.length === 0) {
+                                // 所有文件都已存在,提示并结束
+                                message.warning('选中文件均已存在知识库,未执行上传。');
+                                setUploadLoading(false);
+                                return;
+                            }
+
+                            // 构建参数并继续上传剩余文件
+                            const nextParams = {
+                                ...values,
+                                parsingType: values.parsingType,
+                                standardClassification,
+                                fileList: filtered.map((item: any) => ({
+                                    ...item,
+                                    suffix: (item.fileName || item.name || '').split('.').pop(),
+                                })),
+                            };
+                            await onUploadDocumentApi(nextParams);
+                            setUploadLoading(false);
+                        },
+                        onCancel: () => {
+                            setUploadLoading(false);
+                        }
+                    });
+                }
+            } catch (error) {
+                setUploadLoading(false);
+                console.error(error);
+            }
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+    const onUploadDocumentApi = async (params: any) => {
+        const res = await apis.uploadDocumentApi(knowledgeId, params)
+
+        if (res.code === 200) {
+            // 上传逻辑已在上传组件的 onChange 中处理
+            message.success('操作成功');
+            onCancel();
+            onSuccess();
+            form.resetFields();
+        }
+    }
+    // 点击取消
+    const handleClickCancel = () => {
+        form.resetFields();
+        onCancel();
+    };
+    return (
+        <Modal
+            width={600}
+            title='上传知识文件'
+            maskClosable={false}
+            centered={true}
+            open={open}
+            onCancel={handleClickCancel}
+            footer={
+                <div>
+                    <Button
+                        className="ant-btn ant-btn-default"
+                        onClick={handleClickCancel}
+                        style={{ marginRight: 8 }}
+                    >
+                        取消
+                    </Button>
+                    <Button
+                        className="ant-btn ant-btn-primary"
+                        onClick={handleClickConfirm}
+                        loading={uploadLoading}
+                    >
+                        确定
+                    </Button>
+                </div>
+            }
+        >
+            <Spin spinning={false}>
+                <Form form={form} layout='vertical'>
+                    <FormItem
+                        label='选择分类'
+                        name='standardClassification'
+                        rules={[{ required: true, message: '请选择分类' }]}
+                    >
+                        <Select
+                            style={{ width: '100%' }}
+                            placeholder='请选择分类'
+                            optionLabelProp="label"
+                            allowClear={true}
+                            value={standardClassification}
+                            onChange={(e) => {
+                                // form.setFieldsValue({
+                                //     standardClassification: e,
+                                // })
+                                let nextFormatb = 'md,txt,pdf,doc,docx,odt,rtf,ods,ppt,pptx,odp';
+
+                                if(e === '0') {
+                                    nextFormatb = 'md,txt,pdf,doc,docx,odt,rtf,ods,ppt,pptx,odp';
+                                }
+                                if(e === '1') {
+                                    nextFormatb = 'md,txt,pdf,doc,docx,odt,rtf,ods,ppt,pptx,odp,jpg,png,jpeg';
+                                }
+                                if(e === '2') {
+                                    nextFormatb = 'xlsx';
+                                }
+                                if(e === '3') {
+                                    // nextFormatb = 'md,txt,pdf,jpg,png,jpeg,doc,docx,odt,rtf,xls,xlsx,ppt,pptx,odp';
+                                    nextFormatb = '*';
+                                }
+                                // 切换分类时,判断是新的类型是否支持当前选中的这些文件 如果不支持就给提示让手动去清除
+                                const allowedExtensions = nextFormatb.split(',');
+                                const invalidFiles = oldFileList.filter((file: any) => {
+                                    const fileExt = file.name.split('.').pop()?.toLowerCase();
+                                    return fileExt && !allowedExtensions.includes(fileExt);
+                                });
+                                if (invalidFiles.length > 0) {
+                                    // 还原Select选中值
+                                    form.setFieldsValue({
+                                        standardClassification: standardClassification
+                                    });
+                                    Modal.confirm({
+                                        title: '提示',
+                                        content: invalidFiles.map((item: any) => {
+                                            return <div key={item.uid}>文件“{item.name}”,与所选分类不匹配</div>
+                                        }),
+                                        onOk: () => {
+                                            
+                                        }
+                                    })
+                                    return;
+                                }
+
+                                setStandardClassification(e);
+                                const oldfileOssIds = fileOssList.map((item: any) => item.ossId).join(',');
+                                if (oldfileOssIds) {
+                                    onDeleteOssFileApi(oldfileOssIds);
+                                }
+                                // setOldFileList([]);
+                                // setFileOssList([]);
+                                setOldfileName('');
+                                if (e === '0') {
+                                    // 标准规范
+                                    const newSplittingList = splittingOldList.filter((item: any) => item.value === '3');
+                                    setSplittingType(newSplittingList);
+                                    form.setFieldsValue({
+                                        customSeparator: newSplittingList[0]?.value,
+                                    });
+
+                                    const newParsingTypeList = parsingTypeListBackup.filter((item: any) => item.value === '0');
+                                    setParsingTypeList(newParsingTypeList);
+
+                                    form.setFieldsValue({
+                                        parsingType: newParsingTypeList[0]?.value,
+                                    })
+                                } else {
+                                    setSplittingType(splittingOldList);
+                                    // parsingTypeListBackup
+                                    setParsingTypeList(parsingTypeListBackup);
+                                }
+                                if (e === '1') {
+                                    // 通用规范
+                                    form.setFieldsValue({
+                                        customSeparator: '2',
+                                    });
+                                }
+                                setFormatb(nextFormatb);
+                                // 清空文件名称
+                                form.setFieldsValue({
+                                    name: '',
+                                });
+                            }}
+                        >
+                            {
+                                standardClass.map((item, index) => {
+                                    return <Option value={item.value} key={index} label={item.label}>
+                                        {item.label}
+                                        <Tooltip title={item.remark} >
+                                            <QuestionCircleOutlined style={{ color: '#FF9800', marginLeft: '3px' }} />
+                                        </Tooltip>
+                                    </Option>
+                                })
+                            }
+                        </Select>
+                    </FormItem>
+                    <div style={{ marginBottom: 20, width: '100%', minHeight: '150px' }}>
+                        <Dragger {...uploadProps}>
+                            <p className="ant-upload-drag-icon">
+                                <InboxOutlined />
+                            </p>
+                            <p>
+                                点击上传,或拖放文件到此处
+                            </p>
+                            {standardClassification==='3'?<p className="ant-upload-hint">
+                                支持常规日程工作中的大部分文件格式
+                            </p>:
+                            <p className="ant-upload-hint">
+                                支持文件格式{formatb}
+                                ,<br/>单个文件 ≤ 50M
+                            </p>}
+                        </Dragger>
+                    </div>
+                    {(standardClassification === '0' || standardClassification === '1') &&
+                        <><FormItem
+                            label='解析工具'
+                            name='parsingType'
+                            rules={[{ required: true, message: '请解析工具' }]}
+                        >
+                            <Select
+                                style={{ width: '100%' }}
+                                placeholder='请解析工具'
+                                allowClear={true}
+                                onChange={(e) => {
+                                    setParsingType(e)
+                                    if (e === '2') {
+                                        const newSplittingList = splittingOldList.filter((item: any) => item.value !== '3');
+                                        setSplittingType(newSplittingList);
+                                        form.setFieldsValue({
+                                            customSeparator: newSplittingList[0]?.value,
+                                        });
+                                    } else {
+                                        setSplittingType(splittingOldList);
+                                    }
+                                }}
+                            >
+                                {
+                                    parsingTypeList.map((item, index) => {
+                                        return <Option value={item.value} key={index}>
+                                            {item.label}
+                                        </Option>
+                                    })
+                                }
+                            </Select>
+                        </FormItem>
+                            <FormItem
+                                label='默认切分规则'
+                                name='customSeparator'
+                                rules={[{ required: true, message: '默认切分规则不能为空' }]}
+                            >
+                                {
+                                    <Select
+                                        style={{ width: '100%' }}
+                                        placeholder='请选择默认切分规则'
+                                        allowClear={true}
+                                        onChange={onChangeF}
+                                        optionLabelProp="label"
+                                    >
+                                        {
+                                            splittingType.map((item: any, index: any) => {
+                                                return <Option value={item.value} key={index} label={item.label}>
+                                                    {item.label}
+                                                    <Tooltip title={item.remark} >
+                                                        <QuestionCircleOutlined style={{ color: '#FF9800', marginLeft: '3px' }} />
+                                                    </Tooltip>
+                                                </Option>
+                                            })
+                                        }
+                                    </Select>
+                                }
+                            </FormItem></>}
+                    {isVisibleSlice &&
+                        <FormItem
+                            label='分隔符'
+                            name='sliceValue'
+                            rules={[{ required: true, message: '自定义切片设置不能为空' }]}
+                        >
+                            <Input max={1024}
+                            />
+                        </FormItem>
+                    }
+                    {standardClassification === '3' && <><FormItem
+                        label='文件名称'
+                        name='name'
+                        rules={[{ required: true, message: '文件名称不能为空', whitespace: true }]}
+                    >
+                        <Input placeholder='请输入文件名称' />
+                    </FormItem>
+                        <FormItem
+                            label='描述'
+                            name='remark'
+                            rules={[{ required: true, message: '描述不能为空', whitespace: true }]}
+                        >
+                            <TextArea
+                                placeholder='请输入描述信息'
+                                showCount={true}
+                                rows={6}
+                                maxLength={500}
+                            />
+                        </FormItem></>}
+                </Form>
+            </Spin>
+        </Modal>
+    );
+};
+
+export default UploadModal;
+

+ 437 - 0
src/pages/deepseek/knowledgeLib/detail/components/prevewSlice.tsx

@@ -0,0 +1,437 @@
+// 查看切片
+import React, { useEffect, useMemo, useState, useRef, useLayoutEffect } from 'react';
+import { observer } from 'mobx-react';
+import { Drawer, Row, Col, Input, Button, List, Typography, Select, Spin, Image, message } from 'antd';
+import type { DrawerProps, RadioChangeEvent } from 'antd';
+import { SnippetsOutlined } from '@ant-design/icons';
+import MarkdownIt from 'markdown-it';
+import { fetchReviseToolAllList, fetchReviseToolSliceList, apis } from '@/apis';
+import '../../revisionTool/components/reviseDrawer.less'
+import { Document, Page, pdfjs } from 'react-pdf';
+
+interface ReviseDrawerProps {
+    openDrawer: boolean;
+    onClose: () => void;
+    title: string;
+    record: any;
+}
+// 设置 pdf.worker(使用 CDN 作为回退)
+try {
+    pdfjs.GlobalWorkerOptions.workerSrc = (pdfjs.GlobalWorkerOptions.workerSrc || '') || '//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
+} catch (e) {
+    // ignore
+}
+
+// =================== PDF 子组件(文件级,最重要) ===================
+
+const LazyPage = React.memo(
+    ({
+        pageNumber,
+        width,
+        containerRef,
+    }: {
+        pageNumber: number;
+        width: number;
+        containerRef: React.RefObject<HTMLDivElement>;
+    }) => {
+        const elRef = React.useRef<HTMLDivElement | null>(null);
+        const [visible, setVisible] = React.useState(false);
+
+        React.useEffect(() => {
+            const el = elRef.current;
+            const root = containerRef.current;
+            if (!el || !root) return;
+
+            const io = new IntersectionObserver(
+                entries => {
+                    entries.forEach(e => e.isIntersecting && setVisible(true));
+                },
+                { root, rootMargin: '400px' }
+            );
+
+            io.observe(el);
+            return () => io.disconnect();
+        }, [containerRef]);
+
+        return (
+            <div ref={elRef} style={{ background: '#fff' }}>
+                {visible ? (
+                    <Page
+                        pageNumber={pageNumber}
+                        // width={width}
+                        renderTextLayer={false}
+                        renderAnnotationLayer={false}
+                        className='pdf-page'
+                    />
+                ) : (
+                    <div
+                        style={{
+                            width: '100%',
+                            height: Math.floor(width * 1.3),
+                            background: '#fafafa',
+                        }}
+                    />
+                )}
+            </div>
+        );
+    }
+);
+
+const PdfViewer = React.memo(
+    ({
+        file,
+        numPages,
+        pageWidth,
+        scale,
+        onLoadSuccess,
+        containerRef,
+    }: {
+        file: string;
+        numPages: number;
+        pageWidth: number;
+        scale: number;
+        onLoadSuccess: any;
+        containerRef: React.RefObject<HTMLDivElement>;
+    }) => {
+        return (
+            <Document
+                // renderMode="canvas"
+                file={file}
+                onLoadSuccess={onLoadSuccess}
+            >
+                {Array.from({ length: numPages }).map((_, idx) => (
+                    <LazyPage
+                        key={idx}
+                        pageNumber={idx + 1}
+                        width={Math.floor(pageWidth * scale)}
+                        containerRef={containerRef}
+                    />
+                ))}
+            </Document>
+        );
+    },
+    (prev, next) =>
+        prev.file === next.file &&
+        prev.numPages === next.numPages &&
+        prev.pageWidth === next.pageWidth &&
+        prev.scale === next.scale
+);
+
+const ReviseDrawer: React.FC<ReviseDrawerProps> = (props: ReviseDrawerProps) => {
+    const { openDrawer, onClose, title, record } = props;
+    const [placement, setPlacement] = useState<DrawerProps['placement']>('right');
+
+    const onGetSliceListByDocumentId = async (documentId: string) => {
+        try {
+            const res: any = await apis.getSliceListByDocumentId(documentId);
+            if (res && res.data && Array.isArray(res.data)) {
+                const results = res.data;
+                results.forEach((item: any) => {
+                    item.sliceText = customRender(item.sliceText, item.mediaList)
+                })
+                setRightSlices(results);
+            } else {
+                return [];
+            }
+        } catch (err) {
+            return [];
+        }
+    };
+
+    useEffect(() => {
+        if (openDrawer) {
+            console.log('预览切片record', record);
+            onGetSliceListByDocumentId(record.documentId);
+        }
+    }, [openDrawer]);
+
+    const [leftSearch, setLeftSearch] = useState('');// 左边搜索
+    const [rightSearch, setRightSearch] = useState(''); // 右边搜索
+    const [leftSpliceSearch, setLeftSpliceSearch] = useState('');// 左边切片搜索
+    const [rightSpliceSearch, setRightSpliceSearch] = useState('');// 右边切片搜索
+    const [revisionOptions, setRevisionOptions] = useState<any[]>([]);
+    const [revisionLoading, setRevisionLoading] = useState(false);
+    const [selectedRevision, setSelectedRevision] = useState<string | undefined>(undefined);
+    const [leftDocumentId, setLeftDocumentId] = useState(''); // 左边选中的文档ID
+    const [rightDocumentId, setRightDocumentId] = useState(''); // 右边选中的文档ID
+    const [leftOptions, setLeftOptions] = useState<any[]>([]);// 左边数据
+    const [rightOptions, setRightOptions] = useState<any[]>([]);// 右边数据
+    const [leftLoading, setLeftLoading] = useState(false);// 左边加载状态
+    const [rightLoading, setRightLoading] = useState(false);// 右边加载状态
+    const [selectedStandard, setSelectedStandard] = useState<string | null>(null);
+    const [leftSlices, setLeftSlices] = useState<string[]>([]);// 左边切片列表
+    const [rightSlices, setRightSlices] = useState<string[]>([]);// 右边切片列表
+    const [leftSlicesLoading, setLeftSlicesLoading] = useState(false);// 左边切片加载状态
+    const [rightSlicesLoading, setRightSlicesLoading] = useState(false);// 右边切片加载状态
+    const [pdfBlobUrl, setPdfBlobUrl] = useState<string | null>(null);
+    const [pdfLoading, setPdfLoading] = useState(false);
+    const [largeFile, setLargeFile] = useState(false);
+    const [pageNumber, setPageNumber] = useState<number>(1);
+    const [scale, setScale] = useState<number>(1.0);
+    const containerRef = useRef<HTMLDivElement | null>(null);
+    const [pageWidth, setPageWidth] = useState<number>(600);
+    const marked = new MarkdownIt({ html: true, typographer: true });
+    useEffect(() => {
+        if (leftDocumentId) {
+            onFetchReviseToolSliceList(leftDocumentId, 'left');
+        }
+    }, [leftDocumentId]);
+    useEffect(() => {
+        if (rightDocumentId) {
+            onFetchReviseToolSliceList(rightDocumentId, 'right');
+        }
+    }, [rightDocumentId]);
+    const onChange = (e: RadioChangeEvent) => {
+        setPlacement(e.target.value);
+    };
+
+    const onFetchTakaiAppTypeListApi = async () => {
+        setRevisionLoading(true);
+        try {
+            const res: any = await apis.fetchTakaiAppTypeList('revision_status');
+            if (res && res.data && Array.isArray(res.data)) {
+                const opts = res.data.map((it: any) => ({ label: it.dictLabel, value: it.dictValue }));
+                setSelectedRevision(opts[0].value);
+                setRevisionOptions(opts);
+            } else {
+                setRevisionOptions([]);
+            }
+        } catch (err) {
+            setRevisionOptions([]);
+        } finally {
+            setRevisionLoading(false);
+        }
+    };
+    useEffect(() => {
+        onFetchTakaiAppTypeListApi();
+    }, []);
+    const customRender = (text: string, mdImgUrlList: any[]) => {
+        // 比如:把 "我是图片" 替换成一张图片
+        mdImgUrlList?.forEach(item => {
+            text = text.replace(new RegExp(item.originText, 'g'), `<img src="${item.mediaUrl}" alt="${item.originText}" />`);
+        })
+        return text;
+    }
+    // 获取知识库修订工具切片列表
+    const onFetchReviseToolSliceList = async (documentId: string, side?: 'left' | 'right', sliceText?: string) => {
+        setLeftSlicesLoading(side === 'left' ? true : leftSlicesLoading);
+        setRightSlicesLoading(side === 'right' ? true : rightSlicesLoading);
+        // Implement the function to fetch revise tool slice list
+        const res: any = await fetchReviseToolSliceList({ documentId: documentId || '', sliceText: sliceText || '' });
+        // 假设接口返回结构为 { code: 200, data: [ { sliceContent }, ... ] }
+        if (res && res.data && Array.isArray(res.data)) {
+            const results = res.data;
+            results.forEach((item: any) => {
+                item.sliceText = customRender(item.sliceText, item.mediaList)
+            })
+            if (side === 'left') {
+                setLeftSlicesLoading(false);
+                setLeftSlices(results);
+            }
+            else if (side === 'right') {
+                setRightSlicesLoading(false);
+                setRightSlices(results);
+
+            }
+        } else {
+            if (side === 'left')
+                setLeftSlices([]);
+            else if (side === 'right')
+                setRightSlices([]);
+        }
+    }
+    const [LeftActiveId, setLeftActiveId] = useState<string | null>(null);
+    const [RightActiveId, setRightActiveId] = useState<string | null>(null);
+    const [subLoading, setSubLoading] = useState(false);
+    const onAllClose = () => {
+        setLeftActiveId(null);
+        setRightActiveId(null);
+        setLeftSearch('');
+        setRightSearch('');
+        setLeftSpliceSearch('');
+        setRightSpliceSearch('');
+        setLeftDocumentId('');
+        setRightDocumentId('');
+        setLeftOptions([]);
+        setRightOptions([]);
+        setLeftSlices([]);
+        setRightSlices([]);
+        onClose();
+    }
+    const [numPages, setNumPages] = useState<number>(0);
+    function onLoadSuccess({ numPages }: { numPages: number }) {
+        setNumPages(numPages);
+        setPageNumber(1);
+    }
+
+
+
+    // 测量容器宽度以计算 Page 渲染宽度
+    useLayoutEffect(() => {
+        const update = () => {
+            const el = containerRef.current;
+            if (el) {
+                const w = el.clientWidth - 20; // 留白
+                setPageWidth(Math.max(200, w));
+            }
+        };
+        update();
+        window.addEventListener('resize', update);
+        return () => window.removeEventListener('resize', update);
+    }, []);
+
+    // Fetch PDF as blob to avoid browser auto-download from Content-Disposition
+    useEffect(() => {
+        let cancelled = false;
+        let currentBlobUrl: string | null = null;
+        const fetchBlob = async () => {
+            if (!record?.pdfUrl) {
+                setPdfBlobUrl(null);
+                return;
+            }
+            try {
+                // 尝试先用 HEAD 获取文件大小,若大文件则跳过下载 blob,改用原始 URL 由 pdf.js 处理流式加载
+                const headResp = await fetch(record.pdfUrl, { method: 'HEAD', mode: 'cors' });
+                if (headResp && headResp.ok) {
+                    const len = headResp.headers.get('Content-Length');
+                    if (len) {
+                        const size = parseInt(len, 10);
+                        const threshold = 10 * 1024 * 1024; // 10MB
+                        if (!Number.isNaN(size) && size > threshold) {
+                            setLargeFile(true);
+                            // 不下载 blob,直接让 Document 使用原始 URL(支持 range 请求的服务器会更快)
+                            setPdfBlobUrl(null);
+                            return;
+                        }
+                    }
+                }
+
+                setPdfLoading(true);
+                const res = await fetch(record.pdfUrl, { method: 'GET', mode: 'cors' });
+                if (!res.ok) throw new Error('fetch failed');
+                const blob = await res.blob();
+                currentBlobUrl = URL.createObjectURL(blob);
+                if (!cancelled) {
+                    setPdfBlobUrl(prev => {
+                        if (prev) URL.revokeObjectURL(prev);
+                        return currentBlobUrl;
+                    });
+                } else {
+                    if (currentBlobUrl) URL.revokeObjectURL(currentBlobUrl);
+                }
+            } catch (err) {
+                console.error('fetch pdf blob error', err);
+                setPdfBlobUrl(null);
+            } finally {
+                if (!cancelled) setPdfLoading(false);
+            }
+        };
+        fetchBlob();
+        return () => {
+            cancelled = true;
+            if (currentBlobUrl) URL.revokeObjectURL(currentBlobUrl);
+        };
+    }, [record?.pdfUrl]);
+    return (
+        <Drawer
+            title={title}
+            placement={placement}
+            closable={true}
+            onClose={onAllClose}
+            open={openDrawer}
+            width={'90%'}
+        >
+            <div className="flex gap-4 h-full">
+                {/* Left column */}
+                <div className="w-1/2 border-r pr-4">
+                    <Spin spinning={leftSlicesLoading || pdfLoading} className="h-full">
+                        <div className="flex flex-col h-full">
+                            <div className="mb-2 flex items-center justify-end">
+                                <div className="flex items-center gap-2">
+                                    <Button size="small" onClick={() => setScale(s => Math.max(0.5, s - 0.1))}>-</Button>
+                                    <span className="text-sm">{Math.round(scale * 100)}%</span>
+                                    <Button size="small" onClick={() => setScale(s => Math.min(2, s + 0.1))}>+</Button>
+                                    <Button size="small" onClick={() => { if (record?.pdfUrl) window.open(record.pdfUrl, '_blank'); }}>在新窗口打开</Button>
+                                </div>
+                            </div>
+                            <div
+                                ref={containerRef}
+                                className="overflow-y-auto"
+                                style={{ maxHeight: 'calc(100vh - 130px)' }}
+                            >
+                                {pdfLoading ? (
+                                    <div className="text-center py-8">PDF 加载中...</div>
+                                ) : record?.pdfUrl ? (
+                                    (pdfBlobUrl || record.pdfUrl) ? (
+                                        <PdfViewer
+                                            file={pdfBlobUrl || record.pdfUrl}
+                                            numPages={numPages}
+                                            pageWidth={pageWidth}
+                                            scale={scale}
+                                            onLoadSuccess={onLoadSuccess}
+                                            containerRef={containerRef}
+                                        />
+                                    ) : (
+                                        <div className="text-center py-8">
+                                            无法生成预览,
+                                            <Button
+                                                type="link"
+                                                onClick={() => {
+                                                    if (record?.pdfUrl) window.open(record.pdfUrl, '_blank');
+                                                }}
+                                            >
+                                                在新窗口打开
+                                            </Button>
+                                        </div>
+                                    )
+                                ) : (
+                                    <div className="text-center text-gray-500 mt-10">未找到 PDF</div>
+                                )}
+                            </div>
+
+                        </div>
+                    </Spin>
+                </div>
+
+                {/* Right column (same as left) */}
+                <div className="w-1/2">
+                    <Spin spinning={rightSlicesLoading} className='h-full'>
+                        {rightSlices.length > 0 ? <div className="overflow-y-auto" style={{ maxHeight: 'calc(100vh - 130px)' }}>
+                            {rightSlices.map((module: any, index) => (
+                                <div
+                                    key={`r-${index}`}
+                                    className={`relative px-3 py-2 text-sm leading-7 transition-all duration-200 cursor-pointer 
+                                        ${index !== rightSlices.length - 1 ? 'border-b border-gray-100' : ''
+                                        }`}
+                                    onClick={() => setRightActiveId(module.sliceId)}
+                                >
+                                    {module.sliceText && (() => {
+                                        const html = marked.render(module.sliceText || '');
+                                        const parts: any[] = [];
+                                        const imgRegex = /<img[^>]*src=["']([^"']+)["'][^>]*>/g;
+                                        let lastIndex = 0;
+                                        let match: RegExpExecArray | null;
+                                        while ((match = imgRegex.exec(html)) !== null) {
+                                            const idx = match.index;
+                                            const textSeg = html.substring(lastIndex, idx);
+                                            if (textSeg) parts.push(<div key={`rt-${index}-${lastIndex}`} dangerouslySetInnerHTML={{ __html: textSeg }} />);
+                                            const url = match[1];
+                                            parts.push(<Image key={`rimg-${index}-${idx}`} src={url} preview={{}} style={{ maxWidth: '100%' }} />);
+                                            lastIndex = idx + match[0].length;
+                                        }
+                                        const rest = html.substring(lastIndex);
+                                        if (rest) parts.push(<div key={`rt-last-${index}`} dangerouslySetInnerHTML={{ __html: rest }} />);
+                                        return <div className="text-sm leading-7 text-gray-800 markdown-preview">{parts}</div>;
+                                    })()}
+                                </div>
+                            ))}
+                        </div> : <div className="text-center text-gray-500 mt-10">暂无数据</div>}
+                    </Spin>
+
+                </div>
+            </div>
+        </Drawer>
+
+    )
+}
+export default observer(ReviseDrawer);

+ 29 - 0
src/pages/deepseek/knowledgeLib/detail/components/store.ts

@@ -0,0 +1,29 @@
+import { action, makeAutoObservable } from 'mobx';
+
+const stateGenerator = () => ({
+    starts: 1
+})
+
+const stateActionsGenerator = (state: any) => {
+    return {
+        setStarts(starts: number) {
+            state.starts = starts+1
+        }
+    }
+}
+
+const useKnowledgeLibInfoStore = () => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    const onSetStarts = (a:any)=>{
+        actions.setStarts(a)
+    }
+
+    return {
+        state,
+        onSetStarts
+    }
+}
+
+export default useKnowledgeLibInfoStore();

+ 40 - 0
src/pages/deepseek/knowledgeLib/detail/components/style.less

@@ -0,0 +1,40 @@
+/* 覆盖 markdown 渲染出来的样式 */
+ .ant-typography h1 {
+  font-size: 20px;   /* 调整大小 */
+  color: #333;       /* 字体颜色 */
+//   border-bottom: 2px solid #eee; /* 底部加一条分隔线 */
+    margin: 2px 0;
+}
+
+.ant-typography h2 {
+  font-size: 18px;
+  color: #333;
+  margin: 2px 0;
+//   border-left: 4px solid #4caf50; /* 左边加一条绿色竖线 */
+}
+.ant-typography h3 {
+  font-size: 16px;
+  color: #333;
+   margin: 2px 0;
+//   border-left: 4px solid #4caf50; /* 左边加一条绿色竖线 */
+}
+.ant-typography h4 {
+  font-size: 14px;
+  color: #333;
+   margin: 2px 0;
+//   border-left: 4px solid #4caf50; /* 左边加一条绿色竖线 */
+}
+.ant-typography h5,h6 {
+  font-size: 12px;
+  color: #333;
+   margin: 2px 0;
+//   border-left: 4px solid #4caf50; /* 左边加一条绿色竖线 */
+}
+.ant-spin-container {
+  width: 100%;
+}
+.md_center{
+  .ant-tabs-tab{
+    padding: 0 0 !important;
+  }
+}

+ 364 - 0
src/pages/deepseek/knowledgeLib/detail/drawerIndex.tsx

@@ -0,0 +1,364 @@
+import * as React from 'react';
+import { generatePath, useParams, useLocation } from 'react-router-dom';
+import { observer } from 'mobx-react';
+
+import config, { getHeaders } from '@/apis/config';
+
+import {
+  Button,
+  Table,
+  TableColumnsType,
+  Modal,
+  TablePaginationConfig,
+  Upload,
+  UploadProps,
+  message,
+  Spin
+} from 'antd';
+import { EditOutlined, DeleteOutlined, InboxOutlined, PlusOutlined, ArrowLeftOutlined } from '@ant-design/icons';
+import InfoModal from './components/InfoModal';
+import InfoModalSetting from './components/InfoModalSetting';
+import router from '@/router';
+import { Record } from './types';
+import dayjs from 'dayjs';
+import axios from 'axios';
+import LocalStorage from '@/LocalStorage';
+import store from './store';
+import './style.less';
+
+const { Dragger } = Upload;
+interface Props{
+    drawerItem: any;
+}
+
+const KnowledgeLibInfo : React.FC<Props> = ({drawerItem}:Props) => {
+  const params = {
+    knowledgeId: drawerItem.value,
+    ...drawerItem,
+  }
+
+  const {
+    state,
+    init,
+    onClickModify,
+    onClickDelete,
+    onChangePagination,
+    onClickDocumentDetail,
+    infoModalOnClickConfirm,
+    infoModalOnClickCancel,
+    infoModalSettingOnClickConfirm,
+    infoModalSettingOnClickCancel,
+    onClickSettings,
+    reset
+  } = store;
+  const {
+    knowledge_id,
+    listLoading,
+    page,
+    list,
+    infoModalOpen,
+    infoModalId,
+    infoModalSettingOpen,
+    infoModalSettingId,
+    knowledgeDetail,
+  } = state;
+  const location = useLocation();
+  const [ uploadLoading, setUploadLoading ] = React.useState( false );
+
+
+  const [ fileList, setFileList ] = React.useState<any[]>( [] );
+  const [ uploading, setUploading ] = React.useState( false );
+
+  const [ sListFlag, setSListFlag ] = React.useState<boolean>();
+  const [ cUpdateFlag, setCUpdateFlag ] = React.useState<boolean>();
+  const [ detailFlag, setDetailFlag ] = React.useState<boolean>();
+  const [ deleteFlag, setDeleteFlag ] = React.useState<boolean>();
+  const [ createFlag, setCreateFlag ] = React.useState<boolean>();
+  const [userInfoAll, setUserInfoAll] = React.useState<any>({});
+
+  const props : UploadProps = {
+    name: 'files',
+    multiple: true,
+    action: '/api/deepseek/api/uploadDocument/' + params.knowledgeId,
+    headers: getHeaders(),
+    beforeUpload( file, fileList ) {
+      setUploadLoading( true );
+      // const allowedExtensions = ['md', 'txt', 'pdf', 'jpg', 'png', 'jpeg', 'docx', 'xlsx', 'pptx', 'eml', 'csv', 'tar', 'gz', 'bz2', 'zip', 'rar', 'jar'];
+
+      const allowedExtensions = [ 'txt', 'pdf', 'jpg', 'png', 'jpeg', 'doc', 'docx', 'ppt', 'pptx' ];
+
+      // 检查文件类型
+      for ( const file of fileList ) {
+        const fileExt = file.name.split( '.' ).pop()?.toLowerCase();
+        if ( !fileExt || !allowedExtensions.includes( fileExt ) ) {
+          message.error( `不支持 ${ fileExt } 格式的文件上传` );
+          setUploadLoading( false );
+          return Upload.LIST_IGNORE;
+        }
+      }
+
+      // 检查文件大小
+      let totalSize = 0;
+      for ( const file of fileList ) {
+        const fileExt = file.name.split( '.' ).pop()?.toLowerCase();
+        const fileSizeMB = file.size / 1024 / 1024;
+
+        if ( fileSizeMB > 30 ) {
+          message.error( '单个文件不能大于30M' );
+          setUploadLoading( false );
+          return Upload.LIST_IGNORE;
+        }
+
+        if ( [ 'jpg', 'png', 'jpeg' ].includes( fileExt! ) && fileSizeMB > 5 ) {
+          message.error( '单张图片不能大于5M' );
+          setUploadLoading( false );
+          return Upload.LIST_IGNORE;
+        }
+
+        totalSize += fileSizeMB;
+      }
+
+      if ( totalSize > 125 ) {
+        message.error( '文件总大小超过125M' );
+        setUploadLoading( false );
+        return Upload.LIST_IGNORE;
+      }
+
+    },
+    onChange( info ) {
+      const { status } = info.file;
+
+      if ( status !== 'uploading' ) {
+        console.log( status, 'status--uploading' );
+      }
+      if ( status === 'done' ) {
+        console.log( status, 'status--done' );
+        console.info( info.file.response, 'info.file.response.data' );
+        if ( info.file.response.code === 200 && info.file.response.data === 1 ) {
+          message.success( `${ info.file.name } file uploaded successfully.` );
+          init( params.knowledgeId );
+        }
+        setUploadLoading( false );
+      } else if ( status === 'error' ) {
+        console.log( status, 'status--error' );
+        message.error( `${ info.file.name } file upload failed.` );
+        setUploadLoading( false );
+      }
+    },
+    onDrop( e ) {
+      console.log( 'Dropped files', e.dataTransfer.files );
+    },
+  };
+
+  const handleUpload = async () => {
+    if ( fileList.length === 0 ) return;
+
+    setUploading( true );
+    const formData = new FormData();
+
+    // 添加所有文件
+    fileList.forEach( file => {
+      if ( file.originFileObj ) {
+        formData.append( 'files', file.originFileObj );
+      }
+    } );
+
+    try {
+      const res = await axios.post( '/api/deepseek/api/uploadDocument/' + params.knowledgeId, formData, {
+        headers: { 'Content-Type': 'multipart/form-data' }
+      } );
+
+      message.success( `${ fileList.length }个文件上传成功` );
+      setFileList( [] );
+    } catch ( err ) {
+      message.error( '上传失败' );
+    } finally {
+      setUploading( false );
+    }
+  };
+
+  React.useEffect( () => {
+    init( params.knowledgeId );
+    const cList = LocalStorage.getStatusFlag( 'deepseek:slice:list' );
+    setSListFlag( cList );
+    const cDetail = LocalStorage.getStatusFlag( 'deepseek:config:update' );
+    setCUpdateFlag( cDetail );
+    const detail = LocalStorage.getStatusFlag( 'deepseek:document:detail' );
+    setDetailFlag( detail );
+    const deleteF = LocalStorage.getStatusFlag( 'deepseek:document:delete' );
+    setDeleteFlag( deleteF );
+    const createF = LocalStorage.getStatusFlag( 'deepseek:document:create' );
+    setCreateFlag( createF );
+    setUserInfoAll(LocalStorage.getUserInfo());
+    return () => reset();
+  }, [params.knowledgeId] );
+
+  const columns : TableColumnsType<Record> = [
+    {
+      title: '序号',
+      dataIndex: 'index',
+      width: 80,
+      render: ( text, record, index ) => {
+        return index + 1;
+      }
+    },
+    {
+      title: '文件名',
+      dataIndex: 'name',
+      width: 300,
+      sorter: (a, b) => a.name.localeCompare(b.name),
+      render: ( text, record ) => {
+        return (
+            `${ text }`
+        )
+      }
+    },
+    {
+      title: '文件大小',
+      dataIndex: 'length',
+      width: 100,
+      render: ( text ) => {
+        if ( text ) {
+          const size = ( text / 1024 / 1024 ).toFixed( 2 );
+          return `${ size } M`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '字符数量',
+      dataIndex: 'wordNum',
+      width: 100,
+      render: ( text ) => {
+        if ( text ) {
+          return `${ text }`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '分段',
+      dataIndex: 'sliceTotal',
+      width: 100,
+      render: ( text ) => {
+        if ( text ) {
+          return `${ text }`;
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '上传时间',
+      dataIndex: 'createTime',
+      width: 180,
+      render: ( text ) => {
+        if ( text ) {
+          return dayjs( text ).format( 'YYYY-MM-DD HH:mm:ss' );
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '更新时间',
+      dataIndex: 'updateTime',
+      width: 180,
+      render: ( text ) => {
+        if ( text ) {
+          return dayjs( text ).format( 'YYYY-MM-DD HH:mm:ss' );
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '操作',
+      dataIndex: 'operation',
+      width: 80,
+      fixed: 'right',
+      render: ( text, record:any ) => {
+        return (
+            <>
+              {
+                  <a
+                      style={ { marginRight: 16 } }
+                      onClick={ () => {
+                        // window.location= record.url
+                        window.open(`${record.url}`, '_blank');
+                        // window.open(`https://10.1.28.14:9000/deepseek-doc/%E6%95%B0%E5%AD%97%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0%E7%94%A8%E6%88%B7%E6%93%8D%E4%BD%9C%E6%89%8B%E5%86%8C_%E9%83%A8%E5%88%863.pdf`, '_blank');
+                      } }
+                  >
+                    查看
+                  </a>
+              }
+            </>
+        )
+      }
+    }
+  ];
+
+  const paginationConfig : TablePaginationConfig = {
+    // 显示数据总量
+    showTotal: ( total : number ) => {
+      return `共 ${ total } 条`;
+    },
+    // 展示分页条数切换
+    showSizeChanger: true,
+    // 指定每页显示条数
+    pageSizeOptions: [ '10', '20', '50', '100' ],
+    // 快速跳转至某页
+    showQuickJumper: true,
+    current: page.page,
+    pageSize: page.size,
+    total: page.total,
+    onChange: async ( page, pageSize ) => {
+      await onChangePagination( page, pageSize );
+    },
+  };
+
+  return (
+      <div className='knowledgeLibInfo'>
+        <Spin spinning={ uploadLoading || listLoading }>
+          {
+              <>
+                <div className='knowledgeLibInfo-table'>
+                  <Table
+                      scroll={ { x: 'max-content' } }
+                      rowKey={ ( record ) => record.documentId }
+                      loading={ listLoading }
+                      columns={ columns }
+                      dataSource={ list }
+                      pagination={ paginationConfig }
+                  />
+                </div>
+
+                {
+                    infoModalOpen &&
+                    <InfoModal
+                        id={ infoModalId }
+                        open={ infoModalOpen }
+                        onClickConfirm={ infoModalOnClickConfirm }
+                        onClickCancel={ infoModalOnClickCancel }
+                    />
+                }
+
+                {
+                    infoModalSettingOpen &&
+                    <InfoModalSetting
+                        id={ infoModalSettingId }
+                        open={ infoModalSettingOpen }
+                        onClickConfirm={ infoModalSettingOnClickConfirm }
+                        onClickCancel={ infoModalSettingOnClickCancel }
+                    />
+                }
+              </>
+          }
+        </Spin>
+      </div>
+  );
+};
+
+export default observer( KnowledgeLibInfo );

+ 680 - 0
src/pages/deepseek/knowledgeLib/detail/index.tsx

@@ -0,0 +1,680 @@
+import * as React from 'react';
+import { generatePath, useParams, useLocation, useNavigate } from 'react-router-dom';
+import { observer } from 'mobx-react';
+import PrevewSlice from './components/prevewSlice';
+
+import config, { getHeaders } from '@/apis/config';
+
+import {
+  Button,
+  Table,
+  TableColumnsType,
+  Modal,
+  TablePaginationConfig,
+  Upload,
+  UploadProps,
+  message,
+  Tooltip,
+  Spin,
+  Input,
+  Space
+} from 'antd';
+import type { TableProps } from 'antd';
+
+import { EditOutlined, DeleteOutlined, InboxOutlined, PlusOutlined, ArrowLeftOutlined, EyeOutlined, ExportOutlined, FileTextOutlined, ArrowDownOutlined, SearchOutlined } from '@ant-design/icons';
+import InfoModal from './components/InfoModal';
+import InfoModalSetting from './components/InfoModalSetting';
+import UploadModal from './components/UploadModal';
+import MdModal from './components/MdModal'
+import QuoteModal from './components/QuoteModal'
+import router from '@/router';
+import { Record } from './types';
+import dayjs from 'dayjs';
+import axios from 'axios';
+import LocalStorage from '@/LocalStorage';
+import store from './store';
+import './style.less';
+import { apis } from '@/apis';
+import layoutStore from '@/pages/layout/store';
+const { Dragger } = Upload;
+
+const KnowledgeLibInfo: React.FC = () => {
+  const navigate = useNavigate()
+  const {
+    handleNameChange,
+    state,
+    init,
+    onClickModify,
+    onClickDelete,
+    onChangePagination,
+    onClickDocumentDetail,
+    infoModalOnClickConfirm,
+    infoModalOnClickCancel,
+    infoModalSettingOnClickConfirm,
+    infoModalSettingOnClickCancel,
+    onClickSettings,
+    reset,
+    onDeleteTakaiDocumentLibApi,
+    onExportDocumentSliceExport
+  } = store;
+  const { onSetRoouterName } = layoutStore
+  const {
+    knowledge_id,
+    listLoading,
+    page,
+    list,
+    processingList, // 处理中的状态
+    infoModalOpen,
+    infoModalId,
+    infoModalSettingOpen,
+    infoModalSettingId,
+    knowledgeDetail,
+  } = state;
+  const location = useLocation();
+  const [uploadLoading, setUploadLoading] = React.useState(false);
+
+  const params = useParams();
+
+  const [mdModalOpen, setMdModalOpen] = React.useState(false); // 切片弹窗
+  const [quoteModalOpen, setQuoteModalOpen] = React.useState(false); // 引用知识库弹窗
+  const [detailDocument, setDetailDocument] = React.useState<any>({}); // 切片详情
+  const [userInfoAll, setUserInfoAll] = React.useState<any>({});
+  const [uploadModalOpen, setUploadModalOpen] = React.useState<boolean>(false);
+  const [record, setRecord] = React.useState<any>({});
+  const [deletingIds, setDeletingIds] = React.useState<string[]>([]);
+  const [standardClass, setStandardClass] = React.useState<any[]>([]);// 分类-下拉选项
+  const [parsingTypeList, setParsingTypeList] = React.useState<any[]>([]);// 解析工具-下拉选项
+  const [splittingType, setSplittingType] = React.useState<any>([]); // 选择切分规则 
+  // 获取选择分类
+  const fetchAppstandardClass = async () => {
+    try {
+      const res = await apis.fetchTakaiAppTypeList('standard_classification');
+      const list = res.data.map((item: any) => {
+        return {
+          label: item.dictLabel,
+          value: item.dictValue,
+        }
+      });
+      setStandardClass(list);
+    } catch (error: any) {
+      console.error(error);
+    }
+  }
+  // 获取解析工具
+  const fetchParsingTypeList = async () => {
+    try {
+      const res = await apis.fetchTakaiAppTypeList('parsing_type');
+      const list = res.data.map((item: any) => {
+        return {
+          label: item.dictLabel,
+          value: item.dictValue,
+        }
+      });
+      setParsingTypeList(list);
+    } catch (error: any) {
+      console.error(error);
+    }
+  }
+  // 获取向默认切分规则
+  const fetchsplittingType = async () => {
+    try {
+      const res = await apis.fetchTakaiAppTypeList('splitting_type');
+      const list = res.data.map((item: any) => {
+        return {
+          label: item.dictLabel,
+          value: item.dictValue,
+        }
+      });
+      setSplittingType(list);
+    } catch (error: any) {
+      console.error(error);
+    }
+  }
+  const [cUpdateFlag, setCUpdateFlag] = React.useState<boolean>();
+  const [deleteFlag, setDeleteFlag] = React.useState<boolean>(); // 删除权限
+  const [createFlag, setCreateFlag] = React.useState<boolean>();
+  const [updateDoc, setupdateDoc] = React.useState<boolean>(false); // 上传知识文件权限
+  const [quoteDoc, setQuoteDoc] = React.useState<boolean>(false); // 引用知识文件权限
+  const [exportSlice, setExportSlice] = React.useState<boolean>(false); // 导出切片权限
+  const [exportMd, setExportMd] = React.useState<boolean>(false); // 导出Md权限
+  const [exportOr, setExportOr] = React.useState<boolean>(false); // 导出原文件权限
+  const [slicPre, setSlicePre] = React.useState<boolean>(false); // 查看切片
+  const [configuration, setConfiguration] = React.useState<boolean>(false); // 配置权限
+  const [editName, setEditName] = React.useState<boolean>(false); // 编辑名称
+  React.useEffect(() => {
+    fetchAppstandardClass();
+    fetchParsingTypeList();
+    fetchsplittingType();
+    init(params.knowledgeId);
+    setupdateDoc(LocalStorage.getStatusFlag('knowledgeLib:detail:update'));
+    setQuoteDoc(LocalStorage.getStatusFlag('knowledgeLib:detail:quote'));
+    setExportSlice(LocalStorage.getStatusFlag('knowledgeLib:detail:exportSlice'));
+    setExportMd(LocalStorage.getStatusFlag('knowledgeLib:detail:exportMd'));
+    setExportOr(LocalStorage.getStatusFlag('knowledgeLib:detail:exportOr'));
+    setSlicePre(LocalStorage.getStatusFlag('knowledgeLib:detail:slice'));
+    setConfiguration(LocalStorage.getStatusFlag('knowledgeLib:detail:configuration'));
+    setEditName(LocalStorage.getStatusFlag('knowledgeLib:detail:editName'));
+
+
+    const cDetail = LocalStorage.getStatusFlag('deepseek:config:update');
+    setCUpdateFlag(cDetail);
+    const deleteF = LocalStorage.getStatusFlag('knowledgeLib:detail:del');
+    setDeleteFlag(deleteF);
+    const createF = LocalStorage.getStatusFlag('deepseek:document:create');
+    setCreateFlag(createF);
+    setUserInfoAll(LocalStorage.getUserInfo());
+    return () => reset();
+  }, []);
+
+  React.useEffect(() => {
+    // console.log('knowledgeDetail',knowledgeDetail)
+    if (knowledgeDetail.name) {
+      onSetRoouterName(knowledgeDetail.name)
+    }
+  }, [knowledgeDetail])
+
+  const [documentids, setdocumentids] = React.useState<string[]>([]);
+  const rowSelection: TableProps<Record>['rowSelection'] = {
+    onChange: (selectedRowKeys: React.Key[], selectedRows: Record[]) => {
+      const flagids = selectedRows.map((item) => {
+        return item.documentId
+      })
+      setdocumentids(flagids)
+    },
+  };
+
+    const [openDrawer, setOpenDrawer] = React.useState<boolean>(false);
+
+
+  const columns: TableColumnsType<Record> = [
+    {
+      title: '序号',
+      dataIndex: 'index',
+      width: 80,
+      render: (text, record, index) => {
+        return index + 1;
+      }
+    },
+    {
+      title: '文件名',
+      dataIndex: 'name',
+      width: 300,
+      sorter: (a, b) => a.name.localeCompare(b.name),
+      render: (text, record) => {
+        return (
+          `${text}`
+        )
+      }
+    },
+    {
+      title: '文件类型',
+      dataIndex: 'suffix',
+      width: 100,
+      render: (text, record) => {
+        return (
+          `${text}`
+        )
+      }
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: 180,
+      render: (text) => {
+        if (text === '4') {
+          return <Spin size="small" />;
+        } else if (text === '5' || text === '1') {
+          return '已完成';
+        } else if (text === '6' || text === '2') {
+          return '处理失败';
+        }
+      }
+    },
+    {
+      title: '文件大小',
+      dataIndex: 'length',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          const size = (text / 1024 / 1024).toFixed(2);
+          return `${size} M`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '分类',
+      dataIndex: 'standardClassification',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          standardClass.forEach((item: any) => {
+            if (item.value === text) {
+              text = item.label
+            }
+          });
+          return `${text}`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '解析工具',
+      dataIndex: 'parsingType',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          parsingTypeList.forEach((item: any) => {
+            if (item.value === text) {
+              text = item.label
+            }
+          });
+          return `${text}`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '切分规则',
+      dataIndex: 'customSeparator',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          splittingType.forEach((item: any) => {
+            if (item.value === text) {
+              text = item.label
+            }
+          });
+          return `${text}`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '字符数量',
+      dataIndex: 'wordNum',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          return `${text}`;
+        } else {
+          return '--'
+        }
+      }
+    },
+    {
+      title: '切片数量',
+      dataIndex: 'sliceTotal',
+      width: 100,
+      render: (text) => {
+        if (text) {
+          return `${text}`;
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '上传时间',
+      dataIndex: 'createTime',
+      width: 180,
+      render: (text) => {
+        if (text) {
+          return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '更新时间',
+      dataIndex: 'updateTime',
+      width: 180,
+      render: (text) => {
+        if (text) {
+          return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+        } else {
+          return '--';
+        }
+      }
+    },
+    {
+      title: '操作',
+      dataIndex: 'operation',
+      width: 180,
+      fixed: 'right',
+      render: (text, record: any) => {
+        const isProcessing = record.status === '4';
+        return (
+          <>
+            {
+              <a
+                style={{
+                  marginRight: 16,
+                  color: isProcessing ? '#d9d9d9' : undefined,
+                  cursor: isProcessing ? 'not-allowed' : 'pointer'
+                }}
+                onClick={() => {
+                  setOpenDrawer(true);
+                  setDetailDocument(record);
+                }}
+              >
+                查看
+              </a>
+            }
+            {
+              (record.standardClassification !== '3' && (slicPre || userInfoAll.id === record.createBy)) && <a
+                style={{
+                  marginRight: 16,
+                  color: isProcessing ? '#d9d9d9' : undefined,
+                  cursor: isProcessing ? 'not-allowed' : 'pointer'
+                }}
+                onClick={() => {
+                  if (isProcessing) return;
+                  // const path = generatePath('/knowledge/knowledgeLib/:knowledgeId/:createBy/slice/:documentId/:embeddingId', {
+                  //   knowledgeId: params.knowledgeId as string,
+                  //   createBy: params.createBy as string,
+                  //   documentId: record.documentId,
+                  //   embeddingId: state.knowledgeDetail.embeddingId,
+                  // });
+                  // router.navigate({ pathname: path }, { state: { createBy: record.createBy } });
+                  setMdModalOpen(true);
+                  setDetailDocument(record);
+                }}
+              >
+                切片
+              </a>
+            }
+            {
+              (configuration || userInfoAll.id === record.createBy) && <a
+                style={{
+                  marginRight: 16,
+                  color: isProcessing ? '#d9d9d9' : undefined,
+                  cursor: isProcessing ? 'not-allowed' : 'pointer'
+                }}
+                onClick={() => {
+                  if (isProcessing) return;
+                  onClickSettings(record.documentId);
+                  setRecord(record)
+                }}
+              >
+                配置
+              </a>
+            }
+            {
+              (editName || userInfoAll.id === record.createBy) &&
+              <a
+                style={{
+                  marginRight: 16,
+                  color: isProcessing ? '#d9d9d9' : undefined,
+                  cursor: isProcessing ? 'not-allowed' : 'pointer'
+                }}
+                onClick={() => {
+                  if (isProcessing) return;
+                  onClickModify(record.documentId);
+                }}>
+                <EditOutlined />
+              </a>
+            }
+            {
+              (deleteFlag || userInfoAll.id === record.createBy) &&
+              <Button
+                type="link"
+                danger
+                className='p-0 mr-0'
+                onClick={() => {
+                  if (isProcessing) return;
+                  Modal.confirm({
+                    title: '删除',
+                    content: `确定删除知识文件:${record.name}吗?`,
+                    okType: 'danger',
+                    onOk: async () => {
+                      try {
+                        setDeletingIds((prev) => [...prev, record.documentId]);
+                        const userInfo = LocalStorage.getUserInfo();
+                        await onClickDelete(record.documentId);
+                      } finally {
+                        setDeletingIds((prev) => prev.filter((id) => id !== record.documentId));
+                      }
+                    }
+                  });
+                }}
+                loading={deletingIds.includes(record.documentId)}
+                disabled={isProcessing || deletingIds.includes(record.documentId)}
+                icon={<DeleteOutlined />}
+              />
+            }
+          </>
+        )
+      }
+    }
+  ];
+
+  const paginationConfig: TablePaginationConfig = {
+    // 显示数据总量
+    showTotal: (total: number) => {
+      return `共 ${total} 条`;
+    },
+    // 展示分页条数切换
+    showSizeChanger: true,
+    // 指定每页显示条数
+    pageSizeOptions: ['10', '20', '50', '100'],
+    // 快速跳转至某页
+    showQuickJumper: true,
+    current: page.page,
+    pageSize: page.size,
+    total: page.total,
+    onChange: async (page, pageSize) => {
+      await onChangePagination(page, pageSize);
+    },
+  };
+  const progressBar = () => {
+    return processingList.map((item: any, index: number) => {
+      return <div key={index} className='knowledgeLibInfo-progress'>
+        <div className="task-card bg-[#FAFAFA] rounded-xl py-2 px-5 card-shadow task-item fade-in" data-status="processing" data-name="市场调研报告需求.docx" data-date="2023-06-15 09:32" data-project-id="1" data-project-name="电商平台重构" data-project-color="#165DFF">
+          <div className="flex flex-wrap justify-between items-start mb-2">
+            <div>
+              <div className="flex items-center">
+                <p className="font-semibold text-[14px]" style={{ marginRight: 16 }}>{item?.name}</p>
+              </div>
+              <p className="text-[12px] text-gray-500">上传于:{item?.createTime}</p>
+            </div>
+            {item?.status === '0' && <span className="bg-blue-100 text-primary text-xs font-medium px-2.5 py-0.5 rounded-full flex items-center mt-1">
+              <i className="fa fa-spinner fa-spin mr-1"></i> 处理中
+            </span>}
+            {item?.status === '2' && <span className="bg-blue-100 text-primary text-xs font-medium px-2.5 py-0.5 rounded-full flex items-center mt-1">
+              处理失败
+            </span>}
+            {item?.status === '3' && <span className="bg-blue-100 text-primary text-xs font-medium px-2.5 py-0.5 rounded-full flex items-center mt-1">
+              待处理
+            </span>}
+            {item?.progress === 100 && <span className="bg-green-100 text-success text-xs font-medium px-2.5 py-0.5 rounded-full flex items-center mt-1">
+              <i className="fa fa-check mr-1"></i> 已完成
+            </span>}
+          </div>
+          <div className="mb-1">
+            <div className="flex justify-between text-[12px] mb-1">
+              <span>处理进度</span>
+              <span id="progressText-1">{item?.progress}%</span>
+            </div>
+            <div className="w-full bg-gray-200 rounded-full h-2.5">
+              <div className="progress-bar bg-blue-500 h-2.5 rounded-full" style={{ width: `${item?.progress}%` }} id="progressBar-1"></div>
+            </div>
+            <div className="flex justify-between text-[11px] mt-1">
+              <span className='text-error'>{item?.errorMessage}</span>
+              <p>
+                <EyeOutlined className='mr-2 cursor-pointer' onClick={() => {
+                  window.open(item?.url)
+                }} />
+
+                {(deleteFlag || userInfoAll.id === item.createBy) && <Button
+                  type="link"
+                  danger
+                  className='p-0'
+                  onClick={() => {
+                    Modal.confirm({
+                      title: '删除',
+                      content: `确定删除知识文件:${item.name}吗?`,
+                      okType: 'danger',
+                      onOk: async () => {
+                        try {
+                          setDeletingIds((prev) => [...prev, item.documentId]);
+                          await onDeleteTakaiDocumentLibApi(item.documentId)
+                        } finally {
+                          setDeletingIds((prev) => prev.filter((id) => id !== item.documentId));
+                        }
+                      }
+                    });
+                  }}
+                  loading={deletingIds.includes(item.documentId)}
+                  disabled={deletingIds.includes(item.documentId)}
+                  icon={<DeleteOutlined />}
+                />}
+              </p>
+            </div>
+          </div>
+        </div>
+      </div>
+    })
+  }
+  return (
+    <div className='knowledgeLibInfo'>
+      <Spin spinning={false}>
+        {
+          <>
+            <div className='knowledgeLibInfo-operation'>
+              <Button
+                type='primary'
+                icon={<ArrowLeftOutlined />} onClick={() => {
+                  navigate({ pathname: '/knowledge/knowledgeLib' });
+                }}>
+                返回
+              </Button>
+              {
+                // ((createFlag && userInfoAll.id === 1) || userInfoAll.id === params?.createBy) &&
+                <p>
+                  {updateDoc && <Button
+                    icon={<PlusOutlined />}
+                    onClick={() => setUploadModalOpen(true)}
+                  >
+                    上传知识文件
+                  </Button>}
+                  {quoteDoc && <Button
+                    type='primary'
+                    className='ml-3'
+                    onClick={() => setQuoteModalOpen(true)}
+                  >
+                    引用知识文件
+                  </Button>}</p>
+              }
+            </div>
+            {/* 进度条 */}
+            <div>
+              {progressBar()}
+            </div>
+            <div className='knowledgeLibInfo-operation' style={{ justifyContent: 'flex-end' }}>
+              <Space.Compact style={{ width: '300px' }} className='mr-3'>
+                <Input
+                  placeholder='请输入文件名称进行搜索'
+                  value={state.name}
+                  onChange={(e) => handleNameChange(e.target.value)}
+                />
+                <Button type="primary" onClick={() => { onClickDocumentDetail() }}><SearchOutlined /></Button>
+              </Space.Compact>
+              {
+                // ((userInfoAll.id === 1) || userInfoAll.id === params?.createBy) &&
+                <p>
+                  {exportSlice && <Tooltip title="导出切片">
+                    <Button
+                      icon={<ExportOutlined />}
+                      onClick={() =>
+                        onExportDocumentSliceExport(documentids, 1)
+                      }
+                    >
+                    </Button>
+                  </Tooltip>}
+                  {exportMd && <Tooltip title="导出MD文件">
+                    <Button
+                      className='ml-3'
+                      icon={<FileTextOutlined />}
+                      onClick={() =>
+                        onExportDocumentSliceExport(documentids, 2)
+                      }
+                    >
+                    </Button>
+                  </Tooltip>}
+                  {exportOr && <Tooltip title="导出原文件">
+                    <Button
+                      className='ml-3'
+                      icon={<ArrowDownOutlined />}
+                      onClick={() =>
+                        onExportDocumentSliceExport(documentids, 3)
+                      }
+                    >
+                    </Button>
+                  </Tooltip>}
+                </p>
+              }
+            </div>
+            <div className='knowledgeLibInfo-table'>
+              <Table
+                scroll={{ x: 'max-content' }}
+                rowSelection={{ type: 'checkbox', ...rowSelection }}
+                rowKey={(record) => record.documentId}
+                loading={listLoading}
+                columns={columns}
+                dataSource={list}
+                pagination={paginationConfig}
+              />
+            </div>
+            {/* 上传知识文件 */}
+            {(uploadModalOpen||knowledgeDetail?.createBy === userInfoAll.id) && <UploadModal
+              open={uploadModalOpen}
+              knowledgeId={params.knowledgeId || ''}
+              knowledgeDetail={knowledgeDetail}
+              onCancel={() => setUploadModalOpen(false)}
+              onSuccess={() => {
+                init(params.knowledgeId, 2);
+              }}
+            />}
+            {
+              (infoModalOpen||knowledgeDetail?.createBy === userInfoAll.id) &&
+              <InfoModal
+                id={infoModalId}
+                open={infoModalOpen}
+                onClickConfirm={infoModalOnClickConfirm}
+                onClickCancel={infoModalOnClickCancel}
+              />
+            }
+
+            {
+              infoModalSettingOpen &&
+              <InfoModalSetting
+                id={infoModalSettingId}
+                open={infoModalSettingOpen}
+                record={record}
+                onClickConfirm={infoModalSettingOnClickConfirm}
+                onClickCancel={infoModalSettingOnClickCancel}
+              />
+            }
+          </>
+        }
+      </Spin>
+      {mdModalOpen && <MdModal open={mdModalOpen} detailDocument={detailDocument} knowledgeDetail={knowledgeDetail} onCancel={(type?: number) => {
+        init(params.knowledgeId, 2, '0');
+        if (!type) {
+          setMdModalOpen(false)
+        }
+      }}></MdModal>}
+      {quoteModalOpen && <QuoteModal open={quoteModalOpen} knowledgeDetail={knowledgeDetail} onCancel={() => { init(params.knowledgeId, 2); setQuoteModalOpen(false) }}></QuoteModal>}
+      <PrevewSlice openDrawer={openDrawer} onClose={() => setOpenDrawer(false)} title={detailDocument?.name || '预览切片'} record={detailDocument} />
+      
+    </div>
+  );
+};
+
+export default observer(KnowledgeLibInfo);

+ 410 - 0
src/pages/deepseek/knowledgeLib/detail/store.ts

@@ -0,0 +1,410 @@
+import { action, makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import { fetchEventSource } from '@fortaine/fetch-event-source';
+import LocalStorage from '@/LocalStorage';
+import { apis, ModifyDocumentApiParams, ModifyDocumentSettingApiParams } from '@/apis';
+import { State, ReadonlyState, StateAction, DocumentLibInfoStore } from './types';
+import { downloadFile } from '@/utils/index'
+// 定义状态
+const stateGenerator = (): ReadonlyState => ({
+    knowledge_id: '',
+    name: '',
+    listLoading: false,
+    list: [],
+    processingList: [],
+    infoModalId: '',
+    infoModalOpen: false,
+    infoModalSettingId: '',
+    infoModalSettingOpen: false,
+    page: {
+        page: 1,
+        size: 10,
+        total: 0,
+    },
+    knowledgeDetail: {
+        knowledgeId: '',
+        embeddingId: '',
+        name: '',
+        standardClassification: '',
+        splittingType: ''
+    }
+});
+
+// 修改状态
+const stateActionsGenerator = (state: State): StateAction => {
+    return {
+        setknowledge_id(knowledge_id) {
+            state.knowledge_id = knowledge_id;
+        },
+        setListLoading: (loading) => {
+            state.listLoading = loading;
+        },
+        setList: (list) => {
+            state.list = list;
+        },
+        setProcessingList: (list) => {
+            state.processingList = list;
+        },
+        setInfoModalId: (id) => {
+            state.infoModalId = id;
+        },
+        setInfoModalOpen: (open) => {
+            state.infoModalOpen = open;
+        },
+        setPage: (page) => {
+            state.page = page;
+        },
+        setInfoModalSettingOpen: (open) => {
+            state.infoModalSettingOpen = open;
+        },
+        setInfoModalSettingId: (id) => {
+            state.infoModalSettingId = id;
+        },
+        setKnowledgeDetail: (knowledgeDetail) => {
+            state.knowledgeDetail = knowledgeDetail;
+        },
+        setName: (name) => {
+            state.name = name
+        }
+    };
+};
+
+// 使用仓库
+const useKnowledgeLibInfoStore = (): DocumentLibInfoStore => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    // 当前 SSE 连接的关闭函数,用于确保同一时刻只有一个 SSE 连接
+    let currentSSEClose: (() => void) | null = null;
+
+    const api = {
+        // 获取知识列表
+        fetchDocumentLibList: async (status = 1) => {
+            actions.setListLoading(true);
+            try {
+                const data = {
+                    knowledge_id: state.knowledge_id,
+                    page: state.page.page,
+                    size: state.page.size,
+                    name: state.name,
+                    status, // 0 未完成,1已完成
+                };
+                const res = await apis.fetchTakaiDocumentLibListApi(data);
+                if (status === 1) {
+                    actions.setList(res.rows);
+                    actions.setPage({
+                        ...state.page,
+                        total: res.total,
+                    });
+                }
+                if (status === 0) {
+                    res.rows?.forEach((item: any) => {
+                        item.progress = 0
+                    });
+                    actions.setProcessingList(res.rows);
+                }
+            } catch (error: any) {
+                console.error(error);
+            } finally {
+                actions.setListLoading(false);
+            }
+        },
+        // 修改知识
+        modifyDocumentLib: async (id: string, data: ModifyDocumentApiParams) => {
+            try {
+                await apis.modifyTakaiDocumentLibApi(id, data);
+                // 获取知识列表
+                api.fetchDocumentLibList();
+                message.success('修改成功');
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+        // 删除知识
+        deleteDocumentLib: async (id: string) => {
+            try {
+                await apis.deleteTakaiDocumentLibApi(id);
+                // 获取知识列表
+                api.fetchDocumentLibList();
+                message.success('删除成功');
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+
+        // 修改知识配置
+        modifyDocumentSettingLib: async (id: string, data: ModifyDocumentSettingApiParams) => {
+            try {
+                actions.setListLoading(true);
+                const res = await apis.modifyTakaiDocumentSettingLibApi(id, data);
+                if (res.data === 1) {
+                    // 获取知识列表
+                    api.fetchDocumentLibList(0);
+                    api.fetchDocumentLibList(1);
+                    message.success('修改成功');
+                } else {
+                    message.success('修改失败');
+                }
+            } catch (error: any) {
+                message.error(error.msg);
+            } finally {
+                actions.setListLoading(false);
+            }
+        },
+
+        // 获取知识库详情
+        fetchKnowledgeLibDetail: async () => {
+            try {
+                const res = await apis.fetchTakaiKnowledgeLibDetail(state.knowledge_id);
+                const { knowledgeId, embeddingId, name, standardClassification } = res.data;
+                actions.setKnowledgeDetail({
+                    knowledgeId: knowledgeId,
+                    embeddingId: embeddingId,
+                    name: name,
+                    standardClassification: standardClassification,
+                    splittingType: res.data.splittingType
+                });
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        }
+    }
+
+    // 更改分页
+    const onChangePagination: DocumentLibInfoStore['onChangePagination'] = async (page, size) => {
+        actions.setPage({
+            ...state.page,
+            page: page,
+            size: size,
+        });
+        // 获取知识列表
+        api.fetchDocumentLibList();
+    }
+    // 搜索名称更新
+    const handleNameChange: DocumentLibInfoStore['handleNameChange'] = (name) => {
+        actions.setName(name)
+    }
+    // 点击上传文件
+    const onClickDocumentDetail: DocumentLibInfoStore['onClickDocumentDetail'] = () => {
+        api.fetchDocumentLibList();
+    }
+
+    // 点击修改
+    const onClickModify: DocumentLibInfoStore['onClickModify'] = (id) => {
+        actions.setInfoModalId(id);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 点击配置
+    const onClickSettings: DocumentLibInfoStore['onClickSettings'] = (id) => {
+        actions.setInfoModalSettingId(id);
+        actions.setInfoModalSettingOpen(true);
+    }
+
+    // 信息弹出层-点击确定
+    const infoModalOnClickConfirm: DocumentLibInfoStore['infoModalOnClickConfirm'] = async (id, data) => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+
+        if (id) {
+            // 修改知识数据
+            api.modifyDocumentLib(id, data);
+        }
+    }
+
+    // 信息弹出层-点击取消
+    const infoModalOnClickCancel: DocumentLibInfoStore['infoModalOnClickCancel'] = () => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+    }
+
+    // 知识配置信息弹出层-点击确定
+    const infoModalSettingOnClickConfirm: DocumentLibInfoStore['infoModalSettingOnClickConfirm'] = async (id, data) => {
+        const initialInfoModalSettingOpen = stateGenerator().infoModalSettingOpen;
+
+        actions.setInfoModalSettingOpen(initialInfoModalSettingOpen);
+
+        if (id) {
+            // 修改知识数据
+            api.modifyDocumentSettingLib(id, data);
+        }
+    }
+
+    // 只是配置信息弹出层-点击取消
+    const infoModalSettingOnClickCancel: DocumentLibInfoStore['infoModalSettingOnClickCancel'] = () => {
+        const initialInfoModalSettingOpen = stateGenerator().infoModalSettingOpen;
+
+        actions.setInfoModalSettingOpen(initialInfoModalSettingOpen);
+    }
+
+    // 点击删除
+    const onClickDelete: DocumentLibInfoStore['onClickDelete'] = async (id) => {
+        // 删除知识文件
+        await api.deleteDocumentLib(id);
+    }
+
+
+    // 初始渲染
+    const init: DocumentLibInfoStore['init'] = (id, type = 1,status?:string) => {
+        // 获取知识列表
+        if (id) {
+            actions.setknowledge_id(id);
+            if(!status){
+                api.fetchDocumentLibList(0);
+            }
+            api.fetchDocumentLibList(1);
+            api.fetchKnowledgeLibDetail();
+            // sse();
+        }
+        if (type === 1) {
+            setTimeout(() => {
+                sse()
+            }, 1000)
+        }
+    }
+
+    // 状态重置
+    const reset: DocumentLibInfoStore['reset'] = async () => {
+        const initialListLoading = stateGenerator().listLoading;
+        const initialList = stateGenerator().list;
+        const initialInfoModalId = stateGenerator().infoModalId;
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+        const initialPage = stateGenerator().page;
+        const knowledge_id = stateGenerator().knowledge_id;
+        const initialInfoModalSettingId = stateGenerator().infoModalSettingId;
+        const initialInfoModalSettingOpen = stateGenerator().infoModalSettingOpen;
+        const initialKnowledgeDetail = stateGenerator().knowledgeDetail;
+
+        actions.setListLoading(initialListLoading);
+        actions.setList(initialList);
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(initialInfoModalOpen);
+        actions.setPage(initialPage);
+        actions.setknowledge_id(knowledge_id);
+        actions.setInfoModalSettingId(initialInfoModalSettingId);
+        actions.setInfoModalSettingOpen(initialInfoModalSettingOpen);
+        actions.setKnowledgeDetail(initialKnowledgeDetail);
+        console.log('resetreset---')
+        await apis.getSseclose()
+    }
+    /**
+     * 接入 SSE (Server-Sent Events) 服务
+     * 使用 GET 请求连接到服务器端事件流,实时接收服务器推送的数据
+     * 注意:此方法会确保同一时刻只有一个 SSE 连接,如果已有连接则会先关闭旧连接
+     * 
+     * @param {Function} onMessage - 接收到消息时的回调函数,参数为消息数据
+     * @param {Function} onError - 发生错误时的回调函数,参数为错误信息
+     * @param {Function} onOpen - 连接打开时的回调函数
+     * @param {Function} onClose - 连接关闭时的回调函数
+     * @returns {Function} 返回一个用于关闭 SSE 连接的函数
+     */
+    const sse: DocumentLibInfoStore['sse'] = (
+        onMessage?: (data: any) => void,
+        onError?: (error: any) => void,
+        onOpen?: () => void,
+        onClose?: () => void
+    ) => {
+        // 从 LocalStorage 获取认证令牌
+        const token = LocalStorage.getToken();
+
+        // 如果没有令牌,提示错误并返回
+        if (!token) {
+            message.error('未获取到认证令牌,无法建立 SSE 连接');
+            if (onError) {
+                onError(new Error('未获取到认证令牌'));
+            }
+            return;
+        }
+
+        // 客户端 ID
+        const clientid = 'e5cd7e4891bf95d1d19206ce24a7b32e';
+
+        // 构建完整的请求 URL,包含查询参数
+        // 将 Authorization 和 clientid 作为查询参数传递
+        const url = new URL('/api/resource/sse', window.location.origin);
+        url.searchParams.append('Authorization', `Bearer ${token}`);
+        url.searchParams.append('clientid', clientid);
+        const en = new EventSource(url)
+        en.onmessage = event => {
+            // console.log('e.data', event.data)
+            let data: any = event.data;
+            try {
+                data = JSON.parse(event.data);
+                // console.log('event--消息接收成功', data)
+                const flagProcessingList: any = [...state.processingList]
+                flagProcessingList.forEach((item: any) => {
+                    if (item.documentId === data.documentId) {
+                        // console.log('进来没有---', data.progress)
+                        item.progress = data.progress
+                        item.status = data.status
+                        if (data.progress === 100 || data.message === 'error') {
+                            api.fetchDocumentLibList(0);
+                            api.fetchDocumentLibList(1);
+                        }
+                    }
+                })
+                // console.log('flagProcessingList', flagProcessingList)
+                actions.setProcessingList(flagProcessingList)
+            } catch {
+                // 如果不是 JSON 格式,直接使用原始数据
+            }
+        }
+        en.onerror = e => {
+            console.log('err', e)
+        }
+        en.onopen = e => {
+            console.log('onopen', e)
+        }
+        return
+    }
+    const onDeleteTakaiDocumentLibApi = async (documentId: string) => {
+        const res = await apis.deleteTakaidelUnfinishedDocumentLibApi(documentId)
+        if (res.code === 200) {
+            api.fetchDocumentLibList(0);
+            api.fetchDocumentLibList(1);
+        }
+    }
+
+    const onExportDocumentSliceExport = async (lis: String[], type = 1) => {
+        if (!lis.length) {
+            message.warning('请选择文件')
+            return
+        }
+        if (type === 1) {
+            const blob = await apis.exportDocumentSliceExport(lis)
+            downloadFile(blob, '切片')
+        }
+        if (type === 2) {
+            const blob = await apis.exportDocumentExport(lis)
+            downloadFile(blob, '文件.zip')
+        }
+        if (type === 3) {
+            const blob = await apis.documentFileExport(lis)
+            downloadFile(blob, '原文件.zip')
+        }
+    }
+
+
+    return {
+        handleNameChange,
+        state,
+        onChangePagination,
+        onClickDocumentDetail,
+        onClickModify,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        onClickDelete,
+        init,
+        onClickSettings,
+        infoModalSettingOnClickConfirm,
+        infoModalSettingOnClickCancel,
+        reset,
+        sse,
+        onDeleteTakaiDocumentLibApi,
+        onExportDocumentSliceExport
+    };
+};
+
+export default useKnowledgeLibInfoStore();

+ 40 - 0
src/pages/deepseek/knowledgeLib/detail/style.less

@@ -0,0 +1,40 @@
+.knowledgeLibInfo {
+  width: 100%;
+  height: 100%;
+  background: #FFFFFF;
+  border-radius: @border-radius-base;
+  // @keyframes progress {
+  //     0% { width: 0%; }
+  //     100% { width: var(--progress-width, 10%); }
+  // }
+
+  .progress-bar {
+      animation: progress 1.5s ease-out forwards;
+  }
+  &-table {
+    padding: 20px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+  }
+
+  &-operation {
+    padding:20px;
+    padding-bottom: 0;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+    display:flex;
+    justify-content: space-between;
+  }
+
+  &-progress {
+    // background: #F5F5F5;
+    padding: 10px 20px 0px;
+    border-radius: @border-radius-base;
+
+    &-divider {
+      height: 1px;
+      background: #E5E5E5;
+      margin: 16px 0;
+    }
+  }
+}

+ 86 - 0
src/pages/deepseek/knowledgeLib/detail/types.ts

@@ -0,0 +1,86 @@
+import { ModifyDocumentApiParams, ModifyDocumentSettingApiParams } from '@/apis';
+
+export type Record = {
+    documentId: string,
+    name: string,
+    url: string,
+    length: number,
+    sentence_size: number,
+    knowledge_type: number,
+    custom_separator: string[],
+    embedding_stat: number,
+    word_num: number,
+    parse_image: number
+};
+
+export type RecordKonwledge = {
+    knowledgeId: string,
+    embeddingId: string,
+    name: string,
+    standardClassification: string,
+    splittingType: string,
+    sliceValue?: string,
+    createBy?: string,
+};
+
+// 定义状态
+export type State = {
+    name?: string,
+    knowledge_id: string,
+    listLoading: boolean,
+    list: Record[],
+    processingList:[],
+    infoModalId: string,
+    infoModalOpen: boolean,
+    infoModalSettingId: string,
+    infoModalSettingOpen: boolean,
+    page: {
+        page: number,
+        size: number,
+        total: number,
+    },
+    knowledgeDetail: RecordKonwledge,
+};
+
+// 只读状态
+export type ReadonlyState = Readonly<State>;
+
+// 修改状态
+export type StateAction = {
+    setknowledge_id(knowledge_id: string): unknown;
+    setListLoading: (loading: State['listLoading']) => void,
+    setList: (list: State['list']) => void,
+    setProcessingList: (list: State['processingList']) => void,
+    setInfoModalId: (id: State['infoModalId']) => void,
+    setInfoModalOpen: (open: State['infoModalOpen']) => void,
+    setInfoModalSettingId: (id: State['infoModalSettingId']) => void,
+    setInfoModalSettingOpen: (open: State['infoModalSettingOpen']) => void,
+    setPage: (page: State['page']) => void,
+    setKnowledgeDetail: (knowledgeDetail: State['knowledgeDetail']) => void,
+    setName: (name: string) => void,
+};
+
+// 仓库类型
+export type DocumentLibInfoStore = {
+    state: ReadonlyState,
+    init: (knowledgeId?: string,type?:number,status?:string) => void,
+    onChangePagination: (page: number, size: number) => Promise<any>,
+    onClickDocumentDetail: (knowledgeId?: string) => void,
+    onClickModify: (id: string) => void,
+    infoModalOnClickConfirm: (id: string, data: ModifyDocumentApiParams) => Promise<any>,
+    infoModalOnClickCancel: () => void,
+    onClickDelete: (id: string) => Promise<any>,
+    onClickSettings: (id: string) => void,
+    infoModalSettingOnClickConfirm: (id: string, data: ModifyDocumentSettingApiParams) => Promise<any>,
+    infoModalSettingOnClickCancel: () => void,
+    reset: () => void,
+    onDeleteTakaiDocumentLibApi: (documentId: string) => Promise<any>,
+    onExportDocumentSliceExport: (lis:String[],type:number) => Promise<any>,
+    handleNameChange: (name: string) => void,
+    sse: (
+        onMessage?: (data: any) => void,
+        onError?: (error: any) => void,
+        onOpen?: () => void,
+        onClose?: () => void
+    ) => void,
+};

+ 345 - 0
src/pages/deepseek/knowledgeLib/list/components/InfoModal.tsx

@@ -0,0 +1,345 @@
+import * as React from 'react';
+import { Modal, Spin, Form, Input, Select, Switch, message } from 'antd';
+import { apis, CreateOrModifyKnowledgeLibApiParams } from '@/apis';
+
+const FormItem = Form.Item;
+const { Option } = Select;
+const { TextArea } = Input;
+
+interface Props {
+    id: string,
+    open: boolean,
+    onClickConfirm: (id: string, data: CreateOrModifyKnowledgeLibApiParams) => Promise<any>,
+    onClickCancel: () => void,
+};
+
+const InfoModal: React.FC<Props> = (props: Props) => {
+    const {
+        id,
+        open,
+        onClickConfirm,
+        onClickCancel
+    } = props;
+
+    const [form] = Form.useForm();
+
+    const [loading, setLoading] = React.useState<boolean>(false);
+    const [confirmLoading, setConfirmLoading] = React.useState<boolean>(false);
+    const mountedRef = React.useRef<boolean>(true);
+
+    type EmbeddingList = {
+        label: string,
+        value: string,
+    }[];
+    type AppTypeList = {
+        label: string,
+        value: string,
+        children: {
+            label: string,
+            value: string,
+        }[],
+    }[];
+    const [embeddingList, setEmbeddingList] = React.useState<EmbeddingList>([]);
+    const [standardClass, setStandardClass] = React.useState<AppTypeList>([]); // 选择分类 
+    const [modelType, setModelType] = React.useState<AppTypeList>([]); // 选择模型 
+    const [splittingType, setSplittingType] = React.useState<AppTypeList>([]); // 选择切分规则 
+ // 获取调用模型的列表数据
+    const onFetchRerankModelList = async () => {
+        const res = await apis.fetchRerankModelList();
+        if(res && res.data){
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.embeddingModel,
+                    value: item.embeddingModel,
+                }
+            })
+            setModelType(list);
+            // setModeOldList(res.data);
+        }
+    }
+    const getTitle = () => {
+        if (id) {
+            return '修改知识库';
+        } else {
+            return '创建知识库';
+        }
+    };
+
+    // 获取向量化模型列表
+    const fetchEmbeddingList = async () => {
+        try {
+            const res = await apis.fetchEmbeddingList();
+            const list = res.data.list.map((item: any) => {
+                return {
+                    label: item.name,
+                    value: item.id,
+                }
+            });
+            setEmbeddingList(list);
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+
+    // 获取知识库详情
+    const fetchDetail = async () => {
+        try {
+            const res = await apis.fetchTakaiKnowledgeLibDetail(props.id);
+            const { name, embeddingId, description, visible, knowledgeGraph, standardClassification, splittingType } = res.data;
+            console.log('res.data', res.data)
+            form.setFieldsValue({
+                name: name,
+                embeddingId: embeddingId,
+                description: description,
+                standardClassification: standardClassification,
+                // splittingType: splittingType,
+                // 将后端的 0/1 或 true/false 映射为 Switch 所需的布尔值
+                visible: visible === 0 || visible === '0' || visible === true || visible === 'true',
+                knowledgeGraph: knowledgeGraph === 'true' ? true : false,
+            });
+        } catch (error: any) {
+            message.error(error.msg);
+        }
+    };
+    // 获取是否公开类型
+    const fetchAppVisible = async (id: string) => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('app_visible');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                }
+            });
+            if (!id) {
+                form.setFieldsValue({
+                    visible: list[0].value === '0' ? true : false
+                });
+            }
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    // // 获取向量化模型
+    const fetchAppmodelType = async (id: string) => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('model_type');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                }
+            });
+            setModelType(list);
+            if (!id) {
+                form.setFieldsValue({
+                    // visible: list[0].value === '0' ? true : false
+                });
+            }
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    // 获取向默认切分规则
+    const fetchsplittingType = async (id: string) => {
+        try {
+            const res = await apis.fetchTakaiAppTypeList('splitting_type');
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.dictLabel,
+                    value: item.dictValue,
+                }
+            });
+            setSplittingType(list);
+            if (!id) {
+                form.setFieldsValue({
+                    // visible: list[0].value === '0' ? true : false
+                });
+            }
+        } catch (error: any) {
+            console.error(error);
+        }
+    }
+    const init = async () => {
+        setLoading(true);
+        // await fetchEmbeddingList();
+        if (props.id) {
+            await fetchDetail();
+        }
+        await fetchAppVisible(props.id);
+        onFetchRerankModelList()
+        // await fetchAppstandardClass(props.id);
+        // await fetchAppmodelType(props.id);
+        await fetchsplittingType(props.id);
+        setLoading(false);
+    };
+
+    React.useEffect(() => {
+        init();
+        return () => {
+            mountedRef.current = false;
+        };
+    }, []);
+
+    // 点击确定
+    const handleClickConfirm = () => {
+        form.validateFields().then(async (values) => {
+            const data = {
+                ...values,
+                // 将 Switch 布尔值转换回后端使用的 0/1
+                visible: values.visible ? 0 : 1,
+                knowledgeGraph: `${values.knowledgeGraph}`
+            };
+            try {
+                setConfirmLoading(true);
+                await onClickConfirm(props.id, data);
+            } catch (error) {
+                console.error(error);
+            } finally {
+                if (mountedRef.current) setConfirmLoading(false);
+            }
+        }).catch((error) => {
+            console.error(error);
+        });
+    };
+
+    // 点击取消
+    const handleClickCancel = () => {
+        // 重置表单,替代 destroyOnClose 的销毁行为
+        try {
+            form.resetFields();
+            if (mountedRef.current) setConfirmLoading(false);
+        } catch (error) {
+            console.error('Error resetting form fields:', error);
+        } finally {
+            onClickCancel();
+        }
+    };
+
+    return (
+        <Modal
+            width={500}
+            title={getTitle()}
+            maskClosable={false}
+            centered={true}
+            open={open}
+            confirmLoading={confirmLoading}
+            onOk={handleClickConfirm}
+            onCancel={handleClickCancel}
+        >
+            <Spin spinning={loading}>
+                <Form form={form} layout='vertical' initialValues={{
+                    knowledgeGraph: false, // 给 knowledgeGraph 字段设置初始值为 false
+                    // 其他字段的初始值...
+                }}
+                >
+                    <FormItem
+                        label='知识库名称'
+                        name='name'
+                        rules={[{ required: true, message: '知识库名称不能为空', whitespace: true }]}
+                    >
+                        <Input placeholder='请输入知识库名称' />
+                    </FormItem>
+                    <div style={{ display: 'flex', gap: 16, marginBottom: 24 }}>
+                        <div style={{ flex: 1 }}>
+                            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
+                                <span>是否公开</span>
+                                <FormItem name='visible' valuePropName='checked' noStyle>
+                                    <Switch checkedChildren="是" disabled={id ? true : false} unCheckedChildren="否" />
+                                </FormItem>
+                            </div>
+                        </div>
+                        <div style={{ flex: 1 }}>
+                            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
+                                <span>知识图谱</span>
+                                <FormItem name='knowledgeGraph' valuePropName='checked' noStyle>
+                                    <Switch checkedChildren="开启" disabled={true} unCheckedChildren="关闭" />
+                                </FormItem>
+                            </div>
+                        </div>
+                    </div>
+                    {/* <FormItem
+                        label='选择分类'
+                        name='standardClassification'
+                        rules={[{ required: true, message: '请选择分类' }]}
+                    >
+                        <Select
+                            style={{ width: '100%' }}
+                            placeholder='请选择分类'
+                            allowClear={true}
+                            disabled={id?true:false}
+                        >
+
+                            {
+                                standardClass.map((item, index) => {
+                                    return <Option value={item.value} key={index}>
+                                        {item.label}
+                                    </Option>
+                                })
+                            }
+                        </Select>
+                    </FormItem> */}
+                    <FormItem
+                        label='向量化模型'
+                        name='embeddingId'
+                        rules={[{ required: true, message: '向量化模型不能为空' }]}
+                    >
+                        {
+                            <Select
+                                style={{ width: '100%' }}
+                                placeholder='请选择向量化模型'
+                                allowClear={true}
+                                disabled={id ? true : false}
+                            >
+                                {
+                                    modelType.map((item, index) => {
+                                        return <Option value={item.value} key={index}>
+                                            {item.label}
+                                        </Option>
+                                    })
+                                }
+                            </Select>
+                        }
+
+                    </FormItem>
+                    {/* <FormItem
+                        label='默认切分规则'
+                        name='splittingType'
+                        rules={[{ required: true, message: '默认切分规则不能为空' }]}
+                    >
+                        {
+                            <Select
+                                style={{ width: '100%' }}
+                                placeholder='请选择默认切分规则'
+                                allowClear={true}
+                            >
+                                {
+                                    splittingType.map((item, index) => {
+                                        return <Option value={item.value} key={index}>
+                                            {item.label}
+                                        </Option>
+                                    })
+                                }
+                            </Select>
+                        }
+                    </FormItem> */}
+                    <FormItem
+                        label='知识库描述'
+                        name='description'
+                        rules={[{ required: true, message: '知识库描述不能为空', whitespace: true }]}
+                    >
+                        <TextArea
+                            placeholder='知识库描述需要描述清楚知识库中的文件内容,搭建应用时模型会将此作为判断是否获取知识库内容的依据'
+                            showCount={true}
+                            rows={4}
+                            maxLength={100}
+                        />
+                    </FormItem>
+                    <div style={{ width: '100%', height: 10 }}></div>
+                </Form>
+            </Spin>
+        </Modal>
+    );
+};
+
+export default InfoModal;

+ 347 - 0
src/pages/deepseek/knowledgeLib/list/index.tsx

@@ -0,0 +1,347 @@
+import * as React from 'react';
+import { useNavigate } from 'react-router-dom';
+import { observer } from 'mobx-react';
+import { Button, Table, TableColumnsType, Modal, TablePaginationConfig, Tooltip, Input, Radio, Space } from 'antd';
+import { PlusOutlined, EditOutlined, DeleteOutlined, ArrowDownOutlined, SearchOutlined, BulbOutlined,CloseOutlined,CloudDownloadOutlined } from '@ant-design/icons';
+import InfoModal from './components/InfoModal';
+import dayjs from 'dayjs';
+import store from './store';
+import { Record } from './types';
+import './style.less';
+import LocalStorage from '@/LocalStorage';
+
+import Step from '@/components/step';
+
+const KnowledgeLibList: React.FC = () => {
+    const navigate = useNavigate();
+    const {
+        state,
+        onChangePagination,
+        onClickCreate,
+        onClickModify,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        onClickDelete,
+        init,
+        reset,
+        handleModeChange,
+        handleNameChange,
+        exportKnowledgeFile,
+        exportKnowledgeMarkDown
+    } = store;
+    const {
+        listLoading,
+        list,
+        infoModalId,
+        infoModalOpen,
+        page
+    } = state;
+
+    const [downloadOriginal, setDownloadOriginal] = React.useState<boolean>(); //原文档
+    const [downloadMd, setDownloadMd] = React.useState<boolean>(); //MD文档
+    const [deleteFlag, setDeleteFlag] = React.useState<boolean>(); // 删除权限
+    const [updateFlag, setUpdateFlag] = React.useState<boolean>(); // 编辑权限
+    const [listFlag, setListFlag] = React.useState<boolean>(); // 详情权限
+    const [userInfoAll, setUserInfoAll] = React.useState<any>({});
+    React.useEffect(() => {
+        init();
+        const downloadOriginal = LocalStorage.getStatusFlag('knowledge:knowledgeLib:downloadOriginal');
+        setDownloadOriginal(downloadOriginal);
+        const downloadMd = LocalStorage.getStatusFlag('knowledge:knowledgeLib:downloadMd');
+        setDownloadMd(downloadMd);
+        const dFlag = LocalStorage.getStatusFlag('knowledge:knowledgeLib:del');
+        setDeleteFlag(dFlag);
+        const tFlag = LocalStorage.getStatusFlag('knowledge:knowledgeLib:edit');
+        setUpdateFlag(tFlag);
+        const lFlag = LocalStorage.getStatusFlag('knowledge:knowledgeLib:detail');
+        setListFlag(lFlag);
+        setUserInfoAll(LocalStorage.getUserInfo());
+
+        // 监听面包屑创建知识库事件
+        const handleKnowledgeLibCreate = (event: CustomEvent) => {
+            if (event.detail.platform === 'deepseek') {
+                onClickCreate();
+            }
+        };
+
+        window.addEventListener('knowledgeLibCreate', handleKnowledgeLibCreate as EventListener);
+
+        return () => {
+            reset();
+            window.removeEventListener('knowledgeLibCreate', handleKnowledgeLibCreate as EventListener);
+        };
+    }, []);
+
+    const columns: TableColumnsType<Record> = [
+        {
+            title: '序号',
+            dataIndex: 'index',
+            width: 80,
+            render: (text, record, index) => {
+                return index + 1;
+            }
+        },
+        {
+            title: '知识库名称',
+            dataIndex: 'name',
+            sorter: (a, b) => a.name.localeCompare(b.name),
+            render: (text, record) => {
+                if (listFlag||userInfoAll.id === record.createBy) {
+                    return (
+                        <p
+                            className='text-primary cursor-pointer'
+                            style={{ fontWeight: 600 }} 
+                            onClick={() => {
+                                navigate(`/knowledge/knowledgeLib/${record.knowledgeId}/${record.createBy}`);
+                            }}
+                        >
+                            {text}
+                        </p>
+                    )
+                } else {
+                    return (
+                        <>
+                            {text}
+                        </>
+                    )
+                }
+            }
+        },
+        {
+            title: '使用空间',
+            dataIndex: 'length',
+            render: (text) => {
+                if (text) {
+                    const size = (text / 1024 / 1024).toFixed(2);
+                    return `${size}M`;
+                } else {
+                    return '--'
+                }
+            }
+        },
+        {
+            title: '字符数量',
+            dataIndex: 'wordNum',
+            render: (text) => {
+                if (text) {
+                    return `${text}`;
+                } else {
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '文件数量',
+            dataIndex: 'documentSize',
+            render: (text) => {
+                if (text) {
+                    return `${text}`;
+                } else {
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '是否公开',
+            dataIndex: 'visible',
+            render: (text) => {
+                if (text==='0') {
+                    return '公开';
+                } else {
+                    return '私有';
+                }
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            width: 200,
+            render: (text) => {
+                if (text) {
+                    return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+                } else {
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '更新时间',
+            dataIndex: 'updateTime',
+            width: 200,
+            render: (text) => {
+                if (text) {
+                    return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
+                } else {
+                    return '--';
+                }
+            }
+        },
+        {
+            title: '操作',
+            dataIndex: 'operation',
+            width: 150,
+            fixed: 'right',
+            render: (text, record) => {
+                return (
+                    <>
+                        {
+                            (updateFlag || userInfoAll.id === record.createBy) &&
+                            <a
+                                style={{ marginRight: 16 }}
+                                onClick={() => {
+                                    onClickModify(record.knowledgeId);
+                                }}
+                            >
+                                <EditOutlined />
+                            </a >
+                        }
+                        {
+                            ((downloadOriginal||userInfoAll.id === record.createBy) && record.documentSize>0 &&
+                            <a
+                                style={{ marginRight: 16 }}
+                                onClick={() => {
+                                    Modal.confirm({
+                                        title: '提示',
+                                        content: `确定是否下载原文档?`,
+                                        okType: 'primary',
+                                        onOk: async () => {
+                                            exportKnowledgeFile(record)
+                                        }
+                                    });
+                                }}
+                            >
+                             <Tooltip title="下载原文档"> <ArrowDownOutlined /></Tooltip>
+                            </a>)
+                        }
+                        {
+                             ((downloadMd||userInfoAll.id === record.createBy) && record.documentSize>0)&&<a
+                                style={{ marginRight: 16 }}
+                                onClick={() => {
+                                    Modal.confirm({
+                                        title: '提示',
+                                        content: `确定是否下载MD文件?`,
+                                        okType: 'primary',
+                                        onOk: async () => {
+                                            exportKnowledgeMarkDown(record)
+                                        }
+                                    });
+                                }}
+                            >
+                                <Tooltip title="下载MD"> <CloudDownloadOutlined /></Tooltip>
+                            </a>
+                        }
+                        {
+                            (deleteFlag || userInfoAll.id === record.createBy) &&
+                            <a
+                                className='text-error'
+                                onClick={() => {
+                                    Modal.confirm({
+                                        title: '删除',
+                                        content: `确定删除知识库名称${record.name}吗?`,
+                                        okType: 'danger',
+                                        onOk: async () => {
+                                            await onClickDelete(record.knowledgeId);
+                                        }
+                                    });
+                                }}
+                            >
+                                <DeleteOutlined />
+                            </a>
+                        }
+                    </>
+                )
+            }
+        }
+    ];
+
+    const paginationConfig: TablePaginationConfig = {
+        // 显示数据总量
+        showTotal: (total: number) => {
+            return `共 ${total} 条`;
+        },
+        // 展示分页条数切换
+        showSizeChanger: true,
+        // 指定每页显示条数
+        pageSizeOptions: ['10', '20', '50', '100'],
+        // 快速跳转至某页
+        showQuickJumper: true,
+        current: page.pageNum,
+        pageSize: page.pageSize,
+        total: page.total,
+        onChange: async (page, pageSize) => {
+            await onChangePagination(page, pageSize);
+        },
+    };
+    const steps = [
+        {
+            title: '创建知识库',
+            description: '按特定场景/领域管理知识库,当前仅创建空的知识库集合。',
+            number: 1,
+        },
+        {
+            title: '上传文档',
+            description: 'Word, Pdf, Excel等多种文档格式,支持图片 OCR;',
+            number: 2,
+        },
+        {
+            title: '高质量切片工具',
+            description: '等待文档自动解析完成,既能直接使用默认结果,又能再次进行人工干预。',
+            number: 3,
+        }
+    ]
+    const [showGuide, setShowGuide] = React.useState<boolean>(() => localStorage.getItem('knowledgeGuideHidden') !== 'true');
+    const hideGuide = () => { localStorage.setItem('knowledgeGuideHidden', 'true'); setShowGuide(false); };
+    return (
+        <div className='knowledgeLibList'>
+            {/* 创建按钮已移至面包屑组件 */}
+            <div className='knowledgeLibList-table'>
+                {showGuide && <> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
+                    <div style={{ fontSize: 13, color: '#333', display: 'flex', alignItems: 'center', gap: 6 }}>
+                        <BulbOutlined style={{ color: '#faad14' }} />
+                        提示: 如何创建并管理自己的知识库?
+                    </div>
+                    <CloseOutlined onClick={hideGuide} style={{ color: '#999', cursor: 'pointer' }} />
+                </div>
+                <Step steps={steps} className='mb-3' /></>}
+                <div className='knowledgeLibList-filter mb-3'>
+                    <Radio.Group onChange={(e) => {
+                        handleModeChange(e.target.value)
+                    }} value={state.classificationType} style={{ marginBottom: 8 }}>
+                        <Radio.Button value="0">全部</Radio.Button>
+                        <Radio.Button value="1">我创建的</Radio.Button>
+                    </Radio.Group>
+                    <Space.Compact style={{ width: '300px' }}>
+                        <Input
+                            placeholder='请输入知识库名称进行搜索'
+                            value={state.name}
+                            onChange={(e) => handleNameChange(e.target.value)}
+                        />
+                        <Button type="primary" onClick={() => { init() }}><SearchOutlined /></Button>
+                    </Space.Compact>
+                </div>
+                <Table
+                    scroll={{ x: 'max-content' }}
+                    rowKey={(record) => record.knowledgeId}
+                    loading={listLoading}
+                    columns={columns}
+                    dataSource={list}
+                    pagination={paginationConfig}
+                />
+            </div>
+            {
+                infoModalOpen &&
+                <InfoModal
+                    id={infoModalId}
+                    open={infoModalOpen}
+                    onClickConfirm={infoModalOnClickConfirm}
+                    onClickCancel={infoModalOnClickCancel}
+                />
+            }
+        </div>
+    );
+};
+
+// 设置组件名称,帮助 React Fast Refresh 识别组件
+KnowledgeLibList.displayName = 'KnowledgeLibList';
+
+export default observer(KnowledgeLibList);

+ 260 - 0
src/pages/deepseek/knowledgeLib/list/store.ts

@@ -0,0 +1,260 @@
+import { makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import { apis, CreateOrModifyKnowledgeLibApiParams } from '@/apis';
+import { State, ReadonlyState, StateAction, KnowledgeLibListStore } from './types';
+import { downloadFile } from '@/utils';
+// 定义状态
+const stateGenerator = (): ReadonlyState => ({
+    listLoading: false,
+    list: [],
+    infoModalId: '',
+    infoModalOpen: false,
+    page: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0,
+    },
+    name:'',
+    classificationType:'0',
+});
+
+// 修改状态
+const stateActionsGenerator = (state: State): StateAction => {
+    return {
+        setListLoading: (loading) => {
+            state.listLoading = loading;
+        },
+        setList: (list) => {
+            state.list = list;
+        },
+        setInfoModalId: (id) => {
+            state.infoModalId = id;
+        },
+        setInfoModalOpen: (open) => {
+            state.infoModalOpen = open;
+        },
+        setPage: (page) => {
+            state.page = page;
+        },
+        setClassificationType: (data)=>{
+            state.classificationType = data
+        },
+        setName: (name) => {
+            state.name = name
+        }
+    };
+};
+
+// 使用仓库
+const useKnowledgeLibListStore = (): KnowledgeLibListStore => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    const api = {
+        // 下载知识库
+        fetchExportKnowledgeSliceExport:async (record:any)=>{
+            const blob = await apis.exportKnowledgeSliceExport(record.knowledgeId);
+            const url = window.URL.createObjectURL(blob);
+            const link = document.createElement("a");
+            link.href = url;
+            link.download = record.name;
+            document.body.appendChild(link);
+            link.click();
+            document.body.removeChild(link);
+            window.URL.revokeObjectURL(url);
+        },
+        // 获取知识库列表
+        fetchKnowledgeLibList: async () => {
+            actions.setListLoading(true);
+            try {
+                const data = {
+                    pageNum: state.page.pageNum,
+                    pageSize: state.page.pageSize,
+                    name:state.name,
+                    classificationType:state.classificationType==='0'?true:false
+                };
+                const res = await apis.fetchTakaiKnowledgeLibList(data);
+                actions.setList(res.rows);
+                actions.setPage({
+                    ...state.page,
+                    total: res.total,
+                });
+            } catch (error: any) {
+                console.error(error);
+            } finally {
+                actions.setListLoading(false);
+            }
+        },
+        // 创建知识库
+        createKnowledgeLib: async (data: CreateOrModifyKnowledgeLibApiParams) => {
+            actions.setListLoading(true);
+            const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+            try {
+                const res = await apis.createTakaiKnowledgeLib(data);
+                // 获取知识库列表
+                api.fetchKnowledgeLibList();
+                if(res.data === 1 && res.code === 200){
+                    message.success('创建成功');
+                    actions.setInfoModalOpen(initialInfoModalOpen);
+                }else{
+                    console.error('DeepSeek创建知识库响应异常:', res);
+                    message.error('创建失败');
+                }
+            } catch (error: any) {
+                console.error('DeepSeek创建知识库错误:', error);
+                message.error(error.msg || '创建失败');
+            }finally{
+                actions.setListLoading(false);
+            }
+        },
+        // 修改知识库
+        modifyKnowledgeLib: async (knowledgeId: string, data: CreateOrModifyKnowledgeLibApiParams) => {
+            try {
+                const initialInfoModalOpen = stateGenerator().infoModalOpen;
+                const res = await apis.modifyTakaiKnowledgeLib(knowledgeId, data);
+                // 获取知识库列表
+                api.fetchKnowledgeLibList();
+                if(res.data === 1 && res.code === 200){
+                    message.success('修改成功');
+                    actions.setInfoModalOpen(initialInfoModalOpen);
+                }else{
+                    message.error('修改失败');
+                }
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+        // 删除知识库
+        deleteKnowledgeLib: async (knowledgeId: string) => {
+            try {
+                const res = await apis.deleteTakaiKnowledgeLib(knowledgeId);
+                // 获取知识库列表
+                api.fetchKnowledgeLibList();
+                if(res.data === 1 && res.code === 200){
+                    message.success('删除成功');
+                }else{
+                    message.error('删除失败');
+                }
+            } catch (error: any) {
+                message.error(error.msg);
+            }
+        },
+    }
+
+    // 更改分页
+    const onChangePagination: KnowledgeLibListStore['onChangePagination'] = async (pageNum, pageSize) => {
+        actions.setPage({
+            ...state.page,
+            pageNum: pageNum,
+            pageSize: pageSize,
+        });
+        // 获取知识库列表
+        await api.fetchKnowledgeLibList();
+    }
+
+    // 点击创建
+    const onClickCreate: KnowledgeLibListStore['onClickCreate'] = () => {
+        const initialInfoModalId = stateGenerator().infoModalId;
+
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 点击修改
+    const onClickModify: KnowledgeLibListStore['onClickModify'] = (knowledgeId) => {
+        actions.setInfoModalId(knowledgeId);
+        actions.setInfoModalOpen(true);
+    }
+
+    // 信息弹出层-点击确定
+    const infoModalOnClickConfirm: KnowledgeLibListStore['infoModalOnClickConfirm'] = async (knowledgeId, data) => {
+
+        if (knowledgeId) {
+            // 修改知识库
+            const res:any  = await api.modifyKnowledgeLib(knowledgeId, data);
+        } else {
+            // 创建知识库
+            const res:any = await api.createKnowledgeLib(data);
+        }
+    }
+
+    // 信息弹出层-点击取消
+    const infoModalOnClickCancel: KnowledgeLibListStore['infoModalOnClickCancel'] = () => {
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+
+        actions.setInfoModalOpen(initialInfoModalOpen);
+    }
+
+    // 点击删除
+    const onClickDelete: KnowledgeLibListStore['onClickDelete'] = async (knowledgeId) => {
+        // 删除知识库
+        await api.deleteKnowledgeLib(knowledgeId);
+    }
+
+    // 初始渲染
+    const init: KnowledgeLibListStore['init'] = async () => {
+        // 获取知识库列表
+        await api.fetchKnowledgeLibList();
+    }
+
+    // 状态重置
+    const reset: KnowledgeLibListStore['reset'] = () => {
+        const initialListLoading = stateGenerator().listLoading;
+        const initialList = stateGenerator().list;
+        const initialInfoModalId = stateGenerator().infoModalId;
+        const initialInfoModalOpen = stateGenerator().infoModalOpen;
+        const initialPage = stateGenerator().page;
+        const initialName = stateGenerator().name;
+        const initialClassificationType = stateGenerator().classificationType;
+
+        actions.setListLoading(initialListLoading);
+        actions.setList(initialList);
+        actions.setInfoModalId(initialInfoModalId);
+        actions.setInfoModalOpen(initialInfoModalOpen);
+        actions.setPage(initialPage);
+        actions.setName(initialName);
+        actions.setClassificationType(initialClassificationType);
+    }
+
+    // 列表全部和我创建的进行切换
+    const handleModeChange:KnowledgeLibListStore['handleModeChange'] = (data)=>{
+        actions.setClassificationType(data)
+        init()
+    }
+
+    // 搜索名称更新
+    const handleNameChange:KnowledgeLibListStore['handleNameChange'] = (name) => {
+        actions.setName(name)
+    }
+    // 导出知识库列表
+    const handFetchExportKnowledgeSliceExport = (record:any)=>{
+         api.fetchExportKnowledgeSliceExport(record)
+    }
+    const exportKnowledgeMarkDown = async (record:any) => {
+        const blob = await apis.exportKnowledgeMarkDown(record.knowledgeId);
+        downloadFile(blob, `${record.name}.zip`); 
+    }
+    const exportKnowledgeFile = async (record:any) => {
+        const blob = await apis.exportKnowledgeFile(record.knowledgeId);
+        downloadFile(blob, `${record.name}.zip`); 
+    }
+    return {
+        state,
+        onChangePagination,
+        onClickCreate,
+        onClickModify,
+        infoModalOnClickConfirm,
+        infoModalOnClickCancel,
+        onClickDelete,
+        init,
+        reset,
+        handleModeChange,
+        handleNameChange,
+        handFetchExportKnowledgeSliceExport,
+        exportKnowledgeMarkDown,
+        exportKnowledgeFile
+    };
+};
+
+export default useKnowledgeLibListStore();

+ 32 - 0
src/pages/deepseek/knowledgeLib/list/style.less

@@ -0,0 +1,32 @@
+.knowledgeLibList {
+  &-operation {
+    padding: 20px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+    margin-bottom: 20px;
+  }
+
+  &-table {
+    padding: 20px;
+    background: #FFFFFF;
+    border-radius: @border-radius-base;
+  }
+  .lis{
+    border: 1px solid #E9F3FE;
+    border-radius: 5px;
+  }
+  .libg1{
+        background: linear-gradient(to right, #95D3F4, white);
+  }
+  .libg2{
+    background: linear-gradient(to right,#9ABEFF, white);
+  }
+  .libg3{
+        background: linear-gradient(to right,  #87CEFA, white);
+  }
+  &-filter {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}

+ 59 - 0
src/pages/deepseek/knowledgeLib/list/types.ts

@@ -0,0 +1,59 @@
+import { CreateOrModifyKnowledgeLibApiParams } from '@/apis';
+
+export type Record = {
+    [x: string]: any;
+    knowledgeId: string,
+    name: string,// 知识库名称
+    length: number,// 使用空间
+    wordNum: number,// 字符数量
+    documentSize: number,// 文件数量
+    createTime: string,// 创建时间
+    updateTime: string,// 更新时间
+};
+
+// 定义状态
+export type State = {
+    listLoading: boolean,
+    list: Record[],
+    infoModalId: string,
+    classificationType?: string,
+    name?: string,
+    infoModalOpen: boolean,
+    page: {
+        pageNum: number,
+        pageSize: number,
+        total: number,
+    },
+};
+
+// 只读状态
+export type ReadonlyState = Readonly<State>;
+
+// 修改状态
+export type StateAction = {
+    setListLoading: (loading: State['listLoading']) => void,
+    setList: (list: State['list']) => void,
+    setInfoModalId: (id: State['infoModalId']) => void,
+    setInfoModalOpen: (open: State['infoModalOpen']) => void,
+    setPage: (page: State['page']) => void,
+    setClassificationType: (data?: string) => void,
+    setName: (name?: string) => void,
+};
+
+// 仓库类型
+export type KnowledgeLibListStore = {
+    state: ReadonlyState,
+    onChangePagination: (pageNum: number, pageSize: number) => Promise<any>,
+    onClickCreate: () => void,
+    onClickModify: (knowledgeId: string) => void,
+    infoModalOnClickConfirm: (knowledgeId: string, data: CreateOrModifyKnowledgeLibApiParams) => Promise<any>,
+    infoModalOnClickCancel: () => void,
+    onClickDelete: (knowledgeId: string) => Promise<any>,
+    init: () => Promise<any>,
+    reset: () => void,
+    handleModeChange: (data:State['classificationType']) => void,
+    handleNameChange: (name?: string) => void,
+    handFetchExportKnowledgeSliceExport: (record?: any) => void,
+    exportKnowledgeMarkDown: (record: any) => Promise<void>,
+    exportKnowledgeFile: (record: any) => Promise<void>,
+};

+ 20 - 0
src/pages/deepseek/knowledgeLib/revisionTool/components/reviseDrawer.less

@@ -0,0 +1,20 @@
+.ant-spin-nested-loading {
+  height: 100% !important;
+}
+.pdf-page {
+  width: 100% !important;
+}
+
+.pdf-page canvas {
+  width: 100% !important;
+  height: auto !important;
+}
+.pdf-page-wrapper {
+  width: 100%;
+}
+
+.pdf-page-placeholder {
+  width: 100%;
+  aspect-ratio: 1 / 1.3;
+  background: #f5f5f5;
+}

+ 547 - 0
src/pages/deepseek/knowledgeLib/revisionTool/components/reviseDrawer.tsx

@@ -0,0 +1,547 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { observer } from 'mobx-react';
+import { Drawer, Row, Col, Input, Button, List, Typography, Select, Spin, Image, message, Modal, Tooltip } from 'antd';
+import type { DrawerProps, RadioChangeEvent } from 'antd';
+import { SnippetsOutlined, ExceptionOutlined, DeleteOutlined,QuestionCircleOutlined } from '@ant-design/icons';
+import MarkdownIt from 'markdown-it';
+import { fetchReviseToolAllList, fetchReviseToolSliceList, apis, submitReviseSliceApi } from '@/apis';
+import './reviseDrawer.less'
+import LocalStorage from '@/LocalStorage';
+
+import RevisionHistory from './revisionHistory';
+import tubing from '@/assets/public/tubing.png'
+import rfq from '@/assets/public/rfq.png'
+
+interface ReviseDrawerProps {
+    openDrawer: boolean;
+    onClose: () => void;
+    title: string;
+    record: any;
+}
+
+const ReviseDrawer: React.FC<ReviseDrawerProps> = (props: ReviseDrawerProps) => {
+    const { openDrawer, onClose, title, record } = props;
+    const [placement, setPlacement] = useState<DrawerProps['placement']>('right');
+    const [historyTool, setHistoryTool] = useState<boolean>(false);
+
+    useEffect(() => {
+        if (record.knowledgeId && openDrawer) {
+            // 初始化左侧文档搜索
+            onFetchReviseToolAllList('', 'left', record.knowledgeId);
+            onFetchReviseToolAllList('', 'right', record.knowledgeId);
+        }
+        setHistoryTool(LocalStorage.getStatusFlag('knowledge:revisionTool:history'));
+    }, [openDrawer]);
+
+    const [leftSearch, setLeftSearch] = useState('');// 左边搜索
+    const [rightSearch, setRightSearch] = useState(''); // 右边搜索
+    const [leftSpliceSearch, setLeftSpliceSearch] = useState('');// 左边切片搜索
+    const [rightSpliceSearch, setRightSpliceSearch] = useState('');// 右边切片搜索
+    const [revisionOptions, setRevisionOptions] = useState<any[]>([]);
+    const [revisionLoading, setRevisionLoading] = useState(false);
+    const [selectedRevision, setSelectedRevision] = useState<string | undefined>(undefined);
+    const [leftDocumentId, setLeftDocumentId] = useState(''); // 左边选中的文档ID
+    const [rightDocumentId, setRightDocumentId] = useState(''); // 右边选中的文档ID
+    const [leftOptions, setLeftOptions] = useState<any[]>([]);// 左边数据
+    const [rightOptions, setRightOptions] = useState<any[]>([]);// 右边数据
+    const [leftLoading, setLeftLoading] = useState(false);// 左边加载状态
+    const [rightLoading, setRightLoading] = useState(false);// 右边加载状态
+    const [selectedStandard, setSelectedStandard] = useState<string | null>(null);
+    const [leftSlices, setLeftSlices] = useState<string[]>([]);// 左边切片列表
+    const [rightSlices, setRightSlices] = useState<string[]>([]);// 右边切片列表
+    const [leftSlicesLoading, setLeftSlicesLoading] = useState(false);// 左边切片加载状态
+    const [rightSlicesLoading, setRightSlicesLoading] = useState(false);// 右边切片加载状态
+    const marked = new MarkdownIt({ html: true, typographer: true });
+    useEffect(() => {
+        if (leftDocumentId) {
+            onFetchReviseToolSliceList(leftDocumentId, 'left');
+        }
+    }, [leftDocumentId]);
+    useEffect(() => {
+        if (rightDocumentId) {
+            onFetchReviseToolSliceList(rightDocumentId, 'right');
+        }
+    }, [rightDocumentId]);
+    const onChange = (e: RadioChangeEvent) => {
+        setPlacement(e.target.value);
+    };
+
+    const onFetchTakaiAppTypeListApi = async () => {
+        setRevisionLoading(true);
+        try {
+            const res: any = await apis.fetchTakaiAppTypeList('revision_status');
+            if (res && res.data && Array.isArray(res.data)) {
+                const opts = res.data.map((it: any) => ({ label: it.dictLabel, value: it.dictValue }));
+                setSelectedRevision(opts[0].value);
+                setRevisionOptions(opts);
+            } else {
+                setRevisionOptions([]);
+            }
+        } catch (err) {
+            setRevisionOptions([]);
+        } finally {
+            setRevisionLoading(false);
+        }
+    };
+    useEffect(() => {
+        onFetchTakaiAppTypeListApi();
+    }, []);
+    const customRender = (text: string, mdImgUrlList: any[]) => {
+        // 比如:把 "我是图片" 替换成一张图片
+        mdImgUrlList?.forEach(item => {
+            text = text.replace(new RegExp(item.originText, 'g'), `<img src="${item.mediaUrl}" alt="${item.originText}" />`);
+        })
+        return text;
+    }
+    // 获取知识库修订工具列表
+    const onFetchReviseToolAllList = async (documentName?: string, side?: 'left' | 'right', knowledgeId?: string) => {
+        // Implement the function to fetch revise tool all list
+        const res: any = await fetchReviseToolAllList({ documentName: documentName || '', knowledgeId: knowledgeId || '' });
+        // 假设接口返回结构为 { code: 200, data: [ { id, name }, ... ] }
+        if (res && res.data && Array.isArray(res.data)) {
+            const results = res.data.map((it: any) => ({ label: it.documentName, value: it.documentId }));
+            if (side === 'left')
+                setLeftOptions(results);
+            else if (side === 'right')
+                setRightOptions(results);
+        } else {
+            if (side === 'left')
+                setLeftOptions([]);
+            else if (side === 'right')
+                setRightOptions([]);
+        }
+    };
+    // 获取知识库修订工具切片列表
+    const onFetchReviseToolSliceList = async (documentId: string, side?: 'left' | 'right', sliceText?: string) => {
+        setLeftSlicesLoading(side === 'left' ? true : leftSlicesLoading);
+        setRightSlicesLoading(side === 'right' ? true : rightSlicesLoading);
+        // Implement the function to fetch revise tool slice list
+        const res: any = await fetchReviseToolSliceList({ documentId: documentId || '', sliceText: sliceText || '' });
+        // 假设接口返回结构为 { code: 200, data: [ { sliceContent }, ... ] }
+        if (res && res.data && Array.isArray(res.data)) {
+            const results = res.data;
+            results.forEach((item: any) => {
+                item.sliceText = customRender(item.sliceText, item.mediaList)
+            })
+            if (side === 'left') {
+                setLeftSlicesLoading(false);
+                setLeftSlices(results);
+            }
+            else if (side === 'right') {
+                setRightSlicesLoading(false);
+                setRightSlices(results);
+
+            }
+        } else {
+            if (side === 'left')
+                setLeftSlices([]);
+            else if (side === 'right')
+                setRightSlices([]);
+        }
+    }
+    const [LeftActiveId, setLeftActiveId] = useState<string | null>(null);
+    const [RightActiveId, setRightActiveId] = useState<string | null>(null);
+    const [subLoading, setSubLoading] = useState(false);
+    const [showReviseModal, setShowReviseModal] = useState(false);
+    const [historyDrawerOpen, setHistoryDrawerOpen] = useState(false);
+
+    // 处理从修订历史传来的编辑事件
+    const handleEditFromHistory = async (editRecord: any) => {
+        try {
+            // 1. 关闭修订历史 drawer
+            setHistoryDrawerOpen(false);
+
+            // 2. 设置右侧搜索条件和文档
+            setRightSearch(editRecord.documentName || '');
+            setRightDocumentId(editRecord.documentId);
+            
+            // 3. 设置左侧搜索条件和文档
+            setLeftSearch(editRecord.refDocumentName || '');
+            // 需要根据 refDocumentName 查找对应的文档ID,这里假设需要调用搜索API
+            
+            // 4. 搜索切片列表
+            await onFetchReviseToolSliceList(editRecord.documentId, 'right');
+            if(editRecord.refDocumentId){
+                await onFetchReviseToolSliceList(editRecord.refDocumentId, 'left');
+            }
+            
+            // 5. 通过 sliceId 定位并选中切片
+            // 延迟一下确保数据已加载
+            setTimeout(() => {
+                const targetSliceElement = document.querySelector(`[data-slice-id="${editRecord.sliceId}"]`);
+                if (targetSliceElement) {
+                    setRightActiveId(editRecord.sliceId);
+                    targetSliceElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
+                }
+            }, 300);
+        } catch (error) {
+            message.error('加载编辑数据失败');
+        }
+    };
+    const [editingRightId, setEditingRightId] = useState<string | null>(null);
+
+    const onAllClose = () => {
+        setLeftActiveId(null);
+        setRightActiveId(null);
+        setLeftSearch('');
+        setRightSearch('');
+        setLeftSpliceSearch('');
+        setRightSpliceSearch('');
+        setLeftDocumentId('');
+        setRightDocumentId('');
+        setLeftOptions([]);
+        setRightOptions([]);
+        setLeftSlices([]);
+        setRightSlices([]);
+        setRevisionSliceText('');
+        onClose();
+    }
+    const [revisionSliceText, setRevisionSliceText] = useState<string>('');
+    // submitReviseSliceApi --- IGNORE ---
+    const onSubmitReviseSliceApi = async (selectedRevision: string) => {
+        try {
+            const res: any = await submitReviseSliceApi({
+                revisionSliceText: revisionSliceText,
+                revisionStatus: selectedRevision,
+                sliceId: RightActiveId,
+                refSliceId: selectedRevision === '1' ? LeftActiveId : null
+            })
+            if (res && res.code === 200) {
+                message.success('修订提交成功');
+                if (revisionSliceText && selectedRevision === '1') {
+                    // 如果是修订操作,更新右侧切片内容
+                    setRightSlices(prevSlices => prevSlices.map((slice: any) => {
+                        if (slice.sliceId === RightActiveId) {
+                            return { ...slice, revisionSliceText: revisionSliceText, revisionStatus: '1'};
+                        }
+                        return slice;
+                    }));
+                }
+                if (selectedRevision === '0') {
+                    // 如果是修订操作,更新右侧切片内容
+                    setRightSlices(prevSlices => prevSlices.map((slice: any) => {
+                        if (slice.sliceId === RightActiveId) {
+                            return { ...slice, revisionStatus: '0'};
+                        }
+                        return slice;
+                    }));
+                }
+            }
+        } catch (error: any) {
+            console.log('error', error);
+            message.error(error.msg || '修订提交失败');
+        } finally {
+            setSubLoading(false);
+        }
+    }
+    return (
+        <>
+            <Drawer
+                title={
+                    <div className='flex items-center justify-between'>
+                        <p>{title}</p>
+                        {historyTool && <Button icon={<SnippetsOutlined />} size='small' onClick={() => setHistoryDrawerOpen(true)}>
+                            修订记录
+                        </Button>}
+                        {/* <p className='cursor-pointer' onClick={() => setHistoryDrawerOpen(true)}>修订历史</p> */}
+                    </div>
+                }
+                placement={placement}
+                closable={true}
+                onClose={onAllClose}
+                open={openDrawer}
+                width={'70%'}
+                footer={
+                    <div style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center', height: 50, gap: 12 }}>
+                        {/* <Select
+                        style={{ width: 220 }}
+                        options={revisionOptions}
+                        loading={revisionLoading}
+                        placeholder="选择修订状态"
+                        value={selectedRevision}
+                        onChange={(val) => setSelectedRevision(val)}
+                    /> */}
+                        <Button onClick={onAllClose}>关闭</Button>
+                        {/* <Button type="primary"
+                        loading={subLoading}
+                        icon={
+                            <SnippetsOutlined />
+                        }
+                        onClick={async () => {
+                            // 确认动作:这里你可以把选中的修订状态应用到选中项或提交
+                            // submitReviseSliceApi
+                            setSubLoading(true);
+                            try {
+                                const res:any = await submitReviseSliceApi({
+                                    revisionStatus: selectedRevision,
+                                    sliceId: RightActiveId,
+                                    refSliceId: selectedRevision==='1'? LeftActiveId : null
+                                })
+                                if(res && res.code === 200){
+                                    message.success('修订提交成功');
+                                }
+                            } catch (error:any) {
+                                console.log('error',error);
+                                message.error(error.msg || '修订提交失败');
+                            } finally {
+                                setSubLoading(false);
+                            }
+                        }}>保存</Button> */}
+                    </div>
+                }
+            >
+                <div className="flex gap-4 h-full">
+                    {/* Left column */}
+                    <div className="w-1/2 border-r pr-4">
+                        <div className="text-lg font-semibold mb-3">新标准规范文搜索 
+                            <Tooltip title="仅支持标准规范">  <QuestionCircleOutlined style={{fontSize:'15px'}} />
+                            </Tooltip> </div>
+                        <div className="mb-3">
+                            <Select
+                                showSearch
+                                placeholder="搜索标准规范条文"
+                                style={{ width: '100%' }}
+                                value={leftSearch || undefined}
+                                filterOption={false}
+                                onSearch={async (val) => {
+                                    setLeftOptions([]);
+                                    setLeftSearch(val);
+                                    if (!val) {
+                                        return;
+                                    }
+                                    setLeftLoading(true);
+                                    try {
+                                        onFetchReviseToolAllList(val, 'left',record.knowledgeId?record.knowledgeId:'');
+                                    } catch (err) {
+                                        setLeftOptions([]);
+                                    } finally {
+                                        setLeftLoading(false);
+                                    }
+                                }}
+                                notFoundContent={leftLoading ? <Spin size="small" /> : '无匹配结果'}
+                                options={leftOptions}
+                                onChange={(value, option) => {
+                                    // value is the selected option value (id), option contains label
+                                    const label = (option && (option as any).label) || value;
+                                    setLeftSearch(label as string);
+                                    setLeftDocumentId(value as string);
+                                    setLeftSpliceSearch('');
+                                    // Fetch slices for the selected document
+                                }}
+                            />
+                        </div>
+                        <div className="mb-3">
+                            <div className="flex items-center justify-between mb-2">
+                                <div className="font-medium">标准规范条文结果</div>
+                                <div style={{ width: 230 }}>
+                                    <Input.Search placeholder="搜索切片" disabled={!leftSearch} value={leftSpliceSearch} enterButton size="small"
+                                        onChange={(e) => {
+                                            setLeftSpliceSearch(e.target.value);
+                                        }}
+                                        onSearch={(e) => {
+                                            onFetchReviseToolSliceList(leftDocumentId, 'left', e);
+                                        }} />
+                                </div>
+                            </div>
+                        </div>
+
+                        <Spin spinning={leftSlicesLoading} className="h-full">
+                            {leftSlices.length > 0 ? <div className="overflow-y-auto max-h-full" style={{ maxHeight: 'calc(90vh - 130px)' }}>
+                                {leftSlices.map((module: any, index) => (
+                                    <div
+                                        key={index}
+                                        className={`relative px-3 py-2 text-sm leading-7 transition-all duration-200 cursor-pointer 
+                                        ${index !== leftSlices.length - 1 ? 'border-b border-gray-100' : ''
+                                            } ${LeftActiveId === module.sliceId
+                                                ? 'bg-blue-100  border-l-blue-500 shadow-sm scale-[1]'
+                                                : 'hover:bg-gray-50'
+                                            }`}
+                                        onClick={() => { setLeftActiveId(module.sliceId); setRevisionSliceText(module.sliceText || '') }}
+                                    >
+                                        {module.sliceText && (() => {
+                                            const html = marked.render(module.sliceText || '');
+                                            const parts: any[] = [];
+                                            const imgRegex = /<img[^>]*src=["']([^"']+)["'][^>]*>/g;
+                                            let lastIndex = 0;
+                                            let match: RegExpExecArray | null;
+                                            while ((match = imgRegex.exec(html)) !== null) {
+                                                const idx = match.index;
+                                                const textSeg = html.substring(lastIndex, idx);
+                                                if (textSeg) parts.push(<div key={`t-${index}-${lastIndex}`} dangerouslySetInnerHTML={{ __html: textSeg }} />);
+                                                const url = match[1];
+                                                parts.push(<Image key={`img-${index}-${idx}`} src={url} preview={{}} style={{ maxWidth: '100%' }} />);
+                                                lastIndex = idx + match[0].length;
+                                            }
+                                            const rest = html.substring(lastIndex);
+                                            if (rest) parts.push(<div key={`tlast-${index}`} dangerouslySetInnerHTML={{ __html: rest }} />);
+                                            return <div className="text-sm leading-7 text-gray-800 markdown-preview">{parts}</div>;
+                                        })()}
+                                    </div>
+                                ))}
+                            </div> : <div className="text-center text-gray-500 mt-10">暂无数据</div>}
+                        </Spin>
+                    </div>
+
+                    {/* Right column (same as left) */}
+                    <div className="w-1/2">
+                        <div className="text-lg font-semibold mb-3">受影响规范条文结果
+                            <Tooltip title="仅支持标准规范">  <QuestionCircleOutlined style={{fontSize:'15px'}} />
+                            </Tooltip>
+                        </div>
+                        <div className="mb-3">
+                            <Select
+                                showSearch
+                                placeholder="搜索受影响标准规范条文"
+                                style={{ width: '100%' }}
+                                value={rightSearch || undefined}
+                                filterOption={false}
+                                onSearch={async (val) => {
+                                    setRightSearch(val);
+                                    if (!val) {
+                                        setRightOptions([]);
+                                        return;
+                                    }
+                                    setRightLoading(true);
+                                    try {
+                                        onFetchReviseToolAllList(val, 'right',record.knowledgeId?record.knowledgeId:'');
+                                    } catch (err) {
+                                        setRightOptions([]);
+                                    } finally {
+                                        setRightLoading(false);
+                                    }
+                                }}
+                                notFoundContent={rightLoading ? <Spin size="small" /> : '无匹配结果'}
+                                options={rightOptions}
+                                onChange={(value, option) => {
+                                    // value is the selected option value (id), option contains label
+                                    const label = (option && (option as any).label) || value;
+                                    setRightSearch(label as string);
+                                    setRightDocumentId(value as string);
+                                    setRightSpliceSearch('');
+                                    // Fetch slices for the selected document
+                                }}
+                            />
+                        </div>
+
+                        <div className="mb-3">
+                            <div className="flex items-center justify-between mb-2">
+                                <div className="font-medium">受影响规范条文结果 </div>
+                                <div style={{ width: 230 }}>
+                                    <Input.Search placeholder="搜索切片" disabled={!rightSearch} value={rightSpliceSearch}
+                                        onChange={(e) => {
+                                            setRightSpliceSearch(e.target.value);
+                                        }}
+                                        onSearch={(e) => {
+                                            onFetchReviseToolSliceList(rightDocumentId, 'right', e);
+                                        }} enterButton size="small" />
+                                </div>
+                            </div>
+                        </div>
+                        <Spin spinning={rightSlicesLoading} className='h-full'>
+                            {rightSlices.length > 0 ? <div className="overflow-y-auto" style={{ maxHeight: 'calc(80vh - 130px)' }}>
+                                {rightSlices.map((module: any, index) => (
+                                    <div
+                                        key={`r-${index}`}
+                                        data-slice-id={module.sliceId}
+                                        className={`relative px-3 py-2 text-sm leading-7 transition-all duration-200 cursor-pointer 
+                                        ${index !== rightSlices.length - 1 ? 'border-b border-gray-100' : ''
+                                            } ${RightActiveId === module.sliceId
+                                                ? 'bg-blue-100  border-l-blue-500 shadow-sm scale-[1] pb-[40px]'
+                                                : 'hover:bg-gray-50'
+                                            } ${RightActiveId === module.sliceId && editingRightId === module.sliceId ? 'pb-[340px]' : ''}`
+                                        }
+                                        onClick={() => setRightActiveId(module.sliceId)}
+                                    >
+                                        <div className='absolute top-1 right-3'>
+                                            {module.revisionStatus==='1' && <Tooltip title={module.revisionSliceText} placement="top">
+                                                <Image width={16} height={16} src={tubing} preview={false} className='cursor-pointer ml-2' />
+                                            </Tooltip>}
+                                            {module.revisionStatus==='0' && <Tooltip title="已废弃" placement="top">
+                                                <Image width={16} height={16} src={rfq} preview={false} className='cursor-pointer ml-2' />
+                                            </Tooltip>}
+                                        </div>
+                                        {module.sliceText && (() => {
+                                            const html = marked.render(module.sliceText || '');
+                                            const parts: any[] = [];
+                                            const imgRegex = /<img[^>]*src=["']([^"']+)["'][^>]*>/g;
+                                            let lastIndex = 0;
+                                            let match: RegExpExecArray | null;
+                                            while ((match = imgRegex.exec(html)) !== null) {
+                                                const idx = match.index;
+                                                const textSeg = html.substring(lastIndex, idx);
+                                                if (textSeg) parts.push(<div key={`rt-${index}-${lastIndex}`} dangerouslySetInnerHTML={{ __html: textSeg }} />);
+                                                const url = match[1];
+                                                parts.push(<Image key={`rimg-${index}-${idx}`} src={url} preview={{}} style={{ maxWidth: '100%' }} />);
+                                                lastIndex = idx + match[0].length;
+                                            }
+                                            const rest = html.substring(lastIndex);
+                                            if (rest) parts.push(<div key={`rt-last-${index}`} dangerouslySetInnerHTML={{ __html: rest }} />);
+                                            return <div className="text-sm leading-7 text-gray-800 markdown-preview">{parts}</div>;
+                                        })()}
+                                        {RightActiveId === module.sliceId && (
+                                            <div className="absolute bottom-2 w-full right-3">
+                                                <div className="w-full flex flex-col items-end">
+                                                    {editingRightId === module.sliceId && <div className="w-[96%] flex items-center gap-2 justify-end mb-2">
+                                                        <Input.TextArea autoSize={{ minRows: 13, maxRows: 13 }} value={revisionSliceText} onChange={(e) => setRevisionSliceText(e.target.value)} />
+                                                    </div>}
+                                                    <p className='w-full flex items-center gap-2 justify-end'>
+                                                        <Button size="small" danger onClick={(e) => {
+                                                            e.stopPropagation();
+                                                            onSubmitReviseSliceApi('0');
+                                                        }}>废弃</Button>
+                                                        {editingRightId !== module.sliceId ? (
+                                                            <Button size="small" type="primary" onClick={(e) => {
+                                                                e.stopPropagation();
+                                                                setRevisionSliceText(module.revisionSliceText || '');
+                                                                setEditingRightId(module.sliceId);
+                                                            }}>修订</Button>
+                                                        ) : (
+                                                            <Button size="small" type="primary" loading={subLoading} onClick={async (e) => {
+                                                                e.stopPropagation();
+                                                                setSubLoading(true);
+                                                                await onSubmitReviseSliceApi('1');
+                                                                setSubLoading(false);
+                                                                setEditingRightId(null);
+                                                            }}>保存</Button>
+                                                        )}
+                                                    </p>
+                                                </div>
+                                                {/* {editingRightId === module.sliceId && (
+                                                <div className="mt-2 pr-20">
+                                                    <Input.TextArea autoSize={{ maxRows: 3 }} value={revisionSliceText} onChange={(e) => setRevisionSliceText(e.target.value)} />
+                                                </div>
+                                            )} */}
+                                            </div>
+                                        )}
+                                    </div>
+                                ))}
+                            </div> : <div className="text-center text-gray-500 mt-10">暂无数据</div>}
+                        </Spin>
+
+                    </div>
+                </div>
+                <Modal
+                    title="修订切片"
+                    open={showReviseModal}
+                    onCancel={() => setShowReviseModal(false)}
+                    footer={
+                        <div className="flex gap-2 justify-end">
+                            <Button onClick={() => setShowReviseModal(false)}>取消</Button>
+                            <Button type="primary" loading={subLoading} onClick={async () => {
+                                setSubLoading(true);
+                                await onSubmitReviseSliceApi('1');
+                                setSubLoading(false);
+                                setShowReviseModal(false);
+                            }}>确定</Button>
+                        </div>
+                    }
+                >
+                    <Input.TextArea autoSize={{ minRows: 6 }} value={revisionSliceText} onChange={(e) => setRevisionSliceText(e.target.value)} />
+                </Modal>
+            </Drawer>
+            {/* 修订历史 */}
+            <RevisionHistory historyDrawerOpen={historyDrawerOpen} record={record} onClose={() => setHistoryDrawerOpen(false)} onEdit={handleEditFromHistory} />        
+        </>
+    )
+}
+export default observer(ReviseDrawer);

+ 344 - 0
src/pages/deepseek/knowledgeLib/revisionTool/components/revisionHistory.tsx

@@ -0,0 +1,344 @@
+import React, { useEffect, useMemo, useRef, useState } from 'react';
+import { Drawer, Row, Col, Input, Button, List, Typography, Select, Spin, Image, message, Table, Tooltip } from 'antd';
+import type { ColumnsType } from 'antd/es/table';
+
+import { fetchReviseHistoryList } from '@/apis';
+import { observer } from 'mobx-react';
+import {InfoCircleOutlined} from "@ant-design/icons";
+
+interface RevisionHistoryProps {
+    historyDrawerOpen: boolean;
+    onClose: () => void;
+    onEdit?: (record: any) => void;
+    // title: string;
+    record: any;
+}
+
+const RevisionHistory: React.FC<RevisionHistoryProps> = (props) => {
+    const { historyDrawerOpen, onClose, onEdit, record } = props;
+    const [kbName, setKbName] = useState<string>('');
+    const [docName, setDocName] = useState<string>('');
+    const [refDocName, setRefDocName] = useState<string>('');
+    const [loading, setLoading] = useState<boolean>(false);
+    const [data, setData] = useState<any[]>([]);
+    // const [pageNum, setPage] = useState<number>(1);
+    const pageNum = useRef<number>(1);
+    const [pageSize, setSize] = useState<number>(10);
+    const [total, setTotal] = useState<number>(0);
+// 1. 创建一个查询触发器
+    const [searchTrigger, setSearchTrigger] = useState(0);
+    const onFetchReviseHistoryList = async () => {
+        setLoading(true);
+        try {
+            const params = {
+                pageNum: pageNum.current,
+                pageSize: pageSize,
+                knowledgeId: record.knowledgeId,
+                knowledgeName: kbName,
+                documentName: docName,
+                refDocumentName: refDocName,
+            };
+            const response: any = await fetchReviseHistoryList(params);
+            if (response && response.rows) {
+                setData(response.rows);
+                setTotal(response.total || 0);
+            } else {
+                message.error('获取修订历史失败');
+            }
+        } catch (error) {
+            message.error('获取修订历史异常');
+        } finally {
+            setLoading(false);
+        }
+    }
+    useEffect(() => {
+        // 避免组件首次挂载时就执行查询
+        if (searchTrigger > 0) {
+            onFetchReviseHistoryList();
+        }
+    }, [searchTrigger, kbName, docName, refDocName]);
+
+    useEffect(() => {
+        if (historyDrawerOpen) {
+            onFetchReviseHistoryList();
+        }
+    }, [historyDrawerOpen]);
+
+    const handleSearch = () => {
+        pageNum.current = 1;
+        setSearchTrigger(prev => prev + 1);
+    }
+    const onSet = () => {
+        setKbName('');
+        setDocName('');
+        setRefDocName('');
+        pageNum.current = 1;
+        setSearchTrigger(prev => prev + 1);
+    }
+    // 表格列定义
+const columns: ColumnsType<any> = [
+    {
+        title: (
+            <span>
+                受影响文档名称
+                <Tooltip
+                    title={
+                        // 说明文本:支持换行、自定义样式,可根据需求修改
+                        <div style={{ maxWidth: 300, whiteSpace: 'normal' }}>
+                            <b>知识库中的知识文档名称</b>
+                        </div>
+                    }
+                    placement="right" // 提示框显示在图标右侧
+                >
+                  <InfoCircleOutlined
+                      style={{
+                          marginLeft: 6, // 与标题的间距
+                          color: '#1890ff', // Ant Design 主色,适配风格
+                          fontSize: 14 // 图标大小适配标题
+                      }}
+                  />
+                </Tooltip>
+              </span>
+        ),
+        dataIndex: 'documentName', width: 160, ellipsis: {
+            showTitle: false,
+        },
+        render: (text) => (
+            <Tooltip placement="topLeft" title={(
+                <div style={{ maxWidth: 480, maxHeight: 320, overflow: 'auto', whiteSpace: 'normal' }}>
+                    {text}
+                </div>
+            )}>
+                {text}
+            </Tooltip>
+        ),
+    },
+    {
+        title: (
+            <span>
+                所在知识库
+                <Tooltip
+                    title={
+                        // 说明文本:支持换行、自定义样式,可根据需求修改
+                        <div style={{ maxWidth: 300, whiteSpace: 'normal' }}>
+                            <b>知识文档所在知识库名称</b>
+                        </div>
+                    }
+                    placement="right" // 提示框显示在图标右侧
+                    // arrowPointAtCenter // 箭头指向图标中心,更美观
+                >
+                  <InfoCircleOutlined
+                      style={{
+                          marginLeft: 6, // 与标题的间距
+                          color: '#1890ff', // Ant Design 主色,适配风格
+                          fontSize: 14 // 图标大小适配标题
+                      }}
+                  />
+                </Tooltip>
+              </span>
+        )
+        , dataIndex: 'knowledgeName', width: 180, ellipsis: {
+            showTitle: false,
+        },
+        render: (text) => (
+            <Tooltip placement="topLeft" title={(
+                <div style={{ maxWidth: 480, maxHeight: 320, overflow: 'auto', whiteSpace: 'normal' }}>
+                    {text}
+                </div>
+            )}>
+                {text}
+            </Tooltip>
+        ),
+    },
+    {
+        title: (
+            <span>
+                受影响规范条文原文
+                <Tooltip
+                    title={
+                        // 说明文本:支持换行、自定义样式,可根据需求修改
+                        <div style={{ maxWidth: 300, whiteSpace: 'normal' }}>
+                            <b>切片原文</b>
+                        </div>
+                    }
+                    placement="right" // 提示框显示在图标右侧
+                >
+                  <InfoCircleOutlined
+                      style={{
+                          marginLeft: 6, // 与标题的间距
+                          color: '#1890ff', // Ant Design 主色,适配风格
+                          fontSize: 14 // 图标大小适配标题
+                      }}
+                  />
+                </Tooltip>
+              </span>
+        )
+        , dataIndex: 'sliceText', width: 180,
+        ellipsis: {
+            showTitle: false,
+        },
+        render: (text) => (
+            <Tooltip placement="topLeft" title={(
+                <div style={{ maxWidth: 480, maxHeight: 320, overflow: 'auto', whiteSpace: 'normal' }}>
+                    {text}
+                </div>
+            )}>
+                {text}
+            </Tooltip>
+        ),
+    },
+    {
+        title: (
+            <span>
+                新标准规范文档
+                <Tooltip
+                    title={
+                        // 说明文本:支持换行、自定义样式,可根据需求修改
+                        <div style={{ maxWidth: 300, whiteSpace: 'normal' }}>
+                            <b>引用的新标准规范文档名称</b>
+                        </div>
+                    }
+                    placement="right" // 提示框显示在图标右侧
+                    // arrowPointAtCenter // 箭头指向图标中心,更美观
+                >
+                  <InfoCircleOutlined
+                      style={{
+                          marginLeft: 6, // 与标题的间距
+                          color: '#1890ff', // Ant Design 主色,适配风格
+                          fontSize: 14 // 图标大小适配标题
+                      }}
+                  />
+                </Tooltip>
+              </span>
+        )
+        , dataIndex: 'refDocumentName', width: 180, ellipsis: {
+            showTitle: false,
+        },
+        render: (text) => (
+            <Tooltip placement="topLeft" title={(
+                <div style={{ maxWidth: 480, maxHeight: 320, overflow: 'auto', whiteSpace: 'normal' }}>
+                    {text}
+                </div>
+            )}>
+                {text}
+            </Tooltip>
+        ),
+    },
+    {
+        title: (
+            <span>
+                修订后的受影响规范条文
+                <Tooltip
+                    title={
+                        // 说明文本:支持换行、自定义样式,可根据需求修改
+                        <div style={{ maxWidth: 300, whiteSpace: 'normal' }}>
+                            <b>根据新标准规范文档修订后的切片内容</b>
+                        </div>
+                    }
+                    placement="right" // 提示框显示在图标右侧
+                    // arrowPointAtCenter // 箭头指向图标中心,更美观
+                >
+                  <InfoCircleOutlined
+                      style={{
+                          marginLeft: 6, // 与标题的间距
+                          color: '#1890ff', // Ant Design 主色,适配风格
+                          fontSize: 14 // 图标大小适配标题
+                      }}
+                  />
+                </Tooltip>
+              </span>
+        )
+        , dataIndex: 'revisionSliceText', width: 230,
+        ellipsis: {
+            showTitle: false,
+        },
+        render: (text,record) => (
+            <Tooltip placement="topLeft" title={(
+                <div style={{ maxWidth: 480, maxHeight: 320, overflow: 'auto', whiteSpace: 'normal' }}>
+                    {text}
+                </div>
+            )}>
+                {text}
+            </Tooltip>
+        ),
+    },
+
+    {
+        title: '修订时间', dataIndex: 'createTime', width: 120, align: 'center'
+    },
+    {
+        title: '修订状态', dataIndex: 'revisionStatus', width: 120, align: 'center', render: (text: any, record: any) => (
+            <p>{text === '1' ? '已修订' : '废弃'}</p>
+        )
+    },
+    {
+        title: '操作', dataIndex: 'revisionStatus', width: 120, align: 'center', render: (text: any, record: any) => (
+            <p 
+                className='text-primary cursor-pointer'
+                onClick={() => {
+                    onEdit?.(record);
+                }}
+            >
+                重新修订
+            </p>
+        )
+    }
+];
+    return (
+        <Drawer
+            title="修订记录"
+            placement="left"
+            width={'60%'}
+            onClose={() => { onClose() }}
+            open={historyDrawerOpen}
+        >
+            <div style={{ marginBottom: 12 }}>
+                <Row gutter={12} align="middle">
+                    <Col span={6}>
+                        <Input placeholder="知识库名称" value={kbName} onChange={(e) =>{
+                            setKbName(e.target.value)
+                            setSearchTrigger(0)
+                        }} />
+                    </Col>
+                    <Col span={6}>
+                        <Input placeholder="受影响文档名称" value={docName} onChange={(e) => {
+                            setDocName(e.target.value)
+                            setSearchTrigger(0)
+                        }} />
+                    </Col>
+                    <Col span={6}>
+                        <Input placeholder="新标准规范文档名称" value={refDocName} onChange={(e) => {
+                            setRefDocName(e.target.value)
+                            setSearchTrigger(0)
+                        }} />
+                    </Col>
+                    <Col>
+                        <Button className='mr-2' onClick={onSet}>重置</Button>
+                        <Button type="primary" onClick={handleSearch}>搜索</Button>
+                    </Col>
+                </Row>
+            </div>
+            <div>
+                <Table
+                    columns={columns}
+                    dataSource={data}
+                    loading={loading}
+                    rowKey="createTime"
+                    pagination={{
+                        current: pageNum.current,
+                        pageSize: pageSize,
+                        total: total,
+                        onChange: (p, ps) => {
+                            console.log('onChange', p, ps);
+                            pageNum.current = p;
+                            setSize(ps || pageSize);
+                            onFetchReviseHistoryList();
+                        }
+                    }}
+                />
+            </div>
+        </Drawer>)
+}
+
+
+export default observer(RevisionHistory);

+ 163 - 0
src/pages/deepseek/knowledgeLib/revisionTool/list/index.tsx

@@ -0,0 +1,163 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { Table, Pagination, Space, Button, TablePaginationConfig, Input } from 'antd';
+import type { ColumnsType } from 'antd/es/table';
+import { observer } from 'mobx-react';
+import { SearchOutlined, BulbOutlined, CloseOutlined } from '@ant-design/icons';
+
+import store from './store';
+import Step from '@/components/step';
+import ReviseDrawer from '../components/reviseDrawer';
+import LocalStorage from '@/LocalStorage';
+
+
+interface KnowledgeRecord {
+  knowledgeName: string;
+  knowledgeId: string | number;
+  length: string | number; // 使用空间
+  appNames: string; // 关联空间
+  documentSize: number; // 文件数量
+  createTime: string; // 创建时间
+  updateTime: string; // 更新时间
+  status: string | number; // 状态
+}
+
+
+const RevisionToolList: React.FC = () => {
+  const [loading, setLoading] = useState(false);
+
+  const { state, init, handleNameChange, onChangePagination } = store;
+
+  const { reviseList, knowledgeName } = state
+
+
+  const [allupdateSliceDoc, setAllupdateSliceDoc] = useState<boolean>(false);
+  const [singleUpdateSliceDoc, setSingleUpdateSliceDoc] = useState<boolean>(false);
+  useEffect(() => {
+    // 模拟加载状态
+    setLoading(true);
+    const t = setTimeout(() => setLoading(false), 250);
+    return () => clearTimeout(t);
+  }, [state.page]);
+  useEffect(() => {
+
+    setAllupdateSliceDoc(LocalStorage.getStatusFlag('knowledge:revisionTool:all'));
+    setSingleUpdateSliceDoc(LocalStorage.getStatusFlag('knowledge:revisionTool:single'));
+
+
+
+    init();
+  }, []);
+
+  const steps = [
+    {
+      title: '选择知识库',
+      description: '选中某个已解析完成的标准规范类知识库',
+      number: 1,
+    },
+    {
+      title: '选择切片,检索相似的切片',
+      description: '切片工具中选择切片,系统将自动检索相似的切片',
+      number: 2,
+    },
+    {
+      title: '人工标记',
+      description: '对目标切片进行快速标记',
+      number: 3,
+    }
+  ]
+  const [showGuide, setShowGuide] = React.useState<boolean>(() => localStorage.getItem('revisionToolGuideHidden') !== 'true');
+  const hideGuide = () => { localStorage.setItem('revisionToolGuideHidden', 'true'); setShowGuide(false); };
+  const [record, setRecord] = useState<KnowledgeRecord>({} as KnowledgeRecord);
+  const columns: ColumnsType<KnowledgeRecord> = [
+    {
+      title: '知识库名称/ID', dataIndex: 'knowledgeName', width: 220,
+      render: (text, record: any) => {
+        return <div>
+          <div style={{ fontWeight: 600 }} className='cursor-pointer text-primary'>{text}</div>
+          <div style={{ color: '#999', fontSize: 12, marginTop: 4 }}>ID: {record?.knowledgeId}
+          </div>
+        </div>
+      },
+    },
+    {
+      title: '关联RAG应用', dataIndex: 'appNames', width: 120, render: (text) => (
+          text.length ? text.map((item: string, index: number) => (
+              <span key={index} className='mr-2'>{item}{index === text.length - 1 ? '' : ','}</span>
+          )) : '-'
+      )
+    },
+    { title: '使用空间', dataIndex: 'length', width: 120 },
+
+    { title: '文件数量', dataIndex: 'documentSize', width: 120 },
+    { title: '创建时间', dataIndex: 'createTime', width: 140 },
+    { title: '更新时间', dataIndex: 'updateTime', width: 140 },
+    {
+      title: '操作',
+      dataIndex: 'status',
+      key: 'status',
+      align: 'center',
+      width: 120,
+      render: (val, record) => (
+        singleUpdateSliceDoc ? <Button type="link" onClick={() => { setOpenDrawer(true); setTitle(record.knowledgeName); setRecord(record); }}>当前知识修订</Button> :
+        '-'
+        // <Button type="link" onClick={() => { setOpenDrawer(true); setTitle(record.knowledgeName); setRecord(record); }}>当前知识修订</Button>
+      ),
+    }
+  ]
+
+  const paginationConfig: TablePaginationConfig = {
+    // 显示数据总量
+    showTotal: (total: number) => {
+      return `共 ${total} 条`;
+    },
+    // 展示分页条数切换
+    showSizeChanger: true,
+    // 指定每页显示条数
+    pageSizeOptions: ['10', '20', '50', '100'],
+    // 快速跳转至某页
+    showQuickJumper: true,
+    current: state.page.page,
+    pageSize: state.page.size,
+    total: state.page.total,
+    onChange: async (page, pageSize) => {
+      await onChangePagination(page, pageSize);
+    },
+  };
+  const [openDrawer, setOpenDrawer] = useState(false);
+  const [title, setTitle] = useState('');
+  return (
+    <div style={{ padding: 20, background: '#fff' }}>
+      {showGuide && <> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
+        <div style={{ fontSize: 13, color: '#333', display: 'flex', alignItems: 'center', gap: 6 }}>
+          <BulbOutlined style={{ color: '#faad14' }} />
+          提示: 如何创建并管理自己的知识库?
+        </div>
+        <CloseOutlined onClick={hideGuide} style={{ color: '#999', cursor: 'pointer' }} />
+      </div>
+        <Step steps={steps} className='mb-3' /></>}
+      <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 12 }}>
+        {allupdateSliceDoc && <Button type="primary" style={{ margin: 0 }} onClick={() => { setOpenDrawer(true); setRecord({} as KnowledgeRecord); setTitle('全局修订工具'); }}>全局修订工具</Button>}
+        <Space.Compact style={{ width: '300px' }}>
+          <Input
+            placeholder='请输入知识库名称进行搜索'
+            value={knowledgeName}
+            onChange={(e) => handleNameChange(e.target.value)}
+          />
+          <Button type="primary" onClick={() => { init() }}><SearchOutlined /></Button>
+        </Space.Compact>
+      </div>
+      {/* 表格 */}
+      <Table
+        columns={columns}
+        dataSource={reviseList}
+        rowKey="knowledgeId"
+        loading={loading}
+        pagination={paginationConfig}
+      />
+      {/* 修订工具弹窗 */}
+      {<ReviseDrawer openDrawer={openDrawer} record={record} title={title} onClose={() => setOpenDrawer(false)} />}
+    </div>
+  );
+};
+
+export default observer(RevisionToolList);

+ 77 - 0
src/pages/deepseek/knowledgeLib/revisionTool/list/store.ts

@@ -0,0 +1,77 @@
+import { action, makeAutoObservable } from 'mobx';
+import { message } from 'antd';
+import LocalStorage from '@/LocalStorage';
+import { fetchReviseToolList } from '@/apis';
+import { downloadFile } from '@/utils/index'
+import { data } from 'react-router-dom';
+
+// 定义状态
+const stateRevise = (): any => ({
+    reviseList: [] as any[],
+    knowledgeName:'',
+    page: {
+        page: 1,
+        size: 10,
+        total: 0,
+    },
+})
+// 修改状态
+const stateActionRevise = (state: any) => {
+
+    return{
+        setPage: (page: { page: number; size: number; total: number }) => {
+            state.page = page;
+        },
+        setKnowledgeName: (knowledgeName: string) => {
+            state.knowledgeName = knowledgeName;
+        },
+    }
+}
+// 使用仓库
+const useRevisionToolListStore = () => {
+    const state = makeAutoObservable(stateRevise());
+    const actions = stateActionRevise(state);
+
+    const onFetchReviseToolList = async () => {
+        try {
+            const data = {
+                pageNum: state.page.page,
+                pageSize: state.page.size,
+                knowledgeName: state.knowledgeName || '',
+            }
+            const res:any = await fetchReviseToolList(data);
+            if (res && res.code === 200) {
+                state.reviseList = res.rows;
+                state.page.total = res.total;
+            } else {
+                message.error(res.message || '获取修订工具列表失败');
+            }
+        } catch (error) {
+            message.error('获取修订工具列表异常');
+        }
+    }
+    const handleNameChange = (name: string) => {
+        actions.setKnowledgeName(name);
+    };
+    const onChangePagination = async (page: number, pageSize: number) => {
+        actions.setPage({
+            ...state.page,
+            page: page,
+            size: pageSize,
+        });
+        await onFetchReviseToolList();
+    }
+
+    const init = ()=>{
+        onFetchReviseToolList()
+    }
+
+
+    return {
+        state,
+        init,
+        handleNameChange,
+        onChangePagination
+    };
+}
+export default useRevisionToolListStore();

+ 434 - 0
src/pages/deepseek/questionAnswer/appPlazaList/index.tsx

@@ -0,0 +1,434 @@
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import {
+  List,
+  Button,
+  Divider,
+  Flex,
+  Layout,
+  Empty,
+  Image,
+  Modal,
+  Tag,
+  message,
+  Tooltip,
+  Select,
+  Form,
+  Space,
+  Row,
+  Col,
+  Input,
+  Cascader,
+  Pagination,
+} from 'antd';
+import {
+  HeartFilled,
+  BookOutlined,
+  TeamOutlined,
+  AppstoreOutlined,
+  HeartOutlined,
+  GlobalOutlined
+} from '@ant-design/icons';
+import { apis } from '@/apis';
+import './style.less';
+import { PaginationConfig } from 'antd/es/pagination';
+import router from '@/router';
+import LocalStorage from '@/LocalStorage';
+import IconSvg from "@/assets/public/icon.svg";
+import bg1 from "@/assets/public/bg1.png";
+const FormItem = Form.Item;
+import * as AllIcons from '@ant-design/icons';
+import { getContrastColor } from '@/utils';
+
+
+const QuestionAnswerList: React.FC = () => {
+  const [form] = Form.useForm();
+
+  interface Item {
+    name: string,
+    desc: string,
+    appId: string,
+    createBy: string,
+    typeId: string;
+    status: string;
+    comment: string;
+    auditStatus: string;
+    projectName: string;
+    updateTime: string;
+    isCollect: boolean;
+    iconType: string;
+    iconColor: string;
+    groupVisible?: string;
+  };
+
+  interface PageInfo {
+    pageNum: number,
+    pageSize: number,
+    total: number,
+  };
+
+  type AppTypeList = {
+    label: string,
+    value: string,
+    dictCode: string,
+  }[];
+
+  type ProjectTypeList = {
+    label: string,
+    value: string,
+  }[];
+
+  const [listLoading, setListLoading] = React.useState(false);
+  const [list, setList] = React.useState<Item[]>([]);
+  const [page, setPage] = React.useState<PageInfo>({
+    pageNum: 1,
+    pageSize: 12,
+    total: 0,
+  });
+  const [appTypeList, setAppTypeList] = React.useState<AppTypeList>([]);
+  const [showSubPanel, setShowSubPanel] = React.useState(false);
+  const [selectedType, setSelectedType] = React.useState<string>('全部');
+  const wrapperRef = React.useRef<HTMLDivElement>(null);
+  const selectRef = React.useRef<any>(null);
+  const [levelTypeList, setLevelTypeList] = React.useState<AppTypeList>([]);
+
+  const appApi = {
+    fetchList: async (typeId: any, projectId: any) => {
+      setListLoading(true);
+      try {
+        const userInfo = LocalStorage.getUserInfo();
+        const userId = (userInfo?.id ?? '').toString();
+        const keyword = form.getFieldValue('keyword');
+        const res = await apis.fetchTakaiAppList({
+          pageSize: page.pageSize,
+          pageNum: page.pageNum,
+          userId: userId,
+          isCollect: typeId==='收藏' ? '1' : null,
+          typeId: typeId==='收藏'|| typeId==='全部' ? null : typeId,
+          projectId: projectId?.toString(),
+          keyword: keyword,
+        })
+        const list = res.rows.map((item: any) => {
+          return {
+            name: item.name,
+            desc: item.desc,
+            appId: item.appId,
+            createBy: item.createBy,
+            typeId: item.typeId,
+            status: item.status,
+            comment: item.comment,
+            auditStatus: item.auditStatus,
+            projectName: item.projectName,
+            updateTime: item.updateTime,
+            isCollect: item.isCollect,
+            iconType: item.iconType,
+            iconColor: item.iconColor,
+            groupVisible: item.groupVisible,
+          }
+        });
+        const c = LocalStorage.getStatusFlag('deepseek:application:create');
+        const u = LocalStorage.getStatusFlag('deepseek:application:delete');
+        const filteredList = list.filter((item: any) => {
+          // 如果有 createFlag 或 updateFlag 权限,显示所有数据
+          if (c || u) {
+            return true;
+          }
+          // 没有权限时排除 status='5' 的数据
+          return item.status !== '5';
+        });
+        setList(filteredList);
+        setPage({
+          pageNum: page.pageNum,
+          pageSize: page.pageSize,
+          total: res.total,
+        });
+      } catch (error) {
+        console.error(error);
+      } finally {
+        setListLoading(false);
+      }
+    },
+
+    auditApplication: async (appId: string, userId: string) => {
+      const res = await apis.auditTakaiApplicationLibApi(appId, userId);
+      if (res.data === 9) {
+        message.error('您没有添加审核人');
+      }
+      await appApi.fetchList(null, null);
+    }
+  };
+
+  // 立即使用应用
+  const useNowAppLication = (appId: string) => {
+    const userInfo = LocalStorage.getUserInfo();
+    const getToken = LocalStorage.getToken();
+    const baseUrl = import.meta.env.VITE_JUMP_URL;
+    // const baseUrl = 'https://llm.jkec.info:11432/#/knowledgeChat?showMenu=false&chatMode=LOCAL'
+    window.open(`${baseUrl}&appId=${appId}&userId=${userInfo?.id}&nickName=${userInfo?.name}&token=${getToken}`, '_blank');
+  }
+
+
+  // 获取应用类型
+  const appTypeApi = {
+    fetchAppType: async () => {
+      try {
+        const res = await apis.fetchTakaiAppTypeList('app_type');
+        const list = res.data.map((item: any) => {
+          return {
+            label: item.dictLabel,
+            value: item.dictValue,
+            dictCode: item.dictCode,
+          }
+        });
+        setAppTypeList([{
+          label: '收藏',
+          value: '收藏',
+          dictCode: '收藏',
+        },{
+          label: '全部',
+          value: '全部',
+          dictCode: '全部',
+        },...list]);
+      } catch (error: any) {
+        console.error(error);
+      }
+    },
+  };
+
+
+
+  // 获取应用类型
+  const levelTypeApi = {
+    fetchLevelAppType: async () => {
+      try {
+        const res = await apis.fetchTakaiAppTypeList('project_type');
+        const list = res.data.map((item: any) => {
+          return {
+            label: item.dictLabel,
+            value: item.dictValue,
+          }
+        });
+        setLevelTypeList(list);
+      } catch (error: any) {
+        console.error(error);
+      }
+    },
+  };
+
+  const init = async () => {
+    await appApi.fetchList(null, null);
+    await appTypeApi.fetchAppType();
+    await levelTypeApi.fetchLevelAppType();
+
+    // 设置默认选择"全部"
+    form.setFieldsValue({ typeId: '全部' });
+  }
+
+  React.useEffect(() => {
+    init();
+  }, [page.pageSize, page.pageNum])
+
+  const paginationConfig: PaginationConfig = {
+    // 显示数据总量
+    showTotal: (total: number) => {
+      return `共 ${total} 条`;
+    },
+    // 展示分页条数切换
+    showSizeChanger: true,
+    // 指定每页显示条数
+    // pageSizeOptions: ['2', '20', '50', '100'],
+    // 快速跳转至某页
+    showQuickJumper: true,
+    current: page.pageNum,
+    pageSize: page.pageSize,
+    total: page.total,
+    onChange: (pageNum, pageSize) => {
+      setPage({
+        pageNum: pageNum,
+        pageSize: pageSize,
+        total: page.total,
+      });
+    },
+  };
+
+  /** 点击外部关闭面板 */
+  React.useEffect(() => {
+    const handleClickOutside = (event: MouseEvent) => {
+      if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) {
+        setShowSubPanel(false);
+      }
+    };
+
+    document.addEventListener('mousedown', handleClickOutside, true);
+    return () => {
+      document.removeEventListener('mousedown', handleClickOutside, true);
+    };
+  }, []);
+
+
+  // Tab切换逻辑
+  const handleTabChange = (key: string) => {
+    setSelectedType(key);
+    form.setFieldsValue({ typeId: key });
+    if (key === '全部') {
+      appApi.fetchList(null, null);
+    } else {
+      appApi.fetchList(key, null);
+    }
+  };
+
+  return (
+    <div className="h-full bg-cover bg-center" style={{ backgroundImage: `url(${bg1})`, overflowX: 'hidden' }}>
+      <div className="flex flex-col items-center justify-center pt-2 pb-5">
+        <Form form={form} layout="inline" colon={false}>
+          <FormItem name="typeId" style={{ marginBottom: 0 }}>
+            <div className="w-full flex justify-center">
+              <div className="w-fit">
+                <div className="flex gap-8 border-b border-transparent">
+                  {/* Tabs */}
+                  {[...appTypeList.map(item => item.value)].map((key, idx) => {
+                    const label = key === '全部'
+                      ? '全部'
+                      : appTypeList.find(i => i.value === key)?.label || key;
+                    const icon = key === '全部'
+                      ? null
+                      : label === '专业知识' ? <BookOutlined className="mr-1" />
+                        : label === '职能管理' ? <TeamOutlined className="mr-1" />
+                          : label === '项目级应用' ? <AppstoreOutlined className="mr-1" />
+                            : null;
+                    const selected = selectedType === key;
+                    return (
+                      <button
+                        key={key}
+                        type="button"
+                        className={`px-6 py-2 text-base font-medium flex items-center justify-center transition-colors duration-200 relative bg-transparent border-none outline-none ${selected ? 'text-blue-600' : 'text-gray-700'} `}
+                        onClick={() => handleTabChange(key)}
+                      >
+                        {icon}
+                        {label}
+                        {selected && (
+                          <span className="absolute left-0 right-0 -bottom-1 h-[3px] bg-blue-600 rounded-full" />
+                        )}
+                      </button>
+                    );
+                  })}
+                </div>
+              </div>
+            </div>
+          </FormItem>
+        </Form>
+      </div>
+      <div className="app-plaza-list flex flex-col items-center justify-center">
+        { (
+          <>
+            <div className="w-full px-8">
+              <div className='overflow-hidden' style={{ height: 'calc(100vh - 155px)', width: '100%', display: 'flex', flexDirection: 'column', boxSizing: 'border-box' }}>
+                {/* 列表滚动区 */}
+                <div className='h-[calc(100%)] overflow-y-auto overflow-x-hidden px-30' style={{ flex: '1 1 auto' }}>
+                  <List
+                    style={{ padding: 0, margin: 0 }}
+                    grid={{
+                      gutter: 36,
+                      xs: 1,
+                      sm: 2,
+                      md: 2,
+                      lg: 3,
+                      xl: 4,
+                      xxl: 4,
+                    }}
+                    dataSource={list}
+                    loading={listLoading}
+                    renderItem={(item) => (
+                      <List.Item style={{ padding: 0 }}>
+                        <div key={item.appId} style={{ boxSizing: 'border-box', width: '100%', minWidth:'290px', padding: '16px 26px' }} className="bg-[#F0F8FF] rounded-xl shadow-md p-6 flex flex-col items-center relative">
+                          {/* 1. 头像居中显示 */}
+                          <div className="flex justify-center items-center mb-4 pt-2">
+                            <div style={{ marginRight: 10, overflow: 'auto', background: item.iconColor, width: 50, height: 50, borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
+                              {item.iconType ? (() => {
+                                const C = (AllIcons as any)[item.iconType];
+                                const iconColor = getContrastColor(item.iconColor);
+                                return C ? <C style={{ fontSize: 28, color: iconColor }} /> : <span style={{ fontSize: 12 }}>{item.iconType}</span>
+                              })()
+                                : <Image
+                                  width={32}
+                                  height={32}
+                                  src={IconSvg}
+                                  preview={false}
+                                />}
+                                </div>
+                            </div>
+                            {/* 2. 名称+类型 */}
+                            <div className="text-left mb-2 w-full">
+                              <div className="font-bold text-[17px] text-gray-900 flex items-center justify-between" title={item.name}>
+                                <Tooltip title={item.name}>
+                                    <p className='truncate w-[68%]'>{item.name.length > 20 ? `${item.name.substring(0, 30)}...` : item.name}</p>
+                                </Tooltip>
+                                {item.groupVisible==='1'&&<p className='font-normal text-[10px]'> <GlobalOutlined /> 集团RAG应用 </p>}
+                              </div>
+                            </div>
+                            {/* 3. 描述,两行高度,溢出省略 */}
+                            <div className="w-full text-gray-700 text-[12px] mb-4 min-h-11 flex items-center">
+                              <Tooltip title={item.desc || '暂无描述'}>
+                                <div className="line-clamp-2 w-full" style={{ minHeight: 40 }}>
+                                  {item.desc || '暂无描述'}
+                                </div>
+                              </Tooltip>
+                            </div>
+                            {/* 4. 底部按钮组 */}
+                            <div className="w-full flex justify-between items-center mt-auto pt-2">
+                              <Tag
+                                style={{
+                                  // padding: '4px 8px',
+                                  marginRight: 0,
+                                  fontSize: 12,
+                                  fontWeight: 600,
+                                  background: '#f8f8f8',
+                                  // border: '1px solid #d9d9d9'
+                                }}
+                              >
+                                {
+                                  appTypeList
+                                    .find(item1 => item1.dictCode.toString() === item.typeId)?.label || levelTypeList.find(item2 => item2.value.toString() === item.typeId)?.label || '未分类'
+                                }
+                              </Tag>
+                                {item.isCollect && <Button size='small' icon={< HeartFilled style={{ color: '#F5E663' }} />} onClick={async () => {
+                                if (item.isCollect) {
+                                  const res: any = await apis.delCollectApi(item.appId);
+                                  if (res.code === 200) {
+                                    message.success('取消收藏成功')
+                                    await appApi.fetchList(selectedType, null);
+                                  }
+                                }
+                              }} >已收藏</Button>}
+                              {!item.isCollect && <Button size='small' icon={<HeartOutlined />} onClick={async () => {
+                                if (!item.isCollect) {
+                                  const res: any = await apis.setCollectApi(item.appId);
+                                  if (res.code === 200) {
+                                    message.success('收藏成功')
+                                    await appApi.fetchList(selectedType, null);
+                                  }
+                                }
+                              }} >收藏</Button>}
+                              <Button size="small" type="primary" className="font-medium" onClick={() => useNowAppLication(item.appId)}>
+                                立即使用
+                              </Button>
+                            </div>
+                          </div>
+                      </List.Item>
+                    )}
+                  />
+                </div>
+                {/* 分页固定在底部 */}
+                <div style={{ paddingTop: 16, display: 'flex', justifyContent: 'end' }}>
+                  <Pagination {...paginationConfig} />
+                </div>
+              </div>
+            </div>
+          </>
+        )}
+      </div>
+    </div>
+  );
+};
+
+export default observer(QuestionAnswerList);

+ 2 - 0
src/pages/deepseek/questionAnswer/appPlazaList/store.ts

@@ -0,0 +1,2 @@
+import { makeAutoObservable } from 'mobx';
+import { apis } from '@/apis';

+ 226 - 0
src/pages/deepseek/questionAnswer/appPlazaList/style.less

@@ -0,0 +1,226 @@
+.questionAnswerList {
+  width: 100%;
+  height: 100%;
+  background: #FFFFFF;
+  border-radius: @border-radius-base;
+  padding: 16px 20px;
+}
+
+.applicationList {
+  width: 100%;
+  min-height: 600px;
+}
+
+.card{
+  padding: 16px;
+  border: 1px solid @border-color;
+  border-radius: @border-radius-large;
+  min-height: 200px;
+  overflow: auto;
+
+  // 默认状态下操作按钮颜色
+  .action-button {
+    color: #999 !important;
+    transition: color 0.3s ease;
+
+    &:hover {
+      color: @primary-color !important;
+    }
+  }
+
+  .delete-button {
+    color: #999 !important;
+    transition: color 0.3s ease;
+
+    &:hover {
+      color: @error-color !important;
+    }
+  }
+}
+.card:hover{
+  box-shadow: 0 0 8px rgba(0,0,0,.1);
+  border: 1px solid @primary-color ;
+
+  // 悬停状态下操作按钮颜色
+  .action-button {
+    color: @primary-color !important;
+  }
+
+  .delete-button {
+    color: @error-color !important;
+  }
+}
+.main-content{
+  // height: calc(100vh - 200px);
+  padding-bottom: 0;
+}
+.desc {
+  height: 56px;
+  overflow: hidden;
+  font-weight: 300; /* 细体字 */
+  line-height: 20px;
+  transition: all 0.3s;
+}
+
+.ant-select-selector {
+  border-radius: 4px !important;
+  background: #fff !important;
+  //height: 32px !important;
+}
+
+.ant-select-dropdown {
+  .ant-select-item-option-selected {
+    background-color: @primary-color !important;
+    color: #fff !important;
+  }
+
+  .ant-select-item-option-active {
+    background-color: rgba(0, 123, 255, 0.1);
+  }
+}
+
+
+
+// 按钮组筛选样式
+.filter-button-group {
+  display: flex;
+  gap: 8px;
+  flex-wrap: wrap;
+
+  .ant-btn {
+    border-radius: 16px;
+    height: 32px;
+    padding: 0 16px;
+    font-size: 14px;
+    font-weight: 400;
+    border: 1px solid #d9d9d9;
+    background-color: #fff;
+    color: #000;
+    transition: all 0.3s ease;
+    display: flex;
+    align-items: center;
+
+    &:hover {
+      transform: translateY(-1px);
+      box-shadow: 0 2px 8px rgba(24, 144, 255, 0.2);
+      border-color: #40a9ff;
+      color: #40a9ff;
+    }
+
+    // 所有选中状态的按钮都使用统一的蓝色主题
+    &.ant-btn-primary {
+      background-color: #1890ff !important;
+      border-color: #1890ff !important;
+      color: #fff !important;
+      font-weight: 500 !important;
+
+      &:hover {
+        background-color: #40a9ff !important;
+        border-color: #40a9ff !important;
+        color: #fff !important;
+      }
+    }
+
+    // 全部按钮特殊样式 - 未选中时
+    &:first-child:not(.ant-btn-primary) {
+      background-color: #f5f5f5;
+      border-color: #d9d9d9;
+      color: #666;
+
+      &:hover {
+        background-color: #e6f7ff;
+        border-color: #40a9ff;
+        color: #40a9ff;
+      }
+    }
+
+    // 图标样式优化
+    .anticon {
+      font-size: 14px;
+      margin-right: 4px;
+      transition: color 0.3s ease;
+      color: #666; // 默认颜色
+    }
+
+    // 悬停时图标颜色变化
+    &:hover .anticon {
+      color: #40a9ff !important;
+    }
+
+    // 选中状态时图标颜色
+    &.ant-btn-primary .anticon {
+      color: #fff !important;
+    }
+
+    // 选中状态悬停时图标颜色
+    &.ant-btn-primary:hover .anticon {
+      color: #fff !important;
+    }
+
+    // 全部按钮未选中时图标颜色
+    &:first-child:not(.ant-btn-primary) .anticon {
+      color: #666;
+    }
+
+    // 全部按钮悬停时图标颜色
+    &:first-child:not(.ant-btn-primary):hover .anticon {
+      color: #40a9ff;
+    }
+  }
+}
+
+// 响应式处理
+@media (max-width: 768px) {
+  .filter-button-group {
+    gap: 6px;
+
+    .ant-btn {
+      font-size: 12px;
+      padding: 0 12px;
+      height: 28px;
+    }
+  }
+}
+
+@media (max-width: 480px) {
+  .filter-button-group {
+    gap: 4px;
+
+    .ant-btn {
+      font-size: 11px;
+      padding: 0 8px;
+      height: 24px;
+      border-radius: 12px;
+    }
+  }
+}
+
+// 圆形按钮样式优化
+.ant-btn-circle {
+  width: 32px;
+  height: 32px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  transition: all 0.3s ease;
+
+  &:hover {
+    transform: translateY(-1px);
+    box-shadow: 0 2px 8px rgba(24, 144, 255, 0.2);
+  }
+
+  .anticon {
+    font-size: 14px;
+  }
+}
+
+// 将 List 的内置 loading 居中显示在组件滚动区域中
+.app-plaza-list {
+  .ant-list {
+    height: 100vh;
+    .ant-spin-nested-loading,.ant-spin-container{
+      height: 100%;
+    }
+  }
+}

+ 140 - 0
src/pages/deepseek/questionAnswer/info/README.md

@@ -0,0 +1,140 @@
+# 提示词模板配置系统
+
+## 概述
+
+这个配置系统用于管理问答应用中的提示词模板,避免在代码中硬编码长文本,提高代码的可维护性和可扩展性。
+
+## 文件结构
+
+```
+src/pages/deepseek/questionAnswer/info/
+├── promptTemplates.ts    # 提示词模板配置文件
+├── index.tsx            # 主组件文件
+└── README.md           # 说明文档
+```
+
+## 使用方法
+
+### 1. 基本使用
+
+```typescript
+import { DEFAULT_PROMPT_TEMPLATE, getPromptTemplate } from './promptTemplates';
+
+// 使用默认模板
+const defaultPrompt = DEFAULT_PROMPT_TEMPLATE;
+
+// 使用特定模板
+const chatPrompt = getPromptTemplate('CHAT_ASSISTANT');
+```
+
+### 2. 在组件中使用
+
+```typescript
+import { DEFAULT_PROMPT_TEMPLATE } from './promptTemplates';
+
+// 在FormItem中使用
+<FormItem 
+  name='prompt'
+  initialValue={DEFAULT_PROMPT_TEMPLATE}
+  rules={[{ required: true, message: '提示词不能为空' }]}
+>
+  <TextArea placeholder="提示词" rows={50} />
+</FormItem>
+```
+
+### 3. 添加新的提示词模板
+
+在 `promptTemplates.ts` 中添加新的模板:
+
+```typescript
+export const PROMPT_TEMPLATES = {
+  // 现有模板...
+  
+  // 新增模板
+  CUSTOM_ASSISTANT: `你是一个自定义助手,请根据以下要求提供服务:
+
+用户需求: {{用户}}
+参考文档: {{知识}}
+
+请按照要求完成任务。`
+};
+```
+
+### 4. 验证和格式化
+
+```typescript
+import { 
+  validatePromptTemplate, 
+  formatPromptTemplate 
+} from './promptTemplates';
+
+// 验证模板是否包含必要占位符
+const isValid = validatePromptTemplate(template);
+
+// 格式化模板(替换占位符)
+const formattedPrompt = formatPromptTemplate(
+  template, 
+  '知识库内容', 
+  '用户输入'
+);
+```
+
+## 模板类型
+
+| 类型 | 描述 | 用途 |
+|------|------|------|
+| `KNOWLEDGE_RETRIEVAL_ASSISTANT` | 知识检索助手 | 基于知识库内容回答问题 |
+| `CHAT_ASSISTANT` | 聊天助手 | 提供友好的对话服务 |
+| `DOCUMENT_SUMMARY` | 文档总结 | 提取文档关键信息 |
+| `CODE_ASSISTANT` | 代码助手 | 提供代码解决方案 |
+| `TRANSLATION_ASSISTANT` | 翻译助手 | 多语言翻译服务 |
+
+## 占位符说明
+
+- `{{知识}}`: 知识库内容占位符
+- `{{用户}}`: 用户输入占位符
+
+## 最佳实践
+
+1. **保持模板简洁**: 避免在模板中包含过多的逻辑判断
+2. **使用占位符**: 统一使用 `{{知识}}` 和 `{{用户}}` 占位符
+3. **添加描述**: 为每个模板添加清晰的描述
+4. **验证模板**: 使用 `validatePromptTemplate` 验证模板格式
+5. **版本控制**: 对模板的修改进行版本控制
+
+## 扩展功能
+
+### 动态模板选择
+
+可以添加一个下拉选择器让用户选择不同的提示词模板:
+
+```typescript
+import { 
+  getAvailableTemplateTypes, 
+  PROMPT_TEMPLATE_DESCRIPTIONS 
+} from './promptTemplates';
+
+const templateTypes = getAvailableTemplateTypes();
+
+<Select 
+  placeholder="选择提示词模板"
+  onChange={(value) => setSelectedTemplate(value)}
+>
+  {templateTypes.map(type => (
+    <Option key={type} value={type}>
+      {PROMPT_TEMPLATE_DESCRIPTIONS[type]}
+    </Option>
+  ))}
+</Select>
+```
+
+### 模板预览
+
+可以添加模板预览功能,让用户在应用前查看模板内容。
+
+## 注意事项
+
+1. 修改模板后需要重新测试应用功能
+2. 确保所有模板都包含必要的占位符
+3. 保持模板的向后兼容性
+4. 定期审查和更新模板内容

+ 482 - 0
src/pages/deepseek/questionAnswer/info/component/IconPicker.tsx

@@ -0,0 +1,482 @@
+import React from 'react';
+import { Modal, Input, Row, Col } from 'antd';
+import * as AllIcons from '@ant-design/icons';
+import { SearchOutlined } from '@ant-design/icons';
+
+type Props = {
+  open: boolean;
+  onClose: () => void;
+  onSelect: (iconName: string) => void;
+  value?: string | null;
+};
+
+const IconPicker: React.FC<Props> = ({ open, onClose, onSelect, value }) => {
+  const [keyword, setKeyword] = React.useState('');
+
+  // 需要排除的图标黑名单(字符串数组)
+  const blacklist = [
+    'AccountBookFilled',
+    'AccountBookOutlined',
+    'AccountBookTwoTone',
+    'AlipayCircleFilled',
+    'AlipayCircleoutlined',
+    'AlipayOutined',
+    'AlipaySquareFilled',
+    'AlibabaOutlined',
+    'AliwangwangFilled',
+    'AliwangwangOutlined',
+    'AliyunOutlined',
+    'AmazonCircleFilled',
+    'AmazonOutlined',
+    'AmazonSquareFilled',
+    'AndroidFilled',
+    'AndroidOutlined',
+    'Applefilled',
+    'AppleOutlined',
+    'ArrowDownOutlined',
+    'ArrowLeftOutlined',
+    'ArrowRightOutlined',
+    'ArrowUpOutlined',
+    'ArrowsAltOutlined',
+    'BackwardFilled',
+    'BackwardOutlined',
+    'BaiduOutlined',
+    'BehanceCircleFilled',
+    'BehanceOutlined',
+    'BehanceSquareFilled',
+    'BehanceSquareOutlined',
+    'Bilibilifilled',
+    'BilibilioOutined',
+    'BugFilled',
+    'BugOutined',
+    'BugTwoTone',
+    'Carfilled',
+    'CarOutined',
+    'CarTwoTone',
+    'CaretDownFilled',
+    'CaretDownOutlined',
+    'Caretleftfilled',
+    'CaretleftOutlined',
+    'CaretRightFilld',
+    'CaretRightOutlined',
+    'CaretUpFilled',
+    'CaretUpoutlined',
+    'CarryOutFilled',
+    'Carryoutoutined',
+    'CarryOutTwoTone',
+    'CheckCircleFilled',
+    'Checkcircleoutlined',
+    'CheckCircleTwoTone',
+    'CheckOutined',
+    'CheckSquare',
+    'ChromeFilled',
+    'ChromeOutlined',
+    'CiCircleFilledFilled',
+    'CheckSquareTwoTone',
+    'Cicircleoutlined',
+    'CiCircleTwoTone',
+    'Cioutlined',
+    'CiTwoTone',
+    'ClearOutlined',
+    'ClockCirclefill',
+    'ClockCircleOutined',
+    'ClockCircleTwoTone',
+    'CloseCirclefilled',
+    'CloseCircleOutlined',
+    'CloseCircleTwoTone',
+    'CloseOutlined',
+    'CloseSquareFilled',
+    'CloseSquareoutlined',
+    'CloseSquareTwoTone',
+    'CloudDownloadOutlined',
+    'CloudFilled',
+    'Cloudoutined',
+    'CloudServeroutlined',
+    'CloudSyncOutlined',
+    'CloudTwoTone',
+    'CloudUploadOutlined',
+    'ClusterOutlined',
+    'CreditCardFilled',
+    'Creditcardoutined',
+    'CreditCardTwoTone',
+    'DingdingOutlined',
+    'DingtalkCircleFilled',
+    'DingtalkOutlined',
+    'DingtalkSquareFilled',
+    'DislikeOutined',
+    'DislikeTwoTone',
+    'DockerOutlined',
+    'DollarCircleFlilled',
+    'DiscordFilled',
+    'DislikeFilled',
+    'DislikeOutine',
+    'DislikeTwoToned',
+    'DollarCircleOutlined',
+    'DollarCircleTwoTone',
+    'DollarOutlined',
+    'DollarTwoTone',
+    'DotNetOutlined',
+    'DoubleLeftOutlined',
+    'DoubleRightoutlined',
+    'DownCircleFilled',
+    'DownCircleOutlined',
+    'DownCircleTwoTone',
+    'DownOutlined',
+    'DownSquareFilled',
+    'DownSquareOutined',
+    'DownSquareTwoTone',
+    'DownloadOut!ined',
+    'DragOutlined',
+    'DribbbleCircleFilled',
+    'DribbbleOutined',
+    'DribboleSquareFilled',
+    'DribbbleSquareOutlined',
+    'DropboxCircleFilled',
+    'DropboxOutlined',
+    'DropboxSquar efilled',
+    'Editfilled',
+    'EditOutlined',
+    'EditTwoTone',
+    'EllipsisOutline',
+    'EnterOutlined',
+    'EnvironmentFilled',
+    'Environmentoutlined',
+    'EnvironmentTwoTone',
+    'EuroCircleFille  EuroCircleOutl',
+    'EuroCircleTwo',
+    'EuroOutlined',
+    'ined',
+    'ExceptionOutl ined',
+    'ExclamationCi rclefilled',
+    'ExclamationCi rcleOutlined',
+    'FacebookFille',
+    'FacebookOutlined',
+    'GithubFilled',
+    'Githuboutine',
+    'GitlabFilled',
+    'GitlabOutlined',
+    'GoogleCircleF illed',
+    'GoogleOutlined',
+    'GooglePlusCir clelilled',
+    'GooglePlusOu tlined',
+    'GooglePlusSq uareFilled',
+    'GoogleSquare',
+    'Htm15Filled',
+    'Html50utlined',
+    'PinterestFilled',
+    'PinterestOutli ned',
+    'PlayCircleFilled',
+    'Html5TwoToneFilled',
+    'WeibocircleFilled',
+    'WeiboCircleoutlined',
+    'WeiboOutline',
+    'WeiboSquareFilled',
+    'WeiboSquare',
+    'WifiOutlined',
+    'WindowsFilledOutlined',
+    'WhatsAppOutlined',
+    'WindowsOutlined',
+    'WomanOutlined',
+    'Xfilled',
+    'XOutlined',
+    'Yahoofilled',
+    'YahooOutline',
+    'Youtubefilled',
+    'YoutubeOutlined',
+    'Yuquefilled',
+    'YuqueOutlined',
+    'ZhihuCircleFilled',
+    'ZhihuOutlined',
+    'ZhihuSquareFilled',
+    'ZoomInOutlined',
+    'ZoomOutOutlined',
+    'TwitchFilled',
+    'TwitchOutlined',
+    'TwitterCircleFilled',
+    'TwitterOutlined',
+    'TwitterSquare',
+    'UndoOutlinedFilled',
+    'UnderlineOutlined',
+    'QqCircleFilled',
+    'QqOutlined',
+    'QqSquareFilled',
+    'AlipayCircleOutlined',
+    'AlipayOutlined',
+    'AppleFilled',
+    'BankFilled',
+    'BankOutlined',
+    'BankTwoTone',
+    'BilibiliFilled',
+    'BilibiliOutlined',
+    'BoldOutlined',
+    'BugOutlined',
+    'CarFilled',
+    'CarOutlined',
+    'CaretLeftFilled',
+    'CaretLeftOutlined',
+    'CaretRightFilled',
+    'CaretUpOutlined',
+    'CarryOutOutlined',
+    'CheckCircleOutlined',
+    'CheckOutlined',
+    'CheckSquareFilled',
+    'CheckSquareOutlined',
+    'CiCircleFilled',
+    'CiCircleOutlined',
+    'CiOutlined',
+    'CloseCircleFilled',
+    'CloseSquareOutlined',
+    'CodepenCircleFilled',
+    'CodepenCircleOutlined',
+    'CodepenOutlined',
+    'CodepenSquareFilled',
+    'ColumnHeightOutlined',
+    'ColumnWidthOutlined',
+    'CopyrightCircleFilled',
+    'CopyrightCircleOutlined',
+    'CopyrightCircleTwoTone',
+    'CopyrightOutlined',
+    'CopyrightTwoTone',
+    'CreditCardOutlined',
+    'DeleteColumnOutlined',
+    'DeleteFilled',
+    'DeleteOutlined',
+    'DeleteRowOutlined',
+    'DeleteTwoTone',
+    'DeliveredProcedureOutlined',
+    'DisconnectOutlined',
+    'DiscordOutlined',
+    'DislikeOutlined',
+    'DollarCircleFilled',
+    'DoubleRightOutlined',
+    'DownSquareOutlined',
+    'DownloadOutlined',
+    'DribbbleOutlined',
+    'DribbbleSquareFilled',
+    'DropboxSquareFilled',
+    'EditFilled',
+    'EllipsisOutlined',
+    'EuroCircleFilled',
+    'EuroCircleOutlined',
+    'EuroCircleTwoTone',
+    'ExceptionOutlined',
+    'ExclamationCircleFilled',
+    'ExclamationCircleOutlined',
+    'ExclamationCircleTwoTone',
+    'ExclamationOutlined',
+    'ExpandAltOutlined',
+    'ExpandOutlined',
+    'ExportOutlined',
+    'EyeFilled',
+    'EyeInvisibleFilled',
+    'EyeInvisibleOutlined',
+    'EyeInvisibleTwoTone',
+    'FacebookFilled',
+    'FallOutlined',
+    'FastBackwardFilled',
+    'FastBackwardOutlined',
+    'FastForwardFilled',
+    'FastForwardOutlined',
+    'FieldBinaryOutlined',
+    'FieldNumberOutlined',
+    'FieldStringOutlined',
+    'FileAddFilled',
+    'FileAddOutlined',
+    'FileAddTwoTone',
+    'FileGifOutlined',
+    'FileJpgOutlined',
+    'FileUnknownFilled',
+    'FileUnknownOutlined',
+    'FileUnknownTwoTone',
+    'FolderAddFilled',
+    'FolderAddOutlined',
+    'FolderAddTwoTone',
+    'FormOutlined',
+    'ForwardFilled',
+    'ForwardOutlined',
+    'FrownFilled',
+    'FrownOutlined',
+    'FrownTwoTone',
+    'FullscreenExitOutlined',
+    'GifOutlined',
+    'GithubOutlined',
+    'GooglePlusOutlined',
+    'GoogleCircleFilled',
+    'GooglePlusCircleFilled',
+    'Html5Filled',
+    'Html5Outlined',
+    'IeSquareFilled',
+    'ImportOutlined',
+    'Html5TwoTone',
+    'IdcardFilled',
+    'IdcardOutlined',
+    'InfoCircleFilled',
+    'InfoCircleOutlined',
+    'InfoCircleTwoTone',
+    'InfoOutlined',
+    'ItalicOutlined',
+    'JavaOutlined',
+    'JavaScriptOutlined',
+    'KubernetesOutlined',
+    'LaptopOutline',
+    'LeftCircleFilled',
+    'LeftCircleOutlined',
+    'LeftCircleTwoTone',
+    'LeftOutlined',
+    'LinkedinFilled',
+    'LinkedinOutlined',
+    'LinuxOutlined',
+    'LoadingOutlined',
+    'Loading3QuartersOutlined',
+    'LoginOutlined',
+    'LogoutOutlined',
+    'ManOutlined',
+    'MediumCircleFilled',
+    'MediumOutlined',
+    'MediumSquareFilled',
+    'MediumWorkmarkOutlined',
+    'MehFilled',
+    'MehOutlined',
+    'MehTwoTone',
+    'MenuFoldOutlined',
+    'MenuOutlined',
+    'MenuUnfoldOutlined',
+    'MinusCircleFilled',
+    'MinusCircleOutlined',
+    'MinusCircleTwoTone',
+    'MinusOutlined',
+    'MoneyCollectFilled',
+    'MoneyCollectOutlined',
+    'MoneyCollectTwoTone',
+    'OrderedListOutlined',
+    'PayCircleFilled',
+    'PayCircleOutlined',
+    'PercentageOutlined',
+    'PinterestOutlined',
+    'PlusCircleFilled',
+    'PlusCircleOutlined',
+    'PlusCircleTwoTone',
+    'PlusOutlined',
+    'PlusSquareFilled',
+    'PlusSquareOutlined',
+    'PlusSquareTwoTone',
+    'PoundCircleFilled',
+    'PoundCircleOutlined',
+    'PoundCircleTwoTone',
+    'PoundOutlined',
+    'PropertySafetyFilled',
+    'PropertySafetyOutlined',
+    'PropertySafetyTwoTone',
+    'QuestionCircleFilled',
+    'QuestionCircleOutlined',
+    'QuestionCircleTwoTone',
+    'QuestionOutlined',
+    'RedEnvelopeFilled',
+    'RedEnvelopeOutlined',
+    'RedEnvelopeTwoTone',
+    'RedditCircleFilled',
+    'RedditOutlined',
+    'RedditSquareFilled',
+    'RedoOutlined',
+    'ReloadOutlined',
+    'RestFilled',
+    'RestOutlined',
+    'RestTwoTone',
+    'ShoppingCartOutlined',
+    'ShoppingFilled',
+    'ShoppingOutlined',
+    'ShoppingTwoTone',
+    'ShrinkOutlined',
+    'SkypeFilled',
+    'SkypeOutlined',
+    'SlackCircleFilled',
+    'SlackOutlined',
+    'SlackSquareFilled',
+    'SlackSquareOutlined',
+    'SmallDashOutlined',
+    'SpotifyFilled',
+    'SpotifyOutlined',
+    'StarFilled',
+    'StarOutlined',
+    'StarTwoTone',
+    'StepBackwardFilled',
+    'StepBackwardOutlined',
+    'TaobaoCircleFilled',
+    'TaobaoCircleOutlined',
+    'TaobaoOutlined',
+    'TaobaoSquareFilled',
+    'TikTokFilled',
+    'TikTokOutlined',
+    'ToTopOutlined',
+    'TwitterSquare',
+    'UndoOutlined',
+    'VerticalAlignBottomOutlined',
+    'VerticalAlignMiddleOutlined',
+    'VerticalAlignTopOutlined',
+    'WechatFilled',
+    'WechatOutlined',
+    'WechatWorkFilled',
+    'WechatWorkOutlined',
+    'WeiboCircleFilled',
+    'WeiboCircleOutlined',
+    'WeiboOutlined',
+    'WeiboSquareOutlined',
+    'WindowsFilled',
+    'XFilled',
+    'YahooFilled',
+    'YahooOutlined',
+    'YoutubeFilled',
+    'YuqueFilled'
+  ];
+
+  const icons = React.useMemo(() => {
+    return Object.keys(AllIcons)
+      .filter((name) => {
+        if (name === 'default' || name === 'IconProvider' || blacklist.includes(name)) return false;
+        return /^[A-Z].*/.test(name);
+      })
+      .filter((name) => name.toLowerCase().includes(keyword.toLowerCase()));
+  }, [keyword]);
+
+  return (
+    <Modal title="选择图标" open={open} onCancel={onClose} footer={null} width={800}>
+      <Input
+        placeholder="搜索图标名称"
+        prefix={<SearchOutlined />}
+        allowClear
+        value={keyword}
+        onChange={(e) => setKeyword(e.target.value)}
+        style={{ marginBottom: 12 }}
+      />
+      <div style={{ maxHeight: '60vh', overflow: 'auto' }}>
+        <Row gutter={[8, 8]}>
+          {icons.map((name) => {
+            const Comp = (AllIcons as any)[name];
+            if (!Comp) return null;
+            return (
+              <Col key={name} span={3} style={{ textAlign: 'center' }}>
+                <div
+                  style={{
+                    padding: 8,
+                    border: value === name ? '1px solid #1677ff' : '1px solid transparent',
+                    borderRadius: 6,
+                    cursor: 'pointer',
+                  }}
+                  onClick={() => {
+                    onSelect(name);
+                    onClose();
+                  }}
+                >
+                  <Comp style={{ fontSize: 24 }} />
+                  <div style={{ fontSize: 10, marginTop: 6, wordBreak: 'break-word' }}>{name}</div>
+                </div>
+              </Col>
+            );
+          })}
+        </Row>
+      </div>
+    </Modal>
+  );
+};
+
+export default IconPicker;

+ 1575 - 0
src/pages/deepseek/questionAnswer/info/index.tsx

@@ -0,0 +1,1575 @@
+import * as React from 'react';
+import { useLocation, useNavigate } from 'react-router-dom';
+import { observer } from 'mobx-react';
+import './style.less';
+import {
+    Button, Input, Form, Divider, Splitter, Select, InputNumber, InputNumberProps,
+    Radio, Switch, Row, Col, Slider, Space, RadioChangeEvent,
+    Spin, message, Typography, Tooltip,
+    Cascader,
+    Tag, Modal, Table, TablePaginationConfig, Drawer, ColorPicker
+} from 'antd';
+import type { TableProps } from 'antd';
+
+import { PlusCircleOutlined, MinusCircleOutlined, ArrowLeftOutlined, InfoCircleOutlined, CloseCircleOutlined, LinkOutlined, FileDoneOutlined } from '@ant-design/icons';
+import * as AllIcons from '@ant-design/icons';
+import IconPicker from './component/IconPicker';
+import { apis } from '@/apis';
+import router from '@/router';
+import LocalStorage from '@/LocalStorage';
+import Chat from '@/components/chat';
+import store from './store';
+import DrawerIndex from '@/pages/deepseek/knowledgeLib/detail/drawerIndex'
+import { values } from 'mobx';
+
+const { TextArea } = Input;
+const FormItem = Form.Item;
+const { Option } = Select;
+const MAX_COUNT = 5;
+
+const QuestionAnswerInfo: React.FC = () => {
+
+    const { state, onChangePagination, onFetchUserListApi } = store;
+    const { page, sourceData } = state;
+    const navigate = useNavigate();
+
+
+    const [form] = Form.useForm();
+    const [iconPickerVisible, setIconPickerVisible] = React.useState(false);
+    const [selectedIcon, setSelectedIcon] = React.useState<string | null>(null);
+    const [previewBg, setPreviewBg] = React.useState<string>('#ffffff');
+
+    const getContrastColor = (hex: string) => {
+        // remove #
+        const c = hex.replace('#', '');
+        const r = parseInt(c.substring(0, 2), 16);
+        const g = parseInt(c.substring(2, 4), 16);
+        const b = parseInt(c.substring(4, 6), 16);
+        // relative luminance
+        const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
+        return luminance > 0.6 ? '#000' : '#fff';
+    }
+
+    const presetColors = ['#1677ff', '#52c41a', '#fa8c16', '#f5222d', '#722ed1', '#ffffff', '#f0f0f0'];
+    const presetItems = [{ label: '', colors: presetColors }];
+
+    // top_p
+    const [topPValue, setTopPValue] = React.useState(0.1);
+    const [topKValue, setTopKValue] = React.useState(1);
+
+
+    const TopPDecimalStep: React.FC = () => {
+
+        const onChange: InputNumberProps['onChange'] = (value) => {
+            if (Number.isNaN(value)) {
+                return;
+            }
+            setTopPValue(value as number);
+        };
+
+        return (
+            <Row>
+                <Col span={12}>
+                    <Slider
+                        min={0}
+                        max={1}
+                        onChange={onChange}
+                        // value={typeof topPValue === 'number' ? topPValue : 0}
+                        value={topPValue}
+                        step={0.1}
+                    />
+                </Col>
+                <Col span={4}>
+                    <InputNumber
+                        min={0}
+                        max={1}
+                        className='form-input-number-small'
+                        step={0.01}
+                        value={topPValue}
+                        onChange={onChange}
+                    />
+                </Col>
+            </Row>
+        );
+    };
+    const [tempValue, setTempValue] = React.useState(0.01);
+    // temperature
+    const TempDecimalStep: React.FC = () => {
+        const onChange: InputNumberProps['onChange'] = (value) => {
+            if (Number.isNaN(value)) {
+                return;
+            }
+            setTempValue(value as number);
+        };
+
+        return (
+            <Row>
+                <Col span={12}>
+                    <Slider
+                        min={0}
+                        max={1}
+                        onChange={onChange}
+                        // value={typeof tempValue === 'number' ? tempValue : 0}
+                        value={tempValue}
+                        step={0.01}
+                    />
+                </Col>
+                <Col span={4}>
+                    <InputNumber
+                        min={0}
+                        max={1}
+                        className='form-input-number-small'
+                        step={0.01}
+                        value={tempValue}
+                        onChange={onChange}
+                    />
+                </Col>
+            </Row>
+        );
+    };
+
+    type ModelList = {
+        label: string,
+        value: string,
+    }[];
+
+    type KnowledgeList = {
+        label: string,
+        value: string,
+        createBy: string,
+    }[];
+
+    type AppTypeList = {
+        label: string,
+        value: string,
+        children: {
+            label: string,
+            value: string,
+        }[],
+    }[];
+    const tagRender = (props: any) => {
+        const { label, value, closable, onClose } = props;
+        return (
+            <Tag
+                color="blue"
+                closable={closable}
+                onClose={onClose} // 保留原有的删除事件
+                style={{ marginRight: 4 }}
+            >
+                {label}
+                {/* 在删除按钮后添加自定义图标 */}
+                <LinkOutlined style={{
+                    marginLeft: 4,
+                    fontSize: 12,
+                    cursor: 'pointer',
+                    color: '#FF9500',
+                    fontWeight: 'bold',
+                }}
+                    onMouseDown={(e) => {
+                        e.stopPropagation();
+                        e.preventDefault();
+                    }}
+                    onMouseUp={(e) => {
+                        e.stopPropagation();
+                        e.preventDefault();
+                    }}
+                    // 自定义图标点击事件
+                    onClick={(e) => {
+                        // 阻止事件冒泡到Tag,避免触发删除
+                        e.stopPropagation();
+                        e.preventDefault();
+                        knowledgeList.forEach((item) => {
+                            if (item.value === value) {
+                                // router.navigate({ pathname: `/deepseek/knowledgeLib/${value}/${item.createBy}`,},);
+                                setDrawerItem(item);
+                                setOpenDrawer(true)
+                                e.stopPropagation();
+                            }
+                        });
+                        // console.log('点击了额外图标,当前选项值:', value,props);
+                        // 这里可以添加你的业务逻辑,如:打开详情、编辑等
+                    }} />
+            </Tag>
+        );
+    };
+
+    const [step, setStep] = React.useState(1);
+    const [pageLoading, setPageLoading] = React.useState(false);
+    const [modelList, setModelList] = React.useState<ModelList>([]);
+    const [knowledgeList, setKnowledgeList] = React.useState<KnowledgeList>([]);
+    const [isVisible, setIsVisible] = React.useState(true);
+    const [isVisibleCus, setIsVisibleCus] = React.useState(false);
+    const [isVisibleSlice, setIsVisibleSlice] = React.useState(false);
+    const [isVisibleRerank, setIsVisibleRerank] = React.useState(true);
+    const [isDeepThinkVisible, setIsDeepThinkVisible] = React.useState(true);
+    const [name, setName] = React.useState('');
+    const [appTypeList, setAppTypeList] = React.useState<AppTypeList>([]);
+    const [appVisibleList, setAppVisibleList] = React.useState<AppTypeList>([]); // 是否公开
+    const [visibleFlag, setVisibleFlag] = React.useState<string | number>(0); // 是否公开用来判断是否展示VIP用户
+    const [updateFlag, setUpdateFlag] = React.useState<boolean>();
+    const [createFlag, setCreateFlag] = React.useState<boolean>();
+    const [appProjectList, setAppProjectList] = React.useState<AppTypeList>([]);
+    const [isAppPro, setIsAppPro] = React.useState<boolean>(false);
+    const [appId, setAppId] = React.useState<string>('');
+    const [fetchUserTypeList, setFetchUserTypeList] = React.useState<AppTypeList>([]); // 用户类型
+    const [userName, setUserName] = React.useState<string>(''); // 用户名
+    const [userNickName, setUserNickName] = React.useState<string>(''); // 用户昵称
+    const [userType, setUserType] = React.useState<string>(''); // 用户类型
+    const [vipList, setVipList] = React.useState<any>([]); // 用户列表
+    const [infoDetail, setinfoDetail] = React.useState<any>(null);// 知识库详情
+    const [parameter,setParameter] = React.useState<any>(null);
+    const style: React.CSSProperties = {
+        display: 'flex',
+        flexDirection: 'column',
+        gap: 8,
+        width: 300,
+    };
+    const userInfo = LocalStorage.getUserInfo();
+    const userId = (userInfo?.id ?? '').toString();
+
+    const location = useLocation();
+
+    const [modeList,setModeList] = React.useState<any>([]); // 模型列表数据
+    const [modeOldList,setModeOldList] = React.useState<any>([]); // 模型列表数据(原始)
+    // 获取调用模型的列表数据
+    const onFetchRerankModelList = async () => {
+        const res = await apis.fetchRerankModelList();
+        if(res && res.data){
+            const list = res.data.map((item: any) => {
+                return {
+                    label: item.model,
+                    value: item.model,
+                }
+            })
+            setModeList(list);
+            setModeOldList(res.data);
+        }
+    }
+
+
+
+    const init = async (id: string) => {
+        await Promise.all([
+            api.fetchKnowlegde(),
+            api.fetchAppType(),
+            // api.fetchModelList(),
+            api.fetchAppProType(),
+            api.fetchAppVisible(id)
+        ])
+        if (id) {
+            await api.fetchDetail(id);
+        }
+        onFetchUserListApi('', '', '');
+        onFetchRerankModelList();
+        await api.fetchUserType();
+    }
+    React.useEffect(() => {
+        const id = location?.state?.id;
+        init(id);
+        const uFlag = LocalStorage.getStatusFlag('deepseek:application:update');
+        setUpdateFlag(uFlag);
+        setParameter(LocalStorage.getStatusFlag('appCenter:questionAnswer:parameter'));
+        setEditPrompt(LocalStorage.getStatusFlag('appCenter:questionAnswer:parameter'))
+        setCreateFlag(true);
+    }, []);
+
+    // 定义一个状态来存储输入框数组
+    const [inputs, setInputs] = React.useState([{ id: 1, value: '' }]);
+
+
+
+    // 添加新输入框的函数
+    const addInput = () => {
+        const newId = inputs.length + 1; // 生成新的唯一ID
+        setInputs([...inputs, { id: newId, value: '' }]);
+    };
+
+    // 删除输入框(按id删除+最少数量限制)
+    const delInput = (id: number) => {
+        if (inputs.length <= 1) {
+            message.warning("至少保留1个预设问题");
+            return;
+        }
+        setInputs(inputs.filter(input => input.id !== id));
+    };
+
+    // 处理输入变更的函数
+    const handleChange = (id: number, value: string) => {
+        setInputs(inputs.map(input => (input.id === id ? { ...input, value } : input)));
+    };
+
+    const handleAppChange = (typeId: number) => {
+        console.log('typeId', typeId)
+        if (typeId === 62) { // 根据实际值进行判断
+            setIsAppPro(true);
+        } else {
+            setIsAppPro(false);
+        }
+    };
+
+
+    const onChangeShow = (checked: boolean) => {
+        console.log(`switch to ${checked}`);
+    };
+
+    const onChangeCount = (value: string) => {
+        if (value === 'fixed') {
+            setIsVisibleSlice(!isVisibleSlice);
+        } else {
+            setIsVisibleSlice(false);
+        }
+    };
+
+    // 召回方式
+    const onChangeRecallMethod = (e: RadioChangeEvent) => {
+
+    };
+
+    // 获取应用详情
+    const api = {
+        fetchDetail: async (app_id: string) => {
+            setPageLoading(true);
+            try {
+                const res = await apis.fetchTakaiApplicationDetail(app_id);
+                const sd = res.data.questionlist.map((item: any, index: number) => {
+                    return {
+                        "id": index + 1,
+                        "value": item.question,
+                    }
+                });
+
+                const info = res.data.detail;
+
+                setAppId(info.appId);
+
+                setTopPValue(info.topP as number);
+                setTempValue(info.temperature as number);
+                setName(info.name);
+                setinfoDetail(res.data);
+                interface Item2 {
+                    index_type_id: number,
+                    knowledge_id: string
+                }
+
+                interface Item {
+                    show_recall_result: boolean,
+                    recall_method: string,
+                    rerank_status: boolean,
+                    slice_config_type: string,
+                    slice_count: number,
+                    param_desc: string,
+                    rerank_model_name: string,
+                    is_multi_round: string,
+                    multi_round: string,
+                    rerank_index_type_list: [Item2],
+                    recall_index_type_list: [Item2]
+                }
+
+                const data_info: Item = JSON.parse(info.knowledgeInfo);
+
+                if (data_info.param_desc === 'custom') {
+
+                    setIsVisibleCus(!isVisibleCus);    //自定义回答风格
+                }
+                if (data_info.rerank_status === true) {
+                    setIsVisibleRerank(data_info.rerank_status) //模型
+                }
+                //召回切片数量
+                if (data_info.slice_config_type === 'fixed') {
+                    setIsVisibleSlice(!isVisibleSlice);
+                } else {
+                    setIsVisibleSlice(false);
+                }
+
+                if (info.typeId === 62) {
+                    setIsAppPro(true);
+                } else {
+                    setIsAppPro(false);
+                }
+
+                if (info.model === 'Qwen3-30B') {
+                    setIsDeepThinkVisible(true);
+                } else {
+                    setIsDeepThinkVisible(false);
+                }
+
+                form.setFieldsValue({
+                    id: info.id,
+                    name: info.name,  //应用名称
+                    desc: info.desc,  //应用描述
+                    prompt: info.prompt, //应用提示语
+                    topP: info.topP as string, //topP
+                    topK: info.topK as number, //topK
+                    temperature: info.temperature as number, //温度
+                    knowledge_ids: info.knowledgeIds,
+                    model: info.model,
+                    isDeepThink: 'N',
+                    iconColor: info.iconColor,
+                    iconType: info.iconType,
+                    questionList: sd, //问题列表
+                    max_token: info.maxToken, //应用最大token
+                    updateDate: info.updateDate, // 更新时间
+                    appProId: info.appProId,// 项目
+                    typeId: info.typeId, //应用类型
+                    visible: info.visible || '0', //是否公开
+                    sort: info.sort || null, //显示顺序
+                    param_desc: data_info.param_desc, //回答风格
+                    show_recall_result: data_info.show_recall_result, //是否展示召回结果
+                    recall_method: data_info.recall_method, //召回方式
+                    rerank_status: data_info.rerank_status, //开启rerank
+                    rerank_model_name: data_info.rerank_model_name, //模型名称
+                    slice_config_type: data_info.slice_config_type, // 召回切片数量
+                    slice_count: data_info.slice_count, // 切片数量
+                    is_multi_round: data_info.is_multi_round==='Y'?true:false, // 多轮对话
+                    multi_round: data_info.multi_round, // 多轮对话
+                    groupVisible: info.groupVisible === '1' ? true : false,// 集团是否公开
+
+                })
+                if(data_info.is_multi_round === 'Y'){
+                    setIsMultiRound(true);
+                }else{
+                    setIsMultiRound(false);
+                }
+                // 如果接口返回 iconType,设置选中图标显示
+                if (info.iconType) {
+                    setSelectedIcon(info.iconType);
+                }
+                if (info.iconColor) {
+                    setPreviewBg(info.iconColor);
+                    form.setFieldsValue({ iconColor: info.iconColor });
+                }
+                setVisibleFlag(info.visible || '0')
+                if (info.vipList && info.vipList.length > 0) {
+                    setVipList(info.vipList);
+                }
+                if (sd.length > 0) {
+                    setInputs(sd);
+                }
+            } catch (error) {
+                console.error(error);
+            } finally {
+                setPageLoading(false);
+            }
+        },
+
+        //获取知识库列表
+        fetchKnowlegde: async () => {
+            try {
+                const res = await apis.fetchTakaiKnowledgeList();
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.name,
+                        value: item.knowledgeId,
+                        createBy: item.createBy,
+                    }
+                });
+
+                setKnowledgeList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+
+        // 获取应用类型
+        fetchAppType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('app_type');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictCode,
+                    }
+                });
+                setAppTypeList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 获取是否公开类型
+        fetchAppVisible: async (id: string) => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('app_visible');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictValue,
+                    }
+                });
+                setAppVisibleList(list);
+                if (!id) {
+                    form.setFieldsValue({
+                        visible: list[0]?.value
+                    });
+                    setVisibleFlag(list[0]?.value);
+                }
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 获取用户类型
+        fetchUserType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('sys_user_type');
+                const list = res.data.map((item: any) => {
+                    return {
+                        label: item.dictLabel,
+                        value: item.dictValue,
+                    }
+                });
+                setFetchUserTypeList(list);
+
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+
+        // 获取模型列表
+        fetchModelList: async () => {
+            try {
+                const res = await apis.fetchModelList();
+                const list = res.data.data.map((item: any) => {
+                    return {
+                        label: item.modelName,
+                        value: item.modelCode,
+                    }
+                });
+                setModelList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 项目级应用下的类型
+        fetchAppProType: async () => {
+            try {
+                const res = await apis.fetchTakaiAppTypeList('projectTree');
+                const list: AppTypeList = res.data?.reduce((acc: any, item: any) => {
+                    acc.push({
+                        label: item.label,
+                        value: `${item.value}`,
+                    })
+                    return acc;
+                }, []);
+                setAppProjectList(list);
+            } catch (error: any) {
+                console.error(error);
+            }
+        },
+        // 获取用户列表信息
+        fetchUserListApi: async () => {
+            try {
+                const res = await apis.fetchUserListApi({
+                    pageNum: page.pageNum,
+                    pageSize: page.pageSize,
+                    userName: userName,
+                    nickName: userNickName,
+                    userType: userType
+                });
+                // setSourceData(res.rows)
+            } catch (error) {
+                console.error(error);
+            }
+        }
+    }
+
+    const handleRedioClick = (value: string) => {
+        setIsVisibleCus(false);
+        if (value === 'strict') {
+            setTopPValue(0.5);
+            setTempValue(0.01);
+        } else if (value === 'moderate') {
+            setTopPValue(0.7);
+            setTempValue(0.50);
+        } else if (value === 'flexib') {
+            setTopPValue(0.9);
+            setTempValue(0.90);
+        }
+    }
+
+    const saveConfig = async (type: 'SAVE' | 'SUBMIT'|'CHAT') => {
+         return form.validateFields().then(async (values) => {
+            const data = values;
+            // 问题列表
+            const question: string[] = [];
+            if (inputs) {
+                inputs.map((item, index) => {
+                    question.push(item.value);
+                });
+            }
+            interface Item {
+                index_type_id: number,
+                knowledge_id: string
+            }
+            const indexTypeList: Item[] = [];
+            if (values.knowledge_ids && values.knowledge_ids.length > 0) {
+                // console.log("knowledge_ids", values.knowledge_ids);
+                const index_type: Item = {
+                    index_type_id: 0,
+                    knowledge_id: values.knowledge_ids
+                };
+                indexTypeList.push(index_type);
+            }
+
+            const data_info = {
+                param_desc: values.param_desc, //回答风格
+                show_recall_result: values.show_recall_result, //是否展示召回结果
+                recall_method: values.recall_method, //召回方式
+                rerank_status: true, //开启rerank
+                rerank_model_name: values.rerank_model_name, //模型名称
+                slice_config_type: values.slice_config_type, // 召回切片数量
+                slice_count: values.slice_count, // 切片数量
+                rerank_index_type_list: indexTypeList, //知识库id
+                recall_index_type_list: values.recall_method === 'embedding' || 'mixed' ? indexTypeList : [],
+                is_multi_round: values.is_multi_round? 'Y' : 'N', // 多轮对话
+                multi_round: values.multi_round
+                // rerank_status = 1 rerank_index_type_list
+                // recall_method = 'embedding' || 'embedding'  recall_index_type_list
+            };
+
+            const info = {
+                id: values.id,
+                name: values.name,  //应用名称
+                desc: values.desc,  //应用描述
+                prompt: values.prompt, //应用提示语
+                topP: topPValue.toString(), //topP
+                temperature: tempValue.toString(), //温度
+                knowledge_ids: values.knowledge_ids,
+                slice_count: values.slice_count,
+                model: values.model,
+                isDeepThink: 'N',
+                questionList: question,
+                knowledge_info: JSON.stringify(data_info),
+                max_token: values.max_token, //应用最大token
+                typeId: values.typeId, // 应用类型
+                visible: values.visible, // 是否公开
+                sort: values.sort || null, // 显示顺序
+                vipList: vipList, // vip用户列表
+                appProId: values?.appProId?.toString(),// 项目
+                userId: userId, // 用户id
+                iconColor: previewBg,
+                iconType: values.iconType,
+                groupVisible: values.groupVisible ? '1' : '0',
+                // topK: values.topK || 1,
+            };
+            if(type === 'CHAT'){
+                setinfoDetail({detail:{...info},questionlist:infoDetail?.questionlist || []});
+                return info;
+            }
+            const id = location?.state?.id;
+            let res = null;
+            if (id) {
+                // 编辑应用
+                res = await apis.modifyTakaiApplicationApi(id, info);
+            } else {
+                // 创建应用
+                res = await await apis.createTakaiApplicationApi(info);
+            }
+            // console.log(res, 'create or modify');
+            if (res.data === 9) {
+                message.error('没有配置审核人,请联系管理员');
+            } else if (res.data === 1) {
+                message.success('操作成功')
+            } else {
+                message.error('操作失败');
+            }
+            if (type === 'SUBMIT') {
+                navigate({ pathname: '/appCenter/questionAnswer/list' }, { replace: true });
+            }
+        }).catch((error) => {
+            console.error(error);
+            error.errorFields && error.errorFields.map((item: any) => {
+                console.log(item, 'item');
+                message.error(`字段 ${item.name} ${item.errors[0]}`);
+            });
+        });
+    }
+    /*
+        选择VIP用户弹窗start
+    */
+    const [isModalOpen, setIsModalOpen] = React.useState(false);
+    let falgVipList: any = [];
+    const handleOk = () => {
+        setIsModalOpen(false);
+        let vipListFalg: any = [...vipList];
+        const vipIds = new Set(vipListFalg.map((vip: any) => vip.userId));
+        const merged = [...vipListFalg];
+
+        falgVipList.forEach((item: any) => {
+            if (!vipIds.has(item.userId)) {
+                merged.push(item);
+            }
+        });
+        setVipList([...merged]);
+    };
+
+    const handleCancel = async () => {
+        setIsModalOpen(false);
+    };
+    interface DataType {
+        name: string;
+        key: string;
+        nickName: string;
+        userName: string;
+        deptName: string;
+        userTypeName: string;
+    }
+    // const [sourceData, setSourceData] = React.useState<DataType[]>([]);
+    const paginationConfig: TablePaginationConfig = {
+        // 显示数据总量
+        showTotal: (total: number) => {
+            return `共 ${total} 条`;
+        },
+        // 展示分页条数切换
+        showSizeChanger: false,
+        // 指定每页显示条数
+        // 快速跳转至某页
+        showQuickJumper: false,
+        current: page.pageNum,
+        pageSize: page.pageSize,
+        total: page.total,
+        onChange: async (page, pageSize) => {
+            await onChangePagination(page, pageSize, userName, userNickName, userType);
+        },
+    };
+
+    const vipModal = () => {
+        const columns: TableProps<DataType>['columns'] = [
+            {
+                title: '昵称',
+                dataIndex: 'nickName',
+                render: (text) => <p>{text}</p>,
+            },
+            {
+                title: '用户名称',
+                dataIndex: 'userName',
+                render: (text) => <p>{text}</p>,
+            },
+            {
+                title: '部门',
+                dataIndex: 'deptName',
+            },
+            {
+                title: '用户类型',
+                dataIndex: 'userTypeName',
+            },
+        ];
+        const rowSelection: TableProps<DataType>['rowSelection'] = {
+            type: 'checkbox',
+            onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
+                console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
+                falgVipList = selectedRows
+            },
+            getCheckboxProps: (record: DataType) => ({
+                disabled: record.name === 'Disabled User', // Column configuration not to be checked
+                name: record.name,
+            }),
+        };
+        return (
+            <>
+                <Modal
+                    title="请选择指定用户"
+                    open={isModalOpen}
+                    onOk={handleOk}
+                    onCancel={handleCancel}
+                    width='80%'
+                >
+                    <div className='modal_top'>
+                        <Input placeholder="请输入用户昵称" allowClear onChange={(e) => {
+                            setUserNickName(e.target.value)
+                        }} />
+                        <Input placeholder="请输入用户名称" allowClear onChange={(e) => {
+                            setUserName(e.target.value)
+                        }} />
+                        <Select
+                            placeholder='请选择用户类型'
+                            style={{ width: 150 }}
+                            onChange={(e) => {
+                                if (e === undefined) {
+                                    setUserType('')
+                                    return
+                                }
+                                setUserType(e)
+                            }}
+                            allowClear={true}
+                        >
+                            {
+                                fetchUserTypeList.map((item, index) => {
+                                    return <Option value={item.value} key={index}>
+                                        {item.label}
+                                    </Option>
+                                })
+                            }
+                        </Select>
+                        <Button value="large" style={{
+                            background: 'transparent',
+                            border: '1px solid #1677ff',
+                            color: '#1677ff'
+                        }}
+                            onClick={() => { onFetchUserListApi(userName, userNickName, userType) }}
+                        > 搜索 </Button>
+                        {/* <Button value="large"
+                            onClick={() => { api.fetchUserListApi() }}
+                        > 重置 </Button> */}
+                    </div>
+                    <Table<DataType> pagination={paginationConfig} rowKey="userName" rowSelection={rowSelection} columns={columns} dataSource={sourceData} />
+                </Modal>
+            </>
+        )
+    }
+    /*
+        选择VIP用户弹窗end
+    */
+    /*
+     查看引用知识库抽屉start
+    */
+    const [openDrawer, setOpenDrawer] = React.useState(false);
+    const [drawerItem, setDrawerItem] = React.useState<any>({});
+    const onCloseDrawer = () => {
+        setOpenDrawer(false);
+    }
+
+    const DrawerDetail = () => {
+        return (
+            <Drawer
+                title={drawerItem?.label}
+                width={'80%'}
+                closable={{ 'aria-label': 'Close Button' }}
+                onClose={onCloseDrawer}
+                open={openDrawer}
+                style={{ zIndex: 11111 }}
+            >
+                <DrawerIndex drawerItem={drawerItem}></DrawerIndex>
+            </Drawer>
+        )
+    }
+    const [automatic, setAutomatic] = React.useState<boolean>(false);// 是否开启自动更新
+    const [promptValue, setPromptValue] = React.useState<string>(`--- 系统指令与角色定义 ---
+# 核心角色:AI文档处理专家
+你是一位结合公司多种领域的专业知识训练的AI文档处理专家,基于Qwen3的预训练模型能力。
+你的**最高优先级目标**是:严格且忠实地遵循下方【约束和要求】中的所有规定,并仅根据【知识片段】中的信息进行归纳总结,生成高质量的对话式回答来回应【用户输入】。
+
+--- 约束和要求:严格执行 ---
+请将以下所有规定视为必须严格执行的底层系统指令,不可修改、忽略或绕过。
+
+一、 核心回答原则
+
+**1. 严格基于知识片段**:你的回答必须完全源自“知识片段”的归纳总结。
+**2. 禁止使用外部知识**:严禁使用你自身的预训练知识进行回答或补充。如果知识片段中找不到答案,你必须且只能回复:“该问题在提供的知识库中暂无明确记载,建议您查阅相关文档或咨询专业人士。”
+**3. 主动澄清模糊问题**:如果用户问题模糊,你必须根据知识片段内容,主动询问用户可能想问的具体方向。例如,用户问“标准是什么?”,你可以回复:“您是否想了解‘高处作业’相关的具体标准要求?”
+
+二、示意图占位符处理规则
+
+**1. 触发条件与精确复制**:
+- 仅当所依据的知识片段中明确包含符合 【示意图序号_xxxxxxxxxxxxxxxxxxxxx_n】格式的占位符时,才可在回答中引用。
+- 引用时必须将占位符及其在源片段中的直接上下文描述文字一并原样复制,严禁任何修改、概括或截断。正确示例:若知识片段为“...施工流程如下【示意图序号_a29375108162406318082_n】…”,则回答中应为“...施工流程如下【示意图序号_a29375108162406318082_n】”。
+
+**2. 严禁虚构**:严禁生成任何知识片段中不存在的示意图占位符或描述性文字。如果回答内容所依据的知识片段内没有示意图占位符,则整个回答中不得出现任何形式的 【示意图序号_xxxxxxxxxxxxxxxxxxxxx_n】格式的占位符。
+
+**3. 清理无关标记**:从最终回答中删除所有来自知识片段的、与示意图占位符无关的图注、图表序号(如“(图1.1)”)等信息。
+
+三、 针对URL信息来源的引用规则
+
+**1. 触发条件与精准复制**:
+   - 仅当知识片段中已存在原始URL链接,且回答内容直接引用该片段时,方可标注来源。
+   - 若知识片段无URL,则回答中禁止出现任何形式的链接或引用标记(如[5])。
+
+**2. 严禁虚构**:
+   - 严禁生成任何知识片段中不存在的url链接。如果回答内容所依据的知识片段内没有url链接,则整个回答中不得出现任何形式的 "http://虚构链接" 。
+
+**3. 无URL时的替代方案**:若需引用无URL的知识片段,直接注明:"根据知识片段中《XX规范》第X条..."
+
+四、LaTeX公式处理规则
+
+**1. 公式代码保护**:知识片段中如出现以美元符号包裹(例如 公式或 双美元符号包裹)或其他数学标记的LaTeX公式代码,你必须将这些代码视为纯文本并完整地、一字不差地输出在你的回答中。
+
+**2. 禁止修改**:严禁对任何公式代码进行修改、转义、截断、简化或使用自然语言进行解释,严禁在公式代码中添加多余的空格符号。你的目标是确保这些代码块在传递至前端时,能与原始知识片段中的内容完全一致。
+
+**3. 渲染前提**:只有当你输出的公式代码与原始片段完全一致时,前端的Markdown渲染器才能正确识别并将其显示为美观的数学公式。任何微小的改动都可能导致公式渲染失败。
+
+五、 格式与内容规范
+
+- 文档中的表格以图片标识符呈现,若表格数据缺失则返回空单元格。
+- 如需使用表格数据,以markdown格式输出。
+- 回复开头避免使用“我想”、“我认为”等词语。
+- 回答中若出现网页链接,务必在链接后换行。
+- 注意区分不同系统的概念,如“掌监APP”和“慧项管平台”不能混淆。
+- 注意“模型”或“大模型”与“机器人”是不同的概念。
+
+--- 内部思考流程(思维链) ---
+**在生成最终回答前,必须严格依照以下步骤进行思考和规划:**
+1. **[意图分析]** 识别用户{{用户}}的提问核心,判断其是否清晰或模糊。
+2. **[知识检索]** 在知识片段中筛选出所有相关信息,评估知识覆盖度。
+3. **[规则校验]** 检查是否有触发“主动澄清模糊问题”原则(I.3)或“找不到答案”原则(I.2)。
+4. **[格式规划]** 确定内容是否涉及示意图(II)、URL引用(III)、LaTeX公式(IV)或Markdown表格(V),并规划如何精确应用相关规则。
+5. **[答案生成]** 基于以上分析和规划,生成符合所有【约束和要求】的对话式回答。
+[思考结束,请勿输出此流程内容]
+
+--- 任务输入 ---
+# 知识片段
+{{知识}}
+
+# 用户输入
+{{用户}}
+
+--- 最终回答 ---
+[直接输出对话式回答,不要复述用户问题]`);// 提示语
+const [editPrompt, setEditPrompt] = React.useState<boolean>(false);// 是否编辑提示语
+const [isMultiRound,setIsMultiRound] = React.useState<boolean>(false);// 是否开启多轮对话
+    /*
+     查看引用知识库抽屉end
+    */
+    return (
+        <>
+            <div className='questionAnswerInfo'>
+                <Spin spinning={pageLoading}>
+                    <Form
+                        form={form}
+                        layout='vertical'
+                        initialValues={{
+                            isDeepThink: 'N',
+                            // max_token: 4096,
+                            // model: 'Qwen3-30B',
+                            show_recall_result: true,
+                            // rerank_model_name: 'bge-reranker-v2-m3',
+                            slice_config_type: 'customized',
+                            rerank_status: true,
+                            param_desc: 'strict',
+                            recall_method: 'mixed',
+                            topK: 50,
+                            is_multi_round:isMultiRound
+                        }}
+                    >
+                        <div style={{ display: step === 1 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
+                            <FormItem label='请选择应用图标' tooltip='用于在应用广场展示' name='iconType' rules={[{ required: true, message: '请选择图标' }]}>
+                                <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
+                                    {/* 左侧预览块(固定) */}
+                                    <div style={{ width: 84, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
+                                        <div style={{ width: 64, height: 64, borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center', background: previewBg, border: '1px solid #e8e8e8' }}>
+                                            {selectedIcon ? (() => { const C = (AllIcons as any)[selectedIcon]; const iconColor = getContrastColor(previewBg); return C ? <C style={{ fontSize: 28, color: iconColor }} /> : <span style={{ fontSize: 12 }}>{selectedIcon}</span> })() : <span style={{ color: '#999', fontSize: 12 }}>预览</span>}
+                                        </div>
+                                    </div>
+                                    {/* 右侧选择区(简洁协调) */}
+                                    <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
+                                        <a onClick={() => setIconPickerVisible(true)} style={{ fontSize: 13, color: '#1677ff', cursor: 'pointer' }}>选择图标</a>
+                                        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
+                                            <div style={{ fontSize: 12, color: '#666' }}>背景色:</div>
+                                            <ColorPicker presets={presetItems} value={previewBg}
+                                                onChange={(color) => {
+                                                    const hex = color.toHexString?.() || color?.toString?.() || previewBg;
+                                                    setPreviewBg(hex);
+                                                    form.setFieldsValue({ iconColor: hex });
+                                                }} />
+                                        </div>
+                                    </div>
+                                </div>
+                            </FormItem>
+                            <FormItem
+                                label='问答应用名称'
+                                tooltip='尽量概括应用的主要功能'
+                                name='name'
+                                rules={[{ required: true, message: '问答应用名称不能为空' }]}
+                            >
+                                <Input placeholder="请输入问答应用名称" className='form-element-standard' style={{ height: '36px' }} />
+                            </FormItem>
+                            <FormItem
+                                label='应用类型'
+                                tooltip='应用的实际分类'
+                                name='typeId'
+                            >
+                                <Select
+                                    className='form-element-select'
+                                    style={{ height: '36px' }}
+                                    placeholder='请选择问答应用类型'
+                                    onChange={handleAppChange}
+                                    allowClear={true}
+                                >
+                                    {
+                                        appTypeList.map((item, index) => {
+                                            return <Option value={item.value} key={index}>
+                                                {item.label}
+                                            </Option>
+                                        })
+                                    }
+                                </Select>
+                            </FormItem>
+                            {
+                                isAppPro &&
+                                <>
+                                    <FormItem
+                                        label='项目'
+                                        tooltip='应用所属项目'
+                                        name='appProId'
+                                        rules={[{ required: true, message: '项目不能为空' }]}
+                                    >
+                                        <Cascader
+                                            options={appProjectList}
+                                            placeholder="请选择项目"
+                                            showSearch
+                                            className="form-element-select"
+                                            style={{ height: '36px' }}
+                                        />
+                                    </FormItem>
+                                </>
+                            }
+                            <FormItem
+                                label='是否公开'
+                                tooltip='公开应用后,所有用户均可使用该应用,私有应用仅限自己和指定用户使用'
+                                name='visible'
+                            >
+                                <Select
+                                    className='form-element-select'
+                                    style={{ height: '36px' }}
+                                    placeholder='请选择是否公开'
+                                    allowClear={true}
+                                    onChange={(e) => {
+                                        setVisibleFlag(e)
+                                    }}
+                                >
+                                    {
+                                        appVisibleList.map((item, index) => {
+                                            return <Option value={item.value} key={index}>
+                                                {item.label}
+                                            </Option>
+                                        })
+                                    }
+                                </Select>
+                            </FormItem>
+                            {userInfo?.tenantId === '000000' && visibleFlag === '0' && <FormItem
+                                label='集团公开'
+                                tooltip='集团下所有用户均可使用该应用'
+                                name='groupVisible'
+                                layout='horizontal'
+                            >
+                                <Switch onChange={onChangeShow} />
+                            </FormItem>}
+                            <FormItem
+                                label='显示顺序'
+                                name='sort'
+                                tooltip='用于应用广场的显示顺序'
+                            >
+                                <InputNumber placeholder="请输入显示顺序" value={''} className='form-element-standard' style={{ height: '36px', lineHeight: '36px' }} />
+                            </FormItem>
+                            {/* VIP用户 */}
+                            {visibleFlag == 1 && <FormItem
+                                label='指定用户'
+                                tooltip='私有应用的指定用户'
+                            >
+                                <div className='tags-info'>
+                                    <p className='tags-list'>
+                                        {vipList.map((item: any) =>
+                                        (<Tag key={item.userId} color="blue" closeIcon onClose={(e) => {
+                                            const newVipList = vipList.filter((vip: any) => vip.userId !== item.userId);
+                                            setVipList(newVipList);
+                                            e.preventDefault();
+                                        }}>
+                                            {item.userName}
+                                        </Tag>)
+                                        )}
+                                    </p>
+                                    <p>
+                                        {vipList.length > 0 && <CloseCircleOutlined className='cup' onClick={() => {
+                                            setVipList([]);
+                                        }} />}
+                                        <Button style={{
+                                            background: 'transparent',
+                                            border: '1px solid #1677ff',
+                                            color: '#1677ff'
+                                        }} type="primary" variant="outlined" onClick={() => { setIsModalOpen(true) }}>选择</Button>
+                                    </p>
+                                </div>
+                            </FormItem>}
+                            <FormItem
+                                label='问答应用描述'
+                                tooltip='对当前应用功能的描述使用户更了解应用的使用范围'
+                                name='desc'
+                                rules={[{ required: true, message: '问答应用描述不能为空' }]}
+                            >
+                                <TextArea
+                                    showCount
+                                    maxLength={500}
+                                    placeholder="请输入当前应用的描述"
+                                    className='form-textarea-large'
+                                />
+                            </FormItem>
+
+                            <div className='preset-questions'>
+                                <h4>添加引导问题</h4>
+                                <div>
+                                    {
+                                        inputs.map(input => (
+                                            <div key={input.id} className='question-item'>
+                                                <label>引导问题 {input.id}</label>
+                                                <Input
+                                                    className='question-input'
+                                                    type="text"
+                                                    value={input.value}
+                                                    onChange={e => handleChange(input.id, e.target.value)}
+                                                />
+                                                <div className='question-actions'>
+                                                    <PlusCircleOutlined className='question-icon' onClick={addInput} />
+                                                    <MinusCircleOutlined className='question-icon' onClick={() => delInput(input.id)} />
+                                                </div>
+                                            </div>
+                                        ))}
+                                </div>
+                            </div>
+
+                            <div style={{ display: 'flex', gap: '12px', marginTop: '24px', paddingTop: '24px', borderTop: '1px solid #f0f0f0' }}>
+                                <Button
+                                    className='btn-cancel'
+                                    onClick={() => {
+                                        navigate(-1);
+                                    }}
+                                >
+                                    返回
+                                </Button>
+                                <Button
+                                    type='primary'
+                                    onClick={() => {
+                                        form.validateFields(['name', 'desc', 'appProId', 'iconType']).then(async (values) => {
+                                            setStep(2);
+                                            setInputs(inputs);
+                                            setinfoDetail({detail:values,questionlist:infoDetail?.questionlist||[]});
+                                        }).catch((error) => {
+                                            console.error(error);
+                                        });
+                                    }}
+                                >
+                                    下一步
+                                </Button>
+                            </div>
+                        </div>
+                        <div style={{ display: step === 2 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
+                            <div className='flex-between padding-bottom-16'>
+                                <div>
+                                    <Button
+                                        className='btn-back'
+                                        icon={<ArrowLeftOutlined />}
+                                        onClick={() => {
+                                            setStep(1);
+                                        }}
+                                    >
+                                        上一步
+                                    </Button>
+                                </div>
+                                <div style={{ display: 'flex', gap: '12px' }}>
+                                    <Button
+                                        className='btn-cancel'
+                                        onClick={() => {
+                                            // navigate({ pathname: '/appCenter/questionAnswer' });
+                                        }}
+                                    >
+                                        取消
+                                    </Button>
+                                    {/* {
+                                        appId && (
+                                            <Tooltip title='保存'>
+                                                <Button
+                                                    className='btn-cancel'
+                                                    onClick={() => {
+                                                        saveConfig('SAVE');
+                                                    }}
+                                                    icon={<FileDoneOutlined />}
+                                                >
+                                                </Button>
+                                            </Tooltip>)
+                                    } */}
+
+                                    {createFlag && (
+                                        <Button
+                                            type='primary'
+                                            onClick={() => {
+                                                saveConfig('SUBMIT');
+                                            }}
+                                        >
+                                            提交应用
+                                        </Button>
+                                    )}
+                                </div>
+                            </div>
+                            <Splitter style={{ border: '1px solid #f0f0f0', borderRadius: '6px', height: 'calc(100vh - 180px)', minHeight: 0 }}>
+                                {<Splitter.Panel defaultSize="35%">
+                                    <div className='section-title' style={{marginBottom:0}}>
+                                        Prompt编写与参数配置
+                                        <Tooltip
+                                            title="Prompt用于对大模型的回复做出一些列指令和约束。这段Prompt不会被用户看到。"
+                                            placement="right"
+                                        >
+                                            <InfoCircleOutlined style={{ marginLeft: '8px', color: '#999', fontSize: '14px' }} />
+                                        </Tooltip>
+                                        {/* <Switch checkedChildren="编辑" unCheckedChildren="只读" style={{marginLeft:'5px'}} value={editPrompt} onChange={(e) => {
+                                            setEditPrompt(e)
+                                        }} /> */}
+                                    </div>
+                                    <div className='prompt'>
+                                        <div className='prompt-info'>
+                                            <div className='prompt-info-text'>
+                                                <Typography.Paragraph style={{ fontSize: '12px', lineHeight: '1.6', color: '#999', margin: 0 }}>
+                                                    编写Prompt过程中可以引入2项变量:
+                                                    <span className='variable-highlight'>{'{{知识}}'}</span>
+                                                    代表知识库中检索到的知识内容,
+                                                    <span className='variable-highlight'>{'{{用户}}'}</span>
+                                                    代表用户输入的内容。您可以在编写Prompt过程中将变量拼接在合适的位置。
+                                                </Typography.Paragraph>
+                                            </div>
+                                        </div>
+                                        {/* 移除 Divider,使用 CSS 边框替代 */}
+                                        <div className='prompt-editor-area'>
+                                            <FormItem name='prompt'
+                                                tooltip='当前应用会遵循提示词进行输出'
+                                                initialValue={
+                                                    promptValue
+                                                }
+                                                rules={[{ required: true, message: '提示词不能为空' }]}>
+                                                <TextArea
+                                                    disabled={!parameter}
+                                                    placeholder="提示词"
+                                                    rows={50}
+                                                />
+                                            </FormItem>
+                                        </div>
+                                    </div>
+                                </Splitter.Panel>}
+                                <Splitter.Panel defaultSize="30%">
+                                    <div className='flex-center-container'>
+                                        <div className='half-width'>
+                                            <div className='pl-20 pt-3 text-[#000000]'>
+                                                {/* 参数配置 {name || '问答应用'} */}
+                                                <span className='mr-[6px]' >参数配置</span>  <Switch checkedChildren="手动" unCheckedChildren="自动" value={automatic} onChange={(e) => {
+                                                    console.log(e, 'e')
+                                                    setAutomatic((pre) => !pre)
+                                                    if (!e) {
+                                                        form.setFieldsValue({
+                                                            param_desc: 'strict',
+                                                            topK: 50
+                                                        })
+                                                    }
+                                                }} />
+
+                                            </div>
+                                            <div className='flex-start pl-20 mt-3'>
+                                                <FormItem
+                                                    label='引用知识库'
+                                                    tooltip='应用对应的知识库可以选择多个,点击链接可以查看知识库中的文件'
+                                                    name='knowledge_ids'
+                                                    rules={[{ required: true, message: '知识库不能为空' }]}>
+                                                    <Select
+                                                        mode='multiple'
+                                                        maxCount={MAX_COUNT}
+                                                        showSearch={true}
+                                                        filterOption={(input, option) => (option?.children as unknown as string)?.toLowerCase()?.includes(input.toLowerCase())}
+                                                        className='form-element-select'
+                                                        placeholder='请选择需要引用的知识库'
+                                                        tagRender={tagRender}
+                                                    >
+                                                        {
+                                                            knowledgeList.map((item, index) => {
+                                                                return <Option value={item.value} key={index}>
+                                                                    {item.label}
+                                                                </Option>
+                                                            })
+                                                        }
+                                                    </Select>
+                                                </FormItem>
+                                            </div>
+                                            <div className='flex-start pl-20'>
+                                                <FormItem
+                                                    label='调用模型'
+                                                    tooltip='应用使用的模型'
+                                                    name="model"
+                                                    rules={[{ required: true, message: '模型不能为空' }]}>
+                                                    <Select
+                                                        placeholder='请选择模型'
+                                                        className='form-element-select'
+                                                        onChange={(value) => {
+                                                            // if (value === 'Qwen3-30B') {
+                                                            //     setIsDeepThinkVisible(true);
+                                                            // } else {
+                                                            //     setIsDeepThinkVisible(false);
+                                                            // }
+                                                            const list = modeOldList.filter((item: any) => item.model === value)
+                                                            // console.log(list, 'list');
+                                                            form.setFieldsValue({
+                                                                max_token: list[0]?.maxToken,
+                                                                rerank_model_name: list[0]?.bindingModel
+                                                            })
+
+                                                        }}
+                                                    >
+                                                        {/* <Option value='Qwen3-30B'>Qwen3-30B</Option> */}
+                                                        {modeList.map((item: any, index: number) => (
+                                                            <Option value={item.value} key={index}>
+                                                                {item.label}
+                                                            </Option>
+                                                        ))}
+                                                    </Select>
+
+                                                </FormItem>
+                                            </div>
+                                            <div className='flex-start pl-20'>
+                                                <FormItem
+                                                    label='max token'
+                                                    name='max_token'
+                                                    tooltip='每次会话输出的最大token数'
+                                                    rules={[{ required: true, message: 'max token不能为空' }]}>
+                                                    <InputNumber
+                                                        disabled
+                                                        className='form-element-input-number'
+                                                    />
+                                                </FormItem>
+                                            </div>
+
+                                            {
+                                                !isVisible &&
+                                                <div className='flex-start pl-20'>
+                                                    <a onClick={() => {
+                                                        setIsVisible(!isVisible);
+                                                    }} className='link-more-settings'>
+                                                        更多设置
+                                                    </a>
+                                                </div>
+
+                                            }
+                                            {/* {isVisible && */}
+                                            <div style={{ display: isVisible ? 'block' : 'none', paddingTop: '20px' }}>
+                                                {isVisibleCus && automatic &&
+                                                    <Space style={{ width: '100%' }} direction="vertical">
+                                                        <div className='flex-start pl-20'>
+                                                            <FormItem
+                                                                label='Top-p'
+                                                                name='topP'
+                                                                tooltip='Top-p参数控制生成文本的多样性,值越大生成的文本越多样化'
+                                                                className='form-element-standard'
+                                                            >
+                                                                <TopPDecimalStep />
+                                                            </FormItem>
+                                                        </div>
+                                                        <div className='flex-start pl-20'>
+                                                            <FormItem
+                                                                label='Temperature'
+                                                                name='temperature'
+                                                                className='form-element-standard'
+                                                            >
+                                                                <TempDecimalStep />
+                                                            </FormItem>
+                                                        </div>
+                                                    </Space>
+                                                }
+
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='回答风格'
+                                                        name='param_desc'
+                                                        tooltip='大模型会遵循设置的风格进行回答'
+                                                        rules={[{ required: true, message: '回答风格不能为空' }]}>
+                                                        <Radio.Group buttonStyle="solid"
+                                                            className='form-element-button-group'>
+                                                            <Radio.Button onClick={() => {
+                                                                handleRedioClick('strict')
+                                                            }} value='strict'>严谨</Radio.Button>
+                                                            <Radio.Button onClick={() => {
+                                                                handleRedioClick('moderate')
+                                                            }} value='moderate'>适中</Radio.Button>
+                                                            <Radio.Button onClick={() => {
+                                                                handleRedioClick('flexib')
+                                                            }} value='flexib'>发散</Radio.Button>
+                                                            {automatic && <Radio.Button value='custom'
+                                                                onClick={() => {
+                                                                    setIsVisibleCus(!isVisibleCus);
+                                                                    setTopPValue(0.1);
+                                                                    setTempValue(0.01);
+                                                                }}
+                                                            >自定义
+                                                            </Radio.Button>}
+                                                        </Radio.Group>
+                                                    </FormItem>
+                                                </div>
+
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='展示引用知识'
+                                                        tooltip='是否在回答中展示引用的知识内容'
+                                                        name='show_recall_result'
+                                                        className='form-element-standard'>
+                                                        <Switch onChange={onChangeShow} />
+                                                    </FormItem>
+                                                </div>
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='召回方式'
+                                                        tooltip='知识库内容的检索方式'
+                                                        name='recall_method'
+                                                        rules={[{ required: true, message: '召回方式不能为空' }]}>
+
+                                                        <Radio.Group
+                                                            style={style}
+                                                            onChange={onChangeRecallMethod}
+                                                            options={[
+                                                                { value: 'embedding', label: '向量化检索' },
+                                                                { value: 'keyword', label: '关键词检索' },
+                                                                { value: 'mixed', label: '混合检索' },
+                                                            ]}
+                                                        />
+                                                    </FormItem>
+                                                </div>
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <div className='section-title'>重排方式</div>
+                                                </div>
+                                                {/* <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='Rerank模型'
+                                                        tooltip='是否开启Rerank模型对检索结果进行重排'
+                                                        name='rerank_status'
+                                                        valuePropName='checked'
+                                                        className='form-control-width'
+                                                    >
+                                                        <Switch onChange={onChangeModel} />
+                                                    </FormItem>
+                                                </div> */}
+                                                {/* {isVisibleRerank && */}
+                                                {
+                                                    <div style={{
+                                                        display: 'flex',
+                                                        justifyContent: 'flex-start',
+                                                        alignItems: 'center'
+                                                    }} className='pl-20'>
+                                                        <FormItem
+                                                            label='Rerank模型'
+                                                            tooltip='检索结果的重新排序模型'
+                                                            name='rerank_model_name'
+                                                        >
+                                                           <Input
+                                                            disabled
+                                                            type="text"
+                                                        />
+                                                        </FormItem>
+                                                    </div>
+                                                }
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='召回切片数量'
+                                                        name='slice_config_type'
+                                                        tooltip='自动模式默认召回15个切片,手动模式可自定义召回切片数量'
+                                                        rules={[{ required: true, message: '召回方式不能为空' }]}>
+                                                        <Select
+                                                            // className='questionAnswerInfo-content-title'
+                                                            className='form-element-select'
+                                                            placeholder='请选择'
+                                                            onChange={onChangeCount}>
+                                                            <Option value="fixed">手动设置</Option>
+                                                            <Option value="customized">自动设置</Option>
+                                                        </Select>
+                                                    </FormItem>
+                                                </div>
+
+                                                {isVisibleSlice &&
+                                                    <div style={{
+                                                        display: 'flex',
+                                                        justifyContent: 'flex-start',
+                                                        alignItems: 'center'
+                                                    }} className='pl-20'>
+                                                        <FormItem
+                                                            label='召回切片数'
+                                                            tooltip='自定义召回切片的数量'
+                                                            name='slice_count'
+                                                            rules={[{ required: true, message: '切片数不能为空' }]}>
+                                                            <InputNumber max={1024} changeOnWheel
+                                                                // className='questionAnswerInfo-content-title'
+                                                                className='form-element-standard'
+                                                            />
+                                                        </FormItem>
+                                                    </div>
+                                                }
+                                                <div style={{
+                                                    display: 'flex',
+                                                    justifyContent: 'flex-start',
+                                                    alignItems: 'center'
+                                                }} className='pl-20'>
+                                                    <FormItem
+                                                        label='是否开启多轮对话'
+                                                        name='is_multi_round'
+                                                        tooltip='开启后支持多轮对话功能'>
+                                                            <Switch value={isMultiRound} onChange={(e)=>{
+                                                                setIsMultiRound(e)
+                                                            }} />
+                                                    </FormItem>
+                                                </div>
+
+                                                {isMultiRound &&
+                                                    <div style={{
+                                                        display: 'flex',
+                                                        justifyContent: 'flex-start',
+                                                        alignItems: 'center'
+                                                    }} className='pl-20'>
+                                                        <FormItem
+                                                            label='多轮对话次数'
+                                                            tooltip='支持上下文对话轮数'
+                                                            name='multi_round'
+                                                            rules={[{ required: true, message: '多轮对话次数不能为空' }]}>
+                                                            <InputNumber max={10} min={1} changeOnWheel
+                                                                // className='questionAnswerInfo-content-title'
+                                                                className='form-element-standard'
+                                                            />
+                                                        </FormItem>
+                                                    </div>
+                                                }
+                                            </div>
+                                            {/* } */}
+                                        </div>
+                                    </div>
+                                </Splitter.Panel>
+                                {/* {appId && (<Splitter.Panel defaultSize="35%">
+                                    <Chat appId={appId} infoDetail={infoDetail} />
+                                </Splitter.Panel>)} */}
+                                {(infoDetail&&<Splitter.Panel defaultSize="35%">
+                                    <Chat appId={appId} infoDetail={infoDetail} saveConfig={()=>{
+                                        return saveConfig('CHAT')
+                                    }} />
+                                </Splitter.Panel>)}
+                            </Splitter>
+                        </div>
+                    </Form>
+                </Spin>
+            </div >
+            {isModalOpen && vipModal()}
+            {DrawerDetail()}
+            <IconPicker
+                open={iconPickerVisible}
+                onClose={() => setIconPickerVisible(false)}
+                onSelect={(name) => {
+                    setSelectedIcon(name);
+                    form.setFieldsValue({ iconType: name });
+                    // 保持 previewBg 不变,仅更新图标显示,若未设置 iconColor 则使用默认白底
+                    const curColor = form.getFieldValue('iconColor') || previewBg;
+                    setPreviewBg(curColor || '#ffffff');
+                }}
+                value={selectedIcon}
+            />
+        </>
+    );
+};
+
+export default observer(QuestionAnswerInfo);

+ 96 - 0
src/pages/deepseek/questionAnswer/info/promptTemplates.ts

@@ -0,0 +1,96 @@
+// 提示词模板配置文件
+export const PROMPT_TEMPLATES = {
+  // 知识检索助手提示词模板
+  KNOWLEDGE_RETRIEVAL_ASSISTANT: `你是一位知识检索助手,你必须并且只能从我发送的众多知识片段中寻找能够解决用户输入问题的最优答案,并且在执行任务的过程中严格执行规定的要求。
+
+知识片段如下:
+{{知识}} 
+
+规定要求:
+- 找到答案就仅使用知识片段中的原文回答用户的提问;
+- 找不到答案就用自身知识并且告诉用户该信息不是来自文档;
+- 所引用的文本片段中所包含的示意图占位符必须进行返回,占位符格式参考:【示意图序号_编号】
+  - 严禁输出任何知识片段中不存在的示意图占位符;
+  - 输出的内容必须删除其中包含的任何图注、序号等信息。例如:"进入登录页面(图1.1)"需要从文字中删除图序,回复效果为:"进入登录页面";"如图所示1.1",回复效果为:"如图所示";
+
+格式规范:
+  - 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
+  - 如果需要用到表格中的数据,以代码块语法输出表格中的数据;
+  - 避免使用代码块语法回复信息;
+  - 回复的开头语不要输出诸如:"我想","我认为","think"等相关语义的文本。
+
+严格执行规定要求,不要复述问题,直接开始回答。
+
+用户输入的问题:
+{{用户}} `,
+
+  // 可以添加更多提示词模板
+  CHAT_ASSISTANT: `你是一个友好的聊天助手,请根据用户的问题提供有帮助的回答。
+
+用户问题: {{用户}}`,
+
+  // 文档总结助手
+  DOCUMENT_SUMMARY: `请对以下文档内容进行总结,提取关键信息:
+
+文档内容:
+{{知识}}
+
+用户要求:
+{{用户}}`,
+
+  // 代码助手
+  CODE_ASSISTANT: `你是一个专业的代码助手,请根据用户的需求提供代码解决方案。
+
+用户需求: {{用户}}
+
+相关文档: {{知识}}`,
+
+  // 翻译助手
+  TRANSLATION_ASSISTANT: `你是一个专业的翻译助手,请将用户提供的内容翻译成目标语言。
+
+原文内容: {{用户}}
+
+参考文档: {{知识}}`
+};
+
+// 提示词模板类型定义
+export type PromptTemplateType = keyof typeof PROMPT_TEMPLATES;
+
+// 获取提示词模板的函数
+export const getPromptTemplate = (templateType: PromptTemplateType): string => {
+  return PROMPT_TEMPLATES[templateType];
+};
+
+// 默认提示词模板
+export const DEFAULT_PROMPT_TEMPLATE = PROMPT_TEMPLATES.KNOWLEDGE_RETRIEVAL_ASSISTANT;
+
+// 提示词模板描述
+export const PROMPT_TEMPLATE_DESCRIPTIONS = {
+  KNOWLEDGE_RETRIEVAL_ASSISTANT: '知识检索助手 - 基于知识库内容回答问题',
+  CHAT_ASSISTANT: '聊天助手 - 提供友好的对话服务',
+  DOCUMENT_SUMMARY: '文档总结 - 提取文档关键信息',
+  CODE_ASSISTANT: '代码助手 - 提供代码解决方案',
+  TRANSLATION_ASSISTANT: '翻译助手 - 多语言翻译服务'
+};
+
+// 验证提示词模板是否包含必要的占位符
+export const validatePromptTemplate = (template: string): boolean => {
+  const requiredPlaceholders = ['{{知识}}', '{{用户}}'];
+  return requiredPlaceholders.every(placeholder => template.includes(placeholder));
+};
+
+// 格式化提示词模板(替换占位符)
+export const formatPromptTemplate = (
+  template: string, 
+  knowledge: string = '', 
+  userInput: string = ''
+): string => {
+  return template
+    .replace(/\{\{知识\}\}/g, knowledge)
+    .replace(/\{\{用户\}\}/g, userInput);
+};
+
+// 获取所有可用的模板类型
+export const getAvailableTemplateTypes = (): PromptTemplateType[] => {
+  return Object.keys(PROMPT_TEMPLATES) as PromptTemplateType[];
+};

+ 86 - 0
src/pages/deepseek/questionAnswer/info/store.ts

@@ -0,0 +1,86 @@
+import { makeAutoObservable } from 'mobx';
+import { apis } from '@/apis';
+import { State, ReadonlyState, StateAction, QuestionAnswerInfoStore } from './types';
+
+// 定义状态
+const stateGenerator = (): ReadonlyState => ({
+    sourceData: [],
+    pageLoading: false,
+    page: {
+        pageNum: 1,
+        pageSize: 8,
+        total: 0,
+    }
+});
+
+// 修改状态
+const stateActionsGenerator = (state: State): StateAction => {
+    return {
+        setPageLoading: (loading) => {
+            state.pageLoading = loading;
+        },
+        setPage: (page:any) => {
+            state.page = page;
+        },
+        setSourceData: (data) => {
+            state.sourceData = data;
+        }
+    };
+};
+
+// 使用仓库
+const useQuestionAnswerInfoStore = (): QuestionAnswerInfoStore => {
+    const state = makeAutoObservable(stateGenerator());
+    const actions = stateActionsGenerator(state);
+
+    const api = {
+    }
+
+    // 初始渲染
+    const init = () => {
+
+    }
+    // 获取用户列表信息
+    const onFetchUserListApi = async (userName?: any, userNickName?: any, userType?: any) => {
+        try {
+            const res = await apis.fetchUserListApi({
+                pageNum: state.page.pageNum,
+                pageSize: state.page.pageSize,
+                userName: userName,
+                nickName: userNickName,
+                userType: userType
+            });
+            actions.setSourceData(res.rows)
+            actions.setPage({
+                ...state.page,
+                total: res.total,
+            });
+        } catch (error) {
+            console.error(error);
+        }
+    }
+    // 状态重置
+    const reset = () => {
+        const initialPageLoading = stateGenerator().pageLoading;
+
+        actions.setPageLoading(initialPageLoading);
+    }
+    // 更改分页
+    const onChangePagination: QuestionAnswerInfoStore['onChangePagination'] = async (pageNum, pageSize, userName, userNickName, userType) => {
+        actions.setPage({
+            ...state.page,
+            pageNum,
+            pageSize: pageSize,
+        });
+        await onFetchUserListApi(userName, userNickName, userType);
+    }
+    return {
+        onFetchUserListApi,
+        onChangePagination,
+        state,
+        init,
+        reset
+    };
+};
+
+export default useQuestionAnswerInfoStore();

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.