From 87bb0e126df37831708e18ce6b9651a8b9a44f5e Mon Sep 17 00:00:00 2001 From: WuYongJie Date: Fri, 17 Apr 2026 11:07:18 +0800 Subject: [PATCH] feat: refresh branding and material library workspace --- README.md | 2 +- docs/Precision-Atelier设计系统改造记录.md | 40 + docs/前端UI改动清单.md | 17 + furniture-3d-system/README.md | 2 +- furniture-3d-system/docs/README.md | 2 +- furniture-3d-system/docs/项目总览.md | 2 +- furniture-3d-system/public/custom-logo.png | Bin 0 -> 8345 bytes .../MaterialLibraryClient.test.tsx | 8 +- .../MaterialLibraryClient.tsx | 1135 ++++++++++------- furniture-3d-system/src/app/layout.tsx | 2 +- furniture-3d-system/src/lib/branding.ts | 2 +- 11 files changed, 770 insertions(+), 442 deletions(-) create mode 100644 furniture-3d-system/public/custom-logo.png diff --git a/README.md b/README.md index eb802ba4..e700c46d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 3D 家具开品平台工作区 +# 由壹点「产品开发平台」工作区 > 最后更新:2026-04-07 > 当前主线:`资产中心 -> 自动组合 -> 草稿组 -> 包装方案 -> 正式入库 -> 轻仓库` diff --git a/docs/Precision-Atelier设计系统改造记录.md b/docs/Precision-Atelier设计系统改造记录.md index 13874f62..2dae1627 100644 --- a/docs/Precision-Atelier设计系统改造记录.md +++ b/docs/Precision-Atelier设计系统改造记录.md @@ -212,3 +212,43 @@ | `src/app/warehouse/WarehouseClient.tsx` | 移除 headerTools/eyebrow | | `src/app/HomeClient.workspace.tsx` | 移除 topTools 传参 | | ~20 个业务文件 | 硬编码颜色替换 | + +--- + +## 第三阶段:管理基础设施视觉升级 (2026-04-16) + +### 10. 管理端专属视觉模式 (Management UI Patterns) + +在重构 `/admin` 和 `/users` 页面时,引入了针对“高密度控制类页面”的增强视觉模式,以平衡“工业精密感”与“视觉通透度”。 + +**1. 沉浸式页头 (Immersive Page Header)** +- **视觉特征**: + - 采用 `bg-white/60` + `backdrop-blur-2xl`。 + - 强化左侧 Icon 视觉,使用 `rounded-[2rem] bg-black` 黑色底座,并叠加状态徽章(如 `ShieldCheck`)。 + - **排版建议**:Manrope 3XL 标题 + 紧跟其后的 `text-apple-blue` 高亮关键词。 + - **副标题**:使用 `text-[10px] tracking-[0.4em] uppercase` 的精密说明文字。 + +**2. 精密控制条 (Precision Control Bar)** +- **定义**:将原本分散的“搜索框”与“筛选器”整合进一个逻辑整体。 +- **视觉实现**: + - 容器:`rounded-[2rem]` 极圆圆角,`border-white/80` 微光边框,`bg-white/40` 背景。 + - 搜索框:沉浸式设计,背景为 `bg-white/80`,聚焦时通过 `ring-apple-blue/5` 产生柔和晕染。 + - 筛选器:图标 (Lucide Icon) + Select 组件的紧凑组合,图标作为装饰前缀。 + +**3. 玻璃态卡片增强 (Enhanced Glass Cards)** +- **改动**:在 `rounded-[2rem]` 的基础上,引入了“装饰线”动效。 +- **动效逻辑**:`group-hover:w-full` 的底部 1.5px 强调线,颜色与模块 Icon 色调一致。 +- **背景文字装饰**:绝对定位的 `text-[80px]` 背景大字(如模块 path),设置 `opacity-[0.03]` 极低透明度,增加“空间感”。 + +**4. 状态指标看板 (System Health Dashboard)** +- **应用场景**:`/admin` 首页。 +- **组成**:Icon 容器 + 上下两行文本(上行为微缩标签,下行为状态值)。 +- **配色**:动态使用 `emerald-500` (正常), `blue-500` (活动), `amber-500` (注意)。 + +### 11. 改动文件清单 + +| 文件 | 改动类型 | 备注 | +|------|----------|------| +| `src/app/admin/page.tsx` | 重构 | 系统总控制台首页视觉重写 | +| `src/app/users/page.tsx` | 重构 | 身份控制中心 (用户管理) 视觉重写 | + diff --git a/docs/前端UI改动清单.md b/docs/前端UI改动清单.md index 4309f430..3263b66a 100644 --- a/docs/前端UI改动清单.md +++ b/docs/前端UI改动清单.md @@ -1,4 +1,21 @@ # 协作任务板 +## 已完成任务 (Completed) + +- **管理基础设施视觉升级 (Management Infrastructure UI Refactor)** + - **重构页面**: + - `系统总控制台 (/admin)`:引入“中枢枢纽”布局,增加系统状态看板 (Mock),优化卡片视觉张力。 + - `身份控制中心 (/users)`:引入“沉浸式页头”与“精密控制条”,整合搜索与筛选器。 + - **核心特性**: + - **Frosted Glass (磨砂玻璃)**:全局背景与卡片采用 70% 透明度 + 30px 模糊。 + - **Visual Hierarchy (视觉层级)**:通过大面积阴影与精致边框区分功能模块。 + - **Typography (排版)**:强化了 Manrope 标题与 Inter 技术标签的对比。 + - **负责人**:Gemini UI Engineer + - **完成日期**:2026-04-16 + +--- + +## 进行中任务 (In Progress) + - assisted-assembly(辅助装配):真实样本联调与验收 - 负责人:Codex diff --git a/furniture-3d-system/README.md b/furniture-3d-system/README.md index 7f4aef79..805f4af2 100644 --- a/furniture-3d-system/README.md +++ b/furniture-3d-system/README.md @@ -1,4 +1,4 @@ -# 家具开品平台 +# 由壹点「产品开发平台」 > 最后更新:2026-04-15 > 当前默认主线:`资产中心 -> 辅助装配 -> 草稿组 -> 正式入库 -> 轻仓库` diff --git a/furniture-3d-system/docs/README.md b/furniture-3d-system/docs/README.md index 43243904..4664ad4f 100644 --- a/furniture-3d-system/docs/README.md +++ b/furniture-3d-system/docs/README.md @@ -1,4 +1,4 @@ -# 家具开品平台文档导航 +# 由壹点「产品开发平台」文档导航 > 最后更新:2026-04-15 > 当前主线入口:`/asset-center -> /assisted-assembly -> /draft-groups -> /intake -> /warehouse` diff --git a/furniture-3d-system/docs/项目总览.md b/furniture-3d-system/docs/项目总览.md index 75d93ea2..5e7381e5 100644 --- a/furniture-3d-system/docs/项目总览.md +++ b/furniture-3d-system/docs/项目总览.md @@ -1,4 +1,4 @@ -# 家具开品平台项目总览 +# 由壹点「产品开发平台」项目总览 > 最后更新:2026-04-15 > 当前状态:新平台主线已进入真实业务测试与收口阶段 diff --git a/furniture-3d-system/public/custom-logo.png b/furniture-3d-system/public/custom-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b7baa95d257b820fb55f68e18307915e19d2b5b8 GIT binary patch literal 8345 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 { await actor.click(screen.getByRole('button', { name: /饰面花色/ })) await actor.click(screen.getByRole('button', { name: /新建/ })) await actor.type(screen.getByLabelText('花色名称'), '北美橡木') - await actor.clear(screen.getByLabelText('金属度')) - await actor.type(screen.getByLabelText('金属度'), '0.2') - await actor.clear(screen.getByLabelText('粗糙度')) - await actor.type(screen.getByLabelText('粗糙度'), '0.6') + fireEvent.change(screen.getByLabelText('金属度'), { target: { value: '0.2' } }) + fireEvent.change(screen.getByLabelText('粗糙度'), { target: { value: '0.6' } }) await actor.clear(screen.getByLabelText('纹理实物宽度(mm)')) await actor.type(screen.getByLabelText('纹理实物宽度(mm)'), '800') await actor.click(screen.getByRole('button', { name: '创建' })) diff --git a/furniture-3d-system/src/app/asset-center/material-library/MaterialLibraryClient.tsx b/furniture-3d-system/src/app/asset-center/material-library/MaterialLibraryClient.tsx index b3368e11..cb8e9541 100644 --- a/furniture-3d-system/src/app/asset-center/material-library/MaterialLibraryClient.tsx +++ b/furniture-3d-system/src/app/asset-center/material-library/MaterialLibraryClient.tsx @@ -21,6 +21,7 @@ import { DeleteConfirmDialog } from '@/components/ui/DeleteConfirmDialog' import Modal from '@/components/ui/Modal' import Input from '@/components/ui/Input' import Select from '@/components/ui/Select' +import Slider from '@/components/ui/Slider' import { ToastContainer, useToast } from '@/components/ui/Toast' import { PlatformSplitLayout } from '@/components/platform/PlatformSplitLayout' import type { PlatformMetricItem } from '@/components/platform/types' @@ -158,6 +159,26 @@ function toOptionalNumber(value: string): number | null { return Number.isFinite(next) ? next : null } +function normalizeSliderValue(value: number): string { + return value.toFixed(2).replace(/\.?0+$/, '') +} + +function toClampedUnitValue(value: string, fallback: number): number { + const numericValue = Number(value) + if (!Number.isFinite(numericValue)) { + return fallback + } + return Math.min(1, Math.max(0, numericValue)) +} + +function formatDecimalValue(value: string | number, digits = 2): string { + const numericValue = typeof value === 'number' ? value : Number(value) + if (!Number.isFinite(numericValue)) { + return '--' + } + return numericValue.toFixed(digits).replace(/\.?0+$/, '') +} + function emptySubstrateForm(dict: SubstrateDictionaryBundleDTO): SubstrateFormState { return { categoryId: dict.categories[0]?.id ?? '', @@ -269,6 +290,157 @@ function materialPreviewUrl(material: MaterialDTO): string | null { return material.thumbnailUrl ?? material.textureUrl ?? material.previewUrl ?? null } +function materialToFinishForm(item: MaterialDTO): FinishFormState { + return { + name: item.name, + categoryId: item.categoryId, + thumbnailUrl: item.thumbnailUrl ?? '', + thumbnailPreview: item.thumbnailUrl ?? '', + textureUrl: item.textureUrl ?? '', + texturePreview: item.textureUrl ?? item.previewUrl ?? '', + normalMapUrl: item.normalMapUrl ?? '', + normalMapPreview: item.normalMapUrl ?? '', + color: item.color ?? '#cccccc', + metalness: String(item.metalness ?? 0), + roughness: String(item.roughness ?? 0.5), + opacity: String(item.opacity ?? 1), + textureRepeat: String(item.textureRepeat ?? 1), + textureRotation: String(item.textureRotation ?? 0), + textureSizeMm: String(item.textureSizeMm ?? 600), + } +} + +function FinishParameterSliderField({ + id, + label, + value, + helper, + disabled = false, + onChange, +}: { + id: string + label: string + value: string + helper: string + disabled?: boolean + onChange: (nextValue: string) => void +}) { + const fallback = label === '粗糙度' ? 0.5 : label === '透明度' ? 1 : 0 + const currentValue = toClampedUnitValue(value, fallback) + + return ( +
+
+
+ +

{helper}

+
+ + {formatDecimalValue(currentValue)} + +
+ + onChange(normalizeSliderValue(nextValue))} + /> + +
+ 0 + 1 +
+
+ ) +} + +function FinishWorkbenchPreviewCard({ + form, + categoryName, + code, + statusLabel, +}: { + form: FinishFormState + categoryName: string + code: string + statusLabel: string +}) { + const displayColor = form.color || '#cccccc' + + const sphereSurfaceStyle = useMemo(() => ({ + backgroundColor: displayColor, + backgroundImage: form.texturePreview + ? `url(${form.texturePreview})` + : form.textureUrl + ? `url(${form.textureUrl})` + : form.thumbnailPreview + ? `url(${form.thumbnailPreview})` + : 'none', + backgroundSize: 'cover', + backgroundPosition: 'center', + }), [displayColor, form.texturePreview, form.textureUrl, form.thumbnailPreview]) + + return ( +
+
+
+
+ + {statusLabel} + +

+ {form.name.trim() || '未命名材质'} +

+

+ {categoryName} · {code} +

+
+
+ 实时预览 +
+
+ +
+
+
+
+
+
+
+ +
+ {[ + { label: '金属度', value: form.metalness }, + { label: '粗糙度', value: form.roughness }, + { label: '透明度', value: form.opacity }, + ].map((item) => ( +
+

+ {item.label} +

+

+ {formatDecimalValue(item.value)} +

+
+ ))} +
+
+ ) +} + function FinishPreviewHeader({ form, categoryName, @@ -600,6 +772,32 @@ export default function MaterialLibraryClient({ return null }, [panel, substrates]) + const finishWorkspaceForm = + panel.mode === 'create-finish' || panel.mode === 'edit-finish' + ? finishForm + : panel.mode === 'view-finish' && selectedFinish + ? materialToFinishForm(selectedFinish) + : null + + const finishWorkspaceCategoryName = finishWorkspaceForm + ? categories.find((item) => item.id === finishWorkspaceForm.categoryId)?.name + ?? selectedFinish?.categoryName + ?? '未分类' + : '未分类' + + const finishWorkspaceCode = + panel.mode === 'create-finish' + ? '保存后生成' + : selectedFinish?.code ?? '系统生成' + + const finishSpotlightPreviewUrl = finishWorkspaceForm + ? finishWorkspaceForm.texturePreview + || finishWorkspaceForm.textureUrl + || finishWorkspaceForm.thumbnailPreview + || finishWorkspaceForm.thumbnailUrl + || null + : null + const liveMetrics = useMemo( () => buildLiveMetrics(metrics, { @@ -637,23 +835,7 @@ export default function MaterialLibraryClient({ } function startEditFinish(item: MaterialDTO) { - setFinishForm({ - name: item.name, - categoryId: item.categoryId, - thumbnailUrl: item.thumbnailUrl ?? '', - thumbnailPreview: item.thumbnailUrl ?? '', - textureUrl: item.textureUrl ?? '', - texturePreview: item.textureUrl ?? '', - normalMapUrl: item.normalMapUrl ?? '', - normalMapPreview: item.normalMapUrl ?? '', - color: item.color ?? '#cccccc', - metalness: String(item.metalness ?? 0), - roughness: String(item.roughness ?? 0.5), - opacity: String(item.opacity ?? 1), - textureRepeat: String(item.textureRepeat ?? 1), - textureRotation: String(item.textureRotation ?? 0), - textureSizeMm: String(item.textureSizeMm ?? 600), - }) + setFinishForm(materialToFinishForm(item)) setPanel({ mode: 'edit-finish', id: item.id }) } @@ -1179,428 +1361,421 @@ export default function MaterialLibraryClient({ let inspectorHeader: ReactNode = null if (panel.mode === 'empty') { - rightContent = ( -
-
-
- -
-

- 选择资料 -

-

- 从左侧选择一个基材或饰面查看详情,也可以直接点击「新建」开始维护。 -

-
-
- ) - } else if (panel.mode === 'view-finish' && selectedFinish) { - const finishPreview = materialPreviewUrl(selectedFinish) - inspectorHeader = ( - - ) - - rightContent = ( -
-
-

花色详情

-
- - -
-
- - {finishPreview ? ( - {selectedFinish.name} setPreviewUrl(finishPreview)} - /> - ) : ( -
- )} - -
-
-

编码

-

{selectedFinish.code}

-
-
-

分类

-

{selectedFinish.categoryName ?? '-'}

-
-
-

基础颜色

-
- -

{selectedFinish.color}

+ if (activeTab === 'finish') { + rightContent = ( +
+
+
+
+ +
+

+ 实时预览区 +

+

+ 先从左侧选一个花色,右侧上半区会立即显示材质预览,下半区进入参数维护。 +

-
-

透明度

-

{selectedFinish.opacity}

-
-
-

金属度

-

{selectedFinish.metalness}

-
-
-

粗糙度

-

{selectedFinish.roughness}

-
-
-

纹理重复

-

{selectedFinish.textureRepeat}

-
-
-

纹理旋转

-

{selectedFinish.textureRotation}

-
-
-

纹理实物宽度

-

{selectedFinish.textureSizeMm} mm

+ +
+
+

+ Material Controls +

+

参数工作区待激活

+

+ 这里会显示金属度、粗糙度、透明度滑块,以及贴图、颜色和纹理参数。 +

+
+ ) + } else { + rightContent = ( +
+
+
+ +
+

+ 选择资料 +

+

+ 从左侧选择一个基材或饰面查看详情,也可以直接点击「新建」开始维护。 +

+
+
+ ) + } + } else if (panel.mode === 'view-finish' && selectedFinish) { + const viewForm = materialToFinishForm(selectedFinish) + rightContent = ( +
+ -
- + +
+
+ +
+
+ + +
+ +
+
+

+ 基础颜色 +

+
+
+
+ {selectedFinish.color} +
+
+
+ + +
+ +
+ {}} /> - ) : ( -

未上传

- )} - - + {}} + /> +
+ +
+ + +
+ +
+ {[ + { title: '缩略图', preview: viewForm.thumbnailPreview }, + { title: '颜色纹理', preview: viewForm.texturePreview }, + { title: '法线贴图', preview: viewForm.normalMapPreview }, + ].map((asset) => ( +
+
+

+ {asset.title} +

+ {asset.preview && ( + + )} +
+ + {asset.preview ? ( + + ) : ( +
+ +
+ )} +
+ ))} +
+
) } else if (panel.mode === 'create-finish' || panel.mode === 'edit-finish') { const isCreate = panel.mode === 'create-finish' - const categoryName = categories.find((item) => item.id === finishForm.categoryId)?.name ?? '未分类' - inspectorHeader = - rightContent = ( -
-
-

- {isCreate ? '新建花色' : '编辑花色'} -

- -
+
+ -
- setFinishForm((current) => ({ ...current, name: event.target.value }))} - placeholder="例如 北美橡木" - /> - - setFinishForm((current) => ({ ...current, color: event.target.value })) - } - className="h-10 w-12 rounded border border-apple-separator bg-transparent" - /> - - setFinishForm((current) => ({ ...current, color: event.target.value })) - } - /> -
-
- - setFinishForm((current) => ({ ...current, textureSizeMm: event.target.value })) - } - /> - - setFinishForm((current) => ({ ...current, metalness: event.target.value })) - } - /> - - setFinishForm((current) => ({ ...current, roughness: event.target.value })) - } - /> - - setFinishForm((current) => ({ ...current, opacity: event.target.value })) - } - /> - - setFinishForm((current) => ({ ...current, textureRepeat: event.target.value })) - } - /> - - setFinishForm((current) => ({ ...current, textureRotation: event.target.value })) - } - /> -
- -
-
-

缩略图

- {finishForm.thumbnailPreview ? ( - - ) : ( -
- -
- )} - { - const file = event.target.files?.[0] - if (file) { - void handleMaterialAssetUpload('thumbnail', file) - } - event.target.value = '' - }} - /> -
- - {finishForm.thumbnailPreview && ( - - )} -
+

+ Material Controls +

+

+ {isCreate ? '新建花色工作台' : '编辑材质参数'} +

+

+ 预览始终在上面,参数始终在下面,调整时不会再被旧布局打散。 +

-
-

颜色纹理

- {finishForm.texturePreview ? ( - - ) : ( -
- -
- )} - { - const file = event.target.files?.[0] - if (file) { - void handleMaterialAssetUpload('texture', file) - } - event.target.value = '' - }} - /> -
- - {finishForm.texturePreview && ( - - )} -
-
- -
-

法线贴图

- {finishForm.normalMapPreview ? ( - - ) : ( -
- -
- )} - { - const file = event.target.files?.[0] - if (file) { - void handleMaterialAssetUpload('normal', file) - } - event.target.value = '' - }} - /> -
- - {finishForm.normalMapPreview && ( - - )} -
-
-
- -
-
+ +
+
+ setFinishForm((current) => ({ ...current, name: event.target.value }))} + placeholder="例如 北美橡木" + /> + + + setFinishForm((current) => ({ ...current, color: event.target.value })) + } + className="h-11 w-12 rounded-xl border border-apple-separator bg-transparent" + /> +
+
+ {finishForm.color} +
+
+
+ + + setFinishForm((current) => ({ ...current, textureSizeMm: event.target.value })) + } + /> +
+ +
+ + setFinishForm((current) => ({ ...current, metalness: nextValue })) + } + /> + + setFinishForm((current) => ({ ...current, roughness: nextValue })) + } + /> + + setFinishForm((current) => ({ ...current, opacity: nextValue })) + } + /> +
+ +
+ + setFinishForm((current) => ({ ...current, textureRepeat: event.target.value })) + } + /> + + setFinishForm((current) => ({ ...current, textureRotation: event.target.value })) + } + /> +
+ +
+ {[ + { + key: 'thumbnail' as const, + title: '缩略图', + preview: finishForm.thumbnailPreview, + inputRef: thumbnailInputRef, + onClear: () => + setFinishForm((current) => ({ + ...current, + thumbnailUrl: '', + thumbnailPreview: '', + })), + }, + { + key: 'texture' as const, + title: '颜色纹理', + preview: finishForm.texturePreview, + inputRef: textureInputRef, + onClear: () => + setFinishForm((current) => ({ + ...current, + textureUrl: '', + texturePreview: '', + })), + }, + { + key: 'normal' as const, + title: '法线贴图', + preview: finishForm.normalMapPreview, + inputRef: normalMapInputRef, + onClear: () => + setFinishForm((current) => ({ + ...current, + normalMapUrl: '', + normalMapPreview: '', + })), + }, + ].map((asset) => ( +
+
+

+ {asset.title} +

+ {asset.preview && ( + + )} +
+ + {asset.preview ? ( + + ) : ( +
+ +
+ )} + +
+ + {asset.preview && ( + + )} +
+
+ ))} +
+ +
+ +
+
) @@ -2036,7 +2211,7 @@ export default function MaterialLibraryClient({ } metrics={liveMetrics} - rightPanelClassName="w-[760px] max-w-[65vw]" + rightPanelClassName={activeTab === 'finish' ? 'w-[520px] max-w-[42vw]' : 'w-[760px] max-w-[65vw]'} leftContent={
@@ -2158,7 +2333,105 @@ export default function MaterialLibraryClient({
)} -
+
+ {activeTab === 'finish' ? ( +
+
+

+ Precision Material Definition Workspace +

+

+ 物料定义 +

+

+ 左侧挑选花色,右侧上半区实时预览,下半区集中调金属度、粗糙度、透明度和纹理参数。 +

+
+ +
+
+ {finishSpotlightPreviewUrl ? ( + + ) : ( +
+ )} +
+ +
+

+ {finishWorkspaceForm?.name || '等待选择花色'} +

+

+ {finishWorkspaceCategoryName} · {finishWorkspaceCode} +

+
+ {[ + { label: '金属度', value: finishWorkspaceForm?.metalness ?? '0' }, + { label: '粗糙度', value: finishWorkspaceForm?.roughness ?? '0.5' }, + { label: '透明度', value: finishWorkspaceForm?.opacity ?? '1' }, + ].map((item) => ( +
+

+ {item.label} +

+

+ {formatDecimalValue(item.value)} +

+
+ ))} +
+
+
+
+ ) : ( +
+
+

+ Technical Dictionary Workspace +

+

+ 基材定义 +

+

+ 这里维护基材主类、环保等级、厚度规格和系统名称,下面的卡片区继续负责资料查找与新增。 +

+
+ +
+ {[ + { label: '基材总数', value: substrates.length }, + { label: '花色总数', value: finishes.length }, + { label: '字典项', value: dictionaries.categories.length + dictionaries.environmentGrades.length + dictionaries.thicknessSpecs.length + dictionaries.surfaceOptions.length + dictionaries.systemNameOptions.length }, + { label: '当前系统名', value: previewSystemName || '未设置' }, + ].map((item) => ( +
+

+ {item.label} +

+

+ {item.value} +

+
+ ))} +
+
+ )} +
+ +
未找到花色

) : ( -
+
{filteredFinishes.map((item) => (