From f54421fb96a25ab397b53820340442321d5c2784 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 2 Jul 2026 04:34:41 +0800 Subject: [PATCH] test: align Taro visual guardrails with legacy UI --- docs/refactor/frontend-handoff-index.md | 4 +- docs/refactor/taro-visual-language.md | 28 +++++------ scripts/taro-visual-guardrails-test.js | 2 +- scripts/taro-visual-guardrails.js | 64 ++++++++++++++++++++++--- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/docs/refactor/frontend-handoff-index.md b/docs/refactor/frontend-handoff-index.md index 4663831c..3e166136 100644 --- a/docs/refactor/frontend-handoff-index.md +++ b/docs/refactor/frontend-handoff-index.md @@ -21,7 +21,7 @@ 7. `docs/refactor/taro-h5-deployment.md` - H5 三域名部署、`runtime-config.json`、Nginx history fallback、缓存、CSP 和 CORS 边界。 8. `docs/refactor/taro-visual-language.md` - - 学生端、租户后台、平台后台的视觉语言、旧题库参考边界、8px 圆角/工具型页面规范和 CSS 守卫。 + - 学生端、租户后台、平台后台的视觉语言、旧题库参考边界、旧题库圆润尺度/蓝色网格工作台规范和 CSS 守卫。 9. `docs/refactor/taro-production-integration-checklist.md` - 正式接 Supabase Auth、三套 H5、真实 provider、runtime-config 和上线门禁时逐项对照。 10. `docs/refactor/multitenant-auth-security-contract.md` @@ -48,7 +48,7 @@ - 新增、删除或重命名 Taro 页面时必须同步 `apps/taro/src/app.config.ts`、启动页跳转、H5 静态烟测入口和本文页面清单,并运行 `node scripts/taro-route-contract-test.js`。该脚本会阻断“页面文件存在但未注册”“路由注册但文件缺失”“启动页或烟测跳到不存在页面”的漂移。 - 新增或修改 Taro API service 时必须运行 `node scripts/taro-api-contract-test.js`。该脚本会比对前端 `apiRequest('/api/...')` 与后端 `RouteDefinition[]` 注册表,阻断调用不存在的接口、method 写错或绕过统一 API client;动态路由只能通过脚本 allowlist 明确声明。 - 修改学生端、租户后台或平台后台关键页面时必须运行 `node scripts/taro-persona-contract-test.js`。该脚本按学生刷题/会员订单/错题收藏、租户学生运营/内容导入/营销财务/品牌权限、平台租户/账务/公共题库/员工权限三类角色旅程检查路由和服务调用,避免前端样式重做时误删核心业务入口。 -- 修改 Taro CSS 或新建页面样式时必须运行 `npm run guard:taro:visual`。该脚本会阻断大圆角卡片、视口字体、负字距、装饰性径向渐变/模糊背景和未登记线性渐变;视觉规范见 `docs/refactor/taro-visual-language.md`。 +- 修改 Taro CSS 或新建页面样式时必须运行 `npm run guard:taro:visual`。该脚本会阻断超过旧题库尺度的大圆角、视口字体、负字距、装饰性径向渐变、裸模糊背景和未登记线性渐变;视觉规范见 `docs/refactor/taro-visual-language.md`。 - H5 构建完成后必须运行 `npm run smoke:taro:h5:interaction` 做真实浏览器点击验证。它会覆盖学生首页到题库练习、答题、收藏、会员收银台下单/支付参数/订单状态,租户后台工作台到题库内容/财务运营,以及平台后台工作台到租户管理/账务中心;如果 Chrome/Edge 缺失,可设置 `TARO_H5_SMOKE_BROWSER` 指向 Chromium 浏览器。 - H5 可以优先验证 `@supabase/supabase-js` 管理 Auth session;微信小程序端先验证运行时兼容性,业务数据默认仍走 `apps/api`。 - H5 生产部署优先用每个静态目录自己的 `runtime-config.json` 配置 `apiBaseUrl`、`supabaseUrl`、`supabasePublishableKey`、`tenantCode`;不要为了换域名重打包,也不要把任何 service role、数据库、支付、短信、对象存储密钥放进该文件。 diff --git a/docs/refactor/taro-visual-language.md b/docs/refactor/taro-visual-language.md index 0c5edb02..3e566af9 100644 --- a/docs/refactor/taro-visual-language.md +++ b/docs/refactor/taro-visual-language.md @@ -1,36 +1,36 @@ # Taro H5 视觉语言规范 -更新时间:2026-07-01 +更新时间:2026-07-02 这份规范用于约束 `apps/taro` 的学生端、租户后台和平台后台。旧题库前端参考目录为 `F:\project\参考\旧题库小程序前端文件`,只作为页面状态、学习流程、后台信息密度和微信平台交互的参考,不继承旧 PocketBase 直连、旧鉴权、旧字段模型或旧技术栈。 ## 总原则 - Taro 是前端体验层:负责路由、布局、交互、公开运行时配置、Supabase Auth session 和统一 API client;复杂业务判断、权限、价格、权益、导入、支付、CRM 和对象存储签名以后端为准。 -- Web 首发优先做成可反复使用的工具型产品,不做营销落地页式的大图 Hero、装饰卡片堆叠、渐变背景和过度留白。 -- 学生端要接近旧题库小程序的学习节奏:入口清楚、题目阅读专注、答题卡稳定、错题/收藏/报告路径短。 -- 租户后台和平台后台要接近运营工具:信息密度高、层级清楚、操作按钮固定、列表和指标可扫读。 +- Web 首发优先做成可反复使用的工具型产品,不做营销落地页式的大图 Hero、装饰卡片堆叠和过度留白。 +- 学生端要接近旧题库小程序/旧 Web 的学习节奏:浅灰网格背景、PC 左侧栏、移动底部 dock、蓝色学习横幅、彩色学习模块、白色统计卡和短路径练习入口。 +- 租户后台和平台后台要接近旧后台运营工具:浅灰/白色密集工作台、圆角侧栏、深色 active nav、表格/列表优先、操作按钮固定、指标可扫读。 ## 视觉基线 | 项 | 规范 | | --- | --- | -| 页面背景 | `#f6f8fb`、`#f8fafc`、`#f7f9fc` 这类浅灰蓝工作台背景 | +| 页面背景 | `#f4f6f9` 为主,叠加旧题库 40px 网格线;后台主区可用白色/浅灰工作台背景 | | 主文字 | `#0f172a`、`#111827`、`#172033` | | 次级文字 | `#64748b`、`#475569` | -| 主色 | `#2563eb` / `#1d4ed8`,租户发布主题后可由后端安全 token 覆盖 | +| 主色 | 旧题库蓝 `#1152d4`,辅以 `#2563eb` / `#1d4ed8`;租户发布主题后可由后端安全 token 覆盖 | | 成功/强调 | `#10b981`、`#16a34a`,只用于进度、完成、兑换等状态 | | 危险 | `#be123c`、`#dc2626`,只用于退款、驳回、删除、失败 | -| 圆角 | 卡片、按钮、输入框、面板统一不超过 `8px`;小进度条、chip、badge 可用 `999px` | +| 圆角 | 延续旧题库圆润但克制的尺度:输入/小按钮约 `8-12px`,列表/卡片约 `12-18px`,首页模块/登录/侧栏面板可到 `24-32px`;进度条、chip、badge、头像、滚动条和装饰标记可用 `999px` | | 字体 | 固定 px/rpx 风格,不使用 `vw/vh/vmin/vmax` 缩放字体 | | 字距 | 不使用负 `letter-spacing` | -| 装饰 | 禁止径向渐变、模糊光斑、装饰性大渐变背景;头像预设和水印纹理是当前允许例外 | +| 装饰 | 禁止径向光斑和裸 `filter: blur()` 装饰;允许旧题库样式里的网格背景、蓝色学习横幅、彩色模块卡、主按钮渐变、状态面板渐变,以及侧栏/dock 的受控 `backdrop-filter` | ## 页面结构 -- 学生端页面使用 `student-page`、`student-topbar`、`section-block`、`list-stack`、`quiet-panel` 等现有类名体系。 -- 租户后台使用 `admin-page`、`admin-shell`、`admin-header`、`admin-metric`、`admin-row`、`admin-button`。 -- 平台后台使用 `platform-page`、`platform-shell`、`platform-header`、`platform-metric`、`platform-row`、`platform-button`。 +- 学生端页面使用 `StudentLegacyShell` 提供 PC 左侧栏和移动 dock;页面内部继续使用 `student-page`、`student-topbar`、`section-block`、`list-stack`、`quiet-panel` 等现有类名体系。 +- 租户后台使用 `AdminLegacyShell` 提供旧后台侧栏/移动横向 nav,并复用 `admin-page`、`admin-shell`、`admin-header`、`admin-metric`、`admin-row`、`admin-button`。 +- 平台后台使用 `AdminLegacyShell` 提供旧后台侧栏/移动横向 nav,并复用 `platform-page`、`platform-shell`、`platform-header`、`platform-metric`、`platform-row`、`platform-button`。 - 新页面优先复用这些体系,不要为同类按钮、卡片、列表重新发明一套视觉类名。 - 页面区域不要做卡片套卡片。重复列表项、工具面板、表单组可以是卡片;页面大 section 应保持无外框或全宽分区。 @@ -62,10 +62,10 @@ npm run smoke:taro:h5:interaction `taro-visual-guardrails` 会扫描 `apps/taro/src/**/*.css`,阻断: -- 卡片、按钮、面板、输入框出现超过 `8px` 的圆角。 -- 进度条/chip/badge/pill 之外滥用 `999px` 大圆角。 +- 卡片、按钮、面板、输入框出现超过旧题库 `32px` 尺度的大圆角。 +- 进度条/chip/badge/pill/头像/滚动条/装饰标记之外滥用 `999px` 大圆角。 - 使用 `vw/vh/vmin/vmax` 做字体大小。 - 负 `letter-spacing`。 -- 装饰性径向渐变、模糊背景和未登记线性渐变。 +- 装饰性径向渐变、裸 `filter: blur()`、未登记的 `backdrop-filter` 或未登记线性渐变。 如确实需要新增例外,必须先说明 UI 目的,再更新 `scripts/taro-visual-guardrails.js` 的白名单和这份文档。 diff --git a/scripts/taro-visual-guardrails-test.js b/scripts/taro-visual-guardrails-test.js index a7469c2d..a5dcbdb7 100644 --- a/scripts/taro-visual-guardrails-test.js +++ b/scripts/taro-visual-guardrails-test.js @@ -37,7 +37,7 @@ assert.ok(currentPayload.checks.some(item => item.id === 'css.decorative_effects const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'taro-visual-guardrails-')); fs.writeFileSync(path.join(fixtureRoot, 'bad.css'), ` .hero-card { - border-radius: 24px; + border-radius: 44px; font-size: 6vw; letter-spacing: -0.04em; background: radial-gradient(circle, #fff, #dbeafe); diff --git a/scripts/taro-visual-guardrails.js b/scripts/taro-visual-guardrails.js index d907774a..47389802 100644 --- a/scripts/taro-visual-guardrails.js +++ b/scripts/taro-visual-guardrails.js @@ -6,6 +6,7 @@ const repoRoot = process.cwd(); const defaultRoot = path.join(repoRoot, 'apps', 'taro', 'src'); const allowedPillRadiusSelectors = [ + 'avatar', 'progress', 'track', 'fill', @@ -13,15 +14,54 @@ const allowedPillRadiusSelectors = [ 'badge', 'tag', 'pill', + 'meta', + 'option-prefix', 'watermark', + 'scrollbar', + 'thumb', + 'dot', + '::before', + '::after', ]; const allowedLinearGradientSelectors = [ + 'body', + 'page', + 'layout', + 'student-page', + 'admin-page', + 'platform-page', + 'bootstrap-page', + 'header', + 'hero', + 'band', + 'surface', + 'module', + 'tone-', + 'button.primary', + 'primary-button', + 'avatar', 'profile-avatar', 'avatar-choice-icon', + 'brand-icon', + 'shell::after', + 'mini-avatar', + 'sidebar-user-tag', + 'form', + 'panel', + 'revealed', + 'trend', + 'points', + 'nested', 'asset-watermark', ]; +const allowedBackdropBlurSelectors = [ + 'sidebar', + 'mobile-dock', + 'mobile-nav', +]; + function parseArgs(argv) { const options = { root: defaultRoot, @@ -124,14 +164,14 @@ function collectBorderRadiusViolations(files) { continue; } const pxValues = [...value.matchAll(/([0-9]+(?:\.[0-9]+)?)px/g)].map(item => Number(item[1])); - const tooLarge = pxValues.filter(item => item > 8); + const tooLarge = pxValues.filter(item => item > 32); if (tooLarge.length) { violations.push({ file: relative(filePath), line: lineNumber(text, match.index || 0), selector, value, - reason: 'Cards, panels, inputs and buttons should stay at 8px radius or less.', + reason: 'Legacy question-bank cards, panels and buttons should stay within the 8-32px rounded scale.', }); } } @@ -171,7 +211,7 @@ function main() { emitCheck( collector, 'css.border_radius', - 'Taro CSS uses 8px-or-less radii for cards, panels, buttons and inputs', + 'Taro CSS keeps legacy radii within the old question-bank rounded scale', collectBorderRadiusViolations(files), ); emitCheck( @@ -189,14 +229,24 @@ function main() { emitCheck( collector, 'css.decorative_effects', - 'Taro CSS avoids decorative radial gradients, blur backgrounds and unapproved linear gradients', + 'Taro CSS uses only legacy-approved grid, banner, module and state gradients', [ ...collectPatternViolations(files, /radial-gradient\s*\(/gi, 'Do not add decorative radial/orb gradients.'), - ...collectPatternViolations(files, /filter\s*:\s*[^;]*blur\s*\(/gi, 'Do not add blurred decorative backgrounds.'), + ...collectPatternViolations( + files, + /(^|[;\s{])filter\s*:\s*[^;]*blur\s*\(/gi, + 'Do not add raw blurred decorative backgrounds; use scoped backdrop-filter only for legacy glass navigation.', + ), + ...collectPatternViolations( + files, + /backdrop-filter\s*:\s*[^;]*blur\s*\(/gi, + 'Backdrop blur is only allowed for legacy glass navigation surfaces.', + selector => selectorMatches(selector, allowedBackdropBlurSelectors), + ), ...collectPatternViolations( files, /linear-gradient\s*\(/gi, - 'Linear gradients require a documented UI purpose and scoped selector.', + 'Linear gradients must be scoped to legacy grid backgrounds, blue banners, module cards, primary actions or state panels.', selector => selectorMatches(selector, allowedLinearGradientSelectors), ), ], @@ -204,7 +254,7 @@ function main() { emitCheck( collector, 'css.pill_radius_scope', - '999px radius is scoped to progress bars, chips, badges and pill controls', + '999px radius is scoped to progress, chips, badges, avatars, scrollbars and decorative legacy markers', collectBorderRadiusViolations(files).filter(item => item.value.includes('999px')), );