diff --git a/.gitignore b/.gitignore
index 46f6770..9f7d411 100644
--- a/.gitignore
+++ b/.gitignore
@@ -96,6 +96,10 @@ missing-video-files*.json
/.claude/worktrees/
/.playwright-mcp/
/.performance-survey-audits/
+/outputs/department-dashboard-qa/
+/.impeccable/screenshots/
+/pnpm-lock.yaml
+/pnpm-workspace.yaml
# Temporary investigation/probe artifacts
/tmp/
@@ -124,4 +128,3 @@ backups/
# DSH 视觉工具产物目录(本地生成,不进 git)
.dsh-vision-toolkit/
-
diff --git a/.impeccable/design.json b/.impeccable/design.json
new file mode 100644
index 0000000..f5a5cef
--- /dev/null
+++ b/.impeccable/design.json
@@ -0,0 +1,531 @@
+{
+ "schemaVersion": 2,
+ "generatedAt": "2026-08-19T00:00:00+08:00",
+ "title": "Design System: 品牌中心部门看板",
+ "extensions": {
+ "colorMeta": {
+ "nav-rail": {
+ "role": "neutral",
+ "displayName": "深海军蓝导航轨",
+ "canonical": "#06192d",
+ "tonalRamp": [
+ "#f1f5f9",
+ "#dbe4ed",
+ "#aebdcd",
+ "#7f93a8",
+ "#526b83",
+ "#2b435b",
+ "#142b42",
+ "#06192d"
+ ]
+ },
+ "action-blue": {
+ "role": "primary",
+ "displayName": "当前项高识别蓝",
+ "canonical": "#1677ff",
+ "tonalRamp": [
+ "#eff6ff",
+ "#dbeafe",
+ "#bfdbfe",
+ "#93c5fd",
+ "#60a5fa",
+ "#3b82f6",
+ "#1677ff",
+ "#0958d9"
+ ]
+ },
+ "canvas": {
+ "role": "neutral",
+ "displayName": "冷灰工作画布",
+ "canonical": "#f2f4f7",
+ "tonalRamp": [
+ "#ffffff",
+ "#fafbfc",
+ "#f8fafc",
+ "#f2f4f7",
+ "#e9edf2",
+ "#dfe4ea",
+ "#cfd6df",
+ "#98a2b3"
+ ]
+ },
+ "surface": {
+ "role": "neutral",
+ "displayName": "白色数据面板",
+ "canonical": "#ffffff",
+ "tonalRamp": [
+ "#ffffff",
+ "#fcfcfd",
+ "#f9fafb",
+ "#f2f4f7",
+ "#e4e7ec",
+ "#d0d5dd",
+ "#98a2b3",
+ "#667085"
+ ]
+ },
+ "surface-soft": {
+ "role": "neutral",
+ "displayName": "次级交互面",
+ "canonical": "#f8fafc",
+ "tonalRamp": [
+ "#ffffff",
+ "#f8fafc",
+ "#f1f5f9",
+ "#e2e8f0",
+ "#cbd5e1",
+ "#94a3b8",
+ "#64748b",
+ "#334155"
+ ]
+ },
+ "border": {
+ "role": "neutral",
+ "displayName": "数据面板边界",
+ "canonical": "#e2e8f0",
+ "tonalRamp": [
+ "#ffffff",
+ "#f8fafc",
+ "#f1f5f9",
+ "#e2e8f0",
+ "#cbd5e1",
+ "#94a3b8",
+ "#64748b",
+ "#334155"
+ ]
+ },
+ "text-primary": {
+ "role": "neutral",
+ "displayName": "主要文字",
+ "canonical": "#101828",
+ "tonalRamp": [
+ "#f2f4f7",
+ "#d0d5dd",
+ "#98a2b3",
+ "#667085",
+ "#475467",
+ "#344054",
+ "#1d2939",
+ "#101828"
+ ]
+ },
+ "text-secondary": {
+ "role": "neutral",
+ "displayName": "辅助文字",
+ "canonical": "#66758b",
+ "tonalRamp": [
+ "#f8fafc",
+ "#e9eef5",
+ "#d7e0ea",
+ "#b6c4d4",
+ "#8fa2b8",
+ "#66758b",
+ "#4f6077",
+ "#344054"
+ ]
+ },
+ "nav-secondary": {
+ "role": "neutral",
+ "displayName": "导航辅助文字",
+ "canonical": "#aebdcd",
+ "tonalRamp": [
+ "#f5f8fb",
+ "#e4ebf2",
+ "#cfdae5",
+ "#aebdcd",
+ "#8aa0b6",
+ "#647b92",
+ "#425a72",
+ "#243c54"
+ ]
+ },
+ "connected": {
+ "role": "success",
+ "displayName": "真实已接入状态",
+ "canonical": "#31d0aa",
+ "tonalRamp": [
+ "#ecfdf8",
+ "#d1fae5",
+ "#a7f3d0",
+ "#6ee7b7",
+ "#31d0aa",
+ "#0e9f78",
+ "#087052",
+ "#064e3b"
+ ]
+ },
+ "danger": {
+ "role": "danger",
+ "displayName": "错误与风险",
+ "canonical": "#b42318",
+ "tonalRamp": [
+ "#fff1f0",
+ "#fee4e2",
+ "#fecdca",
+ "#fda29b",
+ "#f97066",
+ "#d92d20",
+ "#b42318",
+ "#7a271a"
+ ]
+ },
+ "delivery-yellow": {
+ "role": "warning",
+ "displayName": "交付率黄色区间",
+ "canonical": "#a88a00",
+ "tonalRamp": [
+ "#fffceb",
+ "#fff7cc",
+ "#ffec99",
+ "#ffdd66",
+ "#e9c436",
+ "#c4a516",
+ "#a88a00",
+ "#725400"
+ ]
+ },
+ "business-orange": {
+ "role": "secondary",
+ "displayName": "业务经营识别色",
+ "canonical": "#9a4d08",
+ "tonalRamp": [
+ "#fff4e7",
+ "#ffe2bd",
+ "#ffc982",
+ "#f3a94f",
+ "#d9821c",
+ "#b6630b",
+ "#9a4d08",
+ "#663004"
+ ]
+ },
+ "assets-green": {
+ "role": "secondary",
+ "displayName": "资产与自动化识别色",
+ "canonical": "#087052",
+ "tonalRamp": [
+ "#e9f8f2",
+ "#ccefe2",
+ "#9fe0ca",
+ "#63c4a4",
+ "#2ea481",
+ "#0f8563",
+ "#087052",
+ "#064b39"
+ ]
+ },
+ "organization-gold": {
+ "role": "secondary",
+ "displayName": "组织管理识别色",
+ "canonical": "#725400",
+ "tonalRamp": [
+ "#fff8d9",
+ "#ffed9a",
+ "#f8dc58",
+ "#d9bb22",
+ "#b99408",
+ "#8f7000",
+ "#725400",
+ "#4f3a00"
+ ]
+ },
+ "governance-blue": {
+ "role": "secondary",
+ "displayName": "治理与设置识别色",
+ "canonical": "#214ba7",
+ "tonalRamp": [
+ "#edf3ff",
+ "#d6e4ff",
+ "#adc8ff",
+ "#85a5ff",
+ "#597ef7",
+ "#3569df",
+ "#214ba7",
+ "#15347a"
+ ]
+ },
+ "workflow-active": {
+ "role": "tertiary",
+ "displayName": "工作流选中底",
+ "canonical": "#e6f4ff",
+ "tonalRamp": [
+ "#f7fcff",
+ "#eef9ff",
+ "#e6f4ff",
+ "#bae0ff",
+ "#91caff",
+ "#69b1ff",
+ "#4096ff",
+ "#1677ff"
+ ]
+ },
+ "workflow-active-title": {
+ "role": "primary",
+ "displayName": "工作流选中标题",
+ "canonical": "#0050cb",
+ "tonalRamp": [
+ "#e6f4ff",
+ "#bae0ff",
+ "#69b1ff",
+ "#1677ff",
+ "#0958d9",
+ "#0050cb",
+ "#003eb3",
+ "#002c8c"
+ ]
+ },
+ "workflow-active-description": {
+ "role": "tertiary",
+ "displayName": "工作流选中说明",
+ "canonical": "#315f91",
+ "tonalRamp": [
+ "#edf6ff",
+ "#d6e9fb",
+ "#b5d4ee",
+ "#8fb8dc",
+ "#699ac5",
+ "#4c7daf",
+ "#315f91",
+ "#20436c"
+ ]
+ },
+ "workflow-inactive-title": {
+ "role": "neutral",
+ "displayName": "工作流未选标题",
+ "canonical": "#4f6077",
+ "tonalRamp": [
+ "#f8fafc",
+ "#e9eef5",
+ "#d7e0ea",
+ "#b6c4d4",
+ "#8fa2b8",
+ "#66758b",
+ "#4f6077",
+ "#344054"
+ ]
+ },
+ "workflow-inactive-description": {
+ "role": "neutral",
+ "displayName": "工作流未选说明",
+ "canonical": "#667085",
+ "tonalRamp": [
+ "#fcfcfd",
+ "#f2f4f7",
+ "#e4e7ec",
+ "#d0d5dd",
+ "#98a2b3",
+ "#667085",
+ "#475467",
+ "#344054"
+ ]
+ },
+ "workflow-hover": {
+ "role": "neutral",
+ "displayName": "工作流未选悬停",
+ "canonical": "#eef2f6",
+ "tonalRamp": [
+ "#ffffff",
+ "#f8fafc",
+ "#f4f6f8",
+ "#eef2f6",
+ "#e4e9ef",
+ "#d5dde6",
+ "#b8c4d2",
+ "#7f93a8"
+ ]
+ },
+ "workflow-focus": {
+ "role": "tertiary",
+ "displayName": "工作流焦点环",
+ "canonical": "#5a9ce6",
+ "tonalRamp": [
+ "#eff7ff",
+ "#dbeeff",
+ "#b8dcff",
+ "#8fc4f5",
+ "#5a9ce6",
+ "#2f7fcf",
+ "#176fc1",
+ "#0d4d8c"
+ ]
+ }
+ },
+ "typographyMeta": {
+ "display": {
+ "displayName": "页面主标题",
+ "use": "首页与关键二级页标题"
+ },
+ "headline": {
+ "displayName": "数据页标题",
+ "use": "指标与明细页标题"
+ },
+ "title": {
+ "displayName": "面板标题",
+ "use": "职责域与数据分区"
+ },
+ "body": {
+ "displayName": "正文",
+ "use": "页面说明和数据解释"
+ },
+ "label": {
+ "displayName": "操作标签",
+ "use": "导航、按钮、表头和状态"
+ }
+ },
+ "shadows": [
+ {
+ "name": "panel-low",
+ "value": "0 6px 18px rgba(15, 23, 42, 0.05)",
+ "purpose": "需要与冷灰画布分离的主要白色面板"
+ },
+ {
+ "name": "menu",
+ "value": "0 14px 38px rgba(15, 23, 42, 0.16)",
+ "purpose": "账户菜单、移动抽屉和可拖动榜单"
+ }
+ ],
+ "motion": [
+ {
+ "name": "state",
+ "value": "200ms ease",
+ "purpose": "导航折叠、选中和轻量悬停反馈"
+ }
+ ],
+ "breakpoints": [
+ {
+ "name": "sm",
+ "value": "640px"
+ },
+ {
+ "name": "lg",
+ "value": "1024px"
+ },
+ {
+ "name": "2xl",
+ "value": "1536px"
+ }
+ ]
+ },
+ "components": [
+ {
+ "name": "Department Navigation Active",
+ "type": "navigation",
+ "description": "二级页面在深色导航轨中的唯一当前位置;16px 语义图标与文字一起变为白色。",
+ "projection": "业务趋势"
+ },
+ {
+ "name": "Data Panel",
+ "type": "card",
+ "description": "边框优先的白色矩形数据工作面。",
+ "projection": ""
+ },
+ {
+ "name": "Primary Button",
+ "type": "button",
+ "description": "高识别蓝色主要行动按钮。",
+ "projection": ""
+ },
+ {
+ "name": "Search Field",
+ "type": "input",
+ "description": "白底细边框的数据筛选字段。",
+ "projection": ""
+ },
+ {
+ "name": "Connected Status",
+ "type": "chip",
+ "description": "只有真实接入业务才使用绿色状态。",
+ "projection": "实时读取"
+ },
+ {
+ "name": "Workspace Row",
+ "type": "custom",
+ "description": "不可点击的大职责域和可点击的小项入口。",
+ "projection": ""
+ },
+ {
+ "name": "Sidebar Account Menu",
+ "type": "navigation",
+ "description": "账户入口固定在侧栏底部,菜单向上展开。",
+ "projection": "
"
+ },
+ {
+ "name": "Mobile Navigation Drawer",
+ "type": "navigation",
+ "description": "1024px 以下使用的完整模态导航抽屉。",
+ "projection": ""
+ },
+ {
+ "name": "Automation Workflow Split Workbench",
+ "type": "navigation",
+ "description": "Department Shell 内的 232px 二级业务栏与同源真实操作面;移动端菜单改为顶部两列,不渲染标题或接入数量区。",
+ "projection": ""
+ }
+ ],
+ "narrative": {
+ "northStar": "深色导航轨数据工作台",
+ "overview": "品牌中心是一套固定导航、快速切换与逐层下钻的内部运营界面。深海军蓝导航轨提供稳定坐标,白色操作顶栏承载全局控制,冷灰画布上以矩形白色工作面板组织真实数据、示例状态与待接入框架。\n\n它保留品牌中心自己的五个职责域、22 个小项入口,以及素材库与自动化工作流两项已接入业务,不复制参考图中的外部品牌、店铺数据或水印。首页是工作地图,不是营销门户;子页是数据工作面,不用巨型漂浮英雄卡重复标题。",
+ "keyCharacteristics": [
+ "272px 固定深色导航轨,桌面可折叠为 80px。",
+ "72px 白色顶栏与 `#f2f4f7` 冷灰画布组成稳定后台骨架;账户入口固定在侧栏底部。",
+ "`#1677ff` 只用于当前项、主要行动和明确焦点。",
+ "白色面板以 8–12px 圆角、细边框和克制阴影呈现。",
+ "移动端导航是完整的模态抽屉;内容状态始终诚实标注。",
+ "自动化工作流在 Department Shell 内使用 232px 二级业务栏与同源真实操作面,移动端改为顶部两列菜单。"
+ ],
+ "rules": [
+ {
+ "name": "The Current Location Rule",
+ "body": "进入二级页面后只保留一个最强的 `#1677ff` 导航选中态;首页不设置独立“部门总览”导航项,职责域色不得与当前项竞争。",
+ "section": "colors"
+ },
+ {
+ "name": "The Truth Color Rule",
+ "body": "绿色只表示真实已接入,示例值和待接入状态不得伪装成成功。",
+ "section": "colors"
+ },
+ {
+ "name": "The Embedded Business Truth Rule",
+ "body": "二级栏只切换既有真实业务操作面;选中态、URL 与 iframe 内容必须同步,不能用入口卡片或示例数据替代。",
+ "section": "colors"
+ },
+ {
+ "name": "The Dense Tool Rule",
+ "body": "顶栏和导航保持 12–14px 紧凑标签;页面标题才使用 30–36px,不把每个面板都做成英雄区。",
+ "section": "typography"
+ },
+ {
+ "name": "The Two-Level Workflow Rule",
+ "body": "自动化工作流的二级栏只包含两个业务菜单,不添加标题、数量、说明头或入口卡;右侧始终是当前菜单对应的真实操作面。",
+ "section": "layout"
+ },
+ {
+ "name": "The Top-Level Return Rule",
+ "body": "嵌入业务的根路径返回必须跳出 iframe 到顶层浏览上下文,禁止在操作面内再次嵌入品牌中心首页。",
+ "section": "layout"
+ },
+ {
+ "name": "The Border-First Rule",
+ "body": "默认先用 `#e2e8f0` 细边框建立结构;不要用超过 20px 的主表面圆角与大阴影制造漂浮岛。",
+ "section": "elevation"
+ }
+ ],
+ "dos": [
+ "**Do** 在首页、框架页、指标页、明细页、加载/异常状态和素材库复用同一 Department Shell。",
+ "**Do** 保持 5 个职责域、22 个小项、20 个框架入口,以及素材库和自动化工作流两项已接入业务的产品真相。",
+ "**Do** 明确区分真实数据、示例值、公式待接入与空数据。",
+ "**Do** 在桌面与 390px 移动宽度验证导航、焦点和横向溢出。",
+ "**Do** 让自动化工作流的菜单、`?workflow=` 和右侧真实业务操作面始终同步。",
+ "**Do** 让嵌入业务的根路径返回以 `target=\"_top\"` 跳出 iframe。"
+ ],
+ "donts": [
+ "**Don't** 恢复旧版漂浮岛视觉、门户式白色英雄卡或超过 20px 的主表面圆角。",
+ "**Don't** 让职责域标题本身成为导航;只有下方小项链接进入二级页面。",
+ "**Don't** 复制参考图中的京东品牌、店铺指标、水印或虚构业务数据。",
+ "**Don't** 让移动抽屉键盘焦点穿透到底层页面。",
+ "**Don't** 在自动化工作流二级栏顶部显示标题、接入数量、统计区或独立说明区。",
+ "**Don't** 用入口卡片、复制页面或假数据替代 `/performance-survey` 与 `/work-review` 的真实操作面。",
+ "**Don't** 让 `href=\"/\"` 在 iframe 内打开并嵌套品牌中心首页。"
+ ]
+ }
+}
diff --git a/DESIGN.md b/DESIGN.md
index a3e16d6..2f466288 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -1,65 +1,281 @@
-# DESIGN.md — 由壹点·品牌中心(看板首页)
+---
+name: "品牌中心部门看板"
+description: "以深色部门导航轨组织业务、资产、组织与治理工作的内部数据工作台。"
+colors:
+ nav-rail: "#06192d"
+ action-blue: "#1677ff"
+ canvas: "#f2f4f7"
+ surface: "#ffffff"
+ surface-soft: "#f8fafc"
+ border: "#e2e8f0"
+ text-primary: "#101828"
+ text-secondary: "#66758b"
+ nav-secondary: "#aebdcd"
+ connected: "#31d0aa"
+ danger: "#b42318"
+ delivery-yellow: "#a88a00"
+ business-orange: "#9a4d08"
+ assets-green: "#087052"
+ organization-gold: "#725400"
+ governance-blue: "#214ba7"
+ workflow-active: "#e6f4ff"
+ workflow-active-title: "#0050cb"
+ workflow-active-description: "#315f91"
+ workflow-inactive-title: "#4f6077"
+ workflow-inactive-description: "#667085"
+ workflow-hover: "#eef2f6"
+ workflow-focus: "#5a9ce6"
+typography:
+ display:
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif"
+ fontSize: "36px"
+ fontWeight: 700
+ lineHeight: 1.2
+ letterSpacing: "-0.03em"
+ headline:
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif"
+ fontSize: "30px"
+ fontWeight: 700
+ lineHeight: 1.25
+ letterSpacing: "-0.02em"
+ title:
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif"
+ fontSize: "20px"
+ fontWeight: 700
+ lineHeight: 1.4
+ body:
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif"
+ fontSize: "16px"
+ fontWeight: 400
+ lineHeight: 1.75
+ label:
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif"
+ fontSize: "14px"
+ fontWeight: 600
+ lineHeight: 1.4
+rounded:
+ sm: "4px"
+ md: "8px"
+ lg: "12px"
+ full: "9999px"
+spacing:
+ xs: "4px"
+ sm: "8px"
+ md: "12px"
+ lg: "16px"
+ xl: "24px"
+ xxl: "32px"
+components:
+ navigation-active:
+ backgroundColor: "{colors.action-blue}"
+ textColor: "{colors.surface}"
+ rounded: "{rounded.md}"
+ padding: "12px"
+ panel:
+ backgroundColor: "{colors.surface}"
+ textColor: "{colors.text-primary}"
+ rounded: "{rounded.lg}"
+ padding: "24px"
+ button-primary:
+ backgroundColor: "{colors.action-blue}"
+ textColor: "{colors.surface}"
+ rounded: "{rounded.md}"
+ padding: "12px 16px"
+ field:
+ backgroundColor: "{colors.surface}"
+ textColor: "{colors.text-primary}"
+ rounded: "{rounded.md}"
+ padding: "12px 16px"
+ status-connected:
+ backgroundColor: "{colors.connected}"
+ textColor: "{colors.nav-rail}"
+ rounded: "{rounded.full}"
+ size: "6px"
+ workflow-secondary-nav:
+ backgroundColor: "{colors.surface-soft}"
+ textColor: "{colors.workflow-inactive-title}"
+ rounded: "{rounded.md}"
+ padding: "16px"
+ width: "232px"
+ workflow-secondary-item-active:
+ backgroundColor: "{colors.workflow-active}"
+ textColor: "{colors.workflow-active-title}"
+ rounded: "{rounded.md}"
+ padding: "10px 12px"
+ height: "58px"
+---
-
+# Design System: 品牌中心部门看板
-> 记录自建成代码,非先行规范。方向:用户裁定的 Zen Minimal × Future Organic 融合(2026-08-15)。
-> **全站浅色单主题**:深色主题已废弃(2026-08-15 用户裁定),`darkMode: 'class'` 且不挂 `.dark`,所有 `dark:` 变体失效;新代码禁止再写 `dark:` 类。遗留 `dark:` 类 inert 保留,随逐页统一清理。
+## Overview
-## World
+**Creative North Star: "深色导航轨数据工作台"**
-「白皮书」:整页是一张编辑排印的品牌白皮书——白纸黑字、发丝线、超大留白;五个板块排成作品集式编号索引;唯一的色彩氛围是右上角一枚缓慢呼吸的柔紫光晕。安静、克制、有底气。
+品牌中心是一套固定导航、快速切换与逐层下钻的内部运营界面。深海军蓝导航轨提供稳定坐标,白色操作顶栏承载全局控制,冷灰画布上以矩形白色工作面板组织真实数据、示例状态与待接入框架。
-## Color
+它保留品牌中心自己的五个职责域、22 个小项入口,以及素材库与自动化工作流两项已接入业务,不复制参考图中的外部品牌、店铺数据或水印。首页是工作地图,不是营销门户;子页是数据工作面,不用巨型漂浮英雄卡重复标题。
-| 令牌 | 值 | 用途 |
-|---|---|---|
-| paper | `#fafafa` | 页面底 |
-| surface | `#ffffff` | 白卡、悬停行底 |
-| ink | `#1a1c1d` | 标题、正文主色、主按钮 |
-| body | `#6b7075` | 次级正文(≥4.5:1) |
-| faint | `#86898e` | 注脚/微标注/规划态文字(≥4.5:1) |
-| ghost-title | `#8f9398` | 规划中板块标题(大字 ≥3:1) |
-| hairline | `#e7e8ea` | 全部分割线与卡片边 |
-| accent | `#6e79c8` / 深链 `#5a66b8` | 柔光光晕 / 页脚链接 |
-| accent-wash | `#eef0fa` | 光晕最浅层、::selection |
-| signal-live | `#157a4b` | 已上线状态点 |
-| signal-building | `#6e79c8` | 建设中状态点 |
-| signal-planned | `#9aa0a8` | 规划中状态点 |
+**Key Characteristics:**
-无阴影(平面化);层级靠留白、字重与发丝线。**logo 双版本**:浅底表面用 `loginLogoUrl`(深蓝+橙图案),黑底表面用 `headerLogoUrl`(亮色图案)。
+- 272px 固定深色导航轨,桌面可折叠为 80px。
+- 72px 白色顶栏与 `#f2f4f7` 冷灰画布组成稳定后台骨架;账户入口固定在侧栏底部。
+- `#1677ff` 只用于当前项、主要行动和明确焦点。
+- 白色面板以 8–12px 圆角、细边框和克制阴影呈现。
+- 移动端导航是完整的模态抽屉;内容状态始终诚实标注。
+- 自动化工作流在 Department Shell 内使用 232px 二级业务栏与同源真实操作面,移动端改为顶部两列菜单。
-## Type
+## Colors
-- 全站默认字栈:`Space Grotesk` → `Noto Sans SC`。拉丁字母和数字走 Space Grotesk,汉字走思源黑体,同一段字里自动切换。
-- 中文标题:Noto Sans SC(`font-sans` / `font-display`),600 字重、`-0.03em` 紧字距;首页巨标 `clamp(60px, 9vw, 132px)`
-- 工程标注/编号/英文:Space Grotesk(字栈首位 + `font-en`),11–13px、大写、`0.14em` 字距
-- 正文:同上字栈,13–16px、行高 1.7;不再用系统默认黑体
-- 自托管:`@fontsource/noto-sans-sc`(400/500/600/700/900)、`@fontsource/space-grotesk`(400/500/600/700)
+深色导航和高识别蓝色建立方向感,冷灰中性色保持高密度数据的可读性;职责域色只做局部识别,不铺满主画布。
+
+### Primary
+
+- **Action Blue** (`#1677ff`): 当前导航项、主要按钮、焦点环和关键链接。
+- **Deep Navy Rail** (`#06192d`): 桌面固定导航和移动抽屉。
+
+### Secondary
+
+- **Business Orange** (`#9a4d08`), **Assets Green** (`#087052`), **Organization Gold** (`#725400`), **Governance Blue** (`#214ba7`): 五个职责域的局部图标、摘要和软色块。
+- **Connected Mint** (`#31d0aa`): 已接入业务入口的小圆点状态。
+
+### Neutral
+
+- **Canvas Gray** (`#f2f4f7`): 主工作区背景。
+- **Panel White** (`#ffffff`): 顶栏、面板、表格和字段。
+- **Soft Surface** (`#f8fafc`): 面板内部的次级行或骨架。
+- **Divider** (`#e2e8f0`): 面板、行、表格与字段边界。
+- **Primary Ink** (`#101828`) / **Secondary Ink** (`#66758b`): 标题、正文和辅助信息。
+- **Workflow Active** (`#e6f4ff`, `#0050cb`, `#315f91`): 自动化工作流二级栏的选中底、标题与说明。
+- **Workflow Inactive** (`#4f6077`, `#667085`, `#eef2f6`): 未选标题、说明与 hover;焦点环固定为 `#5a9ce6`。
+
+### Named Rules
+
+**The Current Location Rule.** 进入二级页面后只保留一个最强的 `#1677ff` 导航选中态;首页不设置独立“部门总览”导航项,职责域色不得与当前项竞争。
+
+**The Truth Color Rule.** 绿色只表示真实已接入,示例值和待接入状态不得伪装成成功。
+
+**The Embedded Business Truth Rule.** 二级栏只切换既有真实业务操作面;选中态、URL 与 iframe 内容必须同步,不能用入口卡片或示例数据替代。
+
+## Typography
+
+**Display Font:** System UI sans-serif
+
+**Body Font:** System UI sans-serif
+
+**Character:** 紧凑、直接、适合中文运营后台;依靠字重和间距建立层级,不使用装饰性字体。
+
+### Hierarchy
+
+- **Display** (700, 36px, 1.2): 首页与关键二级页标题;移动端降至约 30px。
+- **Headline** (700, 30px, 1.25): 指标与明细页标题。
+- **Title** (700, 20px, 1.4): 工作板块、数据分区和面板标题。
+- **Body** (400, 16px, 1.75): 页面说明,建议控制在约 70ch 内。
+- **Label** (600, 14px, 1.4): 导航、表头、按钮和状态标签。
+
+### Named Rules
+
+**The Dense Tool Rule.** 顶栏和导航保持 12–14px 紧凑标签;页面标题才使用 30–36px,不把每个面板都做成英雄区。
## Layout
-- 顶栏:56px 高,logo + 「由壹点·品牌中心」+ 板块导航 + 用户区;发丝线下边
-- 容器:`max-w-[1280px] px-6`;板块间距 64–96px
-- 编号索引:五行,网格 `[64px_1fr_160px_120px_32px]`(移动端 `[44px_1fr_auto]`,状态点保留)
-- 已上线板块:两张 12px 圆角白卡(`p-8/10`)承载入口按钮
+桌面端采用固定侧栏工作台:导航轨宽 272px,可折叠为 80px;右侧顶栏高 72px;主内容最大宽度 1600px,使用 16/24/32px 响应式内边距。首页标题后直接进入五条纵向职责域,每条职责域下的小项在桌面端同一横排,窄屏改为一至两列。
+
+1024px 以下隐藏固定侧栏,以左侧模态抽屉替代。抽屉宽度为 `min(86vw, 304px)`,打开时锁定页面滚动、底层内容 `inert`、焦点进入并约束在导航内,支持 Escape 关闭并恢复触发器焦点。390px 页面不得产生全局横向溢出。
+
+自动化工作流在 Department Shell 内容区内再分两层:桌面左侧为 232px 白 / 雾灰二级栏,右侧为 `minmax(0, 1fr)` 的同源实际业务操作面;移动端二级栏移动到内容顶部,以两列菜单呈现。二级栏永久不渲染“自动化工作流”标题、接入数量或独立统计区,只显示“绩效考核调研”“作品过稿看板”两个菜单。`?workflow=performance-survey|work-review` 持久化当前选择并与嵌入内容同步。
+
+右侧通过同源 iframe 直接嵌入 `/performance-survey` 与 `/work-review`,保留原业务的真实数据、权限和交互。嵌入业务中所有 `href="/"` 的跨应用返回必须使用 `target="_top"`,确保返回品牌中心根页面而不是在 iframe 内再次嵌套首页。
+
+**The Two-Level Workflow Rule.** 自动化工作流的二级栏只包含两个业务菜单,不添加标题、数量、说明头或入口卡;右侧始终是当前菜单对应的真实操作面。
+
+**The Top-Level Return Rule.** 嵌入业务的根路径返回必须跳出 iframe 到顶层浏览上下文,禁止在操作面内再次嵌入品牌中心首页。
+
+## Elevation & Depth
+
+系统以边框和底色分层为主,阴影只提供轻微离地感。顶栏与静态数据面板无需强阴影;首页职责域、指标组和悬浮菜单可使用低强度环境阴影。
+
+### Shadow Vocabulary
+
+- **Panel Low** (`0 6px 18px rgba(15, 23, 42, 0.05)`): 仅用于需要与画布分离的主要白色面板。
+- **Menu** (`0 14px 38px rgba(15, 23, 42, 0.16)`): 账户菜单、移动浮层和可拖动榜单。
+
+### Named Rules
+
+**The Border-First Rule.** 默认先用 `#e2e8f0` 细边框建立结构;不要用超过 20px 的主表面圆角与大阴影制造漂浮岛。
+
+## Shapes
+
+主表面使用 8–12px 圆角:8px 用于字段、导航项和小面板,12px 用于职责域和大数据面板。固定侧栏和顶栏已提供位置上下文,子页面不重复渲染面包屑。圆形只用于状态点、头像和明确图标容器。不得恢复 22–28px 的门户式主表面。
## Components
-- 索引行:已上线 = 整行可点 Link,悬停白底+箭头浮现+编号变紫;规划中 = 灰行不可点
-- 按钮:主 = 墨色实心 8px 圆角;次 = 1px 墨边白底,hover 反色
-- 状态:7px 圆点 + 12px 文字(移动端不隐藏)
-- 焦点:`ring-2 ring-[#1a1c1d]/70 ring-offset-2`,全站交互元素必带
+### Buttons
-## Motion
+- **Shape:** 8–12px 圆角,最小触控高度 40–44px。
+- **Primary:** `#1677ff` 背景和白字;hover 变深,focus-visible 使用清晰蓝色环。
+- **Secondary:** 白底、`#e2e8f0` 边框和深色文字。
-GSAP(`useGSAP` + `matchMedia('(prefers-reduced-motion: no-preference)')`):巨字升起 → 光晕淡入 → 索引行 stagger 0.08 → 注脚淡入;光晕 5s 纯 opacity 呼吸循环。全部 0.4–1.2s,信息效率优先(用户既定标准:略丰富但克制)。
+### Chips
-## Surfaces
+- **Style:** 8px 或全圆角;状态文案必须同时说明“实时读取”“示例值”或“待接入”,不能只靠颜色。
-::selection = `#eef0fa`;链接 `underline-offset-4`;光晕容器 `overflow-hidden` 防移动端横向溢出。
+### Cards / Containers
-## Scope Notes
+- **Corner Style:** 主要面板 12px,内部分区 8px。
+- **Background:** 白色;次级行可用 `#f8fafc`。
+- **Shadow Strategy:** 边框优先,阴影克制。
+- **Internal Padding:** 20–32px,随屏宽收紧。
-- **2026-08-17 用户裁定:本次是比较重大的升级,视觉语言需要全面升级。** 后续页面不得再做「旧壳换色 / 只改角标和按钮」的局部换皮;信息架构可保留,版式、组件、密度、动效应按本世界重做。
-- 组织架构页(`/organization`)仍为旧「云采石场」语言(BoardShell),待按本世界全面对齐
-- 素材库(`/materials`)顶栏已是看板语言;列表、筛选、卡片仍是旧素材库骨架,需按本世界全面升级,而不是只改色板
+### Inputs / Fields
+
+- **Style:** 白底、8px 圆角、`#e2e8f0` 边框。
+- **Focus:** `#1677ff` 边框或 2px focus ring。
+- **Error / Disabled:** 红色错误与降低不透明度并用,保留文字解释。
+
+### Navigation
+
+- 深色轨默认文字为 `#aebdcd`,hover 使用低透明白色,当前项使用 `#1677ff` + 白字。
+- 侧栏从五个职责域直接开始,不显示独立“部门总览”入口;首页标题仍由白色顶栏提供页面定位。
+- 账户入口固定在侧栏最下方并向上展开菜单;顶栏只保留页面定位与导航折叠控制。
+- 子页面标题直接承接首屏内容,不在标题上方增加重复的面包屑面板。
+- 22 个小项在侧栏使用 16px 语义线性图标;选中项图标随文字切为白色,页面标题区不重复摆放同一导航图标。
+- 大职责域按钮只展开/收起;小项链接承担导航,并以 `aria-current="page"` 标识当前位置。
+- 移动抽屉使用 `role="dialog"`、`aria-modal="true"` 和完整键盘焦点管理。
+
+### Automation Workflow Split Workbench
+
+- **Desktop Structure:** 深色主导航右侧是 232px 白 / 雾灰二级栏,再右侧是同源真实操作面;整体填满 `calc(100dvh - 72px)`,不生成欢迎页或入口卡片。
+- **Menus:** 只显示“绩效考核调研”和“作品过稿看板”。选中项使用 `#e6f4ff` 底、`#0050cb` 标题、`#1677ff` 图标和 `#315f91` 说明;未选项使用 `#4f6077` 标题、`#667085` 说明,hover 为 `#eef2f6`,active hover 不得覆盖选中底。
+- **Focus:** 两个菜单最小高度 58px,8px 圆角,焦点环为 `#5a9ce6`;当前项同时设置 `aria-current="page"`。
+- **Mobile:** 同一菜单移动到操作面顶部并变为两列;桌面说明在窄屏隐藏,顺序和 URL 语义不变。
+- **Embedding:** `/performance-survey` 与 `/work-review` 直接保留各自真实数据、权限、工具栏和交互;`?workflow=` 记录选择。所有跨应用根路径返回使用 `target="_top"`。
+- **Permanent Omission:** 二级栏顶部永久不显示“自动化工作流”、接入数量、统计区或解释区。
+
+### Workspace Row
+
+首页每个职责域是不可点击的白色分组面板;域标题、摘要和说明置于上方,小项链接置于下方横排。五域色只用于图标软底、摘要与箭头,不改变统一白色数据面板材质。
+
+### Data Status Placement
+
+所有子页面从页面标题直接进入核心内容,不渲染独立的“数据接入说明”“数据来源说明”或“计算说明”面板。真实读取、示例值、待接入、读取失败和公式状态由对应卡片或数据模块自身承担;实际业务操作帮助不属于此类,仍应保留在需要的位置。
+
+## Do's and Don'ts
+
+### Do:
+
+- **Do** 在首页、框架页、指标页、明细页、加载/异常状态和素材库复用同一 Department Shell。
+- **Do** 保持 5 个职责域、22 个小项、20 个框架入口,以及素材库和自动化工作流两项已接入业务的产品真相。
+- **Do** 明确区分真实数据、示例值、公式待接入与空数据。
+- **Do** 在桌面与 390px 移动宽度验证导航、焦点和横向溢出。
+- **Do** 让自动化工作流的菜单、`?workflow=` 和右侧真实业务操作面始终同步。
+- **Do** 让嵌入业务的根路径返回以 `target="_top"` 跳出 iframe。
+
+### Don't:
+
+- **Don't** 恢复旧版漂浮岛视觉、门户式白色英雄卡或超过 20px 的主表面圆角。
+- **Don't** 让职责域标题本身成为导航;只有下方小项链接进入二级页面。
+- **Don't** 复制参考图中的京东品牌、店铺指标、水印或虚构业务数据。
+- **Don't** 让移动抽屉键盘焦点穿透到底层页面。
+- **Don't** 在自动化工作流二级栏顶部显示标题、接入数量、统计区或独立说明区。
+- **Don't** 用入口卡片、复制页面或假数据替代 `/performance-survey` 与 `/work-review` 的真实操作面。
+- **Don't** 让 `href="/"` 在 iframe 内打开并嵌套品牌中心首页。
diff --git a/Dockerfile b/Dockerfile
index 81bbb5d..d0511e1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -31,6 +31,20 @@ RUN --mount=type=cache,target=/root/.npm \
node -e "const sharp=require('sharp'); sharp(Buffer.alloc(4),{raw:{width:1,height:1,channels:4}}).png().toBuffer().then(()=>console.log('sharp dependency smoke passed')).catch((error)=>{console.error(error);process.exit(1)})" && \
echo "Dependencies installed ($(du -sh /app/node_modules | cut -f1))"
+# 本地开发阶段:复用依赖层,并补齐项目运行时会调用的媒体处理工具。
+# 源码由 Compose 绑定挂载,避免每次修改代码都重新构建镜像。
+FROM deps AS dev
+ARG ALPINE_MIRROR
+RUN apk add --no-cache ffmpeg openssl poppler-utils
+
+ENV NODE_ENV=development
+ENV NEXT_TELEMETRY_DISABLED=1
+ENV HOSTNAME=0.0.0.0
+
+EXPOSE 3000
+
+CMD ["npm", "run", "dev", "--", "--hostname", "0.0.0.0"]
+
# 构建阶段
FROM base AS builder
ARG ALPINE_MIRROR
diff --git a/PRODUCT.md b/PRODUCT.md
index 68087fb..51ddd87 100644
--- a/PRODUCT.md
+++ b/PRODUCT.md
@@ -6,63 +6,45 @@
web
-## Stack
-
-Next.js 14 (App Router) + React 18 + TypeScript + TailwindCSS + PostgreSQL(Prisma)。既有代码库已定栈。
-
## Users
-- **系统管理员**:维护平台人员与组织数据,需要看到全量真实组织架构、人员归属、职级与汇报线。
-- **部门负责人**:查看本部门组织与人员情况(本部门范围内)。
-- 用户为内部员工(非程序员),界面需日常语言、少术语、可直接读。
+品牌中心内部成员、部门负责人和管理者。他们需要从统一入口定位业务、资产、组织与治理相关工作,并按自身权限进入具体工具。
## Product Purpose
-把「由壹点3D素材库」逐步改造为「品牌中心部门看板」(对内品牌:**由壹点·品牌中心**,隶属由壹点软件集团)。第一阶段(2026-08-15)已完成:登录落点切换为看板首页 `/`,素材库整体迁至 `/materials`,组织架构上移为顶层 `/organization`(旧路径 `/admin/org` 服务端跳转)。
-
-## Positioning
-
-以钉钉唯一值为唯一人员身份判定依据,统一接入公司 HR 报表库(非钉钉通讯录),人员/组织数据全平台一致;考核调研与素材库共用同一份权威人员主档,业务特殊数据隔离在各自专属表。素材库为在产系统,改造期间上传/下载/分享/权限链路不动。
+“品牌中心部门看板”是品牌中心的一级工作门户,用五个业务域组织部门工作入口:中心仪表盘、业务经营、资产与AI自动化、组织管理、治理与设置。当前先建立信息架构和导航框架,底层业务数据后续接入。
## Operating Context
-- 人员权威数据源:公司 SQL Server 报表库(`rpt` schema),每日 02:00(Asia/Shanghai)自动同步组织架构→在职状态→离职联动。
-- 只有「开过素材库账号 + 已建立钉钉绑定」的人员进入展示/统计体系(约 503 人);无账号的仓储/物流等约 1200 人不纳入。
-- 在职判定用规范化 `employmentState`(ACTIVE/RESIGNED/UNKNOWN,UNKNOWN 视为在职),不用关键词匹配。
+产品运行在内部 Web 环境中,既有“由壹点3D素材”平台已经在线运行。本地开发阶段必须与线上数据和部署链路隔离;代码只有在用户明确指示后才允许提交或部署。
## Capabilities and Constraints
-- 看板首页 `/`:五大板块编号索引(01 创意资产库全员可进 / 02 组织管理仅管理员 / 03-05 规划中如实标灰),入场"对焦"动效,悬停物理重量语言。
-- 创意资产库 `/materials`:原素材库首页,**业务功能不动**;顶栏已统一为看板语言。2026-08-17 起按「重大升级」处理:视觉语言要全面对齐看板世界,禁止只改色板/圆角的局部换皮。
-- 组织架构页 `/organization`:组织树 + 人员列表,展示 M/P 等级、人员归属(部门路径)、直属主管、在职状态。
-- 纯展示(只读),不改数据。
-- 权限:系统管理员看全部;部门负责人看本部门。
-- 离职人员默认隐藏,可切换「含离职」。
-- 无绑定账号(无钉钉 ID,约 15 人)与部门未确定人员(约 57 人)单独分组,不消失、不硬塞部门。
-- 数据缺口如实展示:直属主管覆盖率低(约 158/503)、部分人员无 M/P 等级。
+- 一级门户根路径为 `/`。
+- “由壹点3D素材”作为“资产与AI自动化”下的二级页面保留完整现有能力。
+- “自动化工作流”作为“资产与AI自动化”下的业务入口,集中链接现有的绩效考核调研与作品过稿看板。
+- 除素材资产库、自动化工作流和已接入的中心指标外,其余板块现阶段只展示可理解、可扩展的模块框架,不虚构业务数据。
+- 沿用项目现有 Next.js、NextAuth、Tailwind CSS 和权限体系。
## Brand Commitments
-- 平台名:由壹点·品牌中心(隶属由壹点软件集团;素材库模块沿用「由壹点3D素材」之名)。
-- **首页视觉方向(2026-08-15 用户裁定):Zen Minimal × Future Organic 融合**——白纸(#fafafa)黑字(#1a1c1d)的瑞士编辑排印、发丝线、超大留白、编号索引列表(作品集语言)、右上角唯一柔紫光晕(#6e79c8 系)缓慢呼吸;平面化无阴影,黑实心按钮 8px 圆角。方向源自用户在 Stitch 自生成的候选 3/4 + 作品集文件夹两份 DESIGN.md(Monochrome/Studio Minimalist)。此前的「云采石场」语言仅保留在组织架构页(BoardShell),后续按新方向对齐。
-- **logo 双版本规则**:黑底表面(素材库旧顶栏)用 `headerLogoUrl`(亮色图案);浅底表面(看板首页、BoardShell)用 `loginLogoUrl`(深蓝+橙图案)。两者内容不同,不可混用。
-- **全站浅色单主题(2026-08-15 裁定)**:深色主题废弃,`tailwind darkMode: 'class'` 且不挂 `.dark`;新代码禁止 `dark:` 类。
-- 动效标准:略丰富但克制(用户既定),GSAP + matchMedia(prefers-reduced-motion) + fromTo + clearProps,200-500ms,信息效率优先。
+- 产品主标题使用“品牌中心部门看板”。
+- 信息架构以用户提供的五分支部门工作地图为依据,使用克制、清晰的业务语言。
+- 保留“由壹点3D素材”现有名称和功能语义。
## Evidence on Hand
-- 思维导图:`资料/品牌中心部门看板(初版).jpg`(5 大板块规划)。
-- 交接文档:`docs/人员架构界面切换-交接文档-2026-08-14.md`。
-- 数据盘点:`scripts/diagnose-people-architecture.ts`(只读,可重复跑)。
+- 用户提供的五板块思维导图截图。
+- 当前仓库内已运行的素材库页面、登录、权限和后台功能。
+- 暂无用于一级门户的真实业务指标,界面不得编造数值或经营结论。
## Product Principles
-1. 人员身份只认钉钉唯一值;姓名/邮箱仅人工排错,不自动建绑定。
-2. 只展示「有账号+绑定」的人,无账号的仓储/物流等不纳入统计。
-3. 在职判定用规范化 `employmentState`,UNKNOWN 视为在职(宁可多留)。
-4. 数据如实展示,不造假:主管/等级缺失就显示"未记录"。
-5. 归属与署名分离:素材归属与作者署名对不上通常是正确的,不"修正"。
+- 先让入口与职责边界清楚,再接入数据。
+- 一级门户负责导航与全局理解,二级页面负责完成具体任务。
+- 保持线上业务稳定,本地验证充分后再由用户决定是否提交和部署。
+- 对不可用能力诚实标注状态,不用假数据制造完成感。
## Accessibility & Inclusion
-内部后台工具,目标用户为内部员工;遵循基础可访问性(语义化、键盘可操作、对比度达标)。
+门户的核心导航必须支持键盘操作、清晰焦点、语义化标签,并在桌面端与移动端保持可读和可用。
diff --git a/README.md b/README.md
index be90666..8c2b1a7 100644
--- a/README.md
+++ b/README.md
@@ -243,6 +243,51 @@ docker compose up -d
http://localhost:3000
```
+登录后的一级入口为“品牌中心部门看板”,当前页面路由如下:
+
+```text
+品牌中心部门看板:http://localhost:3000/
+小项二级框架示例:http://localhost:3000/workspaces/dashboard/core-metrics
+由壹点3D素材:http://localhost:3000/assets/material-library
+```
+
+### 无本机 Node 环境时使用 Docker 开发
+
+仓库提供一套隔离的 Docker 开发环境,包含 Node.js 22、PostgreSQL、Redis、MinIO 和支持源码热更新的 Next.js。它使用独立数据卷,不连接生产数据库或生产对象存储。
+
+```bash
+docker compose \
+ --env-file .env.docker-test.local \
+ -f docker-compose.local-test.yml \
+ -f docker-compose.dev.yml \
+ up -d --build
+```
+
+首次启动会自动执行 `prisma generate` 和 `prisma db push`。启动完成后访问:
+
+```text
+应用:http://localhost:4321
+MinIO 控制台:http://localhost:59001
+```
+
+查看应用日志或停止环境:
+
+```bash
+docker compose \
+ --env-file .env.docker-test.local \
+ -f docker-compose.local-test.yml \
+ -f docker-compose.dev.yml \
+ logs -f app
+
+docker compose \
+ --env-file .env.docker-test.local \
+ -f docker-compose.local-test.yml \
+ -f docker-compose.dev.yml \
+ down
+```
+
+`down` 会保留本地数据库和上传文件;只有显式增加 `--volumes` 才会清除本地开发数据。
+
## 常用脚本
```bash
diff --git a/app/api/department-dashboard/core-metrics/first-pass/route.ts b/app/api/department-dashboard/core-metrics/first-pass/route.ts
new file mode 100644
index 0000000..a4b2eff
--- /dev/null
+++ b/app/api/department-dashboard/core-metrics/first-pass/route.ts
@@ -0,0 +1,37 @@
+import { getServerSession } from 'next-auth'
+import { NextResponse } from 'next/server'
+import { authOptions } from '@/lib/auth'
+import { PerformanceSurveyApiError } from '@/lib/performance-survey-service'
+import {
+ WorkReviewApiError,
+ getFirstPassReviewSummary,
+} from '@/lib/work-review-service'
+
+export const runtime = 'nodejs'
+export const dynamic = 'force-dynamic'
+export const revalidate = 0
+
+const PRIVATE_HEADERS = {
+ 'Cache-Control': 'private, no-store, max-age=0',
+}
+
+export async function GET() {
+ try {
+ const session = await getServerSession(authOptions)
+ const data = await getFirstPassReviewSummary(session)
+ return NextResponse.json({ success: true, data }, { headers: PRIVATE_HEADERS })
+ } catch (error) {
+ if (error instanceof WorkReviewApiError || error instanceof PerformanceSurveyApiError) {
+ return NextResponse.json(
+ { success: false, error: error.message },
+ { status: error.status, headers: PRIVATE_HEADERS },
+ )
+ }
+
+ console.error('[department-dashboard] 首轮通过指标读取失败:', error)
+ return NextResponse.json(
+ { success: false, error: '首轮通过指标读取失败,请稍后重试' },
+ { status: 500, headers: PRIVATE_HEADERS },
+ )
+ }
+}
diff --git a/app/assets/material-library/layout.tsx b/app/assets/material-library/layout.tsx
new file mode 100644
index 0000000..7fa9c52
--- /dev/null
+++ b/app/assets/material-library/layout.tsx
@@ -0,0 +1,14 @@
+import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+ title: '由壹点3D素材 | 品牌中心部门看板',
+ description: '品牌中心资产与AI自动化素材库',
+}
+
+export default function MaterialLibraryLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode
+}>) {
+ return children
+}
diff --git a/app/assets/material-library/page.tsx b/app/assets/material-library/page.tsx
new file mode 100644
index 0000000..424c608
--- /dev/null
+++ b/app/assets/material-library/page.tsx
@@ -0,0 +1,1639 @@
+'use client'
+
+import { useEffect, useState, useRef, useCallback, useDeferredValue, useMemo } from 'react'
+import { useSession } from 'next-auth/react'
+import { useRouter, usePathname } from 'next/navigation'
+import Link from 'next/link'
+import UploadModal from '@/components/UploadModal'
+import RankingPanel from '@/components/RankingPanel'
+import DepartmentShell from '@/components/department-dashboard/DepartmentShell'
+import AIChatWidget from '@/components/AIChatWidget'
+import VideoPlayerModal from '@/components/VideoPlayerModal'
+import ToastBubble from '@/components/ToastBubble'
+import { useToast } from '@/hooks/useToast'
+import { parseDownloadError } from '@/lib/download-errors'
+import { validateAndTriggerDownload } from '@/lib/client-download'
+import { parseApiError, handleError, parseFetchError } from '@/lib/error-handler'
+import { normalizeVideoMaterialType, isVideoMaterialType as isVideoMaterialTypeValue } from '@/lib/video-material-types'
+import { buildPublicMaterialShareUrl } from '@/lib/public-app-url'
+import { normalizeMaterialPreviewUrl, pickFirstMaterialPreviewUrl } from '@/lib/material-preview-url'
+// 首页拆分组件
+import { SearchBar, FilterPanel, LoadMoreTrigger, MaterialGrid } from '@/components/home'
+
+interface Material {
+ id: string
+ userId: string
+ previewUrl: string
+ productModel: string
+ categoryName: string
+ sceneName: string
+ platformName?: string // 平台分类
+ productCategoryName?: string // 品类分类
+ materialType: string
+ isAiGenerated?: boolean
+ taskDetailSourceType?: string | null
+ renderer: string
+ authorName: string
+ zipFileName: string
+ zipFileSize: string | number
+ downloadCount: number
+ likeCount: number
+ isLiked: boolean
+ isFavorited: boolean // 收藏状态
+ createdAt: string
+ displayImages?: string[] // 展示图片数组(详情页/模特类型)
+ videoSourceUrl?: string | null // 原始视频URL
+ videoPreview540Url?: string | null // 720p预览视频URL(字段名保持540Url以兼容数据库)
+ videoPreviewClipUrl?: string | null // 视频片段URL
+ videoCoverUrl?: string | null // 视频封面URL
+ videoProcessingStatus?: string | null // 视频处理状态
+ videoPreviewBlocked?: boolean
+ videoPreviewUnavailableMessage?: string | null
+ videoPreviewRemainingDays?: number | null
+ videoDuration?: number | null // 视频时长(秒)
+ transcodeLastError?: string | null // 转码错误信息
+ transcodeAttempts?: number | null // 转码尝试次数
+ transcodeProgress?: number | null // 转码进度百分比
+ transcodeStage?: string | null // 转码阶段:preview/clip/cover
+ transcodeQueueWaitingIndex?: number | null // 队列等待索引
+ transcodeQueueWaitingTotal?: number | null // 队列等待总数
+ transcodeQueueProcessingIds?: string[] // 正在处理的ID列表
+ transcodeQueueMaxConcurrent?: number | null // 最大并发数
+ user: {
+ username: string
+ avatar?: string | null
+ }
+}
+
+interface FacetItem {
+ id: string
+ name: string
+ count: number
+}
+
+interface MonthFacetItem {
+ value: string
+ label: string
+ count: number
+}
+
+interface FacetTotals {
+ materialType: number
+ category: number
+ scene: number
+ platform: number
+ productCategory: number
+ month: number
+}
+
+const EMPTY_FACET_TOTALS: FacetTotals = {
+ materialType: 0,
+ category: 0,
+ scene: 0,
+ platform: 0,
+ productCategory: 0,
+ month: 0,
+}
+
+export default function MaterialLibraryPage() {
+ const { data: session, status } = useSession()
+ const router = useRouter()
+ const pathname = usePathname()
+ const [materials, setMaterials] = useState([])
+ const [loading, setLoading] = useState(true)
+ const [showUploadModal, setShowUploadModal] = useState(false)
+ const [searchKeyword, setSearchKeyword] = useState('')
+ const [selectedCategory, setSelectedCategory] = useState('')
+ const [selectedScene, setSelectedScene] = useState('')
+ const [selectedMaterialType, setSelectedMaterialType] = useState('') // 素材类型筛选,默认展示全部
+ // const [selectedMaterialType, setSelectedMaterialType] = useState('3D场景') // 素材类型筛选,默认展示3D场景(已注释,改为默认展示全部)
+ const [selectedPlatform, setSelectedPlatform] = useState('') // 平台分类筛选
+ const [selectedProductCategory, setSelectedProductCategory] = useState('') // 品类筛选
+ const [categories, setCategories] = useState([])
+ const [scenes, setScenes] = useState([])
+ const [platforms, setPlatforms] = useState([])
+ const [productCategories, setProductCategories] = useState([])
+ const [isFilterCollapsed, setIsFilterCollapsed] = useState(true) // 筛选区域折叠状态,默认折叠
+ // 素材类型列表(已分类排序)
+ const [materialTypes, setMaterialTypes] = useState<{ value: string; label: string; count?: number }[]>([])
+ const [materialTypeCounts, setMaterialTypeCounts] = useState>({})
+ const [isTransitionLoading, setIsTransitionLoading] = useState(false)
+ const [downloadingId, setDownloadingId] = useState(null)
+ const [downloadProgress, setDownloadProgress] = useState(0)
+ const [selectedMonth, setSelectedMonth] = useState('')
+ const [months, setMonths] = useState([])
+ const [sortBy, setSortBy] = useState('createdAt') // createdAt | downloadCount
+ const [sortOrder, setSortOrder] = useState<'desc' | 'asc'>('desc') // 排序方向:desc 倒序(默认)| asc 正序
+ const [previewImage, setPreviewImage] = useState<{ url: string; title: string } | null>(null)
+ const [showVideoModal, setShowVideoModal] = useState(false)
+ const [videoSrc, setVideoSrc] = useState(null)
+ const transcodePollTimers = useRef