From 1455cc850d7ed0950988d9eb0dd6b5c6fc30658b Mon Sep 17 00:00:00 2001
From: lanyuanxiaoyao
Date: Fri, 27 Mar 2026 18:46:34 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=A1=B5=E9=9D=A2=E7=8A=B6?=
=?UTF-8?q?=E6=80=81=E7=94=B1=20URL=20=E8=B7=AF=E7=94=B1=E9=A9=B1=E5=8A=A8?=
=?UTF-8?q?=20-=20=E7=A7=BB=E9=99=A4=20usePageState/useNavigation/hooks/co?=
=?UTF-8?q?nstants=EF=BC=8C=E6=94=B9=E7=94=A8=E5=B5=8C=E5=A5=97=E8=B7=AF?=
=?UTF-8?q?=E7=94=B1=20+=20useParams?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 109 ++++-----
openspec/config.yaml | 4 +
.../specs/unified-state-management/spec.md | 32 +--
src/App.jsx | 96 +++++++-
src/components/layout/AdminLayout.jsx | 92 ++++++++
src/components/layout/ConsoleLayout.jsx | 99 ++++++++
src/components/layout/DeveloperLayout.jsx | 84 +++++++
src/constants/pages.js | 61 -----
src/constants/storageKeys.js | 25 --
src/hooks/useLocalStorage.js | 25 --
src/hooks/useNavigation.js | 50 ----
src/hooks/usePageState.js | 58 -----
src/pages/AdminPage.jsx | 192 ---------------
src/pages/ConsolePage.jsx | 219 ------------------
src/pages/DeveloperPage.jsx | 180 --------------
src/pages/HomePage.jsx | 2 +-
src/pages/LoginPage.jsx | 2 +-
src/pages/admin/AddDepartmentPage.jsx | 11 +-
src/pages/admin/AddModelConfigPage.jsx | 12 +-
src/pages/admin/AddProjectPage.jsx | 11 +-
src/pages/admin/AddUserPage.jsx | 11 +-
src/pages/admin/AdminProjectsPage.jsx | 8 +-
src/pages/admin/DepartmentsPage.jsx | 8 +-
src/pages/admin/ModelConfigsPage.jsx | 8 +-
src/pages/admin/UsersPage.jsx | 8 +-
src/pages/console/AddMemberPage.jsx | 8 +-
src/pages/console/ChatPage.jsx | 7 +-
src/pages/console/ConsoleReviewDetailPage.jsx | 15 +-
src/pages/console/ConsoleReviewListPage.jsx | 8 +-
src/pages/console/MemberConfigPage.jsx | 13 +-
src/pages/console/MySkillsPage.jsx | 6 +-
src/pages/console/ProjectsPage.jsx | 8 +-
src/pages/console/SkillConfigPage.jsx | 13 +-
src/pages/console/SkillDetailPage.jsx | 9 +-
src/pages/console/SkillsPage.jsx | 6 +-
src/pages/console/TaskDetailPage.jsx | 11 +-
src/pages/console/TasksPage.jsx | 6 +-
src/pages/developer/DevOverviewPage.jsx | 6 +-
src/pages/developer/MySkillsPage.jsx | 8 +-
src/pages/developer/NewVersionPage.jsx | 58 -----
src/pages/developer/SkillEditorPage.jsx | 13 +-
src/pages/developer/UpdateSkillInfoPage.jsx | 13 +-
src/pages/developer/UploadSkillPage.jsx | 8 +-
src/pages/developer/UploadVersionPage.jsx | 12 +-
44 files changed, 587 insertions(+), 1048 deletions(-)
create mode 100644 src/components/layout/AdminLayout.jsx
create mode 100644 src/components/layout/ConsoleLayout.jsx
create mode 100644 src/components/layout/DeveloperLayout.jsx
delete mode 100644 src/constants/pages.js
delete mode 100644 src/constants/storageKeys.js
delete mode 100644 src/hooks/useLocalStorage.js
delete mode 100644 src/hooks/useNavigation.js
delete mode 100644 src/hooks/usePageState.js
delete mode 100644 src/pages/AdminPage.jsx
delete mode 100644 src/pages/ConsolePage.jsx
delete mode 100644 src/pages/DeveloperPage.jsx
delete mode 100644 src/pages/developer/NewVersionPage.jsx
diff --git a/README.md b/README.md
index 92acd2f..bbdf1d4 100644
--- a/README.md
+++ b/README.md
@@ -96,13 +96,11 @@ pnpm build # 验证打包(不运行pnpm dev,会挂起流程)
src/
├── components/ # 组件库
│ ├── common/ # 通用组件 (Modal, Toast, EmptyState等)
-│ ├── layout/ # 布局组件 (AppHeader, AppLayout, UserDropdown等)
+│ ├── layout/ # 布局组件 (AppHeader, AppLayout, UserDropdown, ConsoleLayout, AdminLayout, DeveloperLayout等)
│ ├── Layout.jsx # 主布局组件(sidebar + content)
│ └── ListSelector.jsx # 列表选择器
│
├── contexts/ # 全局状态 (UserContext)
-├── hooks/ # 自定义Hook (usePageState, useNavigation)
-├── constants/ # 常量配置 (pages, storageKeys)
├── services/ # 数据访问层 (api.js)
├── data/ # 模拟数据
│
@@ -279,7 +277,9 @@ export default Example;
## 路由规范
-### 顶层路由
+### 嵌套路由结构
+
+所有页面通过正式路由导航,使用 HashRouter + 嵌套路由。
```jsx
// App.jsx
@@ -288,9 +288,29 @@ export default Example;
} />
}>
} />
- } />
- } />
- } />
+
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+ {/* ...更多子路由 */}
+
+
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+ {/* ...更多子路由 */}
+
+
+ }>
+ } />
+ {/* ...子路由 */}
+
@@ -299,41 +319,33 @@ export default Example;
**说明**:
- `AppLayout` 包裹所有需要统一 Header 的页面
- 登录页独立,不使用 `AppLayout`
+- 每个模块(Console/Admin/Developer)使用独立的 Layout 组件包裹 ``
+- 模块根路径自动重定向到默认子页面
+- 新增/编辑表单通过 URL 参数区分:`/admin/departments/add` vs `/admin/departments/:id/edit`
-### 子页面路由
-
-每个主页面内部管理子页面:
+### 子页面参数获取
```jsx
-// ConsolePage.jsx示例
-const [currentPage, setCurrentPage] = useState('chat');
-
-const renderPage = () => {
- switch (currentPage) {
- case 'chat': return ;
- case 'skills': return ;
- // ...
- }
-};
-```
-
-### 页面配置
-
-```javascript
-// constants/pages.js
-export const CONSOLE_PAGES = {
- chat: { title: '智能助手', icon: 'FiMessageSquare' },
- skills: { title: '技能市场', icon: 'FaPuzzlePiece' },
+// 使用 useParams 获取 URL 参数
+function SkillDetailPage() {
+ const { skillId } = useParams();
+ const skill = api.skills.getById(Number(skillId));
// ...
-};
+}
+
+// 使用 useNavigate 进行导航
+function SkillsPage() {
+ const navigate = useNavigate();
+ return ;
+}
```
### 新增页面流程
-1. 在 `constants/pages.js` 添加页面配置
-2. 在父页面组件导入新页面
-3. 在 `renderPage()` 添加case分支
-4. 添加导航项(如需要)
+1. 在 `App.jsx` 添加路由定义
+2. 创建页面组件(使用 `useParams` / `useNavigate`)
+3. 在对应 Layout 的 sidebar 添加导航项
+4. 确保页面返回按钮使用固定路径导航
---
@@ -351,28 +363,17 @@ function Component() {
}
```
-### 页面状态持久化
+### 页面状态由 URL 驱动
-| 模块 | localStorage键 | 默认值 |
-|------|---------------|--------|
-| 工作台 | `console_currentPage` | `'chat'` |
-| 管理台 | `admin_currentPage` | `'overview'` |
-| 开发台 | `developer_currentPage` | `'overview'` |
+所有页面状态(当前页面、场景名、实体 ID)通过 URL 参数驱动,不依赖 localStorage。
-### 自定义Hook
-
-```javascript
-// usePageState - 页面状态持久化
-const { currentPage, setCurrentPage } = usePageState({
- storageKey: CONSOLE_KEYS.CURRENT_PAGE,
- defaultPage: 'chat',
- pageTitles: CONSOLE_PAGES,
-});
-
-// useNavigation - 导航逻辑
-const { navigateToPage, extraData } = useNavigation(setCurrentPage);
-navigateToPage('skillDetail', { skillId: '1' });
-```
+| 状态类型 | 驱动方式 | 示例 |
+|---------|---------|------|
+| 当前页面 | URL 路径 | `/console/skills` |
+| 实体 ID | URL 参数 | `/console/skills/:skillId` |
+| 场景名 | URL 参数 | `/console/chat/:scene` |
+| 新增/编辑模式 | URL 参数有无 | `/admin/users/add` vs `/admin/users/:id/edit` |
+| 编辑数据 | `api.getById(Number(id))` | 通过 ID 重新获取 |
---
diff --git a/openspec/config.yaml b/openspec/config.yaml
index 2c7374b..1ddf838 100644
--- a/openspec/config.yaml
+++ b/openspec/config.yaml
@@ -14,3 +14,7 @@ context: |
- **优先阅读README.md**,README.md文档是项目的开发文档,记录代码结构和关键开发模式,优先读取获取上下文
- 涉及页面/路由/组件/功能模块变更或技术栈调整时,同步更新README.md
- Git提交: 仅中文; 格式为"类型: 简短描述",类型可选: feat(新功能)/fix(修复)/refactor(重构)/docs(文档)/style(格式)/test(测试)/chore(构建/工具); 多行描述空行后加详细说明; 禁创建git操作task
+
+rules:
+ proposal:
+ - 仔细审查每一个过往spec判断是否存在Modified Capabilities
diff --git a/openspec/specs/unified-state-management/spec.md b/openspec/specs/unified-state-management/spec.md
index 27911e7..a06d459 100644
--- a/openspec/specs/unified-state-management/spec.md
+++ b/openspec/specs/unified-state-management/spec.md
@@ -2,7 +2,7 @@
## Purpose
-提供统一的状态管理方案,包括全局用户信息上下文、页面状态持久化、导航逻辑管理,确保应用状态的一致性和可维护性。
+提供统一的全局用户信息上下文,确保应用状态的一致性和可维护性。页面状态和导航逻辑由 URL 路由驱动。
## Requirements
@@ -20,33 +20,3 @@
#### Scenario: UserContext 提供默认值
- **WHEN** 应用启动且没有提供用户信息
- **THEN** 系统使用默认用户信息(name: '张三', avatar: '张', role: 'AI 产品部')
-
-### Requirement: 页面状态持久化 Hook
-系统 SHALL 提供 usePageState Hook,封装页面状态持久化逻辑,自动处理 localStorage 同步和主页跳转重置。
-
-#### Scenario: usePageState 初始化从 localStorage 恢复状态
-- **WHEN** 页面使用 usePageState Hook 并传入 storageKey 和 defaultPage
-- **THEN** 系统从 localStorage 读取之前保存的页面状态,若无则使用 defaultPage
-
-#### Scenario: usePageState 自动同步状态到 localStorage
-- **WHEN** 调用 usePageState 返回的 setCurrentPage 函数
-- **THEN** 系统更新状态并自动保存到 localStorage
-
-#### Scenario: usePageState 处理主页跳转重置
-- **WHEN** 从主页跳转到页面(location.state.fromHome 为 true)
-- **THEN** 系统重置页面状态为默认值,并清除路由 state
-
-#### Scenario: usePageState 提供 getPageTitle 函数
-- **WHEN** 调用 usePageState 返回的 getPageTitle 函数
-- **THEN** 系统根据当前页面 ID 从配置中查找并返回对应的页面标题
-
-### Requirement: 导航逻辑 Hook
-系统 SHALL 提供 useNavigation Hook,统一处理页面导航和路由状态管理。
-
-#### Scenario: useNavigation 提供页面切换函数
-- **WHEN** 调用 useNavigation 返回的 navigateToPage 函数并传入目标页面 ID
-- **THEN** 系统更新当前页面状态并执行相应导航逻辑
-
-#### Scenario: useNavigation 处理带数据的页面切换
-- **WHEN** 调用 navigateToPage 并传入目标页面 ID 和附加数据(如 skillId)
-- **THEN** 系统更新页面状态和附加数据状态
diff --git a/src/App.jsx b/src/App.jsx
index 18ec7b0..1245922 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,11 +1,47 @@
-import { HashRouter as Router, Routes, Route } from 'react-router-dom';
+import { HashRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { UserProvider } from './contexts/UserContext.jsx';
import AppLayout from './components/layout/AppLayout.jsx';
+import ConsoleLayout from './components/layout/ConsoleLayout.jsx';
+import AdminLayout from './components/layout/AdminLayout.jsx';
+import DeveloperLayout from './components/layout/DeveloperLayout.jsx';
import HomePage from './pages/HomePage.jsx';
import LoginPage from './pages/LoginPage.jsx';
-import ConsolePage from './pages/ConsolePage.jsx';
-import AdminPage from './pages/AdminPage.jsx';
-import DeveloperPage from './pages/DeveloperPage.jsx';
+
+// Console 子页面
+import ChatPage from './pages/console/ChatPage.jsx';
+import SkillsPage from './pages/console/SkillsPage.jsx';
+import SkillDetailPage from './pages/console/SkillDetailPage.jsx';
+import ConsoleMySkillsPage from './pages/console/MySkillsPage.jsx';
+import SkillConfigPage from './pages/console/SkillConfigPage.jsx';
+import LogsPage from './pages/console/LogsPage.jsx';
+import TasksPage from './pages/console/TasksPage.jsx';
+import TaskDetailPage from './pages/console/TaskDetailPage.jsx';
+import ProjectsPage from './pages/console/ProjectsPage.jsx';
+import MemberConfigPage from './pages/console/MemberConfigPage.jsx';
+import AddMemberPage from './pages/console/AddMemberPage.jsx';
+import ConsoleReviewListPage from './pages/console/ConsoleReviewListPage.jsx';
+import ConsoleReviewDetailPage from './pages/console/ConsoleReviewDetailPage.jsx';
+
+// Admin 子页面
+import OverviewPage from './pages/admin/OverviewPage.jsx';
+import DepartmentsPage from './pages/admin/DepartmentsPage.jsx';
+import AddDepartmentPage from './pages/admin/AddDepartmentPage.jsx';
+import UsersPage from './pages/admin/UsersPage.jsx';
+import AddUserPage from './pages/admin/AddUserPage.jsx';
+import AdminProjectsPage from './pages/admin/AdminProjectsPage.jsx';
+import AddProjectPage from './pages/admin/AddProjectPage.jsx';
+import AdminLogsPage from './pages/admin/AdminLogsPage.jsx';
+import ModelConfigsPage from './pages/admin/ModelConfigsPage.jsx';
+import AddModelConfigPage from './pages/admin/AddModelConfigPage.jsx';
+
+// Developer 子页面
+import DevOverviewPage from './pages/developer/DevOverviewPage.jsx';
+import DeveloperMySkillsPage from './pages/developer/MySkillsPage.jsx';
+import UploadSkillPage from './pages/developer/UploadSkillPage.jsx';
+import SkillEditorPage from './pages/developer/SkillEditorPage.jsx';
+import UploadVersionPage from './pages/developer/UploadVersionPage.jsx';
+import UpdateSkillInfoPage from './pages/developer/UpdateSkillInfoPage.jsx';
+import DevDocsPage from './pages/developer/DevDocsPage.jsx';
function App() {
return (
@@ -15,9 +51,53 @@ function App() {
} />
}>
} />
- } />
- } />
- } />
+
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
@@ -25,4 +105,4 @@ function App() {
);
}
-export default App;
\ No newline at end of file
+export default App;
diff --git a/src/components/layout/AdminLayout.jsx b/src/components/layout/AdminLayout.jsx
new file mode 100644
index 0000000..b67fc26
--- /dev/null
+++ b/src/components/layout/AdminLayout.jsx
@@ -0,0 +1,92 @@
+import { Outlet, useLocation, useNavigate } from 'react-router-dom';
+import { FiHome, FiBarChart2, FiUsers, FiList, FiCheckCircle, FiActivity, FiSettings } from 'react-icons/fi';
+import Layout from '../Layout.jsx';
+import SidebarNavItem from './SidebarNavItem.jsx';
+
+function AdminLayout() {
+ const location = useLocation();
+ const navigate = useNavigate();
+
+ const isPathActive = (basePath) => location.pathname.startsWith(basePath);
+
+ const sidebar = (
+ <>
+
+ >
+ );
+
+ return (
+
+
+
+ );
+}
+
+export default AdminLayout;
diff --git a/src/components/layout/ConsoleLayout.jsx b/src/components/layout/ConsoleLayout.jsx
new file mode 100644
index 0000000..887becd
--- /dev/null
+++ b/src/components/layout/ConsoleLayout.jsx
@@ -0,0 +1,99 @@
+import { Outlet, useLocation, useNavigate } from 'react-router-dom';
+import { FiPlus, FiClock, FiList, FiUsers, FiBox } from 'react-icons/fi';
+import { FaPuzzlePiece } from 'react-icons/fa';
+import Layout from '../Layout.jsx';
+import SidebarNavItem from './SidebarNavItem.jsx';
+import api from '../../services/api.js';
+
+function ConsoleLayout() {
+ const location = useLocation();
+ const navigate = useNavigate();
+
+ // 从 URL 提取当前 scene
+ const sceneMatch = location.pathname.match(/\/console\/chat\/(.+)$/);
+ const currentScene = sceneMatch ? sceneMatch[1] : null;
+
+ // 判断是否在 chat 页面(需要全宽布局)
+ const isChatPage = location.pathname === '/console/chat' ||
+ location.pathname.startsWith('/console/chat/');
+
+ // sidebar 高亮判断
+ const isPathActive = (basePath) => location.pathname.startsWith(basePath);
+
+ const sidebar = (
+ <>
+
+
+
+
+ {api.conversations.list().map(conv => (
+
navigate(`/console/chat/${conv.scene}`)}
+ >
+
{conv.title}
+
{conv.time}
+
+ ))}
+
+
+
+
+
+
+ }
+ label="技能市场"
+ active={isPathActive('/console/skills')}
+ onClick={() => navigate('/console/skills')}
+ />
+ }
+ label="我的技能"
+ active={isPathActive('/console/my-skills')}
+ onClick={() => navigate('/console/my-skills')}
+ />
+ }
+ label="定时任务"
+ active={isPathActive('/console/tasks')}
+ onClick={() => navigate('/console/tasks')}
+ />
+ }
+ label="日志查询"
+ active={isPathActive('/console/logs')}
+ onClick={() => navigate('/console/logs')}
+ />
+ }
+ label="项目管理"
+ active={isPathActive('/console/projects')}
+ onClick={() => navigate('/console/projects')}
+ />
+
+ >
+ );
+
+ return (
+
+
+
+ );
+}
+
+export default ConsoleLayout;
diff --git a/src/components/layout/DeveloperLayout.jsx b/src/components/layout/DeveloperLayout.jsx
new file mode 100644
index 0000000..7e3a306
--- /dev/null
+++ b/src/components/layout/DeveloperLayout.jsx
@@ -0,0 +1,84 @@
+import { Outlet, useLocation, useNavigate } from 'react-router-dom';
+import { FiPlus, FiTerminal, FiHome } from 'react-icons/fi';
+import { FaPuzzlePiece } from 'react-icons/fa';
+import Layout from '../Layout.jsx';
+import SidebarNavItem from './SidebarNavItem.jsx';
+import api from '../../services/api.js';
+
+const skillStatusMap = {
+ dev: { text: '开发中', className: 'status-stopped' },
+ published: { text: '已上架', className: 'status-running' },
+ unlisting: { text: '下架审核中', className: 'status-warning' },
+ unlisted: { text: '已下架', className: 'status-stopped' }
+};
+
+function DeveloperLayout() {
+ const location = useLocation();
+ const navigate = useNavigate();
+
+ const isPathActive = (basePath) => location.pathname.startsWith(basePath);
+
+ // 获取当前技能编辑器中的 skillId
+ const editorMatch = location.pathname.match(/\/developer\/my-skills\/(\d+)\/editor$/);
+ const activeSkillId = editorMatch ? parseInt(editorMatch[1]) : null;
+
+ const sidebar = (
+ <>
+
+
+
+
+ {api.developer.getMySkills().map(skill => (
+
navigate(`/developer/my-skills/${skill.id}/editor`)}
+ >
+
{skill.name}
+
+
+ {skillStatusMap[skill.status]?.text || skill.status}
+
+
+
+ ))}
+
+
+ }
+ label="总览"
+ active={location.pathname === '/developer/overview'}
+ onClick={() => navigate('/developer/overview')}
+ />
+ }
+ label="我的技能"
+ active={isPathActive('/developer/my-skills')}
+ onClick={() => navigate('/developer/my-skills')}
+ />
+ }
+ label="开发文档"
+ active={location.pathname === '/developer/docs'}
+ onClick={() => navigate('/developer/docs')}
+ />
+
+ >
+ );
+
+ return (
+
+
+
+ );
+}
+
+export default DeveloperLayout;
diff --git a/src/constants/pages.js b/src/constants/pages.js
deleted file mode 100644
index 61e0c31..0000000
--- a/src/constants/pages.js
+++ /dev/null
@@ -1,61 +0,0 @@
-// 页面配置常量
-
-/**
- * 工作台页面配置
- */
-export const CONSOLE_PAGES = {
- chat: { title: '智能助手', icon: 'FiMessageSquare' },
- skills: { title: '技能市场', icon: 'FaPuzzlePiece' },
- skillDetail: { title: '技能详情', icon: null },
- mySkills: { title: '我的技能', icon: 'FiBox' },
- skillConfig: { title: '技能配置', icon: null },
- logs: { title: '日志查询', icon: 'FiList' },
- scheduledTasks: { title: '定时任务', icon: 'FiClock' },
- taskDetail: { title: '任务详情', icon: null },
- account: { title: '账号管理', icon: 'FiUser' },
- projects: { title: '项目管理', icon: 'FiUsers' },
- memberConfig: { title: '成员配置', icon: null },
- addMember: { title: '增加成员', icon: null },
-};
-
-/**
- * 管理台页面配置
- */
-export const ADMIN_PAGES = {
- overview: { title: '总览', icon: 'FiHome' },
- departments: { title: '部门管理', icon: 'FiBarChart2' },
- users: { title: '用户管理', icon: 'FiUsers' },
- projects: { title: '项目管理', icon: 'FiList' },
- modelConfigs: { title: '模型配置', icon: 'FiSettings' },
- adminLogs: { title: '日志查询', icon: 'FiActivity' },
- reviewList: { title: '审核管理', icon: 'FiCheckCircle' },
- reviewDetail: { title: '审核详情', icon: null },
- addDepartment: { title: '新增部门', icon: null },
- addUser: { title: '新增用户', icon: null },
- addProject: { title: '新增项目', icon: null },
- addModelConfig: { title: '新增配置', icon: null },
- account: { title: '账号管理', icon: 'FiUser' },
-};
-
-/**
- * 开发台页面配置
- */
-export const DEVELOPER_PAGES = {
- overview: { title: '总览', icon: 'FiHome' },
- mySkills: { title: '我的技能', icon: 'FaPuzzlePiece' },
- uploadSkill: { title: '创建技能', icon: 'FiPlus' },
- newVersion: { title: '上传新版本', icon: null },
- devDocs: { title: '开发文档', icon: 'FiTerminal' },
- devAccount: { title: '账号管理', icon: 'FiSettings' },
- skillEditor: { title: '技能详情', icon: null },
-};
-
-/**
- * 获取页面标题
- * @param {string} pageId - 页面ID
- * @param {Object} pagesConfig - 页面配置对象
- * @returns {string} 页面标题
- */
-export function getPageTitle(pageId, pagesConfig) {
- return pagesConfig[pageId]?.title || '';
-}
diff --git a/src/constants/storageKeys.js b/src/constants/storageKeys.js
deleted file mode 100644
index 2aa4b1b..0000000
--- a/src/constants/storageKeys.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// localStorage 键名常量
-
-/**
- * 工作台相关键名
- */
-export const CONSOLE_KEYS = {
- CURRENT_PAGE: 'console_currentPage',
- CURRENT_SCENE: 'console_currentScene',
-};
-
-/**
- * 管理台相关键名
- */
-export const ADMIN_KEYS = {
- CURRENT_PAGE: 'admin_currentPage',
- MODEL_CONFIG_EDIT_DATA: 'admin_modelConfigEditData',
-};
-
-/**
- * 开发台相关键名
- */
-export const DEVELOPER_KEYS = {
- CURRENT_PAGE: 'developer_currentPage',
- CURRENT_SKILL_ID: 'developer_currentSkillId',
-};
diff --git a/src/hooks/useLocalStorage.js b/src/hooks/useLocalStorage.js
deleted file mode 100644
index 7c717c4..0000000
--- a/src/hooks/useLocalStorage.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { useState, useEffect } from 'react';
-
-function useLocalStorage(key, initialValue) {
- const [value, setValue] = useState(() => {
- try {
- const saved = localStorage.getItem(key);
- return saved ? JSON.parse(saved) : initialValue;
- } catch (error) {
- console.warn(`Error reading localStorage key "${key}":`, error);
- return initialValue;
- }
- });
-
- useEffect(() => {
- try {
- localStorage.setItem(key, JSON.stringify(value));
- } catch (error) {
- console.warn(`Error setting localStorage key "${key}":`, error);
- }
- }, [key, value]);
-
- return [value, setValue];
-}
-
-export default useLocalStorage;
\ No newline at end of file
diff --git a/src/hooks/useNavigation.js b/src/hooks/useNavigation.js
deleted file mode 100644
index aa1da25..0000000
--- a/src/hooks/useNavigation.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { useState, useCallback } from 'react';
-
-/**
- * 导航逻辑 Hook
- * 统一处理页面导航和附加数据状态管理
- *
- * @param {Function} setPageCallback - 设置当前页面的回调函数
- * @returns {Object} 导航操作函数
- */
-function useNavigation(setPageCallback) {
- const [extraData, setExtraData] = useState({});
-
- /**
- * 导航到指定页面
- * @param {string} pageId - 目标页面 ID
- * @param {Object} data - 附加数据(如 skillId、taskId 等)
- */
- const navigateToPage = useCallback((pageId, data = {}) => {
- setPageCallback(pageId);
-
- // 如果有附加数据,更新 extraData
- if (Object.keys(data).length > 0) {
- setExtraData(data);
- }
- }, [setPageCallback]);
-
- /**
- * 设置附加数据
- * @param {Object} data - 附加数据对象
- */
- const setExtraDataValue = useCallback((data) => {
- setExtraData(prev => ({ ...prev, ...data }));
- }, []);
-
- /**
- * 清除附加数据
- */
- const clearExtraData = useCallback(() => {
- setExtraData({});
- }, []);
-
- return {
- extraData,
- navigateToPage,
- setExtraData: setExtraDataValue,
- clearExtraData,
- };
-}
-
-export default useNavigation;
diff --git a/src/hooks/usePageState.js b/src/hooks/usePageState.js
deleted file mode 100644
index 8294bc5..0000000
--- a/src/hooks/usePageState.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import { useState, useEffect } from 'react';
-import { useLocation, useNavigate } from 'react-router-dom';
-
-/**
- * 页面状态持久化 Hook
- * 封装页面状态管理、localStorage 同步和主页跳转重置逻辑
- *
- * @param {Object} options - 配置选项
- * @param {string} options.storageKey - localStorage 存储键名
- * @param {string} options.defaultPage - 默认页面 ID
- * @param {Object} options.pageTitles - 页面标题映射对象
- * @param {Function} options.getPageTitle - 自定义获取页面标题函数(可选)
- * @returns {Object} 状态和操作函数
- */
-function usePageState({
- storageKey,
- defaultPage,
- pageTitles,
- getPageTitle: customGetPageTitle,
-}) {
- const location = useLocation();
- const navigate = useNavigate();
-
- // 从 localStorage 恢复或使用默认值
- const [currentPage, setCurrentPage] = useState(() => {
- const saved = localStorage.getItem(`${storageKey}_currentPage`);
- return saved || defaultPage;
- });
-
- // 处理主页跳转重置
- useEffect(() => {
- if (location.state?.fromHome) {
- setCurrentPage(defaultPage);
- navigate('.', { replace: true, state: {} });
- }
- }, [location.state, navigate, defaultPage]);
-
- // 同步到 localStorage
- useEffect(() => {
- localStorage.setItem(`${storageKey}_currentPage`, currentPage);
- }, [storageKey, currentPage]);
-
- // 获取页面标题
- const getPageTitle = (pageId = currentPage) => {
- if (customGetPageTitle) {
- return customGetPageTitle(pageId, currentPage);
- }
- return pageTitles[pageId] || '';
- };
-
- return {
- currentPage,
- setCurrentPage,
- getPageTitle,
- };
-}
-
-export default usePageState;
diff --git a/src/pages/AdminPage.jsx b/src/pages/AdminPage.jsx
deleted file mode 100644
index d0bc7f0..0000000
--- a/src/pages/AdminPage.jsx
+++ /dev/null
@@ -1,192 +0,0 @@
-import { useState, useEffect } from 'react';
-import { useLocation, useNavigate } from 'react-router-dom';
-import { FiHome, FiBarChart2, FiUsers, FiList, FiCheckCircle, FiActivity, FiSettings } from 'react-icons/fi';
-import Layout from '../components/Layout.jsx';
-import SidebarNavItem from '../components/layout/SidebarNavItem.jsx';
-import usePageState from '../hooks/usePageState.js';
-import { ADMIN_PAGES } from '../constants/pages.js';
-import { ADMIN_KEYS } from '../constants/storageKeys.js';
-import OverviewPage from './admin/OverviewPage.jsx';
-import DepartmentsPage from './admin/DepartmentsPage.jsx';
-import UsersPage from './admin/UsersPage.jsx';
-import AdminProjectsPage from './admin/AdminProjectsPage.jsx';
-import AddDepartmentPage from './admin/AddDepartmentPage.jsx';
-import AddUserPage from './admin/AddUserPage.jsx';
-import AddProjectPage from './admin/AddProjectPage.jsx';
-import AdminLogsPage from './admin/AdminLogsPage.jsx';
-import ConsoleReviewListPage from './console/ConsoleReviewListPage.jsx';
-import ConsoleReviewDetailPage from './console/ConsoleReviewDetailPage.jsx';
-import ModelConfigsPage from './admin/ModelConfigsPage.jsx';
-import AddModelConfigPage from './admin/AddModelConfigPage.jsx';
-
-function AdminPage() {
- const location = useLocation();
- const navigate = useNavigate();
-
- const { currentPage, setCurrentPage } = usePageState({
- storageKey: ADMIN_KEYS.CURRENT_PAGE,
- defaultPage: 'overview',
- pageTitles: ADMIN_PAGES,
- });
-
- const [editData, setEditData] = useState(null);
- const [reviewType, setReviewType] = useState(null);
- const [reviewId, setReviewId] = useState(null);
-
- const navigateTo = (page, data) => {
- setEditData(data || null);
- setCurrentPage(page);
- };
-
- const handleReviewClick = (type, id) => {
- setReviewType(type);
- setReviewId(id);
- navigateTo('reviewDetail');
- };
-
- const handleReviewBack = () => {
- setReviewType(null);
- setReviewId(null);
- navigateTo('reviewList');
- };
-
- const renderPage = () => {
- switch (currentPage) {
- case 'overview':
- return ;
- case 'departments':
- return navigateTo('addDepartment')}
- onEdit={(dept) => navigateTo('addDepartment', dept)}
- />;
- case 'users':
- return navigateTo('addUser')}
- onEdit={(user) => navigateTo('addUser', user)}
- />;
- case 'projects':
- return navigateTo('addProject')}
- onEdit={(project) => navigateTo('addProject', project)}
- />;
- case 'adminLogs':
- return ;
- case 'reviewList':
- return ;
- case 'reviewDetail':
- return ;
- case 'addDepartment':
- return navigateTo('departments')}
- editData={editData}
- />;
- case 'addUser':
- return navigateTo('users')}
- editData={editData}
- />;
- case 'addProject':
- return navigateTo('projects')}
- editData={editData}
- />;
- case 'modelConfigs':
- return navigateTo('addModelConfig')}
- onEdit={(config) => navigateTo('addModelConfig', config)}
- />;
- case 'addModelConfig':
- return navigateTo('modelConfigs')}
- editData={editData}
- />;
- default:
- return Page not found
;
- }
- };
-
- const sidebar = (
- <>
-
- >
- );
-
- return (
-
- {renderPage()}
-
- );
-}
-
-export default AdminPage;
diff --git a/src/pages/ConsolePage.jsx b/src/pages/ConsolePage.jsx
deleted file mode 100644
index ef664a4..0000000
--- a/src/pages/ConsolePage.jsx
+++ /dev/null
@@ -1,219 +0,0 @@
-import { useState, useEffect } from 'react';
-import { useLocation, useNavigate } from 'react-router-dom';
-import { FiPlus, FiClock, FiList, FiUsers, FiBox } from 'react-icons/fi';
-import { FaPuzzlePiece } from 'react-icons/fa';
-import Layout from '../components/Layout.jsx';
-import SidebarNavItem from '../components/layout/SidebarNavItem.jsx';
-import usePageState from '../hooks/usePageState.js';
-import { CONSOLE_PAGES } from '../constants/pages.js';
-import { CONSOLE_KEYS } from '../constants/storageKeys.js';
-import api from '../services/api.js';
-import ChatPage from './console/ChatPage.jsx';
-import SkillsPage from './console/SkillsPage.jsx';
-import SkillDetailPage from './console/SkillDetailPage.jsx';
-import MySkillsPage from './console/MySkillsPage.jsx';
-import SkillConfigPage from './console/SkillConfigPage.jsx';
-import LogsPage from './console/LogsPage.jsx';
-import TasksPage from './console/TasksPage.jsx';
-import TaskDetailPage from './console/TaskDetailPage.jsx';
-import ProjectsPage from './console/ProjectsPage.jsx';
-import MemberConfigPage from './console/MemberConfigPage.jsx';
-import AddMemberPage from './console/AddMemberPage.jsx';
-
-function ConsolePage() {
- const location = useLocation();
- const navigate = useNavigate();
-
- // 使用 usePageState 管理 currentPage(不使用其返回的 getPageTitle,因为需要访问组件局部变量)
- const { currentPage, setCurrentPage } = usePageState({
- storageKey: CONSOLE_KEYS.CURRENT_PAGE,
- defaultPage: 'chat',
- pageTitles: CONSOLE_PAGES,
- });
-
- // 保留额外的状态(scene 和 skillId 等需要特殊处理)
- const [currentScene, setCurrentScene] = useState(() => {
- return localStorage.getItem(CONSOLE_KEYS.CURRENT_SCENE) || 'welcome';
- });
- const [currentSkillId, setCurrentSkillId] = useState(null);
- const [currentTaskId, setCurrentTaskId] = useState(null);
- const [currentSubscriptionId, setCurrentSubscriptionId] = useState(null);
-
- // 处理主页跳转重置
- useEffect(() => {
- if (location.state?.fromHome) {
- setCurrentPage('chat');
- setCurrentScene('welcome');
- navigate('.', { replace: true, state: {} });
- }
- }, [location.state, navigate, setCurrentPage, setCurrentScene]);
-
- // 同步 currentScene 到 localStorage
- useEffect(() => {
- localStorage.setItem(CONSOLE_KEYS.CURRENT_SCENE, currentScene);
- }, [currentScene]);
-
- const switchPage = (pageId, data = {}) => {
- setCurrentPage(pageId);
- if (data.skillId !== undefined) {
- setCurrentSkillId(data.skillId);
- }
- if (data.subscriptionId !== undefined) {
- setCurrentSubscriptionId(data.subscriptionId);
- }
- };
-
- const handleSkillClick = (skillId) => {
- switchPage('skillDetail', { skillId });
- };
-
- const handleBack = () => {
- switchPage('skills');
- };
-
- const switchChatScene = (scene) => {
- setCurrentScene(scene);
- if (currentPage !== 'chat') {
- setCurrentPage('chat');
- }
- };
-
- const createNewChat = () => {
- setCurrentScene('welcome');
- setCurrentPage('chat');
- };
-
- const activeScene = currentPage === 'chat' ? currentScene : null;
-
- const renderPage = () => {
- switch (currentPage) {
- case 'chat':
- return ;
- case 'skills':
- return ;
- case 'skillDetail':
- return ;
- case 'mySkills':
- return switchPage('skillConfig', { subscriptionId })}
- onBack={() => switchPage('skills')}
- />;
- case 'skillConfig':
- return switchPage('mySkills')}
- />;
- case 'logs':
- return ;
- case 'scheduledTasks':
- return {
- setCurrentTaskId(taskId);
- switchPage('taskDetail');
- }}
- />;
- case 'taskDetail':
- return switchPage('scheduledTasks')}
- />;
- case 'projects':
- return switchPage('addMember')} />;
- case 'memberConfig':
- return switchPage('projects')} />;
- case 'addMember':
- return switchPage('projects')} />;
- default:
- return Page not found
;
- }
- };
-
- const getPageTitle = () => {
- let title = CONSOLE_PAGES[currentPage]?.title || '';
- if (currentPage === 'chat') {
- const conv = api.conversations.list().find(c => c.scene === currentScene);
- title = conv?.title || '智能助手';
- }
- if (currentPage === 'skillDetail' && currentSkillId) {
- const skill = api.skills.getById(currentSkillId);
- title = skill?.name || '技能详情';
- }
- return title;
- };
-
- const sidebar = (
- <>
-
-
-
-
- {api.conversations.list().map(conv => (
-
switchChatScene(conv.scene)}
- >
-
{conv.title}
-
{conv.time}
-
- ))}
-
-
-
-
-
-
- }
- label="技能市场"
- active={currentPage === 'skills'}
- onClick={() => switchPage('skills')}
- />
- }
- label="我的技能"
- active={currentPage === 'mySkills'}
- onClick={() => switchPage('mySkills')}
- />
- }
- label="定时任务"
- active={currentPage === 'scheduledTasks'}
- onClick={() => switchPage('scheduledTasks')}
- />
- }
- label="日志查询"
- active={currentPage === 'logs'}
- onClick={() => switchPage('logs')}
- />
- }
- label="项目管理"
- active={currentPage === 'projects'}
- onClick={() => switchPage('projects')}
- />
-
- >
- );
-
- return (
-
- {renderPage()}
-
- );
-}
-
-export default ConsolePage;
\ No newline at end of file
diff --git a/src/pages/DeveloperPage.jsx b/src/pages/DeveloperPage.jsx
deleted file mode 100644
index 2c0ebfd..0000000
--- a/src/pages/DeveloperPage.jsx
+++ /dev/null
@@ -1,180 +0,0 @@
-import { useState, useEffect } from 'react';
-import { useLocation, useNavigate } from 'react-router-dom';
-import { FiPlus, FiTerminal, FiHome } from 'react-icons/fi';
-import { FaPuzzlePiece } from 'react-icons/fa';
-import Layout from '../components/Layout.jsx';
-import SidebarNavItem from '../components/layout/SidebarNavItem.jsx';
-import usePageState from '../hooks/usePageState.js';
-import { DEVELOPER_PAGES } from '../constants/pages.js';
-import { DEVELOPER_KEYS } from '../constants/storageKeys.js';
-import api from '../services/api.js';
-import DevOverviewPage from './developer/DevOverviewPage.jsx';
-import MySkillsPage from './developer/MySkillsPage.jsx';
-import UploadSkillPage from './developer/UploadSkillPage.jsx';
-import NewVersionPage from './developer/NewVersionPage.jsx';
-import DevDocsPage from './developer/DevDocsPage.jsx';
-import SkillEditorPage from './developer/SkillEditorPage.jsx';
-import UpdateSkillInfoPage from './developer/UpdateSkillInfoPage.jsx';
-import UploadVersionPage from './developer/UploadVersionPage.jsx';
-
-const skillStatusMap = {
- dev: { text: '开发中', className: 'status-stopped' },
- published: { text: '已上架', className: 'status-running' },
- unlisting: { text: '下架审核中', className: 'status-warning' },
- unlisted: { text: '已下架', className: 'status-stopped' }
-};
-
-function DeveloperPage() {
- const location = useLocation();
- const navigate = useNavigate();
-
- // 使用 usePageState 管理页面状态
- const { currentPage, setCurrentPage } = usePageState({
- storageKey: DEVELOPER_KEYS.CURRENT_PAGE,
- defaultPage: 'overview',
- pageTitles: DEVELOPER_PAGES,
- });
-
- // 保留额外的状态(currentSkillId 需要持久化到 localStorage)
- const [currentSkillId, setCurrentSkillId] = useState(() => {
- const saved = localStorage.getItem(DEVELOPER_KEYS.CURRENT_SKILL_ID);
- return saved ? JSON.parse(saved) : null;
- });
- const [newVersionSkillName, setNewVersionSkillName] = useState('');
-
- useEffect(() => {
- if (location.state?.fromHome) {
- setCurrentPage('overview');
- setCurrentSkillId(null);
- navigate('.', { replace: true, state: {} });
- }
- }, [location.state, navigate, setCurrentPage, setCurrentSkillId]);
-
- useEffect(() => {
- localStorage.setItem(DEVELOPER_KEYS.CURRENT_SKILL_ID, JSON.stringify(currentSkillId));
- }, [DEVELOPER_KEYS.CURRENT_SKILL_ID, currentSkillId]);
-
- const switchPage = (pageId, data = {}) => {
- setCurrentPage(pageId);
- if (data.skillId !== undefined) {
- setCurrentSkillId(data.skillId);
- }
- };
-
- const openSkillEditor = (skillId) => {
- setCurrentSkillId(skillId);
- setCurrentPage('skillEditor');
- };
-
- const createNewProject = () => {
- setCurrentPage('uploadSkill');
- };
-
- const openNewVersionPage = (skillName) => {
- setNewVersionSkillName(skillName);
- setCurrentPage('newVersion');
- };
-
- const openUpdateInfoPage = (skillId) => {
- setCurrentSkillId(skillId);
- setCurrentPage('updateInfo');
- };
-
- const handleBack = () => {
- setCurrentPage('mySkills');
- setCurrentSkillId(null);
- };
-
- const handleEditorBack = () => {
- setCurrentPage('skillEditor');
- setNewVersionSkillName('');
- };
-
- const renderPage = () => {
- switch (currentPage) {
- case 'overview':
- return ;
- case 'mySkills':
- return ;
- case 'uploadSkill':
- return switchPage('mySkills')} />;
- case 'devDocs':
- return ;
- case 'skillEditor':
- return ;
- case 'newVersion':
- return ;
- case 'updateInfo':
- return ;
- default:
- return Page not found
;
- }
- };
-
- const sidebar = (
- <>
-
-
-
-
- {api.developer.getMySkills().map(skill => (
-
openSkillEditor(skill.id)}
- >
-
{skill.name}
-
-
- {skillStatusMap[skill.status]?.text || skill.status}
-
-
-
- ))}
-
-
- }
- label="总览"
- active={currentPage === 'overview'}
- onClick={() => switchPage('overview')}
- />
- }
- label="我的技能"
- active={currentPage === 'mySkills'}
- onClick={() => switchPage('mySkills')}
- />
- }
- label="开发文档"
- active={currentPage === 'devDocs'}
- onClick={() => switchPage('devDocs')}
- />
-
- >
- );
-
- return (
-
- {renderPage()}
-
- );
-}
-
-export default DeveloperPage;
diff --git a/src/pages/HomePage.jsx b/src/pages/HomePage.jsx
index c82f71b..01d451a 100644
--- a/src/pages/HomePage.jsx
+++ b/src/pages/HomePage.jsx
@@ -15,7 +15,7 @@ function HomePage() {
基于容器化实例的 智能助手平台,提供租户隔离、技能市场、安全审计等核心能力
-
+
进入工作台
diff --git a/src/pages/LoginPage.jsx b/src/pages/LoginPage.jsx
index 13bb589..bb7c59a 100644
--- a/src/pages/LoginPage.jsx
+++ b/src/pages/LoginPage.jsx
@@ -112,7 +112,7 @@ function LoginPage() {
diff --git a/src/pages/admin/AddDepartmentPage.jsx b/src/pages/admin/AddDepartmentPage.jsx
index 4293dc3..2533fe6 100644
--- a/src/pages/admin/AddDepartmentPage.jsx
+++ b/src/pages/admin/AddDepartmentPage.jsx
@@ -1,8 +1,13 @@
import { useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
import ListSelector from '../../components/ListSelector.jsx';
import { availableLeaders } from '../../data/adminData.js';
+import { api } from '../../services/api.js';
-function AddDepartmentPage({ onBack, editData }) {
+function AddDepartmentPage() {
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const editData = id ? api.admin.departments.getById(Number(id)) : null;
const isEdit = !!editData;
const [name, setName] = useState(editData?.name || '');
const [description, setDescription] = useState(editData?.description || '');
@@ -22,7 +27,7 @@ function AddDepartmentPage({ onBack, editData }) {
return (
<>
-
+
navigate('/admin/departments')}>
←
返回部门列表
@@ -53,7 +58,7 @@ function AddDepartmentPage({ onBack, editData }) {
/>
-
+
diff --git a/src/pages/admin/AddModelConfigPage.jsx b/src/pages/admin/AddModelConfigPage.jsx
index f33077e..5f894da 100644
--- a/src/pages/admin/AddModelConfigPage.jsx
+++ b/src/pages/admin/AddModelConfigPage.jsx
@@ -1,9 +1,13 @@
import { useState, useEffect } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
import { FiEye, FiEyeOff } from 'react-icons/fi';
import { api } from '../../services/api.js';
import { MODEL_CONFIG_TYPES, getConfigFields, getConfigTypeList } from '../../data/configTypes.js';
-function AddModelConfigPage({ onBack, editData }) {
+function AddModelConfigPage() {
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const editData = id ? api.admin.modelConfigs.getById(id) : null;
const isEdit = !!editData;
// 基础信息
@@ -98,7 +102,7 @@ function AddModelConfigPage({ onBack, editData }) {
api.admin.modelConfigs.create(configData);
}
- onBack();
+ navigate('/admin/models');
};
// 获取当前类型的字段定义
@@ -107,7 +111,7 @@ function AddModelConfigPage({ onBack, editData }) {
return (
<>
-
+
navigate('/admin/models')}>
←
返回配置列表
@@ -215,7 +219,7 @@ function AddModelConfigPage({ onBack, editData }) {
{/* 操作按钮 */}
-
+
diff --git a/src/pages/admin/AddProjectPage.jsx b/src/pages/admin/AddProjectPage.jsx
index 64507b8..c38359a 100644
--- a/src/pages/admin/AddProjectPage.jsx
+++ b/src/pages/admin/AddProjectPage.jsx
@@ -1,8 +1,13 @@
import { useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
import ListSelector from '../../components/ListSelector.jsx';
import { availableLeaders } from '../../data/adminData.js';
+import { api } from '../../services/api.js';
-function AddProjectPage({ onBack, editData }) {
+function AddProjectPage() {
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const editData = id ? api.admin.projects.getById(Number(id)) : null;
const isEdit = !!editData;
const [name, setName] = useState(editData?.name || '');
const [description, setDescription] = useState(editData?.description || '');
@@ -22,7 +27,7 @@ function AddProjectPage({ onBack, editData }) {
return (
<>
-
+
navigate('/admin/projects')}>
←
返回项目列表
@@ -53,7 +58,7 @@ function AddProjectPage({ onBack, editData }) {
/>
-
+
diff --git a/src/pages/admin/AddUserPage.jsx b/src/pages/admin/AddUserPage.jsx
index 66ef137..9f06d74 100644
--- a/src/pages/admin/AddUserPage.jsx
+++ b/src/pages/admin/AddUserPage.jsx
@@ -1,8 +1,13 @@
import { useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
import ListSelector from '../../components/ListSelector.jsx';
import { availableDepartments } from '../../data/adminData.js';
+import { api } from '../../services/api.js';
-function AddUserPage({ onBack, editData }) {
+function AddUserPage() {
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const editData = id ? api.admin.users.getById(Number(id)) : null;
const isEdit = !!editData;
const [name, setName] = useState(editData?.name || '');
const [role, setRole] = useState(editData?.role || '成员');
@@ -24,7 +29,7 @@ function AddUserPage({ onBack, editData }) {
return (
<>
-
+
navigate('/admin/users')}>
←
返回用户列表
@@ -67,7 +72,7 @@ function AddUserPage({ onBack, editData }) {
setPhone(e.target.value)} />
-
+
diff --git a/src/pages/admin/AdminProjectsPage.jsx b/src/pages/admin/AdminProjectsPage.jsx
index 5f83a21..4c5c273 100644
--- a/src/pages/admin/AdminProjectsPage.jsx
+++ b/src/pages/admin/AdminProjectsPage.jsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { api } from '../../services/api.js';
import Modal from '../../components/common/Modal.jsx';
@@ -7,7 +8,8 @@ function StatusTag({ status }) {
return {status};
}
-function AdminProjectsPage({ onAdd, onEdit }) {
+function AdminProjectsPage() {
+ const navigate = useNavigate();
const sourceData = api.admin.projects.list();
const [filters, setFilters] = useState({ keyword: '', status: '' });
const [deleteTarget, setDeleteTarget] = useState(null);
@@ -71,7 +73,7 @@ function AdminProjectsPage({ onAdd, onEdit }) {
项目列表
-
+
@@ -99,7 +101,7 @@ function AdminProjectsPage({ onAdd, onEdit }) {
-
+
|
diff --git a/src/pages/admin/DepartmentsPage.jsx b/src/pages/admin/DepartmentsPage.jsx
index bc879e3..b905715 100644
--- a/src/pages/admin/DepartmentsPage.jsx
+++ b/src/pages/admin/DepartmentsPage.jsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { api } from '../../services/api.js';
import Modal from '../../components/common/Modal.jsx';
@@ -7,7 +8,8 @@ function StatusTag({ status }) {
return
{status};
}
-function DepartmentsPage({ onAdd, onEdit }) {
+function DepartmentsPage() {
+ const navigate = useNavigate();
const sourceData = api.admin.departments.list();
const [filters, setFilters] = useState({ keyword: '', status: '' });
const [deleteTarget, setDeleteTarget] = useState(null);
@@ -71,7 +73,7 @@ function DepartmentsPage({ onAdd, onEdit }) {
部门列表
-
+
@@ -99,7 +101,7 @@ function DepartmentsPage({ onAdd, onEdit }) {
-
+
|
diff --git a/src/pages/admin/ModelConfigsPage.jsx b/src/pages/admin/ModelConfigsPage.jsx
index a12e583..95b1205 100644
--- a/src/pages/admin/ModelConfigsPage.jsx
+++ b/src/pages/admin/ModelConfigsPage.jsx
@@ -1,10 +1,12 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { FiPlus } from 'react-icons/fi';
import { api } from '../../services/api.js';
import { MODEL_CONFIG_TYPES, getConfigSummary } from '../../data/configTypes.js';
import Modal from '../../components/common/Modal.jsx';
-function ModelConfigsPage({ onAdd, onEdit }) {
+function ModelConfigsPage() {
+ const navigate = useNavigate();
const [configs, setConfigs] = useState(api.admin.modelConfigs.list());
const [showSetActiveModal, setShowSetActiveModal] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false);
@@ -44,7 +46,7 @@ function ModelConfigsPage({ onAdd, onEdit }) {
配置列表
-
@@ -85,7 +87,7 @@ function ModelConfigsPage({ onAdd, onEdit }) {
)}
onEdit(config)}
+ onClick={() => navigate(`/admin/models/${config.id}/edit`)}
disabled={config.isActive}
title={config.isActive ? '生效中的配置不可编辑' : ''}
style={config.isActive ? { opacity: 0.5, cursor: 'not-allowed' } : {}}
diff --git a/src/pages/admin/UsersPage.jsx b/src/pages/admin/UsersPage.jsx
index 315ce5f..b035cb6 100644
--- a/src/pages/admin/UsersPage.jsx
+++ b/src/pages/admin/UsersPage.jsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { api } from '../../services/api.js';
import Modal from '../../components/common/Modal.jsx';
@@ -12,7 +13,8 @@ function RoleTag({ role }) {
return {role};
}
-function UsersPage({ onAdd, onEdit }) {
+function UsersPage() {
+ const navigate = useNavigate();
const sourceData = api.admin.users.list();
const [filters, setFilters] = useState({ keyword: '', department: '', status: '' });
const [deleteTarget, setDeleteTarget] = useState(null);
@@ -94,7 +96,7 @@ function UsersPage({ onAdd, onEdit }) {
用户列表
-
新增用户
+
navigate('/admin/users/add')}>新增用户
@@ -124,7 +126,7 @@ function UsersPage({ onAdd, onEdit }) {
{user.status === '正常' ? '禁用' : '启用'}
- onEdit(user)}>编辑
+ navigate(`/admin/users/${user.id}/edit`)}>编辑
setDeleteTarget(user)}>删除
|
diff --git a/src/pages/console/AddMemberPage.jsx b/src/pages/console/AddMemberPage.jsx
index 0e578c9..70d005c 100644
--- a/src/pages/console/AddMemberPage.jsx
+++ b/src/pages/console/AddMemberPage.jsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import ListSelector from '../../components/ListSelector.jsx';
const availableMembers = [
@@ -12,7 +13,8 @@ const availableMembers = [
{ id: 8, name: '杨十八', department: '数据分析部', email: 'yangshiba@example.com' }
];
-function AddMemberPage({ onBack }) {
+function AddMemberPage() {
+ const navigate = useNavigate();
const [selectedMembers, setSelectedMembers] = useState([]);
const memberColumns = [
@@ -31,7 +33,7 @@ function AddMemberPage({ onBack }) {
return (
<>
-
+
navigate('/console/projects')}>
←
返回成员列表
@@ -51,7 +53,7 @@ function AddMemberPage({ onBack }) {
onClearSelected={() => setSelectedMembers([])}
/>
-
取消
+
navigate('/console/projects')}>取消
添加选中成员 ({selectedMembers.length})
diff --git a/src/pages/console/ChatPage.jsx b/src/pages/console/ChatPage.jsx
index 9c34c7a..48c74ca 100644
--- a/src/pages/console/ChatPage.jsx
+++ b/src/pages/console/ChatPage.jsx
@@ -1,10 +1,13 @@
import { useEffect, useRef } from 'react';
+import { useParams } from 'react-router-dom';
import { getChatScenes } from '../../data/conversations.js';
import { FiPaperclip, FiCode, FiSend } from 'react-icons/fi';
-function ChatPage({ scene }) {
+function ChatPage() {
+ const { scene } = useParams();
+ const currentScene = scene || 'welcome';
const chatScenes = getChatScenes();
- const html = chatScenes[scene] || '';
+ const html = chatScenes[currentScene] || '';
const chatMessagesRef = useRef(null);
useEffect(() => {
diff --git a/src/pages/console/ConsoleReviewDetailPage.jsx b/src/pages/console/ConsoleReviewDetailPage.jsx
index 624fc7f..efecb4c 100644
--- a/src/pages/console/ConsoleReviewDetailPage.jsx
+++ b/src/pages/console/ConsoleReviewDetailPage.jsx
@@ -1,14 +1,17 @@
import { useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
import { FiFile } from 'react-icons/fi';
import { pendingVersionReviews, pendingUnlistReviews, skillFiles } from '../../data/skills.js';
import Toast from '../../components/common/Toast.jsx';
-function ConsoleReviewDetailPage({ type, reviewId, onBack }) {
+function ConsoleReviewDetailPage() {
+ const { type, reviewId } = useParams();
+ const navigate = useNavigate();
const [showToast, setShowToast] = useState(false);
const [toastMessage, setToastMessage] = useState('');
- const versionReview = type === 'version' ? pendingVersionReviews.find(r => r.id === reviewId) : null;
- const unlistReview = type === 'unlist' ? pendingUnlistReviews.find(r => r.id === reviewId) : null;
+ const versionReview = type === 'version' ? pendingVersionReviews.find(r => r.id === Number(reviewId)) : null;
+ const unlistReview = type === 'unlist' ? pendingUnlistReviews.find(r => r.id === Number(reviewId)) : null;
const review = versionReview || unlistReview;
@@ -20,7 +23,7 @@ function ConsoleReviewDetailPage({ type, reviewId, onBack }) {
setToastMessage('审核通过');
setShowToast(true);
setTimeout(() => {
- onBack && onBack();
+ onBack && navigate('/admin/reviews');
}, 1000);
};
@@ -28,13 +31,13 @@ function ConsoleReviewDetailPage({ type, reviewId, onBack }) {
setToastMessage('已拒绝');
setShowToast(true);
setTimeout(() => {
- onBack && onBack();
+ onBack && navigate('/admin/reviews');
}, 1000);
};
return (
<>
-
+
navigate('/admin/reviews')}>
←
返回审核列表
diff --git a/src/pages/console/ConsoleReviewListPage.jsx b/src/pages/console/ConsoleReviewListPage.jsx
index 761b9fa..40e4877 100644
--- a/src/pages/console/ConsoleReviewListPage.jsx
+++ b/src/pages/console/ConsoleReviewListPage.jsx
@@ -1,7 +1,9 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { pendingVersionReviews, pendingUnlistReviews } from '../../data/skills.js';
-function ConsoleReviewListPage({ onReviewClick }) {
+function ConsoleReviewListPage() {
+ const navigate = useNavigate();
const [activeTab, setActiveTab] = useState('version');
return (
@@ -50,7 +52,7 @@ function ConsoleReviewListPage({ onReviewClick }) {
onReviewClick('version', review.id)}
+ onClick={() => navigate(`/admin/reviews/version/${review.id}`)}
>
审核
@@ -84,7 +86,7 @@ function ConsoleReviewListPage({ onReviewClick }) {
|
onReviewClick('unlist', review.id)}
+ onClick={() => navigate(`/admin/reviews/unlist/${review.id}`)}
>
审核
diff --git a/src/pages/console/MemberConfigPage.jsx b/src/pages/console/MemberConfigPage.jsx
index 5f04b88..7eb276f 100644
--- a/src/pages/console/MemberConfigPage.jsx
+++ b/src/pages/console/MemberConfigPage.jsx
@@ -1,7 +1,12 @@
-function MemberConfigPage({ onBack }) {
+import { useNavigate, useParams } from 'react-router-dom';
+
+function MemberConfigPage() {
+ const { memberId } = useParams();
+ const navigate = useNavigate();
+
return (
<>
-
+ navigate('/console/projects')}>
←
返回成员列表
@@ -10,11 +15,11 @@ function MemberConfigPage({ onBack }) {
成员配置
- 成员配置页面内容
+ 成员配置页面内容 (成员 ID: {memberId})
>
);
}
-export default MemberConfigPage;
\ No newline at end of file
+export default MemberConfigPage;
diff --git a/src/pages/console/MySkillsPage.jsx b/src/pages/console/MySkillsPage.jsx
index 8d9c629..be5cdc0 100644
--- a/src/pages/console/MySkillsPage.jsx
+++ b/src/pages/console/MySkillsPage.jsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { FiSearch } from 'react-icons/fi';
import { FaBoxOpen } from 'react-icons/fa';
import { skills, userSubscriptions } from '../../data/skills.js';
@@ -6,7 +7,8 @@ import EmptyState from '../../components/common/EmptyState.jsx';
import Modal from '../../components/common/Modal.jsx';
import Toast from '../../components/common/Toast.jsx';
-function MySkillsPage({ onConfig, onBack }) {
+function MySkillsPage() {
+ const navigate = useNavigate();
const [filters, setFilters] = useState({ keyword: '', category: '', status: '' });
const [subscriptions, setSubscriptions] = useState(userSubscriptions);
const [actionTarget, setActionTarget] = useState(null);
@@ -249,7 +251,7 @@ function MySkillsPage({ onConfig, onBack }) {
)}
onConfig(item.id)}
+ onClick={() => navigate(`/console/my-skills/${item.id}/config`)}
>
配置
diff --git a/src/pages/console/ProjectsPage.jsx b/src/pages/console/ProjectsPage.jsx
index a041ac3..850a18c 100644
--- a/src/pages/console/ProjectsPage.jsx
+++ b/src/pages/console/ProjectsPage.jsx
@@ -1,10 +1,12 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { FiUsers, FiSearch } from 'react-icons/fi';
import { projectMembers } from '../../data/members.js';
import EmptyState from '../../components/common/EmptyState.jsx';
import Modal from '../../components/common/Modal.jsx';
-function ProjectsPage({ onAddMember }) {
+function ProjectsPage() {
+ const navigate = useNavigate();
const [members, setMembers] = useState(projectMembers);
const [removeTarget, setRemoveTarget] = useState(null);
const [filters, setFilters] = useState({
@@ -82,7 +84,7 @@ function ProjectsPage({ onAddMember }) {
成员列表
- 增加成员
+ navigate('/console/projects/members/add')}>增加成员
{filteredMembers.length > 0 ? (
@@ -110,7 +112,7 @@ function ProjectsPage({ onAddMember }) {
{member.role} |
- 配置
+ navigate(`/console/projects/members/${member.id}/config`)}>配置
handleRemoveClick(member)}>移除
|
diff --git a/src/pages/console/SkillConfigPage.jsx b/src/pages/console/SkillConfigPage.jsx
index 9b1d303..3758128 100644
--- a/src/pages/console/SkillConfigPage.jsx
+++ b/src/pages/console/SkillConfigPage.jsx
@@ -1,9 +1,12 @@
import { useState, useEffect } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
import { FiPlus, FiX, FiUsers, FiStar, FiPackage } from 'react-icons/fi';
import { skills, userSubscriptions } from '../../data/skills.js';
import Toast from '../../components/common/Toast.jsx';
-function SkillConfigPage({ subscriptionId, onBack }) {
+function SkillConfigPage() {
+ const { subscriptionId } = useParams();
+ const navigate = useNavigate();
const [subscriptions, setSubscriptions] = useState(userSubscriptions);
const [subscription, setSubscription] = useState(null);
const [skill, setSkill] = useState(null);
@@ -12,7 +15,7 @@ function SkillConfigPage({ subscriptionId, onBack }) {
const [toast, setToast] = useState({ visible: false, type: 'success', message: '' });
useEffect(() => {
- const sub = subscriptions.find(s => s.id === subscriptionId);
+ const sub = subscriptions.find(s => s.id === Number(subscriptionId));
if (sub) {
setSubscription(sub);
const skillData = skills.find(s => s.id === sub.skillId);
@@ -82,7 +85,7 @@ function SkillConfigPage({ subscriptionId, onBack }) {
// 延迟返回
setTimeout(() => {
- onBack();
+ navigate('/console/my-skills');
}, 500);
};
@@ -94,7 +97,7 @@ function SkillConfigPage({ subscriptionId, onBack }) {
return (
<>
-
+ navigate('/console/my-skills')}>
←
返回我的技能
@@ -207,7 +210,7 @@ function SkillConfigPage({ subscriptionId, onBack }) {
)}
-
+ navigate('/console/my-skills')}>
取消
diff --git a/src/pages/console/SkillDetailPage.jsx b/src/pages/console/SkillDetailPage.jsx
index 840b256..edffd09 100644
--- a/src/pages/console/SkillDetailPage.jsx
+++ b/src/pages/console/SkillDetailPage.jsx
@@ -1,8 +1,11 @@
+import { useNavigate, useParams } from 'react-router-dom';
import { FiChevronLeft, FiFile, FiUsers, FiStar, FiPackage } from 'react-icons/fi';
import { skills, skillFiles } from '../../data/skills.js';
-function SkillDetailPage({ skillId, onBack }) {
- const skill = skills.find(s => s.id === skillId);
+function SkillDetailPage() {
+ const { skillId } = useParams();
+ const navigate = useNavigate();
+ const skill = skills.find(s => s.id === Number(skillId));
if (!skill) {
return Skill not found ;
@@ -12,7 +15,7 @@ function SkillDetailPage({ skillId, onBack }) {
return (
<>
-
+ navigate('/console/skills')} style={{ marginBottom: '16px' }}>
返回技能市场
{cv ? (
diff --git a/src/pages/console/SkillsPage.jsx b/src/pages/console/SkillsPage.jsx
index dc804f4..7c42daf 100644
--- a/src/pages/console/SkillsPage.jsx
+++ b/src/pages/console/SkillsPage.jsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { FiUser, FiStar, FiSearch } from 'react-icons/fi';
import { FaBoxOpen } from 'react-icons/fa';
import { skills, userSubscriptions } from '../../data/skills.js';
@@ -46,7 +47,8 @@ function SkillCard({ skill, onClick, onSubscribe }) {
);
}
-function SkillsPage({ onSkillClick }) {
+function SkillsPage() {
+ const navigate = useNavigate();
const [sort, setSort] = useState('subs');
const [searchQuery, setSearchQuery] = useState('');
const [subscriptions, setSubscriptions] = useState(userSubscriptions);
@@ -140,7 +142,7 @@ function SkillsPage({ onSkillClick }) {
onSkillClick(skill.id)}
+ onClick={() => navigate(`/console/skills/${skill.id}`)}
onSubscribe={handleSubscribeClick}
/>
))}
diff --git a/src/pages/console/TaskDetailPage.jsx b/src/pages/console/TaskDetailPage.jsx
index 1dfbcc8..9910baa 100644
--- a/src/pages/console/TaskDetailPage.jsx
+++ b/src/pages/console/TaskDetailPage.jsx
@@ -1,12 +1,15 @@
+import { useParams, useNavigate } from 'react-router-dom';
import { scheduledTasks } from '../../data/tasks.js';
-function TaskDetailPage({ taskId, onBack }) {
- const task = scheduledTasks.find(t => t.id === taskId);
+function TaskDetailPage() {
+ const { taskId } = useParams();
+ const navigate = useNavigate();
+ const task = scheduledTasks.find(t => t.id === Number(taskId));
if (!task) {
return (
<>
-
+ navigate('/console/tasks')}>
←
返回任务列表
@@ -24,7 +27,7 @@ function TaskDetailPage({ taskId, onBack }) {
return (
<>
-
+ navigate('/console/tasks')}>
←
返回任务列表
diff --git a/src/pages/console/TasksPage.jsx b/src/pages/console/TasksPage.jsx
index ee15a86..4567ef6 100644
--- a/src/pages/console/TasksPage.jsx
+++ b/src/pages/console/TasksPage.jsx
@@ -1,10 +1,12 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { FiClock } from 'react-icons/fi';
import { scheduledTasks } from '../../data/tasks.js';
import EmptyState from '../../components/common/EmptyState.jsx';
import Modal from '../../components/common/Modal.jsx';
-function TasksPage({ onViewDetail }) {
+function TasksPage() {
+ const navigate = useNavigate();
const [tasks, setTasks] = useState(scheduledTasks);
const [deleteTarget, setDeleteTarget] = useState(null);
@@ -66,7 +68,7 @@ function TasksPage({ onViewDetail }) {
toggleTask(task.id)}>
{task.enabled ? '禁用' : '启用'}
- onViewDetail(task.id)}>详情
+ navigate(`/console/tasks/${task.id}`)}>详情
handleDeleteClick(task)}>删除
|
diff --git a/src/pages/developer/DevOverviewPage.jsx b/src/pages/developer/DevOverviewPage.jsx
index 003708d..adb6ef2 100644
--- a/src/pages/developer/DevOverviewPage.jsx
+++ b/src/pages/developer/DevOverviewPage.jsx
@@ -1,7 +1,9 @@
+import { useNavigate } from 'react-router-dom';
import { FiAlertTriangle, FiInfo } from 'react-icons/fi';
import { api } from '../../services/api.js';
-function DevOverviewPage({ onSkillClick }) {
+function DevOverviewPage() {
+ const navigate = useNavigate();
const data = api.developer.getOverview();
return (
@@ -36,7 +38,7 @@ function DevOverviewPage({ onSkillClick }) {
key={index}
className={`anomaly-item ${item.status === 'rejected' ? 'anomaly-warning' : 'anomaly-info'}`}
style={{ cursor: 'pointer' }}
- onClick={() => onSkillClick && onSkillClick(item.skillId)}
+ onClick={() => navigate(`/developer/my-skills/${item.skillId}/editor`)}
>
{item.status === 'rejected' ? : }
diff --git a/src/pages/developer/MySkillsPage.jsx b/src/pages/developer/MySkillsPage.jsx
index df569a9..38a1eb5 100644
--- a/src/pages/developer/MySkillsPage.jsx
+++ b/src/pages/developer/MySkillsPage.jsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { api } from '../../services/api.js';
import Modal from '../../components/common/Modal.jsx';
import Toast from '../../components/common/Toast.jsx';
@@ -10,7 +11,8 @@ const skillStatusMap = {
unlisted: { text: '已下架', className: 'status-stopped' }
};
-function MySkillsPage({ onSkillClick }) {
+function MySkillsPage() {
+ const navigate = useNavigate();
const sourceData = api.developer.getMySkills();
const [filters, setFilters] = useState({ keyword: '', status: '' });
const [deleteTarget, setDeleteTarget] = useState(null);
@@ -100,7 +102,7 @@ function MySkillsPage({ onSkillClick }) {
{filteredList.map(skill => (
- onSkillClick(skill.id)}>
+
navigate(`/developer/my-skills/${skill.id}/editor`)}>
| {skill.name} |
{skill.desc} |
@@ -110,7 +112,7 @@ function MySkillsPage({ onSkillClick }) {
|
- { e.stopPropagation(); onSkillClick(skill.id); }}>
+ { e.stopPropagation(); navigate(`/developer/my-skills/${skill.id}/editor`); }}>
编辑
{skill.status === 'published' && (
diff --git a/src/pages/developer/NewVersionPage.jsx b/src/pages/developer/NewVersionPage.jsx
deleted file mode 100644
index c272130..0000000
--- a/src/pages/developer/NewVersionPage.jsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { useState } from 'react';
-import { FiUpload } from 'react-icons/fi';
-import Toast from '../../components/common/Toast.jsx';
-
-function NewVersionPage({ skillName, onBack }) {
- const [showToast, setShowToast] = useState(false);
-
- const handleSubmit = () => {
- setShowToast(true);
- setTimeout(() => {
- onBack();
- }, 1000);
- };
-
- return (
- <>
-
- ←
- 返回技能详情
-
-
-
-
-
-
-
-
-
-
-
-
- 点击或拖拽文件到此处上传
- 支持 .zip 格式
-
-
-
- 取消
- 提交审核
-
-
-
- setShowToast(false)}
- />
- >
- );
-}
-
-export default NewVersionPage;
diff --git a/src/pages/developer/SkillEditorPage.jsx b/src/pages/developer/SkillEditorPage.jsx
index c0ce267..f6d5353 100644
--- a/src/pages/developer/SkillEditorPage.jsx
+++ b/src/pages/developer/SkillEditorPage.jsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
import { FiUpload, FiUsers, FiPackage, FiStar, FiRotateCcw } from 'react-icons/fi';
import { api } from '../../services/api.js';
import Modal from '../../components/common/Modal.jsx';
@@ -18,8 +19,10 @@ const skillStatusMap = {
unlisted: { text: '已下架', className: 'status-stopped' }
};
-function SkillEditorPage({ skillId, onBack, onUploadNewVersion, onUpdateInfo }) {
- const skill = api.developer.getSkillById(skillId);
+function SkillEditorPage() {
+ const { skillId } = useParams();
+ const navigate = useNavigate();
+ const skill = api.developer.getSkillById(Number(skillId));
const [deleteSkillModal, setDeleteSkillModal] = useState(false);
const [unlistSkillModal, setUnlistSkillModal] = useState(false);
const [deleteVersionTarget, setDeleteVersionTarget] = useState(null);
@@ -50,7 +53,7 @@ function SkillEditorPage({ skillId, onBack, onUploadNewVersion, onUpdateInfo })
return (
<>
-
+ navigate('/developer/my-skills')}>
←
返回我的技能
@@ -64,7 +67,7 @@ function SkillEditorPage({ skillId, onBack, onUploadNewVersion, onUpdateInfo })
{skillStatusMap[skill.status]?.text || skill.status}
- onUpdateInfo && onUpdateInfo(skill.id)}>编辑内部信息
+ navigate(`/developer/my-skills/${skillId}/update-info`)}>编辑内部信息
@@ -121,7 +124,7 @@ function SkillEditorPage({ skillId, onBack, onUploadNewVersion, onUpdateInfo })
版本历史
onUploadNewVersion(skill)}
+ onClick={() => navigate(`/developer/my-skills/${skillId}/new-version`)}
disabled={skill.status === 'unlisting' || skill.status === 'unlisted' || skill.hasPendingReview}
title={skill.status === 'unlisted' ? '已下架的技能不能上传新版本' : (skill.status === 'unlisting' ? '下架审核中的技能不能上传新版本' : (skill.hasPendingReview ? '存在审核中的版本,请先撤回后再上传新版本' : ''))}
>
diff --git a/src/pages/developer/UpdateSkillInfoPage.jsx b/src/pages/developer/UpdateSkillInfoPage.jsx
index cf17f29..dff7d5d 100644
--- a/src/pages/developer/UpdateSkillInfoPage.jsx
+++ b/src/pages/developer/UpdateSkillInfoPage.jsx
@@ -1,7 +1,12 @@
import { useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
+import { api } from '../../services/api.js';
import Toast from '../../components/common/Toast.jsx';
-function UpdateSkillInfoPage({ skill, onBack }) {
+function UpdateSkillInfoPage() {
+ const { skillId } = useParams();
+ const navigate = useNavigate();
+ const skill = api.developer.getSkillById(Number(skillId));
const [name, setName] = useState(skill?.name || '');
const [desc, setDesc] = useState(skill?.desc || '');
const [showToast, setShowToast] = useState(false);
@@ -9,13 +14,13 @@ function UpdateSkillInfoPage({ skill, onBack }) {
const handleSave = () => {
setShowToast(true);
setTimeout(() => {
- onBack();
+ navigate(`/developer/my-skills/${skillId}/editor`);
}, 1000);
};
return (
<>
-
+ navigate(`/developer/my-skills/${skillId}/editor`)}>
←
返回技能详情
@@ -48,7 +53,7 @@ function UpdateSkillInfoPage({ skill, onBack }) {
/>
- 取消
+ navigate(`/developer/my-skills/${skillId}/editor`)}>取消
保存修改
diff --git a/src/pages/developer/UploadSkillPage.jsx b/src/pages/developer/UploadSkillPage.jsx
index 09b5520..52443ae 100644
--- a/src/pages/developer/UploadSkillPage.jsx
+++ b/src/pages/developer/UploadSkillPage.jsx
@@ -1,7 +1,9 @@
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import Toast from '../../components/common/Toast.jsx';
-function UploadSkillPage({ onBack }) {
+function UploadSkillPage() {
+ const navigate = useNavigate();
const [showToast, setShowToast] = useState(false);
const handleCreate = () => {
@@ -10,7 +12,7 @@ function UploadSkillPage({ onBack }) {
return (
<>
-
+ navigate('/developer/my-skills')}>
←
返回技能管理
@@ -31,7 +33,7 @@ function UploadSkillPage({ onBack }) {
- 取消
+ navigate('/developer/my-skills')}>取消
创建技能
diff --git a/src/pages/developer/UploadVersionPage.jsx b/src/pages/developer/UploadVersionPage.jsx
index df212b6..3480666 100644
--- a/src/pages/developer/UploadVersionPage.jsx
+++ b/src/pages/developer/UploadVersionPage.jsx
@@ -1,11 +1,15 @@
import { FiUpload, FiX } from 'react-icons/fi';
import { useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
import { api } from '../../services/api.js';
import Toast from '../../components/common/Toast.jsx';
const ICON_OPTIONS = ['🌤️', '📊', '📝', '🔧', '💻', '📋', '🔍', '📈', '🎯', '⚡', '🌐', '🤖'];
-function UploadVersionPage({ skill, onBack }) {
+function UploadVersionPage() {
+ const { skillId } = useParams();
+ const navigate = useNavigate();
+ const skill = api.developer.getSkillById(Number(skillId));
const categories = api.developer.getCategories();
const [showToast, setShowToast] = useState(false);
@@ -38,13 +42,13 @@ function UploadVersionPage({ skill, onBack }) {
const handleSubmit = () => {
setShowToast(true);
setTimeout(() => {
- onBack();
+ navigate(`/developer/my-skills/${skillId}/editor`);
}, 1000);
};
return (
<>
-
+ navigate(`/developer/my-skills/${skillId}/editor`)}>
←
返回技能详情
@@ -162,7 +166,7 @@ function UploadVersionPage({ skill, onBack }) {
- 取消
+ navigate(`/developer/my-skills/${skillId}/editor`)}>取消
提交审核
|