feat: 优化技能编辑页UI布局 - 新增概览卡片、信息卡片重构

重构技能编辑页面为四层结构:技能概览卡片(两行布局)→ 详细信息卡片 → 操作按钮区 → 版本管理

主要改进:
- 技能概览卡片:左侧80x80图标,右侧两行结构(技能名称 + 关键指标)
- 关键指标图标化:👥 订阅数、📦 当前版本、 评分
- 详细信息卡片:网格布局展示状态、分类、标签、技能描述、版本说明
- 操作按钮区:独立区域,视觉层次更清晰
- 响应式设计:移动端自适应布局
This commit is contained in:
2026-03-21 13:11:04 +08:00
parent fb9616a10f
commit 07b6d99054
7 changed files with 373 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
import { useState } from 'react';
import { FiChevronLeft, FiUpload } from 'react-icons/fi';
import { FiChevronLeft, FiUpload, FiUsers, FiPackage, FiStar } from 'react-icons/fi';
import { api } from '../../services/api.js';
import Modal from '../../components/common/Modal.jsx';
import Toast from '../../components/common/Toast.jsx';
@@ -43,70 +43,93 @@ function SkillEditorPage({ skillId, onBack, onUploadNewVersion, onUpdateInfo })
setToast({ visible: true, type: 'success', message: '已删除' });
};
const currentVersion = skill.versions && skill.versions.length > 0
? skill.versions.find(v => v.status === 'approved') || skill.versions[0]
: null;
return (
<>
<div className="dev-back-btn" onClick={onBack}>
<FiChevronLeft /> 返回我的技能
</div>
<div className="card">
{/* 1. 技能概览卡片(两行结构) */}
<div className="skill-overview-card">
<div className="skill-icon">{skill.icon || skill.name.charAt(0)}</div>
<div className="skill-header">
{/* 第一行:技能名称 */}
<h2 className="skill-name">{skill.name}</h2>
{/* 第二行:关键指标(带图标) */}
<div className="skill-metrics-row">
<div className="metric-item">
<FiUsers className="metric-icon" />
<span className="metric-value">{skill.installs || 0}</span>
</div>
<div className="metric-item">
<FiPackage className="metric-icon" />
<span className="metric-value">{skill.version || 'v1.0.0'}</span>
</div>
<div className="metric-item">
<FiStar className="metric-icon" />
<span className="metric-value">{skill.rating || 0}</span>
</div>
</div>
</div>
</div>
{/* 2. 详细信息卡片(普通卡片,不可折叠) */}
<div className="info-card">
<div className="card-header">
<div className="card-title">配置信息</div>
<h3>详细信息</h3>
</div>
<div className="card-body">
<div className="dev-detail-header">
<div className="dev-detail-icon">{skill.icon || skill.name.charAt(0)}</div>
<div className="dev-detail-main">
<h2 style={{ marginBottom: '8px' }}>{skill.name}</h2>
<div style={{ color: '#64748B', marginBottom: '12px' }}>{skill.category}</div>
<div className="dev-detail-tags">
<div className="info-grid">
<div className="info-item">
<label>状态</label>
<span className={`status ${skillStatusMap[skill.status]?.className || 'status-stopped'}`}>
{skillStatusMap[skill.status]?.text || skill.status}
</span>
</div>
<div className="info-item">
<label>分类</label>
<span>{skill.category}</span>
</div>
<div className="info-item full-width">
<label>标签</label>
<div className="tags">
{skill.tags.map(tag => (
<span key={tag} className="dev-detail-tag">{tag}</span>
))}
</div>
<div className="dev-detail-stats">
<span>当前版本: {skill.version}</span>
</div>
</div>
</div>
<div className="dev-detail-section">
<h3>基本信息</h3>
<div className="dev-info-row">
<span className="dev-info-label">技能名称</span>
<span className="dev-info-value">{skill.name}</span>
<div className="info-item full-width">
<label>技能描述</label>
<p>{skill.desc}</p>
</div>
<div className="dev-info-row">
<span className="dev-info-label">技能描述</span>
<span className="dev-info-value">{skill.desc}</span>
<div className="info-item full-width">
<label>版本说明</label>
<span>{currentVersion?.desc || '暂无版本说明'}</span>
</div>
<div className="dev-info-row">
<span className="dev-info-label">技能分类</span>
<span className="dev-info-value">{skill.category}</span>
</div>
<div className="dev-info-row">
<span className="dev-info-label">技能标签</span>
<span className="dev-info-value">
{skill.tags.map(tag => (
<span key={tag} className="dev-detail-tag" style={{ marginRight: '6px' }}>{tag}</span>
))}
</span>
</div>
<div style={{ display: 'flex', gap: '12px', marginBottom: '24px' }}>
<button className="btn btn-primary" onClick={() => onUpdateInfo && onUpdateInfo(skill.id)}>更新基本信息</button>
{skill.status === 'published' && (
<button className="btn btn-danger" onClick={handleTogglePublish}>下架技能</button>
)}
<button
className="btn btn-danger"
onClick={() => setDeleteSkillModal(true)}
disabled={skill.status === 'published'}
title={skill.status === 'published' ? '已上架的技能需要先下架才能删除' : ''}
>
删除技能
</button>
</div>
</div>
</div>
</div>
{/* 3. 操作按钮区 */}
<div className="action-buttons">
<button className="btn btn-primary" onClick={() => onUpdateInfo && onUpdateInfo(skill.id)}>更新基本信息</button>
{skill.status === 'published' && (
<button className="btn btn-danger" onClick={handleTogglePublish}>下架技能</button>
)}
<button
className="btn btn-danger"
onClick={() => setDeleteSkillModal(true)}
disabled={skill.status === 'published'}
title={skill.status === 'published' ? '已上架的技能需要先下架才能删除' : ''}
>
删除技能
</button>
</div>
<div className="card" style={{ marginTop: '24px' }}>
<div className="card-header">
<div className="card-title">技能包管理</div>