fix: 侧边详情显示产品/项目/版本上下文

所有 Drawer 新增 contextLabel 可选属性:
- 从工作台打开时传入"产品 / 项目 / 版本"路径
- 显示在 Drawer 顶部灰色背景条中
- 从版本详情打开时不传,不显示(无需冗余)
- 统一样式:px-5 py-2 bg-[var(--bg-subtle)] text-[11px]

涉及组件:
- PlanDetailDrawer
- DevTaskDetailDrawer
- TestCaseDetailDrawer
- BugDetailDrawer

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Script Generator
2026-06-15 17:52:15 +08:00
parent c7bccd7819
commit fa7a0f7294
5 changed files with 34 additions and 8 deletions

View File

@@ -222,16 +222,16 @@ export default function WorkspacePage() {
{/* Detail Drawers */}
{drawerItem && (drawerItem.type === 'plan_research' || drawerItem.type === 'plan_product' || drawerItem.type === 'plan_ui') && (
<PlanDetailDrawer planId={drawerItem.id} onClose={() => setDrawerItem(null)} />
<PlanDetailDrawer planId={drawerItem.id} onClose={() => setDrawerItem(null)} contextLabel={`${drawerItem.productName} / ${drawerItem.projectName} / ${drawerItem.versionName}`} />
)}
{drawerItem && drawerItem.type === 'devTask' && (
<DevTaskDetailDrawer taskId={drawerItem.id} allTaskIds={devTasks.map((t) => t.id)} onClose={() => setDrawerItem(null)} />
<DevTaskDetailDrawer taskId={drawerItem.id} allTaskIds={devTasks.map((t) => t.id)} onClose={() => setDrawerItem(null)} contextLabel={`${drawerItem.productName} / ${drawerItem.projectName} / ${drawerItem.versionName}`} />
)}
{drawerItem && drawerItem.type === 'testCase' && (
<TestCaseDetailDrawer testCaseId={drawerItem.id} onClose={() => setDrawerItem(null)} onCreateBug={(tcId) => { setDrawerItem(null); setBugFromTestCaseId(tcId); }} />
<TestCaseDetailDrawer testCaseId={drawerItem.id} onClose={() => setDrawerItem(null)} onCreateBug={(tcId) => { setDrawerItem(null); setBugFromTestCaseId(tcId); }} contextLabel={`${drawerItem.productName} / ${drawerItem.projectName} / ${drawerItem.versionName}`} />
)}
{drawerItem && drawerItem.type === 'bug' && (
<BugDetailDrawer bugId={drawerItem.id} onClose={() => setDrawerItem(null)} />
<BugDetailDrawer bugId={drawerItem.id} onClose={() => setDrawerItem(null)} contextLabel={`${drawerItem.productName} / ${drawerItem.projectName} / ${drawerItem.versionName}`} />
)}
{bugFromTestCaseId && (
<BugCreateModal testCaseId={bugFromTestCaseId} onClose={() => setBugFromTestCaseId(null)} />

View File

@@ -21,9 +21,10 @@ const LOG_ACTION_LABEL: Record<string, string> = {
interface Props {
bugId: string;
onClose: () => void;
contextLabel?: string;
}
export function BugDetailDrawer({ bugId, onClose }: Props) {
export function BugDetailDrawer({ bugId, onClose, contextLabel }: Props) {
const { bugs, changeStatus, transferBug } = useBugStore();
const { testCases } = useTestCaseStore();
const { requirements } = useRequirementStore();
@@ -66,6 +67,11 @@ export function BugDetailDrawer({ bugId, onClose }: Props) {
return (
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
{contextLabel && (
<div className="px-5 py-2 border-b border-[var(--line)] bg-[var(--bg-subtle)] shrink-0">
<span className="text-[11px] text-[var(--ink-muted)]">{contextLabel}</span>
</div>
)}
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
<div className="flex items-center gap-2">
<span className="text-[12px] font-mono text-[var(--ink-muted)]">{bug.bugNo}</span>

View File

@@ -15,9 +15,10 @@ interface Props {
taskId: string;
allTaskIds: string[];
onClose: () => void;
contextLabel?: string;
}
export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose }: Props) {
export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose, contextLabel }: Props) {
const { tasks, changeStatus, setBlocked, deleteTask, updateTask } = useDevTaskStore();
const { categories } = useTaskCategoryStore();
const { requirements } = useRequirementStore();
@@ -56,6 +57,12 @@ export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose }: Props) {
return (
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
{/* 上下文 */}
{contextLabel && (
<div className="px-5 py-2 border-b border-[var(--line)] bg-[var(--bg-subtle)] shrink-0">
<span className="text-[11px] text-[var(--ink-muted)]">{contextLabel}</span>
</div>
)}
{/* 顶栏 */}
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
<div className="flex items-center gap-2">

View File

@@ -17,9 +17,10 @@ interface Props {
testCaseId: string;
onClose: () => void;
onCreateBug?: (testCaseId: string) => void;
contextLabel?: string;
}
export function TestCaseDetailDrawer({ testCaseId, onClose, onCreateBug }: Props) {
export function TestCaseDetailDrawer({ testCaseId, onClose, onCreateBug, contextLabel }: Props) {
const { testCases, changeStatus, deleteTestCase, updateTestCase } = useTestCaseStore();
const { bugs } = useBugStore();
const { requirements } = useRequirementStore();
@@ -60,6 +61,11 @@ export function TestCaseDetailDrawer({ testCaseId, onClose, onCreateBug }: Props
return (
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
{contextLabel && (
<div className="px-5 py-2 border-b border-[var(--line)] bg-[var(--bg-subtle)] shrink-0">
<span className="text-[11px] text-[var(--ink-muted)]">{contextLabel}</span>
</div>
)}
<div className="flex items-center justify-between h-14 px-5 border-b border-[var(--line)] bg-[var(--bg-card)] shrink-0">
<div className="flex items-center gap-2">
<span className="text-[12px] font-mono text-[var(--ink-muted)]">{tc.caseNo}</span>

View File

@@ -11,13 +11,14 @@ import type { PlanTask, VersionPlan } from '@/lib/version-plan';
interface Props {
planId: string;
onClose: () => void;
contextLabel?: string;
}
const STATUS_STYLE: Record<string, string> = { pending: 'bg-zinc-100 text-zinc-600', in_progress: 'bg-blue-50 text-blue-600', completed: 'bg-emerald-50 text-emerald-600' };
const STATUS_LABEL: Record<string, string> = { pending: '未开始', in_progress: '进行中', completed: '已完成' };
const TYPE_LABEL: Record<string, string> = { research: '调研', product: '产品方案', ui: 'UI设计' };
export function PlanDetailDrawer({ planId, onClose }: Props) {
export function PlanDetailDrawer({ planId, onClose, contextLabel }: Props) {
const { plans, updatePlan, completePlan } = useVersionPlanStore();
const { requirements } = useRequirementStore();
const { members } = useMemberStore();
@@ -77,6 +78,12 @@ export function PlanDetailDrawer({ planId, onClose }: Props) {
return (
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col overflow-hidden" onClick={(e) => e.stopPropagation()}>
{/* Context */}
{contextLabel && (
<div className="px-5 py-2 border-b border-[var(--line)] bg-[var(--bg-subtle)] shrink-0">
<span className="text-[11px] text-[var(--ink-muted)]">{contextLabel}</span>
</div>
)}
{/* Header */}
<div className="flex items-center justify-between px-5 py-4 border-b border-[var(--line)] shrink-0">
<div className="flex items-center gap-2">