Ver Fonte

feat: 更新 .claude-rules.md,添加修改功能模块前强制提交 git 的规则

Ryuiso há 1 mês atrás
pai
commit
a39b059565
26 ficheiros alterados com 960 adições e 1271 exclusões
  1. 309 200
      jk-rag-platform/.claude-rules.md
  2. 8 1
      jk-rag-platform/.claude/settings.local.json
  3. BIN
      jk-rag-platform/e1.png
  4. 1 0
      jk-rag-platform/package.json
  5. 1 1
      jk-rag-platform/src/components/404/style.scss
  6. 27 23
      jk-rag-platform/src/components/common/AppCard/index.tsx
  7. 3 3
      jk-rag-platform/src/components/common/FilterDrawer/index.scss
  8. 2 4
      jk-rag-platform/src/components/common/GuideTips/index.tsx
  9. 31 36
      jk-rag-platform/src/components/common/HeroBanner/index.scss
  10. 2 1
      jk-rag-platform/src/components/common/HeroBanner/index.tsx
  11. 11 1
      jk-rag-platform/src/components/common/StatsGrid/index.tsx
  12. 2 1
      jk-rag-platform/src/pages/appCenter/appPlazaList/index.tsx
  13. 2 1
      jk-rag-platform/src/pages/appCenter/categoryApps/index.tsx
  14. 39 35
      jk-rag-platform/src/pages/knowledgeLib/detail/components/style.scss
  15. 1 1
      jk-rag-platform/src/pages/knowledgeLib/detail/style.scss
  16. 7 6
      jk-rag-platform/src/pages/knowledgeLib/list/KnowledgeDrawer.tsx
  17. 4 12
      jk-rag-platform/src/pages/knowledgeLib/list/index.tsx
  18. 6 11
      jk-rag-platform/src/pages/layout/components/Header.tsx
  19. 49 29
      jk-rag-platform/src/pages/layout/components/Sidebar.tsx
  20. 30 30
      jk-rag-platform/src/pages/questionAnswer/form/DrawerForm.scss
  21. 3 2
      jk-rag-platform/src/pages/questionAnswer/form/Step1Drawer.tsx
  22. 12 12
      jk-rag-platform/src/pages/questionAnswer/form/VipSelector.scss
  23. 4 3
      jk-rag-platform/src/pages/questionAnswer/form/VipSelector.tsx
  24. 1 1
      jk-rag-platform/src/pages/questionAnswer/form/style.scss
  25. 397 857
      jk-rag-platform/src/pages/system/audit/components/style.scss
  26. 8 0
      jk-rag-platform/src/styles/variables.scss

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

@@ -1,265 +1,374 @@
 # Claude Project Rules - jk-rag-platform
 # 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. 全局变量优先原则
 ### 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. 间距控制规范
 ### 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 数据规范
 ## Mock 数据规范
 
 
 ### 1. Mock 数据位置
 ### 1. Mock 数据位置
+
 - 主文件:`src/mock/index.ts`
 - 主文件:`src/mock/index.ts`
 - API 特定 Mock: `src/mock/{apiName}.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
 ```tsx
 <div className="page-container">
 <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>
 </div>
 ```
 ```
 
 
-### 2. 卡片网格页结构
-```tsx
+### 3. 卡片网格页结构
+
+```text
 <div className="page-container">
 <div className="page-container">
     <div className="list-header">...</div>
     <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>
 </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 操作规范
 ## Git 操作规范
 
 
 ### 1. 提交前检查
 ### 1. 提交前检查
+
 - 确认所有必要的文件已存在或已删除
 - 确认所有必要的文件已存在或已删除
 - 避免误删重要组件文件
 - 避免误删重要组件文件
 - 备份关键配置文件
 - 备份关键配置文件
 
 
 ### 2. 分支管理
 ### 2. 分支管理
+
 - 主分支:`master`
 - 主分支:`master`
 - 开发分支:当前分支 (如 `zy`)
 - 开发分支:当前分支 (如 `zy`)
 - 不要直接 push 到 master
 - 不要直接 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 - 紧急且重要
+
+- [ ] **补充核心 API Mock 数据**
+  - [ ] 登录 API (`/auth/login`, `/auth/code`)
+  - [ ] 首页统计 API (`/deepseek/overview/topData`)
+  - [ ] 应用列表 API (`/bigmodel/api/getApplicationList`)
+  - [ ] 审核列表 API (`/deepseek/api/app/audit/list`)
+
+- [ ] **完成审核页面实现**
+  - 当前使用 `audit/index.placeholder.tsx`
+  - 需要实现完整的审核功能
+
+### P1 - 重要不紧急
+
+- [ ] **统一样式变量使用**
+  - [ ] 检查所有 `.scss` 文件是否导入 `variables.scss`
+  - [ ] 移除硬编码的颜色值和间距值
+  - [ ] 确保使用 `$spacing-*` 系列变量
+
+- [ ] **补充应用管理 API Mock**
+  - [ ] 应用详情 API
+  - [ ] 创建应用 API
+  - [ ] 更新应用 API
+  - [ ] 删除应用 API
+
+- [ ] **完善文档**
+  - [ ] 更新 README.md
+  - [ ] 补充 API 接口文档
+
+### P2 - 可选优化
+
+- [ ] 响应式布局优化
+- [ ] 主题切换功能 (dark/light)
+- [ ] 性能优化 (代码分割、图片压缩)
+
+---
 
 
 ## 技术栈版本
 ## 技术栈版本
+
 - React: 18.2.0
 - React: 18.2.0
 - TypeScript: 5.7.0
 - TypeScript: 5.7.0
 - Vite: 7.1.11
 - Vite: 7.1.11
 - Ant Design: 5.23.0
 - Ant Design: 5.23.0
 - Zustand: 5.0.12
 - Zustand: 5.0.12
-- Less: 4.2.0
+- React Router: 7.1.0
+- TailwindCSS: 4.1.17
+- SCSS (Sass): 1.98.0
+
+---
 
 
 ## 启动命令
 ## 启动命令
+
 ```bash
 ```bash
-npm run start:demo      # Demo 模式(静态)
+# 开发
+npm run start:demo      # Demo 模式(静态 + Mock)
 npm run start           # 开发模式(带 API)
 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

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

@@ -73,7 +73,14 @@
       "Bash(done)",
       "Bash(done)",
       "Bash(grep:*)",
       "Bash(grep:*)",
       "Bash(curl -s http://localhost:3100)",
       "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)"
     ]
     ]
   }
   }
 }
 }

BIN
jk-rag-platform/e1.png


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

@@ -25,6 +25,7 @@
     "axios": "^1.13.5",
     "axios": "^1.13.5",
     "crypto-js": "^4.2.0",
     "crypto-js": "^4.2.0",
     "dayjs": "^1.11.0",
     "dayjs": "^1.11.0",
+    "iconoir-react": "^7.11.0",
     "jsencrypt": "^3.5.4",
     "jsencrypt": "^3.5.4",
     "mammoth": "^1.11.0",
     "mammoth": "^1.11.0",
     "markdown-it": "^14.1.0",
     "markdown-it": "^14.1.0",

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

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

+ 27 - 23
jk-rag-platform/src/components/common/AppCard/index.tsx

@@ -1,5 +1,6 @@
 import * as React from 'react';
 import * as React from 'react';
 import { Dropdown, MenuProps, Button } from 'antd';
 import { Dropdown, MenuProps, Button } from 'antd';
+import { CodeBracketsSquare, EditPencil, Trash, ShareIos, Star, BrightStar, Eye, Heart, Calendar, BadgeCheck, Building, Menu, ArrowRight } from 'iconoir-react';
 import './index.scss';
 import './index.scss';
 
 
 export interface AppCardProps {
 export interface AppCardProps {
@@ -142,25 +143,25 @@ const AppCard: React.FC<AppCardProps> = (props) => {
             items.push({
             items.push({
                 key: 'api',
                 key: 'api',
                 label: 'API 调用',
                 label: 'API 调用',
-                icon: <span className="iconify" data-icon="solar:code-square-linear"></span>,
+                icon: <CodeBracketsSquare width="16" height="16" />,
                 onClick: () => onApi(),
                 onClick: () => onApi(),
             });
             });
         }
         }
-        
+
         if (isCreator && onEdit) {
         if (isCreator && onEdit) {
             items.push({
             items.push({
                 key: 'edit',
                 key: 'edit',
                 label: '编辑',
                 label: '编辑',
-                icon: <span className="iconify" data-icon="solar:pen-linear"></span>,
+                icon: <EditPencil width="16" height="16" />,
                 onClick: () => onEdit(),
                 onClick: () => onEdit(),
             });
             });
         }
         }
-        
+
         if (isCreator && onDelete) {
         if (isCreator && onDelete) {
             items.push({
             items.push({
                 key: 'delete',
                 key: 'delete',
                 label: '删除',
                 label: '删除',
-                icon: <span className="iconify" data-icon="solar:trash-bin-linear"></span>,
+                icon: <Trash width="16" height="16" />,
                 danger: true,
                 danger: true,
                 onClick: () => onDelete(),
                 onClick: () => onDelete(),
             });
             });
@@ -210,7 +211,7 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                         }}
                         }}
                         title='分享'
                         title='分享'
                     >
                     >
-                        <span className='iconify' data-icon='solar:share-linear'></span>
+                        <ShareIos width="18" height="18" />
                     </button>
                     </button>
                     <button
                     <button
                         className='card-action-btn'
                         className='card-action-btn'
@@ -221,9 +222,9 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                         title={isCollect ? '取消收藏' : '收藏'}
                         title={isCollect ? '取消收藏' : '收藏'}
                     >
                     >
                         {isCollect ? (
                         {isCollect ? (
-                            <span className='iconify' data-icon='solar:star-bold' style={{ color: '#F5E663' }}></span>
+                            <BrightStar width="18" height="18" style={{ color: '#F5E663' }} />
                         ) : (
                         ) : (
-                            <span className='iconify' data-icon='solar:star-linear'></span>
+                            <Star width="18" height="18" />
                         )}
                         )}
                     </button>
                     </button>
                 </div>
                 </div>
@@ -235,7 +236,10 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                     {iconImage ? (
                     {iconImage ? (
                         <img alt={name} className='card-icon' src={iconImage} />
                         <img alt={name} className='card-icon' src={iconImage} />
                     ) : icon ? (
                     ) : icon ? (
-                        <span className='iconify' data-icon={icon}></span>
+                        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: 24, height: 24 }}>
+                            {/* 动态 icon 支持 - 如果传入的是 iconoir 组件名称则渲染,否则显示占位 */}
+                            <BrightStar width="24" height="24" />
+                        </div>
                     ) : null}
                     ) : null}
                 </div>
                 </div>
 
 
@@ -275,13 +279,13 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                     <div className='card-meta-left'>
                     <div className='card-meta-left'>
                         {showViewCount && viewCount !== undefined && (
                         {showViewCount && viewCount !== undefined && (
                             <span className='card-meta-item'>
                             <span className='card-meta-item'>
-                                <span className='iconify' data-icon='solar:eye-linear'></span>
+                                <Eye width="14" height="14" />
                                 <span>{viewCount}</span>
                                 <span>{viewCount}</span>
                             </span>
                             </span>
                         )}
                         )}
                         {showFavoriteCount && favoriteCount !== undefined && (
                         {showFavoriteCount && favoriteCount !== undefined && (
                             <span className='card-meta-item'>
                             <span className='card-meta-item'>
-                                <span className='iconify' data-icon='solar:heart-linear'></span>
+                                <Heart width="14" height="14" />
                                 <span>{favoriteCount}</span>
                                 <span>{favoriteCount}</span>
                             </span>
                             </span>
                         )}
                         )}
@@ -289,7 +293,7 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                     {showCreateTime && createTime && (
                     {showCreateTime && createTime && (
                         <div className='card-meta-right'>
                         <div className='card-meta-right'>
                             <span className='card-meta-item'>
                             <span className='card-meta-item'>
-                                <span className='iconify' data-icon='solar:calendar-linear'></span>
+                                <Calendar width="14" height="14" />
                                 <span>{createTime}</span>
                                 <span>{createTime}</span>
                             </span>
                             </span>
                         </div>
                         </div>
@@ -302,13 +306,13 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                 <div className='card-footer-info'>
                 <div className='card-footer-info'>
                     {certification && (
                     {certification && (
                         <div className='card-certification'>
                         <div className='card-certification'>
-                            <span className='iconify' data-icon='solar:verified-check-bold'></span>
+                            <BadgeCheck width="14" height="14" />
                             <span>{certification}</span>
                             <span>{certification}</span>
                         </div>
                         </div>
                     )}
                     )}
                     {showDepartment && department && (
                     {showDepartment && department && (
                         <div className='card-department'>
                         <div className='card-department'>
-                            <span className='iconify' data-icon='solar:buildings-bold'></span>
+                            <Building width="14" height="14" />
                             <span>{department}</span>
                             <span>{department}</span>
                         </div>
                         </div>
                     )}
                     )}
@@ -328,24 +332,24 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                 <div className='card-hover-actions'>
                 <div className='card-hover-actions'>
                     {/* 创建者显示【更多操作】,非创建者显示【API 调用】 */}
                     {/* 创建者显示【更多操作】,非创建者显示【API 调用】 */}
                     {isCreator ? (
                     {isCreator ? (
-                        <Dropdown 
-                            menu={{ items: operationItems }} 
+                        <Dropdown
+                            menu={{ items: operationItems }}
                             trigger={['click']}
                             trigger={['click']}
                             placement='topLeft'
                             placement='topLeft'
                             className='card-operation-dropdown'
                             className='card-operation-dropdown'
                         >
                         >
-                            <Button 
+                            <Button
                                 className='card-operation-btn'
                                 className='card-operation-btn'
-                                icon={<span className='iconify' data-icon='solar:menu-dots-linear'></span>}
+                                icon={<Menu width="18" height="18" />}
                                 size='large'
                                 size='large'
                             >
                             >
                                 更多操作
                                 更多操作
                             </Button>
                             </Button>
                         </Dropdown>
                         </Dropdown>
                     ) : (
                     ) : (
-                        <Button 
+                        <Button
                             className='card-operation-btn'
                             className='card-operation-btn'
-                            icon={<span className='iconify' data-icon='solar:code-square-linear'></span>}
+                            icon={<CodeBracketsSquare width="18" height="18" />}
                             size='large'
                             size='large'
                             onClick={(e) => {
                             onClick={(e) => {
                                 e.stopPropagation();
                                 e.stopPropagation();
@@ -355,10 +359,10 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                             API 调用
                             API 调用
                         </Button>
                         </Button>
                     )}
                     )}
-                    
-                    <Button 
+
+                    <Button
                         className='card-use-btn'
                         className='card-use-btn'
-                        icon={<span className='iconify' data-icon='solar:arrow-right-linear'></span>}
+                        icon={<ArrowRight width="18" height="18" />}
                         size='large'
                         size='large'
                         onClick={(e) => {
                         onClick={(e) => {
                             e.stopPropagation();
                             e.stopPropagation();

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

@@ -4,7 +4,7 @@
     }
     }
 
 
     .filter-section {
     .filter-section {
-        margin-bottom: $spacing-4;  // 16px - 紧凑间距
+        margin-bottom: $spacing-md;  // 紧凑间距
 
 
         &:last-child {
         &:last-child {
             margin-bottom: 0;
             margin-bottom: 0;
@@ -15,12 +15,12 @@
         font-size: $font-lg;
         font-size: $font-lg;
         font-weight: $font-weight-semibold;
         font-weight: $font-weight-semibold;
         color: $text-primary;
         color: $text-primary;
-        margin-bottom: $spacing-3;
+        margin-bottom: $spacing-md;
     }
     }
 
 
     .filter-tags {
     .filter-tags {
         display: flex;
         display: flex;
         flex-wrap: wrap;
         flex-wrap: wrap;
-        gap: 8px;
+        gap: $spacing-sm;  // 8px
     }
     }
 }
 }

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

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

+ 31 - 36
jk-rag-platform/src/components/common/HeroBanner/index.scss

@@ -3,7 +3,7 @@
 .hero-banner {
 .hero-banner {
     position: relative;
     position: relative;
     width: 100%;
     width: 100%;
-    height: 150px;
+    height: $font-3xl * 9;  // 150px
     border-radius: $radius-2xl;
     border-radius: $radius-2xl;
     overflow: hidden;
     overflow: hidden;
     margin-bottom: $spacing-10;
     margin-bottom: $spacing-10;
@@ -26,17 +26,12 @@
 }
 }
 
 
 .hero-banner-content {
 .hero-banner-content {
-    max-width: 800px;
+    max-width: $spacing-10 * 7.5;  // 800px
     display: flex;
     display: flex;
     align-items: center;
     align-items: center;
     gap: $spacing-5;
     gap: $spacing-5;
 }
 }
 
 
-.hero-banner-text {
-    flex: 1;
-    min-width: 0;
-}
-
 .hero-banner-badge {
 .hero-banner-badge {
     display: inline-flex;
     display: inline-flex;
     align-items: center;
     align-items: center;
@@ -56,7 +51,7 @@
     span:last-child {
     span:last-child {
         font-size: 10px;
         font-size: 10px;
         color: #DBEAFE;
         color: #DBEAFE;
-        font-weight: 600;
+        font-weight: $font-weight-semibold;
         font-style: italic;
         font-style: italic;
     }
     }
 }
 }
@@ -75,26 +70,26 @@
     line-height: 1.4;
     line-height: 1.4;
     display: flex;
     display: flex;
     flex-direction: column;
     flex-direction: column;
-    gap: 2px;
+    gap: $spacing-1;
 }
 }
 
 
 .hero-banner-actions {
 .hero-banner-actions {
     flex-shrink: 0;
     flex-shrink: 0;
     display: flex;
     display: flex;
-    gap: 8px;
+    gap: $spacing-2;
 }
 }
 
 
 .hero-banner-btn {
 .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;
     border: none;
     cursor: pointer;
     cursor: pointer;
     transition: all 0.2s ease;
     transition: all 0.2s ease;
     display: inline-flex;
     display: inline-flex;
     align-items: center;
     align-items: center;
-    gap: 4px;
+    gap: $spacing-1;
     white-space: nowrap;
     white-space: nowrap;
     box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
     box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
 
 
@@ -116,7 +111,7 @@
         border: 1px solid $border-base;
         border: 1px solid $border-base;
         color: $text-primary;
         color: $text-primary;
         backdrop-filter: blur(4px);
         backdrop-filter: blur(4px);
-        font-weight: 600;
+        font-weight: $font-weight-semibold;
 
 
         &:hover {
         &:hover {
             background: $bg-primary;
             background: $bg-primary;
@@ -125,46 +120,46 @@
     }
     }
 }
 }
 
 
-@media (max-width: 1024px) {
+@media (max-width: $screen-lg) {
     .hero-banner {
     .hero-banner {
-        height: 150px;
+        height: $font-3xl * 9;  // 150px
     }
     }
 
 
     .hero-banner-overlay {
     .hero-banner-overlay {
-        padding: 0 20px;
+        padding: 0 $spacing-lg;
     }
     }
 
 
     .hero-banner-content {
     .hero-banner-content {
-        gap: 16px;
+        gap: $spacing-md;
     }
     }
 
 
     .hero-banner-title {
     .hero-banner-title {
-        font-size: 16px;
+        font-size: $font-2xl;  // 16px
     }
     }
 
 
     .hero-banner-description {
     .hero-banner-description {
-        font-size: 11px;
+        font-size: $font-xs;  // 11px
     }
     }
 
 
     .hero-banner-btn {
     .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 {
     .hero-banner {
-        height: 180px;
+        height: $font-3xl * 9.6;  // 180px
     }
     }
 
 
     .hero-banner-overlay {
     .hero-banner-overlay {
-        padding: 0 16px;
+        padding: 0 $spacing-md;
     }
     }
 
 
     .hero-banner-content {
     .hero-banner-content {
         flex-direction: column;
         flex-direction: column;
         align-items: flex-start;
         align-items: flex-start;
-        gap: 12px;
+        gap: $spacing-sm;
     }
     }
 
 
     .hero-banner-actions {
     .hero-banner-actions {
@@ -177,10 +172,10 @@
     }
     }
 
 
     .hero-banner-badge {
     .hero-banner-badge {
-        padding: 2px 8px;
+        padding: $spacing-1 $spacing-sm;
 
 
         .iconify {
         .iconify {
-            font-size: 11px;
+            font-size: $font-xs;  // 11px
         }
         }
 
 
         span:last-child {
         span:last-child {
@@ -189,17 +184,17 @@
     }
     }
 
 
     .hero-banner-title {
     .hero-banner-title {
-        font-size: 16px;
-        margin-bottom: 4px;
+        font-size: $font-2xl;  // 16px
+        margin-bottom: $spacing-1;  // 4px
     }
     }
 
 
     .hero-banner-description {
     .hero-banner-description {
-        font-size: 11px;
-        gap: 2px;
+        font-size: $font-xs;  // 11px
+        gap: $spacing-1;  // 2px
     }
     }
 
 
     .hero-banner-btn {
     .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 * as React from 'react';
+import { BrightStar } from 'iconoir-react';
 import './index.scss';
 import './index.scss';
 
 
 const HeroBanner: React.FC = () => {
 const HeroBanner: React.FC = () => {
@@ -13,7 +14,7 @@ const HeroBanner: React.FC = () => {
                 <div className='hero-banner-content'>
                 <div className='hero-banner-content'>
                     <div className='hero-banner-text'>
                     <div className='hero-banner-text'>
                         <div className='hero-banner-badge'>
                         <div className='hero-banner-badge'>
-                            <span className='iconify' data-icon='solar:star-bold'></span>
+                            <BrightStar width="16" height="16" />
                             <span>Featured Application</span>
                             <span>Featured Application</span>
                         </div>
                         </div>
                         <h2 className='hero-banner-title'>广告占位</h2>
                         <h2 className='hero-banner-title'>广告占位</h2>

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

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

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

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

+ 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;
-}
+// 覆盖 markdown 渲染出来的样式 - 使用全局变量
+@import '@/styles/variables.scss';
 
 
-.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 {
 .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 {
 .ant-typography {
     h1 {
     h1 {
-        font-size: @font-4xl;   // 20px - 使用全局变量
+        font-size: $font-4xl;   // 20px - 使用全局变量
         color: $text-primary;   // 使用全局变量
         color: $text-primary;   // 使用全局变量
         margin: 2px 0;
         margin: 2px 0;
     }
     }

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

@@ -1,5 +1,6 @@
 import * as React from 'react';
 import * as React from 'react';
 import { Drawer, Form, Input, Select, Button, Space, Divider, message, Radio } from 'antd';
 import { Drawer, Form, Input, Select, Button, Space, Divider, message, Radio } from 'antd';
+import { Database, Scissors, Text, AlignLeft } from 'iconoir-react';
 import './KnowledgeDrawer.scss';
 import './KnowledgeDrawer.scss';
 
 
 interface KnowledgeDrawerProps {
 interface KnowledgeDrawerProps {
@@ -60,7 +61,7 @@ const KnowledgeDrawer: React.FC<KnowledgeDrawerProps> = ({
                 {/* 基本信息 */}
                 {/* 基本信息 */}
                 <div className='icon-select-section'>
                 <div className='icon-select-section'>
                     <div className='section-icon'>
                     <div className='section-icon'>
-                        <span className='iconify' data-icon='solar:database-linear'></span>
+                        <Database width="24" height="24" />
                     </div>
                     </div>
                     <div className='section-info'>
                     <div className='section-info'>
                         <div className='section-title'>基本信息</div>
                         <div className='section-title'>基本信息</div>
@@ -110,7 +111,7 @@ const KnowledgeDrawer: React.FC<KnowledgeDrawerProps> = ({
 
 
                 <div className='icon-select-section'>
                 <div className='icon-select-section'>
                     <div className='section-icon'>
                     <div className='section-icon'>
-                        <span className='iconify' data-icon='solar:scissors-linear'></span>
+                        <Scissors width="24" height="24" />
                     </div>
                     </div>
                     <div className='section-info'>
                     <div className='section-info'>
                         <div className='section-title'>切片设置</div>
                         <div className='section-title'>切片设置</div>
@@ -125,17 +126,17 @@ const KnowledgeDrawer: React.FC<KnowledgeDrawerProps> = ({
                         rules={[{ required: true, message: '请选择切片方式' }]}
                         rules={[{ required: true, message: '请选择切片方式' }]}
                         extra='选择文档的切片方式'
                         extra='选择文档的切片方式'
                     >
                     >
-                        <Radio.Group 
-                            buttonStyle="solid" 
+                        <Radio.Group
+                            buttonStyle="solid"
                             className='splitting-radio'
                             className='splitting-radio'
                             onChange={(e) => setSplittingType(e.target.value)}
                             onChange={(e) => setSplittingType(e.target.value)}
                         >
                         >
                             <Radio.Button value='1'>
                             <Radio.Button value='1'>
-                                <span className='iconify' data-icon='solar:text-block-linear' style={{ marginRight: 4 }}></span>
+                                <Text width="16" height="16" style={{ marginRight: 4 }} />
                                 按段落
                                 按段落
                             </Radio.Button>
                             </Radio.Button>
                             <Radio.Button value='2'>
                             <Radio.Button value='2'>
-                                <span className='iconify' data-icon='solar:text-align-left-linear' style={{ marginRight: 4 }}></span>
+                                <AlignLeft width="16" height="16" style={{ marginRight: 4 }} />
                                 按章节
                                 按章节
                             </Radio.Button>
                             </Radio.Button>
                         </Radio.Group>
                         </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 { useNavigate } from 'react-router-dom';
 import { Button, Table, TableColumnsType, TablePaginationConfig, Input, Space, Tabs, message, Tooltip, Dropdown, MenuProps } from 'antd';
 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 { PlusOutlined, SearchOutlined, EditFilled, FileWordFilled, FileMarkdownFilled, DeleteFilled, DownOutlined } from '@ant-design/icons';
+import { EditPencil, Download, Trash } from 'iconoir-react';
 import { GuideTips, FilterBar } from '@/components/common';
 import { GuideTips, FilterBar } from '@/components/common';
 import InfoModal from './components/InfoModal';
 import InfoModal from './components/InfoModal';
 import { useKnowledgeLibListStore } from './store';
 import { useKnowledgeLibListStore } from './store';
@@ -255,10 +256,7 @@ const KnowledgeLibList: React.FC = () => {
                                 onClick={() => onClickModify(record)}
                                 onClick={() => onClickModify(record)}
                                 className="action-btn"
                                 className="action-btn"
                             >
                             >
-                            <span
-                                className="iconify"
-                                data-icon="material-symbols:edit-rounded"
-                            />
+                                <EditPencil width="18" height="18" />
                             </Button>
                             </Button>
                         </Tooltip>
                         </Tooltip>
 
 
@@ -274,10 +272,7 @@ const KnowledgeLibList: React.FC = () => {
                                     size="large"
                                     size="large"
                                     className="action-btn"
                                     className="action-btn"
                                 >
                                 >
-                                    <span
-                                        className="iconify"
-                                        data-icon="solar:download-square-bold"
-                                    />
+                                    <Download width="18" height="18" />
                                 </Button>
                                 </Button>
                             </Tooltip>
                             </Tooltip>
                         </Dropdown>
                         </Dropdown>
@@ -291,10 +286,7 @@ const KnowledgeLibList: React.FC = () => {
                                 onClick={() => onClickDelete(record)}
                                 onClick={() => onClickDelete(record)}
                                 className="action-btn"
                                 className="action-btn"
                             >
                             >
-                            <span
-                                className="iconify"
-                                data-icon="solar:trash-bin-trash-bold"
-                            />
+                                <Trash width="18" height="18" />
                             </Button>
                             </Button>
                         </Tooltip>
                         </Tooltip>
                     </Space>
                     </Space>

+ 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 { Modal, Button, Tooltip } from 'antd';
 import { useNavigate } from 'react-router-dom';
 import { useNavigate } from 'react-router-dom';
 import { MenuFoldOutlined, MenuUnfoldOutlined, MessageOutlined } from '@ant-design/icons';
 import { MenuFoldOutlined, MenuUnfoldOutlined, MessageOutlined } from '@ant-design/icons';
+import { Bell, ArrowDown, UserSquare, Settings, LogOut } from 'iconoir-react';
 import LocalStorage from '@/LocalStorage';
 import LocalStorage from '@/LocalStorage';
 import { useLayoutStore } from '../store';
 import { useLayoutStore } from '../store';
 import './header.scss';
 import './header.scss';
@@ -141,10 +142,7 @@ const Header: React.FC<Props> = (props) => {
 
 
                     {/* 通知按钮 */}
                     {/* 通知按钮 */}
                     <button className='notification-btn'>
                     <button className='notification-btn'>
-                        <span
-                            className='iconify'
-                            data-icon='solar:bell-linear'
-                        ></span>
+                        <Bell width="20" height="20" />
                         <span className='notification-dot'></span>
                         <span className='notification-dot'></span>
                     </button>
                     </button>
 
 
@@ -164,10 +162,7 @@ const Header: React.FC<Props> = (props) => {
                                 <p className='user-name'>{userName}</p>
                                 <p className='user-name'>{userName}</p>
                                 <p className='user-dept'>部门信息</p>
                                 <p className='user-dept'>部门信息</p>
                             </div>
                             </div>
-                            <span
-                                className='iconify user-dropdown-icon'
-                                data-icon='solar:alt-arrow-down-linear'
-                            ></span>
+                            <ArrowDown width="16" height="16" className='user-dropdown-icon' />
                         </button>
                         </button>
 
 
                         {/* 下拉菜单 */}
                         {/* 下拉菜单 */}
@@ -179,19 +174,19 @@ const Header: React.FC<Props> = (props) => {
                                 </div>
                                 </div>
 
 
                                 <button className='user-dropdown-item'>
                                 <button className='user-dropdown-item'>
-                                    <span className='iconify' data-icon='solar:user-id-linear'></span>
+                                    <UserSquare width="16" height="16" />
                                     <span>个人中心</span>
                                     <span>个人中心</span>
                                 </button>
                                 </button>
 
 
                                 <button className='user-dropdown-item'>
                                 <button className='user-dropdown-item'>
-                                    <span className='iconify' data-icon='solar:settings-linear'></span>
+                                    <Settings width="16" height="16" />
                                     <span>账户设置</span>
                                     <span>账户设置</span>
                                 </button>
                                 </button>
 
 
                                 <div className='user-dropdown-item divider'></div>
                                 <div className='user-dropdown-item divider'></div>
 
 
                                 <button className='user-dropdown-item danger' onClick={handleLogout}>
                                 <button className='user-dropdown-item danger' onClick={handleLogout}>
-                                    <span className='iconify' data-icon='solar:logout-2-linear'></span>
+                                    <LogOut width="16" height="16" />
                                     <span>退出登录</span>
                                     <span>退出登录</span>
                                 </button>
                                 </button>
                             </div>
                             </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 { useNavigate, useLocation } from 'react-router-dom';
 import { useLayoutStore } from '../store';
 import { useLayoutStore } from '../store';
 import './sidebar.scss';
 import './sidebar.scss';
+import { BrightStar, Database, Key, ClipboardCheck, Book, BookStack, FolderPlus, PlusCircle } from 'iconoir-react';
 
 
 interface NavItem {
 interface NavItem {
     key: string;
     key: string;
@@ -10,6 +11,19 @@ interface NavItem {
     path: string;
     path: string;
 }
 }
 
 
+// icon 名称到 iconoir 组件的映射
+const iconMap: Record<string, React.ComponentType<any>> = {
+    'widget': BrightStar, // 临时用 BrightStar 替代
+    'book': Book,
+    'star': BrightStar,
+    'notebook': BookStack,
+    'gallery': FolderPlus,
+    'plus-circle': PlusCircle,
+    'database': Database,
+    'key': Key,
+    'clipboard-check': ClipboardCheck,
+};
+
 const Sidebar: React.FC = () => {
 const Sidebar: React.FC = () => {
     const navigate = useNavigate();
     const navigate = useNavigate();
     const location = useLocation();
     const location = useLocation();
@@ -17,19 +31,19 @@ const Sidebar: React.FC = () => {
 
 
     // 应用矩阵菜单
     // 应用矩阵菜单
     const appMenuItems: NavItem[] = [
     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[] = [
     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>
                 <div>
                     <h3 className='section-title'>应用矩阵</h3>
                     <h3 className='section-title'>应用矩阵</h3>
                     <nav className='nav-menu'>
                     <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] || BrightStar;
+                            return (
+                                <button
+                                    key={item.key}
+                                    className={`nav-item ${isActive(item.path, location.pathname, location.search, false) ? 'active' : ''}`}
+                                    onClick={() => handleNavClick(item.path)}
+                                >
+                                    <IconComponent width="18" height="18" />
+                                    <span>{item.label}</span>
+                                </button>
+                            );
+                        })}
                     </nav>
                     </nav>
                 </div>
                 </div>
 
 
@@ -82,16 +99,19 @@ const Sidebar: React.FC = () => {
                 <div>
                 <div>
                     <h3 className='section-title'>管理控制台</h3>
                     <h3 className='section-title'>管理控制台</h3>
                     <nav className='nav-menu'>
                     <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] || BrightStar;
+                            return (
+                                <button
+                                    key={item.key}
+                                    className={`nav-item ${isActive(item.path, location.pathname, location.search, true) ? 'active' : ''}`}
+                                    onClick={() => handleNavClick(item.path)}
+                                >
+                                    <IconComponent width="18" height="18" />
+                                    <span>{item.label}</span>
+                                </button>
+                            );
+                        })}
                     </nav>
                     </nav>
                 </div>
                 </div>
             </div>
             </div>

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

@@ -5,9 +5,9 @@
 
 
 .rag-drawer {
 .rag-drawer {
     .ant-drawer-header {
     .ant-drawer-header {
-        padding: $spacing-4 $spacing-6;
+        padding: $spacing-4 $spacing-lg;
         border-bottom: 1px solid $border-light;
         border-bottom: 1px solid $border-light;
-        
+
         .ant-drawer-title {
         .ant-drawer-title {
             font-size: $font-2xl;
             font-size: $font-2xl;
             font-weight: $font-weight-bold;
             font-weight: $font-weight-bold;
@@ -26,7 +26,7 @@
 
 
 .drawer-form-container {
 .drawer-form-container {
     height: 100%;
     height: 100%;
-    padding: $spacing-5;
+    padding: $spacing-lg;
     overflow-y: auto;
     overflow-y: auto;
 
 
     // 表单区域
     // 表单区域
@@ -38,18 +38,18 @@
     .icon-select-section {
     .icon-select-section {
         display: flex;
         display: flex;
         align-items: center;
         align-items: center;
-        gap: $spacing-6;
-        padding: $spacing-5;
+        gap: $spacing-xl;
+        padding: $spacing-lg;
         background: $bg-tertiary;
         background: $bg-tertiary;
         border-radius: $radius-xl;
         border-radius: $radius-xl;
-        margin-bottom: $spacing-4;  // 16px - 紧凑间距
+        margin-bottom: $spacing-md;
 
 
         .icon-preview-wrapper {
         .icon-preview-wrapper {
             flex-shrink: 0;
             flex-shrink: 0;
 
 
             .icon-preview-box {
             .icon-preview-box {
-                width: 80px;
-                height: 80px;
+                width: $font-3xl * 4;  // 80px
+                height: $font-3xl * 4;
                 border-radius: $radius-xl;
                 border-radius: $radius-xl;
                 display: flex;
                 display: flex;
                 align-items: center;
                 align-items: center;
@@ -68,7 +68,7 @@
             flex: 1;
             flex: 1;
             display: flex;
             display: flex;
             flex-direction: column;
             flex-direction: column;
-            gap: $spacing-3;
+            gap: $spacing-md;
 
 
             .color-label {
             .color-label {
                 font-size: $font-sm;
                 font-size: $font-sm;
@@ -79,8 +79,8 @@
 
 
     // 分割线
     // 分割线
     .section-divider {
     .section-divider {
-        margin: $spacing-4 0 $spacing-4 0;
-        
+        margin: $spacing-lg 0 $spacing-lg 0;
+
         &::before {
         &::before {
             content: '';
             content: '';
             display: inline-block;
             display: inline-block;
@@ -103,11 +103,11 @@
     .tags-info {
     .tags-info {
         border: 1px solid $border-base;
         border: 1px solid $border-base;
         border-radius: $radius-md;
         border-radius: $radius-md;
-        padding: $spacing-2 $spacing-3;
+        padding: $spacing-sm $spacing-lg;
         display: flex;
         display: flex;
         align-items: center;
         align-items: center;
         justify-content: space-between;
         justify-content: space-between;
-        gap: $spacing-3;
+        gap: $spacing-md;
         min-height: 46px;
         min-height: 46px;
         background: $bg-secondary;
         background: $bg-secondary;
 
 
@@ -137,18 +137,18 @@
 
 
     // 预设问题区域
     // 预设问题区域
     .preset-questions {
     .preset-questions {
-        margin-top: $spacing-4;
+        margin-top: $spacing-md;
 
 
         .questions-list {
         .questions-list {
             display: flex;
             display: flex;
             flex-direction: column;
             flex-direction: column;
-            gap: $spacing-3;
+            gap: $spacing-sm;
         }
         }
 
 
         .question-item {
         .question-item {
             display: flex;
             display: flex;
             align-items: center;
             align-items: center;
-            gap: $spacing-3;
+            gap: $spacing-md;
 
 
             label {
             label {
                 min-width: 70px;
                 min-width: 70px;
@@ -167,7 +167,7 @@
                 flex-shrink: 0;
                 flex-shrink: 0;
 
 
                 .question-icon {
                 .question-icon {
-                    font-size: 18px;
+                    font-size: $icon-lg;
                     cursor: pointer;
                     cursor: pointer;
                     transition: all 0.2s ease;
                     transition: all 0.2s ease;
 
 
@@ -175,7 +175,7 @@
                         color: $success-color;
                         color: $success-color;
 
 
                         &:hover {
                         &:hover {
-                            color: rgba(4, 120, 87, 0.9);
+                            color: $success-dark;
                             transform: scale(1.1);
                             transform: scale(1.1);
                         }
                         }
                     }
                     }
@@ -184,7 +184,7 @@
                         color: $error-color;
                         color: $error-color;
 
 
                         &:hover {
                         &:hover {
-                            color: rgba(185, 28, 28, 0.9);
+                            color: $error-dark;
                             transform: scale(1.1);
                             transform: scale(1.1);
                         }
                         }
                     }
                     }
@@ -198,7 +198,7 @@
 .drawer-form-container {
 .drawer-form-container {
     .ant-form {
     .ant-form {
         .ant-form-item {
         .ant-form-item {
-            margin-bottom: $spacing-4;  // 16px - 紧凑间距
+            margin-bottom: $spacing-md;
 
 
             .ant-form-item-label {
             .ant-form-item-label {
                 > label {
                 > label {
@@ -231,7 +231,7 @@
             .ant-input:focus,
             .ant-input:focus,
             .ant-input-affix-wrapper:focus-within {
             .ant-input-affix-wrapper:focus-within {
                 border-color: $primary-color;
                 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 {
     &::-webkit-scrollbar-thumb {
-        background: rgba(209, 213, 219, 0.5);
-        border-radius: 3px;
+        background: rgba($text-disabled, 0.5);
+        border-radius: $spacing-1;
 
 
         &:hover {
         &:hover {
-            background: rgba(209, 213, 219, 0.8);
+            background: rgba($text-disabled, 0.8);
         }
         }
     }
     }
 }
 }
@@ -261,22 +261,22 @@
 .visibility-radio {
 .visibility-radio {
     display: flex;
     display: flex;
     width: 100%;
     width: 100%;
-    
+
     .ant-radio-button-wrapper {
     .ant-radio-button-wrapper {
         flex: 1;
         flex: 1;
         text-align: center;
         text-align: center;
-        height: 40px;
-        line-height: 38px;
+        height: $search-height - 8;  // 40px
+        line-height: $search-height - 10;
         border-radius: $radius-md;
         border-radius: $radius-md;
-        
+
         &:first-child {
         &:first-child {
             border-radius: $radius-md 0 0 $radius-md;
             border-radius: $radius-md 0 0 $radius-md;
         }
         }
-        
+
         &:last-child {
         &:last-child {
             border-radius: 0 $radius-md $radius-md 0;
             border-radius: 0 $radius-md $radius-md 0;
         }
         }
-        
+
         &::before {
         &::before {
             display: none;
             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 { 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 { PlusCircleOutlined, MinusCircleOutlined, CloseCircleOutlined, LinkOutlined } from '@ant-design/icons';
 import * as AllIcons from '@ant-design/icons';
 import * as AllIcons from '@ant-design/icons';
+import { Globe, Lock } from 'iconoir-react';
 import IconPicker from './IconPicker';
 import IconPicker from './IconPicker';
 import VipSelector from './VipSelector';
 import VipSelector from './VipSelector';
 import './DrawerForm.scss';
 import './DrawerForm.scss';
@@ -214,11 +215,11 @@ const Step1Drawer: React.FC<Step1DrawerProps> = (props) => {
                                                 onChange={(e) => onVisibleChange(e.target.value)}
                                                 onChange={(e) => onVisibleChange(e.target.value)}
                                             >
                                             >
                                                 <Radio.Button value='0'>
                                                 <Radio.Button value='0'>
-                                                    <span className='iconify' data-icon='solar:earth-linear' style={{ marginRight: 4 }}></span>
+                                                    <Globe width="16" height="16" style={{ marginRight: 4 }} />
                                                     公开
                                                     公开
                                                 </Radio.Button>
                                                 </Radio.Button>
                                                 <Radio.Button value='1'>
                                                 <Radio.Button value='1'>
-                                                    <span className='iconify' data-icon='solar:lock-linear' style={{ marginRight: 4 }}></span>
+                                                    <Lock width="16" height="16" style={{ marginRight: 4 }} />
                                                     私有
                                                     私有
                                                 </Radio.Button>
                                                 </Radio.Button>
                                             </Radio.Group>
                                             </Radio.Group>

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

@@ -11,13 +11,13 @@
 
 
 .vip-selector-container {
 .vip-selector-container {
     display: flex;
     display: flex;
-    height: 500px;
+    height: $spacing-12 * 4;  // 500px
     overflow: hidden;
     overflow: hidden;
 }
 }
 
 
 // 左侧:部门树
 // 左侧:部门树
 .vip-selector-left {
 .vip-selector-left {
-    width: 240px;
+    width: $sidebar-width-md;  // 240px
     border-right: 1px solid $border-light;
     border-right: 1px solid $border-light;
     padding: $spacing-4;
     padding: $spacing-4;
     display: flex;
     display: flex;
@@ -50,13 +50,13 @@
             transition: all 0.2s ease;
             transition: all 0.2s ease;
 
 
             &:hover {
             &:hover {
-                background: rgba(0, 93, 128, 0.05);
+                background: rgba($primary-color, 0.05);
                 border-radius: $radius-sm;
                 border-radius: $radius-sm;
             }
             }
         }
         }
 
 
         .ant-tree-node-selected {
         .ant-tree-node-selected {
-            background: rgba(0, 93, 128, 0.1) !important;
+            background: rgba($primary-color, 0.1) !important;
             color: $primary-color;
             color: $primary-color;
             font-weight: $font-weight-medium;
             font-weight: $font-weight-medium;
         }
         }
@@ -100,8 +100,8 @@
 
 
         .dept-filter-tag {
         .dept-filter-tag {
             margin-left: $spacing-2;
             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;
             color: $primary-color;
             border-radius: $radius-full;
             border-radius: $radius-full;
             font-size: $font-xs;
             font-size: $font-xs;
@@ -111,7 +111,7 @@
 
 
     .filter-bar {
     .filter-bar {
         margin-bottom: $spacing-3;
         margin-bottom: $spacing-3;
-        padding: $spacing-3;
+        padding: $spacing-md;
         background: $bg-tertiary;
         background: $bg-tertiary;
         border-radius: $radius-lg;
         border-radius: $radius-lg;
     }
     }
@@ -128,11 +128,11 @@
         }
         }
 
 
         .ant-table-tbody > tr:hover {
         .ant-table-tbody > tr:hover {
-            background: rgba(0, 93, 128, 0.05);
+            background: rgba($primary-color, 0.05);
         }
         }
 
 
         .ant-table-selection-column {
         .ant-table-selection-column {
-            width: 50px;
+            width: $spacing-10;  // 50px
         }
         }
     }
     }
 }
 }
@@ -141,17 +141,17 @@
 @media (max-width: $screen-md) {
 @media (max-width: $screen-md) {
     .vip-selector-container {
     .vip-selector-container {
         flex-direction: column;
         flex-direction: column;
-        height: 600px;
+        height: $spacing-12 * 4.8;  // 600px
     }
     }
 
 
     .vip-selector-left {
     .vip-selector-left {
         width: 100%;
         width: 100%;
         border-right: none;
         border-right: none;
         border-bottom: 1px solid $border-light;
         border-bottom: 1px solid $border-light;
-        max-height: 200px;
+        max-height: $spacing-12 * 3;  // 200px
     }
     }
 
 
     .vip-selector-right {
     .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 { Modal, Table, Input, Select, Space, message, Tree, Divider, Button } from 'antd';
 import type { TableColumnsType } from 'antd';
 import type { TableColumnsType } from 'antd';
 import type { DataNode } from 'antd/es/tree';
 import type { DataNode } from 'antd/es/tree';
+import { Tree as TreeIcon, Group, Search } from 'iconoir-react';
 import './VipSelector.scss';
 import './VipSelector.scss';
 
 
 interface VipUser {
 interface VipUser {
@@ -195,7 +196,7 @@ const VipSelector: React.FC<VipSelectorProps> = ({ open, onClose, onConfirm, exi
                 {/* 左侧:部门树 */}
                 {/* 左侧:部门树 */}
                 <div className='vip-selector-left'>
                 <div className='vip-selector-left'>
                     <div className='section-title'>
                     <div className='section-title'>
-                        <span className='iconify' data-icon='solar:folder-tree-linear'></span>
+                        <TreeIcon width="18" height="18" />
                         选择部门
                         选择部门
                     </div>
                     </div>
                     <Tree
                     <Tree
@@ -214,7 +215,7 @@ const VipSelector: React.FC<VipSelectorProps> = ({ open, onClose, onConfirm, exi
                 {/* 右侧:用户列表 */}
                 {/* 右侧:用户列表 */}
                 <div className='vip-selector-right'>
                 <div className='vip-selector-right'>
                     <div className='section-title'>
                     <div className='section-title'>
-                        <span className='iconify' data-icon='solar:users-group-linear'></span>
+                        <Group width="18" height="18" />
                         用户列表
                         用户列表
                         {selectedDeptId && (
                         {selectedDeptId && (
                             <span className='dept-filter-tag'>
                             <span className='dept-filter-tag'>
@@ -231,7 +232,7 @@ const VipSelector: React.FC<VipSelectorProps> = ({ open, onClose, onConfirm, exi
                             onChange={(e) => setSearchUserName(e.target.value)}
                             onChange={(e) => setSearchUserName(e.target.value)}
                             style={{ width: 140 }}
                             style={{ width: 140 }}
                             allowClear
                             allowClear
-                            prefix={<span className='iconify' data-icon='solar:magnifer-linear'></span>}
+                            prefix={<Search width="14" height="14" />}
                         />
                         />
                         <Input
                         <Input
                             placeholder="搜索昵称"
                             placeholder="搜索昵称"

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

@@ -24,7 +24,7 @@
     }
     }
 
 
     .tags-info {
     .tags-info {
-        border: 1px solid @border-color;
+        border: 1px solid $border-color;
         width: 100%;
         width: 100%;
         max-width: 646px;
         max-width: 646px;
         min-height: 46px;
         min-height: 46px;

+ 397 - 857
jk-rag-platform/src/pages/system/audit/components/style.scss

@@ -1,998 +1,538 @@
-// 主容器样式
-.questionAnswerInfo {
-  width: 100%;
-  height: 100%;
-  background: $bg-secondary;
-  border-radius: $border-radius-base;
+// 导入全局样式变量
+@import '@/styles/variables.scss';
+
+// ===== 审计日志详情页面样式 =====
+// 使用全局变量,避免硬编码
 
 
-  // 内容区域
-  &-content {
+.questionAnswerInfo {
     width: 100%;
     width: 100%;
     height: 100%;
     height: 100%;
     background: $bg-secondary;
     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;
-    }
+    border-radius: $border-radius-base;
 
 
-    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);
-    }
+    &-content {
+        width: 100%;
+        height: 100%;
+        background: $bg-secondary;
+        padding: $spacing-3 $spacing-lg;
 
 
-    &:active {
-      background: #dcdcdc;
-      color: #000000;
-      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
-      transform: translateY(0);
+        &-title {
+            width: 100%;
+            max-width: 646px;
+            height: 48px;
+        }
     }
     }
 
 
-    &:focus {
-      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    .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;
     }
     }
-  }
 
 
-  &-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);
+    .pl-20 {
+        padding-left: $spacing-lg;
     }
     }
 
 
-    &:active {
-      background: #f0f0f0;
-      border-color: #1890ff;
-      color: #1890ff;
-      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
-      transform: translateY(0);
-    }
+    .tags-info {
+        border: 1px solid $border-base;
+        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-sm;
 
 
-    &:focus {
-      border-color: #40a9ff;
-      box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+        .tags-list {
+            width: 80%;
+        }
     }
     }
-  }
 }
 }
 
 
-// 表单样式
-.form {
-  &-control {
-    &-width {
-      width: 100%;
-      max-width: 646px;
-    }
-
-    &-height {
-      height: 48px;
-    }
-  }
-
-  &-input {
-    &-large {
-      width: 100%;
-      max-width: 646px;
-      padding: 8px;
-    }
+.modal_top {
+    display: flex;
+    gap: $spacing-2;
+    margin-bottom: $spacing-2;
 
 
-    &-number-small {
-      margin: 0 16px;
-      width: 100px;
+    .ant-input {
+        width: 200px !important;
     }
     }
-  }
 
 
-  &-textarea {
-    &-large {
-      height: 120px;
-      resize: none;
-      width: 100%;
-      max-width: 646px;
+    .ant-input-affix-wrapper {
+        width: auto !important;
     }
     }
-  }
 }
 }
 
 
-// 文本区域样式
-.textarea {
-  &-full-width {
-    width: 100%;
-  }
-
-  &-fixed-height {
-    height: 300px;
-  }
+.ant-btn-outlined {
+    background: transparent !important;
+    border: 1px solid $primary-color !important;
+    color: $primary-color !important;
 }
 }
 
 
-// 预设问题区域样式
-.preset-questions {
-  margin: 24px 0;
+.cup {
+    cursor: pointer;
+    margin-right: $spacing-2;
+}
 
 
-  h4 {
-    margin-bottom: 16px;
-    color: #262626;
-  }
+// ===== 布局样式 =====
 
 
-  .question-item {
-    display: flex;
-    align-items: center;
-    margin-bottom: 12px;
-    flex-wrap: wrap;
-    gap: 12px;
+.flex {
+    &-center {
+        &-container {
+            width: 100%;
+            min-height: 100%;
+            background: $bg-secondary;
+        }
 
 
-    label {
-      min-width: 60px;
-      color: #595959;
-      flex-shrink: 0;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+
+        &-top {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            padding-top: $spacing-xl;
+            font-size: $font-md;
+        }
     }
     }
 
 
-    .question-input {
-      flex: 1;
-      min-width: 200px;
-      max-width: 400px;
-      margin: 0;
+    &-between {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
     }
     }
 
 
-    .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);
-        }
-      }
+    &-start {
+        display: flex;
+        justify-content: flex-start;
     }
     }
-  }
-}
 
 
-// 问题输入框样式(保留向后兼容)
-.question-input {
-  width: 100%;
-  max-width: 300px;
-  padding-top: 8px;
-  margin-left: 20px;
+    &-end {
+        display: flex;
+        justify-content: flex-end;
+    }
 }
 }
 
 
-.link-more-settings {
-  color: $primary-color;
-  cursor: pointer;
-  text-decoration: none;
+// ===== 按钮样式 =====
 
 
-  &:hover {
-    text-decoration: underline;
-  }
-}
+.btn {
+    &-cancel {
+        background: $bg-tertiary;
+        border: none;
+        color: $text-primary;
+        transition: $transition-base;
+        box-shadow: $shadow-sm;
 
 
-// 标题和链接样式
-.section-title {
-  font-size: 14px;
-  font-weight: 500;
-  color: #262626;
-  margin-bottom: 12px;
-}
+        &:hover {
+            background: #e8e8e8;
+            color: $text-primary;
+            box-shadow: $shadow-md;
+            transform: translateY(-1px);
+        }
 
 
-// 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;
+        &:active {
+            background: #dcdcdc;
+            color: $text-primary;
+            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+            transform: translateY(0);
+        }
 
 
-    .ant-form-item {
-      margin-bottom: 0;
-      height: 100%;
+        &:focus {
+            box-shadow: $shadow-sm;
+        }
+    }
 
 
-      .ant-form-item-control {
-        height: 100%;
+    &-back {
+        background: $bg-secondary;
+        border: 1px solid #f0f0f0;
+        color: $text-secondary;
+        transition: $transition-base;
+        box-shadow: $shadow-sm;
 
 
-        .ant-form-item-control-input {
-          height: 100%;
+        &:hover {
+            background: #fafafa;
+            border-color: $primary-light;
+            color: $primary-light;
+            box-shadow: $shadow-md;
+            transform: translateY(-1px);
+        }
 
 
-          .ant-form-item-control-input-content {
-            height: 100%;
+        &:active {
+            background: #f0f0f0;
+            border-color: $primary-color;
+            color: $primary-color;
+            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+            transform: translateY(0);
+        }
 
 
-            .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;
-              }
-            }
-          }
+        &:focus {
+            border-color: $primary-light;
+            box-shadow: 0 0 0 2px rgba($primary-color, 0.2);
         }
         }
-      }
     }
     }
-  }
 }
 }
 
 
-.half-width {
-  margin: 0 auto;
-  width: 50%;
-  height: 100%;
-}
+// ===== 表单样式 =====
 
 
-// 间距样式
-.padding {
-  &-top {
-    &-10 {
-      padding-top: 10px;
-    }
+.form {
+    &-control {
+        &-width {
+            width: 100%;
+            max-width: 646px;
+        }
 
 
-    &-20 {
-      padding-top: 20px;
+        &-height {
+            height: 48px;
+        }
     }
     }
-  }
 
 
-  &-bottom {
-    &-10 {
-      padding-bottom: 10px;
-    }
+    &-input {
+        &-large {
+            width: 100%;
+            max-width: 646px;
+            padding: $spacing-2;
+        }
 
 
-    &-12 {
-      padding-bottom: 12px;
+        &-number-small {
+            margin: 0 $spacing-md;
+            width: 100px;
+        }
     }
     }
 
 
-    &-16 {
-      padding-bottom: 16px;
+    &-textarea {
+        &-large {
+            height: 120px;
+            resize: none;
+            width: 100%;
+            max-width: 646px;
+        }
     }
     }
-  }
 }
 }
 
 
-// 响应式设计
-@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 {
+.textarea {
+    &-full-width {
         width: 100%;
         width: 100%;
-        max-width: 100%;
-        min-width: auto;
-      }
+    }
 
 
-      .question-actions {
-        align-self: flex-end;
-      }
+    &-fixed-height {
+        height: 300px;
     }
     }
-  }
 }
 }
 
 
-@media (max-width: 480px) {
-  .questionAnswerInfo {
-    &-content {
-      padding: 16px;
-    }
-  }
+// ===== 预设问题区域样式 =====
 
 
-  .form {
-    &-input-large,
-    &-textarea-large {
-      padding: 6px;
-    }
-  }
+.preset-questions {
+    margin: $spacing-lg 0;
 
 
-  .preset-questions {
-    .question-item {
-      .question-actions {
-        align-self: center;
-        width: 100%;
-        justify-content: center;
-      }
+    h4 {
+        margin-bottom: $spacing-md;
+        color: $text-primary;
     }
     }
-  }
-}
 
 
+    .question-item {
+        display: flex;
+        align-items: center;
+        margin-bottom: $spacing-sm;
+        flex-wrap: wrap;
+        gap: $spacing-sm;
+
+        label {
+            min-width: 60px;
+            color: $text-secondary;
+            flex-shrink: 0;
+        }
 
 
-// 主容器样式
-.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;
+        .question-input {
+            flex: 1;
+            min-width: 200px;
+            max-width: 400px;
+            margin: 0;
+        }
 
 
-    // 标题样式
-    &-title {
-      width: 100%;
-      max-width: 646px;
-      height: 48px;
+        .question-actions {
+            display: flex;
+            gap: $spacing-2;
+            flex-shrink: 0;
+
+            .question-icon {
+                font-size: $icon-lg;
+                color: $primary-color;
+                cursor: pointer;
+                transition: all 0.3s ease;
+
+                &:hover {
+                    color: $primary-color;
+                    transform: scale(1.1);
+                }
+            }
+        }
     }
     }
-  }
-  .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;
-  }
+.question-input {
+    width: 100%;
+    max-width: 300px;
+    padding-top: $spacing-2;
+    margin-left: $spacing-lg;
 }
 }
 
 
-// 按钮样式
-.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);
+.link-more-settings {
+    color: $primary-color;
+    cursor: pointer;
+    text-decoration: none;
 
 
     &:hover {
     &: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);
+        text-decoration: underline;
     }
     }
+}
 
 
-    &: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);
+.section-title {
+    font-size: $font-md;
+    font-weight: $font-weight-medium;
+    color: $text-primary;
+    margin-bottom: $spacing-sm;
+}
 
 
-    &:hover {
-      background: #fafafa;
-      border-color: #40a9ff;
-      color: #40a9ff;
-      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
-      transform: translateY(-1px);
-    }
+// ===== Prompt 编辑器布局样式 =====
 
 
-    &:active {
-      background: #f0f0f0;
-      border-color: #1890ff;
-      color: #1890ff;
-      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
-      transform: translateY(0);
-    }
+.prompt {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    overflow-y: auto;
 
 
-    &:focus {
-      border-color: #40a9ff;
-      box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+    &-info {
+        padding: $spacing-md $spacing-lg $spacing-sm $spacing-lg;
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-start;
+
+        &-text {
+            .variable-highlight {
+                color: $primary-color;
+                font-weight: $font-weight-medium;
+                padding: 2px $spacing-2;
+                border-radius: $radius-sm;
+                font-family: $font-family-mono;
+                margin: 0 $spacing-1;
+            }
+        }
     }
     }
-  }
-}
 
 
-// 表单样式
-.form {
-  &-control {
-    &-width {
-      width: 100%;
-      max-width: 646px;
-    }
+    &-editor-area {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        padding: 0 $spacing-lg;
 
 
-    &-height {
-      height: 48px;
-    }
-  }
+        .ant-form-item {
+            margin-bottom: 0;
+            height: 100%;
 
 
-  &-input {
-    &-large {
-      width: 100%;
-      max-width: 646px;
-      height: 48px;
-      padding: 8px;
+            .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 $border-base;
+                            border-radius: $radius-lg;
+                            padding: $spacing-lg;
+                            font-size: $font-md;
+                            line-height: 1.6;
+                            resize: none;
+
+                            &:focus {
+                                border-color: $primary-light;
+                                box-shadow: 0 0 0 2px rgba($primary-color, 0.2);
+                            }
+
+                            &::placeholder {
+                                color: #bfbfbf;
+                                font-style: italic;
+                            }
+                        }
+                    }
+                }
+            }
+        }
     }
     }
+}
 
 
-    &-number-small {
-      margin: 0 16px;
-      width: 100px;
-    }
-  }
+.half-width {
+    margin: 0 auto;
+    width: 50%;
+    height: 100%;
+}
 
 
-  &-textarea {
-    &-large {
-      height: 96px;
-      resize: none;
-      width: 100%;
-      min-width: 200px;
-      max-width: 646px;
-    }
-  }
+// ===== 间距样式 =====
 
 
-  // 统一表单元素宽度样式
-  &-element {
-    &-standard {
-      width: 100%;
-      max-width: 646px;
-      min-width: 200px;
-    }
+.padding {
+    &-top {
+        &-10 {
+            padding-top: $spacing-2;
+        }
 
 
-    &-full-width {
-      width: 100%;
+        &-20 {
+            padding-top: $spacing-lg;
+        }
     }
     }
 
 
-    &-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;
+    &-bottom {
+        &-10 {
+            padding-bottom: $spacing-2;
         }
         }
-      }
-    }
 
 
-    &-select {
-      width: 100%;
-      max-width: 646px;
-      min-width: 200px;
-    }
+        &-12 {
+            padding-bottom: $spacing-md;
+        }
 
 
-    &-input-number {
-      width: 100%;
-      max-width: 646px;
-      min-width: 200px;
+        &-16 {
+            padding-bottom: $spacing-lg;
+        }
     }
     }
-  }
 }
 }
 
 
-// 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 {
 .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;
-  }
-}
+    padding-top: $spacing-lg;
 
 
-// 文本区域样式
-.textarea {
-  &-full-width {
-    width: 100%;
-  }
+    .flex-center {
+        margin-bottom: $spacing-lg;
+    }
 
 
-  &-fixed-height {
-    height: 300px;
-  }
+    .section-title {
+        font-size: $font-md;
+        font-weight: $font-weight-semibold;
+        color: $text-primary;
+        text-align: center;
+        margin: $spacing-lg 0;
+    }
 }
 }
 
 
-// 预设问题区域样式
-.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;
+// ===== Splitter 面板背景样式 =====
 
 
-    label {
-      min-width: 60px;
-      color: #595959;
-      flex-shrink: 0;
+.ant-splitter-panel {
+    &:first-child {
+        background: $bg-secondary;
     }
     }
 
 
-    .question-input {
-      flex: 1;
-      min-width: 200px;
-      max-width: 400px;
-      margin: 0;
+    &:nth-child(2) {
+        background: $bg-tertiary;
     }
     }
 
 
-    .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);
-        }
-      }
+    &:last-child {
+        background: $bg-secondary;
     }
     }
-  }
 }
 }
 
 
-// 问题输入框样式(保留向后兼容)
-.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;
-              }
-            }
-          }
+.questionAnswerInfo {
+    .ant-splitter-panel,
+    .prompt,
+    .prompt-editor-area,
+    .ant-input {
+        -ms-overflow-style: none;
+        scrollbar-width: none;
+
+        &::-webkit-scrollbar {
+            display: none;
+            width: 0;
+            height: 0;
         }
         }
-      }
     }
     }
-  }
-}
-
-// 隐藏 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;
+@media (max-width: $screen-md) {
+    .questionAnswerInfo {
+        &-content {
+            &-title {
+                max-width: 100%;
+            }
+        }
     }
     }
 
 
-    &-16 {
-      padding-bottom: 16px;
+    .form {
+        &-control-width,
+        &-input-large,
+        &-textarea-large {
+            max-width: 100%;
+        }
     }
     }
-  }
-}
 
 
-// 响应式设计
-@media (max-width: 768px) {
-  .questionAnswerInfo {
-    &-content {
-      &-title {
+    .question-input {
         max-width: 100%;
         max-width: 100%;
-      }
+        margin-left: 0;
     }
     }
-  }
 
 
-  .form {
-    &-control-width,
-    &-input-large,
-    &-textarea-large {
-      max-width: 100%;
+    .half-width {
+        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: $spacing-sm;
 
 
-  .preset-questions {
-    .question-item {
-      flex-direction: column;
-      align-items: flex-start;
-      gap: 8px;
-
-      label {
-        min-width: auto;
-      }
+            label {
+                min-width: auto;
+            }
 
 
-      .question-input {
-        width: 100%;
-        max-width: 100%;
-        min-width: auto;
-      }
+            .question-input {
+                width: 100%;
+                max-width: 100%;
+                min-width: auto;
+            }
 
 
-      .question-actions {
-        align-self: flex-end;
-      }
+            .question-actions {
+                align-self: flex-end;
+            }
+        }
     }
     }
-  }
 }
 }
 
 
-@media (max-width: 480px) {
-  .questionAnswerInfo {
-    &-content {
-      padding: 16px;
+@media (max-width: $screen-sm) {
+    .questionAnswerInfo {
+        &-content {
+            padding: $spacing-md;
+        }
     }
     }
-  }
 
 
-  .form {
-    &-input-large,
-    &-textarea-large {
-      padding: 6px;
+    .form {
+        &-input-large,
+        &-textarea-large {
+            padding: $spacing-1;
+        }
     }
     }
-  }
 
 
-  .preset-questions {
-    .question-item {
-      .question-actions {
-        align-self: center;
-        width: 100%;
-        justify-content: center;
-      }
+    .preset-questions {
+        .question-item {
+            .question-actions {
+                align-self: center;
+                width: 100%;
+                justify-content: center;
+            }
+        }
     }
     }
-  }
 }
 }

+ 8 - 0
jk-rag-platform/src/styles/variables.scss

@@ -108,7 +108,9 @@ $spacing-3: 12px;
 $spacing-4: 16px;
 $spacing-4: 16px;
 $spacing-5: 20px;
 $spacing-5: 20px;
 $spacing-6: 24px;
 $spacing-6: 24px;
+$spacing-7: 28px;
 $spacing-8: 32px;
 $spacing-8: 32px;
+$spacing-9: 36px;
 $spacing-10: 40px;
 $spacing-10: 40px;
 $spacing-12: 48px;
 $spacing-12: 48px;
 $spacing-16: 64px;
 $spacing-16: 64px;
@@ -421,6 +423,12 @@ $font-size-md: $font-md;
 $font-size-lg: $font-lg;
 $font-size-lg: $font-lg;
 $font-size-xl: $font-xl;
 $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-base: $radius-md;
 $border-radius-sm: $radius-sm;
 $border-radius-sm: $radius-sm;