diff --git a/docs/designs/ui06-implementation/before/01-login.png b/docs/designs/ui06-implementation/before/01-login.png new file mode 100644 index 0000000..1c399a3 Binary files /dev/null and b/docs/designs/ui06-implementation/before/01-login.png differ diff --git a/docs/designs/ui06-implementation/before/02-albums.png b/docs/designs/ui06-implementation/before/02-albums.png new file mode 100644 index 0000000..51198ba Binary files /dev/null and b/docs/designs/ui06-implementation/before/02-albums.png differ diff --git a/docs/designs/ui06-implementation/before/03-photos.png b/docs/designs/ui06-implementation/before/03-photos.png new file mode 100644 index 0000000..462380a Binary files /dev/null and b/docs/designs/ui06-implementation/before/03-photos.png differ diff --git a/docs/designs/ui06-implementation/before/04-members.png b/docs/designs/ui06-implementation/before/04-members.png new file mode 100644 index 0000000..f8c1946 Binary files /dev/null and b/docs/designs/ui06-implementation/before/04-members.png differ diff --git a/docs/designs/ui06-implementation/before/05-categories.png b/docs/designs/ui06-implementation/before/05-categories.png new file mode 100644 index 0000000..b0f1c2d Binary files /dev/null and b/docs/designs/ui06-implementation/before/05-categories.png differ diff --git a/docs/designs/ui06-implementation/before/06-watermark.png b/docs/designs/ui06-implementation/before/06-watermark.png new file mode 100644 index 0000000..2ad8ff3 Binary files /dev/null and b/docs/designs/ui06-implementation/before/06-watermark.png differ diff --git a/docs/designs/ui06-implementation/before/07-share.png b/docs/designs/ui06-implementation/before/07-share.png new file mode 100644 index 0000000..c41d634 Binary files /dev/null and b/docs/designs/ui06-implementation/before/07-share.png differ diff --git a/docs/designs/ui06-implementation/before/08-create.png b/docs/designs/ui06-implementation/before/08-create.png new file mode 100644 index 0000000..88ab517 Binary files /dev/null and b/docs/designs/ui06-implementation/before/08-create.png differ diff --git a/docs/designs/ui06-implementation/before/09-edit.png b/docs/designs/ui06-implementation/before/09-edit.png new file mode 100644 index 0000000..d4aecbe Binary files /dev/null and b/docs/designs/ui06-implementation/before/09-edit.png differ diff --git a/docs/designs/ui06-implementation/before/10-users.png b/docs/designs/ui06-implementation/before/10-users.png new file mode 100644 index 0000000..0ea7de5 Binary files /dev/null and b/docs/designs/ui06-implementation/before/10-users.png differ diff --git a/docs/designs/ui06-implementation/before/11-user-sync.png b/docs/designs/ui06-implementation/before/11-user-sync.png new file mode 100644 index 0000000..1ab87e3 Binary files /dev/null and b/docs/designs/ui06-implementation/before/11-user-sync.png differ diff --git a/docs/designs/ui06-implementation/before/12-usage.png b/docs/designs/ui06-implementation/before/12-usage.png new file mode 100644 index 0000000..15bfe02 Binary files /dev/null and b/docs/designs/ui06-implementation/before/12-usage.png differ diff --git a/docs/designs/ui06-implementation/before/13-embed-slots.png b/docs/designs/ui06-implementation/before/13-embed-slots.png new file mode 100644 index 0000000..6938c11 Binary files /dev/null and b/docs/designs/ui06-implementation/before/13-embed-slots.png differ diff --git a/docs/designs/ui06-implementation/before/14-embed-editor.png b/docs/designs/ui06-implementation/before/14-embed-editor.png new file mode 100644 index 0000000..9c1f575 Binary files /dev/null and b/docs/designs/ui06-implementation/before/14-embed-editor.png differ diff --git a/docs/designs/ui06-implementation/before/15-branding.png b/docs/designs/ui06-implementation/before/15-branding.png new file mode 100644 index 0000000..b1b23e9 Binary files /dev/null and b/docs/designs/ui06-implementation/before/15-branding.png differ diff --git a/docs/designs/ui06-implementation/before/16-photo-viewer.png b/docs/designs/ui06-implementation/before/16-photo-viewer.png new file mode 100644 index 0000000..b28f0c5 Binary files /dev/null and b/docs/designs/ui06-implementation/before/16-photo-viewer.png differ diff --git a/docs/designs/ui06-implementation/before/17-403.png b/docs/designs/ui06-implementation/before/17-403.png new file mode 100644 index 0000000..39c6c35 Binary files /dev/null and b/docs/designs/ui06-implementation/before/17-403.png differ diff --git a/docs/designs/ui06-implementation/before/18-404.png b/docs/designs/ui06-implementation/before/18-404.png new file mode 100644 index 0000000..b781baa Binary files /dev/null and b/docs/designs/ui06-implementation/before/18-404.png differ diff --git a/docs/designs/ui06-implementation/before/19-500.png b/docs/designs/ui06-implementation/before/19-500.png new file mode 100644 index 0000000..a0eeff6 Binary files /dev/null and b/docs/designs/ui06-implementation/before/19-500.png differ diff --git a/docs/designs/ui06-implementation/before/20-sync-detail.png b/docs/designs/ui06-implementation/before/20-sync-detail.png new file mode 100644 index 0000000..a229c35 Binary files /dev/null and b/docs/designs/ui06-implementation/before/20-sync-detail.png differ diff --git a/docs/designs/ui06-implementation/before/capture.json b/docs/designs/ui06-implementation/before/capture.json new file mode 100644 index 0000000..a477b15 --- /dev/null +++ b/docs/designs/ui06-implementation/before/capture.json @@ -0,0 +1,10 @@ +{ + "date": "2026-09-22T14:45:36.894Z", + "base": "http://219.157.255.213:32005", + "viewport": "1440x1000", + "errors": [], + "notes": [ + "15-branding: before 状态 banner 位于详情卡内,未独立页签", + "16-photo-viewer: before 状态无大图预览,以照片表格代替" + ] +} \ No newline at end of file diff --git a/docs/designs/ui06-implementation/capture-before.cjs b/docs/designs/ui06-implementation/capture-before.cjs new file mode 100644 index 0000000..4a8adaf --- /dev/null +++ b/docs/designs/ui06-implementation/capture-before.cjs @@ -0,0 +1,184 @@ +/** + * UI06 B0:管理后台「改动前」截图脚本。 + * 目标:测试服务器上当前部署的后台(= HEAD 的 admin 产物),1440×1000 全页截图, + * 命名与 admin-preview 示例编号对齐,存入同目录 before/。 + * 用法:ADMIN_PW=<密码> node capture-before.cjs [--out before] [--base http://219.157.255.213:32005] + * 凭据不写入本文件;仅浏览器会话内存。 + */ +const fs = require('fs'); +const path = require('path'); +const { chromium } = require( + require.resolve('@playwright/test', { paths: [path.resolve(__dirname, '../../../apps/admin')] }) +); + +const args = process.argv.slice(2); +const argOf = (name, def) => { + const i = args.indexOf(name); + return i >= 0 ? args[i + 1] : def; +}; +const BASE = argOf('--base', 'http://219.157.255.213:32005'); +const OUT = path.join(__dirname, argOf('--out', 'before')); +const ACCOUNT = process.env.ADMIN_ACCOUNT || 'admin'; +const PASSWORD = process.env.ADMIN_PW; +if (!PASSWORD) { + console.error('missing ADMIN_PW env'); + process.exit(1); +} + +const notes = []; +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +(async () => { + fs.mkdirSync(OUT, { recursive: true }); + const browser = await chromium.launch({ headless: true }); + const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } }); + const errors = []; + page.on('pageerror', (e) => errors.push(e.message)); + + const shot = async (name) => { + await sleep(1200); // 等数据渲染;无动画依赖 + await page.screenshot({ path: path.join(OUT, name + '.png'), fullPage: true }); + }; + const gotoHash = async (hash) => { + await page.goto(`${BASE}/admin/#${hash}`); + await page.waitForLoadState('networkidle').catch(() => {}); + await sleep(800); + }; + + // 01 登录页(未登录态) + await gotoHash('/auth/login'); + await shot('01-login'); + + // 登录 + await page.fill('input[autocomplete="username"]', ACCOUNT); + await page.fill('input[autocomplete="current-password"]', PASSWORD); + await page.click('.auth-right-wrap .el-button--primary'); + await page.waitForURL((u) => !u.href.includes('/auth/login'), { timeout: 15000 }); + await sleep(1200); + + // 02 相册列表 + await gotoHash('/albums/manage'); + await shot('02-albums'); + + // 进入第一个相册详情(03–07、15、16 的宿主) + const detailBtn = page.locator('[data-test="album-detail-btn"]').first(); + if (await detailBtn.count()) { + await detailBtn.click(); + await page.waitForURL('**/albums/detail/**'); + await sleep(1200); + await shot('03-photos'); // photos 为默认页签 + + // 04–07 各页签 + for (const [name, tab] of [ + ['04-members', 'members'], + ['05-categories', 'categories'], + ['06-watermark', 'watermark'], + ['07-share', 'share'], + ]) { + const tabEl = page.locator(`#tab-${tab}`); + if (await tabEl.count()) { + await tabEl.click(); + await sleep(900); + await shot(name); + } else { + notes.push(`${name}: tab #tab-${tab} not found`); + } + } + + // 09 编辑对话框(详情页入口) + const editBtn = page.locator('[data-test="album-detail-edit"]').first(); + if (await editBtn.count()) { + // 回到 photos 页签,避免页签状态干扰 + const photosTab = page.locator('#tab-photos'); + if (await photosTab.count()) await photosTab.click().catch(() => {}); + await sleep(400); + await editBtn.click(); + await sleep(900); + await shot('09-edit'); + await page.keyboard.press('Escape'); + await sleep(400); + } else { + notes.push('09-edit: album-detail-edit not found'); + } + + // 15 品牌资产(现状:详情卡内 banner 上传区,未独立成页签)——整页含该区 + await shot('15-branding'); + notes.push('15-branding: before 状态 banner 位于详情卡内,未独立页签'); + // 16 照片大图(现状:表格视图,无大图预览) + await shot('16-photo-viewer'); + notes.push('16-photo-viewer: before 状态无大图预览,以照片表格代替'); + } else { + notes.push('03-07/15/16: 无相册数据,未截详情系'); + } + + // 08 新建对话框(列表页入口) + await gotoHash('/albums/manage'); + const createBtn = page.locator('[data-test="album-create-btn"]').first(); + if (await createBtn.count()) { + await createBtn.click(); + await sleep(900); + await shot('08-create'); + await page.keyboard.press('Escape'); + await sleep(300); + } else { + notes.push('08-create: album-create-btn not found'); + } + + // 10–12 治理页 + await gotoHash('/system/users'); + await shot('10-users'); + await gotoHash('/system/user-sync'); + await shot('11-user-sync'); + // 20 同步批次失败明细(现状:点历史行打开抽屉;无失败批次则记录) + const failRow = page.locator('[data-test^="sync-run"]').first(); + if (await failRow.count()) { + await failRow.click().catch(() => {}); + await sleep(900); + await shot('20-sync-detail'); + } else { + await shot('20-sync-detail'); + notes.push('20-sync-detail: 未找到可点历史行,截页面原状'); + } + await gotoHash('/system/usage'); + await shot('12-usage'); + + // 13 展示位列表 + 14 配置对话框 + await gotoHash('/system/embed-slots'); + await shot('13-embed-slots'); + const slotEdit = page.locator('[data-test="slot-edit-btn"]').first(); + if (await slotEdit.count()) { + await slotEdit.click(); + await sleep(900); + await shot('14-embed-editor'); + await page.keyboard.press('Escape'); + await sleep(300); + } else { + notes.push('14-embed-editor: slot-edit-btn not found'); + } + + // 17–19 异常页 + await gotoHash('/403'); + await shot('17-403'); + await gotoHash('/ui06-nonexistent'); + await shot('18-404'); + await gotoHash('/500'); + await shot('19-500'); + + const result = { + date: new Date().toISOString(), + base: BASE, + viewport: '1440x1000', + errors, + notes, + }; + fs.writeFileSync( + path.join(OUT, 'capture.json'), + JSON.stringify(result, null, 2) + ); + console.log(JSON.stringify(result, null, 2)); + await browser.close(); + if (errors.length) process.exitCode = 1; +})().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/docs/plans/progress/UI06-验收记录.md b/docs/plans/progress/UI06-验收记录.md new file mode 100644 index 0000000..73c7de3 --- /dev/null +++ b/docs/plans/progress/UI06-验收记录.md @@ -0,0 +1,65 @@ +# UI-06 全端视觉统一 验收记录 + +方案:`docs/plans/2026-09-22-UI06-全端视觉统一实施方案.md`(commit `37d88da`) +日期:2026-09-22 起 · 执行环境:Windows 11 + 测试服务器 219.157.255.213(入口 32005) +视觉基准:`docs/designs/admin-preview-2026-09-22/`(后台 20 页)+ `docs/designs/app-preview-2026-09-22/`(App 20 页),冲突一律以示例为准。 + +## 1. 任务完成表 + +| 阶段 | 内容 | Commit | 状态 | +|---|---|---|---| +| B0 | 基线提交 + before 截图 + 契约核对 | 见下 | ✅ 完成 | +| B1 | 主题 token + 布局壳 + 登录页 | | 待执行 | +| B2 | 共享业务组件 | | 待执行 | +| B3a–B3e | 页面批次(每批部署 32005 验收) | | 待执行 | +| B4 | 后台全量回归验收 | | 待执行 | +| A0–A7 | App 线(B4 后启动) | | 待执行 | + +## 2. B0 记录(2026-09-22) + +### 2.1 基线提交 + +`37d88da`:admin-preview 20 页原型+截图+validation、app-preview 截图/脚本、UI05/UI06 方案文档、概念图、g4-sync-once 脚本(85 文件)。工作树干净后开工。 + +### 2.2 Before 截图 + +- 工具:`docs/designs/ui06-implementation/capture-before.cjs`(Playwright,凭据经 env 注入不入库) +- 对象:测试服务器已部署后台(= HEAD admin 产物),1440×1000 全页,20 张 → `docs/designs/ui06-implementation/before/` +- 页面错误:0。注记 2 条(结构性,符合预期): + - `15-branding`:现状 banner 位于详情卡内未独立页签(B3c 改) + - `16-photo-viewer`:现状无大图预览,以照片表格代替(B2 新增 PhotoPreview) +- 关键现状确认:02 相册为**文字表格**(无封面卡);侧栏为深色窄栏(非示例 216px 白底);10 用户页分页器 15/页共 230 条 + 同步档案列在位(G4 成果,保留)。 + +### 2.3 契约核对结论(方案 §2.2 四项) + +| # | 项 | 测试服务器实测结论 | 处理 | +|---|---|---|---| +| 1 | Album `cover` | ✅ **服务端已实现**:`GET /v1/albums` 每项含 `cover: { url(签名OSS), expiresAt }`,900s 过期 | 分支 (a)——前端仅补 `Summary.cover` 类型 + 卡片使用;过期经受控重取 | +| 2 | `AdminPhoto.preview` | ✅ **服务端已实现**:`GET /v1/albums/:id/photos` 每项含 `preview.thumb/browse`(签名 URL) | 前端补类型;为空呈现真实空态 | +| 3 | CreatePayload 载荷 | ✅ 代码确认:仅 translations/defaultLocale/startAt/endAt/timezone/下载开关;公开/上传开关在 UpdatePayload | 整页表单按此禁用或解释,不塞进创建请求 | +| 4 | 展示位 v2 字段 | ✅ 类型已有且 SlotFormDialog **已呈现** displayMode/scrollSpeed/reactionsEnabled(E06/E07 已落地;UI05 §4.4 的担心已过时) | B3e 仅视觉对齐,无需补字段 | + +无服务端缺口:**全部四项均为纯前端工作**,无需用户确认分支 (b)。 + +### 2.4 主题入口核对(B1 准备) + +- 主色链路:`config/index.ts` `systemMainColor[0]`(现 `#5D87FF`)→ `config/setting.ts:45` `systemThemeColor` → `utils/ui/colors.ts` 运行时生成 `--el-color-primary` 系。B1 改预设首位为 `#1A73E8` 并同步派生。 +- SCSS 静态层:`assets/styles/core/el-light.scss`(@forward var.scss,success/warning/danger 已定制,messagebox 12px 圆角已接近示例);`el-ui.scss` 定义 `--main-color` 映射。 +- 布局壳:`components/core/layouts/`(art-header-bar、art-menus/art-sidebar-menu)。 +- 菜单:`router/modules/albums.ts|system.ts`,meta 驱动;分组重组 = 调 meta(B1)。 + +## 3. B1 记录 + +(待执行) + +## 4. B2 记录 + +(待执行) + +## 5. B3 批次记录 + +(待执行;每批:对照截图 → 部署 tag → 用户验收结论) + +## 6. B4 / App 线记录 + +(待执行)