refactor: 统一二级页面返回按钮样式

- 新增 page-back-btn 统一样式类,替换 dev-back-btn 和 console-back-btn
- 所有二级页面返回按钮移至页面左上角
- 表单页面补充底部取消按钮
- 新增 page-navigation spec 文档
- 补充工作台 mySkills 和 skillConfig 页面标题配置
This commit is contained in:
2026-03-26 18:10:08 +08:00
parent 76d613c4fe
commit bc4537b3bc
18 changed files with 213 additions and 90 deletions

View File

@@ -7,6 +7,8 @@ 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 },

View File

@@ -21,10 +21,15 @@ function AddDepartmentPage({ onBack, editData }) {
: null;
return (
<div className="card">
<div className="card-header">
<div className="card-title">{isEdit ? '编辑部门' : '新增部门'}</div>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回部门列表</span>
</div>
<div className="card">
<div className="card-header">
<div className="card-title">{isEdit ? '编辑部门' : '新增部门'}</div>
</div>
<div className="card-body">
<div className="form-group">
<label className="form-label required">部门名称</label>
@@ -52,7 +57,8 @@ function AddDepartmentPage({ onBack, editData }) {
<button className="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
</>
);
}

View File

@@ -106,10 +106,15 @@ function AddModelConfigPage({ onBack, editData }) {
const configTypeList = getConfigTypeList();
return (
<div className="card">
<div className="card-header">
<div className="card-title">{isEdit ? '编辑配置' : '新增配置'}</div>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回配置列表</span>
</div>
<div className="card">
<div className="card-header">
<div className="card-title">{isEdit ? '编辑配置' : '新增配置'}</div>
</div>
<div className="card-body">
{/* 基础信息 */}
<div className="form-group">
@@ -214,7 +219,8 @@ function AddModelConfigPage({ onBack, editData }) {
<button className="btn btn-primary" onClick={handleSave}>保存</button>
</div>
</div>
</div>
</div>
</>
);
}

View File

@@ -21,10 +21,15 @@ function AddProjectPage({ onBack, editData }) {
: null;
return (
<div className="card">
<div className="card-header">
<div className="card-title">{isEdit ? '编辑项目' : '新增项目'}</div>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回项目列表</span>
</div>
<div className="card">
<div className="card-header">
<div className="card-title">{isEdit ? '编辑项目' : '新增项目'}</div>
</div>
<div className="card-body">
<div className="form-group">
<label className="form-label required">项目名称</label>
@@ -52,7 +57,8 @@ function AddProjectPage({ onBack, editData }) {
<button className="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
</>
);
}

View File

@@ -23,10 +23,15 @@ function AddUserPage({ onBack, editData }) {
: null;
return (
<div className="card">
<div className="card-header">
<div className="card-title">{isEdit ? '编辑用户' : '新增用户'}</div>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回用户列表</span>
</div>
<div className="card">
<div className="card-header">
<div className="card-title">{isEdit ? '编辑用户' : '新增用户'}</div>
</div>
<div className="card-body">
<div className="form-group">
<label className="form-label required">姓名</label>
@@ -66,7 +71,8 @@ function AddUserPage({ onBack, editData }) {
<button className="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
</>
);
}

View File

@@ -30,29 +30,35 @@ function AddMemberPage({ onBack }) {
};
return (
<div className="card">
<div className="card-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div className="card-title">增加成员</div>
<button className="btn btn-primary btn-sm" onClick={onBack}>返回列表</button>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回成员列表</span>
</div>
<div className="card-body">
<ListSelector
data={availableMembers}
selectedIds={selectedMembers}
onChange={setSelectedMembers}
searchPlaceholder="搜索成员姓名、部门、邮箱..."
columns={memberColumns}
multiSelect={true}
selectedLabel={selectedLabel}
onClearSelected={() => setSelectedMembers([])}
/>
<div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '16px' }}>
<button className="btn btn-primary" onClick={handleAdd} disabled={selectedMembers.length === 0}>
添加选中成员 ({selectedMembers.length})
</button>
<div className="card">
<div className="card-header">
<div className="card-title">增加成员</div>
</div>
<div className="card-body">
<ListSelector
data={availableMembers}
selectedIds={selectedMembers}
onChange={setSelectedMembers}
searchPlaceholder="搜索成员姓名、部门、邮箱..."
columns={memberColumns}
multiSelect={true}
selectedLabel={selectedLabel}
onClearSelected={() => setSelectedMembers([])}
/>
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '12px', marginTop: '16px' }}>
<button className="btn btn-secondary" onClick={onBack}>取消</button>
<button className="btn btn-primary" onClick={handleAdd} disabled={selectedMembers.length === 0}>
添加选中成员 ({selectedMembers.length})
</button>
</div>
</div>
</div>
</div>
</>
);
}

View File

@@ -1,5 +1,5 @@
import { useState } from 'react';
import { FiChevronLeft, FiFile } from 'react-icons/fi';
import { FiFile } from 'react-icons/fi';
import { pendingVersionReviews, pendingUnlistReviews, skillFiles } from '../../data/skills.js';
import Toast from '../../components/common/Toast.jsx';
@@ -34,8 +34,9 @@ function ConsoleReviewDetailPage({ type, reviewId, onBack }) {
return (
<>
<div className="console-back-btn" onClick={onBack}>
<FiChevronLeft /> 返回审核列表
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回审核列表</span>
</div>
<div className="card">

View File

@@ -1,16 +1,19 @@
function MemberConfigPage({ onBack }) {
return (
<div className="card">
<div className="card-header">
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回成员列表</span>
</div>
<div className="card">
<div className="card-header">
<div className="card-title">成员配置</div>
<button className="btn btn-primary" onClick={onBack}>返回列表</button>
</div>
<div className="card-body">
<p>成员配置页面内容</p>
</div>
</div>
<div className="card-body">
<p>成员配置页面内容</p>
</div>
</div>
</>
);
}

View File

@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { FiChevronLeft, FiPlus, FiX, FiUsers, FiStar, FiPackage } from 'react-icons/fi';
import { FiPlus, FiX, FiUsers, FiStar, FiPackage } from 'react-icons/fi';
import { skills, userSubscriptions } from '../../data/skills.js';
import Toast from '../../components/common/Toast.jsx';
@@ -94,8 +94,9 @@ function SkillConfigPage({ subscriptionId, onBack }) {
return (
<>
<div className="dev-back-btn" onClick={onBack} style={{ marginBottom: '16px' }}>
<FiChevronLeft /> 返回我的技能
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回我的技能</span>
</div>
{/* 技能基本信息卡片 */}
@@ -205,7 +206,10 @@ function SkillConfigPage({ subscriptionId, onBack }) {
暂无配置项点击右上角"新增配置"添加
</div>
)}
<div style={{ marginTop: '16px', textAlign: 'right' }}>
<div style={{ marginTop: '16px', textAlign: 'right', display: 'flex', justifyContent: 'flex-end', gap: '12px' }}>
<button className="btn btn-secondary" onClick={onBack}>
取消
</button>
<button className="btn btn-primary" onClick={handleSave}>
保存
</button>

View File

@@ -5,24 +5,33 @@ function TaskDetailPage({ taskId, onBack }) {
if (!task) {
return (
<div className="card">
<div className="card-header">
<div className="card-title">任务详情</div>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回任务列表</span>
</div>
<div className="card-body">
<p>任务不存在</p>
<button className="btn btn-primary btn-sm" onClick={onBack} style={{ marginTop: '16px' }}>返回列表</button>
<div className="card">
<div className="card-header">
<div className="card-title">任务详情</div>
</div>
<div className="card-body">
<p>任务不存在</p>
</div>
</div>
</div>
</>
);
}
return (
<div className="card">
<div className="card-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div className="card-title">任务详情</div>
<button className="btn btn-primary btn-sm" onClick={onBack}>返回列表</button>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回任务列表</span>
</div>
<div className="card">
<div className="card-header">
<div className="card-title">任务详情</div>
</div>
<div className="card-body">
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '20px', marginBottom: '24px' }}>
<div>
@@ -82,7 +91,8 @@ function TaskDetailPage({ taskId, onBack }) {
</div>
</div>
</div>
</div>
</div>
</>
);
}

View File

@@ -1,5 +1,5 @@
import { useState } from 'react';
import { FiUpload, FiChevronLeft } from 'react-icons/fi';
import { FiUpload } from 'react-icons/fi';
import Toast from '../../components/common/Toast.jsx';
function NewVersionPage({ skillName, onBack }) {
@@ -14,8 +14,9 @@ function NewVersionPage({ skillName, onBack }) {
return (
<>
<div className="dev-back-btn" onClick={onBack}>
<FiChevronLeft /> 返回技能详情
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回技能详情</span>
</div>
<div className="card">
<div className="card-header">

View File

@@ -1,5 +1,5 @@
import { useState } from 'react';
import { FiChevronLeft, FiUpload, FiUsers, FiPackage, FiStar, FiRotateCcw } from 'react-icons/fi';
import { FiUpload, FiUsers, FiPackage, FiStar, FiRotateCcw } from 'react-icons/fi';
import { api } from '../../services/api.js';
import Modal from '../../components/common/Modal.jsx';
import Toast from '../../components/common/Toast.jsx';
@@ -50,8 +50,9 @@ function SkillEditorPage({ skillId, onBack, onUploadNewVersion, onUpdateInfo })
return (
<>
<div className="dev-back-btn" onClick={onBack}>
<FiChevronLeft /> 返回我的技能
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回我的技能</span>
</div>
{/* 1. 开发者内部信息概览卡片 */}

View File

@@ -1,4 +1,3 @@
import { FiChevronLeft } from 'react-icons/fi';
import { useState } from 'react';
import Toast from '../../components/common/Toast.jsx';
@@ -16,8 +15,9 @@ function UpdateSkillInfoPage({ skill, onBack }) {
return (
<>
<div className="dev-back-btn" onClick={onBack}>
<FiChevronLeft /> 返回技能详情
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回技能详情</span>
</div>
<div className="card">
<div className="card-header">

View File

@@ -9,10 +9,15 @@ function UploadSkillPage({ onBack }) {
};
return (
<div className="card">
<div className="card-header">
<div className="card-title">创建技能</div>
<>
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回技能管理</span>
</div>
<div className="card">
<div className="card-header">
<div className="card-title">创建技能</div>
</div>
<div className="card-body">
<div style={{ marginBottom: '20px', padding: '12px', background: '#EFF6FF', borderRadius: '8px', color: '#1E40AF', fontSize: '14px' }}>
<strong>提示</strong>此处填写的信息仅供开发者自己管理使用不会在技能商店展示商店展示信息需要在上传版本时填写
@@ -30,13 +35,14 @@ function UploadSkillPage({ onBack }) {
<button className="btn btn-primary" onClick={handleCreate}>创建技能</button>
</div>
</div>
</div>
<Toast
visible={showToast}
type="success"
message="创建成功"
onClose={() => setShowToast(false)}
/>
</div>
</>
);
}

View File

@@ -1,4 +1,4 @@
import { FiUpload, FiChevronLeft, FiX } from 'react-icons/fi';
import { FiUpload, FiX } from 'react-icons/fi';
import { useState } from 'react';
import { api } from '../../services/api.js';
import Toast from '../../components/common/Toast.jsx';
@@ -44,8 +44,9 @@ function UploadVersionPage({ skill, onBack }) {
return (
<>
<div className="dev-back-btn" onClick={onBack}>
<FiChevronLeft /> 返回技能详情
<div className="page-back-btn" onClick={onBack}>
<span></span>
<span>返回技能详情</span>
</div>
<div className="card">
<div className="card-header">

View File

@@ -16,3 +16,13 @@
@forward 'password-input';
@forward 'search-bar';
@forward 'stat-card';
.page-back-btn {
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
color: var(--color-primary);
font-weight: 600;
margin-bottom: 16px;
}

View File

@@ -2,17 +2,6 @@
@use '../tokens' as *;
// 开发台返回按钮
.dev-back-btn {
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
color: var(--color-primary);
font-weight: 600;
margin-bottom: 16px;
}
// 开发台详情
.dev-detail-header {
display: flex;