feat: 产品页面去掉规划中 + 项目名和版本可点击跳转
1. 移除"规划中"状态:
- 去掉顶部图例的"规划中"
- activeVersions 过滤改为只显示 status === 'developing'
- 项目展开列表中的 projActive 同步只取 developing
2. 项目名可点击跳转:
- 项目名改为按钮样式,点击跳转 /projects/{id}
- hover 显示蓝色下划线
3. 版本胶囊可点击跳转:
- VersionChip 包裹按钮,点击跳转 /versions/{id}
- hover 半透明效果
4. 数据联动:
- 不再展示规划中的版本(视觉简洁)
- 点击直达对应详情页,方便快速访问
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import {
|
||||
Plus,
|
||||
Search,
|
||||
@@ -55,12 +56,14 @@ function SortableProductRow({
|
||||
onToggle,
|
||||
onEdit,
|
||||
onDelete,
|
||||
router,
|
||||
}: {
|
||||
product: ProductOverview;
|
||||
expanded: boolean;
|
||||
onToggle: () => void;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
router: ReturnType<typeof useRouter>;
|
||||
}) {
|
||||
const { attributes, listeners, setNodeRef, transform, transition, isDragging } =
|
||||
useSortable({ id: product.id });
|
||||
@@ -72,7 +75,7 @@ function SortableProductRow({
|
||||
};
|
||||
|
||||
const activeVersions = product.versions.filter(
|
||||
(v) => v.status === 'developing' || v.status === 'planned'
|
||||
(v) => v.status === 'developing'
|
||||
);
|
||||
const releasedCount = product.versions.filter((v) => v.status === 'released').length;
|
||||
|
||||
@@ -148,7 +151,7 @@ function SortableProductRow({
|
||||
v.name.toLowerCase().startsWith(proj.name.toLowerCase())
|
||||
);
|
||||
const projActive = projVersions.filter(
|
||||
(v) => v.status === 'developing' || v.status === 'planned'
|
||||
(v) => v.status === 'developing'
|
||||
);
|
||||
const projReleased = projVersions.filter((v) => v.status === 'released').length;
|
||||
return (
|
||||
@@ -156,9 +159,12 @@ function SortableProductRow({
|
||||
key={proj.id}
|
||||
className="flex items-center gap-3 py-2 border-b border-[var(--line-soft)] last:border-b-0"
|
||||
>
|
||||
<span className="text-[12px] font-medium text-[var(--ink-soft)] min-w-0 flex-shrink-0">
|
||||
<button
|
||||
onClick={() => router.push(`/projects/${proj.id}`)}
|
||||
className="text-[12px] font-medium text-[var(--ink-soft)] hover:text-[var(--accent)] hover:underline min-w-0 flex-shrink-0 cursor-pointer"
|
||||
>
|
||||
{proj.name}
|
||||
</span>
|
||||
</button>
|
||||
{proj.description && (
|
||||
<span className="text-[11px] text-[var(--ink-muted)] truncate hidden lg:inline">
|
||||
{proj.description}
|
||||
@@ -166,11 +172,16 @@ function SortableProductRow({
|
||||
)}
|
||||
<div className="flex-1 flex items-center gap-1.5 flex-wrap justify-end">
|
||||
{projActive.map((v) => (
|
||||
<VersionChip
|
||||
<button
|
||||
key={v.id}
|
||||
name={v.name}
|
||||
status={(v.status as VersionStatus) ?? 'developing'}
|
||||
/>
|
||||
onClick={() => router.push(`/versions/${v.id}`)}
|
||||
className="hover:opacity-80 transition-opacity"
|
||||
>
|
||||
<VersionChip
|
||||
name={v.name}
|
||||
status={(v.status as VersionStatus) ?? 'developing'}
|
||||
/>
|
||||
</button>
|
||||
))}
|
||||
{projReleased > 0 && (
|
||||
<span className="text-[11px] text-[var(--ink-muted)] px-1.5">
|
||||
@@ -320,6 +331,7 @@ function MigrateDialog({
|
||||
|
||||
/* ─── Main Page ─── */
|
||||
export default function ProductsPage() {
|
||||
const router = useRouter();
|
||||
const {
|
||||
overview,
|
||||
loading,
|
||||
@@ -432,9 +444,6 @@ export default function ProductsPage() {
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-[#2563eb]" />开发中
|
||||
</span>
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-orange-500" />规划中
|
||||
</span>
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-zinc-400" />已发布
|
||||
</span>
|
||||
@@ -493,6 +502,7 @@ export default function ProductsPage() {
|
||||
onToggle={() => toggleExpand(product.id)}
|
||||
onEdit={() => setEditing(product)}
|
||||
onDelete={() => handleDelete(product)}
|
||||
router={router}
|
||||
/>
|
||||
))}
|
||||
</SortableContext>
|
||||
|
||||
Reference in New Issue
Block a user