R96 U1-U7 精简页面设计与文案

这个提交包含在:
2026-05-06 16:47:13 +08:00
父节点 6127a537d8
当前提交 3741a3d626
共修改 19 个文件,包含 329 行新增和 549 行删除
+34 -36
查看文件
@@ -352,11 +352,11 @@ function resolveClockAction(
function SummaryPanel({ title, items }: { title: string; items: SummaryItem[] }) {
if (!items.length) {
return <EmptyStateCard title={title} description="暂无需要优先处理的摘要信息。" />;
return <EmptyStateCard title={title} description="暂无摘要。" />;
}
return (
<SectionPanel title={title} description="优先看结论与下一步,再进入对应模块处理。">
<SectionPanel title={title}>
<div className="space-y-3">
{items.map((item) => (
<Link
@@ -391,7 +391,7 @@ function AnnouncementsList({ announcements }: { announcements: PortalHomePayload
</a>
) : null}
</div>
)) : <EmptyStateCard title="暂无公告" description="当前没有需要广播的公告。" />}
)) : <EmptyStateCard title="暂无公告" description="没有公告。" />}
</div>
);
}
@@ -400,14 +400,14 @@ function RecentVisitsPanel() {
const recentVisits = readRecentVisits();
return (
<SectionPanel title="继续工作" description="保留最近访问路径,帮助快速回到上一次处理中断的位置。">
<SectionPanel title="继续工作">
<div className="space-y-3">
{recentVisits.length ? recentVisits.map((item) => (
<Link key={item.path} to={item.path} className="portal-list-card">
<div className="font-medium text-zinc-900">{item.title}</div>
<div className="mt-1 text-xs text-zinc-500">{item.path}</div>
</Link>
)) : <EmptyStateCard title="暂无最近访问" description="开始使用后,最近处理过的页面会显示在这里。" />}
)) : <EmptyStateCard title="暂无最近访问" description="最近页面会显示在这里。" />}
</div>
</SectionPanel>
);
@@ -417,13 +417,13 @@ function QuickLinksPanel({ items }: { items: PortalHomePayload["quickLinks"] })
const safeItems = Array.isArray(items) ? items : [];
return (
<SectionPanel title="常用入口" description="只保留高频入口,避免把所有模块堆成超市。">
<SectionPanel title="常用入口">
<div className="grid gap-3 sm:grid-cols-2">
{safeItems.length ? safeItems.map((item) => (
<Link key={item.key} to={item.href} className="portal-list-card text-sm font-medium text-slate-700">
{item.title}
</Link>
)) : <EmptyStateCard title="暂无常用入口" description="工作区尚未配置推荐入口。" />}
)) : <EmptyStateCard title="暂无常用入口" description="尚未配置。" />}
</div>
</SectionPanel>
);
@@ -431,7 +431,7 @@ function QuickLinksPanel({ items }: { items: PortalHomePayload["quickLinks"] })
function SecondaryCardsPanel({ title, description, cards }: { title: string; description: string; cards: PortalHomePayload["cards"] }) {
if (!cards.length) {
return <EmptyStateCard title={title} description="暂无需要额外关注的统计项。" />;
return <EmptyStateCard title={title} description="暂无统计项。" />;
}
return (
@@ -443,7 +443,7 @@ function SecondaryCardsPanel({ title, description, cards }: { title: string; des
title={card.title}
value={card.value}
href={card.href}
note="进入详情页处理"
note="查看"
tone={severityTone(card.severity)}
/>
))}
@@ -462,26 +462,26 @@ function AdoptionSummaryPanel({ adoptionSummary }: { adoptionSummary: NonNullabl
<summary className="flex cursor-pointer list-none items-center justify-between gap-3 text-left">
<div>
<div className="text-base font-semibold text-zinc-900">试点观测摘要</div>
<div className="mt-1 text-sm text-zinc-500">管理员按需展开,用于观察习惯是否已形成。</div>
<div className="mt-1 text-sm text-zinc-500">管理员按需查看。</div>
</div>
<span className="text-xs uppercase tracking-[0.18em] text-zinc-400">展开 / 收起</span>
</summary>
<div className="mt-5 grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
<div className="portal-status-card text-sm">
<div className="text-zinc-500">近 7 天登录覆盖率</div>
<div className="mt-2 text-2xl font-semibold tracking-tight text-zinc-900">{adoptionSummary.login7dRate}%</div>
<div className="mt-2 text-2xl font-semibold text-zinc-900">{adoptionSummary.login7dRate}%</div>
</div>
<div className="portal-status-card text-sm">
<div className="text-zinc-500">周报提交率</div>
<div className="mt-2 text-2xl font-semibold tracking-tight text-zinc-900">{adoptionSummary.weeklySubmissionRate}%</div>
<div className="mt-2 text-2xl font-semibold text-zinc-900">{adoptionSummary.weeklySubmissionRate}%</div>
</div>
<div className="portal-status-card text-sm">
<div className="text-zinc-500">团队状态覆盖率</div>
<div className="mt-2 text-2xl font-semibold tracking-tight text-zinc-900">{adoptionSummary.presenceCoverageRate}%</div>
<div className="mt-2 text-2xl font-semibold text-zinc-900">{adoptionSummary.presenceCoverageRate}%</div>
</div>
<div className="portal-status-card text-sm">
<div className="text-zinc-500">当前公告数</div>
<div className="mt-2 text-2xl font-semibold tracking-tight text-zinc-900">{adoptionSummary.announcementCount}</div>
<div className="mt-2 text-2xl font-semibold text-zinc-900">{adoptionSummary.announcementCount}</div>
</div>
</div>
<div className="mt-4 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm text-slate-600">
@@ -510,7 +510,7 @@ function SecondaryWorkspacePanel({
<summary className="portal-secondary-summary">
<div>
<div className="text-base font-semibold text-zinc-900">{title}</div>
<div className="mt-1 text-sm leading-6 text-zinc-500">{description}</div>
<div className="mt-1 text-sm text-zinc-500">{description}</div>
</div>
<span className="portal-secondary-summary__toggle">展开 / 收起</span>
</summary>
@@ -549,7 +549,7 @@ function GettingStartedCard({
return (
<SectionPanel
title="快速上手"
description="先完成基础资料和入口熟悉,再进入请假、通知等日常动作。"
description="完成基础资料。"
actions={(
<button
type="button"
@@ -652,7 +652,7 @@ function QuickActionsPanel({
return (
<SectionPanel
title="快捷操作栏"
description="保留每天真正高频的动作,不把所有入口都放在首屏。"
description="高频动作"
className={layout === "rail" ? "portal-panel-fill" : undefined}
>
<div className={layout === "rail" ? "portal-action-stack" : "grid gap-3 sm:grid-cols-2 xl:grid-cols-4"}>
@@ -680,7 +680,7 @@ function TodoAggregatePanel({ items }: { items: TodoAggregateItem[] }) {
return (
<SectionPanel
title="今日待办聚合"
description="合并审批、TODO 和高风险指标,只保留今天最该处理的事。"
description="今天要处理的事"
className="portal-panel-fill"
>
<div className="space-y-3">
@@ -706,11 +706,11 @@ function TodoAggregatePanel({ items }: { items: TodoAggregateItem[] }) {
</div>
</div>
</Link>
)) : <EmptyStateCard title="暂无待办事项,休息一下吧" description="当前没有需要立刻处理的审批、TODO 或风险提醒。" />}
)) : <EmptyStateCard title="暂无待办" description="没有需要立刻处理的事。" />}
</div>
{hiddenCount > 0 ? (
<div className="portal-panel-footer">
<span>还有 {hiddenCount} 项已收起,避免首页变成待办清单。</span>
<span>还有 {hiddenCount} 项已收起。</span>
<Link to="/todos" className="font-medium text-primary hover:underline">查看全部待办</Link>
</div>
) : null}
@@ -726,7 +726,7 @@ function TeamStatusBoardPanel({ items }: { items: PortalTeamStatusItem[] }) {
return (
<SectionPanel
title="团队全员状态"
description="小团队首页只展示关键状态,完整考勤与在岗信息进入团队页。"
description="今日状态"
actions={<Link to="/team" className="text-sm font-medium text-primary hover:underline">查看团队页</Link>}
className="portal-panel-fill"
>
@@ -743,11 +743,11 @@ function TeamStatusBoardPanel({ items }: { items: PortalTeamStatusItem[] }) {
<span className={badge.className}>{badge.label}</span>
</div>
);
}) : <EmptyStateCard title="暂无团队状态" description="当前没有可展示的团队成员状态。" />}
}) : <EmptyStateCard title="暂无团队状态" description="没有成员状态。" />}
</div>
{hiddenCount > 0 ? (
<div className="portal-panel-footer">
<span>已收起 {hiddenCount} 位成员,避免首页纵向过长。</span>
<span>已收起 {hiddenCount} 位成员。</span>
<Link to="/team" className="font-medium text-primary hover:underline">查看全部</Link>
</div>
) : null}
@@ -785,7 +785,7 @@ function ActivityAnnouncementsPanel({
return (
<SectionPanel
title="近期动态流"
description="动态优先,公告进入同一张右侧阅读卡,减少首页白卡堆叠。"
description="动态和公告"
actions={<Link to="/announcements" className="text-sm font-medium text-primary hover:underline">公告页</Link>}
className="portal-panel-fill"
>
@@ -959,7 +959,7 @@ export function PortalHomePage() {
href: payload.todayPresence.href,
label: "今日状态",
value: payload.todayPresence.label,
note: payload.todayPresence.note ?? "可在团队页手动更新在岗、居家、外出或出差状态。",
note: payload.todayPresence.note ?? "可在团队页更新。",
tone: payload.todayPresence.status === "leave" ? "warning" as const : "normal" as const,
}
: null,
@@ -971,7 +971,7 @@ export function PortalHomePage() {
href: payload.teamPresence?.href ?? "/team",
label: "今日团队状态",
value: payload.teamPresence ? `在岗 ${payload.teamPresence.office}/${payload.teamPresence.total}` : "待启用",
note: payload.teamPresence ? `请假 ${payload.teamPresence.leave},未更新 ${payload.teamPresence.unspecified}` : "团队状态板可展示在岗、居家、外出、出差与请假。",
note: payload.teamPresence ? `请假 ${payload.teamPresence.leave},未更新 ${payload.teamPresence.unspecified}` : "团队状态待启用。",
tone: payload.teamPresence && (payload.teamPresence.leave > 0 || payload.teamPresence.unspecified > 0) ? "warning" as const : "normal" as const,
},
payload.weeklySummary
@@ -1039,9 +1039,7 @@ export function PortalHomePage() {
eyebrow={isManagerView ? "管理工作台" : "个人工作台"}
title={`你好,${payload.greeting.name}`}
className="workbench-hero--compact"
subtitle={isManagerView
? "先处理审批、团队状态和周报缺口,再进入项目与组织协同。"
: "先处理今天必须完成的事,再继续查看项目、周报和公告。"}
subtitle={isManagerView ? "审批、团队、周报。" : "待办、打卡、申请。"}
actions={
!payload.workspace.persisted && canSetupWorkspace ? (
<Button asChild variant="secondary" type="button">
@@ -1076,7 +1074,7 @@ export function PortalHomePage() {
fallback={(
<PortalSectionFallback
title="快速上手"
description="先完成基础资料和入口熟悉,再进入请假、通知等日常动作。"
description="完成基础资料。"
/>
)}
>
@@ -1098,7 +1096,7 @@ export function PortalHomePage() {
fallback={(
<PortalSectionFallback
title="团队全员状态"
description="同时看人在不在岗、有没有请假,以及今天是否已打卡。"
description="今日团队状态。"
/>
)}
>
@@ -1108,7 +1106,7 @@ export function PortalHomePage() {
fallback={(
<PortalSectionFallback
title="近期动态流"
description="把最近发生的报销、请假、考勤和资产动作放在同一条时间线上。"
description="最近业务动作。"
/>
)}
>
@@ -1120,7 +1118,7 @@ export function PortalHomePage() {
<>
<SecondaryWorkspacePanel
title="今日管理重点 / 常用入口"
description="默认收起第二阅读层;需要巡检项目、组织协同或常用入口时再展开。"
description="按需展开。"
>
<div className="grid gap-6 xl:grid-cols-[minmax(0,1fr),360px]">
<SummaryPanel title="今日管理重点" items={managerSummaryItems} />
@@ -1129,7 +1127,7 @@ export function PortalHomePage() {
<SecondaryCardsPanel
title="项目跟进与组织协同"
description="把项目、组织和风险类信息下移到第二阅读层。"
description="项目、组织和风险。"
cards={secondaryCards}
/>
</SecondaryWorkspacePanel>
@@ -1139,7 +1137,7 @@ export function PortalHomePage() {
) : (
<SecondaryWorkspacePanel
title="我的申请与资产 / 继续工作"
description="默认收起低频参考信息,首页先服务今天要处理的事。"
description="按需展开。"
>
<div className="grid gap-6 xl:grid-cols-[minmax(0,1fr),minmax(0,1fr)]">
<SummaryPanel title="我的申请与资产" items={employeeSummaryItems} />
@@ -1150,7 +1148,7 @@ export function PortalHomePage() {
<QuickLinksPanel items={quickLinkItems} />
<SecondaryCardsPanel
title="项目跟进与个人协同"
description="项目、资产和其他参考指标保留在第二阅读层。"
description="项目和参考指标。"
cards={secondaryCards}
/>
</div>