3
0

13 Commits c77472d7f2 ... ef7fe1643d

Autor SHA1 Nachricht Datum
  Ryuiso ef7fe1643d scss 样式警告修复 import -> use vor 1 Monat
  Ryuiso 063a612cbb docs: 更新 .claude-rules.md 标记 P1 任务全部完成 vor 1 Monat
  Ryuiso 302e0e2862 docs: 重写 API 文档,参考 Dify 风格只保留 RAG 调用和知识库检索接口 vor 1 Monat
  Ryuiso 9302c02dc2 style: 统一 Ant Design 组件圆角为 8px,符合设计规范 vor 1 Monat
  Ryuiso fe4912b557 docs: 更新 .claude-rules.md 标记文档任务已完成 vor 1 Monat
  Ryuiso 3eb265fec9 docs: 新增 API 接口文档 vor 1 Monat
  Ryuiso 2fcfaaaa92 docs: 更新 README.md 添加完整项目文档 vor 1 Monat
  Ryuiso 3b22e1166c docs: 更新 .claude-rules.md 标记样式变量任务已完成 vor 1 Monat
  Ryuiso cd8dbdcda7 style: 修复 SCSS 文件中的硬编码颜色和间距值 vor 1 Monat
  Ryuiso 221f42bcd6 docs: 更新 .claude-rules.md 中的 TODO List,标记已完成的任务 vor 1 Monat
  Ryuiso 8207e508f8 feat: 实现审核页面,更新 store 和 API 集成 vor 1 Monat
  Ryuiso 0445b194cb feat: 新增应用管理、认证、审核、首页统计 Mock API vor 1 Monat
  Ryuiso a39b059565 feat: 更新 .claude-rules.md,添加修改功能模块前强制提交 git 的规则 vor 1 Monat
71 geänderte Dateien mit 5395 neuen und 2250 gelöschten Zeilen
  1. 311 200
      jk-rag-platform/.claude-rules.md
  2. 31 1
      jk-rag-platform/.claude/settings.local.json
  3. 110 14
      jk-rag-platform/README.md
  4. 0 10
      jk-rag-platform/demo.log
  5. 556 0
      jk-rag-platform/docs/API.md
  6. BIN
      jk-rag-platform/e1.png
  7. 2 0
      jk-rag-platform/package.json
  8. 7 0
      jk-rag-platform/src/App.tsx
  9. 21 5
      jk-rag-platform/src/apis/api.ts
  10. 50 2
      jk-rag-platform/src/apis/index.ts
  11. 1 1
      jk-rag-platform/src/components/404/style.scss
  12. 267 0
      jk-rag-platform/src/components/common/AppCard/AppCardApiDoc.scss
  13. 286 0
      jk-rag-platform/src/components/common/AppCard/AppCardApiDoc.tsx
  14. 28 22
      jk-rag-platform/src/components/common/AppCard/index.scss
  15. 70 49
      jk-rag-platform/src/components/common/AppCard/index.tsx
  16. 1 2
      jk-rag-platform/src/components/common/FilterBar/index.scss
  17. 20 3
      jk-rag-platform/src/components/common/FilterDrawer/index.scss
  18. 1 1
      jk-rag-platform/src/components/common/GuideTips/index.scss
  19. 2 4
      jk-rag-platform/src/components/common/GuideTips/index.tsx
  20. 32 37
      jk-rag-platform/src/components/common/HeroBanner/index.scss
  21. 2 1
      jk-rag-platform/src/components/common/HeroBanner/index.tsx
  22. 25 18
      jk-rag-platform/src/components/common/StatsGrid/index.scss
  23. 11 1
      jk-rag-platform/src/components/common/StatsGrid/index.tsx
  24. 416 0
      jk-rag-platform/src/mock/applicationApi.ts
  25. 385 0
      jk-rag-platform/src/mock/auditApi.ts
  26. 200 0
      jk-rag-platform/src/mock/authApi.ts
  27. 166 0
      jk-rag-platform/src/mock/overviewApi.ts
  28. 2 1
      jk-rag-platform/src/pages/appCenter/appPlazaList/index.tsx
  29. 1 1
      jk-rag-platform/src/pages/appCenter/appPlazaList/style.scss
  30. 2 1
      jk-rag-platform/src/pages/appCenter/categoryApps/index.tsx
  31. 1 1
      jk-rag-platform/src/pages/appCenter/categoryApps/style.scss
  32. 0 2
      jk-rag-platform/src/pages/deepseek/dataExport/style.scss
  33. 1 1
      jk-rag-platform/src/pages/home/style.scss
  34. 39 35
      jk-rag-platform/src/pages/knowledgeLib/detail/components/style.scss
  35. 1 1
      jk-rag-platform/src/pages/knowledgeLib/detail/style.scss
  36. 1 1
      jk-rag-platform/src/pages/knowledgeLib/list/KnowledgeDrawer.scss
  37. 7 6
      jk-rag-platform/src/pages/knowledgeLib/list/KnowledgeDrawer.tsx
  38. 4 12
      jk-rag-platform/src/pages/knowledgeLib/list/index.tsx
  39. 32 1
      jk-rag-platform/src/pages/knowledgeLib/list/style.scss
  40. 1 1
      jk-rag-platform/src/pages/knowledgeLib/revisionTool/components/reviseDrawer.scss
  41. 6 11
      jk-rag-platform/src/pages/layout/components/Header.tsx
  42. 49 29
      jk-rag-platform/src/pages/layout/components/Sidebar.tsx
  43. 1 1
      jk-rag-platform/src/pages/layout/components/header.scss
  44. 4 4
      jk-rag-platform/src/pages/layout/components/sidebar.scss
  45. 9 9
      jk-rag-platform/src/pages/layout/store.ts
  46. 3 3
      jk-rag-platform/src/pages/layout/style.scss
  47. 1 1
      jk-rag-platform/src/pages/login/style.scss
  48. 1 1
      jk-rag-platform/src/pages/otherApps/otherAppList/style.scss
  49. 0 29
      jk-rag-platform/src/pages/otherApps/style.scss
  50. 31 31
      jk-rag-platform/src/pages/questionAnswer/form/DrawerForm.scss
  51. 3 2
      jk-rag-platform/src/pages/questionAnswer/form/Step1Drawer.tsx
  52. 13 13
      jk-rag-platform/src/pages/questionAnswer/form/VipSelector.scss
  53. 4 3
      jk-rag-platform/src/pages/questionAnswer/form/VipSelector.tsx
  54. 2 227
      jk-rag-platform/src/pages/questionAnswer/form/style.scss
  55. 0 105
      jk-rag-platform/src/pages/questionAnswer/info/style.scss
  56. 1 1
      jk-rag-platform/src/pages/questionAnswer/list/style.scss
  57. 304 0
      jk-rag-platform/src/pages/system/apiKey/components/ApiDoc.scss
  58. 415 0
      jk-rag-platform/src/pages/system/apiKey/components/ApiDoc.tsx
  59. 159 3
      jk-rag-platform/src/pages/system/apiKey/index.tsx
  60. 1 0
      jk-rag-platform/src/pages/system/apiKey/style.scss
  61. 8 998
      jk-rag-platform/src/pages/system/audit/components/style.scss
  62. 404 202
      jk-rag-platform/src/pages/system/audit/index.tsx
  63. 61 24
      jk-rag-platform/src/pages/system/audit/store.ts
  64. 241 2
      jk-rag-platform/src/pages/system/audit/style.scss
  65. 0 2
      jk-rag-platform/src/pages/system/contentManagement/style.scss
  66. 0 2
      jk-rag-platform/src/pages/system/usageStatistics/style.scss
  67. 95 5
      jk-rag-platform/src/pages/universalChat/styles/index.scss
  68. 429 40
      jk-rag-platform/src/styles/global.scss
  69. 56 66
      jk-rag-platform/src/styles/variables.scss
  70. 1 1
      jk-rag-platform/vite.config.ts
  71. BIN
      jk-rag-platform/开发计划清单.xlsx

+ 311 - 200
jk-rag-platform/.claude-rules.md

@@ -1,265 +1,376 @@
 # Claude Project Rules - jk-rag-platform
 
+**项目名称**: 建科小智开放平台
+**版本**: v3.8
+**更新日期**: 2026-04-02
+**技术栈**: React 18 + TypeScript + Vite + Ant Design + SCSS + Zustand
+
+---
+
 ## 项目概述
-建科小智开放平台 - React + TypeScript + Vite + Ant Design
+
+建科小智开放平台 - 基于 RAG 技术的知识库管理与应用开发平台
+
+### 目录结构
+
+```
+src/
+├── apis/              # API 接口配置 (api.ts, config.ts, index.ts)
+├── assets/            # 静态资源
+├── components/        # 公共组件
+│   ├── 404/           # 404 页面
+│   ├── chat/          # 聊天组件
+│   ├── common/        # 通用组件
+│   │   ├── FilterBar/     # 筛选栏
+│   │   ├── FilterDrawer/  # 筛选抽屉
+│   │   ├── AppCard/       # 应用卡片
+│   │   ├── GuideTips/     # 引导提示
+│   │   ├── HeroBanner/    # 横幅
+│   │   ├── PageLayout/    # 页面布局
+│   │   └── StatsGrid/     # 统计卡片
+│   └── step/          # 步骤条
+├── config/            # 配置文件
+├── mock/              # Mock 数据
+│   ├── index.ts           # 全局 Mock 数据
+│   └── knowledgeApi.ts    # 知识库 Mock API
+├── pages/             # 页面组件
+│   ├── appCenter/         # 应用中心
+│   ├── home/              # 首页/概览
+│   ├── knowledgeLib/      # 知识库管理
+│   ├── layout/            # 布局组件
+│   ├── login/             # 登录
+│   ├── questionAnswer/    # 问答应用
+│   ├── system/            # 系统管理
+│   └── universalChat/     # 智能问答
+├── store/             # 状态管理 (Zustand + route.tsx)
+├── styles/            # 全局样式
+│   ├── variables.scss     # SCSS 变量
+│   └── global.scss        # 全局样式
+├── typings/           # 类型定义
+├── utils/             # 工具函数
+├── App.tsx
+├── main.tsx
+├── router.tsx         # 路由配置
+└── LocalStorage.ts    # 本地存储封装
+```
+
+---
 
 ## 样式修改规范
 
 ### 1. 全局变量优先原则
-- **必须使用** `src/styles/variables.less` 中定义的变量
-- **禁止硬编码**颜色值、间距值、圆角值等
-- 所有组件样式文件必须以 LESS 格式,导入全局变量
+
+- **必须使用** `src/styles/variables.scss` 中定义的变量
+- **禁止硬编码** 颜色值、间距值、圆角值等
+- 所有组件样式文件必须以 **SCSS** 格式,导入全局变量
+
+```scss
+// 文件顶部必须导入
+@import '@/styles/variables.scss';
+
+.my-component {
+    // ✅ 使用变量
+    color: $text-primary;
+    padding: $spacing-4;
+    border-radius: $radius-lg;
+
+    // ❌ 禁止硬编码
+    color: #1F2937;
+    padding: 16px;
+}
+```
 
 ### 2. 间距控制规范
-- 使用 `@spacing-*` 系列变量(4px 基准)
-- 页面容器:`.page-container { padding: @spacing-4 @spacing-6 }`
-- 内容区块:`.content-section { margin-bottom: @spacing-6; padding: @spacing-5 }`
 
-### 3. 色彩使用规范 (v3.6)
-- **主色**: `@primary-color: #005D80` (企业蓝,WCAG AAA)
+- 使用 `$spacing-*` 系列变量(4px 基准)
+- 页面容器:`.page-container { padding: $spacing-4 $spacing-6 }`
+- 内容区块:`.content-section { margin-bottom: $spacing-4; padding: $spacing-3 }`
+
+间距变量定义:
+- `$spacing-1`: 4px - 最小间距
+- `$spacing-2`: 8px - 小间距
+- `$spacing-3`: 12px - 中等间距
+- `$spacing-4`: 16px - 标准间距
+- `$spacing-5`: 20px - 大间距
+- `$spacing-6`: 24px - 加大间距
+
+### 3. 色彩使用规范 (v3.2 企业品牌色)
+
+主色调:
+- `$primary-color`: #005D80 - 企业主色 (WCAG AAA)
+- `$primary-light`: #007A99 - 悬停/强调
+- `$primary-dark`: #004060 - 点击/激活
+
+文字色:
+- `$text-primary`: #1F2937 - 主文字色
+- `$text-secondary`: #6B7280 - 次要文字色
+
+规范:
 - **渐变仅用于背景** - 不得用于文字
 - **文字必须使用纯色** - 确保对比度安全
 
-### 4. 组件样式结构
-```less
-// src/components/xxx/index.less
-@import '@/styles/variables.less';
+### 4. 圆角系统
 
-.xxx-component {
-    // 使用全局变量
-    padding: @spacing-4;
-    background: @bg-secondary;
-}
-```
+- `$radius-sm`: 4px
+- `$radius-md`: 6px
+- `$radius-lg`: 8px
+- `$radius-xl`: 12px
+- `$radius-2xl`: 16px
+- `$radius-full`: 9999px
+
+---
 
 ## Mock 数据规范
 
 ### 1. Mock 数据位置
+
 - 主文件:`src/mock/index.ts`
 - API 特定 Mock: `src/mock/{apiName}.ts`
+- 启用/禁用:在 `src/apis/api.ts` 中修改 `const USE_MOCK = true/false`
+
+### 2. 已完成的 Mock 配置
+
+#### 知识库管理 API
+- `POST /bigmodel/api/knowledgeList`
+- `GET /bigmodel/api/detailKnowledge/:id`
+- `POST /bigmodel/api/createKnowledge`
+- `PUT /bigmodel/api/updateKnowledge/:id`
+- `DELETE /bigmodel/api/delKnowledge/:id`
+- `GET /bigmodel/api/embedding`
+
+#### 文档管理 API
+- `POST /bigmodel/api/documentList`
+- `GET /bigmodel/api/documentDetail/:id`
+- `PUT /bigmodel/api/updateDocument/:id`
+- `DELETE /bigmodel/api/delDocument/:id`
+- `POST /bigmodel/api/uploadDocument/:knowledgeId`
+- `GET /bigmodel/api/documentSetting/:id`
+- `PUT /bigmodel/api/updateDocumentSetting/:id`
+
+#### 切片管理 API
+- `POST /bigmodel/api/getSliceList`
+- `GET /bigmodel/api/getSliceDetail/:sliceId/:knowledgeId`
+- `POST /bigmodel/api/add/slice`
+- `PUT /bigmodel/api/updateSliceInfo`
+- `DELETE /bigmodel/api/deleteSlice/:sliceId/:knowledgeId/:documentId`
+
+#### 修订工具 API
+- `GET /deepseek/revise/pageList`
+- `GET /deepseek/revise/list`
+- `GET /deepseek/revise/sliceList`
+- `PUT /deepseek/revise/reviseSlice`
+- `GET /deepseek/revise/reviseHistoryList`
+
+#### 字典数据 API
+- `GET /deepseek/api/standard_classification`
+- `GET /deepseek/api/parsing_type`
+- `GET /deepseek/api/splitting_type`
+- `GET /deepseek/api/revision_status`
+
+#### 聊天记录 API
+- `POST /bigmodel/api/chatHistory/list`
+- `POST /bigmodel/api/dialog/export/:id`
+
+### 3. 需要补充的 Mock 数据
+
+#### 高优先级
+- `/auth/login` (POST) - 用户登录
+- `/auth/code` (GET) - 获取验证码
+- `/system/user/getInfo` (GET) - 获取用户信息
+- `/deepseek/overview/topData` (GET) - 首页统计数据
+- `/bigmodel/api/getApplicationList` (POST) - 获取应用列表
+- `/deepseek/api/app/audit/list` (POST) - 审核列表
+
+#### 中优先级
+- `/bigmodel/api/selectApplication/:id` (GET) - 应用详情
+- `/deepseek/overview/onlineUserData` (GET) - 在线用户数据
+- `/deepseek/overview/conversationData` (GET) - 会话数据
+- `/deepseek/dataset/pageList` (GET) - 数据集列表
+
+---
 
-### 2. Mock 数据类型
-- 应用列表 (`mockAppList`)
-- 知识库列表 (`mockKnowledgeLibList`)
-- 系统管理数据
-- 用户数据 (`mockCurrentUser`)
+## 页面路由规范
 
-### 3. 启用/禁用 Mock
-在 `src/apis/api.ts` 中修改:
-```typescript
-const USE_MOCK = true;  // 启用 Mock
-```
+### 1. 路由配置
 
-## Git 操作规范
+**业务路由** (`src/store/route.tsx`):
 
-### 1. 提交前检查
-- 确认所有必要的文件已存在或已删除
-- 避免误删重要组件文件
-- 备份关键配置文件
+- `/overview` - `home/index` - 概览/首页
+- `/appCenter` - `appPlazaList/index` - 应用中心
+- `/appCenter/questionAnswer` - `questionAnswer/list` - 我创建的应用
+- `/appCenter/questionAnswer/create` - `questionAnswer/form/index` - 创建应用
+- `/knowledge/knowledgeLib` - `knowledgeLib/list` - 知识库列表
+- `/knowledge/knowledgeLib/:id/:createBy` - `knowledgeLib/detail/index` - 知识库详情
+- `/knowledge/revisionTool` - `revisionTool/list` - 修订工具
+- `/system/apiKey` - `apiKey/index` - API Key 管理
+- `/system/audit` - `audit/index.placeholder` - 应用审核 (待实现)
 
-### 2. 分支管理
-- 主分支:`master`
-- 开发分支:当前分支 (如 `zy`)
-- 不要直接 push 到 master
+**公共路由** (`src/router.tsx`):
 
-## 页面路由规范
+- `/login` - 登录页
+- `/universalChat` - 智能问答 (独立)
+- `/mobile-test` - H5 测试
+- `/404` - 404 页面
+
+### 2. 标准列表页结构
 
-### 1. 标准列表页结构
 ```tsx
 <div className="page-container">
-    <div className="list-header">...</div>
-    <GuideTips />  {/* 可选 */}
-    <FilterBar />  {/* 可选 */}
-    <div className="content-section">...</div>
+    <div className="list-header">
+        <div className="list-header-title">
+            <h1>页面标题</h1>
+            <p>页面描述</p>
+        </div>
+        <div className="list-header-actions">
+            <Button type="primary">创建</Button>
+        </div>
+    </div>
+
+    <GuideTips visible={true} title="提示" steps={[]} />
+    <FilterBar tabs={[]} searchValue="" />
+
+    <div className="content-section">
+        {/* 表格/卡片内容 */}
+    </div>
 </div>
 ```
 
-### 2. 卡片网格页结构
-```tsx
+### 3. 卡片网格页结构
+
+```text
 <div className="page-container">
     <div className="list-header">...</div>
-    <FilterBar />
-    <div className="app-card-grid">...</div>
-    <div className="pagination-container">...</div>
+    <FilterBar tabs={[]} />
+    <div className="app-card-grid">
+        <AppCard ... />
+    </div>
+    <div className="pagination-container">
+        <Pagination ... />
+    </div>
 </div>
 ```
 
-## 技术栈版本
-- React: 18.2.0
-- TypeScript: 5.7.0
-- Vite: 7.1.11
-- Ant Design: 5.23.0
-- Zustand: 5.0.12
-- Less: 4.2.0
-
-## Mock 数据实现状态
-
-### ✅ 已完成的 Mock 配置
-
-#### 1. API 拦截器 - `src/apis/api.ts` (USE_MOCK = true)
-Mock 处理器映射 (`mockHandlerMap`) 包含以下接口:
-
-**知识库管理 API:**
-- ✅ `POST /bigmodel/api/knowledgeList` → `mockFetchKnowledgeLibList`
-- ✅ `GET /bigmodel/api/detailKnowledge/:id` → `mockFetchKnowledgeLibDetail`
-- ✅ `POST /bigmodel/api/createKnowledge` → `mockCreateKnowledgeLib`
-- ✅ `PUT /bigmodel/api/updateKnowledge/:id` → `mockModifyKnowledgeLib`
-- ✅ `DELETE /bigmodel/api/delKnowledge/:id` → `mockDeleteKnowledgeLib`
-- ✅ `GET /bigmodel/api/embedding` → `mockFetchEmbeddingList`
-
-**文档管理 API:**
-- ✅ `POST /bigmodel/api/documentList` → `mockFetchDocumentLibList`
-- ✅ `GET /bigmodel/api/documentDetail/:id` → `mockFetchDocumentLibDetail`
-- ✅ `PUT /bigmodel/api/updateDocument/:id` → `mockModifyDocumentLib`
-- ✅ `DELETE /bigmodel/api/delDocument/:id` → `mockDeleteDocumentLib`
-- ✅ `POST /bigmodel/api/uploadDocument/:knowledgeId` → `mockUploadDocument`
-- ✅ `GET /bigmodel/api/documentSetting/:id` → `mockFetchDocumentSetting`
-- ✅ `PUT /bigmodel/api/updateDocumentSetting/:id` → `mockModifyDocumentSetting`
-
-**切片管理 API:**
-- ✅ `POST /bigmodel/api/getSliceList` → `mockFetchSliceList`
-- ✅ `GET /bigmodel/api/getSliceDetail/:sliceId/:knowledgeId` → `mockFetchSliceDetail`
-- ✅ `POST /bigmodel/api/add/slice` → `mockAddSlice`
-- ✅ `PUT /bigmodel/api/updateSliceInfo` → `mockModifySlice`
-- ✅ `DELETE /bigmodel/api/deleteSlice/:sliceId/:knowledgeId/:documentId` → `mockDeleteSlice`
-
-**修订工具 API:**
-- ✅ `GET /deepseek/revise/pageList` → `mockFetchReviseToolList`
-- ✅ `GET /deepseek/revise/list` → `mockFetchReviseToolAllList`
-- ✅ `GET /deepseek/revise/sliceList` → `mockFetchReviseToolSliceList`
-- ✅ `PUT /deepseek/revise/reviseSlice` → `mockSubmitReviseSlice`
-- ✅ `GET /deepseek/revise/reviseHistoryList` → `mockFetchReviseHistoryList`
-
-**字典数据 API:**
-- ✅ `GET /deepseek/api/standard_classification` → `mockFetchTakaiAppTypeList`
-- ✅ `GET /deepseek/api/parsing_type` → `mockFetchTakaiAppTypeList`
-- ✅ `GET /deepseek/api/splitting_type` → `mockFetchTakaiAppTypeList`
-- ✅ `GET /deepseek/api/revision_status` → `mockFetchTakaiAppTypeList`
-
-**聊天记录 API:**
-- ✅ `POST /bigmodel/api/chatHistory/list` → `mockFetchChatHistoryList`
-- ✅ `POST /bigmodel/api/dialog/export/:id` → `mockExportChatHistory`
-
-#### 2. Mock 数据文件 - `src/mock/knowledgeApi.ts`
-包含所有知识库相关 Mock 数据和 API 实现:
-- `mockKnowledgeLibList` - 知识库列表 (8 条)
-- `mockDocumentList` - 文档列表 (5 条)
-- `mockSliceList` - 切片列表 (5 条)
-- `mockReviseToolList` - 修订工具列表 (3 条)
-- `mockChatHistoryList` - 聊天记录 (2 条)
-
-#### 3. Mock 数据文件 - `src/mock/index.ts`
-全局 Mock 数据管理:
-- ✅ `mockAppList` - 应用卡片数据
-- ✅ `mockCurrentUser` - 当前登录用户
-- ✅ `getAppsByPageType()` - 按页面类型获取应用
-- ✅ `getPageConfig()` - 获取页面配置
-
-### ⚠️ 需要补充的 Mock 数据
-
-#### 1. 首页相关 API (未实现)
-| 接口 | 方法 | 当前状态 | 优先级 |
-|------|------|---------|--------|
-| `/deepseek/overview/topData` | GET | ❌ 未实现 | 高 |
-| `/deepseek/overview/onlineUserData` | GET | ❌ 未实现 | 中 |
-| `/deepseek/overview/conversationData` | GET | ❌ 未实现 | 中 |
-| `/deepseek/overview/conversationDetailData` | GET | ❌ 未实现 | 低 |
-| `/deepseek/overview/overviewTokenData` | GET | ❌ 未实现 | 低 |
-| `/deepseek/overview/overviewAppData` | GET | ❌ 未实现 | 中 |
-| `/deepseek/overview/overviewKnowledgeData` | GET | ❌ 未实现 | 中 |
-
-#### 2. 应用相关 API (未实现)
-| 接口 | 方法 | 当前状态 | 优先级 |
-|------|------|---------|--------|
-| `/bigmodel/api/getApplicationList` | POST | ⚠️ 需要添加 Mock | 高 |
-| `/bigmodel/api/selectApplication/:id` | GET | ❌ 未实现 | 中 |
-| `/bigmodel/api/createApplication` | POST | ❌ 未实现 | 中 |
-| `/bigmodel/api/updateApplication/:id` | PUT | ❌ 未实现 | 低 |
-| `/bigmodel/api/delApplication/:id` | DELETE | ❌ 未实现 | 低 |
-
-#### 3. 数据集和评测 API (未实现)
-| 接口 | 方法 | 当前状态 | 优先级 |
-|------|------|---------|--------|
-| `/deepseek/dataset/pageList` | GET | ❌ 未实现 | 中 |
-| `/deepseek/dataset/create` | POST | ❌ 未实现 | 低 |
-| `/deepseek/evaluation/pageList` | GET | ❌ 未实现 | 低 |
-
-#### 4. 审核相关 API (部分实现)
-| 接口 | 方法 | 当前状态 | 优先级 |
-|------|------|---------|--------|
-| `/deepseek/api/app/audit/list` | POST | ⚠️ 需要添加 Mock | 高 |
-| `/deepseek/api/app/auditHistory/list` | POST | ❌ 未实现 | 中 |
-
-#### 5. 用户和系统 API (部分实现)
-| 接口 | 方法 | 当前状态 | 优先级 |
-|------|------|---------|--------|
-| `/system/user/getInfo` | GET | ⚠️ 需要添加 Mock | 高 |
-| `/auth/login` | POST | ⚠️ 已配置加密但无 Mock | 高 |
-| `/auth/code` | GET | ❌ 未实现 | 中 |
-
-### 📋 Mock 数据优先级计划
-
-**第一阶段 - 核心页面 (必须):**
-1. 登录 API (`/auth/login`, `/auth/code`)
-2. 首页统计 API (`/deepseek/overview/topData`)
-3. 应用列表 API (`/bigmodel/api/getApplicationList`)
-4. 知识库列表 API (✅ 已完成)
-
-**第二阶段 - 主要功能:**
-5. 用户信息 API (`/system/user/getInfo`)
-6. 审核列表 API (`/deepseek/api/app/audit/list`)
-7. 应用详情 API (`/bigmodel/api/selectApplication/:id`)
-
-**第三阶段 - 辅助功能:**
-8. 数据集管理 API
-9. 评测任务 API
-10. 其他统计图表数据
+---
 
 ## Git 操作规范
 
 ### 1. 提交前检查
+
 - 确认所有必要的文件已存在或已删除
 - 避免误删重要组件文件
 - 备份关键配置文件
 
 ### 2. 分支管理
+
 - 主分支:`master`
 - 开发分支:当前分支 (如 `zy`)
 - 不要直接 push 到 master
 
-## 页面路由规范
+### 3. 当前状态
 
-### 1. 标准列表页结构
-```tsx
-<div className="page-container">
-    <div className="list-header">...</div>
-    <GuideTips />  {/* 可选 */}
-    <FilterBar />  {/* 可选 */}
-    <div className="content-section">...</div>
-</div>
+```bash
+# 查看修改
+git status
+git diff HEAD --stat
 ```
 
-### 2. 卡片网格页结构
-```tsx
-<div className="page-container">
-    <div className="list-header">...</div>
-    <FilterBar />
-    <div className="app-card-grid">...</div>
-    <div className="pagination-container">...</div>
-</div>
-```
+### 4. 重要规则
+
+- **每次修改功能模块之前必须先提交 git** - 确保当前修改已保存后再开始新任务
+- 提交时使用清晰的 commit message
+- 修改完成后自动执行 git commit
+
+---
+
+## TODO List
+
+### P0 - 紧急且重要
+
+- [x] **补充核心 API Mock 数据**
+  - [x] 登录 API (`/auth/login`, `/auth/code`) - 已完成于 `src/mock/authApi.ts`
+  - [x] 首页统计 API (`/deepseek/overview/topData`) - 已完成于 `src/mock/overviewApi.ts`
+  - [x] 应用列表 API (`/bigmodel/api/getApplicationList`) - 已完成于 `src/mock/applicationApi.ts`
+  - [x] 审核列表 API (`/deepseek/api/app/audit/list`) - 已完成于 `src/mock/auditApi.ts`
+
+- [x] **完成审核页面实现**
+  - 已完成审核列表、审核操作(通过/拒绝)、详情查看、统计数据功能
+  - 文件:`src/pages/system/audit/index.tsx`, `src/pages/system/audit/store.ts`
+
+### P1 - 重要不紧急
+
+- [x] **统一样式变量使用**
+  - [x] 检查所有 `.scss` 文件是否导入 `variables.scss`
+  - [x] 移除硬编码的颜色值和间距值
+  - [x] 确保使用 `$spacing-*` 系列变量
+  - 已修复文件:`layout/style.scss`, `layout/components/sidebar.scss`, `system/audit/style.scss`, `styles/global.scss`
+
+- [x] **补充应用管理 API Mock**
+  - [x] 应用列表 API
+  - [x] 应用详情 API
+  - [x] 创建应用 API
+  - [x] 更新应用 API
+  - [x] 删除应用 API
+
+- [x] **完善文档**
+  - [x] 更新 README.md
+  - [x] 补充 API 接口文档 (`docs/API.md`)
+  - API 文档已参考 Dify 风格,保留:应用调用接口、知识库检索接口
+
+### P2 - 可选优化 (待执行)
+
+- [ ] 响应式布局优化 - **待确认页面清单**
+- [ ] 主题切换功能 (dark/light)
+- [ ] 性能优化 (代码分割、图片压缩)
+
+---
 
 ## 技术栈版本
+
 - React: 18.2.0
 - TypeScript: 5.7.0
 - Vite: 7.1.11
 - Ant Design: 5.23.0
 - Zustand: 5.0.12
-- Less: 4.2.0
+- React Router: 7.1.0
+- TailwindCSS: 4.1.17
+- SCSS (Sass): 1.98.0
+
+---
 
 ## 启动命令
+
 ```bash
-npm run start:demo      # Demo 模式(静态)
+# 开发
+npm run start:demo      # Demo 模式(静态 + Mock)
 npm run start           # 开发模式(带 API)
-npm run build:demo      # 构建 Demo 版本
+
+# 构建
+npm run build:demo      # 构建 Demo 版
+npm run build:prod      # 构建生产版
 ```
+
+---
+
+## 登录认证
+
+### SSO 认证地址
+
+`http://esc.sribs.com.cn:8080/esc-sso/oauth2.0/authorize?client_id=e97f94cf93761f4d69e8&response_type=code`
+
+### Token 验证
+
+在 `src/router.tsx` 中实现:
+- Token 登录验证
+- Code 换 Token 流程
+- 白名单路由 (`/login`)
+
+---
+
+## 相关文件
+
+- `README.md` - 项目说明
+- `页面布局与间距控制规范.md` - 布局规范
+- `知识库路由和 Mock 数据说明.md` - Mock 数据说明
+
+
+**最后更新**: 2026-04-02

+ 31 - 1
jk-rag-platform/.claude/settings.local.json

@@ -73,7 +73,37 @@
       "Bash(done)",
       "Bash(grep:*)",
       "Bash(curl -s http://localhost:3100)",
-      "Bash(npx sass:*)"
+      "Bash(npx sass:*)",
+      "WebSearch",
+      "WebFetch(domain:www.npmjs.com)",
+      "Bash(npm search:*)",
+      "WebFetch(domain:iconoir.com)",
+      "WebFetch(domain:github.com)",
+      "Bash(npm info:*)",
+      "Bash(ls -la /Users/misasagi/Git/xiaozhi-v2/jk-rag-platform/*.md)",
+      "WebFetch(domain:lucide.dev)",
+      "Bash(npm uninstall:*)",
+      "Bash(lsof -ti:3100)",
+      "Bash(xargs kill:*)",
+      "Bash(python3 -c \"import pandas; print\\(''pandas available''\\)\")",
+      "Bash(pip3 install:*)",
+      "Bash(pip install:*)",
+      "Bash(/opt/homebrew/bin/python3 -m pip install openpyxl pandas --quiet 2>&1)",
+      "Bash(node:*)",
+      "Bash(git log:*)",
+      "mcp__ide__getDiagnostics",
+      "Bash(ls -la /Users/misasagi/Git/xiaozhi-v2/jk-rag-platform/*.js)",
+      "Bash(brew upgrade:*)",
+      "Bash(xxd)",
+      "Bash(pkill -f \"vite\")",
+      "Bash(g)",
+      "Bash(s)",
+      "Bash(^TEMP_PLACEHOLDER_LINE$)",
+      "Bash(g ' \"/Users/misasagi/Git/xiaozhi-v2/jk-rag-platform/src/pages/system/audit/components/style.scss\")",
+      "Bash(for file:*)",
+      "Bash(rm -rf node_modules/.vite)",
+      "Bash(find . -name \"*.vite\" -type d -exec rm -rf {} +)",
+      "Bash(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:3100/)"
     ]
   }
 }

+ 110 - 14
jk-rag-platform/README.md

@@ -1,8 +1,10 @@
 # 建科小智开放平台
 
-**项目名称**: jk-rag-platform  
-**版本**: v3.0  
-**技术栈**: React 18 + TypeScript + Zustand + Vite + Ant Design
+**项目名称**: jk-rag-platform
+**版本**: v3.8
+**技术栈**: React 18 + TypeScript + Zustand + Vite + Ant Design + SCSS
+
+基于 RAG 技术的知识库管理与应用开发平台
 
 ## 🚀 快速开始
 
@@ -10,36 +12,130 @@
 # 安装依赖
 npm install
 
-# 启动开发服务器(Demo 模式)
+# 启动开发服务器(Demo 模式,静态 + Mock
 npm run start:demo
 
-# 启动开发服务器(开发模式)
+# 启动开发服务器(开发模式,带 API
 npm run start
 
 # 构建生产版本
 npm run build:prod
+
+# 构建 Demo 版本
+npm run build:demo
 ```
 
 ## 📁 项目结构
 
 ```
 src/
-├── components/common/     # 公共组件
+├── apis/                  # API 接口配置
+│   ├── api.ts             # Axios 实例和 Mock 配置
+│   ├── index.ts           # API 函数导出
+│   └── config.ts          # API 配置
+├── components/            # 公共组件
+│   ├── 404/               # 404 页面
+│   ├── chat/              # 聊天组件
+│   └── common/            # 通用组件
+│       ├── FilterBar/     # 筛选栏
+│       ├── FilterDrawer/  # 筛选抽屉
+│       ├── AppCard/       # 应用卡片
+│       ├── GuideTips/     # 引导提示
+│       ├── HeroBanner/    # 横幅
+│       ├── PageLayout/    # 页面布局
+│       └── StatsGrid/     # 统计卡片
+├── config/                # 配置文件
+├── mock/                  # Mock 数据
+│   ├── index.ts           # 全局 Mock 配置
+│   ├── knowledgeApi.ts    # 知识库 Mock API
+│   ├── applicationApi.ts  # 应用管理 Mock API
+│   ├── authApi.ts         # 认证 Mock API
+│   ├── auditApi.ts        # 审核管理 Mock API
+│   └── overviewApi.ts     # 首页统计 Mock API
 ├── pages/                 # 页面组件
+│   ├── appCenter/         # 应用中心
+│   ├── home/              # 首页/概览
+│   ├── knowledgeLib/      # 知识库管理
+│   ├── layout/            # 布局组件
+│   ├── login/             # 登录
+│   ├── questionAnswer/    # 问答应用
+│   ├── system/            # 系统管理
+│   │   ├── apiKey/        # API Key 管理
+│   │   └── audit/         # 应用审核
+│   └── universalChat/     # 智能问答
+├── store/                 # 状态管理 (Zustand)
+│   └── route.tsx          # 路由配置
 ├── styles/                # 全局样式
-├── store/                 # 状态管理
-└── utils/                 # 工具函数
+│   ├── variables.scss     # SCSS 变量
+│   └── global.scss        # 全局样式
+├── typings/               # 类型定义
+├── utils/                 # 工具函数
+│   ├── crypto.ts          # 加密工具
+│   └── jsencrypt.ts       # JS 加密
+├── LocalStorage.ts        # 本地存储封装
+├── App.tsx
+├── main.tsx
+└── router.tsx             # 路由配置
 ```
 
 ## 📋 主要功能
 
-- ✅ 应用广场
-- ✅ 知识库管理
-- ✅ 创建应用
-- ✅ API 管理
-- ✅ 应用审核
+### 应用中心
+- ✅ 应用广场 - 浏览所有 RAG 应用
+- ✅ 应用分类 - 专业知识、职能管理、项目级应用
+- ✅ 我创建的应用 - 管理个人创建的应用
+- ✅ 应用创建/编辑/删除
+
+### 知识库管理
+- ✅ 知识库列表 - CRUD 操作
+- ✅ 文档管理 - 上传、编辑、删除文档
+- ✅ 切片管理 - 查看、编辑、删除切片
+- ✅ 修订工具 - 切片修订和历史记录
+
+### 系统管理
+- ✅ API Key 管理
+- ✅ 应用审核 - 审核应用上线申请
+
+### 其他功能
+- ✅ 智能问答
+- ✅ 聊天记录管理
+- ✅ SSO 登录认证
+
+## 🔧 Mock 数据配置
+
+在 `src/apis/api.ts` 中修改 `USE_MOCK` 标志:
+
+```typescript
+const USE_MOCK = true;  // 启用 Mock 模式
+```
 
-## 📄 文档
+已实现的 Mock API:
+- 知识库管理(知识列表、文档管理、切片管理)
+- 修订工具(修订列表、修订历史)
+- 应用管理(应用列表、详情、CRUD)
+- 认证登录(登录、验证码、用户信息)
+- 审核管理(审核列表、审核操作、统计)
+- 首页统计(概览数据、在线用户、会话数据)
 
+## 🎨 样式规范
+
+使用全局 SCSS 变量,文件顶部必须导入:
+
+```scss
+@import '@/styles/variables.scss';
+```
+
+主要变量:
+- `$primary-color`: #005D80 - 企业主色
+- `$spacing-*`: 4px 基准间距系统
+- `$radius-*`: 圆角系统
+
+## 📄 相关文档
+
+- [.claude-rules.md](./.claude-rules.md) - 项目开发规范
 - [项目修改记录](./项目修改记录.md)
 - [设计规范](./建科小智设计规范_v3.md)
+
+---
+
+**最后更新**: 2026-04-02

+ 0 - 10
jk-rag-platform/demo.log

@@ -1,10 +0,0 @@
-
-> chat-admin-web@1.0.0 start:demo
-> vite --mode development
-
-error when starting dev server:
-Error: Port 3100 is already in use
-    at Server.onError$1 (file:///Users/misasagi/Git/jkec-xiaozhi-v2/jk-rag-platform/node_modules/vite/dist/node/chunks/config.js:14933:28)
-    at Server.emit (node:events:524:28)
-    at emitErrorNT (node:net:1944:8)
-    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

+ 556 - 0
jk-rag-platform/docs/API.md

@@ -0,0 +1,556 @@
+# RAG 应用 API 接口文档
+
+**项目**: 建科小智开放平台
+**版本**: v3.8
+**最后更新**: 2026-04-02
+
+---
+
+## 概述
+
+本文档介绍如何通过 API 调用 RAG 应用和知识库检索功能。
+
+### 基础信息
+
+- **Base URL**: `http://your-domain.com/bigmodel/api`
+- **认证方式**: API Key / Token
+- **数据格式**: JSON
+
+### 认证方式
+
+在请求头中携带认证信息:
+
+```http
+Authorization: Bearer {your_token}
+```
+
+或
+
+```http
+X-API-Key: {your_api_key}
+```
+
+---
+
+## 应用调用接口
+
+通过应用 ID 调用 RAG 应用,实现智能问答功能。
+
+### 发送对话消息
+
+向指定应用发送消息并获取回复。
+
+```http
+POST /chat/{appId}
+```
+
+**路径参数**:
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| appId | string | 是 | RAG 应用 ID |
+
+**请求参数**:
+
+| 参数 | 类型 | 必填 | 默认值 | 说明 |
+|------|------|------|--------|------|
+| query | string | 是 | - | 用户问题内容 |
+| conversationId | string | 否 | - | 会话 ID(用于多轮对话) |
+| userId | string | 否 | - | 用户 ID(用于区分不同用户) |
+| streaming | boolean | 否 | false | 是否使用流式响应 |
+
+**请求示例**:
+
+```bash
+curl -X POST http://your-domain.com/bigmodel/api/chat/app_001 \
+  -H "Authorization: Bearer your_token" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "query": "如何申请年假?",
+    "userId": "user_123",
+    "streaming": false
+  }'
+```
+
+**响应示例**(非流式):
+
+```json
+{
+    "code": 200,
+    "message": "success",
+    "data": {
+        "conversationId": "conv_abc123",
+        "answer": "申请年假的流程如下:\n\n1. 登录公司 OA 系统\n2. 进入\"请假申请\"页面\n3. 选择请假类型为\"年假\"\n4. 填写请假日期和天数\n5. 提交申请等待审批",
+        "sources": [
+            {
+                "documentId": "doc_001",
+                "documentName": "员工手册.pdf",
+                "sliceId": "slice_001",
+                "content": "员工年假申请需提前 3 个工作日在 OA 系统提交...",
+                "score": 0.92
+            },
+            {
+                "documentId": "doc_002",
+                "documentName": "考勤管理制度.pdf",
+                "sliceId": "slice_045",
+                "content": "年假天数根据工龄计算:1-3 年 5 天,3-5 年 10 天...",
+                "score": 0.85
+            }
+        ],
+        "usage": {
+            "promptTokens": 156,
+            "completionTokens": 89,
+            "totalTokens": 245
+        }
+    }
+}
+```
+
+**流式响应示例**:
+
+当 `streaming: true` 时,服务器会以 SSE (Server-Sent Events) 方式推送数据:
+
+```text
+data: {"answer": "申", "conversationId": "conv_abc123"}
+
+data: {"answer": "请年假", "conversationId": "conv_abc123"}
+
+data: {"answer": "的流程如下:\n\n", "conversationId": "conv_abc123"}
+
+data: {"answer": "1. 登录 OA 系统", "conversationId": "conv_abc123"}
+
+data: [DONE]
+```
+
+**错误响应**:
+
+```json
+{
+    "code": 400,
+    "message": "应用不存在或已下线",
+    "data": null
+}
+```
+
+---
+
+### 获取对话历史
+
+获取指定会话的完整对话历史。
+
+```http
+GET /chat/{appId}/history/{conversationId}
+```
+
+**路径参数**:
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| appId | string | 是 | RAG 应用 ID |
+| conversationId | string | 是 | 会话 ID |
+
+**响应示例**:
+
+```json
+{
+    "code": 200,
+    "message": "success",
+    "data": {
+        "conversationId": "conv_abc123",
+        "appId": "app_001",
+        "userId": "user_123",
+        "createdAt": "2026-04-02 10:30:00",
+        "updatedAt": "2026-04-02 11:45:00",
+        "messages": [
+            {
+                "id": "msg_001",
+                "role": "user",
+                "content": "如何申请年假?",
+                "createdAt": "2026-04-02 10:30:00"
+            },
+            {
+                "id": "msg_002",
+                "role": "assistant",
+                "content": "申请年假的流程如下:\n\n1. 登录公司 OA 系统\n2. 进入\"请假申请\"页面...",
+                "createdAt": "2026-04-02 10:30:05",
+                "sources": [
+                    {
+                        "documentName": "员工手册.pdf",
+                        "content": "员工年假申请需提前 3 个工作日..."
+                    }
+                ]
+            },
+            {
+                "id": "msg_003",
+                "role": "user",
+                "content": "年假有多少天?",
+                "createdAt": "2026-04-02 10:31:00"
+            },
+            {
+                "id": "msg_004",
+                "role": "assistant",
+                "content": "年假天数根据工龄计算:\n- 1-3 年:5 天\n- 3-5 年:10 天\n- 5-10 年:15 天",
+                "createdAt": "2026-04-02 10:31:05"
+            }
+        ]
+    }
+}
+```
+
+---
+
+### 删除对话会话
+
+删除指定的对话会话及其所有历史记录。
+
+```http
+DELETE /chat/{appId}/history/{conversationId}
+```
+
+**响应示例**:
+
+```json
+{
+    "code": 200,
+    "message": "删除成功",
+    "data": {
+        "conversationId": "conv_abc123"
+    }
+}
+```
+
+---
+
+## 知识库检索接口
+
+直接调用知识库进行文档检索,不经过应用层。
+
+### 单一知识库检索
+
+在单个知识库中进行语义检索。
+
+```http
+POST /knowledge/{knowledgeId}/search
+```
+
+**路径参数**:
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| knowledgeId | string | 是 | 知识库 ID |
+
+**请求参数**:
+
+| 参数 | 类型 | 必填 | 默认值 | 说明 |
+|------|------|------|--------|------|
+| query | string | 是 | - | 检索关键词或问题 |
+| topK | number | 否 | 5 | 返回结果数量(1-20) |
+| scoreThreshold | number | 否 | 0.5 | 相似度阈值(0-1) |
+| documentIds | array | 否 | - | 指定检索的文档 ID 列表 |
+
+**请求示例**:
+
+```bash
+curl -X POST http://your-domain.com/bigmodel/api/knowledge/kb_001/search \
+  -H "Authorization: Bearer your_token" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "query": "年假申请流程",
+    "topK": 10,
+    "scoreThreshold": 0.7
+  }'
+```
+
+**响应示例**:
+
+```json
+{
+    "code": 200,
+    "message": "success",
+    "data": {
+        "knowledgeId": "kb_001",
+        "knowledgeName": "人力资源知识库",
+        "query": "年假申请流程",
+        "total": 5,
+        "results": [
+            {
+                "sliceId": "slice_001",
+                "documentId": "doc_001",
+                "documentName": "员工手册.pdf",
+                "content": "员工年假申请需提前 3 个工作日在 OA 系统提交申请,经部门经理审批后方可休假。",
+                "score": 0.92,
+                "metadata": {
+                    "pageNumber": 15,
+                    "position": "第 3 章 第 2 节"
+                }
+            },
+            {
+                "sliceId": "slice_045",
+                "documentId": "doc_002",
+                "documentName": "考勤管理制度.pdf",
+                "content": "年假天数根据工龄计算:1-3 年 5 天,3-5 年 10 天,5-10 年 15 天,10 年以上 20 天。",
+                "score": 0.85,
+                "metadata": {
+                    "pageNumber": 8,
+                    "position": "第 2 章 第 5 条"
+                }
+            },
+            {
+                "sliceId": "slice_112",
+                "documentId": "doc_001",
+                "documentName": "员工手册.pdf",
+                "content": "未休年假可在当年申请折现,折现标准按日工资的 300% 计算。",
+                "score": 0.78,
+                "metadata": {
+                    "pageNumber": 16,
+                    "position": "第 3 章 第 3 节"
+                }
+            }
+        ]
+    }
+}
+```
+
+---
+
+### 多知识库联合检索
+
+在多个知识库中进行联合语义检索。
+
+```http
+POST /knowledge/search
+```
+
+**请求参数**:
+
+| 参数 | 类型 | 必填 | 默认值 | 说明 |
+|------|------|------|--------|------|
+| query | string | 是 | - | 检索关键词或问题 |
+| knowledgeIds | array | 是 | - | 知识库 ID 列表 |
+| topK | number | 否 | 5 | 每个知识库返回结果数量 |
+| scoreThreshold | number | 否 | 0.5 | 相似度阈值 |
+| rerank | boolean | 否 | false | 是否启用重排序 |
+
+**请求示例**:
+
+```bash
+curl -X POST http://your-domain.com/bigmodel/api/knowledge/search \
+  -H "Authorization: Bearer your_token" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "query": "项目报销流程",
+    "knowledgeIds": ["kb_001", "kb_003", "kb_005"],
+    "topK": 5,
+    "rerank": true
+  }'
+```
+
+**响应示例**:
+
+```json
+{
+    "code": 200,
+    "message": "success",
+    "data": {
+        "query": "项目报销流程",
+        "knowledgeBaseCount": 3,
+        "total": 12,
+        "results": [
+            {
+                "knowledgeId": "kb_003",
+                "knowledgeName": "财务知识库",
+                "slices": [
+                    {
+                        "sliceId": "slice_201",
+                        "documentId": "doc_050",
+                        "documentName": "项目费用报销管理办法.pdf",
+                        "content": "项目报销流程:1. 填写报销单 2. 附上发票和明细 3. 项目经理审批 4. 财务审核 5. 出纳付款",
+                        "score": 0.95,
+                        "rerankScore": 0.98
+                    },
+                    {
+                        "sliceId": "slice_205",
+                        "documentId": "doc_050",
+                        "documentName": "项目费用报销管理办法.pdf",
+                        "content": "差旅费报销需提供往返交通票据和住宿发票,市内交通按每天 80 元包干。",
+                        "score": 0.82,
+                        "rerankScore": 0.85
+                    }
+                ]
+            },
+            {
+                "knowledgeId": "kb_001",
+                "knowledgeName": "人力资源知识库",
+                "slices": [
+                    {
+                        "sliceId": "slice_078",
+                        "documentId": "doc_015",
+                        "documentName": "员工福利手册.pdf",
+                        "content": "项目奖金发放与报销是独立的流程,奖金随工资发放,报销单独走财务流程。",
+                        "score": 0.71,
+                        "rerankScore": 0.72
+                    }
+                ]
+            }
+        ]
+    }
+}
+```
+
+---
+
+### 获取知识库文档列表
+
+获取指定知识库中的文档列表。
+
+```http
+GET /knowledge/{knowledgeId}/documents
+```
+
+**查询参数**:
+
+| 参数 | 类型 | 必填 | 默认值 | 说明 |
+|------|------|------|--------|------|
+| pageNum | number | 否 | 1 | 页码 |
+| pageSize | number | 否 | 20 | 每页数量 |
+| keyword | string | 否 | - | 文件名关键词 |
+
+**响应示例**:
+
+```json
+{
+    "code": 200,
+    "message": "success",
+    "data": {
+        "knowledgeId": "kb_001",
+        "knowledgeName": "人力资源知识库",
+        "total": 15,
+        "pageNum": 1,
+        "pageSize": 20,
+        "documents": [
+            {
+                "documentId": "doc_001",
+                "fileName": "员工手册.pdf",
+                "fileSize": 2048576,
+                "fileType": "pdf",
+                "status": "active",
+                "sliceCount": 45,
+                "createdAt": "2026-01-15 09:30:00",
+                "updatedAt": "2026-01-20 14:20:00"
+            },
+            {
+                "documentId": "doc_002",
+                "fileName": "考勤管理制度.pdf",
+                "fileSize": 1536000,
+                "fileType": "pdf",
+                "status": "active",
+                "sliceCount": 32,
+                "createdAt": "2026-01-16 10:00:00",
+                "updatedAt": "2026-01-22 11:30:00"
+            }
+        ]
+    }
+}
+```
+
+---
+
+## 错误码说明
+
+| 错误码 | 说明 |
+|--------|------|
+| 200 | 成功 |
+| 400 | 请求参数错误 |
+| 401 | 认证失败(Token 无效或过期) |
+| 403 | 无权限访问 |
+| 404 | 资源不存在(应用/知识库不存在) |
+| 429 | 请求频率超限 |
+| 500 | 服务器内部错误 |
+
+---
+
+## 使用示例
+
+### Python 示例
+
+```python
+import requests
+
+BASE_URL = "http://your-domain.com/bigmodel/api"
+TOKEN = "your_token"
+
+headers = {
+    "Authorization": f"Bearer {TOKEN}",
+    "Content-Type": "application/json"
+}
+
+# 调用 RAG 应用
+response = requests.post(
+    f"{BASE_URL}/chat/app_001",
+    headers=headers,
+    json={
+        "query": "如何申请年假?",
+        "userId": "user_123"
+    }
+)
+result = response.json()
+print(result["data"]["answer"])
+
+# 知识库检索
+response = requests.post(
+    f"{BASE_URL}/knowledge/kb_001/search",
+    headers=headers,
+    json={
+        "query": "年假申请流程",
+        "topK": 5
+    }
+)
+result = response.json()
+for item in result["data"]["results"]:
+    print(f"[{item['score']:.2f}] {item['content']}")
+```
+
+### JavaScript 示例
+
+```javascript
+const BASE_URL = 'http://your-domain.com/bigmodel/api';
+const TOKEN = 'your_token';
+
+const headers = {
+    'Authorization': `Bearer ${TOKEN}`,
+    'Content-Type': 'application/json'
+};
+
+// 调用 RAG 应用
+async function chat(appId, query, userId) {
+    const response = await fetch(`${BASE_URL}/chat/${appId}`, {
+        method: 'POST',
+        headers,
+        body: JSON.stringify({ query, userId })
+    });
+    const result = await response.json();
+    return result.data.answer;
+}
+
+// 知识库检索
+async function searchKnowledge(knowledgeId, query, topK = 5) {
+    const response = await fetch(`${BASE_URL}/knowledge/${knowledgeId}/search`, {
+        method: 'POST',
+        headers,
+        body: JSON.stringify({ query, topK })
+    });
+    const result = await response.json();
+    return result.data.results;
+}
+
+// 使用示例
+chat('app_001', '如何申请年假?', 'user_123')
+    .then(answer => console.log(answer));
+```
+
+---
+
+**备注**:
+- 所有接口的 Mock 数据位于 `src/mock/` 目录下
+- 在 `src/apis/api.ts` 中通过 `USE_MOCK` 标志切换 Mock/真实 API
+- 生产环境请关闭 Mock 模式

BIN
jk-rag-platform/e1.png


+ 2 - 0
jk-rag-platform/package.json

@@ -26,6 +26,7 @@
     "crypto-js": "^4.2.0",
     "dayjs": "^1.11.0",
     "jsencrypt": "^3.5.4",
+    "lucide-react": "^1.7.0",
     "mammoth": "^1.11.0",
     "markdown-it": "^14.1.0",
     "nanoid": "^5.1.6",
@@ -38,6 +39,7 @@
     "react-quill": "^2.0.0",
     "react-router-dom": "^7.1.0",
     "tailwindcss": "^4.1.17",
+    "xlsx": "^0.18.5",
     "zustand": "^5.0.12"
   },
   "devDependencies": {

+ 7 - 0
jk-rag-platform/src/App.tsx

@@ -56,6 +56,13 @@ const ConfigProvider: React.FC<ConfigProviderProps> = (props: ConfigProviderProp
                         headerBg: '#F7F8FA',
                         headerSplitColor: 'transparent',
                     },
+                    // 按钮组件主题配置
+                    Button: {
+                        colorPrimary: '#005D80',        // primary-color
+                        colorPrimaryHover: '#007A99',   // primary-light
+                        colorPrimaryActive: '#004060',  // primary-dark
+                        colorTextLightSolid: '#FFFFFF', // 按钮文字颜色
+                    },
                 },
             }}
             /* 组件配置 */

+ 21 - 5
jk-rag-platform/src/apis/api.ts

@@ -32,6 +32,10 @@ import {
     mockFetchChatHistoryList,
     mockExportChatHistory,
 } from '@/mock/knowledgeApi';
+import { applicationMockHandlers } from '@/mock/applicationApi';
+import { authMockHandlers } from '@/mock/authApi';
+import { auditMockHandlers } from '@/mock/auditApi';
+import { overviewMockHandlers } from '@/mock/overviewApi';
 
 const encryptHeader = 'encrypt-key';
 
@@ -53,7 +57,7 @@ const mockHandlerMap: Record<string, Function> = {
     'PUT /bigmodel/api/updateKnowledge': mockModifyKnowledgeLib,
     'DELETE /bigmodel/api/delKnowledge': mockDeleteKnowledgeLib,
     'GET /bigmodel/api/embedding': mockFetchEmbeddingList,
-    
+
     // 文档管理相关
     'POST /bigmodel/api/documentList': mockFetchDocumentLibList,
     'GET /bigmodel/api/documentDetail': mockFetchDocumentLibDetail,
@@ -62,30 +66,42 @@ const mockHandlerMap: Record<string, Function> = {
     'POST /bigmodel/api/uploadDocument': mockUploadDocument,
     'GET /bigmodel/api/documentSetting': mockFetchDocumentSetting,
     'PUT /bigmodel/api/updateDocumentSetting': mockModifyDocumentSetting,
-    
+
     // 切片管理相关
     'POST /bigmodel/api/getSliceList': mockFetchSliceList,
     'GET /bigmodel/api/getSliceDetail': mockFetchSliceDetail,
     'POST /bigmodel/api/add/slice': mockAddSlice,
     'PUT /bigmodel/api/updateSliceInfo': mockModifySlice,
     'DELETE /bigmodel/api/deleteSlice': mockDeleteSlice,
-    
+
     // 修订工具相关
     'GET /deepseek/revise/pageList': mockFetchReviseToolList,
     'GET /deepseek/revise/list': mockFetchReviseToolAllList,
     'GET /deepseek/revise/sliceList': mockFetchReviseToolSliceList,
     'PUT /deepseek/revise/reviseSlice': mockSubmitReviseSlice,
     'GET /deepseek/revise/reviseHistoryList': mockFetchReviseHistoryList,
-    
+
     // 字典数据相关
     'GET /deepseek/api/standard_classification': () => mockFetchTakaiAppTypeList('standard_classification'),
     'GET /deepseek/api/parsing_type': () => mockFetchTakaiAppTypeList('parsing_type'),
     'GET /deepseek/api/splitting_type': () => mockFetchTakaiAppTypeList('splitting_type'),
     'GET /deepseek/api/revision_status': () => mockFetchTakaiAppTypeList('revision_status'),
-    
+
     // 聊天记录相关
     'POST /bigmodel/api/chatHistory/list': mockFetchChatHistoryList,
     'POST /bigmodel/api/dialog/export': mockExportChatHistory,
+
+    // 应用管理相关
+    ...applicationMockHandlers,
+
+    // 认证与用户相关
+    ...authMockHandlers,
+
+    // 审核管理相关
+    ...auditMockHandlers,
+
+    // 首页统计相关
+    ...overviewMockHandlers,
 };
 
 // 请求拦截器

+ 50 - 2
jk-rag-platform/src/apis/index.ts

@@ -730,9 +730,31 @@ export const getTenantSize = async ()=>{
     return api.get('/system/tenant/getTenantSize');
 }
 // http://localhost:8080/deepseek/api/app/auditHistory/list
-export const fetchAuditHistoryList = async (data: any) => { 
+export const fetchAuditHistoryList = async (data: any) => {
     return api.post('/deepseek/api/app/auditHistory/list', { data: data });
 }
+
+// ==================== 审核管理相关 API ====================
+
+// 获取审核列表
+export const fetchAuditList = async (data: any) => {
+    return api.post('/deepseek/api/app/audit/list', data);
+};
+
+// 获取审核统计数据
+export const fetchAuditStats = async () => {
+    return api.get('/deepseek/api/app/audit/stats');
+};
+
+// 审核操作(通过/拒绝)
+export const auditAction = async (data: { auditId: string; action: string; opinion: string }) => {
+    return api.put('/deepseek/api/app/audit/auditAction', data);
+};
+
+// 获取审核详情
+export const fetchAuditDetail = async (auditId: string) => {
+    return api.get(`/deepseek/api/app/audit/detail/${auditId}`);
+};
 // POST http://localhost:8080/deepseek/api/document/checkQuoteFile 检查引用文件是否存在
 export const checkQuoteFileApi = async (data: any) => {
     return api.post('/deepseek/api/document/checkQuoteFile', data);
@@ -827,6 +849,28 @@ export const fetchOverviewKnowledgeData = async (data: any) => {
 }
 // DELETE http://localhost:8080/deepseek/api/deleteSlice/{{sliceId}}/{{knowledgeId}}/{{documentId}}
 
+// ==================== API Key 管理相关 ====================
+
+// 获取 API Key 列表
+export const fetchApiKeyList = async (data: any) => {
+    return api.get('/system/apikey/list', { params: data });
+};
+
+// 创建 API Key
+export const createApiKey = async (data: { name: string; remark?: string }) => {
+    return api.post('/system/apikey/create', data);
+};
+
+// 删除 API Key
+export const deleteApiKey = async (id: string) => {
+    return api.delete(`/system/apikey/delete/${id}`);
+};
+
+// 下载 API Key 文件
+export const downloadApiKey = async (id: string) => {
+    return api.get(`/system/apikey/download/${id}`, { responseType: 'blob' });
+};
+
 // end 建科新的APi
 
 export const apis = {
@@ -942,6 +986,10 @@ export const apis = {
     fetchOnlineUserData:fetchOnlineUserData,
     fetchConversationData:fetchConversationData,
     fetchConversationDetailData:fetchConversationDetailData,
-    fetchOverviewTokenData:fetchOverviewTokenData
+    fetchOverviewTokenData:fetchOverviewTokenData,
+    fetchApiKeyList: fetchApiKeyList,
+    createApiKey: createApiKey,
+    deleteApiKey: deleteApiKey,
+    downloadApiKey: downloadApiKey,
     // end 建科新的APi
 };

+ 1 - 1
jk-rag-platform/src/components/404/style.scss

@@ -16,7 +16,7 @@
 
     &-text {
         font-size: $font-lg;
-        font-weight: $font-bold;
+        font-weight: $font-weight-bold;
         color: $primary-color;
         margin-bottom: $spacing-5;
     }

+ 267 - 0
jk-rag-platform/src/components/common/AppCard/AppCardApiDoc.scss

@@ -0,0 +1,267 @@
+@use '@/styles/variables.scss' as *;
+// AppCard API 文档样式 - 简化版
+
+.api-doc-drawer {
+    .ant-drawer-body {
+        padding: 0;
+    }
+}
+
+.api-doc-content {
+    padding: $spacing-4 $spacing-5;
+    max-width: 650px;
+    margin: 0 auto;
+
+    // 章节样式
+    .api-section {
+        margin-bottom: $spacing-5;
+
+        .section-title {
+            font-size: $font-xl;
+            font-weight: $font-weight-semibold;
+            color: $text-primary;
+            margin-bottom: $spacing-2;
+            padding-bottom: $spacing-2;
+            border-bottom: 1px solid $border-base;
+        }
+
+        .section-content {
+            color: $text-secondary;
+            line-height: $line-height-relaxed;
+
+            p {
+                margin-bottom: $spacing-2;
+            }
+
+            .app-id-badge {
+                background: $bg-tertiary;
+                padding: 2px 8px;
+                border-radius: $radius-sm;
+                color: $primary-color;
+                font-family: monospace;
+                font-size: $font-sm;
+            }
+        }
+    }
+
+    // 信息卡片
+    .info-cards {
+        display: grid;
+        grid-template-columns: repeat(2, 1fr);
+        gap: $spacing-2;
+        margin-top: $spacing-2;
+    }
+
+    .info-card {
+        background: $bg-tertiary;
+        border-radius: $radius-md;
+        padding: $spacing-2;
+        border: 1px solid $border-light;
+
+        .card-label {
+            font-size: $font-xs;
+            color: $text-hint;
+            margin-bottom: $spacing-1;
+        }
+
+        .card-value {
+            font-size: $font-sm;
+            color: $text-primary;
+            font-family: monospace;
+
+            code {
+                background: $bg-secondary;
+                padding: 2px 6px;
+                border-radius: $radius-sm;
+                font-size: $font-xs;
+            }
+        }
+    }
+
+    // API 项目样式
+    .api-item {
+        padding: $spacing-3 0;
+        border-bottom: 1px solid $border-light;
+
+        &:last-child {
+            border-bottom: none;
+        }
+
+        .api-header {
+            display: flex;
+            align-items: center;
+            gap: $spacing-2;
+            margin-bottom: $spacing-2;
+
+            .api-method {
+                display: inline-block;
+                padding: 3px 10px;
+                border-radius: $radius-sm;
+                font-size: 11px;
+                font-weight: $font-weight-semibold;
+                text-transform: uppercase;
+
+                &.method-post {
+                    background: rgba($success-color, 0.1);
+                    color: $success-color;
+                }
+
+                &.method-get {
+                    background: rgba($info-color, 0.1);
+                    color: $info-color;
+                }
+            }
+
+            .api-path {
+                font-size: $font-md;
+                font-family: monospace;
+                color: $text-primary;
+                font-weight: $font-weight-medium;
+            }
+        }
+
+        .api-description {
+            color: $text-secondary;
+            margin-bottom: $spacing-3;
+            line-height: $line-height-relaxed;
+        }
+
+        h4 {
+            font-size: $font-sm;
+            font-weight: $font-weight-semibold;
+            color: $text-primary;
+            margin: $spacing-3 0 $spacing-2 0;
+        }
+    }
+
+    // 参数表格
+    .params-table {
+        margin: $spacing-2 0;
+        overflow-x: auto;
+
+        table {
+            width: 100%;
+            border-collapse: collapse;
+            font-size: $font-sm;
+
+            th, td {
+                padding: $spacing-2;
+                text-align: left;
+                border-bottom: 1px solid $border-light;
+            }
+
+            th {
+                background: $bg-tertiary;
+                font-weight: $font-weight-semibold;
+                color: $text-primary;
+                white-space: nowrap;
+            }
+
+            td {
+                color: $text-secondary;
+
+                &:nth-child(1) {
+                    code {
+                        background: $bg-tertiary;
+                        padding: 2px 6px;
+                        border-radius: $radius-sm;
+                        font-size: $font-sm;
+                        color: $primary-color;
+                    }
+                }
+
+                &:nth-child(2) {
+                    .param-type {
+                        color: $text-hint;
+                        font-family: monospace;
+                        font-size: $font-sm;
+                    }
+                }
+            }
+        }
+    }
+
+    // 代码块
+    .code-block {
+        margin: $spacing-2 0;
+        border-radius: $radius-md;
+        overflow: hidden;
+        border: 1px solid $border-base;
+
+        .code-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: $spacing-2 $spacing-3;
+            background: $bg-tertiary;
+            border-bottom: 1px solid $border-light;
+
+            .code-language {
+                font-size: $font-xs;
+                color: $text-hint;
+                text-transform: uppercase;
+            }
+
+            .ant-btn {
+                font-size: $font-xs;
+            }
+        }
+
+        .code-content {
+            margin: 0;
+            padding: $spacing-2;
+            background: #1a1a2e;
+            overflow-x: auto;
+            max-height: 200px;
+
+            code {
+                font-family: 'Monaco', 'Consolas', monospace;
+                font-size: $font-xs;
+                line-height: 1.5;
+                color: #e0e0e0;
+            }
+        }
+    }
+
+    // 响应示例
+    .response-example {
+        margin: $spacing-2 0;
+
+        .example-content {
+            margin: 0;
+            padding: $spacing-2;
+            background: $bg-tertiary;
+            border-radius: $radius-md;
+            border: 1px solid $border-light;
+            overflow-x: auto;
+            max-height: 150px;
+
+            code {
+                font-family: 'Monaco', 'Consolas', monospace;
+                font-size: $font-xs;
+                line-height: 1.5;
+                color: $text-primary;
+            }
+        }
+    }
+
+    // API Tabs
+    .api-tabs {
+        margin-top: $spacing-3;
+
+        .ant-tabs-tab {
+            font-size: $font-sm;
+        }
+    }
+}
+
+// 响应式适配
+@media (max-width: $screen-md) {
+    .api-doc-content {
+        padding: $spacing-3;
+
+        .info-cards {
+            grid-template-columns: 1fr;
+        }
+    }
+}

+ 286 - 0
jk-rag-platform/src/components/common/AppCard/AppCardApiDoc.tsx

@@ -0,0 +1,286 @@
+import * as React from 'react';
+import { Drawer, Button, Tabs, Tag, Space, message } from 'antd';
+import { CopyOutlined, CheckOutlined } from '@ant-design/icons';
+import './AppCardApiDoc.scss';
+
+const { TabPane } = Tabs;
+
+interface Props {
+    open: boolean;
+    appId: string;
+    onClose: () => void;
+}
+
+// 代码块组件
+const CodeBlock: React.FC<{ code: string; language?: string }> = ({ code, language = 'bash' }) => {
+    const [copied, setCopied] = React.useState(false);
+
+    const handleCopy = async () => {
+        try {
+            await navigator.clipboard.writeText(code);
+            setCopied(true);
+            message.success('已复制到剪贴板');
+            setTimeout(() => setCopied(false), 2000);
+        } catch (err) {
+            message.error('复制失败');
+        }
+    };
+
+    return (
+        <div className='code-block'>
+            <div className='code-header'>
+                <span className='code-language'>{language}</span>
+                <Button
+                    type='text'
+                    size='small'
+                    icon={copied ? <CheckOutlined /> : <CopyOutlined />}
+                    onClick={handleCopy}
+                >
+                    {copied ? '已复制' : '复制'}
+                </Button>
+            </div>
+            <pre className='code-content'>
+                <code>{code}</code>
+            </pre>
+        </div>
+    );
+};
+
+// 参数表格组件
+const ParamsTable: React.FC<{ params: { name: string; type: string; required: boolean; description: string }[] }> = ({ params }) => (
+    <div className='params-table'>
+        <table>
+            <thead>
+                <tr>
+                    <th>参数</th>
+                    <th>类型</th>
+                    <th>必填</th>
+                    <th>说明</th>
+                </tr>
+            </thead>
+            <tbody>
+                {params.map((param, index) => (
+                    <tr key={index}>
+                        <td><code>{param.name}</code></td>
+                        <td><span className='param-type'>{param.type}</span></td>
+                        <td>
+                            {param.required ? (
+                                <Tag color='red' style={{ fontSize: 12 }}>必填</Tag>
+                            ) : (
+                                <Tag color='default' style={{ fontSize: 12 }}>可选</Tag>
+                            )}
+                        </td>
+                        <td>{param.description}</td>
+                    </tr>
+                ))}
+            </tbody>
+        </table>
+    </div>
+);
+
+// 响应示例组件
+const ResponseExample: React.FC<{ example: string }> = ({ example }) => (
+    <div className='response-example'>
+        <pre className='example-content'>
+            <code>{example}</code>
+        </pre>
+    </div>
+);
+
+const AppCardApiDoc: React.FC<Props> = ({ open, appId, onClose }) => {
+    const baseUrl = window.location.origin;
+    const apiKey = localStorage.getItem('api_key_demo') || 'your_api_key_here';
+
+    // 通用问答接口 - 使用 appId
+    const chatCompletionCode = `curl -X POST ${baseUrl}/api/v1/chat/completions \\
+  -H "Content-Type: application/json" \\
+  -H "Authorization: Bearer ${apiKey}" \\
+  -d '{
+    "app_id": "${appId}",
+    "messages": [
+      {
+        "role": "user",
+        "content": "你好"
+      }
+    ],
+    "stream": false
+  }'`;
+
+    const chatCompletionPython = `import requests
+
+url = "${baseUrl}/api/v1/chat/completions"
+headers = {
+    "Content-Type": "application/json",
+    "Authorization": "Bearer ${apiKey}"
+}
+
+data = {
+    "app_id": "${appId}",
+    "messages": [
+        {
+            "role": "user",
+            "content": "你好"
+        }
+    ],
+    "stream": False
+}
+
+response = requests.post(url, headers=headers, json=data)
+print(response.json())`;
+
+    // RAG 问答接口 - 使用 appId
+    const ragChatCode = `curl -X POST ${baseUrl}/api/v1/rag/chat \\
+  -H "Content-Type: application/json" \\
+  -H "Authorization: Bearer ${apiKey}" \\
+  -d '{
+    "app_id": "${appId}",
+    "query": "请问...",
+    "top_k": 3,
+    "score_threshold": 0.7
+  }'`;
+
+    const ragChatPython = `import requests
+
+url = "${baseUrl}/api/v1/rag/chat"
+headers = {
+    "Content-Type": "application/json",
+    "Authorization": "Bearer ${apiKey}"
+}
+
+data = {
+    "app_id": "${appId}",
+    "query": "请问...",
+    "top_k": 3,
+    "score_threshold": 0.7
+}
+
+response = requests.post(url, headers=headers, json=data)
+print(response.json())`;
+
+    return (
+        <Drawer
+            title="API 文档"
+            placement="right"
+            width={700}
+            open={open}
+            onClose={onClose}
+            className='api-doc-drawer'
+        >
+            <div className='api-doc-content'>
+                {/* 接口说明 */}
+                <div className='api-section'>
+                    <h3 className='section-title'>接口说明</h3>
+                    <div className='section-content'>
+                        <p>当前应用 ID:<code className='app-id-badge'>{appId}</code></p>
+                        <p>以下接口均需传入此 <code>app_id</code> 参数以调用当前应用。</p>
+                        <div className='info-cards'>
+                            <div className='info-card'>
+                                <div className='card-label'>基础 URL</div>
+                                <div className='card-value'><code>{baseUrl}/api/v1</code></div>
+                            </div>
+                            <div className='info-card'>
+                                <div className='card-label'>认证方式</div>
+                                <div className='card-value'><code>Bearer Token</code></div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+                <Tabs defaultActiveKey="1" className='api-tabs'>
+                    {/* 通用问答接口 */}
+                    <TabPane tab="通用问答" key="1">
+                        <div className='api-item'>
+                            <div className='api-header'>
+                                <span className='api-method method-post'>POST</span>
+                                <span className='api-path'>/api/v1/chat/completions</span>
+                            </div>
+                            <p className='api-description'>
+                                兼容 OpenAI 格式的通用对话接口,支持多轮对话和流式输出。
+                            </p>
+
+                            <h4>请求参数</h4>
+                            <ParamsTable params={[
+                                { name: 'app_id', type: 'string', required: true, description: `当前应用 ID:${appId}` },
+                                { name: 'messages', type: 'array', required: true, description: '对话消息列表,包含 role 和 content' },
+                                { name: 'stream', type: 'boolean', required: false, description: '是否使用流式输出,默认 false' },
+                            ]} />
+
+                            <h4>代码示例</h4>
+                            <div style={{ marginTop: 8 }}>
+                                <CodeBlock code={chatCompletionCode} language='bash' />
+                            </div>
+                            <div style={{ marginTop: 8 }}>
+                                <CodeBlock code={chatCompletionPython} language='python' />
+                            </div>
+
+                            <ResponseExample example={`{
+  "id": "chatcmpl-xxxxxxxx",
+  "choices": [{
+    "message": {
+      "role": "assistant",
+      "content": "你好!有什么可以帮助你的?"
+    }
+  }]
+}`} />
+                        </div>
+                    </TabPane>
+
+                    {/* RAG 问答接口 */}
+                    <TabPane tab="RAG 问答" key="2">
+                        <div className='api-item'>
+                            <div className='api-header'>
+                                <span className='api-method method-post'>POST</span>
+                                <span className='api-path'>/api/v1/rag/chat</span>
+                            </div>
+                            <p className='api-description'>
+                                基于知识库的 RAG 问答接口,结合检索结果生成准确回答。
+                            </p>
+
+                            <h4>请求参数</h4>
+                            <ParamsTable params={[
+                                { name: 'app_id', type: 'string', required: true, description: `当前应用 ID:${appId}` },
+                                { name: 'query', type: 'string', required: true, description: '用户问题' },
+                                { name: 'top_k', type: 'integer', required: false, description: '返回最相关的 K 条结果,默认 3' },
+                                { name: 'score_threshold', type: 'number', required: false, description: '相似度阈值,默认 0.5' },
+                            ]} />
+
+                            <h4>代码示例</h4>
+                            <div style={{ marginTop: 8 }}>
+                                <CodeBlock code={ragChatCode} language='bash' />
+                            </div>
+                            <div style={{ marginTop: 8 }}>
+                                <CodeBlock code={ragChatPython} language='python' />
+                            </div>
+
+                            <ResponseExample example={`{
+  "id": "rag-chat-xxxxxxxx",
+  "choices": [{
+    "message": {
+      "role": "assistant",
+      "content": "根据检索结果..."
+    }
+  }],
+  "retrieved_chunks": [...]
+}`} />
+                        </div>
+                    </TabPane>
+                </Tabs>
+
+                {/* 错误码说明 */}
+                <div className='api-section'>
+                    <h3 className='section-title'>错误码</h3>
+                    <div className='section-content'>
+                        <ParamsTable params={[
+                            { name: '400', type: '', required: false, description: '请求参数错误' },
+                            { name: '401', type: '', required: false, description: '未授权,请检查 API Key' },
+                            { name: '404', type: '', required: false, description: '应用不存在' },
+                            { name: '500', type: '', required: false, description: '服务器内部错误' },
+                        ]} />
+                    </div>
+                </div>
+            </div>
+        </Drawer>
+    );
+};
+
+export default AppCardApiDoc;

+ 28 - 22
jk-rag-platform/src/components/common/AppCard/index.scss

@@ -1,5 +1,6 @@
+@use 'sass:color';
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // ===== AppCard 应用卡片样式 =====
 // 使用全局变量,符合设计规范 v3.0
@@ -44,7 +45,7 @@
     top: $spacing-3;
     right: $spacing-3;
     padding: $spacing-1 $spacing-2;
-    background: linear-gradient(135deg, $warning-color 0%, darken($warning-color, 10%) 100%);
+    background: linear-gradient(135deg, $warning-color 0%, color.adjust($warning-color, $lightness: -10%) 100%);
     color: $bg-secondary;
     border-radius: $radius-full;
     font-size: $font-xs;
@@ -146,14 +147,17 @@
     &.bg-green { background: #F0FDF4; }
     &.bg-orange { background: #FFF7ED; }
 
-    .card-icon {
+    .card-icon,
+    svg {
         width: 100%;
         height: 100%;
         object-fit: contain;
-    }
 
-    .iconify {
-        font-size: $icon-3xl;
+        // fill 风格图标 - 移除描边
+        &[fill="none"] {
+            fill: currentColor;
+            stroke: none;
+        }
     }
 }
 
@@ -188,8 +192,9 @@
             transform: scale(1.05);
         }
 
-        .iconify {
-            font-size: $icon-lg;
+        svg {
+            width: 16px;
+            height: 16px;
         }
     }
 }
@@ -273,8 +278,9 @@
         font-size: $font-sm;
         color: $text-hint;
 
-        .iconify {
-            font-size: $icon-md;
+        svg {
+            width: 14px;
+            height: 14px;
         }
     }
 }
@@ -296,8 +302,9 @@
     font-size: $font-xs;
     color: $text-hint;
 
-    .iconify {
-        font-size: $icon-md;
+    svg {
+        width: 14px;
+        height: 14px;
         color: $success-color;
     }
 }
@@ -313,8 +320,9 @@
     text-overflow: ellipsis;
     max-width: 200px;
 
-    .iconify {
-        font-size: $icon-md;
+    svg {
+        width: 14px;
+        height: 14px;
     }
 }
 
@@ -372,10 +380,9 @@
             color: $text-primary;
         }
 
-        .iconify {
-            font-size: $icon-lg;
-            display: inline-flex;
-            align-items: center;
+        svg {
+            width: 18px;
+            height: 18px;
         }
     }
 
@@ -407,10 +414,9 @@
             box-shadow: 0 2px 8px rgba(0, 93, 128, 0.2);
         }
 
-        .iconify {
-            font-size: $icon-lg;
-            display: inline-flex;
-            align-items: center;
+        svg {
+            width: 18px;
+            height: 18px;
         }
     }
 }

+ 70 - 49
jk-rag-platform/src/components/common/AppCard/index.tsx

@@ -1,5 +1,7 @@
 import * as React from 'react';
 import { Dropdown, MenuProps, Button } from 'antd';
+import { Code, Pen, Trash2, Share2, Star, Eye, Heart, Calendar, BadgeCheck, Building, Menu, ArrowRight } from 'lucide-react';
+import AppCardApiDoc from './AppCardApiDoc';
 import './index.scss';
 
 export interface AppCardProps {
@@ -67,35 +69,37 @@ export interface AppCardProps {
 const AppCard: React.FC<AppCardProps> = (props) => {
     const {
         // 基本信息
+        id,
         name,
         description,
         icon,
         iconImage,
         iconBgColor = 'blue',
-        
+
         // 创建者信息
         creator,
         proName,
-        
+
         // 标签和认证
         tags = [],
         certification,
-        
+
         // 状态标识
         isHot,
         status,
-        
+
         // 统计数据
         viewCount,
         favoriteCount,
         createTime,
-        
+
         // 其他信息
         department,
         visible,
+        appId,
         isCollect = false,
         isCreator = false,
-        
+
         // 显示控制
         showCreator = true,
         showActions = true,
@@ -109,7 +113,7 @@ const AppCard: React.FC<AppCardProps> = (props) => {
         showDepartment = false,
         showVisible = false,
         showOperations = false,
-        
+
         // 回调函数
         onShare,
         onFavorite,
@@ -120,6 +124,12 @@ const AppCard: React.FC<AppCardProps> = (props) => {
         onApiDirect,
     } = props;
 
+    // API 文档弹窗状态
+    const [apiDocOpen, setApiDocOpen] = React.useState(false);
+
+    // 使用 appId 或 id 作为应用标识
+    const applicationId = appId || id;
+
     // 配置对象
     const statusConfig = {
         draft: { label: '草稿', color: '#9CA3AF' },
@@ -142,25 +152,25 @@ const AppCard: React.FC<AppCardProps> = (props) => {
             items.push({
                 key: 'api',
                 label: 'API 调用',
-                icon: <span className="iconify" data-icon="solar:code-square-linear"></span>,
+                icon: <Code size={16} />,
                 onClick: () => onApi(),
             });
         }
-        
+
         if (isCreator && onEdit) {
             items.push({
                 key: 'edit',
                 label: '编辑',
-                icon: <span className="iconify" data-icon="solar:pen-linear"></span>,
+                icon: <Pen size={16} />,
                 onClick: () => onEdit(),
             });
         }
-        
+
         if (isCreator && onDelete) {
             items.push({
                 key: 'delete',
                 label: '删除',
-                icon: <span className="iconify" data-icon="solar:trash-bin-linear"></span>,
+                icon: <Trash2 size={16} />,
                 danger: true,
                 onClick: () => onDelete(),
             });
@@ -210,7 +220,7 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                         }}
                         title='分享'
                     >
-                        <span className='iconify' data-icon='solar:share-linear'></span>
+                        <Share2 size={18} />
                     </button>
                     <button
                         className='card-action-btn'
@@ -221,9 +231,9 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                         title={isCollect ? '取消收藏' : '收藏'}
                     >
                         {isCollect ? (
-                            <span className='iconify' data-icon='solar:star-bold' style={{ color: '#F5E663' }}></span>
+                            <Star size={18} className="fill-yellow" style={{ color: '#F5E663' }} />
                         ) : (
-                            <span className='iconify' data-icon='solar:star-linear'></span>
+                            <Star size={18} />
                         )}
                     </button>
                 </div>
@@ -235,7 +245,10 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                     {iconImage ? (
                         <img alt={name} className='card-icon' src={iconImage} />
                     ) : icon ? (
-                        <span className='iconify' data-icon={icon}></span>
+                        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: 24, height: 24 }}>
+                            {/* 动态 icon 支持 - 如果传入的是 iconoir 组件名称则渲染,否则显示占位 */}
+                            <Star size={24} />
+                        </div>
                     ) : null}
                 </div>
 
@@ -275,13 +288,13 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                     <div className='card-meta-left'>
                         {showViewCount && viewCount !== undefined && (
                             <span className='card-meta-item'>
-                                <span className='iconify' data-icon='solar:eye-linear'></span>
+                                <Eye size={14} />
                                 <span>{viewCount}</span>
                             </span>
                         )}
                         {showFavoriteCount && favoriteCount !== undefined && (
                             <span className='card-meta-item'>
-                                <span className='iconify' data-icon='solar:heart-linear'></span>
+                                <Heart size={14} />
                                 <span>{favoriteCount}</span>
                             </span>
                         )}
@@ -289,7 +302,7 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                     {showCreateTime && createTime && (
                         <div className='card-meta-right'>
                             <span className='card-meta-item'>
-                                <span className='iconify' data-icon='solar:calendar-linear'></span>
+                                <Calendar size={14} />
                                 <span>{createTime}</span>
                             </span>
                         </div>
@@ -302,13 +315,13 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                 <div className='card-footer-info'>
                     {certification && (
                         <div className='card-certification'>
-                            <span className='iconify' data-icon='solar:verified-check-bold'></span>
+                            <BadgeCheck size={14} />
                             <span>{certification}</span>
                         </div>
                     )}
                     {showDepartment && department && (
                         <div className='card-department'>
-                            <span className='iconify' data-icon='solar:buildings-bold'></span>
+                            <Building size={14} />
                             <span>{department}</span>
                         </div>
                     )}
@@ -326,49 +339,57 @@ const AppCard: React.FC<AppCardProps> = (props) => {
             {/* 悬停操作按钮层 */}
             {showOperations && (
                 <div className='card-hover-actions'>
-                    {/* 创建者显示【更多操作】,非创建者显示【API 用】 */}
+                    {/* 创建者显示【更多操作】,非创建者显示【API 文档】和【立即使用】 */}
                     {isCreator ? (
-                        <Dropdown 
-                            menu={{ items: operationItems }} 
+                        <Dropdown
+                            menu={{ items: operationItems }}
                             trigger={['click']}
                             placement='topLeft'
                             className='card-operation-dropdown'
                         >
-                            <Button 
+                            <Button
                                 className='card-operation-btn'
-                                icon={<span className='iconify' data-icon='solar:menu-dots-linear'></span>}
+                                icon={<Menu size={18} />}
                                 size='large'
                             >
                                 更多操作
                             </Button>
                         </Dropdown>
                     ) : (
-                        <Button 
-                            className='card-operation-btn'
-                            icon={<span className='iconify' data-icon='solar:code-square-linear'></span>}
-                            size='large'
-                            onClick={(e) => {
-                                e.stopPropagation();
-                                onApiDirect?.();
-                            }}
-                        >
-                            API 调用
-                        </Button>
+                        <>
+                            <Button
+                                className='card-operation-btn'
+                                icon={<Code size={18} />}
+                                size='large'
+                                onClick={(e) => {
+                                    e.stopPropagation();
+                                    setApiDocOpen(true);
+                                }}
+                            >
+                                API 接入
+                            </Button>
+                            <Button
+                                className='card-use-btn'
+                                icon={<ArrowRight size={18} />}
+                                size='large'
+                                onClick={(e) => {
+                                    e.stopPropagation();
+                                    handleViewClick();
+                                }}
+                            >
+                                立即使用
+                            </Button>
+                        </>
                     )}
-                    
-                    <Button 
-                        className='card-use-btn'
-                        icon={<span className='iconify' data-icon='solar:arrow-right-linear'></span>}
-                        size='large'
-                        onClick={(e) => {
-                            e.stopPropagation();
-                            handleViewClick();
-                        }}
-                    >
-                        立即使用
-                    </Button>
                 </div>
             )}
+
+            {/* API 文档抽屉 */}
+            <AppCardApiDoc
+                open={apiDocOpen}
+                appId={applicationId || ''}
+                onClose={() => setApiDocOpen(false)}
+            />
         </div>
     );
 };

+ 1 - 2
jk-rag-platform/src/components/common/FilterBar/index.scss

@@ -1,9 +1,8 @@
+@use '@/styles/variables.scss' as *;
 // FilterBar 筛选工具栏样式
 // 使用全局变量,符合设计规范 v3.6
 // 注意:全局 .filter-bar 已移除 border-bottom,此处定义组件特定样式
 
-@import '@/styles/variables.scss';
-
 .filter-bar {
     display: flex;
     justify-content: space-between;

+ 20 - 3
jk-rag-platform/src/components/common/FilterDrawer/index.scss

@@ -1,10 +1,12 @@
+@use '@/styles/variables.scss' as *;
+
 .filter-drawer {
     .filter-content {
         padding: $spacing-4 0;
     }
 
     .filter-section {
-        margin-bottom: $spacing-4;  // 16px - 紧凑间距
+        margin-bottom: $spacing-md;  // 紧凑间距
 
         &:last-child {
             margin-bottom: 0;
@@ -15,12 +17,27 @@
         font-size: $font-lg;
         font-weight: $font-weight-semibold;
         color: $text-primary;
-        margin-bottom: $spacing-3;
+        margin-bottom: $spacing-md;
     }
 
     .filter-tags {
         display: flex;
         flex-wrap: wrap;
-        gap: 8px;
+        gap: $spacing-sm;  // 8px
+    }
+
+    // Drawer footer buttons - follow global border radius specs
+    .ant-drawer-footer {
+        padding-top: $spacing-4;
+        padding-bottom: $spacing-4;
+
+        .ant-btn {
+            border-radius: $radius-lg;  // 8px - follow global specs
+            min-width: 64px;
+
+            &:first-child {
+                margin-right: $spacing-sm;
+            }
+        }
     }
 }

+ 1 - 1
jk-rag-platform/src/components/common/GuideTips/index.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // GuideTips 引导提示组件 - 遵循全局样式规则
 .guide-tips-wrapper {

+ 2 - 4
jk-rag-platform/src/components/common/GuideTips/index.tsx

@@ -1,6 +1,7 @@
 import * as React from 'react';
 import { Card, Row, Col } from 'antd';
 import { BulbOutlined } from '@ant-design/icons';
+import { ChevronDown } from 'lucide-react';
 import './index.scss';
 
 interface TipsStep {
@@ -77,10 +78,7 @@ const GuideTips: React.FC<GuideTipsProps> = (props) => {
                     <span>提示:{title}</span>
                 </div>
                 <div className='guide-tips-close'>
-                    <span
-                        className='iconify guide-tips-arrow'
-                        data-icon='solar:alt-arrow-down-linear'
-                    />
+                    <ChevronDown size={16} className='guide-tips-arrow' />
                 </div>
             </div>
             

+ 32 - 37
jk-rag-platform/src/components/common/HeroBanner/index.scss

@@ -1,9 +1,9 @@
-@import '@/styles/variables.scss';
+@use '@/styles/variables.scss' as *;
 
 .hero-banner {
     position: relative;
     width: 100%;
-    height: 150px;
+    height: $font-3xl * 9;  // 150px
     border-radius: $radius-2xl;
     overflow: hidden;
     margin-bottom: $spacing-10;
@@ -26,17 +26,12 @@
 }
 
 .hero-banner-content {
-    max-width: 800px;
+    max-width: $spacing-10 * 7.5;  // 800px
     display: flex;
     align-items: center;
     gap: $spacing-5;
 }
 
-.hero-banner-text {
-    flex: 1;
-    min-width: 0;
-}
-
 .hero-banner-badge {
     display: inline-flex;
     align-items: center;
@@ -56,7 +51,7 @@
     span:last-child {
         font-size: 10px;
         color: #DBEAFE;
-        font-weight: 600;
+        font-weight: $font-weight-semibold;
         font-style: italic;
     }
 }
@@ -75,26 +70,26 @@
     line-height: 1.4;
     display: flex;
     flex-direction: column;
-    gap: 2px;
+    gap: $spacing-1;
 }
 
 .hero-banner-actions {
     flex-shrink: 0;
     display: flex;
-    gap: 8px;
+    gap: $spacing-2;
 }
 
 .hero-banner-btn {
-    padding: 6px 16px;
-    border-radius: 8px;
-    font-size: 12px;
-    font-weight: 700;
+    padding: $spacing-1 $spacing-md;
+    border-radius: $radius-lg;
+    font-size: $font-xs;
+    font-weight: $font-weight-bold;
     border: none;
     cursor: pointer;
     transition: all 0.2s ease;
     display: inline-flex;
     align-items: center;
-    gap: 4px;
+    gap: $spacing-1;
     white-space: nowrap;
     box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
 
@@ -116,7 +111,7 @@
         border: 1px solid $border-base;
         color: $text-primary;
         backdrop-filter: blur(4px);
-        font-weight: 600;
+        font-weight: $font-weight-semibold;
 
         &:hover {
             background: $bg-primary;
@@ -125,46 +120,46 @@
     }
 }
 
-@media (max-width: 1024px) {
+@media (max-width: $screen-lg) {
     .hero-banner {
-        height: 150px;
+        height: $font-3xl * 9;  // 150px
     }
 
     .hero-banner-overlay {
-        padding: 0 20px;
+        padding: 0 $spacing-lg;
     }
 
     .hero-banner-content {
-        gap: 16px;
+        gap: $spacing-md;
     }
 
     .hero-banner-title {
-        font-size: 16px;
+        font-size: $font-2xl;  // 16px
     }
 
     .hero-banner-description {
-        font-size: 11px;
+        font-size: $font-xs;  // 11px
     }
 
     .hero-banner-btn {
-        padding: 5px 14px;
-        font-size: 11px;
+        padding: $spacing-1 $spacing-sm;
+        font-size: $font-xs;  // 11px
     }
 }
 
-@media (max-width: 768px) {
+@media (max-width: $screen-md) {
     .hero-banner {
-        height: 180px;
+        height: $font-3xl * 9.6;  // 180px
     }
 
     .hero-banner-overlay {
-        padding: 0 16px;
+        padding: 0 $spacing-md;
     }
 
     .hero-banner-content {
         flex-direction: column;
         align-items: flex-start;
-        gap: 12px;
+        gap: $spacing-sm;
     }
 
     .hero-banner-actions {
@@ -177,10 +172,10 @@
     }
 
     .hero-banner-badge {
-        padding: 2px 8px;
+        padding: $spacing-1 $spacing-sm;
 
         .iconify {
-            font-size: 11px;
+            font-size: $font-xs;  // 11px
         }
 
         span:last-child {
@@ -189,17 +184,17 @@
     }
 
     .hero-banner-title {
-        font-size: 16px;
-        margin-bottom: 4px;
+        font-size: $font-2xl;  // 16px
+        margin-bottom: $spacing-1;  // 4px
     }
 
     .hero-banner-description {
-        font-size: 11px;
-        gap: 2px;
+        font-size: $font-xs;  // 11px
+        gap: $spacing-1;  // 2px
     }
 
     .hero-banner-btn {
-        padding: 6px 16px;
-        font-size: 12px;
+        padding: $spacing-1 $spacing-md;
+        font-size: $font-sm;  // 12px
     }
 }

+ 2 - 1
jk-rag-platform/src/components/common/HeroBanner/index.tsx

@@ -1,4 +1,5 @@
 import * as React from 'react';
+import { Star } from 'lucide-react';
 import './index.scss';
 
 const HeroBanner: React.FC = () => {
@@ -13,7 +14,7 @@ const HeroBanner: React.FC = () => {
                 <div className='hero-banner-content'>
                     <div className='hero-banner-text'>
                         <div className='hero-banner-badge'>
-                            <span className='iconify' data-icon='solar:star-bold'></span>
+                            <Star size={16} />
                             <span>Featured Application</span>
                         </div>
                         <h2 className='hero-banner-title'>广告占位</h2>

+ 25 - 18
jk-rag-platform/src/components/common/StatsGrid/index.scss

@@ -1,8 +1,7 @@
+@use '@/styles/variables.scss' as *;
 // StatsGrid 统计卡片网格 - 紧凑布局 v3.9
 // 遵循全局样式规范,使用全局变量
 
-@import '@/styles/variables.scss';
-
 .stats-grid {
     display: grid;
     grid-template-columns: repeat(4, 1fr);
@@ -49,27 +48,34 @@
     align-items: center;
     justify-content: center;
 
-    &.bg-blue { 
-        background: $icon-bg-blue; 
+    &.bg-blue {
+        background: $icon-bg-blue;
     }
-    &.bg-indigo { 
-        background: $icon-bg-indigo; 
+    &.bg-indigo {
+        background: $icon-bg-indigo;
     }
-    &.bg-orange { 
-        background: $icon-bg-amber; 
+    &.bg-orange {
+        background: $icon-bg-amber;
     }
-    &.bg-green { 
-        background: $success-light; 
+    &.bg-green {
+        background: $success-light;
     }
 
-    .iconify {
-        font-size: $icon-lg;  // 18px - 紧凑图标
+    svg {
+        width: 20px;
+        height: 20px;
 
-        &.icon-blue { color: $primary-color; }
-        &.icon-indigo { color: $info-dark; }
-        &.icon-orange { color: $warning-color; }
-        &.icon-green { color: $success-color; }
+        // 使用 fill 风格 - 移除描边,使用实心填充
+        &[fill="none"] {
+            fill: currentColor;
+            stroke: none;
+        }
     }
+
+    .icon-blue { color: $primary-color; }
+    .icon-indigo { color: $info-dark; }
+    .icon-orange { color: $warning-color; }
+    .icon-green { color: $success-color; }
 }
 
 .stat-card-trend {
@@ -115,8 +121,9 @@
             height: $icon-xl;
             border-radius: $radius-md;  // 6px
 
-            .iconify {
-                font-size: $icon-md;  // 16px
+            svg {
+                width: 18px;
+                height: 18px;
             }
         }
 

+ 11 - 1
jk-rag-platform/src/components/common/StatsGrid/index.tsx

@@ -1,4 +1,5 @@
 import * as React from 'react';
+import { TrendingUp, Cpu, ShieldCheck, Database } from 'lucide-react';
 import './index.scss';
 
 interface StatCardProps {
@@ -10,14 +11,23 @@ interface StatCardProps {
     trendColor?: string;
 }
 
+// icon 名称到 lucide 组件的映射
+const iconMap: Record<string, React.ComponentType<any>> = {
+    'solar:chart-bold-duotone': TrendingUp,
+    'solar:cpu-bold-duotone': Cpu,
+    'solar:shield-check-bold-duotone': ShieldCheck,
+    'solar:database-bold-duotone': Database,
+};
+
 const StatCard: React.FC<StatCardProps> = (props) => {
     const { icon, iconBgColor, title, value, trend, trendColor = 'gray' } = props;
+    const IconComponent = iconMap[icon] || TrendingUp;
 
     return (
         <div className='stat-card'>
             <div className='stat-card-header'>
                 <div className={`stat-card-icon bg-${iconBgColor}`}>
-                    <span className={`iconify icon-${iconBgColor}`} data-icon={icon}></span>
+                    <IconComponent size={20} className={`icon-${iconBgColor}`} />
                 </div>
                 {trend && (
                     <span className={`stat-card-trend text-${trendColor}`}>{trend}</span>

+ 416 - 0
jk-rag-platform/src/mock/applicationApi.ts

@@ -0,0 +1,416 @@
+import { MockRequest } from './index';
+
+// ==================== 应用管理 Mock 数据 ====================
+
+// 应用分类
+const appCategories = [
+    { value: 'professional', label: '专业知识' },
+    { value: 'functional', label: '职能管理' },
+    { value: 'project', label: '项目级应用' },
+];
+
+// 应用状态
+const appStatuses = [
+    { value: 'online', label: '已上线' },
+    { value: 'offline', label: '已下线' },
+    { value: 'auditing', label: '审核中' },
+    { value: 'rejected', label: '已拒绝' },
+];
+
+// 模拟应用数据
+const mockApplicationsData = [
+    {
+        id: 'app_001',
+        name: '合同审查助手',
+        description: '基于 RAG 技术的智能合同审查与风险提示工具',
+        category: 'professional',
+        status: 'online',
+        creatorId: 'user_001',
+        creator: '张三',
+        maintainers: ['张三', '李四'],
+        createdAt: '2025-12-15 10:30:00',
+        updatedAt: '2026-01-05 14:20:00',
+        icon: 'contract',
+        tags: ['合同管理', '风险提示', '法律'],
+        knowledgeBaseCount: 3,
+        conversationCount: 1250,
+        avatar: '',
+    },
+    {
+        id: 'app_002',
+        name: '人力资源问答机器人',
+        description: '员工自助服务平台,解答人事、考勤、福利等问题',
+        category: 'functional',
+        status: 'online',
+        creatorId: 'user_002',
+        creator: '李四',
+        maintainers: ['李四'],
+        createdAt: '2025-12-20 09:15:00',
+        updatedAt: '2026-01-08 11:45:00',
+        icon: 'hr',
+        tags: ['人力资源', '员工服务'],
+        knowledgeBaseCount: 2,
+        conversationCount: 890,
+        avatar: '',
+    },
+    {
+        id: 'app_003',
+        name: '项目管理智能助手',
+        description: '项目进度跟踪、风险预警、资源调配建议',
+        category: 'project',
+        status: 'online',
+        creatorId: 'user_003',
+        creator: '王五',
+        maintainers: ['王五', '赵六'],
+        createdAt: '2026-01-02 13:20:00',
+        updatedAt: '2026-01-10 16:30:00',
+        icon: 'project',
+        tags: ['项目管理', '进度跟踪'],
+        knowledgeBaseCount: 5,
+        conversationCount: 567,
+        avatar: '',
+    },
+    {
+        id: 'app_004',
+        name: '财务报销助手',
+        description: '智能解答财务报销流程、发票规范、费用标准等问题',
+        category: 'functional',
+        status: 'online',
+        creatorId: 'user_004',
+        creator: '赵六',
+        maintainers: ['赵六'],
+        createdAt: '2026-01-05 10:00:00',
+        updatedAt: '2026-01-12 09:15:00',
+        icon: 'finance',
+        tags: ['财务管理', '报销'],
+        knowledgeBaseCount: 2,
+        conversationCount: 432,
+        avatar: '',
+    },
+    {
+        id: 'app_005',
+        name: '技术培训知识库',
+        description: '技术人员在线学习平台,提供技术文档、培训资料查询',
+        category: 'professional',
+        status: 'online',
+        creatorId: 'user_005',
+        creator: '钱七',
+        maintainers: ['钱七', '孙八'],
+        createdAt: '2026-01-08 14:30:00',
+        updatedAt: '2026-01-15 10:20:00',
+        icon: 'tech',
+        tags: ['技术培训', '知识管理'],
+        knowledgeBaseCount: 8,
+        conversationCount: 1580,
+        avatar: '',
+    },
+    {
+        id: 'app_006',
+        name: '安全生产管理系统',
+        description: '安全生产规范、应急预案、事故案例分析',
+        category: 'project',
+        status: 'auditing',
+        creatorId: 'user_006',
+        creator: '孙八',
+        maintainers: ['孙八'],
+        createdAt: '2026-01-10 11:00:00',
+        updatedAt: '2026-01-16 15:45:00',
+        icon: 'safety',
+        tags: ['安全生产', '应急管理'],
+        knowledgeBaseCount: 4,
+        conversationCount: 0,
+        avatar: '',
+    },
+    {
+        id: 'app_007',
+        name: '市场营销支持平台',
+        description: '市场数据分析、竞品调研、营销策略建议',
+        category: 'functional',
+        status: 'offline',
+        creatorId: 'user_007',
+        creator: '周九',
+        maintainers: ['周九', '吴十'],
+        createdAt: '2025-11-20 09:30:00',
+        updatedAt: '2025-12-25 16:00:00',
+        icon: 'marketing',
+        tags: ['市场营销', '数据分析'],
+        knowledgeBaseCount: 3,
+        conversationCount: 2100,
+        avatar: '',
+    },
+    {
+        id: 'app_008',
+        name: 'IT 运维智能助手',
+        description: 'IT 故障排查、系统维护、常见问题解答',
+        category: 'professional',
+        status: 'online',
+        creatorId: 'user_008',
+        creator: '吴十',
+        maintainers: ['吴十'],
+        createdAt: '2026-01-12 10:15:00',
+        updatedAt: '2026-01-18 14:30:00',
+        icon: 'it',
+        tags: ['IT 运维', '故障排查'],
+        knowledgeBaseCount: 6,
+        conversationCount: 789,
+        avatar: '',
+    },
+    {
+        id: 'app_009',
+        name: '合规管理助手',
+        description: '企业合规政策、流程指引、风险预警',
+        category: 'functional',
+        status: 'rejected',
+        creatorId: 'user_009',
+        creator: '郑十一',
+        maintainers: ['郑十一'],
+        createdAt: '2026-01-14 13:45:00',
+        updatedAt: '2026-01-19 11:20:00',
+        icon: 'compliance',
+        tags: ['合规管理', '风险控制'],
+        knowledgeBaseCount: 2,
+        conversationCount: 0,
+        avatar: '',
+    },
+    {
+        id: 'app_010',
+        name: '客户服务知识库',
+        description: '客服常见问题解答、产品使用说明、售后服务流程',
+        category: 'professional',
+        status: 'online',
+        creatorId: 'user_010',
+        creator: '刘十二',
+        maintainers: ['刘十二', '陈十三'],
+        createdAt: '2026-01-15 08:30:00',
+        updatedAt: '2026-01-20 17:00:00',
+        icon: 'service',
+        tags: ['客户服务', '售后支持'],
+        knowledgeBaseCount: 4,
+        conversationCount: 3200,
+        avatar: '',
+    },
+];
+
+// ==================== Mock API 处理函数 ====================
+
+/**
+ * 获取应用列表
+ * POST /bigmodel/api/getApplicationList
+ */
+export const mockFetchApplicationList = async (request: MockRequest) => {
+    const { pageNum = 1, pageSize = 10, category, status, keyword } = request.data || {};
+
+    console.log('[Mock] 获取应用列表', { pageNum, pageSize, category, status, keyword });
+
+    // 筛选数据
+    let filteredData = [...mockApplicationsData];
+
+    if (category && category !== 'all') {
+        filteredData = filteredData.filter(app => app.category === category);
+    }
+
+    if (status && status !== 'all') {
+        filteredData = filteredData.filter(app => app.status === status);
+    }
+
+    if (keyword) {
+        filteredData = filteredData.filter(app =>
+            app.name.toLowerCase().includes(keyword.toLowerCase()) ||
+            app.description.toLowerCase().includes(keyword.toLowerCase())
+        );
+    }
+
+    // 分页
+    const total = filteredData.length;
+    const startIndex = (pageNum - 1) * pageSize;
+    const endIndex = startIndex + pageSize;
+    const list = filteredData.slice(startIndex, endIndex);
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            list,
+            total,
+            pageNum,
+            pageSize,
+        },
+    };
+};
+
+/**
+ * 获取应用详情
+ * GET /bigmodel/api/selectApplication/:id
+ */
+export const mockFetchApplicationDetail = async (request: MockRequest) => {
+    const appId = request.params?.id;
+
+    console.log('[Mock] 获取应用详情', { appId });
+
+    const app = mockApplicationsData.find(a => a.id === appId);
+
+    if (!app) {
+        return {
+            code: 404,
+            message: '应用不存在',
+            data: null,
+        };
+    }
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            ...app,
+            // 扩展详情信息
+            knowledgeBases: [
+                { id: `kb_${appId}_1`, name: `${app.name}核心知识库` },
+                { id: `kb_${appId}_2`, name: `${app.name}补充资料` },
+            ],
+            recentConversations: [
+                { id: `conv_001`, user: '用户 A', time: '2026-04-02 10:30:00', question: '如何...' },
+                { id: `conv_002`, user: '用户 B', time: '2026-04-02 09:15:00', question: '请问...' },
+            ],
+        },
+    };
+};
+
+/**
+ * 创建应用
+ * POST /bigmodel/api/createApplication
+ */
+export const mockCreateApplication = async (request: MockRequest) => {
+    const { name, description, category, knowledgeBaseIds } = request.data || {};
+
+    console.log('[Mock] 创建应用', { name, description, category, knowledgeBaseIds });
+
+    // 生成新 ID
+    const newId = `app_${String(mockApplicationsData.length + 1).padStart(3, '0')}`;
+
+    const newApp = {
+        id: newId,
+        name: name || '新应用',
+        description: description || '暂无描述',
+        category: category || 'professional',
+        status: 'auditing', // 新建应用默认进入审核状态
+        creatorId: 'current_user',
+        creator: '当前用户',
+        maintainers: ['当前用户'],
+        createdAt: new Date().toLocaleString('zh-CN'),
+        updatedAt: new Date().toLocaleString('zh-CN'),
+        icon: 'default',
+        tags: [],
+        knowledgeBaseCount: knowledgeBaseIds?.length || 0,
+        conversationCount: 0,
+        avatar: '',
+    };
+
+    mockApplicationsData.unshift(newApp);
+
+    return {
+        code: 200,
+        message: '创建成功',
+        data: {
+            id: newId,
+            ...newApp,
+        },
+    };
+};
+
+/**
+ * 更新应用
+ * PUT /bigmodel/api/updateApplication/:id
+ */
+export const mockUpdateApplication = async (request: MockRequest) => {
+    const appId = request.params?.id;
+    const { name, description, category, status, tags } = request.data || {};
+
+    console.log('[Mock] 更新应用', { appId, name, description, category, status, tags });
+
+    const appIndex = mockApplicationsData.findIndex(a => a.id === appId);
+
+    if (appIndex === -1) {
+        return {
+            code: 404,
+            message: '应用不存在',
+            data: null,
+        };
+    }
+
+    const app = mockApplicationsData[appIndex];
+    mockApplicationsData[appIndex] = {
+        ...app,
+        name: name || app.name,
+        description: description || app.description,
+        category: category || app.category,
+        status: status || app.status,
+        tags: tags !== undefined ? tags : app.tags,
+        updatedAt: new Date().toLocaleString('zh-CN'),
+    };
+
+    return {
+        code: 200,
+        message: '更新成功',
+        data: mockApplicationsData[appIndex],
+    };
+};
+
+/**
+ * 删除应用
+ * DELETE /bigmodel/api/delApplication/:id
+ */
+export const mockDeleteApplication = async (request: MockRequest) => {
+    const appId = request.params?.id;
+
+    console.log('[Mock] 删除应用', { appId });
+
+    const appIndex = mockApplicationsData.findIndex(a => a.id === appId);
+
+    if (appIndex === -1) {
+        return {
+            code: 404,
+            message: '应用不存在',
+            data: null,
+        };
+    }
+
+    mockApplicationsData.splice(appIndex, 1);
+
+    return {
+        code: 200,
+        message: '删除成功',
+        data: { id: appId },
+    };
+};
+
+/**
+ * 获取我的应用列表
+ * GET /bigmodel/api/myApplications
+ */
+export const mockFetchMyApplications = async (request: MockRequest) => {
+    const userId = 'current_user'; // 当前登录用户 ID
+
+    console.log('[Mock] 获取我的应用列表', { userId });
+
+    const myApps = mockApplicationsData.filter(app => app.creatorId === userId);
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            list: myApps,
+            total: myApps.length,
+        },
+    };
+};
+
+// ==================== 导出所有 Mock 处理函数 ====================
+
+export const applicationMockHandlers = {
+    'POST /bigmodel/api/getApplicationList': mockFetchApplicationList,
+    'GET /bigmodel/api/selectApplication/:id': mockFetchApplicationDetail,
+    'POST /bigmodel/api/createApplication': mockCreateApplication,
+    'PUT /bigmodel/api/updateApplication/:id': mockUpdateApplication,
+    'DELETE /bigmodel/api/delApplication/:id': mockDeleteApplication,
+    'GET /bigmodel/api/myApplications': mockFetchMyApplications,
+};

+ 385 - 0
jk-rag-platform/src/mock/auditApi.ts

@@ -0,0 +1,385 @@
+// ==================== 审核管理 Mock 数据 ====================
+
+// 审核状态
+const auditStatuses = [
+    { value: 'pending', label: '待审核' },
+    { value: 'approved', label: '已通过' },
+    { value: 'rejected', label: '已拒绝' },
+];
+
+// 模拟审核数据
+const mockAuditData = [
+    {
+        id: 'audit_001',
+        appId: 'app_006',
+        appName: '安全生产管理系统',
+        appDescription: '安全生产规范、应急预案、事故案例分析',
+        creatorId: 'user_006',
+        creator: '孙八',
+        department: '安全管理部',
+        submitTime: '2026-01-16 15:45:00',
+        auditStatus: 'pending',
+        auditor: null,
+        auditTime: null,
+        auditOpinion: null,
+        knowledgeBaseCount: 4,
+        documentCount: 28,
+        sliceCount: 156,
+    },
+    {
+        id: 'audit_002',
+        appId: 'app_009',
+        appName: '合规管理助手',
+        appDescription: '企业合规政策、流程指引、风险预警',
+        creatorId: 'user_009',
+        creator: '郑十一',
+        department: '法务合规部',
+        submitTime: '2026-01-19 11:20:00',
+        auditStatus: 'rejected',
+        auditor: '管理员',
+        auditTime: '2026-01-20 09:30:00',
+        auditOpinion: '知识库内容不够完善,建议补充相关法规文件',
+        knowledgeBaseCount: 2,
+        documentCount: 8,
+        sliceCount: 42,
+    },
+    {
+        id: 'audit_003',
+        appId: 'app_011',
+        appName: '质量管理助手',
+        appDescription: 'ISO 质量管理体系、质检流程、问题整改跟踪',
+        creatorId: 'user_011',
+        creator: '钱十三',
+        department: '质量管理部',
+        submitTime: '2026-01-18 10:00:00',
+        auditStatus: 'approved',
+        auditor: '管理员',
+        auditTime: '2026-01-19 14:20:00',
+        auditOpinion: '符合上线标准,予以通过',
+        knowledgeBaseCount: 3,
+        documentCount: 15,
+        sliceCount: 89,
+    },
+    {
+        id: 'audit_004',
+        appId: 'app_012',
+        appName: '采购管理助手',
+        appDescription: '供应商管理、采购流程、合同管理',
+        creatorId: 'user_012',
+        creator: '赵十四',
+        department: '采购部',
+        submitTime: '2026-01-20 11:30:00',
+        auditStatus: 'pending',
+        auditor: null,
+        auditTime: null,
+        auditOpinion: null,
+        knowledgeBaseCount: 2,
+        documentCount: 12,
+        sliceCount: 67,
+    },
+    {
+        id: 'audit_005',
+        appId: 'app_013',
+        appName: '档案管理助手',
+        appDescription: '电子档案管理、档案借阅、档案分类',
+        creatorId: 'user_013',
+        creator: '孙十五',
+        department: '综合办公室',
+        submitTime: '2026-01-15 09:00:00',
+        auditStatus: 'approved',
+        auditor: '管理员',
+        auditTime: '2026-01-16 10:15:00',
+        auditOpinion: '符合上线标准',
+        knowledgeBaseCount: 4,
+        documentCount: 32,
+        sliceCount: 198,
+    },
+    {
+        id: 'audit_006',
+        appId: 'app_014',
+        appName: '知识产权助手',
+        appDescription: '专利管理、商标管理、知识产权申请流程',
+        creatorId: 'user_014',
+        creator: '李十六',
+        department: '知识产权部',
+        submitTime: '2026-01-21 14:00:00',
+        auditStatus: 'pending',
+        auditor: null,
+        auditTime: null,
+        auditOpinion: null,
+        knowledgeBaseCount: 3,
+        documentCount: 18,
+        sliceCount: 95,
+    },
+];
+
+// 模拟审核历史记录
+const mockAuditHistoryData = [
+    {
+        id: 'history_001',
+        auditId: 'audit_002',
+        appId: 'app_009',
+        appName: '合规管理助手',
+        action: 'submit',
+        actionName: '提交审核',
+        operator: '郑十一',
+        operatorRole: 'creator',
+        time: '2026-01-19 11:20:00',
+        remark: '提交应用审核',
+    },
+    {
+        id: 'history_002',
+        auditId: 'audit_002',
+        appId: 'app_009',
+        appName: '合规管理助手',
+        action: 'assigned',
+        actionName: '分配审核员',
+        operator: '系统',
+        operatorRole: 'system',
+        time: '2026-01-19 11:25:00',
+        remark: '自动分配给审核员:管理员',
+    },
+    {
+        id: 'history_003',
+        auditId: 'audit_002',
+        appId: 'app_009',
+        appName: '合规管理助手',
+        action: 'reviewing',
+        actionName: '开始审核',
+        operator: '管理员',
+        operatorRole: 'auditor',
+        time: '2026-01-20 09:00:00',
+        remark: '审核员开始审核',
+    },
+    {
+        id: 'history_004',
+        auditId: 'audit_002',
+        appId: 'app_009',
+        appName: '合规管理助手',
+        action: 'rejected',
+        actionName: '拒绝',
+        operator: '管理员',
+        operatorRole: 'auditor',
+        time: '2026-01-20 09:30:00',
+        remark: '知识库内容不够完善,建议补充相关法规文件',
+    },
+    {
+        id: 'history_005',
+        auditId: 'audit_003',
+        appId: 'app_011',
+        appName: '质量管理助手',
+        action: 'submit',
+        actionName: '提交审核',
+        operator: '钱十三',
+        operatorRole: 'creator',
+        time: '2026-01-18 10:00:00',
+        remark: '提交应用审核',
+    },
+    {
+        id: 'history_006',
+        auditId: 'audit_003',
+        appId: 'app_011',
+        appName: '质量管理助手',
+        action: 'approved',
+        actionName: '通过',
+        operator: '管理员',
+        operatorRole: 'auditor',
+        time: '2026-01-19 14:20:00',
+        remark: '符合上线标准,予以通过',
+    },
+];
+
+import { MockRequest } from './index';
+
+/**
+ * 获取审核列表
+ * POST /deepseek/api/app/audit/list
+ */
+export const mockFetchAuditList = async (request: MockRequest) => {
+    const { pageNum = 1, pageSize = 10, status, keyword, department } = request.data || {};
+
+    console.log('[Mock] 获取审核列表', { pageNum, pageSize, status, keyword, department });
+
+    // 筛选数据
+    let filteredData = [...mockAuditData];
+
+    if (status && status !== 'all') {
+        filteredData = filteredData.filter(item => item.auditStatus === status);
+    }
+
+    if (department) {
+        filteredData = filteredData.filter(item => item.department === department);
+    }
+
+    if (keyword) {
+        filteredData = filteredData.filter(item =>
+            item.appName.toLowerCase().includes(keyword.toLowerCase()) ||
+            item.creator.toLowerCase().includes(keyword.toLowerCase())
+        );
+    }
+
+    // 分页
+    const total = filteredData.length;
+    const startIndex = (pageNum - 1) * pageSize;
+    const endIndex = startIndex + pageSize;
+    const list = filteredData.slice(startIndex, endIndex);
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            list,
+            total,
+            pageNum,
+            pageSize,
+        },
+    };
+};
+
+/**
+ * 获取审核详情
+ * GET /deepseek/api/app/audit/detail/:id
+ */
+export const mockFetchAuditDetail = async (request: MockRequest) => {
+    const auditId = request.params?.id;
+
+    console.log('[Mock] 获取审核详情', { auditId });
+
+    const audit = mockAuditData.find(a => a.id === auditId);
+
+    if (!audit) {
+        return {
+            code: 404,
+            message: '审核记录不存在',
+            data: null,
+        };
+    }
+
+    return {
+        code: 200,
+        message: 'success',
+        data: audit,
+    };
+};
+
+/**
+ * 审核操作(通过/拒绝)
+ * PUT /deepseek/api/app/audit/auditAction
+ */
+export const mockAuditAction = async (request: MockRequest) => {
+    const { auditId, action, opinion } = request.data || {};
+
+    console.log('[Mock] 审核操作', { auditId, action, opinion });
+
+    const auditIndex = mockAuditData.findIndex(a => a.id === auditId);
+
+    if (auditIndex === -1) {
+        return {
+            code: 404,
+            message: '审核记录不存在',
+            data: null,
+        };
+    }
+
+    const audit = mockAuditData[auditIndex];
+
+    // 更新审核状态
+    mockAuditData[auditIndex] = {
+        ...audit,
+        auditStatus: action === 'approve' ? 'approved' : 'rejected',
+        auditor: '当前审核员',
+        auditTime: new Date().toLocaleString('zh-CN'),
+        auditOpinion: opinion || null,
+    };
+
+    // 同时更新应用状态(模拟)
+    const appIndex = mockAuditData.findIndex(a => a.appId === audit.appId);
+    if (appIndex !== -1) {
+        // 这里只是模拟,实际应用列表在 applicationApi.ts 中
+        console.log(`[Mock] 应用 ${audit.appId} 状态已更新为 ${action === 'approve' ? 'online' : 'rejected'}`);
+    }
+
+    return {
+        code: 200,
+        message: action === 'approve' ? '审核通过' : '已拒绝',
+        data: {
+            auditId,
+            action,
+            auditTime: new Date().toLocaleString('zh-CN'),
+        },
+    };
+};
+
+/**
+ * 获取审核历史列表
+ * POST /deepseek/api/app/auditHistory/list
+ */
+export const mockFetchAuditHistoryList = async (request: MockRequest) => {
+    const { auditId, pageNum = 1, pageSize = 20 } = request.data || {};
+
+    console.log('[Mock] 获取审核历史列表', { auditId, pageNum, pageSize });
+
+    // 筛选数据
+    let filteredData = [...mockAuditHistoryData];
+
+    if (auditId) {
+        filteredData = filteredData.filter(item => item.auditId === auditId);
+    }
+
+    // 按时间排序
+    filteredData.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime());
+
+    // 分页
+    const total = filteredData.length;
+    const startIndex = (pageNum - 1) * pageSize;
+    const endIndex = startIndex + pageSize;
+    const list = filteredData.slice(startIndex, endIndex);
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            list,
+            total,
+            pageNum,
+            pageSize,
+        },
+    };
+};
+
+/**
+ * 获取审核统计
+ * GET /deepseek/api/app/audit/stats
+ */
+export const mockFetchAuditStats = async () => {
+    console.log('[Mock] 获取审核统计');
+
+    const total = mockAuditData.length;
+    const pending = mockAuditData.filter(a => a.auditStatus === 'pending').length;
+    const approved = mockAuditData.filter(a => a.auditStatus === 'approved').length;
+    const rejected = mockAuditData.filter(a => a.auditStatus === 'rejected').length;
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            total,
+            pending,
+            approved,
+            rejected,
+            pendingRate: total > 0 ? ((pending / total) * 100).toFixed(1) : '0',
+            approvedRate: total > 0 ? ((approved / total) * 100).toFixed(1) : '0',
+            rejectedRate: total > 0 ? ((rejected / total) * 100).toFixed(1) : '0',
+        },
+    };
+};
+
+// ==================== 导出所有 Mock 处理函数 ====================
+
+export const auditMockHandlers = {
+    'POST /deepseek/api/app/audit/list': mockFetchAuditList,
+    'GET /deepseek/api/app/audit/detail/:id': mockFetchAuditDetail,
+    'PUT /deepseek/api/app/audit/auditAction': mockAuditAction,
+    'POST /deepseek/api/app/auditHistory/list': mockFetchAuditHistoryList,
+    'GET /deepseek/api/app/audit/stats': mockFetchAuditStats,
+};

+ 200 - 0
jk-rag-platform/src/mock/authApi.ts

@@ -0,0 +1,200 @@
+// ==================== 认证与用户信息 Mock 数据 ====================
+
+// 模拟用户数据
+const mockUsers = [
+    {
+        id: 'current_user',
+        username: 'zhangsan',
+        realName: '张三',
+        email: 'zhangsan@jianke.com',
+        phone: '13800138000',
+        department: '技术研发部',
+        position: '高级开发工程师',
+        avatar: '',
+        roles: ['user', 'developer'],
+    },
+    {
+        id: 'user_001',
+        username: 'lisi',
+        realName: '李四',
+        email: 'lisi@jianke.com',
+        phone: '13800138001',
+        department: '人力资源部',
+        position: '人力资源经理',
+        avatar: '',
+        roles: ['user'],
+    },
+    {
+        id: 'user_002',
+        username: 'wangwu',
+        realName: '王五',
+        email: 'wangwu@jianke.com',
+        phone: '13800138002',
+        department: '项目管理部',
+        position: '项目总监',
+        avatar: '',
+        roles: ['user', 'manager'],
+    },
+];
+
+// 模拟验证码(实际场景应该发送到手机/邮箱)
+let verificationCodes: Record<string, { code: string; expiresAt: number }> = {};
+
+/**
+ * 生成随机验证码
+ */
+function generateVerificationCode(): string {
+    return String(Math.floor(Math.random() * 9000) + 1000);
+}
+
+/**
+ * 模拟登录请求
+ * POST /auth/login
+ */
+export const mockLogin = async (request: { data?: { username?: string; password?: string; code?: string } }) => {
+    const { username, password, code } = request.data || {};
+
+    console.log('[Mock] 登录请求', { username, code });
+
+    // 验证验证码(可选,简化流程)
+    if (code && verificationCodes[username || 'default']) {
+        const savedCode = verificationCodes[username || 'default'];
+        if (savedCode.code !== code) {
+            return {
+                code: 400,
+                message: '验证码错误',
+                data: null,
+            };
+        }
+        // 验证码使用后失效
+        delete verificationCodes[username || 'default'];
+    }
+
+    // 简化验证:只要用户名密码不为空即可
+    if (!username || !password) {
+        return {
+            code: 400,
+            message: '用户名或密码不能为空',
+            data: null,
+        };
+    }
+
+    // 查找用户
+    const user = mockUsers.find(u => u.username === username);
+
+    // 返回模拟 Token
+    const mockToken = `mock_token_${username}_${Date.now()}`;
+    const mockRefreshToken = `mock_refresh_token_${username}_${Date.now()}`;
+
+    return {
+        code: 200,
+        message: '登录成功',
+        data: {
+            token: mockToken,
+            refreshToken: mockRefreshToken,
+            expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 天有效期
+            user: user || mockUsers[0], // 返回用户信息
+        },
+    };
+};
+
+/**
+ * 获取验证码
+ * GET /auth/code
+ */
+export const mockGetVerificationCode = async (request: { params?: { phone?: string; email?: string } }) => {
+    const { phone, email } = request.params || {};
+
+    console.log('[Mock] 获取验证码', { phone, email });
+
+    // 生成验证码
+    const code = generateVerificationCode();
+    const key = phone || email || 'default';
+
+    // 存储验证码(5 分钟有效期)
+    verificationCodes[key] = {
+        code,
+        expiresAt: Date.now() + 5 * 60 * 1000,
+    };
+
+    console.log('[Mock] 验证码(仅供调试):', code);
+
+    return {
+        code: 200,
+        message: '验证码已发送',
+        data: {
+            // 开发环境返回验证码,生产环境应隐藏
+            debugCode: code,
+            expiresInSeconds: 300,
+        },
+    };
+};
+
+/**
+ * 获取当前用户信息
+ * GET /system/user/getInfo
+ */
+export const mockGetUserInfo = async (request: { headers?: { Authorization?: string } }) => {
+    const token = request.headers?.Authorization || '';
+
+    console.log('[Mock] 获取用户信息', { token });
+
+    // 从 Token 中提取用户名(简化处理)
+    const username = token.replace('mock_token_', '').split('_')[0] || 'zhangsan';
+    const user = mockUsers.find(u => u.username === username) || mockUsers[0];
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            ...user,
+            permissions: ['app:create', 'app:edit', 'app:delete', 'knowledge:manage'],
+        },
+    };
+};
+
+/**
+ * 退出登录
+ * POST /auth/logout
+ */
+export const mockLogout = async () => {
+    console.log('[Mock] 退出登录');
+
+    return {
+        code: 200,
+        message: '退出成功',
+        data: null,
+    };
+};
+
+/**
+ * 刷新 Token
+ * POST /auth/refresh
+ */
+export const mockRefreshToken = async (request: { data?: { refreshToken?: string } }) => {
+    const { refreshToken } = request.data || {};
+
+    console.log('[Mock] 刷新 Token', { refreshToken });
+
+    const mockToken = `mock_token_refreshed_${Date.now()}`;
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            token: mockToken,
+            refreshToken: refreshToken || `mock_refresh_token_${Date.now()}`,
+            expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,
+        },
+    };
+};
+
+// ==================== 导出所有 Mock 处理函数 ====================
+
+export const authMockHandlers = {
+    'POST /auth/login': mockLogin,
+    'GET /auth/code': mockGetVerificationCode,
+    'GET /system/user/getInfo': mockGetUserInfo,
+    'POST /auth/logout': mockLogout,
+    'POST /auth/refresh': mockRefreshToken,
+};

+ 166 - 0
jk-rag-platform/src/mock/overviewApi.ts

@@ -0,0 +1,166 @@
+// ==================== 首页统计 Mock 数据 ====================
+
+import { MockRequest } from './index';
+
+/**
+ * 获取首页统计数据
+ * GET /deepseek/overview/topData
+ */
+export const mockFetchOverviewData = async () => {
+    console.log('[Mock] 获取首页统计数据');
+
+    // 模拟统计数据
+    const stats = {
+        // 核心指标
+        totalApps: 18,           // 应用总数
+        onlineApps: 14,          // 已上线应用
+        auditingApps: 2,         // 审核中应用
+        offlineApps: 2,          // 已下线应用
+
+        // 知识库统计
+        totalKnowledgeBases: 45,      // 知识库总数
+        totalDocuments: 328,          // 文档总数
+        totalSlices: 2156,            // 切片总数
+
+        // 使用统计
+        totalConversations: 12580,    // 总会话数
+        todayConversations: 156,      // 今日会话数
+        activeUsers: 89,              // 活跃用户数
+
+        // 待办事项
+        pendingAudits: 3,             // 待审核应用数
+        pendingUpdates: 5,            // 待更新应用数
+
+        // 趋势数据(最近 7 天)
+        conversationTrend: [
+            { date: '2026-03-27', count: 142 },
+            { date: '2026-03-28', count: 158 },
+            { date: '2026-03-29', count: 134 },
+            { date: '2026-03-30', count: 189 },
+            { date: '2026-03-31', count: 167 },
+            { date: '2026-04-01', count: 201 },
+            { date: '2026-04-02', count: 156 },
+        ],
+
+        // 应用分类统计
+        categoryStats: [
+            { category: 'professional', name: '专业知识', count: 7, percentage: 38.9 },
+            { category: 'functional', name: '职能管理', count: 6, percentage: 33.3 },
+            { category: 'project', name: '项目级应用', count: 5, percentage: 27.8 },
+        ],
+
+        // 热门应用 TOP5
+        topApps: [
+            { id: 'app_010', name: '客户服务知识库', conversations: 3200, trend: '+12%' },
+            { id: 'app_007', name: '市场营销支持平台', conversations: 2100, trend: '+8%' },
+            { id: 'app_005', name: '技术培训知识库', conversations: 1580, trend: '+15%' },
+            { id: 'app_001', name: '合同审查助手', conversations: 1250, trend: '+5%' },
+            { id: 'app_002', name: '人力资源问答机器人', conversations: 890, trend: '+3%' },
+        ],
+
+        // 最新动态
+        recentActivities: [
+            { id: 1, type: 'app_created', content: '新创建应用「知识产权助手」', user: '李十六', time: '10 分钟前' },
+            { id: 2, type: 'app_updated', content: '更新应用「合同审查助手」知识库', user: '张三', time: '25 分钟前' },
+            { id: 3, type: 'audit_approved', content: '通过应用「质量管理助手」审核', user: '管理员', time: '1 小时前' },
+            { id: 4, type: 'app_published', content: '应用「档案管理助手」已上线', user: '孙十五', time: '2 小时前' },
+            { id: 5, type: 'audit_rejected', content: '拒绝应用「合规管理助手」审核', user: '管理员', time: '3 小时前' },
+        ],
+    };
+
+    return {
+        code: 200,
+        message: 'success',
+        data: stats,
+    };
+};
+
+/**
+ * 获取在线用户数据
+ * GET /deepseek/overview/onlineUserData
+ */
+export const mockFetchOnlineUserData = async () => {
+    console.log('[Mock] 获取在线用户数据');
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            onlineUsers: 89,
+            peakToday: 156,
+            peakTime: '14:30',
+            avgOnlineTime: '45 分钟',
+        },
+    };
+};
+
+/**
+ * 获取会话数据
+ * GET /deepseek/overview/conversationData
+ */
+export const mockFetchConversationData = async (request: MockRequest) => {
+    const { startDate, endDate } = request.params || {};
+
+    console.log('[Mock] 获取会话数据', { startDate, endDate });
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            total: 12580,
+            today: 156,
+            yesterday: 201,
+            thisWeek: 1047,
+            lastWeek: 892,
+            growthRate: '+17.4%',
+        },
+    };
+};
+
+/**
+ * 获取数据集列表
+ * GET /deepseek/dataset/pageList
+ */
+export const mockFetchDatasetList = async (request: MockRequest) => {
+    const { pageNum = 1, pageSize = 10, keyword } = request.data || {};
+
+    console.log('[Mock] 获取数据集列表', { pageNum, pageSize, keyword });
+
+    const datasets = [
+        { id: 'ds_001', name: '法律法规数据集', docCount: 156, sliceCount: 892, updatedAt: '2026-04-01' },
+        { id: 'ds_002', name: '技术规范数据集', docCount: 234, sliceCount: 1245, updatedAt: '2026-03-30' },
+        { id: 'ds_003', name: '企业制度数据集', docCount: 89, sliceCount: 456, updatedAt: '2026-03-28' },
+        { id: 'ds_004', name: '行业案例数据集', docCount: 312, sliceCount: 1678, updatedAt: '2026-03-25' },
+        { id: 'ds_005', name: '产品知识数据集', docCount: 178, sliceCount: 934, updatedAt: '2026-03-22' },
+    ];
+
+    let filteredData = datasets;
+    if (keyword) {
+        filteredData = datasets.filter(d => d.name.toLowerCase().includes(keyword.toLowerCase()));
+    }
+
+    const total = filteredData.length;
+    const startIndex = (pageNum - 1) * pageSize;
+    const endIndex = startIndex + pageSize;
+    const list = filteredData.slice(startIndex, endIndex);
+
+    return {
+        code: 200,
+        message: 'success',
+        data: {
+            list,
+            total,
+            pageNum,
+            pageSize,
+        },
+    };
+};
+
+// ==================== 导出所有 Mock 处理函数 ====================
+
+export const overviewMockHandlers = {
+    'GET /deepseek/overview/topData': mockFetchOverviewData,
+    'GET /deepseek/overview/onlineUserData': mockFetchOnlineUserData,
+    'GET /deepseek/overview/conversationData': mockFetchConversationData,
+    'GET /deepseek/dataset/pageList': mockFetchDatasetList,
+};

+ 2 - 1
jk-rag-platform/src/pages/appCenter/appPlazaList/index.tsx

@@ -2,6 +2,7 @@ import * as React from 'react';
 import { Pagination } from 'antd';
 import { AppCard, FilterDrawer, HeroBanner, StatsGrid } from '@/components/common';
 import { useAppStore, type FilterState } from './store';
+import { Filter } from 'lucide-react';
 import './style.scss';
 // 导入全局 Mock 数据
 import { getAppsByPageType, getPageConfig, processAppData, mockCurrentUser } from '@/mock';
@@ -137,7 +138,7 @@ const AppPlazaList: React.FC = () => {
                         </button>
                     </div>
                     <button className='filter-btn' onClick={() => setFilterOpen(true)}>
-                        <span className='iconify' data-icon='solar:filter-linear'></span>
+                        <Filter size={18} />
                     </button>
                 </div>
             </div>

+ 1 - 1
jk-rag-platform/src/pages/appCenter/appPlazaList/style.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // 应用广场列表页面样式
 // 说明:

+ 2 - 1
jk-rag-platform/src/pages/appCenter/categoryApps/index.tsx

@@ -3,6 +3,7 @@ import { Pagination, message } from 'antd';
 import { useLocation } from 'react-router-dom';
 import { AppCard, FilterDrawer } from '@/components/common';
 import { useCategoryAppStore, type FilterState } from './store';
+import { Filter } from 'lucide-react';
 import './style.scss';
 // 导入全局 Mock 数据
 import { getAppsByPageType, getPageConfig, processAppData, mockCurrentUser } from '@/mock';
@@ -161,7 +162,7 @@ const CategoryAppsList: React.FC = () => {
                         </button>
                     </div>
                     <button className='filter-btn' onClick={() => setFilterOpen(true)}>
-                        <span className='iconify' data-icon='solar:filter-linear'></span>
+                        <Filter size={18} />
                     </button>
                 </div>
             </div>

+ 1 - 1
jk-rag-platform/src/pages/appCenter/categoryApps/style.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // 分类应用列表页面样式
 // 说明:

+ 0 - 2
jk-rag-platform/src/pages/deepseek/dataExport/style.scss

@@ -1,2 +0,0 @@
-// DeepSeek 数据导出页面样式
-// 注意:.content-section 已在全局 global.less 中定义,此处不需要重复

+ 1 - 1
jk-rag-platform/src/pages/home/style.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // Home 首页样式
 // 说明:使用全局变量,避免硬编码

+ 39 - 35
jk-rag-platform/src/pages/knowledgeLib/detail/components/style.scss

@@ -1,40 +1,44 @@
-/* 覆盖 markdown 渲染出来的样式 */
- .ant-typography h1 {
-  font-size: 20px;   /* 调整大小 */
-  color: #333;       /* 字体颜色 */
-//   border-bottom: 2px solid #eee; /* 底部加一条分隔线 */
-    margin: 2px 0;
-}
+@use '@/styles/variables.scss' as *;
+// 覆盖 markdown 渲染出来的样式 - 使用全局变量
 
-.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-typography {
+    h1 {
+        font-size: $font-4xl;   // 20px
+        color: $text-primary;
+        margin: 2px 0;
+    }
+
+    h2 {
+        font-size: $font-3xl;
+        color: $text-primary;
+        margin: 2px 0;
+    }
+
+    h3 {
+        font-size: $font-2xl;
+        color: $text-primary;
+        margin: 2px 0;
+    }
+
+    h4 {
+        font-size: $font-lg;
+        color: $text-primary;
+        margin: 2px 0;
+    }
+
+    h5, h6 {
+        font-size: $font-base;
+        color: $text-primary;
+        margin: 2px 0;
+    }
 }
+
 .ant-spin-container {
-  width: 100%;
+    width: 100%;
 }
-.md_center{
-  .ant-tabs-tab{
-    padding: 0 0 !important;
-  }
+
+.md_center {
+    .ant-tabs-tab {
+        padding: 0 !important;
+    }
 }

+ 1 - 1
jk-rag-platform/src/pages/knowledgeLib/detail/style.scss

@@ -6,7 +6,7 @@
 
 .ant-typography {
     h1 {
-        font-size: @font-4xl;   // 20px - 使用全局变量
+        font-size: $font-4xl;   // 20px - 使用全局变量
         color: $text-primary;   // 使用全局变量
         margin: 2px 0;
     }

+ 1 - 1
jk-rag-platform/src/pages/knowledgeLib/list/KnowledgeDrawer.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // ===== 知识库 Drawer 样式 =====
 // 说明:只定义页面特定的样式,不覆盖 Ant Design 和全局样式

+ 7 - 6
jk-rag-platform/src/pages/knowledgeLib/list/KnowledgeDrawer.tsx

@@ -1,5 +1,6 @@
 import * as React from 'react';
 import { Drawer, Form, Input, Select, Button, Space, Divider, message, Radio } from 'antd';
+import { Database, Scissors, Text, AlignLeft } from 'lucide-react';
 import './KnowledgeDrawer.scss';
 
 interface KnowledgeDrawerProps {
@@ -60,7 +61,7 @@ const KnowledgeDrawer: React.FC<KnowledgeDrawerProps> = ({
                 {/* 基本信息 */}
                 <div className='icon-select-section'>
                     <div className='section-icon'>
-                        <span className='iconify' data-icon='solar:database-linear'></span>
+                        <Database size={24} />
                     </div>
                     <div className='section-info'>
                         <div className='section-title'>基本信息</div>
@@ -110,7 +111,7 @@ const KnowledgeDrawer: React.FC<KnowledgeDrawerProps> = ({
 
                 <div className='icon-select-section'>
                     <div className='section-icon'>
-                        <span className='iconify' data-icon='solar:scissors-linear'></span>
+                        <Scissors size={24} />
                     </div>
                     <div className='section-info'>
                         <div className='section-title'>切片设置</div>
@@ -125,17 +126,17 @@ const KnowledgeDrawer: React.FC<KnowledgeDrawerProps> = ({
                         rules={[{ required: true, message: '请选择切片方式' }]}
                         extra='选择文档的切片方式'
                     >
-                        <Radio.Group 
-                            buttonStyle="solid" 
+                        <Radio.Group
+                            buttonStyle="solid"
                             className='splitting-radio'
                             onChange={(e) => setSplittingType(e.target.value)}
                         >
                             <Radio.Button value='1'>
-                                <span className='iconify' data-icon='solar:text-block-linear' style={{ marginRight: 4 }}></span>
+                                <Text size={16} style={{ marginRight: 4 }} />
                                 按段落
                             </Radio.Button>
                             <Radio.Button value='2'>
-                                <span className='iconify' data-icon='solar:text-align-left-linear' style={{ marginRight: 4 }}></span>
+                                <AlignLeft size={16} style={{ marginRight: 4 }} />
                                 按章节
                             </Radio.Button>
                         </Radio.Group>

+ 4 - 12
jk-rag-platform/src/pages/knowledgeLib/list/index.tsx

@@ -2,6 +2,7 @@ import * as React from 'react';
 import { useNavigate } from 'react-router-dom';
 import { Button, Table, TableColumnsType, TablePaginationConfig, Input, Space, Tabs, message, Tooltip, Dropdown, MenuProps } from 'antd';
 import { PlusOutlined, SearchOutlined, EditFilled, FileWordFilled, FileMarkdownFilled, DeleteFilled, DownOutlined } from '@ant-design/icons';
+import { Pen, Download, Trash2 } from 'lucide-react';
 import { GuideTips, FilterBar } from '@/components/common';
 import InfoModal from './components/InfoModal';
 import { useKnowledgeLibListStore } from './store';
@@ -255,10 +256,7 @@ const KnowledgeLibList: React.FC = () => {
                                 onClick={() => onClickModify(record)}
                                 className="action-btn"
                             >
-                            <span
-                                className="iconify"
-                                data-icon="material-symbols:edit-rounded"
-                            />
+                                <Pen size={18} />
                             </Button>
                         </Tooltip>
 
@@ -274,10 +272,7 @@ const KnowledgeLibList: React.FC = () => {
                                     size="large"
                                     className="action-btn"
                                 >
-                                    <span
-                                        className="iconify"
-                                        data-icon="solar:download-square-bold"
-                                    />
+                                    <Download size={18} />
                                 </Button>
                             </Tooltip>
                         </Dropdown>
@@ -291,10 +286,7 @@ const KnowledgeLibList: React.FC = () => {
                                 onClick={() => onClickDelete(record)}
                                 className="action-btn"
                             >
-                            <span
-                                className="iconify"
-                                data-icon="solar:trash-bin-trash-bold"
-                            />
+                                <Trash2 size={18} />
                             </Button>
                         </Tooltip>
                     </Space>

+ 32 - 1
jk-rag-platform/src/pages/knowledgeLib/list/style.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // 知识库列表页面样式
 // 说明:优先使用全局样式,本文件只定义必要的表格优化样式
@@ -83,3 +83,34 @@
         font-size: 16px;
     }
 }
+
+// ===== 响应式适配 - 表格横向滚动 =====
+@media (max-width: $screen-md) {
+    .content-section {
+        .ant-table {
+            font-size: $font-sm;
+
+            .ant-table-thead {
+                .ant-table-cell {
+                    padding: $spacing-2 $spacing-3;
+                }
+            }
+
+            .ant-table-tbody {
+                .ant-table-cell {
+                    padding: $spacing-2 $spacing-3;
+                }
+            }
+        }
+    }
+
+    // 操作按钮缩小
+    .action-btn {
+        width: 36px;
+        height: 36px;
+
+        .iconify {
+            font-size: 20px;
+        }
+    }
+}

+ 1 - 1
jk-rag-platform/src/pages/knowledgeLib/revisionTool/components/reviseDrawer.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // ===== 修订工具 Drawer 样式 =====
 // 说明:只定义页面特定的样式

+ 6 - 11
jk-rag-platform/src/pages/layout/components/Header.tsx

@@ -2,6 +2,7 @@ import * as React from 'react';
 import { Modal, Button, Tooltip } from 'antd';
 import { useNavigate } from 'react-router-dom';
 import { MenuFoldOutlined, MenuUnfoldOutlined, MessageOutlined } from '@ant-design/icons';
+import { Bell, ChevronDown, User, Settings, LogOut } from 'lucide-react';
 import LocalStorage from '@/LocalStorage';
 import { useLayoutStore } from '../store';
 import './header.scss';
@@ -141,10 +142,7 @@ const Header: React.FC<Props> = (props) => {
 
                     {/* 通知按钮 */}
                     <button className='notification-btn'>
-                        <span
-                            className='iconify'
-                            data-icon='solar:bell-linear'
-                        ></span>
+                        <Bell size={20} />
                         <span className='notification-dot'></span>
                     </button>
 
@@ -164,10 +162,7 @@ const Header: React.FC<Props> = (props) => {
                                 <p className='user-name'>{userName}</p>
                                 <p className='user-dept'>部门信息</p>
                             </div>
-                            <span
-                                className='iconify user-dropdown-icon'
-                                data-icon='solar:alt-arrow-down-linear'
-                            ></span>
+                            <ChevronDown size={16} className='user-dropdown-icon' />
                         </button>
 
                         {/* 下拉菜单 */}
@@ -179,19 +174,19 @@ const Header: React.FC<Props> = (props) => {
                                 </div>
 
                                 <button className='user-dropdown-item'>
-                                    <span className='iconify' data-icon='solar:user-id-linear'></span>
+                                    <User size={16} />
                                     <span>个人中心</span>
                                 </button>
 
                                 <button className='user-dropdown-item'>
-                                    <span className='iconify' data-icon='solar:settings-linear'></span>
+                                    <Settings size={16} />
                                     <span>账户设置</span>
                                 </button>
 
                                 <div className='user-dropdown-item divider'></div>
 
                                 <button className='user-dropdown-item danger' onClick={handleLogout}>
-                                    <span className='iconify' data-icon='solar:logout-2-linear'></span>
+                                    <LogOut size={16} />
                                     <span>退出登录</span>
                                 </button>
                             </div>

+ 49 - 29
jk-rag-platform/src/pages/layout/components/Sidebar.tsx

@@ -2,6 +2,7 @@ import * as React from 'react';
 import { useNavigate, useLocation } from 'react-router-dom';
 import { useLayoutStore } from '../store';
 import './sidebar.scss';
+import { Star, Database, Key, ClipboardCheck, Book, Notebook, FolderPlus, PlusCircle } from 'lucide-react';
 
 interface NavItem {
     key: string;
@@ -10,6 +11,19 @@ interface NavItem {
     path: string;
 }
 
+// icon 名称到 lucide 组件的映射
+const iconMap: Record<string, React.ComponentType<any>> = {
+    'widget': Star, // 临时用 Star 替代
+    'book': Book,
+    'star': Star,
+    'notebook': Notebook,
+    'gallery': FolderPlus,
+    'plus-circle': PlusCircle,
+    'database': Database,
+    'key': Key,
+    'clipboard-check': ClipboardCheck,
+};
+
 const Sidebar: React.FC = () => {
     const navigate = useNavigate();
     const location = useLocation();
@@ -17,19 +31,19 @@ const Sidebar: React.FC = () => {
 
     // 应用矩阵菜单
     const appMenuItems: NavItem[] = [
-        { key: '/appCenter', icon: 'solar:widget-add-bold-duotone', label: '全部 RAG 应用', path: '/appCenter' },
-        { key: '/appCenter/category?category=professional', icon: 'solar:book-2-bold-duotone', label: '专业知识', path: '/appCenter/category?category=professional' },
-        { key: '/appCenter/category?category=functional', icon: 'solar:star-bold-duotone', label: '职能管理', path: '/appCenter/category?category=functional' },
-        { key: '/appCenter/category?category=project', icon: 'solar:notebook-bookmark-bold-duotone', label: '项目级应用', path: '/appCenter/category?category=project' },
-        { key: '/otherApps', icon: 'solar:gallery-add-bold-duotone', label: '其他非 RAG 应用', path: '/otherApps' },
+        { key: '/appCenter', icon: 'widget', label: '全部 RAG 应用', path: '/appCenter' },
+        { key: '/appCenter/category?category=professional', icon: 'book', label: '专业知识', path: '/appCenter/category?category=professional' },
+        { key: '/appCenter/category?category=functional', icon: 'star', label: '职能管理', path: '/appCenter/category?category=functional' },
+        { key: '/appCenter/category?category=project', icon: 'notebook', label: '项目级应用', path: '/appCenter/category?category=project' },
+        { key: '/otherApps', icon: 'gallery', label: '其他非 RAG 应用', path: '/otherApps' },
     ];
 
     // 管理控制台菜单
     const adminMenuItems: NavItem[] = [
-        { key: '/appCenter/questionAnswer', icon: 'solar:add-circle-bold-duotone', label: '我创建的应用', path: '/appCenter/questionAnswer' },
-        { key: '/knowledge/knowledgeLib', icon: 'solar:database-bold-duotone', label: '知识库管理', path: '/knowledge/knowledgeLib' },
-        { key: '/system/apiKey', icon: 'solar:key-bold-duotone', label: 'API 管理', path: '/system/apiKey' },
-        { key: '/system/audit', icon: 'solar:clipboard-check-bold-duotone', label: '应用审核', path: '/system/audit' },
+        { key: '/appCenter/questionAnswer', icon: 'plus-circle', label: '我创建的应用', path: '/appCenter/questionAnswer' },
+        { key: '/knowledge/knowledgeLib', icon: 'database', label: '知识库管理', path: '/knowledge/knowledgeLib' },
+        { key: '/system/apiKey', icon: 'key', label: 'API 管理', path: '/system/apiKey' },
+        { key: '/system/audit', icon: 'clipboard-check', label: '应用审核', path: '/system/audit' },
     ];
 
     // 检查是否为当前激活的路由(支持带参数的路由和子路由)
@@ -65,16 +79,19 @@ const Sidebar: React.FC = () => {
                 <div>
                     <h3 className='section-title'>应用矩阵</h3>
                     <nav className='nav-menu'>
-                        {appMenuItems.map((item) => (
-                            <button
-                                key={item.key}
-                                className={`nav-item ${isActive(item.path, location.pathname, location.search, false) ? 'active' : ''}`}
-                                onClick={() => handleNavClick(item.path)}
-                            >
-                                <span className='iconify' data-icon={item.icon}></span>
-                                <span>{item.label}</span>
-                            </button>
-                        ))}
+                        {appMenuItems.map((item) => {
+                            const IconComponent = iconMap[item.icon] || Star;
+                            return (
+                                <button
+                                    key={item.key}
+                                    className={`nav-item ${isActive(item.path, location.pathname, location.search, false) ? 'active' : ''}`}
+                                    onClick={() => handleNavClick(item.path)}
+                                >
+                                    <IconComponent size={18} />
+                                    <span>{item.label}</span>
+                                </button>
+                            );
+                        })}
                     </nav>
                 </div>
 
@@ -82,16 +99,19 @@ const Sidebar: React.FC = () => {
                 <div>
                     <h3 className='section-title'>管理控制台</h3>
                     <nav className='nav-menu'>
-                        {adminMenuItems.map((item) => (
-                            <button
-                                key={item.key}
-                                className={`nav-item ${isActive(item.path, location.pathname, location.search, true) ? 'active' : ''}`}
-                                onClick={() => handleNavClick(item.path)}
-                            >
-                                <span className='iconify' data-icon={item.icon}></span>
-                                <span>{item.label}</span>
-                            </button>
-                        ))}
+                        {adminMenuItems.map((item) => {
+                            const IconComponent = iconMap[item.icon] || Star;
+                            return (
+                                <button
+                                    key={item.key}
+                                    className={`nav-item ${isActive(item.path, location.pathname, location.search, true) ? 'active' : ''}`}
+                                    onClick={() => handleNavClick(item.path)}
+                                >
+                                    <IconComponent size={18} />
+                                    <span>{item.label}</span>
+                                </button>
+                            );
+                        })}
                     </nav>
                 </div>
             </div>

+ 1 - 1
jk-rag-platform/src/pages/layout/components/header.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 .header {
     width: 100%;

+ 4 - 4
jk-rag-platform/src/pages/layout/components/sidebar.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // ===== Sidebar 侧边栏样式 =====
 
@@ -76,7 +76,7 @@
 .nav-menu {
     display: flex;
     flex-direction: column;
-    gap: 4px;
+    gap: $spacing-1;
 }
 
 .nav-item {
@@ -161,7 +161,7 @@
     }
 
     .promo-btn {
-        font-size: 10px;
+        font-size: $font-xs;
         font-weight: $font-weight-bold;
         padding: $spacing-1 $spacing-3;
         border-radius: $radius-full;
@@ -180,7 +180,7 @@
         position: absolute;
         right: -$spacing-4;
         bottom: -$spacing-4;
-        font-size: 72px;
+        font-size: $icon-3xl;
         opacity: 0.1;
         color: $bg-secondary;
     }

+ 9 - 9
jk-rag-platform/src/pages/layout/store.ts

@@ -52,17 +52,17 @@ const initialState: LayoutState = {
 
 export const useLayoutStore = create<LayoutStore>((set, get) => ({
     ...initialState,
-    
+
     setRouterMatchList: (list) => set({ routerMatchList: list }),
-    
+
     setUserName: (userName) => set({ userName }),
-    
+
     setCollapsed: (collapsed) => set({ collapsed }),
-    
+
     setSelectedKey: (key) => set({ selectedKey: key }),
-    
+
     setOpenKeys: (openKeys) => set({ openKeys }),
-    
+
     setRoouterName: (name) => set((state) => ({
         routerMatchList: state.routerMatchList.map((val) => {
             if (val && val.breadcrumbName === '知识库详情') {
@@ -71,7 +71,7 @@ export const useLayoutStore = create<LayoutStore>((set, get) => ({
             return val;
         }),
     })),
-    
+
     reset: () => set(initialState),
     
     logout: async (navigate) => {
@@ -113,12 +113,12 @@ export const useLayoutStore = create<LayoutStore>((set, get) => ({
             set({ userName: userInfo.name });
         }
         set({ routerMatchList: list });
-        
+
         const routerInfo = list.length > 1 ? list[list.length - 1] : list[0];
         const flagkeyPath = list.map(item => item.path);
         const visibleItems = list.filter(item => item?.hidden === false);
         const lastVisibleItem = visibleItems.at(-1);
-        
+
         if (routerInfo && lastVisibleItem) {
             get().onChangeSelectedKey({
                 key: lastVisibleItem.path,

+ 3 - 3
jk-rag-platform/src/pages/layout/style.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // ===== 应用布局 =====
 .app-layout {
@@ -155,8 +155,8 @@
     .ant-card-cover {
         display: flex;
         justify-content: center;
-        padding: 60px 0;
-        background: #f0f5ff;
+        padding: $spacing-12 0;
+        background: $bg-tertiary;
         flex: 0 0 auto;
     }
 

+ 1 - 1
jk-rag-platform/src/pages/login/style.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 .login {
     width: 100%;

+ 1 - 1
jk-rag-platform/src/pages/otherApps/otherAppList/style.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // 其他应用列表页面样式
 // 说明:使用全局样式类,本文件只保留必要的页面特定样式

+ 0 - 29
jk-rag-platform/src/pages/otherApps/style.scss

@@ -1,29 +0,0 @@
-// 导入全局样式变量
-@import '@/styles/variables.scss';
-
-// 其他应用列表页面样式
-// 说明:
-// - .list-header 已在全局 global.less 中定义
-// - .sort-buttons 已在全局 global.less 中定义
-// - .filter-btn 已在全局 global.less 中定义
-// - .pagination-container 已在全局 global.less 中定义
-// 本文件仅保留页面特定的响应式样式
-
-.app-plaza-list {
-    padding: $spacing-4 $spacing-6;  // 16px/24px - 紧凑间距
-    min-height: calc(100vh - $header-height);
-    background: $bg-primary;
-}
-
-// 响应式适配
-@media (max-width: 1024px) {
-    .app-plaza-list {
-        padding: $spacing-4 $spacing-6;
-    }
-}
-
-@media (max-width: 768px) {
-    .app-plaza-list {
-        padding: $spacing-4;
-    }
-}

+ 31 - 31
jk-rag-platform/src/pages/questionAnswer/form/DrawerForm.scss

@@ -1,13 +1,13 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // ===== Drawer 表单样式 =====
 
 .rag-drawer {
     .ant-drawer-header {
-        padding: $spacing-4 $spacing-6;
+        padding: $spacing-4 $spacing-lg;
         border-bottom: 1px solid $border-light;
-        
+
         .ant-drawer-title {
             font-size: $font-2xl;
             font-weight: $font-weight-bold;
@@ -26,7 +26,7 @@
 
 .drawer-form-container {
     height: 100%;
-    padding: $spacing-5;
+    padding: $spacing-lg;
     overflow-y: auto;
 
     // 表单区域
@@ -38,18 +38,18 @@
     .icon-select-section {
         display: flex;
         align-items: center;
-        gap: $spacing-6;
-        padding: $spacing-5;
+        gap: $spacing-xl;
+        padding: $spacing-lg;
         background: $bg-tertiary;
         border-radius: $radius-xl;
-        margin-bottom: $spacing-4;  // 16px - 紧凑间距
+        margin-bottom: $spacing-md;
 
         .icon-preview-wrapper {
             flex-shrink: 0;
 
             .icon-preview-box {
-                width: 80px;
-                height: 80px;
+                width: $font-3xl * 4;  // 80px
+                height: $font-3xl * 4;
                 border-radius: $radius-xl;
                 display: flex;
                 align-items: center;
@@ -68,7 +68,7 @@
             flex: 1;
             display: flex;
             flex-direction: column;
-            gap: $spacing-3;
+            gap: $spacing-md;
 
             .color-label {
                 font-size: $font-sm;
@@ -79,8 +79,8 @@
 
     // 分割线
     .section-divider {
-        margin: $spacing-4 0 $spacing-4 0;
-        
+        margin: $spacing-lg 0 $spacing-lg 0;
+
         &::before {
             content: '';
             display: inline-block;
@@ -103,11 +103,11 @@
     .tags-info {
         border: 1px solid $border-base;
         border-radius: $radius-md;
-        padding: $spacing-2 $spacing-3;
+        padding: $spacing-sm $spacing-lg;
         display: flex;
         align-items: center;
         justify-content: space-between;
-        gap: $spacing-3;
+        gap: $spacing-md;
         min-height: 46px;
         background: $bg-secondary;
 
@@ -137,18 +137,18 @@
 
     // 预设问题区域
     .preset-questions {
-        margin-top: $spacing-4;
+        margin-top: $spacing-md;
 
         .questions-list {
             display: flex;
             flex-direction: column;
-            gap: $spacing-3;
+            gap: $spacing-sm;
         }
 
         .question-item {
             display: flex;
             align-items: center;
-            gap: $spacing-3;
+            gap: $spacing-md;
 
             label {
                 min-width: 70px;
@@ -167,7 +167,7 @@
                 flex-shrink: 0;
 
                 .question-icon {
-                    font-size: 18px;
+                    font-size: $icon-lg;
                     cursor: pointer;
                     transition: all 0.2s ease;
 
@@ -175,7 +175,7 @@
                         color: $success-color;
 
                         &:hover {
-                            color: rgba(4, 120, 87, 0.9);
+                            color: $success-dark;
                             transform: scale(1.1);
                         }
                     }
@@ -184,7 +184,7 @@
                         color: $error-color;
 
                         &:hover {
-                            color: rgba(185, 28, 28, 0.9);
+                            color: $error-dark;
                             transform: scale(1.1);
                         }
                     }
@@ -198,7 +198,7 @@
 .drawer-form-container {
     .ant-form {
         .ant-form-item {
-            margin-bottom: $spacing-4;  // 16px - 紧凑间距
+            margin-bottom: $spacing-md;
 
             .ant-form-item-label {
                 > label {
@@ -231,7 +231,7 @@
             .ant-input:focus,
             .ant-input-affix-wrapper:focus-within {
                 border-color: $primary-color;
-                box-shadow: 0 0 0 2px rgba(0, 93, 128, 0.1);
+                box-shadow: 0 0 0 2px rgba($primary-color, 0.1);
             }
         }
     }
@@ -248,11 +248,11 @@
     }
 
     &::-webkit-scrollbar-thumb {
-        background: rgba(209, 213, 219, 0.5);
-        border-radius: 3px;
+        background: rgba($text-disabled, 0.5);
+        border-radius: $spacing-1;
 
         &:hover {
-            background: rgba(209, 213, 219, 0.8);
+            background: rgba($text-disabled, 0.8);
         }
     }
 }
@@ -261,22 +261,22 @@
 .visibility-radio {
     display: flex;
     width: 100%;
-    
+
     .ant-radio-button-wrapper {
         flex: 1;
         text-align: center;
-        height: 40px;
-        line-height: 38px;
+        height: $search-height - 8;  // 40px
+        line-height: $search-height - 10;
         border-radius: $radius-md;
-        
+
         &:first-child {
             border-radius: $radius-md 0 0 $radius-md;
         }
-        
+
         &:last-child {
             border-radius: 0 $radius-md $radius-md 0;
         }
-        
+
         &::before {
             display: none;
         }

+ 3 - 2
jk-rag-platform/src/pages/questionAnswer/form/Step1Drawer.tsx

@@ -2,6 +2,7 @@ import * as React from 'react';
 import { Drawer, Form, Input, Select, Cascader, Tag, InputNumber, ColorPicker, Button, Space, Switch, Divider, message, Radio } from 'antd';
 import { PlusCircleOutlined, MinusCircleOutlined, CloseCircleOutlined, LinkOutlined } from '@ant-design/icons';
 import * as AllIcons from '@ant-design/icons';
+import { Globe, Lock } from 'lucide-react';
 import IconPicker from './IconPicker';
 import VipSelector from './VipSelector';
 import './DrawerForm.scss';
@@ -214,11 +215,11 @@ const Step1Drawer: React.FC<Step1DrawerProps> = (props) => {
                                                 onChange={(e) => onVisibleChange(e.target.value)}
                                             >
                                                 <Radio.Button value='0'>
-                                                    <span className='iconify' data-icon='solar:earth-linear' style={{ marginRight: 4 }}></span>
+                                                    <Globe size={16} style={{ marginRight: 4 }} />
                                                     公开
                                                 </Radio.Button>
                                                 <Radio.Button value='1'>
-                                                    <span className='iconify' data-icon='solar:lock-linear' style={{ marginRight: 4 }}></span>
+                                                    <Lock size={16} style={{ marginRight: 4 }} />
                                                     私有
                                                 </Radio.Button>
                                             </Radio.Group>

+ 13 - 13
jk-rag-platform/src/pages/questionAnswer/form/VipSelector.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // ===== VIP 用户选择器样式 =====
 
@@ -11,13 +11,13 @@
 
 .vip-selector-container {
     display: flex;
-    height: 500px;
+    height: $spacing-12 * 4;  // 500px
     overflow: hidden;
 }
 
 // 左侧:部门树
 .vip-selector-left {
-    width: 240px;
+    width: $sidebar-width-md;  // 240px
     border-right: 1px solid $border-light;
     padding: $spacing-4;
     display: flex;
@@ -50,13 +50,13 @@
             transition: all 0.2s ease;
 
             &:hover {
-                background: rgba(0, 93, 128, 0.05);
+                background: rgba($primary-color, 0.05);
                 border-radius: $radius-sm;
             }
         }
 
         .ant-tree-node-selected {
-            background: rgba(0, 93, 128, 0.1) !important;
+            background: rgba($primary-color, 0.1) !important;
             color: $primary-color;
             font-weight: $font-weight-medium;
         }
@@ -100,8 +100,8 @@
 
         .dept-filter-tag {
             margin-left: $spacing-2;
-            padding: 2px 8px;
-            background: rgba(0, 93, 128, 0.1);
+            padding: $spacing-1 $spacing-md;
+            background: rgba($primary-color, 0.1);
             color: $primary-color;
             border-radius: $radius-full;
             font-size: $font-xs;
@@ -111,7 +111,7 @@
 
     .filter-bar {
         margin-bottom: $spacing-3;
-        padding: $spacing-3;
+        padding: $spacing-md;
         background: $bg-tertiary;
         border-radius: $radius-lg;
     }
@@ -128,11 +128,11 @@
         }
 
         .ant-table-tbody > tr:hover {
-            background: rgba(0, 93, 128, 0.05);
+            background: rgba($primary-color, 0.05);
         }
 
         .ant-table-selection-column {
-            width: 50px;
+            width: $spacing-10;  // 50px
         }
     }
 }
@@ -141,17 +141,17 @@
 @media (max-width: $screen-md) {
     .vip-selector-container {
         flex-direction: column;
-        height: 600px;
+        height: $spacing-12 * 4.8;  // 600px
     }
 
     .vip-selector-left {
         width: 100%;
         border-right: none;
         border-bottom: 1px solid $border-light;
-        max-height: 200px;
+        max-height: $spacing-12 * 3;  // 200px
     }
 
     .vip-selector-right {
-        max-height: 400px;
+        max-height: $spacing-12 * 4;  // 400px
     }
 }

+ 4 - 3
jk-rag-platform/src/pages/questionAnswer/form/VipSelector.tsx

@@ -2,6 +2,7 @@ import * as React from 'react';
 import { Modal, Table, Input, Select, Space, message, Tree, Divider, Button } from 'antd';
 import type { TableColumnsType } from 'antd';
 import type { DataNode } from 'antd/es/tree';
+import { TreePine, Users, Search } from 'lucide-react';
 import './VipSelector.scss';
 
 interface VipUser {
@@ -195,7 +196,7 @@ const VipSelector: React.FC<VipSelectorProps> = ({ open, onClose, onConfirm, exi
                 {/* 左侧:部门树 */}
                 <div className='vip-selector-left'>
                     <div className='section-title'>
-                        <span className='iconify' data-icon='solar:folder-tree-linear'></span>
+                        <TreePine size={18} />
                         选择部门
                     </div>
                     <Tree
@@ -214,7 +215,7 @@ const VipSelector: React.FC<VipSelectorProps> = ({ open, onClose, onConfirm, exi
                 {/* 右侧:用户列表 */}
                 <div className='vip-selector-right'>
                     <div className='section-title'>
-                        <span className='iconify' data-icon='solar:users-group-linear'></span>
+                        <Users size={18} />
                         用户列表
                         {selectedDeptId && (
                             <span className='dept-filter-tag'>
@@ -231,7 +232,7 @@ const VipSelector: React.FC<VipSelectorProps> = ({ open, onClose, onConfirm, exi
                             onChange={(e) => setSearchUserName(e.target.value)}
                             style={{ width: 140 }}
                             allowClear
-                            prefix={<span className='iconify' data-icon='solar:magnifer-linear'></span>}
+                            prefix={<Search size={14} />}
                         />
                         <Input
                             placeholder="搜索昵称"

+ 2 - 227
jk-rag-platform/src/pages/questionAnswer/form/style.scss

@@ -1,229 +1,4 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
-// ===== 创建/编辑表单组件样式 =====
-// 注意:
-// 1. 本样式文件只服务于 form 目录下的组件
-// 2. 不覆盖全局样式(.page-layout, .list-header 等)
-// 3. 使用局部类名避免冲突
-
-// ==================== 步骤 1:基本信息 ====================
-
-.create-step1 {
-
-    .form-input {
-        width: 100%;
-        max-width: 646px;
-        height: 36px;
-    }
-
-    .form-textarea {
-        width: 100%;
-        max-width: 646px;
-        min-height: 96px;
-    }
-
-    .tags-info {
-        border: 1px solid @border-color;
-        width: 100%;
-        max-width: 646px;
-        min-height: 46px;
-        border-radius: $radius-md;
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-        flex-wrap: wrap;
-        padding: $spacing-1 $spacing-2;
-
-        .tags-list {
-            width: 80%;
-            display: flex;
-            flex-wrap: wrap;
-            gap: $spacing-1;
-        }
-
-        .cup {
-            cursor: pointer;
-            margin-right: $spacing-3;
-            color: $text-secondary;
-
-            &:hover {
-                color: $error-color;
-            }
-        }
-    }
-
-    .preset-questions {
-        margin: $spacing-6 0;
-        padding: $spacing-5;
-        background: $bg-tertiary;
-        border-radius: $radius-lg;
-
-        h4 {
-            margin-bottom: $spacing-4;
-            color: $text-primary;
-            font-size: $font-lg;
-            font-weight: $font-weight-medium;
-        }
-
-        .question-item {
-            display: flex;
-            align-items: center;
-            margin-bottom: $spacing-3;
-            gap: $spacing-3;
-
-            label {
-                min-width: 80px;
-                color: $text-secondary;
-                font-size: $font-md;
-            }
-
-            .question-input {
-                flex: 1;
-                min-width: 200px;
-            }
-
-            .question-actions {
-                display: flex;
-                gap: $spacing-2;
-
-                .question-icon {
-                    font-size: 18px;
-                    color: $primary-color;
-                    cursor: pointer;
-                    transition: all 0.2s ease;
-
-                    &:hover {
-                        color: $primary-color-hover;
-                        transform: scale(1.1);
-                    }
-                }
-            }
-        }
-    }
-
-    .step-actions {
-        display: flex;
-        gap: $spacing-3;
-        margin-top: $spacing-6;
-        padding-top: $spacing-6;
-        border-top: 1px solid $border-light;
-    }
-}
-
-// ==================== 步骤 2:RAG 配置 ====================
-
-.create-step2 {
-    height: 100%;
-    display: flex;
-    flex-direction: column;
-
-    .step2-header {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        margin-bottom: $spacing-4;
-        padding-bottom: $spacing-4;
-        border-bottom: 1px solid $border-light;
-
-        .btn-back {
-            background: $bg-tertiary;
-            border: 1px solid $border-base;
-            color: $text-secondary;
-
-            &:hover {
-                background: $border-base;
-                border-color: $primary-color;
-                color: $primary-color;
-            }
-        }
-    }
-
-    .app-splitter {
-        flex: 1;
-        border: 1px solid $border-light;
-        border-radius: $radius-lg;
-        min-height: calc(100vh - 300px);
-
-        .splitter-panel {
-            padding: $spacing-5;
-            overflow-y: auto;
-
-            &.param-config {
-                background: $bg-tertiary;
-            }
-
-            .config-header {
-                display: flex;
-                justify-content: space-between;
-                align-items: center;
-                margin-bottom: $spacing-4;
-                font-size: $font-lg;
-                font-weight: $font-weight-medium;
-                color: $text-primary;
-            }
-
-            .section-title {
-                font-size: $font-lg;
-                font-weight: $font-weight-medium;
-                color: $text-primary;
-                margin-bottom: $spacing-4;
-                display: flex;
-                align-items: center;
-                gap: $spacing-2;
-            }
-        }
-    }
-
-    .prompt-editor {
-        width: 100%;
-        height: 100%;
-        display: flex;
-        flex-direction: column;
-
-        .prompt-info {
-            margin-bottom: $spacing-3;
-
-            .variable-highlight {
-                color: $primary-color;
-                font-weight: $font-weight-medium;
-                padding: 2px 6px;
-                border-radius: $radius-sm;
-                background: rgba(0, 93, 128, 0.1);
-                font-family: $font-family-mono;
-            }
-        }
-
-        .prompt-textarea {
-            flex: 1;
-            min-height: 300px;
-            resize: vertical;
-        }
-    }
-
-    .form-input {
-        width: 100%;
-        max-width: 100%;
-    }
-
-    .form-radio-group {
-        width: 100%;
-        display: flex;
-
-        .ant-radio-button-wrapper {
-            flex: 1;
-            text-align: center;
-        }
-    }
-}
-
-// ==================== 工具类 ====================
-
-.hide-scrollbar {
-    scrollbar-width: none;
-    -ms-overflow-style: none;
-
-    &::-webkit-scrollbar {
-        display: none;
-    }
-}
+// ===== 问答表单样式 =====

+ 0 - 105
jk-rag-platform/src/pages/questionAnswer/info/style.scss

@@ -1,105 +0,0 @@
-// 导入全局样式变量
-@import '@/styles/variables.scss';
-
-// ===== 创建应用页面样式 =====
-// 注意:
-// 1. 主容器使用全局的 .page-layout(已定义在 PageLayout/index.less)
-// 2. 标题栏使用 .list-header.with-back(已定义在 global.less)
-// 3. 此处只定义页面特定的表单和布局样式,不要覆盖全局样式
-
-// ===== 预设问题区域 =====
-.preset-questions {
-    margin: $spacing-6 0;
-
-    h4 {
-        margin-bottom: $spacing-4;
-        color: $text-primary;
-        font-size: $font-lg;
-        font-weight: $font-weight-medium;
-    }
-
-    .question-item {
-        display: flex;
-        align-items: center;
-        margin-bottom: $spacing-3;
-        gap: $spacing-3;
-
-        label {
-            min-width: 80px;
-            color: $text-secondary;
-            font-size: $font-md;
-        }
-
-        .question-input {
-            flex: 1;
-            min-width: 200px;
-        }
-
-        .question-actions {
-            display: flex;
-            gap: $spacing-2;
-
-            .question-icon {
-                font-size: 18px;
-                color: $primary-color;
-                cursor: pointer;
-                transition: all 0.2s ease;
-
-                &:hover {
-                    color: $primary-color-hover;
-                    transform: scale(1.1);
-                }
-            }
-        }
-    }
-}
-
-// ===== Splitter 布局 =====
-.app-splitter {
-    border: 1px solid $border-light;
-    border-radius: $radius-lg;
-    height: calc(100vh - 200px);
-    min-height: 400px;
-
-    .splitter-panel {
-        padding: $spacing-5;
-        overflow-y: auto;
-    }
-}
-
-// ===== Prompt 编辑区 =====
-.prompt-editor {
-    width: 100%;
-    height: 100%;
-    display: flex;
-    flex-direction: column;
-
-    .prompt-info {
-        margin-bottom: $spacing-3;
-
-        .variable-highlight {
-            color: $primary-color;
-            font-weight: $font-weight-medium;
-            padding: 2px 6px;
-            border-radius: $radius-sm;
-            background: rgba(0, 93, 128, 0.1);
-            font-family: $font-family-mono;
-        }
-    }
-
-    .prompt-textarea {
-        flex: 1;
-        min-height: 300px;
-        resize: vertical;
-    }
-}
-
-// ===== 隐藏滚动条 =====
-.hide-scrollbar {
-    scrollbar-width: none;
-    -ms-overflow-style: none;
-
-    &::-webkit-scrollbar {
-        display: none;
-    }
-}

+ 1 - 1
jk-rag-platform/src/pages/questionAnswer/list/style.scss

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 // ===== 我创建的应用列表页面样式 =====
 // 说明:

+ 304 - 0
jk-rag-platform/src/pages/system/apiKey/components/ApiDoc.scss

@@ -0,0 +1,304 @@
+@use '@/styles/variables.scss' as *;
+// API 文档样式
+// 参考 Dify API Reference 设计风格
+
+.api-doc-drawer {
+    .ant-drawer-body {
+        padding: 0;
+    }
+}
+
+.api-doc-content {
+    padding: $spacing-4 $spacing-5;
+    max-width: 850px;
+    margin: 0 auto;
+
+    // 章节样式
+    .api-section {
+        margin-bottom: $spacing-6;
+
+        .section-title {
+            font-size: $font-2xl;
+            font-weight: $font-weight-semibold;
+            color: $text-primary;
+            margin-bottom: $spacing-3;
+            padding-bottom: $spacing-2;
+            border-bottom: 1px solid $border-base;
+        }
+
+        .section-content {
+            color: $text-secondary;
+            line-height: $line-height-relaxed;
+
+            p {
+                margin-bottom: $spacing-3;
+            }
+        }
+    }
+
+    // 信息卡片
+    .info-cards {
+        display: grid;
+        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+        gap: $spacing-3;
+        margin-top: $spacing-3;
+    }
+
+    .info-card {
+        background: $bg-tertiary;
+        border-radius: $radius-lg;
+        padding: $spacing-3;
+        border: 1px solid $border-light;
+
+        .card-label {
+            font-size: $font-sm;
+            color: $text-hint;
+            margin-bottom: $spacing-1;
+        }
+
+        .card-value {
+            font-size: $font-md;
+            color: $text-primary;
+            font-family: monospace;
+
+            code {
+                background: $bg-secondary;
+                padding: 2px 6px;
+                border-radius: $radius-sm;
+                font-size: $font-sm;
+            }
+        }
+    }
+
+    // API 项目样式
+    .api-item {
+        padding: $spacing-4 0;
+        border-bottom: 1px solid $border-light;
+
+        &:last-child {
+            border-bottom: none;
+        }
+
+        .api-header {
+            display: flex;
+            align-items: center;
+            gap: $spacing-2;
+            margin-bottom: $spacing-3;
+
+            .api-method {
+                display: inline-block;
+                padding: 4px 12px;
+                border-radius: $radius-md;
+                font-size: 12px;
+                font-weight: $font-weight-semibold;
+                text-transform: uppercase;
+
+                &.method-post {
+                    background: rgba($success-color, 0.1);
+                    color: $success-color;
+                }
+
+                &.method-get {
+                    background: rgba($info-color, 0.1);
+                    color: $info-color;
+                }
+
+                &.method-put {
+                    background: rgba($warning-color, 0.1);
+                    color: $warning-color;
+                }
+
+                &.method-delete {
+                    background: rgba($error-color, 0.1);
+                    color: $error-color;
+                }
+            }
+
+            .api-path {
+                font-size: $font-lg;
+                font-family: monospace;
+                color: $text-primary;
+                font-weight: $font-weight-medium;
+            }
+        }
+
+        .api-description {
+            color: $text-secondary;
+            margin-bottom: $spacing-4;
+            line-height: $line-height-relaxed;
+        }
+
+        h4 {
+            font-size: $font-md;
+            font-weight: $font-weight-semibold;
+            color: $text-primary;
+            margin: $spacing-4 0 $spacing-2 0;
+        }
+    }
+
+    // 参数表格
+    .params-table {
+        margin: $spacing-3 0;
+        overflow-x: auto;
+
+        table {
+            width: 100%;
+            border-collapse: collapse;
+            font-size: $font-sm;
+
+            th, td {
+                padding: $spacing-2 $spacing-3;
+                text-align: left;
+                border-bottom: 1px solid $border-light;
+            }
+
+            th {
+                background: $bg-tertiary;
+                font-weight: $font-weight-semibold;
+                color: $text-primary;
+                white-space: nowrap;
+            }
+
+            td {
+                color: $text-secondary;
+
+                &:nth-child(1) {
+                    code {
+                        background: $bg-tertiary;
+                        padding: 2px 6px;
+                        border-radius: $radius-sm;
+                        font-size: $font-sm;
+                        color: $primary-color;
+                    }
+                }
+
+                &:nth-child(2) {
+                    .param-type {
+                        color: $text-hint;
+                        font-family: monospace;
+                        font-size: $font-sm;
+                    }
+                }
+            }
+        }
+    }
+
+    // 代码块
+    .code-block {
+        margin: $spacing-3 0;
+        border-radius: $radius-lg;
+        overflow: hidden;
+        border: 1px solid $border-base;
+
+        .code-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: $spacing-2 $spacing-3;
+            background: $bg-tertiary;
+            border-bottom: 1px solid $border-light;
+
+            .code-language {
+                font-size: $font-sm;
+                color: $text-hint;
+                text-transform: uppercase;
+            }
+
+            .ant-btn {
+                font-size: $font-sm;
+            }
+        }
+
+        .code-content {
+            margin: 0;
+            padding: $spacing-3;
+            background: #1a1a2e;
+            overflow-x: auto;
+
+            code {
+                font-family: 'Monaco', 'Consolas', monospace;
+                font-size: $font-sm;
+                line-height: 1.6;
+                color: #e0e0e0;
+            }
+
+            &::-webkit-scrollbar {
+                height: 6px;
+            }
+
+            &::-webkit-scrollbar-track {
+                background: #1a1a2e;
+            }
+
+            &::-webkit-scrollbar-thumb {
+                background: rgba(255, 255, 255, 0.2);
+                border-radius: 3px;
+            }
+        }
+    }
+
+    // 代码 Tab
+    .code-tabs {
+        margin-top: $spacing-2;
+
+        .ant-tabs-nav {
+            margin-bottom: 0;
+        }
+
+        .ant-tabs-content-holder {
+            padding: 0;
+        }
+    }
+
+    // 响应示例
+    .response-example {
+        margin: $spacing-3 0;
+
+        .example-header {
+            font-size: $font-md;
+            font-weight: $font-weight-semibold;
+            color: $text-primary;
+            margin-bottom: $spacing-2;
+        }
+
+        .example-content {
+            margin: 0;
+            padding: $spacing-3;
+            background: $bg-tertiary;
+            border-radius: $radius-lg;
+            border: 1px solid $border-light;
+            overflow-x: auto;
+
+            code {
+                font-family: 'Monaco', 'Consolas', monospace;
+                font-size: $font-sm;
+                line-height: 1.6;
+                color: $text-primary;
+            }
+        }
+    }
+
+    // API Tabs
+    .api-tabs {
+        margin-top: $spacing-4;
+    }
+}
+
+// 响应式适配
+@media (max-width: $screen-md) {
+    .api-doc-content {
+        padding: $spacing-3;
+
+        .info-cards {
+            grid-template-columns: 1fr;
+        }
+
+        .params-table {
+            font-size: $font-xs;
+
+            th, td {
+                padding: $spacing-1 $spacing-2;
+            }
+        }
+    }
+}

+ 415 - 0
jk-rag-platform/src/pages/system/apiKey/components/ApiDoc.tsx

@@ -0,0 +1,415 @@
+import * as React from 'react';
+import { Drawer, Button, Tabs, Tag, Space, message } from 'antd';
+import { CopyOutlined, CheckOutlined } from '@ant-design/icons';
+import './ApiDoc.scss';
+
+const { TabPane } = Tabs;
+
+interface Props {
+    open: boolean;
+    onClose: () => void;
+}
+
+// 代码块组件
+const CodeBlock: React.FC<{ code: string; language?: string }> = ({ code, language = 'bash' }) => {
+    const [copied, setCopied] = React.useState(false);
+
+    const handleCopy = async () => {
+        try {
+            await navigator.clipboard.writeText(code);
+            setCopied(true);
+            message.success('已复制到剪贴板');
+            setTimeout(() => setCopied(false), 2000);
+        } catch (err) {
+            message.error('复制失败');
+        }
+    };
+
+    return (
+        <div className='code-block'>
+            <div className='code-header'>
+                <span className='code-language'>{language}</span>
+                <Button
+                    type='text'
+                    size='small'
+                    icon={copied ? <CheckOutlined /> : <CopyOutlined />}
+                    onClick={handleCopy}
+                >
+                    {copied ? '已复制' : '复制'}
+                </Button>
+            </div>
+            <pre className='code-content'>
+                <code>{code}</code>
+            </pre>
+        </div>
+    );
+};
+
+// 参数表格组件
+const ParamsTable: React.FC<{ params: { name: string; type: string; required: boolean; description: string }[] }> = ({ params }) => (
+    <div className='params-table'>
+        <table>
+            <thead>
+                <tr>
+                    <th>参数</th>
+                    <th>类型</th>
+                    <th>必填</th>
+                    <th>说明</th>
+                </tr>
+            </thead>
+            <tbody>
+                {params.map((param, index) => (
+                    <tr key={index}>
+                        <td><code>{param.name}</code></td>
+                        <td><span className='param-type'>{param.type}</span></td>
+                        <td>
+                            {param.required ? (
+                                <Tag color='red' style={{ fontSize: 12 }}>必填</Tag>
+                            ) : (
+                                <Tag color='default' style={{ fontSize: 12 }}>可选</Tag>
+                            )}
+                        </td>
+                        <td>{param.description}</td>
+                    </tr>
+                ))}
+            </tbody>
+        </table>
+    </div>
+);
+
+// 响应示例组件
+const ResponseExample: React.FC<{ example: string }> = ({ example }) => (
+    <div className='response-example'>
+        <div className='example-header'>响应示例</div>
+        <pre className='example-content'>
+            <code>{example}</code>
+        </pre>
+    </div>
+);
+
+const ApiDoc: React.FC<Props> = ({ open, onClose }) => {
+    const baseUrl = window.location.origin;
+    const apiKey = localStorage.getItem('api_key_demo') || 'your_api_key_here';
+
+    // 通用问答接口
+    const chatCompletionCode = `curl -X POST ${baseUrl}/api/v1/chat/completions \\
+  -H "Content-Type: application/json" \\
+  -H "Authorization: Bearer ${apiKey}" \\
+  -d '{
+    "model": "qwen-plus",
+    "messages": [
+      {
+        "role": "user",
+        "content": "你好,请介绍一下你自己"
+      }
+    ],
+    "stream": false
+  }'`;
+
+    const chatCompletionPython = `import requests
+
+url = "${baseUrl}/api/v1/chat/completions"
+headers = {
+    "Content-Type": "application/json",
+    "Authorization": "Bearer ${apiKey}"
+}
+
+data = {
+    "model": "qwen-plus",
+    "messages": [
+        {
+            "role": "user",
+            "content": "你好,请介绍一下你自己"
+        }
+    ],
+    "stream": False
+}
+
+response = requests.post(url, headers=headers, json=data)
+print(response.json())`;
+
+    // RAG 问答接口
+    const ragChatCode = `curl -X POST ${baseUrl}/api/v1/rag/chat \\
+  -H "Content-Type: application/json" \\
+  -H "Authorization: Bearer ${apiKey}" \\
+  -d '{
+    "knowledge_base_id": "kb_xxxxxxxxx",
+    "query": "公司的年假政策是什么?",
+    "top_k": 3,
+    "score_threshold": 0.7
+  }'`;
+
+    const ragChatPython = `import requests
+
+url = "${baseUrl}/api/v1/rag/chat"
+headers = {
+    "Content-Type": "application/json",
+    "Authorization": "Bearer ${apiKey}"
+}
+
+data = {
+    "knowledge_base_id": "kb_xxxxxxxxx",
+    "query": "公司的年假政策是什么?",
+    "top_k": 3,
+    "score_threshold": 0.7
+}
+
+response = requests.post(url, headers=headers, json=data)
+print(response.json())`;
+
+    // 知识库检索接口
+    const knowledgeSearchCode = `curl -X POST ${baseUrl}/api/v1/knowledge/search \\
+  -H "Content-Type: application/json" \\
+  -H "Authorization: Bearer ${apiKey}" \\
+  -d '{
+    "knowledge_base_id": "kb_xxxxxxxxx",
+    "query": "人工智能技术发展趋势",
+    "top_k": 5,
+    "score_threshold": 0.6
+  }'`;
+
+    const knowledgeSearchPython = `import requests
+
+url = "${baseUrl}/api/v1/knowledge/search"
+headers = {
+    "Content-Type": "application/json",
+    "Authorization": "Bearer ${apiKey}"
+}
+
+data = {
+    "knowledge_base_id": "kb_xxxxxxxxx",
+    "query": "人工智能技术发展趋势",
+    "top_k": 5,
+    "score_threshold": 0.6
+}
+
+response = requests.post(url, headers=headers, json=data)
+print(response.json())`;
+
+    return (
+        <Drawer
+            title="API 文档"
+            placement="right"
+            width={900}
+            open={open}
+            onClose={onClose}
+            className='api-doc-drawer'
+        >
+            <div className='api-doc-content'>
+                {/* 接口概览 */}
+                <div className='api-section'>
+                    <h3 className='section-title'>接口说明</h3>
+                    <div className='section-content'>
+                        <p>本文档提供了建科小智 RAG 平台的 API 接口说明,所有接口均采用 RESTful 风格设计。</p>
+                        <div className='info-cards'>
+                            <div className='info-card'>
+                                <div className='card-label'>基础 URL</div>
+                                <div className='card-value'><code>{baseUrl}/api/v1</code></div>
+                            </div>
+                            <div className='info-card'>
+                                <div className='card-label'>认证方式</div>
+                                <div className='card-value'><code>Bearer Token</code></div>
+                            </div>
+                            <div className='info-card'>
+                                <div className='card-label'>数据格式</div>
+                                <div className='card-value'><code>application/json</code></div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+                <Tabs defaultActiveKey="1" className='api-tabs'>
+                    {/* 通用问答接口 */}
+                    <TabPane tab="通用问答" key="1">
+                        <div className='api-item'>
+                            <div className='api-header'>
+                                <span className='api-method method-post'>POST</span>
+                                <span className='api-path'>/api/v1/chat/completions</span>
+                            </div>
+                            <p className='api-description'>
+                                兼容 OpenAI 格式的通用对话接口,支持多轮对话和流式输出。
+                            </p>
+
+                            <h4>请求参数</h4>
+                            <ParamsTable params={[
+                                { name: 'model', type: 'string', required: true, description: '模型名称,如 qwen-plus、qwen-turbo 等' },
+                                { name: 'messages', type: 'array', required: true, description: '对话消息列表,包含 role 和 content' },
+                                { name: 'stream', type: 'boolean', required: false, description: '是否使用流式输出,默认 false' },
+                                { name: 'temperature', type: 'number', required: false, description: '温度参数,控制输出随机性,范围 0-2' },
+                                { name: 'max_tokens', type: 'integer', required: false, description: '最大输出 token 数' },
+                            ]} />
+
+                            <h4>代码示例</h4>
+                            <Tabs type='card' size='small' className='code-tabs'>
+                                <TabPane tab="cURL" key="curl">
+                                    <CodeBlock code={chatCompletionCode} language='bash' />
+                                </TabPane>
+                                <TabPane tab="Python" key="python">
+                                    <CodeBlock code={chatCompletionPython} language='python' />
+                                </TabPane>
+                            </Tabs>
+
+                            <ResponseExample example={`{
+  "id": "chatcmpl-xxxxxxxx",
+  "object": "chat.completion",
+  "created": 1234567890,
+  "model": "qwen-plus",
+  "choices": [
+    {
+      "index": 0,
+      "message": {
+        "role": "assistant",
+        "content": "你好!我是建科小智,是一个基于大语言模型的智能助手..."
+      },
+      "finish_reason": "stop"
+    }
+  ],
+  "usage": {
+    "prompt_tokens": 10,
+    "completion_tokens": 50,
+    "total_tokens": 60
+  }
+}`} />
+                        </div>
+                    </TabPane>
+
+                    {/* RAG 问答接口 */}
+                    <TabPane tab="RAG 问答" key="2">
+                        <div className='api-item'>
+                            <div className='api-header'>
+                                <span className='api-method method-post'>POST</span>
+                                <span className='api-path'>/api/v1/rag/chat</span>
+                            </div>
+                            <p className='api-description'>
+                                基于知识库的 RAG(检索增强生成)问答接口,结合检索结果生成准确回答。
+                            </p>
+
+                            <h4>请求参数</h4>
+                            <ParamsTable params={[
+                                { name: 'knowledge_base_id', type: 'string', required: true, description: '知识库 ID' },
+                                { name: 'query', type: 'string', required: true, description: '用户问题' },
+                                { name: 'top_k', type: 'integer', required: false, description: '返回最相关的 K 条结果,默认 3' },
+                                { name: 'score_threshold', type: 'number', required: false, description: '相似度阈值,低于此值的结果将被过滤,默认 0.5' },
+                                { name: 'stream', type: 'boolean', required: false, description: '是否使用流式输出,默认 false' },
+                            ]} />
+
+                            <h4>代码示例</h4>
+                            <Tabs type='card' size='small' className='code-tabs'>
+                                <TabPane tab="cURL" key="curl">
+                                    <CodeBlock code={ragChatCode} language='bash' />
+                                </TabPane>
+                                <TabPane tab="Python" key="python">
+                                    <CodeBlock code={ragChatPython} language='python' />
+                                </TabPane>
+                            </Tabs>
+
+                            <ResponseExample example={`{
+  "id": "rag-chat-xxxxxxxx",
+  "object": "rag.completion",
+  "created": 1234567890,
+  "model": "qwen-plus",
+  "choices": [
+    {
+      "index": 0,
+      "message": {
+        "role": "assistant",
+        "content": "根据公司的考勤管理制度,员工年假标准如下:\\n1. 累计工作已满 1 年不满 10 年的,年休假 5 天..."
+      },
+      "finish_reason": "stop"
+    }
+  ],
+  "retrieved_chunks": [
+    {
+      "content": "员工累计工作已满 1 年不满 10 年的,年休假 5 天;已满 10 年不满 20 年的,年休假 10 天...",
+      "score": 0.89,
+      "source": "公司考勤管理制度.pdf"
+    }
+  ],
+  "usage": {
+    "prompt_tokens": 150,
+    "completion_tokens": 80,
+    "total_tokens": 230
+  }
+}`} />
+                        </div>
+                    </TabPane>
+
+                    {/* 知识库检索接口 */}
+                    <TabPane tab="知识库检索" key="3">
+                        <div className='api-item'>
+                            <div className='api-header'>
+                                <span className='api-method method-post'>POST</span>
+                                <span className='api-path'>/api/v1/knowledge/search</span>
+                            </div>
+                            <p className='api-description'>
+                                纯检索接口,仅从知识库中检索相关内容,不进行生成。适用于需要自行处理检索结果的场景。
+                            </p>
+
+                            <h4>请求参数</h4>
+                            <ParamsTable params={[
+                                { name: 'knowledge_base_id', type: 'string', required: true, description: '知识库 ID' },
+                                { name: 'query', type: 'string', required: true, description: '检索关键词' },
+                                { name: 'top_k', type: 'integer', required: false, description: '返回最相关的 K 条结果,默认 5' },
+                                { name: 'score_threshold', type: 'number', required: false, description: '相似度阈值,默认 0.5' },
+                            ]} />
+
+                            <h4>代码示例</h4>
+                            <Tabs type='card' size='small' className='code-tabs'>
+                                <TabPane tab="cURL" key="curl">
+                                    <CodeBlock code={knowledgeSearchCode} language='bash' />
+                                </TabPane>
+                                <TabPane tab="Python" key="python">
+                                    <CodeBlock code={knowledgeSearchPython} language='python' />
+                                </TabPane>
+                            </Tabs>
+
+                            <ResponseExample example={`{
+  "object": "knowledge.search.result",
+  "knowledge_base_id": "kb_xxxxxxxxx",
+  "query": "人工智能技术发展趋势",
+  "results": [
+    {
+      "id": "chunk_001",
+      "content": "人工智能技术发展趋势:1. 大模型持续进化,多模态能力成为标配...",
+      "score": 0.92,
+      "metadata": {
+        "source": "AI 行业研究报告.docx",
+        "page": 15
+      }
+    },
+    {
+      "id": "chunk_002",
+      "content": "生成式 AI 市场规模预计 2025 年将达到 xxx 亿元...",
+      "score": 0.85,
+      "metadata": {
+        "source": "AI 行业研究报告.docx",
+        "page": 23
+      }
+    }
+  ],
+  "total": 2
+}`} />
+                        </div>
+                    </TabPane>
+                </Tabs>
+
+                {/* 错误码说明 */}
+                <div className='api-section'>
+                    <h3 className='section-title'>错误码说明</h3>
+                    <div className='section-content'>
+                        <ParamsTable params={[
+                            { name: '400', type: '', required: false, description: '请求参数错误' },
+                            { name: '401', type: '', required: false, description: '未授权,请检查 API Key 是否正确' },
+                            { name: '403', type: '', required: false, description: '权限不足' },
+                            { name: '404', type: '', required: false, description: '资源不存在' },
+                            { name: '429', type: '', required: false, description: '请求过于频繁,请稍后重试' },
+                            { name: '500', type: '', required: false, description: '服务器内部错误' },
+                        ]} />
+                    </div>
+                </div>
+            </div>
+        </Drawer>
+    );
+};
+
+export default ApiDoc;

+ 159 - 3
jk-rag-platform/src/pages/system/apiKey/index.tsx

@@ -1,9 +1,11 @@
 import * as React from 'react';
-import { Table, TableColumnsType, Button, Space } from 'antd';
-import { DownloadOutlined, PlusOutlined } from '@ant-design/icons';
+import { Table, TableColumnsType, Button, Space, Modal, Form, Input, message } from 'antd';
+import { DownloadOutlined, PlusOutlined, FileTextOutlined } from '@ant-design/icons';
 import Search from './components/Search';
+import ApiDoc from './components/ApiDoc';
 import dayjs from 'dayjs';
 import './style.scss';
+import { apis } from '@/apis';
 
 interface Record {
     id: string;
@@ -22,6 +24,14 @@ const ApiKeyList: React.FC = () => {
         total: 0,
     });
 
+    // API 文档弹窗
+    const [apiDocOpen, setApiDocOpen] = React.useState(false);
+
+    // 创建弹窗相关
+    const [createModalOpen, setCreateModalOpen] = React.useState(false);
+    const [createLoading, setCreateLoading] = React.useState(false);
+    const [createForm] = Form.useForm();
+
     const fetchApiKeyList = React.useCallback(async () => {
         setListLoading(true);
         try {
@@ -38,6 +48,59 @@ const ApiKeyList: React.FC = () => {
         fetchApiKeyList();
     }, [fetchApiKeyList]);
 
+    // 处理创建 API Key
+    const handleCreateApiKey = async () => {
+        try {
+            const values = await createForm.validateFields();
+            setCreateLoading(true);
+            const res = await apis.createApiKey({
+                name: values.name,
+                remark: values.remark,
+            });
+
+            if (res.code === 200) {
+                message.success('创建成功');
+                setCreateModalOpen(false);
+                createForm.resetFields();
+                fetchApiKeyList();
+
+                // 如果有返回 apiKey,提示用户保存
+                if (res.data?.apiKey) {
+                    Modal.success({
+                        title: 'API Key 创建成功',
+                        content: (
+                            <div>
+                                <p style={{ marginBottom: 8 }}>请妥善保存此密钥,关闭后将无法查看:</p>
+                                <Input
+                                    value={res.data.apiKey}
+                                    readOnly
+                                    style={{ marginBottom: 8 }}
+                                />
+                                <p style={{ color: '#ff4d4f', fontSize: 12 }}>
+                                    ⚠️ 此密钥仅显示一次,请务必备份保存!
+                                </p>
+                            </div>
+                        ),
+                        width: 500,
+                    });
+                }
+            }
+        } catch (error: any) {
+            console.error('创建 API Key 失败:', error);
+            if (error?.msg) {
+                message.error(error.msg);
+            }
+        } finally {
+            setCreateLoading(false);
+        }
+    };
+
+    // 打开创建弹窗
+    const handleOpenCreateModal = () => {
+        createForm.resetFields();
+        setCreateModalOpen(true);
+    };
+
     const columns: TableColumnsType<Record> = [
         {
             title: '名称',
@@ -48,6 +111,15 @@ const ApiKeyList: React.FC = () => {
             title: 'API Key',
             dataIndex: 'apiKey',
             key: 'apiKey',
+            ellipsis: true,
+            render: (text) => (
+                <span style={{ fontFamily: 'monospace', fontSize: 12 }}>{text}</span>
+            ),
+        },
+        {
+            title: '备注',
+            dataIndex: 'remark',
+            key: 'remark',
         },
         {
             title: '创建时间',
@@ -55,8 +127,46 @@ const ApiKeyList: React.FC = () => {
             key: 'createTime',
             render: (text) => dayjs(text).format('YYYY-MM-DD HH:mm:ss'),
         },
+        {
+            title: '操作',
+            key: 'action',
+            width: 150,
+            render: (_text, record) => (
+                <Space>
+                    <Button
+                        type="link"
+                        size="small"
+                        danger
+                        onClick={() => handleDeleteApiKey(record)}
+                    >
+                        删除
+                    </Button>
+                </Space>
+            ),
+        },
     ];
 
+    // 删除 API Key
+    const handleDeleteApiKey = async (record: Record) => {
+        Modal.confirm({
+            title: '确认删除',
+            content: `确定要删除 API Key "${record.name}" 吗?`,
+            okText: '确认',
+            cancelText: '取消',
+            onOk: async () => {
+                try {
+                    const res = await apis.deleteApiKey(record.id);
+                    if (res.code === 200) {
+                        message.success('删除成功');
+                        fetchApiKeyList();
+                    }
+                } catch (error: any) {
+                    message.error(error?.msg || '删除失败');
+                }
+            },
+        });
+    };
+
     return (
         <div className="page-container">
             {/* 标题区域 */}
@@ -66,9 +176,17 @@ const ApiKeyList: React.FC = () => {
                     <p>管理和使用 API Key</p>
                 </div>
                 <div className='list-header-actions'>
+                    <Button
+                        icon={<FileTextOutlined />}
+                        onClick={() => setApiDocOpen(true)}
+                        style={{ marginRight: 8 }}
+                    >
+                        API 文档
+                    </Button>
                     <Button
                         type='primary'
                         icon={<PlusOutlined />}
+                        onClick={handleOpenCreateModal}
                     >
                         创建
                     </Button>
@@ -81,7 +199,7 @@ const ApiKeyList: React.FC = () => {
                 <div style={{ marginBottom: 16 }}>
                     <Search />
                 </div>
-                
+
                 {/* 表格区域 */}
                 <Table
                     rowKey="id"
@@ -92,9 +210,47 @@ const ApiKeyList: React.FC = () => {
                         current: page.pageNum,
                         pageSize: page.pageSize,
                         total: page.total,
+                        onChange: (pageNum, pageSize) => {
+                            setPage({ ...page, pageNum, pageSize });
+                            fetchApiKeyList();
+                        },
                     }}
                 />
             </div>
+
+            {/* 创建 API Key 弹窗 */}
+            <Modal
+                title="创建 API Key"
+                open={createModalOpen}
+                onOk={handleCreateApiKey}
+                onCancel={() => setCreateModalOpen(false)}
+                confirmLoading={createLoading}
+                okText="创建"
+                cancelText="取消"
+                width={500}
+            >
+                <Form form={createForm} layout="vertical">
+                    <Form.Item
+                        label="名称"
+                        name="name"
+                        rules={[{ required: true, message: '请输入名称' }]}
+                    >
+                        <Input placeholder="请输入 API Key 名称" />
+                    </Form.Item>
+                    <Form.Item
+                        label="备注"
+                        name="remark"
+                    >
+                        <Input.TextArea
+                            rows={3}
+                            placeholder="请输入备注(可选)"
+                        />
+                    </Form.Item>
+                </Form>
+            </Modal>
+
+            {/* API 文档抽屉 */}
+            <ApiDoc open={apiDocOpen} onClose={() => setApiDocOpen(false)} />
         </div>
     );
 };

+ 1 - 0
jk-rag-platform/src/pages/system/apiKey/style.scss

@@ -1,2 +1,3 @@
+@use '@/styles/variables.scss' as *;
 // 系统管理 - API Key 页面样式
 // 注意:.content-section 已在全局 global.less 中定义,此处不需要重复

+ 8 - 998
jk-rag-platform/src/pages/system/audit/components/style.scss

@@ -1,998 +1,8 @@
-// 主容器样式
-.questionAnswerInfo {
-  width: 100%;
-  height: 100%;
-  background: $bg-secondary;
-  border-radius: $border-radius-base;
-
-  // 内容区域
-  &-content {
-    width: 100%;
-    height: 100%;
-    background: $bg-secondary;
-    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: $bg-tertiary;
-    }
-
-    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: $bg-tertiary;
-    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: $bg-secondaryfff;
-    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: $bg-secondary;
-  border-radius: $border-radius-base;
-  .pl-20{
-    padding-left: 20px;
-  }
-  // 内容区域
-  &-content {
-    width: 100%;
-    height: 100%;
-    background: $bg-secondary;
-    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: $bg-secondaryfff;
-      // 移除浅灰色背景,让父级背景色生效
-    }
-
-    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: $bg-tertiary;
-    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: $bg-secondaryfff;
-    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: $bg-secondaryfff;
-  }
-  
-  &:nth-child(2) {
-    // 中间 30% 区域 - 配置区域
-    background: $bg-tertiary;
-  }
-  
-  &:last-child {
-    // 右侧 35% 区域 - 聊天区域保持白色背景
-    background: $bg-secondaryfff;
-  }
-}
-
-// 更多设置区域统一样式
-.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: $bg-tertiary;
-  padding: 12px 20px;
-}
-
-// Prompt编辑器布局样式
-.prompt {
-  width: 100%;
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-  // 滚动条
-  overflow-y: auto;
-  background: $bg-tertiary;
-  // 提示词模板显示区域
-  &-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: $bg-secondaryfff;
-    // 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;
-      }
-    }
-  }
-}
+@use '@/styles/variables.scss' as *;
+// 导入全局样式变量
+
+// ===== 创建/编辑表单组件样式 =====
+// 注意:
+// 1. 本样式文件只服务于 form 目录下的组件
+// 2. 不覆盖全局样式(.page-layout, .list-header 等)
+// 3. 使用局部类名避免冲突

+ 404 - 202
jk-rag-platform/src/pages/system/audit/index.tsx

@@ -1,246 +1,448 @@
 import * as React from 'react';
-
-import { Table, TableColumnsType, TablePaginationConfig, Drawer, Button } from 'antd';
-import { StepForwardOutlined, PlusOutlined } from '@ant-design/icons';
-import dayjs from 'dayjs';
-import { GuideTips } from '@/components/common';
-import store from './store';
-import { Record } from './types';
+import { useState, useEffect } from 'react';
+import { Table, Button, Input, Space, Modal, Form, Drawer, message, Pagination, Tag } from 'antd';
+import { SearchOutlined, EyeOutlined, CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
+import { useAuditStore } from './store';
 import './style.scss';
-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 STATUS_CONFIG = {
+    pending: { text: '待审核', color: '#F59E0B' },    // 警告色
+    approved: { text: '已通过', color: '#059669' },   // 成功色(加深)
+    rejected: { text: '已拒绝', color: '#DC2626' },   // 错误色(加深)
+};
+
+interface AuditItem {
+    id: string;
+    appId: string;
+    appName: string;
+    appDescription: string;
+    creatorId: string;
+    creator: string;
+    department: string;
+    submitTime: string;
+    auditStatus: 'pending' | 'approved' | 'rejected';
+    auditor: string | null;
+    auditTime: string | null;
+    auditOpinion: string | null;
+    knowledgeBaseCount: number;
+    documentCount: number;
+    sliceCount: number;
+}
+
+const AuditPage: React.FC = () => {
     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);
+        page,
+        stats,
+        fetchAuditList,
+        fetchAuditStats,
+        onAuditPass,
+        onAuditReject,
+        setQuery,
+    } = useAuditStore();
 
+    const [detailVisible, setDetailVisible] = useState(false);
+    const [auditModalVisible, setAuditModalVisible] = useState(false);
+    const [currentAudit, setCurrentAudit] = useState<AuditItem | null>(null);
+    const [auditActionType, setAuditActionType] = useState<'approve' | 'reject'>('approve');
+    const [auditForm] = Form.useForm();
+    const [keyword, setKeyword] = useState('');
+    const [statusFilter, setStatusFilter] = useState<string>('all');
+
+    useEffect(() => {
+        fetchAuditList();
+        fetchAuditStats();
+    }, [page.pageNum, page.pageSize]);
+
+    // 处理审核操作
+    const handleAudit = async () => {
+        try {
+            const values = await auditForm.validateFields();
+            if (auditActionType === 'approve') {
+                await onAuditPass(currentAudit?.id || '', values.opinion || '');
+            } else {
+                await onAuditReject(currentAudit?.id || '', values.opinion || '');
+            }
+            setAuditModalVisible(false);
+        } catch (error: any) {
+            if (error?.response?.status !== 200) {
+                console.error('审核操作失败:', error);
+            }
+        }
+    };
 
+    // 查看详情
+    const handleViewDetail = (record: AuditItem) => {
+        setCurrentAudit(record);
+        setDetailVisible(true);
+    };
 
+    // 打开审核弹窗
+    const handleOpenAuditModal = (record: AuditItem, action: 'approve' | 'reject') => {
+        setCurrentAudit(record);
+        setAuditActionType(action);
+        auditForm.resetFields();
+        setAuditModalVisible(true);
+    };
 
-        return () => {
-            reset();
-            window.removeEventListener('auditHistory', handleKnowledgeLibCreate as EventListener);
-        };
-    }, []);
+    // 状态标签渲染
+    const renderStatusBadge = (status: string) => {
+        const config = STATUS_CONFIG[status] || { text: status, color: '#6B7280' };
+        return <Tag color={config.color}>{config.text}</Tag>;
+    };
 
-    const columns: TableColumnsType<Record> = [
+    // 表格列定义
+    const columns = [
+        {
+            title: '应用名称',
+            dataIndex: 'appName',
+            key: 'appName',
+            width: 200,
+            render: (text: string, record: AuditItem) => (
+                <div>
+                    <div style={{ fontWeight: 500, color: 'var(--text-primary)' }}>{text}</div>
+                    <div style={{ fontSize: '12px', color: 'var(--text-secondary)', marginTop: '4px' }}>
+                        {record.appDescription}
+                    </div>
+                </div>
+            ),
+        },
+        {
+            title: '创建人',
+            dataIndex: 'creator',
+            key: 'creator',
+            width: 100,
+            render: (text: string, record: AuditItem) => (
+                <div>
+                    <div>{text}</div>
+                    <div style={{ fontSize: '12px', color: 'var(--text-hint)' }}>{record.department}</div>
+                </div>
+            ),
+        },
         {
-            title: '序号',
-            dataIndex: 'index',
+            title: '提交时间',
+            dataIndex: 'submitTime',
+            key: 'submitTime',
+            width: 160,
+        },
+        {
+            title: '知识库',
+            key: 'knowledgeBase',
             width: 80,
-            render: (text, record, index) => {
-                return index + 1;
-            }
+            render: (_: any, record: AuditItem) => (
+                <span>{record.knowledgeBaseCount} 个</span>
+            ),
         },
         {
-            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: '文档',
+            key: 'document',
+            width: 70,
+            render: (_: any, record: AuditItem) => (
+                <span>{record.documentCount} 篇</span>
+            ),
         },
         {
-            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: '切片',
+            key: 'slice',
+            width: 70,
+            render: (_: any, record: AuditItem) => (
+                <span>{record.sliceCount} 条</span>
+            ),
         },
         {
-            title: '审核',
-            dataIndex: 'userName',
-            render: (text) => {
-                return `${text}`;
-            }
+            title: '审核状态',
+            dataIndex: 'auditStatus',
+            key: 'auditStatus',
+            width: 100,
+            render: renderStatusBadge,
         },
         {
-            title: '审核意见',
-            dataIndex: 'comment',
-            render: (text) => {
-                if(text){
-                    return `${text}`;
-                }else{
-                    return '--';
-                }
-            }
+            title: '审核人',
+            dataIndex: 'auditor',
+            key: 'auditor',
+            width: 90,
+            render: (text: string | null) => text || '-',
         },
         {
-            title: '创建时间',
-            dataIndex: 'createTime',
-            width: 200,
-            render: (text) => {
-                if (text) {
-                    return dayjs(text).format('YYYY-MM-DD HH:mm:ss');
-                } else {
-                    return '--';
-                }
-            }
+            title: '审核时间',
+            dataIndex: 'auditTime',
+            key: 'auditTime',
+            width: 160,
+            render: (text: string | null) => text || '-',
         },
         {
             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);
+            key: 'action',
+            width: 200,
+            render: (_: any, record: AuditItem) => (
+                <Space>
+                    <Button
+                        size="small"
+                        icon={<EyeOutlined />}
+                        onClick={() => handleViewDetail(record)}
+                    >
+                        详情
+                    </Button>
+                    {record.auditStatus === 'pending' && (
+                        <>
+                            <Button
+                                size="small"
+                                type="primary"
+                                icon={<CheckCircleOutlined />}
+                                style={{ background: 'var(--success-color)', borderColor: 'var(--success-color)' }}
+                                onClick={() => handleOpenAuditModal(record, 'approve')}
+                            >
+                                通过
+                            </Button>
+                            <Button
+                                size="small"
+                                danger
+                                icon={<CloseCircleOutlined />}
+                                onClick={() => handleOpenAuditModal(record, 'reject')}
+                            >
+                                拒绝
+                            </Button>
+                        </>
+                    )}
+                </Space>
+            ),
         },
-    };
+    ];
 
     return (
-        <div className="page-container">
-            {/* 标题区域 */}
-            <div className="list-header">
-                <div className='list-header-title'>
-                    <h1>应用审核</h1>
-                    <p>审核和管理应用</p>
+        <div className="page-container audit-page">
+            {/* 统计卡片 */}
+            <div className="audit-stats">
+                <div className="content-section" style={{ textAlign: 'center' }}>
+                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: 'var(--text-primary)' }}>
+                        {stats?.total || 0}
+                    </div>
+                    <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginTop: '4px' }}>
+                        总审核数
+                    </div>
                 </div>
-                <div className='list-header-actions'>
-                    <Button
-                        type='primary'
-                        icon={<PlusOutlined />}
-                        onClick={onClickCreate}
-                    >
-                        创建
-                    </Button>
+                <div className="content-section" style={{ textAlign: 'center' }}>
+                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: 'var(--warning-color)' }}>
+                        {stats?.pending || 0}
+                    </div>
+                    <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginTop: '4px' }}>
+                        待审核
+                    </div>
+                </div>
+                <div className="content-section" style={{ textAlign: 'center' }}>
+                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: 'var(--success-color)' }}>
+                        {stats?.approved || 0}
+                    </div>
+                    <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginTop: '4px' }}>
+                        已通过
+                    </div>
+                </div>
+                <div className="content-section" style={{ textAlign: 'center' }}>
+                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: 'var(--error-color)' }}>
+                        {stats?.rejected || 0}
+                    </div>
+                    <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginTop: '4px' }}>
+                        已拒绝
+                    </div>
                 </div>
             </div>
 
-            {/* 表格区域 - 使用单个 content-section */}
-            <div className="content-section">
+            {/* 审核列表 */}
+            <div className="audit-table content-section">
+                <div className="table-header">
+                    <div className="header-title">
+                        <h3>审核列表</h3>
+                        <p>管理和审核 RAG 应用上线申请</p>
+                    </div>
+                    <div className="header-actions">
+                        <Input
+                            className="search-input"
+                            placeholder="搜索应用名称或创建人"
+                            prefix={<SearchOutlined />}
+                            value={keyword}
+                            onChange={(e) => setKeyword(e.target.value)}
+                            onPressEnter={() => fetchAuditList()}
+                            allowClear
+                        />
+                    </div>
+                </div>
+
+                <div className="filter-tags">
+                    <span
+                        className={`filter-tag ${statusFilter === 'all' ? 'active' : ''}`}
+                        onClick={() => {
+                            setStatusFilter('all');
+                            setQuery({ status: '' });
+                        }}
+                    >
+                        全部
+                    </span>
+                    <span
+                        className={`filter-tag ${statusFilter === 'pending' ? 'active' : ''}`}
+                        onClick={() => {
+                            setStatusFilter('pending');
+                            setQuery({ status: 'pending' });
+                            fetchAuditList();
+                        }}
+                    >
+                        待审核
+                    </span>
+                    <span
+                        className={`filter-tag ${statusFilter === 'approved' ? 'active' : ''}`}
+                        onClick={() => {
+                            setStatusFilter('approved');
+                            setQuery({ status: 'approved' });
+                            fetchAuditList();
+                        }}
+                    >
+                        已通过
+                    </span>
+                    <span
+                        className={`filter-tag ${statusFilter === 'rejected' ? 'active' : ''}`}
+                        onClick={() => {
+                            setStatusFilter('rejected');
+                            setQuery({ status: 'rejected' });
+                            fetchAuditList();
+                        }}
+                    >
+                        已拒绝
+                    </span>
+                </div>
+
                 <Table
-                    scroll={{ x: 'max-content' }}
-                    rowKey={(record) => record.createTime}
-                    loading={listLoading}
                     columns={columns}
                     dataSource={list}
-                    pagination={paginationConfig}
+                    rowKey="id"
+                    loading={listLoading}
+                    pagination={false}
+                    scroll={{ x: 1400 }}
                 />
+
+                <div className="pagination-container" style={{ marginTop: '16px', display: 'flex', justifyContent: 'flex-end' }}>
+                    <Pagination
+                        current={page.pageNum}
+                        pageSize={page.pageSize}
+                        total={page.total}
+                        onChange={(pageNum, pageSize) => {
+                            useAuditStore.getState().setPage({ ...page, pageNum, pageSize });
+                            fetchAuditList();
+                        }}
+                        showSizeChanger
+                        showTotal={(t) => `共 ${t} 条`}
+                        pageSizeOptions={['10', '20', '50', '100']}
+                    />
+                </div>
             </div>
-        </div>
-        {
-            infoModalOpen &&
-            <InfoModal
-                id={infoModalId}
-                open={infoModalOpen}
-                onClickConfirm={infoModalOnClickConfirm}
-                onClickCancel={infoModalOnClickCancel}
-                onClickClose={infoModalOnClickClose}
-            />
-        }
-        {
+
+            {/* 审核操作弹窗 */}
+            <Modal
+                title={auditActionType === 'approve' ? '审核通过' : '审核拒绝'}
+                open={auditModalVisible}
+                onOk={handleAudit}
+                onCancel={() => setAuditModalVisible(false)}
+                okText="确认"
+                cancelText="取消"
+                okButtonProps={{
+                    danger: auditActionType === 'reject',
+                    style: auditActionType === 'reject' ? {} : { background: 'var(--success-color)', borderColor: 'var(--success-color)' },
+                }}
+            >
+                <div style={{ marginBottom: '16px' }}>
+                    <strong>应用名称:</strong>{currentAudit?.appName}
+                </div>
+                <div style={{ marginBottom: '16px' }}>
+                    <strong>创建人:</strong>{currentAudit?.creator} ({currentAudit?.department})
+                </div>
+                <div style={{ marginBottom: '16px' }}>
+                    <strong>应用描述:</strong>
+                    <p style={{ color: 'var(--text-secondary)', fontSize: '13px' }}>{currentAudit?.appDescription}</p>
+                </div>
+                <Form form={auditForm} layout="vertical">
+                    <Form.Item
+                        label="审核意见"
+                        name="opinion"
+                        rules={[{ required: true, message: `请输入${auditActionType === 'approve' ? '通过' : '拒绝'}意见` }]}
+                    >
+                        <Input.TextArea
+                            rows={4}
+                            placeholder={auditActionType === 'reject'
+                                ? '请输入拒绝原因(必填)'
+                                : '请输入审核意见(必填)'}
+                        />
+                    </Form.Item>
+                </Form>
+            </Modal>
+
+            {/* 详情抽屉 */}
             <Drawer
-                title={drawerData.name}
-                closable={{ 'aria-label': 'Close Button' }}
-                onClose={() => { setDrawerFlag(false) }}
-                width="80%"
-                open={drawerFlag}
+                title="应用详情"
+                placement="right"
+                width={600}
+                open={detailVisible}
+                onClose={() => setDetailVisible(false)}
+                className="detail-drawer"
             >
-                {drawerFlag&&<PreviewModal isComponent={true} AuditAppId={drawerData.appId} />}
+                {currentAudit && (
+                    <>
+                        <div className="detail-section">
+                            <h4 className="section-title">基本信息</h4>
+                            <div className="detail-row">
+                                <span className="label">应用名称:</span>
+                                <span className="value">{currentAudit.appName}</span>
+                            </div>
+                            <div className="detail-row">
+                                <span className="label">应用描述:</span>
+                                <span className="value">{currentAudit.appDescription}</span>
+                            </div>
+                            <div className="detail-row">
+                                <span className="label">创建人:</span>
+                                <span className="value">{currentAudit.creator}</span>
+                            </div>
+                            <div className="detail-row">
+                                <span className="label">所属部门:</span>
+                                <span className="value">{currentAudit.department}</span>
+                            </div>
+                            <div className="detail-row">
+                                <span className="label">提交时间:</span>
+                                <span className="value">{currentAudit.submitTime}</span>
+                            </div>
+                            <div className="detail-row">
+                                <span className="label">审核状态:</span>
+                                <span className="value">{renderStatusBadge(currentAudit.auditStatus)}</span>
+                            </div>
+                        </div>
+
+                        <div className="detail-section">
+                            <h4 className="section-title">资源统计</h4>
+                            <div className="detail-row">
+                                <span className="label">知识库:</span>
+                                <span className="value">{currentAudit.knowledgeBaseCount} 个</span>
+                            </div>
+                            <div className="detail-row">
+                                <span className="label">文档:</span>
+                                <span className="value">{currentAudit.documentCount} 篇</span>
+                            </div>
+                            <div className="detail-row">
+                                <span className="label">切片:</span>
+                                <span className="value">{currentAudit.sliceCount} 条</span>
+                            </div>
+                        </div>
+
+                        {currentAudit.auditOpinion && (
+                            <div className="detail-section">
+                                <h4 className="section-title">审核意见</h4>
+                                <p style={{ color: 'var(--text-secondary)', fontSize: '13px' }}>
+                                    {currentAudit.auditOpinion}
+                                </p>
+                            </div>
+                        )}
+                    </>
+                )}
             </Drawer>
-        }
-        <AuditHistory open={historyOpen} onClose={() => setHistoryOpen(false)} />
+        </div>
     );
 };
 
-export default KnowledgeLibList;
+export default AuditPage;

+ 61 - 24
jk-rag-platform/src/pages/system/audit/store.ts

@@ -1,6 +1,6 @@
 import { create } from 'zustand';
 import { message } from 'antd';
-import { apis } from '@/apis';
+import { fetchAuditList, fetchAuditStats, auditAction } from '@/apis';
 
 interface PageState {
     pageNum: number;
@@ -15,6 +15,12 @@ interface AuditState {
     page: PageState;
     infoModalId: string;
     infoModalOpen: boolean;
+    stats: {
+        total: number;
+        pending: number;
+        approved: number;
+        rejected: number;
+    } | null;
 }
 
 interface AuditActions {
@@ -24,12 +30,14 @@ interface AuditActions {
     setPage: (page: PageState) => void;
     setInfoModalId: (id: string) => void;
     setInfoModalOpen: (open: boolean) => void;
+    setStats: (stats: any) => void;
 }
 
 export type AuditStore = AuditState & AuditActions & {
     fetchAuditList: () => Promise<void>;
-    onAuditPass: (id: string) => Promise<void>;
-    onAuditReject: (id: string, reason: string) => Promise<void>;
+    fetchAuditStats: () => Promise<void>;
+    onAuditPass: (auditId: string, opinion: string) => Promise<void>;
+    onAuditReject: (auditId: string, opinion: string) => Promise<void>;
 };
 
 const initialState: AuditState = {
@@ -43,64 +51,93 @@ const initialState: AuditState = {
     },
     infoModalId: '',
     infoModalOpen: false,
+    stats: null,
 };
 
 export const useAuditStore = create<AuditStore>((set, get) => ({
     ...initialState,
-    
+
     setQuery: (query) => set({ query }),
-    
+
     setListLoading: (loading) => set({ listLoading: loading }),
-    
+
     setList: (list) => set({ list }),
-    
+
     setPage: (page) => set({ page }),
-    
+
     setInfoModalId: (id) => set({ infoModalId: id }),
-    
+
     setInfoModalOpen: (open) => set({ infoModalOpen: open }),
-    
+
+    setStats: (stats) => set({ stats }),
+
     fetchAuditList: async () => {
         set({ listLoading: true });
         try {
             const { query, page } = get();
-            const res: any = await apis.fetchAuditList({
+            const res: any = await fetchAuditList({
                 ...query,
                 pageNum: page.pageNum,
                 pageSize: page.pageSize,
             });
-            
+
             if (res.code === 200) {
                 set({
-                    list: res.rows || [],
+                    list: res.data?.list || [],
                     page: {
                         ...page,
-                        total: res.total || 0,
+                        total: res.data?.total || 0,
                     },
                 });
             }
         } catch (error) {
             console.error('获取审核列表失败:', error);
+            message.error('获取审核列表失败');
         } finally {
             set({ listLoading: false });
         }
     },
-    
-    onAuditPass: async (id: string) => {
+
+    fetchAuditStats: async () => {
+        try {
+            const res: any = await fetchAuditStats();
+            if (res.code === 200) {
+                set({ stats: res.data || null });
+            }
+        } catch (error) {
+            console.error('获取统计数据失败:', error);
+        }
+    },
+
+    onAuditPass: async (auditId: string, opinion: string) => {
         try {
-            await apis.auditPass(id);
-            message.success('审核通过');
-            get().fetchAuditList();
+            const res: any = await auditAction({
+                auditId,
+                action: 'approve',
+                opinion,
+            });
+            if (res.code === 200) {
+                message.success('审核通过');
+                get().fetchAuditList();
+                get().fetchAuditStats();
+            }
         } catch (error) {
             message.error('审核失败');
         }
     },
-    
-    onAuditReject: async (id: string, reason: string) => {
+
+    onAuditReject: async (auditId: string, opinion: string) => {
         try {
-            await apis.auditReject(id, reason);
-            message.success('已拒绝');
-            get().fetchAuditList();
+            const res: any = await auditAction({
+                auditId,
+                action: 'reject',
+                opinion,
+            });
+            if (res.code === 200) {
+                message.success('已拒绝');
+                get().fetchAuditList();
+                get().fetchAuditStats();
+            }
         } catch (error) {
             message.error('操作失败');
         }

+ 241 - 2
jk-rag-platform/src/pages/system/audit/style.scss

@@ -1,2 +1,241 @@
-// 系统管理 - 审计日志页面样式
-// 注意:.content-section 已在全局 global.less 中定义,此处不需要重复
+@use '@/styles/variables.scss' as *;
+// 导入全局样式变量
+
+.audit-page {
+    .audit-stats {
+        display: grid;
+        grid-template-columns: repeat(4, 1fr);
+        gap: $spacing-4;
+        margin-bottom: $spacing-4;
+
+        @media (max-width: $screen-lg) {
+            grid-template-columns: repeat(2, 1fr);
+        }
+
+        @media (max-width: $screen-md) {
+            grid-template-columns: 1fr;
+        }
+    }
+
+    .audit-table {
+        background: $bg-secondary;
+        border-radius: $radius-lg;
+        padding: $spacing-4;
+
+        .table-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: $spacing-4;
+
+            .header-title {
+                h3 {
+                    font-size: $font-lg;
+                    font-weight: $font-weight-semibold;
+                    color: $text-primary;
+                    margin: 0 0 $spacing-1 0;
+                }
+
+                p {
+                    font-size: $font-sm;
+                    color: $text-secondary;
+                    margin: 0;
+                }
+            }
+
+            .header-actions {
+                display: flex;
+                gap: $spacing-3;
+                align-items: center;
+
+                .search-input {
+                    width: 240px;
+                }
+            }
+        }
+
+        .filter-tags {
+            display: flex;
+            gap: $spacing-2;
+            margin-bottom: $spacing-4;
+            flex-wrap: wrap;
+
+            .filter-tag {
+                padding: $spacing-2 $spacing-3;
+                background: $bg-tertiary;
+                border-radius: $radius-md;
+                font-size: $font-sm;
+                color: $text-secondary;
+                cursor: pointer;
+                transition: $transition-base;
+
+                &:hover {
+                    background: $bg-hover;
+                    color: $text-primary;
+                }
+
+                &.active {
+                    background: $tag-bg-blue;
+                    color: $tag-text-blue;
+                }
+            }
+        }
+
+        .status-badge {
+            display: inline-flex;
+            align-items: center;
+            gap: $spacing-1;
+            padding: $spacing-1 $spacing-2;
+            border-radius: $radius-md;
+            font-size: $font-sm;
+
+            &.pending {
+                background: $tag-bg-amber;
+                color: $tag-text-amber;
+            }
+
+            &.approved {
+                background: $tag-bg-teal;
+                color: $tag-text-teal;
+            }
+
+            &.rejected {
+                background: $tag-bg-rose;
+                color: $tag-text-rose;
+            }
+        }
+
+        .action-buttons {
+            display: flex;
+            gap: $spacing-2;
+
+            .audit-btn {
+                padding: $spacing-1 $spacing-3;
+                font-size: $font-sm;
+                border-radius: $radius-md;
+
+                &.approve {
+                    background: $success-color;
+                    color: #ffffff;
+                    border: none;
+
+                    &:hover {
+                        background: $success-light;
+                    }
+                }
+
+                &.reject {
+                    background: $error-color;
+                    color: #ffffff;
+                    border: none;
+
+                    &:hover {
+                        background: $error-light;
+                    }
+                }
+            }
+        }
+    }
+
+    .detail-drawer {
+        .detail-section {
+            margin-bottom: $spacing-4;
+
+            .section-title {
+                font-size: $font-md;
+                font-weight: $font-weight-semibold;
+                color: $text-primary;
+                margin-bottom: $spacing-3;
+                padding-bottom: $spacing-2;
+                border-bottom: 1px solid $border-base;
+            }
+
+            .detail-row {
+                display: flex;
+                margin-bottom: $spacing-2;
+
+                .label {
+                    width: 100px;
+                    font-size: $font-sm;
+                    color: $text-secondary;
+                    flex-shrink: 0;
+                }
+
+                .value {
+                    font-size: $font-base;
+                    color: $text-primary;
+                }
+            }
+
+            .tag-list {
+                display: flex;
+                flex-wrap: wrap;
+                gap: $spacing-2;
+
+                .tag {
+                    padding: $spacing-1 $spacing-2;
+                    background: $tag-bg-blue;
+                    color: $tag-text-blue;
+                    border-radius: $radius-md;
+                    font-size: $font-xs;
+                }
+            }
+        }
+
+        .history-timeline {
+            .timeline-item {
+                display: flex;
+                gap: $spacing-3;
+                padding-bottom: $spacing-3;
+                margin-bottom: $spacing-3;
+                border-left: 2px solid $border-base;
+                padding-left: $spacing-4;
+                position: relative;
+
+                &::before {
+                    content: '';
+                    position: absolute;
+                    left: -6px;
+                    top: 0;
+                    width: 10px;
+                    height: 10px;
+                    border-radius: 50%;
+                    background: $primary-color;
+                }
+
+                &.approved::before {
+                    background: $success-color;
+                }
+
+                &.rejected::before {
+                    background: $error-color;
+                }
+
+                .timeline-content {
+                    flex: 1;
+
+                    .timeline-title {
+                        font-size: $font-base;
+                        font-weight: $font-weight-medium;
+                        color: $text-primary;
+                        margin-bottom: $spacing-1;
+                    }
+
+                    .timeline-time {
+                        font-size: $font-xs;
+                        color: $text-hint;
+                        margin-bottom: $spacing-1;
+                    }
+
+                    .timeline-remark {
+                        font-size: $font-sm;
+                        color: $text-secondary;
+                        background: $bg-tertiary;
+                        padding: $spacing-2;
+                        border-radius: $radius-md;
+                    }
+                }
+            }
+        }
+    }
+}

+ 0 - 2
jk-rag-platform/src/pages/system/contentManagement/style.scss

@@ -1,2 +0,0 @@
-// 系统管理 - 内容管理页面样式
-// 注意:.content-section 已在全局 global.less 中定义,此处不需要重复

+ 0 - 2
jk-rag-platform/src/pages/system/usageStatistics/style.scss

@@ -1,2 +0,0 @@
-// 系统管理 - 使用统计页面样式
-// 注意:.content-section 已在全局 global.less 中定义,此处不需要重复

+ 95 - 5
jk-rag-platform/src/pages/universalChat/styles/index.scss

@@ -7,7 +7,7 @@
     --chat-bg-secondary: #ffffff;  // 白色背景,与主项目一致
     --chat-text-primary: #131212;   // 深灰近黑
     --chat-text-secondary: #5E5E66; // 默认文字色(加深)
-    --chat-text-muted: $text-hint;
+    --chat-text-muted: #9CA3AF;
     --chat-border-color: #F3F4F6;   // 浅边框
     --chat-hover-bg: #F3F4F6;       // 悬停背景 = 激活背景
     --chat-active-bg: #F3F4F6;      // 激活背景
@@ -419,7 +419,7 @@
         margin: 0 auto 24px;
 
         .chat-input-wrapper {
-            background: white;
+            background: var(--chat-bg-secondary);
             border: 1px solid var(--chat-border-color);
             border-radius: 16px;
             padding: 16px 24px;
@@ -605,7 +605,7 @@
                 transition: var(--chat-transition);
 
                 &:hover {
-                    background: #f3f4f6;
+                    background: var(--chat-hover-bg);
                 }
             }
         }
@@ -669,7 +669,7 @@
     top: 20px;
     right: 20px;
     padding: 8px 16px;
-    background: white;
+    background: var(--chat-bg-secondary);
     border: 1px solid var(--chat-border-color);
     border-radius: 8px;
     cursor: pointer;
@@ -678,11 +678,101 @@
     transition: var(--chat-transition);
 
     &:hover {
-        background: var(--chat-bg-secondary);
+        background: var(--chat-hover-bg);
     }
 }
 
 // Responsive
+@media (max-width: 1024px) {
+    // 小屏桌面:Sidebar 自动折叠为 80px
+    .chat-sidebar {
+        width: 80px;
+
+        &.collapsed {
+            width: 60px;
+        }
+
+        // 隐藏文字内容,只保留图标
+        .chat-sidebar-header {
+            .logo {
+                justify-content: center;
+
+                .logo-text,
+                .logo-slogan {
+                    display: none;
+                }
+            }
+        }
+
+        .chat-sidebar-body {
+            .collapsible-menu {
+                .menu-header {
+                    .menu-title,
+                    .menu-search-icon {
+                        display: none;
+                    }
+
+                    .menu-arrow {
+                        display: none;
+                    }
+                }
+
+                .menu-content {
+                    display: none;
+                }
+            }
+
+            .recent-chats-section {
+                .section-header {
+                    .section-title-text {
+                        display: none;
+                    }
+                }
+
+                .date-group {
+                    .date-label {
+                        display: none;
+                    }
+
+                    .chat-item {
+                        justify-content: center;
+
+                        .chat-item-title {
+                            display: none;
+                        }
+                    }
+                }
+            }
+
+            .simple-app-item {
+                justify-content: center;
+                padding: 8px 12px;
+
+                .simple-app-name {
+                    display: none;
+                }
+            }
+
+            .new-chat-btn {
+                width: 40px;
+                padding: 10px 0;
+                justify-content: center;
+
+                .new-chat-text {
+                    display: none;
+                }
+            }
+        }
+    }
+
+    // 主内容区域调整
+    .chat-main {
+        .welcome-screen {
+            max-width: 600px;
+        }
+    }
+}
+
 @media (max-width: 768px) {
     .chat-sidebar {
         position: fixed;

+ 429 - 40
jk-rag-platform/src/styles/global.scss

@@ -1,5 +1,5 @@
+@use './variables.scss' as *;
 // Variables imported via main entry point with @/ alias
-@import './variables.scss';
 
 // ===== 隐藏式滚动条(全局) =====
 // 适用于所有内容区域,保持界面简洁
@@ -46,14 +46,35 @@ body {
     color: $theme-text-color !important;
     // Ant-Design 主题 - 属性
     --primary-color: $primary-color;
+    --primary-light: $primary-light;
+    --primary-dark: $primary-dark;
     --text-color: $theme-text-color;
+    --text-primary: $text-primary;
+    --text-secondary: $text-secondary;
+    --text-hint: $text-hint;
+    --text-disabled: $text-disabled;
     --border-radius: $border-radius-base;
+    --success-color: $success-color;
+    --success-light: $success-light;
+    --success-dark: $success-dark;
+    --warning-color: $warning-color;
+    --warning-light: $warning-light;
+    --warning-dark: $warning-dark;
+    --error-color: $error-color;
+    --error-light: $error-light;
+    --error-dark: $error-dark;
+    --info-color: $info-color;
+    --bg-primary: $bg-primary;
+    --bg-secondary: $bg-secondary;
+    --bg-tertiary: $bg-tertiary;
+    --border-base: $border-base;
+    --border-light: $border-light;
     background: $bg-primary; /* 设置背景色 */
-    
+
     // 隐藏滚动条
     scrollbar-width: none; // Firefox
     -ms-overflow-style: none; // IE/Edge
-    
+
     &::-webkit-scrollbar {
         display: none; // Chrome/Safari/Opera
     }
@@ -200,44 +221,412 @@ ul li {
     border: none !important;
 }
 
-// 全局按钮样式
-.ant-btn-primary {
-    background: $primary-color;
-    border: 1px solid $primary-color;
-    color: #ffffff;
+// 全局按钮样式 - 覆盖 Ant Design 默认样式
+.ant-btn {
+    border-radius: $radius-lg;  // 8px - follow global specs
     transition: $transition-base;
+
+    // Primary 按钮
+    &.ant-btn-primary {
+        background: $primary-color !important;
+        border-color: $primary-color !important;
+        color: #ffffff !important;
+        box-shadow: $shadow-sm;
+
+        &:hover {
+            background: $primary-light !important;
+            border-color: $primary-light !important;
+            color: #ffffff !important;
+            box-shadow: $shadow-md;
+        }
+
+        &:active {
+            background: $primary-dark !important;
+            border-color: $primary-dark !important;
+            color: #ffffff !important;
+            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
+        }
+
+        &:disabled {
+            background: $bg-tertiary !important;
+            border-color: $border-base !important;
+            color: $text-disabled !important;
+            box-shadow: none !important;
+        }
+    }
+
+    // Default 按钮
+    &.ant-btn-default {
+        background: $bg-secondary;
+        border-color: $border-base;
+        color: $text-primary;
+
+        &:hover {
+            border-color: $primary-light;
+            color: $primary-light;
+        }
+
+        &:active {
+            border-color: $primary-dark;
+            color: $primary-dark;
+        }
+    }
+
+    // Text 按钮
+    &.ant-btn-text {
+        color: $text-primary;
+
+        &:hover {
+            background: $bg-tertiary;
+            color: $primary-color;
+        }
+
+        &:active {
+            color: $primary-dark;
+        }
+    }
+
+    // Link 按钮
+    &.ant-btn-link {
+        color: $primary-color;
+
+        &:hover {
+            color: $primary-light;
+        }
+
+        &:active {
+            color: $primary-dark;
+        }
+    }
+}
+
+// 输入框组件
+.ant-input,
+.ant-input-affix-wrapper,
+.ant-input-number,
+.ant-input-password {
+    border-radius: $radius-lg !important;
+
+    &:hover,
+    &:focus {
+        border-color: $primary-color !important;
+    }
+}
+
+.ant-input-affix-wrapper-focused,
+.ant-input-affix-wrapper:focus {
+    border-color: $primary-color !important;
+    box-shadow: 0 0 0 2px rgba($primary-color, 0.1) !important;
+}
+
+// 下拉选择框
+.ant-select {
+    .ant-select-selector {
+        border-radius: $radius-lg !important;
+
+        &:hover,
+        &:focus {
+            border-color: $primary-color !important;
+        }
+    }
+
+    &.ant-select-focused .ant-select-selector {
+        border-color: $primary-color !important;
+        box-shadow: 0 0 0 2px rgba($primary-color, 0.1) !important;
+    }
+}
+
+// 下拉菜单
+.ant-select-dropdown,
+.ant-dropdown {
+    border-radius: $radius-lg !important;
+    box-shadow: $shadow-lg !important;
+}
+
+// 模态框
+.ant-modal {
+    border-radius: $radius-2xl !important;
+
+    .ant-modal-header {
+        border-radius: $radius-2xl $radius-2xl 0 0 !important;
+        border-bottom: 1px solid $border-base;
+    }
+
+    .ant-modal-footer {
+        border-top: 1px solid $border-base;
+
+        .ant-btn {
+            border-radius: $radius-lg;
+        }
+    }
+}
+
+// 抽屉
+.ant-drawer {
+    .ant-drawer-header {
+        border-bottom: 1px solid $border-base;
+    }
+
+    .ant-drawer-footer {
+        border-top: 1px solid $border-base;
+        border-radius: 0;
+
+        .ant-btn {
+            border-radius: $radius-lg;
+        }
+    }
+}
+
+// 表格
+.ant-table {
+    border-radius: $radius-lg !important;
+    overflow: hidden;
+
+    thead {
+        .ant-table-cell {
+            background: $bg-tertiary;
+            font-weight: $font-weight-semibold;
+            color: $text-primary;
+        }
+    }
+
+    tbody {
+        .ant-table-row {
+            &:hover {
+                background: $bg-hover !important;
+            }
+        }
+
+        .ant-table-cell {
+            border-bottom-color: $border-light;
+        }
+    }
+}
+
+// 卡片
+.ant-card {
+    border-radius: $radius-xl !important;
+    border: 1px solid $border-light !important;
     box-shadow: $shadow-sm;
-    
+
     &:hover {
-        background: $primary-light;
-        border-color: $primary-light;
-        color: #ffffff;
+        box-shadow: $shadow-md;
     }
-    
-    &:active {
-        background: $primary-dark;
-        border-color: $primary-dark;
-        color: #ffffff;
-        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
-        transform: translateY(0);
+
+    .ant-card-head {
+        border-radius: $radius-xl $radius-xl 0 0 !important;
+        font-weight: $font-weight-semibold;
     }
-    
+
+    .ant-card-body {
+        padding: $spacing-4;
+    }
+}
+
+// 标签
+.ant-tag {
+    border-radius: $radius-md !important;
+    padding: $spacing-1 $spacing-2;
+    font-size: $font-sm;
+
+    &.ant-tag-processing {
+        background: $tag-bg-blue !important;
+        color: $tag-text-blue !important;
+        border-color: transparent !important;
+    }
+
+    &.ant-tag-success {
+        background: $tag-bg-teal !important;
+        color: $tag-text-teal !important;
+        border-color: transparent !important;
+    }
+
+    &.ant-tag-warning {
+        background: $tag-bg-amber !important;
+        color: $tag-text-amber !important;
+        border-color: transparent !important;
+    }
+
+    &.ant-tag-error {
+        background: $tag-bg-rose !important;
+        color: $tag-text-rose !important;
+        border-color: transparent !important;
+    }
+}
+
+// 消息提示
+.ant-message {
+    .ant-message-notice-content {
+        border-radius: $radius-lg;
+        box-shadow: $shadow-lg;
+    }
+}
+
+// 通知
+.ant-notification-notice {
+    border-radius: $radius-lg !important;
+    box-shadow: $shadow-lg !important;
+}
+
+// 弹出框
+.ant-popover {
+    .ant-popover-arrow {
+        width: 10px;
+        height: 10px;
+
+        &::before {
+            background: $bg-secondary;
+        }
+    }
+
+    .ant-popover-inner {
+        border-radius: $radius-lg !important;
+        box-shadow: $shadow-lg !important;
+    }
+
+    .ant-popover-inner-content {
+        border-radius: $radius-lg;
+    }
+}
+
+// 工具提示
+.ant-tooltip {
+    // 箭头 - Ant Design 5.x 使用 ::after 伪元素创建三角形
+    .ant-tooltip-arrow {
+        &::after {
+            position: absolute;
+            width: 0;
+            height: 0;
+            border: 5px solid transparent;
+            content: '';
+        }
+    }
+
+    // 上方 tooltip - 箭头向下
+    &.ant-tooltip-placement-top,
+    &[class*='placement-top'] {
+        .ant-tooltip-arrow::after {
+            border-top: none;
+            border-bottom-color: $text-primary !important;
+        }
+    }
+
+    // 下方 tooltip - 箭头向上
+    &.ant-tooltip-placement-bottom,
+    &[class*='placement-bottom'] {
+        .ant-tooltip-arrow::after {
+            border-bottom: none;
+            border-top-color: $text-primary !important;
+        }
+    }
+
+    // 左侧 tooltip - 箭头向右
+    &.ant-tooltip-placement-left,
+    &[class*='placement-left'] {
+        .ant-tooltip-arrow::after {
+            border-left: none;
+            border-right-color: $text-primary !important;
+        }
+    }
+
+    // 右侧 tooltip - 箭头向左
+    &.ant-tooltip-placement-right,
+    &[class*='placement-right'] {
+        .ant-tooltip-arrow::after {
+            border-right: none;
+            border-left-color: $text-primary !important;
+        }
+    }
+
+    .ant-tooltip-inner {
+        border-radius: $radius-md !important;
+        background: $text-primary !important;
+        padding: $spacing-2 $spacing-3 !important;
+        font-size: $font-sm !important;
+        color: $bg-secondary !important;
+    }
+}
+
+// 表单
+.ant-form-item-label > label {
+    font-weight: $font-weight-medium;
+    color: $text-primary;
+}
+
+// 单选框和复选框
+.ant-radio-wrapper,
+.ant-checkbox-wrapper {
+    font-size: $font-base;
+    color: $text-primary;
+}
+
+.ant-radio-inner,
+.ant-checkbox-inner {
+    border-radius: $radius-sm !important;
+}
+
+// 步骤条
+.ant-steps {
+    .ant-steps-item-icon {
+        border-radius: $radius-full !important;
+    }
+
+    .ant-steps-item-title {
+        font-weight: $font-weight-medium;
+    }
+}
+
+// 日期选择器
+.ant-picker {
+    border-radius: $radius-lg !important;
+
+    &:hover,
     &:focus {
-        background: $primary-color;
-        border-color: $primary-color;
-        color: #ffffff;
-        box-shadow: 0 0 0 2px rgba($primary-color, 0.2);
+        border-color: $primary-color !important;
     }
-    
-    &:disabled {
-        background: $bg-tertiary;
+
+    &.ant-picker-focused {
+        border-color: $primary-color !important;
+        box-shadow: 0 0 0 2px rgba($primary-color, 0.1) !important;
+    }
+}
+
+.ant-picker-panel-container {
+    border-radius: $radius-lg !important;
+}
+
+// 上传组件
+.ant-upload {
+    border-radius: $radius-lg !important;
+
+    &.ant-upload-drag {
+        border-radius: $radius-xl !important;
         border-color: $border-base;
-        color: $text-disabled;
-        box-shadow: none;
-        transform: none;
+
+        &:hover {
+            border-color: $primary-color !important;
+        }
+    }
+}
+
+// 列表
+.ant-list {
+    .ant-list-item {
+        border-radius: $radius-lg;
+        padding: $spacing-3 $spacing-4;
+
+        &:hover {
+            background: $bg-hover;
+        }
     }
 }
 
+// 分割线
+.ant-divider {
+    border-color: $border-light;
+    margin: $spacing-4 0;
+}
+
 // ==================== 排序按钮组 ====================
 .sort-buttons {
     border: 1px solid $border-base;
@@ -275,7 +664,7 @@ ul li {
 .filter-btn {
     width: $search-height;
     height: $search-height;
-    border: 1px solid rgba(0, 122, 153, 0.6);
+    border: 1px solid rgba($primary-light, 0.6);
     background: $icon-bg-blue;
     border-radius: $radius-xl;
     display: flex;
@@ -283,7 +672,7 @@ ul li {
     justify-content: center;
     cursor: pointer;
     transition: $transition-base;
-    
+
     .iconify {
         font-size: $icon-lg;
         color: $primary-color;
@@ -408,20 +797,20 @@ ul li {
             gap: $spacing-2;
             padding: $spacing-2 $spacing-4;
             background: $primary-color;
-            color: #fff;
+            color: #ffffff;
             border: none;
             border-radius: $radius-lg;
             font-size: $font-md;
             font-weight: $font-weight-medium;
             cursor: pointer;
             transition: $transition-base;
-            
+
             &:hover {
                 background: $primary-light;
                 transform: translateY(-$spacing-1);
                 box-shadow: $shadow-md;
             }
-            
+
             .iconify {
                 font-size: $icon-xl;
             }
@@ -489,20 +878,20 @@ ul li {
         gap: $spacing-2;
         padding: $spacing-2 $spacing-4;
         background: $primary-color;
-        color: #fff;
+        color: #ffffff;
         border: none;
         border-radius: $radius-lg;
         font-size: $font-md;
         font-weight: $font-weight-medium;
         cursor: pointer;
         transition: $transition-base;
-        
+
         &:hover {
             background: $primary-light;
             transform: translateY(-$spacing-1);
             box-shadow: $shadow-md;
         }
-        
+
         .iconify {
             font-size: $icon-xl;
         }
@@ -564,9 +953,9 @@ ul li {
             &.ant-pagination-item-active {
                 background: $primary-color;
                 border-color: $primary-color;
-                
+
                 a {
-                    color: #fff;
+                    color: #ffffff;
                 }
             }
         }

+ 56 - 66
jk-rag-platform/src/styles/variables.scss

@@ -5,45 +5,36 @@
 
 // ==================== 主题变量 ====================
 
-:root {
-    --sidebar-bg: #ffffff;
-    --header-bg: #ffffff;
-    --header-text-color: #374151;
-}
-
-html[data-theme='dark'] {
-    --sidebar-bg: #1f2d3d;
-    --header-bg: #1f2d3d;
-    --header-text-color: #ffffff;
-}
-
-html[data-theme='light'] {
-    --sidebar-bg: #ffffff;
-    --header-bg: #ffffff;
-    --header-text-color: #374151;
-}
+// 背景色
+$bg-primary: #F9FAFB;
+$bg-secondary: #FFFFFF;
+$bg-tertiary: #F3F4F6;
+$bg-hover: #F9FAFB;
+$bg-active: rgba(0, 93, 128, 0.1);
 
-// Less 变量别名
-$sidebar-bg: var(--sidebar-bg);
-$header-bg: var(--header-bg);
-$header-text-color: var(--header-text-color);
+// 文字色
+$text-primary: #1F2937;
+$text-secondary: #6B7280;
+$text-hint: #9CA3AF;
+$text-disabled: #D1D5DB;
 
-// 按钮选中/强调色
-html[data-theme='dark'] {
-    --btn-selected-bg: #005D80;
-    --btn-selected-color: #fff;
-}
+// 边框色
+$border-light: #F3F4F6;
+$border-base: #E5E7EB;
+$border-dark: #D1D5DB;
 
-html[data-theme='light'] {
-    --btn-selected-bg: #005D80;
-    --btn-selected-color: #fff;
-}
+// 组件背景
+$sidebar-bg: #ffffff;
+$header-bg: #ffffff;
+$header-text-color: #374151;
 
-$btn-selected-bg: var(--btn-selected-bg);
-$btn-selected-color: var(--btn-selected-color);
+// 按钮选中色
+$btn-selected-bg: #005D80;
+$btn-selected-color: #fff;
 
 
 // ===== 色彩系统(v3.2 更新为企业品牌色)=====
+// 注意:主色调和功能性颜色不使用 CSS 变量,因为它们在暗黑模式下保持不变
 
 // 主色调 - 企业蓝色系(基于 favicon #005D80)
 // 对比度测试:#005D80 on #FFFFFF = 8.02:1 ✅ WCAG AAA
@@ -82,23 +73,32 @@ $chat-primary-start: #00A0C7;   // Chat 渐变起点(青)
 $chat-primary-end: #08A84C;     // Chat 渐变终点(绿)
 $chat-accent: #059669;          // Chat 强调色(加深绿,文字可用)
 
-// 中性色 - 文字
-$text-primary: #1F2937;
-$text-secondary: #6B7280;
-$text-hint: #9CA3AF;
-$text-disabled: #D1D5DB;
-
-// 中性色 - 背景
-$bg-primary: #F9FAFB;
-$bg-secondary: #FFFFFF;
-$bg-tertiary: #F3F4F6;
-$bg-hover: #F9FAFB;
-$bg-active: rgba(0, 93, 128, 0.1);  // 使用新主色的 10% 透明度
+// 标签颜色(明亮主题)
+$tag-bg-slate: #F1F5F9;
+$tag-text-slate: #64748B;
+$tag-bg-blue: #E6F7FA;
+$tag-text-blue: #005D80;
+$tag-bg-indigo: #E0E7FF;
+$tag-text-indigo: #4338CA;
+$tag-bg-teal: #CCFBF1;
+$tag-text-teal: #0D9488;
+$tag-bg-purple: #F3E8FF;
+$tag-text-purple: #7E22CE;
+$tag-bg-rose: #FFE4E6;
+$tag-text-rose: #E11D48;
+$tag-bg-cyan: #CFFAFE;
+$tag-text-cyan: #0891B2;
+$tag-bg-amber: #FEF3C7;
+$tag-text-amber: #B45309;
 
-// 中性色 - 边框
-$border-light: #F3F4F6;
-$border-base: #E5E7EB;
-$border-dark: #D1D5DB;
+// 图标背景色
+$icon-bg-blue: #EFF6FF;
+$icon-bg-indigo: #EEF2FF;
+$icon-bg-teal: #F0FDFA;
+$icon-bg-purple: #FAF5FF;
+$icon-bg-rose: #FFF1F2;
+$icon-bg-cyan: #ECFEFF;
+$icon-bg-amber: #FFFBEB;
 
 // ===== 间距系统(4px 基准)=====
 
@@ -108,7 +108,9 @@ $spacing-3: 12px;
 $spacing-4: 16px;
 $spacing-5: 20px;
 $spacing-6: 24px;
+$spacing-7: 28px;
 $spacing-8: 32px;
+$spacing-9: 36px;
 $spacing-10: 40px;
 $spacing-12: 48px;
 $spacing-16: 64px;
@@ -293,24 +295,6 @@ $icon-bg-rose: #FFF1F2;
 $icon-bg-cyan: #ECFEFF;
 $icon-bg-amber: #FFFBEB;
 
-// 标签颜色
-$tag-bg-slate: #F1F5F9;
-$tag-text-slate: #64748B;
-$tag-bg-blue: #E6F7FA;         // 更新为企业蓝浅色
-$tag-text-blue: #005D80;       // 更新为企业蓝色
-$tag-bg-indigo: #E0E7FF;
-$tag-text-indigo: #4338CA;
-$tag-bg-teal: #CCFBF1;
-$tag-text-teal: #0D9488;
-$tag-bg-purple: #F3E8FF;
-$tag-text-purple: #7E22CE;
-$tag-bg-rose: #FFE4E6;
-$tag-text-rose: #E11D48;
-$tag-bg-cyan: #CFFAFE;
-$tag-text-cyan: #0891B2;
-$tag-bg-amber: #FEF3C7;
-$tag-text-amber: #B45309;
-
 // ===== 混合宏定义 =====
 
 // 文字截断
@@ -421,6 +405,12 @@ $font-size-md: $font-md;
 $font-size-lg: $font-lg;
 $font-size-xl: $font-xl;
 
+// 字重别名(兼容简写)
+$font-normal: $font-weight-normal;
+$font-medium: $font-weight-medium;
+$font-semibold: $font-weight-semibold;
+$font-bold: $font-weight-bold;
+
 // 圆角别名
 $border-radius-base: $radius-md;
 $border-radius-sm: $radius-sm;

+ 1 - 1
jk-rag-platform/vite.config.ts

@@ -12,7 +12,7 @@ export default defineConfig(({ mode, command }) => {
         scss: {
           charset: false,
           // 仅自动导入变量文件,不导入整个 global.scss
-          additionalData: '@import "@/styles/variables.scss";',
+          additionalData: '@use "@/styles/variables.scss" as *;',
         }
       }
     },

BIN
jk-rag-platform/开发计划清单.xlsx