diff --git a/.trellis/spec/hyb-oa/deployment-trialrun.md b/.trellis/spec/hyb-oa/deployment-trialrun.md index 658a3cb8..d349ecc9 100644 --- a/.trellis/spec/hyb-oa/deployment-trialrun.md +++ b/.trellis/spec/hyb-oa/deployment-trialrun.md @@ -107,7 +107,7 @@ SYNC_ENV=0 bash deploy/trialrun/deploy.sh ### 3. Contracts - `assertPortalLoaded(page)` must assert route and page content first: - `/portal` URL and the `今日任务` heading. + `/portal` URL and the `今日待处理` heading. - Navigation-label assertions for the workbench link must accept both `工作台` and `Portal` while older mocks still use English labels. - Navigation assertions must be role-aware. Admin/manager smoke may assert @@ -121,11 +121,11 @@ SYNC_ENV=0 bash deploy/trialrun/deploy.sh ### 4. Validation & Error Matrix -- Page reaches `/portal`, `今日任务` is visible, but nav label is `工作台` -> +- Page reaches `/portal`, `今日待处理` is visible, but nav label is `工作台` -> smoke should pass. - Employee reaches `/portal`, role-aware navigation hides `团队`, and employee pages such as `项目` remain reachable -> smoke should pass. -- Page reaches `/portal`, but `今日任务` is missing -> smoke should fail. +- Page reaches `/portal`, but `今日待处理` is missing -> smoke should fail. - Page stays on login, `/403`, error fallback or another route -> smoke should fail. - New shell label appears only in one live smoke test -> move the compatibility @@ -133,7 +133,7 @@ SYNC_ENV=0 bash deploy/trialrun/deploy.sh ### 5. Good/Base/Bad Cases -- Good: `assertPortalLoaded` checks `/portal`, `今日任务`, and a workbench link +- Good: `assertPortalLoaded` checks `/portal`, `今日待处理`, and a workbench link matching either `工作台` or `Portal`. - Good: `assertMainNavVisible(page, { expectTeam: false })` is used for ordinary employee live smoke. diff --git a/.trellis/spec/hyb-oa/frontend-react-vite-design.md b/.trellis/spec/hyb-oa/frontend-react-vite-design.md index 71992d21..82fa7b97 100644 --- a/.trellis/spec/hyb-oa/frontend-react-vite-design.md +++ b/.trellis/spec/hyb-oa/frontend-react-vite-design.md @@ -1510,8 +1510,10 @@ onNeedRefresh() { ### 4. Login Entry Hierarchy -- Normal browser: account/password login is primary; Enterprise WeChat and OIDC - entries belong below the primary submit button as secondary methods. +- Normal browser: account/password or email-code login is primary. Enterprise + WeChat is shown as a boundary notice or secondary entry that tells users to + open OA from the Enterprise WeChat workbench; do not require a clickable OAuth + button in ordinary browsers. - Enterprise WeChat WebView: Enterprise WeChat one-click entry is primary; account/password login remains available as the fallback path. - Enterprise WeChat entry changes must remain frontend entry hierarchy changes @@ -1528,7 +1530,7 @@ onNeedRefresh() { - keyboard Tab from the username/email field lands on the password input, not the forgot-password link; - password recovery request-code and reset flow on `/forgot-password`; - - normal-browser Enterprise WeChat entry as secondary CTA; + - normal-browser Enterprise WeChat boundary notice or secondary entry; - WeCom WebView Enterprise WeChat entry as primary CTA with password fallback. - UI design rules check and Playwright screenshot evidence when the auth layout changes visibly. diff --git a/.trellis/tasks/05-30-deploy-unified-page-design-public-check/check.jsonl b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/check.jsonl new file mode 100644 index 00000000..6005897a --- /dev/null +++ b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/check.jsonl @@ -0,0 +1,3 @@ +{"file": ".trellis/spec/hyb-oa/project-governance.md", "reason": "Verify task metadata, scoped commits, approvals and finish requirements."} +{"file": ".trellis/spec/hyb-oa/deployment-trialrun.md", "reason": "Verify public deploy evidence, readiness, smoke and can-test declaration."} +{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Verify frontend test and visual baseline expectations."} diff --git a/.trellis/tasks/05-30-deploy-unified-page-design-public-check/implement.jsonl b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/implement.jsonl new file mode 100644 index 00000000..cdfc06ec --- /dev/null +++ b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/implement.jsonl @@ -0,0 +1,3 @@ +{"file": ".trellis/spec/hyb-oa/project-governance.md", "reason": "Trellis task, deployment approval, commit and solo-maintenance rules for this deploy/check task."} +{"file": ".trellis/spec/hyb-oa/deployment-trialrun.md", "reason": "Public deployment command, smoke, live readiness and rollback gates."} +{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Frontend deploy/test expectations and mature enterprise page baseline for visual checks."} diff --git a/.trellis/tasks/05-30-deploy-unified-page-design-public-check/implement.md b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/implement.md new file mode 100644 index 00000000..7ae55c8c --- /dev/null +++ b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/implement.md @@ -0,0 +1,18 @@ +# 实施方案 + +## 步骤 + +1. 预检本地状态:确认工作区干净、当前 commit、基础前端构建和部署环境契约。 +2. 安全部署:运行 `SYNC_ENV=0 bash deploy/trialrun/deploy.sh`,不覆盖远端 `.env`。 +3. 公网复检:检查 `/ready`、public bundle copy、live smoke readiness;如果凭据不足,保留脚本 SKIP 记录。 +4. 页面抽查:用公网地址检查工作台、待我处理、采购、合同、项目、资产、应付账款等本轮重点页面是否反映统一设计规则。 +5. 若发现阻断:只做最小修复并重新部署验证;涉及远端配置、真实数据或写企业微信时停止并单独确认。 +6. 收尾:记录结果,提交任务文档或必要修复,明确是否可线上测试。 + +## 风险控制 + +- 不使用 `SYNC_ENV=1`。 +- 不执行数据库 reset。 +- 不执行真实付款、企业微信写入或外部系统写入。 +- 不把 secret、账号、完整 payload 写入文档或回复。 +- 发现历史 artifact / rsync 清理问题时,先保守排查并只清理部署排除目录或历史产物,不动业务数据目录。 diff --git a/.trellis/tasks/05-30-deploy-unified-page-design-public-check/prd.md b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/prd.md new file mode 100644 index 00000000..a1afc87a --- /dev/null +++ b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/prd.md @@ -0,0 +1,97 @@ +# 部署最新页面改造并公网复检 + +## Goal + +把已提交的统一页面设计改造部署到公网试运行环境,并完成公网可用性、关键页面冒烟和基础视觉/代码审计,明确当前线上是否可以让用户测试。 + +## What I already know + +- 最新页面改造已提交: + - `d5ef818` 统一业务台账首屏设计(05-30-unified-page-design-review) + - `74db53b` 归档统一页面设计规范重审(05-30-unified-page-design-review) +- 上一轮本地验证通过:`git diff --check`、Trellis task validate、Trellis governance check。 +- 用户要求继续推进;结合上一轮结论,本任务范围是部署和公网复检。 +- 公网试运行环境是准生产环境,部署和公网检查必须记录命令、commit、`/ready`、smoke 结果和是否可测试。 +- 默认部署命令是 `SYNC_ENV=0 bash deploy/trialrun/deploy.sh`,不得覆盖远端 `.env`。 +- 部署脚本已包含环境契约、远端 `/ready`、external deps smoke、runtime smoke 和公网 bundle 文案扫描。 + +## Assumptions + +- 本轮只部署已提交代码,不修改生产配置、不重置数据库、不写企业微信、不执行真实付款。 +- 如果缺少 live smoke 凭据或真实 OCR 样本,按脚本规则记录 SKIP,不阻塞基础部署结论。 +- 如果部署或公网检查失败,先定位并修复最小问题,再重新验证;涉及真实配置变更时再单独请求确认。 + +## Scope + +- 部署当前 `main` HEAD 到 `https://oa.hyinda.com` 对应试运行环境。 +- 执行部署前本地质量门禁。 +- 执行部署脚本的安全模式发布。 +- 执行公网 `/ready`、公网 bundle copy、live smoke readiness。 +- 对这次修改涉及的主要页面做公网视觉/交互抽查: + - 工作台 + - 待我处理 + - 采购 + - 合同 + - 项目 + - 资产 + - 应付账款 +- 输出是否可以线上测试的结论。 + +## Out of Scope + +- 不改业务功能范围。 +- 不新增 UI 设计规则。 +- 不做数据库重置、远端 `.env` 覆盖、企业微信写入或真实付款。 +- 不导入真实业务数据。 + +## Requirements + +- 部署前必须确认工作区状态,避免带未提交改动发布。 +- 使用 `SYNC_ENV=0`,不覆盖远端 `.env`。 +- 发布后必须检查公网 `/ready`。 +- 面向用户可测试的声明必须以部署和公网检查通过为前提。 +- 如果发现视觉或交互问题,优先判断是否属于本轮部署阻断;非阻断问题另建后续改造任务。 + +## Acceptance Criteria + +- [x] 当前 commit 已部署到公网试运行环境。 +- [x] `https://oa.hyinda.com/ready` 通过。 +- [x] 部署脚本内置 smoke 通过或失败原因已记录。 +- [x] `scripts/qa/run-live-smoke-readiness.sh` 通过。 +- [x] 至少完成工作台、待我处理和本轮主要业务台账页面的公网抽查。 +- [x] 最终结论明确:可以线上测试 / 已部署但仍有阻断 / 未部署成功。 + +## Test Plan + +- `git status --short` +- `cd client && npm run typecheck` +- `cd client && npm run build` +- `node deploy/trialrun/validate-env-contract.js` +- `SYNC_ENV=0 bash deploy/trialrun/deploy.sh` +- `LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-live-smoke-readiness.sh` +- 必要时运行聚焦公网 Playwright 或截图检查。 +- `git diff --check` +- `python3 ./.trellis/scripts/task.py validate 05-30-deploy-unified-page-design-public-check` +- `node scripts/qa/check-trellis-governance.mjs` + +## Technical Notes + +- 相关规范: + - `.trellis/spec/hyb-oa/project-governance.md` + - `.trellis/spec/hyb-oa/deployment-trialrun.md` + - `.trellis/spec/hyb-oa/frontend-react-vite-design.md` +- 相关脚本: + - `deploy/trialrun/deploy.sh` + - `scripts/qa/run-live-smoke-readiness.sh` + - `scripts/qa/check-public-bundle-copy.mjs` +- 本轮部署 commit:`74db53b`。 +- 公网 readiness 报告:`artifacts/qa-flow/live-smoke-readiness-20260530-200338`。 +- 公网页面抽查截图:`output/playwright/05-30-public-ledger-check/`。 +- `r104-public-visual-acceptance` 原先在普通浏览器要求企业微信 OAuth 按钮;当前产品规则是普通浏览器展示企业微信工作台边界说明,企业微信 WebView UA 才展示一键进入按钮。本任务已同步修正断言。 + +## Definition of Done + +- 公网部署与复检完成。 +- 阻断问题已修复或明确记录。 +- 任务文档、验证命令和提交记录完整。 +- 最终回复包含 commit、部署状态、公网检查结果和可测试结论。 diff --git a/.trellis/tasks/05-30-deploy-unified-page-design-public-check/task.json b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/task.json new file mode 100644 index 00000000..309985a6 --- /dev/null +++ b/.trellis/tasks/05-30-deploy-unified-page-design-public-check/task.json @@ -0,0 +1,26 @@ +{ + "id": "deploy-unified-page-design-public-check", + "name": "deploy-unified-page-design-public-check", + "title": "部署最新页面改造并公网复检", + "description": "部署最新统一页面设计改造到公网试运行环境,并完成公网 readiness、live smoke、视觉抽查和收尾审计。", + "status": "in_progress", + "dev_type": null, + "scope": "deploy,qa,frontend-test", + "package": null, + "priority": "P2", + "creator": "shunli", + "assignee": "shunli", + "createdAt": "2026-05-30", + "completedAt": null, + "branch": null, + "base_branch": "main", + "worktree_path": null, + "commit": null, + "pr_url": null, + "subtasks": [], + "children": [], + "parent": null, + "relatedFiles": [], + "notes": "", + "meta": {} +} diff --git a/client/tests/e2e/r104-public-visual-acceptance.spec.ts b/client/tests/e2e/r104-public-visual-acceptance.spec.ts index afea26e0..66cef5a4 100644 --- a/client/tests/e2e/r104-public-visual-acceptance.spec.ts +++ b/client/tests/e2e/r104-public-visual-acceptance.spec.ts @@ -6,6 +6,8 @@ import { getExpectedWecomStatus, loginLiveUser, logoutLiveUser } from "./helpers import { fetchWecomConfig } from "./helpers/smokeAssertions"; const screenshotDir = path.resolve(process.cwd(), "../output/playwright/r104"); +const WECOM_UA = + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 wxwork/4.1.20 MicroMessenger/8.0.1 Language/zh_CN"; function screenshotPath(fileName: string) { mkdirSync(screenshotDir, { recursive: true }); @@ -30,7 +32,8 @@ test.describe("R104 public visual acceptance", () => { await expect(page.getByTestId("login-identifier")).toBeVisible(); await expect(page.getByTestId("login-password")).toBeVisible(); await expect(page.getByTestId("login-submit")).toBeVisible(); - await expect(page.getByRole("button", { name: /企业微信/ })).toBeVisible(); + await expect(page.getByTestId("wecom-entry-browser-notice")).toBeVisible(); + await expect(page.getByTestId("wecom-entry-browser-notice")).toContainText("企业微信一键进入"); const wecomConfig = await fetchWecomConfig(page); expect(wecomConfig.status).toBe(200); @@ -42,15 +45,24 @@ test.describe("R104 public visual acceptance", () => { await page.screenshot({ path: screenshotPath("desktop-login.png"), fullPage: true }); }); - test("公网企业微信入口跳转到 OAuth 边界", async ({ page }) => { - await page.setViewportSize({ width: 390, height: 844 }); + test("公网企业微信 WebView 入口跳转到 OAuth 边界", async ({ browser }) => { + const context = await browser.newContext({ + viewport: { width: 390, height: 844 }, + isMobile: true, + hasTouch: true, + userAgent: WECOM_UA, + locale: "zh-CN", + serviceWorkers: "block", + }); + const page = await context.newPage(); await page.goto("/login"); - await expect(page.getByRole("button", { name: /企业微信/ })).toBeVisible(); + await expect(page.getByTestId("wecom-entry-primary")).toBeVisible(); await page.screenshot({ path: screenshotPath("mobile-login-before-wecom.png"), fullPage: true }); - await page.getByRole("button", { name: /企业微信/ }).click(); + await page.getByTestId("wecom-entry-primary").click(); await expect(page).toHaveURL(/open\.weixin\.qq\.com|work\.weixin\.qq\.com|wechat_redirect/); + await context.close(); }); test("公网员工移动工作台与高频页面保持移动体验", async ({ page }) => {