Эх сурвалжийг харах

scss 样式警告修复 import -> use

Ryuiso 1 сар өмнө
parent
commit
ef7fe1643d
50 өөрчлөгдсөн 1921 нэмэгдсэн , 1106 устгасан
  1. 0 1
      jk-rag-platform/.claude-rules.md
  2. 20 1
      jk-rag-platform/.claude/settings.local.json
  3. 0 10
      jk-rag-platform/demo.log
  4. BIN
      jk-rag-platform/e1.png
  5. 1 0
      jk-rag-platform/package.json
  6. 7 0
      jk-rag-platform/src/App.tsx
  7. 27 1
      jk-rag-platform/src/apis/index.ts
  8. 267 0
      jk-rag-platform/src/components/common/AppCard/AppCardApiDoc.scss
  9. 286 0
      jk-rag-platform/src/components/common/AppCard/AppCardApiDoc.tsx
  10. 3 2
      jk-rag-platform/src/components/common/AppCard/index.scss
  11. 48 31
      jk-rag-platform/src/components/common/AppCard/index.tsx
  12. 1 2
      jk-rag-platform/src/components/common/FilterBar/index.scss
  13. 2 0
      jk-rag-platform/src/components/common/FilterDrawer/index.scss
  14. 1 1
      jk-rag-platform/src/components/common/GuideTips/index.scss
  15. 1 1
      jk-rag-platform/src/components/common/HeroBanner/index.scss
  16. 1 2
      jk-rag-platform/src/components/common/StatsGrid/index.scss
  17. 1 1
      jk-rag-platform/src/pages/appCenter/appPlazaList/style.scss
  18. 1 1
      jk-rag-platform/src/pages/appCenter/categoryApps/style.scss
  19. 0 2
      jk-rag-platform/src/pages/deepseek/dataExport/style.scss
  20. 1 1
      jk-rag-platform/src/pages/home/style.scss
  21. 1 1
      jk-rag-platform/src/pages/knowledgeLib/detail/components/style.scss
  22. 1 1
      jk-rag-platform/src/pages/knowledgeLib/list/KnowledgeDrawer.scss
  23. 32 1
      jk-rag-platform/src/pages/knowledgeLib/list/style.scss
  24. 1 1
      jk-rag-platform/src/pages/knowledgeLib/revisionTool/components/reviseDrawer.scss
  25. 1 1
      jk-rag-platform/src/pages/layout/components/header.scss
  26. 1 1
      jk-rag-platform/src/pages/layout/components/sidebar.scss
  27. 9 9
      jk-rag-platform/src/pages/layout/store.ts
  28. 1 1
      jk-rag-platform/src/pages/layout/style.scss
  29. 1 1
      jk-rag-platform/src/pages/login/style.scss
  30. 1 1
      jk-rag-platform/src/pages/otherApps/otherAppList/style.scss
  31. 0 29
      jk-rag-platform/src/pages/otherApps/style.scss
  32. 1 1
      jk-rag-platform/src/pages/questionAnswer/form/DrawerForm.scss
  33. 1 1
      jk-rag-platform/src/pages/questionAnswer/form/VipSelector.scss
  34. 2 227
      jk-rag-platform/src/pages/questionAnswer/form/style.scss
  35. 0 105
      jk-rag-platform/src/pages/questionAnswer/info/style.scss
  36. 1 1
      jk-rag-platform/src/pages/questionAnswer/list/style.scss
  37. 304 0
      jk-rag-platform/src/pages/system/apiKey/components/ApiDoc.scss
  38. 415 0
      jk-rag-platform/src/pages/system/apiKey/components/ApiDoc.tsx
  39. 159 3
      jk-rag-platform/src/pages/system/apiKey/index.tsx
  40. 1 0
      jk-rag-platform/src/pages/system/apiKey/style.scss
  41. 6 536
      jk-rag-platform/src/pages/system/audit/components/style.scss
  42. 23 21
      jk-rag-platform/src/pages/system/audit/index.tsx
  43. 2 1
      jk-rag-platform/src/pages/system/audit/style.scss
  44. 0 2
      jk-rag-platform/src/pages/system/contentManagement/style.scss
  45. 0 2
      jk-rag-platform/src/pages/system/usageStatistics/style.scss
  46. 95 5
      jk-rag-platform/src/pages/universalChat/styles/index.scss
  47. 145 30
      jk-rag-platform/src/styles/global.scss
  48. 48 66
      jk-rag-platform/src/styles/variables.scss
  49. 1 1
      jk-rag-platform/vite.config.ts
  50. BIN
      jk-rag-platform/开发计划清单.xlsx

+ 0 - 1
jk-rag-platform/.claude-rules.md

@@ -372,6 +372,5 @@ npm run build:prod      # 构建生产版
 - `页面布局与间距控制规范.md` - 布局规范
 - `页面布局与间距控制规范.md` - 布局规范
 - `知识库路由和 Mock 数据说明.md` - Mock 数据说明
 - `知识库路由和 Mock 数据说明.md` - Mock 数据说明
 
 
----
 
 
 **最后更新**: 2026-04-02
 **最后更新**: 2026-04-02

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

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

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

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

BIN
jk-rag-platform/e1.png


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

@@ -39,6 +39,7 @@
     "react-quill": "^2.0.0",
     "react-quill": "^2.0.0",
     "react-router-dom": "^7.1.0",
     "react-router-dom": "^7.1.0",
     "tailwindcss": "^4.1.17",
     "tailwindcss": "^4.1.17",
+    "xlsx": "^0.18.5",
     "zustand": "^5.0.12"
     "zustand": "^5.0.12"
   },
   },
   "devDependencies": {
   "devDependencies": {

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

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

+ 27 - 1
jk-rag-platform/src/apis/index.ts

@@ -849,6 +849,28 @@ export const fetchOverviewKnowledgeData = async (data: any) => {
 }
 }
 // DELETE http://localhost:8080/deepseek/api/deleteSlice/{{sliceId}}/{{knowledgeId}}/{{documentId}}
 // DELETE http://localhost:8080/deepseek/api/deleteSlice/{{sliceId}}/{{knowledgeId}}/{{documentId}}
 
 
+// ==================== API Key 管理相关 ====================
+
+// 获取 API Key 列表
+export const fetchApiKeyList = async (data: any) => {
+    return api.get('/system/apikey/list', { params: data });
+};
+
+// 创建 API Key
+export const createApiKey = async (data: { name: string; remark?: string }) => {
+    return api.post('/system/apikey/create', data);
+};
+
+// 删除 API Key
+export const deleteApiKey = async (id: string) => {
+    return api.delete(`/system/apikey/delete/${id}`);
+};
+
+// 下载 API Key 文件
+export const downloadApiKey = async (id: string) => {
+    return api.get(`/system/apikey/download/${id}`, { responseType: 'blob' });
+};
+
 // end 建科新的APi
 // end 建科新的APi
 
 
 export const apis = {
 export const apis = {
@@ -964,6 +986,10 @@ export const apis = {
     fetchOnlineUserData:fetchOnlineUserData,
     fetchOnlineUserData:fetchOnlineUserData,
     fetchConversationData:fetchConversationData,
     fetchConversationData:fetchConversationData,
     fetchConversationDetailData:fetchConversationDetailData,
     fetchConversationDetailData:fetchConversationDetailData,
-    fetchOverviewTokenData:fetchOverviewTokenData
+    fetchOverviewTokenData:fetchOverviewTokenData,
+    fetchApiKeyList: fetchApiKeyList,
+    createApiKey: createApiKey,
+    deleteApiKey: deleteApiKey,
+    downloadApiKey: downloadApiKey,
     // end 建科新的APi
     // end 建科新的APi
 };
 };

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

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

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

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

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

@@ -1,5 +1,6 @@
+@use 'sass:color';
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 
 // ===== AppCard 应用卡片样式 =====
 // ===== AppCard 应用卡片样式 =====
 // 使用全局变量,符合设计规范 v3.0
 // 使用全局变量,符合设计规范 v3.0
@@ -44,7 +45,7 @@
     top: $spacing-3;
     top: $spacing-3;
     right: $spacing-3;
     right: $spacing-3;
     padding: $spacing-1 $spacing-2;
     padding: $spacing-1 $spacing-2;
-    background: linear-gradient(135deg, $warning-color 0%, darken($warning-color, 10%) 100%);
+    background: linear-gradient(135deg, $warning-color 0%, color.adjust($warning-color, $lightness: -10%) 100%);
     color: $bg-secondary;
     color: $bg-secondary;
     border-radius: $radius-full;
     border-radius: $radius-full;
     font-size: $font-xs;
     font-size: $font-xs;

+ 48 - 31
jk-rag-platform/src/components/common/AppCard/index.tsx

@@ -1,6 +1,7 @@
 import * as React from 'react';
 import * as React from 'react';
 import { Dropdown, MenuProps, Button } from 'antd';
 import { Dropdown, MenuProps, Button } from 'antd';
 import { Code, Pen, Trash2, Share2, Star, Eye, Heart, Calendar, BadgeCheck, Building, Menu, ArrowRight } from 'lucide-react';
 import { Code, Pen, Trash2, Share2, Star, Eye, Heart, Calendar, BadgeCheck, Building, Menu, ArrowRight } from 'lucide-react';
+import AppCardApiDoc from './AppCardApiDoc';
 import './index.scss';
 import './index.scss';
 
 
 export interface AppCardProps {
 export interface AppCardProps {
@@ -68,35 +69,37 @@ export interface AppCardProps {
 const AppCard: React.FC<AppCardProps> = (props) => {
 const AppCard: React.FC<AppCardProps> = (props) => {
     const {
     const {
         // 基本信息
         // 基本信息
+        id,
         name,
         name,
         description,
         description,
         icon,
         icon,
         iconImage,
         iconImage,
         iconBgColor = 'blue',
         iconBgColor = 'blue',
-        
+
         // 创建者信息
         // 创建者信息
         creator,
         creator,
         proName,
         proName,
-        
+
         // 标签和认证
         // 标签和认证
         tags = [],
         tags = [],
         certification,
         certification,
-        
+
         // 状态标识
         // 状态标识
         isHot,
         isHot,
         status,
         status,
-        
+
         // 统计数据
         // 统计数据
         viewCount,
         viewCount,
         favoriteCount,
         favoriteCount,
         createTime,
         createTime,
-        
+
         // 其他信息
         // 其他信息
         department,
         department,
         visible,
         visible,
+        appId,
         isCollect = false,
         isCollect = false,
         isCreator = false,
         isCreator = false,
-        
+
         // 显示控制
         // 显示控制
         showCreator = true,
         showCreator = true,
         showActions = true,
         showActions = true,
@@ -110,7 +113,7 @@ const AppCard: React.FC<AppCardProps> = (props) => {
         showDepartment = false,
         showDepartment = false,
         showVisible = false,
         showVisible = false,
         showOperations = false,
         showOperations = false,
-        
+
         // 回调函数
         // 回调函数
         onShare,
         onShare,
         onFavorite,
         onFavorite,
@@ -121,6 +124,12 @@ const AppCard: React.FC<AppCardProps> = (props) => {
         onApiDirect,
         onApiDirect,
     } = props;
     } = props;
 
 
+    // API 文档弹窗状态
+    const [apiDocOpen, setApiDocOpen] = React.useState(false);
+
+    // 使用 appId 或 id 作为应用标识
+    const applicationId = appId || id;
+
     // 配置对象
     // 配置对象
     const statusConfig = {
     const statusConfig = {
         draft: { label: '草稿', color: '#9CA3AF' },
         draft: { label: '草稿', color: '#9CA3AF' },
@@ -330,7 +339,7 @@ const AppCard: React.FC<AppCardProps> = (props) => {
             {/* 悬停操作按钮层 */}
             {/* 悬停操作按钮层 */}
             {showOperations && (
             {showOperations && (
                 <div className='card-hover-actions'>
                 <div className='card-hover-actions'>
-                    {/* 创建者显示【更多操作】,非创建者显示【API 用】 */}
+                    {/* 创建者显示【更多操作】,非创建者显示【API 文档】和【立即使用】 */}
                     {isCreator ? (
                     {isCreator ? (
                         <Dropdown
                         <Dropdown
                             menu={{ items: operationItems }}
                             menu={{ items: operationItems }}
@@ -347,32 +356,40 @@ const AppCard: React.FC<AppCardProps> = (props) => {
                             </Button>
                             </Button>
                         </Dropdown>
                         </Dropdown>
                     ) : (
                     ) : (
-                        <Button
-                            className='card-operation-btn'
-                            icon={<Code size={18} />}
-                            size='large'
-                            onClick={(e) => {
-                                e.stopPropagation();
-                                onApiDirect?.();
-                            }}
-                        >
-                            API 调用
-                        </Button>
+                        <>
+                            <Button
+                                className='card-operation-btn'
+                                icon={<Code size={18} />}
+                                size='large'
+                                onClick={(e) => {
+                                    e.stopPropagation();
+                                    setApiDocOpen(true);
+                                }}
+                            >
+                                API 接入
+                            </Button>
+                            <Button
+                                className='card-use-btn'
+                                icon={<ArrowRight size={18} />}
+                                size='large'
+                                onClick={(e) => {
+                                    e.stopPropagation();
+                                    handleViewClick();
+                                }}
+                            >
+                                立即使用
+                            </Button>
+                        </>
                     )}
                     )}
-
-                    <Button
-                        className='card-use-btn'
-                        icon={<ArrowRight size={18} />}
-                        size='large'
-                        onClick={(e) => {
-                            e.stopPropagation();
-                            handleViewClick();
-                        }}
-                    >
-                        立即使用
-                    </Button>
                 </div>
                 </div>
             )}
             )}
+
+            {/* API 文档抽屉 */}
+            <AppCardApiDoc
+                open={apiDocOpen}
+                appId={applicationId || ''}
+                onClose={() => setApiDocOpen(false)}
+            />
         </div>
         </div>
     );
     );
 };
 };

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

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

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

@@ -1,3 +1,5 @@
+@use '@/styles/variables.scss' as *;
+
 .filter-drawer {
 .filter-drawer {
     .filter-content {
     .filter-content {
         padding: $spacing-4 0;
         padding: $spacing-4 0;

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

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

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

@@ -1,4 +1,4 @@
-@import '@/styles/variables.scss';
+@use '@/styles/variables.scss' as *;
 
 
 .hero-banner {
 .hero-banner {
     position: relative;
     position: relative;

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

@@ -1,8 +1,7 @@
+@use '@/styles/variables.scss' as *;
 // StatsGrid 统计卡片网格 - 紧凑布局 v3.9
 // StatsGrid 统计卡片网格 - 紧凑布局 v3.9
 // 遵循全局样式规范,使用全局变量
 // 遵循全局样式规范,使用全局变量
 
 
-@import '@/styles/variables.scss';
-
 .stats-grid {
 .stats-grid {
     display: grid;
     display: grid;
     grid-template-columns: repeat(4, 1fr);
     grid-template-columns: repeat(4, 1fr);

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

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

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

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

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

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

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

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

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

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 覆盖 markdown 渲染出来的样式 - 使用全局变量
 // 覆盖 markdown 渲染出来的样式 - 使用全局变量
-@import '@/styles/variables.scss';
 
 
 .ant-typography {
 .ant-typography {
     h1 {
     h1 {

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

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

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

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

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

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

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

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

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

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 
 // ===== Sidebar 侧边栏样式 =====
 // ===== Sidebar 侧边栏样式 =====
 
 

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

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

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

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 
 // ===== 应用布局 =====
 // ===== 应用布局 =====
 .app-layout {
 .app-layout {

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

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

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

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

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

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

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

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 
 // ===== Drawer 表单样式 =====
 // ===== Drawer 表单样式 =====
 
 

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

@@ -1,5 +1,5 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 
 // ===== VIP 用户选择器样式 =====
 // ===== VIP 用户选择器样式 =====
 
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 6 - 536
jk-rag-platform/src/pages/system/audit/components/style.scss

@@ -1,538 +1,8 @@
+@use '@/styles/variables.scss' as *;
 // 导入全局样式变量
 // 导入全局样式变量
-@import '@/styles/variables.scss';
 
 
-// ===== 审计日志详情页面样式 =====
-// 使用全局变量,避免硬编码
-
-.questionAnswerInfo {
-    width: 100%;
-    height: 100%;
-    background: $bg-secondary;
-    border-radius: $border-radius-base;
-
-    &-content {
-        width: 100%;
-        height: 100%;
-        background: $bg-secondary;
-        padding: $spacing-3 $spacing-lg;
-
-        &-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;
-    }
-
-    .pl-20 {
-        padding-left: $spacing-lg;
-    }
-
-    .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;
-
-        .tags-list {
-            width: 80%;
-        }
-    }
-}
-
-.modal_top {
-    display: flex;
-    gap: $spacing-2;
-    margin-bottom: $spacing-2;
-
-    .ant-input {
-        width: 200px !important;
-    }
-
-    .ant-input-affix-wrapper {
-        width: auto !important;
-    }
-}
-
-.ant-btn-outlined {
-    background: transparent !important;
-    border: 1px solid $primary-color !important;
-    color: $primary-color !important;
-}
-
-.cup {
-    cursor: pointer;
-    margin-right: $spacing-2;
-}
-
-// ===== 布局样式 =====
-
-.flex {
-    &-center {
-        &-container {
-            width: 100%;
-            min-height: 100%;
-            background: $bg-secondary;
-        }
-
-        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;
-        }
-    }
-
-    &-between {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-    }
-
-    &-start {
-        display: flex;
-        justify-content: flex-start;
-    }
-
-    &-end {
-        display: flex;
-        justify-content: flex-end;
-    }
-}
-
-// ===== 按钮样式 =====
-
-.btn {
-    &-cancel {
-        background: $bg-tertiary;
-        border: none;
-        color: $text-primary;
-        transition: $transition-base;
-        box-shadow: $shadow-sm;
-
-        &:hover {
-            background: #e8e8e8;
-            color: $text-primary;
-            box-shadow: $shadow-md;
-            transform: translateY(-1px);
-        }
-
-        &:active {
-            background: #dcdcdc;
-            color: $text-primary;
-            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
-            transform: translateY(0);
-        }
-
-        &:focus {
-            box-shadow: $shadow-sm;
-        }
-    }
-
-    &-back {
-        background: $bg-secondary;
-        border: 1px solid #f0f0f0;
-        color: $text-secondary;
-        transition: $transition-base;
-        box-shadow: $shadow-sm;
-
-        &:hover {
-            background: #fafafa;
-            border-color: $primary-light;
-            color: $primary-light;
-            box-shadow: $shadow-md;
-            transform: translateY(-1px);
-        }
-
-        &:active {
-            background: #f0f0f0;
-            border-color: $primary-color;
-            color: $primary-color;
-            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
-            transform: translateY(0);
-        }
-
-        &:focus {
-            border-color: $primary-light;
-            box-shadow: 0 0 0 2px rgba($primary-color, 0.2);
-        }
-    }
-}
-
-// ===== 表单样式 =====
-
-.form {
-    &-control {
-        &-width {
-            width: 100%;
-            max-width: 646px;
-        }
-
-        &-height {
-            height: 48px;
-        }
-    }
-
-    &-input {
-        &-large {
-            width: 100%;
-            max-width: 646px;
-            padding: $spacing-2;
-        }
-
-        &-number-small {
-            margin: 0 $spacing-md;
-            width: 100px;
-        }
-    }
-
-    &-textarea {
-        &-large {
-            height: 120px;
-            resize: none;
-            width: 100%;
-            max-width: 646px;
-        }
-    }
-}
-
-// ===== 文本区域样式 =====
-
-.textarea {
-    &-full-width {
-        width: 100%;
-    }
-
-    &-fixed-height {
-        height: 300px;
-    }
-}
-
-// ===== 预设问题区域样式 =====
-
-.preset-questions {
-    margin: $spacing-lg 0;
-
-    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;
-        }
-
-        .question-input {
-            flex: 1;
-            min-width: 200px;
-            max-width: 400px;
-            margin: 0;
-        }
-
-        .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);
-                }
-            }
-        }
-    }
-}
-
-// ===== 问题输入框样式(保留向后兼容)=====
-
-.question-input {
-    width: 100%;
-    max-width: 300px;
-    padding-top: $spacing-2;
-    margin-left: $spacing-lg;
-}
-
-.link-more-settings {
-    color: $primary-color;
-    cursor: pointer;
-    text-decoration: none;
-
-    &:hover {
-        text-decoration: underline;
-    }
-}
-
-// ===== 标题样式 =====
-
-.section-title {
-    font-size: $font-md;
-    font-weight: $font-weight-medium;
-    color: $text-primary;
-    margin-bottom: $spacing-sm;
-}
-
-// ===== Prompt 编辑器布局样式 =====
-
-.prompt {
-    width: 100%;
-    height: 100%;
-    display: flex;
-    flex-direction: column;
-    overflow-y: auto;
-
-    &-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;
-            }
-        }
-    }
-
-    &-editor-area {
-        flex: 1;
-        display: flex;
-        flex-direction: column;
-        padding: 0 $spacing-lg;
-
-        .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 $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;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-.half-width {
-    margin: 0 auto;
-    width: 50%;
-    height: 100%;
-}
-
-// ===== 间距样式 =====
-
-.padding {
-    &-top {
-        &-10 {
-            padding-top: $spacing-2;
-        }
-
-        &-20 {
-            padding-top: $spacing-lg;
-        }
-    }
-
-    &-bottom {
-        &-10 {
-            padding-bottom: $spacing-2;
-        }
-
-        &-12 {
-            padding-bottom: $spacing-md;
-        }
-
-        &-16 {
-            padding-bottom: $spacing-lg;
-        }
-    }
-}
-
-// ===== 更多设置区域样式 =====
-
-.more-settings-section {
-    padding-top: $spacing-lg;
-
-    .flex-center {
-        margin-bottom: $spacing-lg;
-    }
-
-    .section-title {
-        font-size: $font-md;
-        font-weight: $font-weight-semibold;
-        color: $text-primary;
-        text-align: center;
-        margin: $spacing-lg 0;
-    }
-}
-
-// ===== Splitter 面板背景样式 =====
-
-.ant-splitter-panel {
-    &:first-child {
-        background: $bg-secondary;
-    }
-
-    &:nth-child(2) {
-        background: $bg-tertiary;
-    }
-
-    &:last-child {
-        background: $bg-secondary;
-    }
-}
-
-// ===== 隐藏滚动条样式 =====
-
-.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;
-        }
-    }
-}
-
-// ===== 响应式设计 =====
-
-@media (max-width: $screen-md) {
-    .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: $spacing-sm;
-
-            label {
-                min-width: auto;
-            }
-
-            .question-input {
-                width: 100%;
-                max-width: 100%;
-                min-width: auto;
-            }
-
-            .question-actions {
-                align-self: flex-end;
-            }
-        }
-    }
-}
-
-@media (max-width: $screen-sm) {
-    .questionAnswerInfo {
-        &-content {
-            padding: $spacing-md;
-        }
-    }
-
-    .form {
-        &-input-large,
-        &-textarea-large {
-            padding: $spacing-1;
-        }
-    }
-
-    .preset-questions {
-        .question-item {
-            .question-actions {
-                align-self: center;
-                width: 100%;
-                justify-content: center;
-            }
-        }
-    }
-}
+// ===== 创建/编辑表单组件样式 =====
+// 注意:
+// 1. 本样式文件只服务于 form 目录下的组件
+// 2. 不覆盖全局样式(.page-layout, .list-header 等)
+// 3. 使用局部类名避免冲突

+ 23 - 21
jk-rag-platform/src/pages/system/audit/index.tsx

@@ -5,6 +5,13 @@ import { SearchOutlined, EyeOutlined, CheckCircleOutlined, CloseCircleOutlined }
 import { useAuditStore } from './store';
 import { useAuditStore } from './store';
 import './style.scss';
 import './style.scss';
 
 
+// ===== 审核状态配置(使用设计规范颜色)=====
+const STATUS_CONFIG = {
+    pending: { text: '待审核', color: '#F59E0B' },    // 警告色
+    approved: { text: '已通过', color: '#059669' },   // 成功色(加深)
+    rejected: { text: '已拒绝', color: '#DC2626' },   // 错误色(加深)
+};
+
 interface AuditItem {
 interface AuditItem {
     id: string;
     id: string;
     appId: string;
     appId: string;
@@ -82,12 +89,7 @@ const AuditPage: React.FC = () => {
 
 
     // 状态标签渲染
     // 状态标签渲染
     const renderStatusBadge = (status: string) => {
     const renderStatusBadge = (status: string) => {
-        const statusMap: Record<string, { text: string; color: string }> = {
-            pending: { text: '待审核', color: '#F59E0B' },
-            approved: { text: '已通过', color: '#059669' },
-            rejected: { text: '已拒绝', color: '#DC2626' },
-        };
-        const config = statusMap[status] || { text: status, color: '#6B7280' };
+        const config = STATUS_CONFIG[status] || { text: status, color: '#6B7280' };
         return <Tag color={config.color}>{config.text}</Tag>;
         return <Tag color={config.color}>{config.text}</Tag>;
     };
     };
 
 
@@ -100,8 +102,8 @@ const AuditPage: React.FC = () => {
             width: 200,
             width: 200,
             render: (text: string, record: AuditItem) => (
             render: (text: string, record: AuditItem) => (
                 <div>
                 <div>
-                    <div style={{ fontWeight: 500, color: '#1F2937' }}>{text}</div>
-                    <div style={{ fontSize: '12px', color: '#6B7280', marginTop: '4px' }}>
+                    <div style={{ fontWeight: 500, color: 'var(--text-primary)' }}>{text}</div>
+                    <div style={{ fontSize: '12px', color: 'var(--text-secondary)', marginTop: '4px' }}>
                         {record.appDescription}
                         {record.appDescription}
                     </div>
                     </div>
                 </div>
                 </div>
@@ -115,7 +117,7 @@ const AuditPage: React.FC = () => {
             render: (text: string, record: AuditItem) => (
             render: (text: string, record: AuditItem) => (
                 <div>
                 <div>
                     <div>{text}</div>
                     <div>{text}</div>
-                    <div style={{ fontSize: '12px', color: '#9CA3AF' }}>{record.department}</div>
+                    <div style={{ fontSize: '12px', color: 'var(--text-hint)' }}>{record.department}</div>
                 </div>
                 </div>
             ),
             ),
         },
         },
@@ -189,7 +191,7 @@ const AuditPage: React.FC = () => {
                                 size="small"
                                 size="small"
                                 type="primary"
                                 type="primary"
                                 icon={<CheckCircleOutlined />}
                                 icon={<CheckCircleOutlined />}
-                                style={{ background: '#059669', borderColor: '#059669' }}
+                                style={{ background: 'var(--success-color)', borderColor: 'var(--success-color)' }}
                                 onClick={() => handleOpenAuditModal(record, 'approve')}
                                 onClick={() => handleOpenAuditModal(record, 'approve')}
                             >
                             >
                                 通过
                                 通过
@@ -214,34 +216,34 @@ const AuditPage: React.FC = () => {
             {/* 统计卡片 */}
             {/* 统计卡片 */}
             <div className="audit-stats">
             <div className="audit-stats">
                 <div className="content-section" style={{ textAlign: 'center' }}>
                 <div className="content-section" style={{ textAlign: 'center' }}>
-                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: '#1F2937' }}>
+                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: 'var(--text-primary)' }}>
                         {stats?.total || 0}
                         {stats?.total || 0}
                     </div>
                     </div>
-                    <div style={{ fontSize: '13px', color: '#6B7280', marginTop: '4px' }}>
+                    <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginTop: '4px' }}>
                         总审核数
                         总审核数
                     </div>
                     </div>
                 </div>
                 </div>
                 <div className="content-section" style={{ textAlign: 'center' }}>
                 <div className="content-section" style={{ textAlign: 'center' }}>
-                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: '#F59E0B' }}>
+                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: 'var(--warning-color)' }}>
                         {stats?.pending || 0}
                         {stats?.pending || 0}
                     </div>
                     </div>
-                    <div style={{ fontSize: '13px', color: '#6B7280', marginTop: '4px' }}>
+                    <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginTop: '4px' }}>
                         待审核
                         待审核
                     </div>
                     </div>
                 </div>
                 </div>
                 <div className="content-section" style={{ textAlign: 'center' }}>
                 <div className="content-section" style={{ textAlign: 'center' }}>
-                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: '#059669' }}>
+                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: 'var(--success-color)' }}>
                         {stats?.approved || 0}
                         {stats?.approved || 0}
                     </div>
                     </div>
-                    <div style={{ fontSize: '13px', color: '#6B7280', marginTop: '4px' }}>
+                    <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginTop: '4px' }}>
                         已通过
                         已通过
                     </div>
                     </div>
                 </div>
                 </div>
                 <div className="content-section" style={{ textAlign: 'center' }}>
                 <div className="content-section" style={{ textAlign: 'center' }}>
-                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: '#DC2626' }}>
+                    <div style={{ fontSize: '28px', fontWeight: 'bold', color: 'var(--error-color)' }}>
                         {stats?.rejected || 0}
                         {stats?.rejected || 0}
                     </div>
                     </div>
-                    <div style={{ fontSize: '13px', color: '#6B7280', marginTop: '4px' }}>
+                    <div style={{ fontSize: '13px', color: 'var(--text-secondary)', marginTop: '4px' }}>
                         已拒绝
                         已拒绝
                     </div>
                     </div>
                 </div>
                 </div>
@@ -344,7 +346,7 @@ const AuditPage: React.FC = () => {
                 cancelText="取消"
                 cancelText="取消"
                 okButtonProps={{
                 okButtonProps={{
                     danger: auditActionType === 'reject',
                     danger: auditActionType === 'reject',
-                    style: auditActionType === 'reject' ? {} : { background: '#059669', borderColor: '#059669' },
+                    style: auditActionType === 'reject' ? {} : { background: 'var(--success-color)', borderColor: 'var(--success-color)' },
                 }}
                 }}
             >
             >
                 <div style={{ marginBottom: '16px' }}>
                 <div style={{ marginBottom: '16px' }}>
@@ -355,7 +357,7 @@ const AuditPage: React.FC = () => {
                 </div>
                 </div>
                 <div style={{ marginBottom: '16px' }}>
                 <div style={{ marginBottom: '16px' }}>
                     <strong>应用描述:</strong>
                     <strong>应用描述:</strong>
-                    <p style={{ color: '#6B7280', fontSize: '13px' }}>{currentAudit?.appDescription}</p>
+                    <p style={{ color: 'var(--text-secondary)', fontSize: '13px' }}>{currentAudit?.appDescription}</p>
                 </div>
                 </div>
                 <Form form={auditForm} layout="vertical">
                 <Form form={auditForm} layout="vertical">
                     <Form.Item
                     <Form.Item
@@ -431,7 +433,7 @@ const AuditPage: React.FC = () => {
                         {currentAudit.auditOpinion && (
                         {currentAudit.auditOpinion && (
                             <div className="detail-section">
                             <div className="detail-section">
                                 <h4 className="section-title">审核意见</h4>
                                 <h4 className="section-title">审核意见</h4>
-                                <p style={{ color: '#6B7280', fontSize: '13px' }}>
+                                <p style={{ color: 'var(--text-secondary)', fontSize: '13px' }}>
                                     {currentAudit.auditOpinion}
                                     {currentAudit.auditOpinion}
                                 </p>
                                 </p>
                             </div>
                             </div>

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

@@ -1,4 +1,5 @@
-@import '@/styles/variables.scss';
+@use '@/styles/variables.scss' as *;
+// 导入全局样式变量
 
 
 .audit-page {
 .audit-page {
     .audit-stats {
     .audit-stats {

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

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

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

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

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

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

+ 145 - 30
jk-rag-platform/src/styles/global.scss

@@ -1,5 +1,5 @@
+@use './variables.scss' as *;
 // Variables imported via main entry point with @/ alias
 // Variables imported via main entry point with @/ alias
-@import './variables.scss';
 
 
 // ===== 隐藏式滚动条(全局) =====
 // ===== 隐藏式滚动条(全局) =====
 // 适用于所有内容区域,保持界面简洁
 // 适用于所有内容区域,保持界面简洁
@@ -46,14 +46,35 @@ body {
     color: $theme-text-color !important;
     color: $theme-text-color !important;
     // Ant-Design 主题 - 属性
     // Ant-Design 主题 - 属性
     --primary-color: $primary-color;
     --primary-color: $primary-color;
+    --primary-light: $primary-light;
+    --primary-dark: $primary-dark;
     --text-color: $theme-text-color;
     --text-color: $theme-text-color;
+    --text-primary: $text-primary;
+    --text-secondary: $text-secondary;
+    --text-hint: $text-hint;
+    --text-disabled: $text-disabled;
     --border-radius: $border-radius-base;
     --border-radius: $border-radius-base;
+    --success-color: $success-color;
+    --success-light: $success-light;
+    --success-dark: $success-dark;
+    --warning-color: $warning-color;
+    --warning-light: $warning-light;
+    --warning-dark: $warning-dark;
+    --error-color: $error-color;
+    --error-light: $error-light;
+    --error-dark: $error-dark;
+    --info-color: $info-color;
+    --bg-primary: $bg-primary;
+    --bg-secondary: $bg-secondary;
+    --bg-tertiary: $bg-tertiary;
+    --border-base: $border-base;
+    --border-light: $border-light;
     background: $bg-primary; /* 设置背景色 */
     background: $bg-primary; /* 设置背景色 */
-    
+
     // 隐藏滚动条
     // 隐藏滚动条
     scrollbar-width: none; // Firefox
     scrollbar-width: none; // Firefox
     -ms-overflow-style: none; // IE/Edge
     -ms-overflow-style: none; // IE/Edge
-    
+
     &::-webkit-scrollbar {
     &::-webkit-scrollbar {
         display: none; // Chrome/Safari/Opera
         display: none; // Chrome/Safari/Opera
     }
     }
@@ -200,44 +221,81 @@ ul li {
     border: none !important;
     border: none !important;
 }
 }
 
 
-// 全局按钮样式
+// 全局按钮样式 - 覆盖 Ant Design 默认样式
 .ant-btn {
 .ant-btn {
     border-radius: $radius-lg;  // 8px - follow global specs
     border-radius: $radius-lg;  // 8px - follow global specs
+    transition: $transition-base;
 
 
+    // Primary 按钮
     &.ant-btn-primary {
     &.ant-btn-primary {
-        background: $primary-color;
-        border: 1px solid $primary-color;
-        color: #ffffff;
-        transition: $transition-base;
+        background: $primary-color !important;
+        border-color: $primary-color !important;
+        color: #ffffff !important;
         box-shadow: $shadow-sm;
         box-shadow: $shadow-sm;
 
 
         &:hover {
         &:hover {
-            background: $primary-light;
-            border-color: $primary-light;
-            color: #ffffff;
+            background: $primary-light !important;
+            border-color: $primary-light !important;
+            color: #ffffff !important;
+            box-shadow: $shadow-md;
         }
         }
 
 
         &:active {
         &:active {
-            background: $primary-dark;
-            border-color: $primary-dark;
-            color: #ffffff;
+            background: $primary-dark !important;
+            border-color: $primary-dark !important;
+            color: #ffffff !important;
             box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
             box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
-            transform: translateY(0);
         }
         }
 
 
-        &:focus {
-            background: $primary-color;
-            border-color: $primary-color;
-            color: #ffffff;
-            box-shadow: 0 0 0 2px rgba($primary-color, 0.2);
+        &:disabled {
+            background: $bg-tertiary !important;
+            border-color: $border-base !important;
+            color: $text-disabled !important;
+            box-shadow: none !important;
         }
         }
+    }
 
 
-        &:disabled {
+    // Default 按钮
+    &.ant-btn-default {
+        background: $bg-secondary;
+        border-color: $border-base;
+        color: $text-primary;
+
+        &:hover {
+            border-color: $primary-light;
+            color: $primary-light;
+        }
+
+        &:active {
+            border-color: $primary-dark;
+            color: $primary-dark;
+        }
+    }
+
+    // Text 按钮
+    &.ant-btn-text {
+        color: $text-primary;
+
+        &:hover {
             background: $bg-tertiary;
             background: $bg-tertiary;
-            border-color: $border-base;
-            color: $text-disabled;
-            box-shadow: none;
-            transform: none;
+            color: $primary-color;
+        }
+
+        &:active {
+            color: $primary-dark;
+        }
+    }
+
+    // Link 按钮
+    &.ant-btn-link {
+        color: $primary-color;
+
+        &:hover {
+            color: $primary-light;
+        }
+
+        &:active {
+            color: $primary-dark;
         }
         }
     }
     }
 }
 }
@@ -412,6 +470,15 @@ ul li {
 
 
 // 弹出框
 // 弹出框
 .ant-popover {
 .ant-popover {
+    .ant-popover-arrow {
+        width: 10px;
+        height: 10px;
+
+        &::before {
+            background: $bg-secondary;
+        }
+    }
+
     .ant-popover-inner {
     .ant-popover-inner {
         border-radius: $radius-lg !important;
         border-radius: $radius-lg !important;
         box-shadow: $shadow-lg !important;
         box-shadow: $shadow-lg !important;
@@ -424,11 +491,59 @@ ul li {
 
 
 // 工具提示
 // 工具提示
 .ant-tooltip {
 .ant-tooltip {
+    // 箭头 - Ant Design 5.x 使用 ::after 伪元素创建三角形
+    .ant-tooltip-arrow {
+        &::after {
+            position: absolute;
+            width: 0;
+            height: 0;
+            border: 5px solid transparent;
+            content: '';
+        }
+    }
+
+    // 上方 tooltip - 箭头向下
+    &.ant-tooltip-placement-top,
+    &[class*='placement-top'] {
+        .ant-tooltip-arrow::after {
+            border-top: none;
+            border-bottom-color: $text-primary !important;
+        }
+    }
+
+    // 下方 tooltip - 箭头向上
+    &.ant-tooltip-placement-bottom,
+    &[class*='placement-bottom'] {
+        .ant-tooltip-arrow::after {
+            border-bottom: none;
+            border-top-color: $text-primary !important;
+        }
+    }
+
+    // 左侧 tooltip - 箭头向右
+    &.ant-tooltip-placement-left,
+    &[class*='placement-left'] {
+        .ant-tooltip-arrow::after {
+            border-left: none;
+            border-right-color: $text-primary !important;
+        }
+    }
+
+    // 右侧 tooltip - 箭头向左
+    &.ant-tooltip-placement-right,
+    &[class*='placement-right'] {
+        .ant-tooltip-arrow::after {
+            border-right: none;
+            border-left-color: $text-primary !important;
+        }
+    }
+
     .ant-tooltip-inner {
     .ant-tooltip-inner {
         border-radius: $radius-md !important;
         border-radius: $radius-md !important;
-        background: $text-primary;
-        padding: $spacing-2 $spacing-3;
-        font-size: $font-sm;
+        background: $text-primary !important;
+        padding: $spacing-2 $spacing-3 !important;
+        font-size: $font-sm !important;
+        color: $bg-secondary !important;
     }
     }
 }
 }
 
 
@@ -549,7 +664,7 @@ ul li {
 .filter-btn {
 .filter-btn {
     width: $search-height;
     width: $search-height;
     height: $search-height;
     height: $search-height;
-    border: 1px solid rgba(0, 122, 153, 0.6);
+    border: 1px solid rgba($primary-light, 0.6);
     background: $icon-bg-blue;
     background: $icon-bg-blue;
     border-radius: $radius-xl;
     border-radius: $radius-xl;
     display: flex;
     display: flex;
@@ -557,7 +672,7 @@ ul li {
     justify-content: center;
     justify-content: center;
     cursor: pointer;
     cursor: pointer;
     transition: $transition-base;
     transition: $transition-base;
-    
+
     .iconify {
     .iconify {
         font-size: $icon-lg;
         font-size: $icon-lg;
         color: $primary-color;
         color: $primary-color;

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

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

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

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

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