# Frontend React / Vite / Design ## Source Of Truth Frontend visual and interaction design uses the installed `frontend-design` skill as the primary design authority. `docs/产品设计规则.md` remains a product experience and business-boundary fact source, not a visual, brand or aesthetic rulebook. For PC/mobile/WeCom pages, add Playwright or visual verification when reasonable. This spec keeps hyb-oa-specific React/Vite, shared-component, business-boundary and verification contracts. Do not copy broad aesthetic guidance from `frontend-design` into this file; use the skill directly for design judgment. ## Rules - Use existing React/Vite/Tailwind patterns and shared components before adding page-local UI systems. - When `frontend-design` and older project visual rules conflict, follow `frontend-design` for visual direction while preserving security, privacy, Trellis, deployment and business data boundaries. - PC pages should keep dense but orderly OA layouts: clear header, filters, table/list, status, details and predictable actions. - Mobile pages must reuse the existing unified mobile shell, card/list rows, safe-area and sticky action patterns unless the current task intentionally redesigns them with `frontend-design`. - Do not add decorative landing-page styling to operational OA pages. - Run `cd client && npm run typecheck && npm run build` for frontend changes. ## Frozen / Boundary Items Frozen modules and Enterprise WeChat-owned HR/attendance entries must be labeled or hidden according to the current Trellis task; do not silently re-enable them. - Use the shared `WorkspaceNotice` pattern for trial boundaries, safety notes, and post-trial capabilities instead of page-local warning blocks. - Trial-facing PC lists must hide obvious TEST/SMOKE records by default when a page-level toggle exists; the toggle may reveal them for troubleshooting. ## Scenario: Business Flow Tests And Frozen Modules ### 1. Scope / Trigger - Trigger: Playwright or QA shell tests need to create workflow data while some product modules are frozen for launch. - Applies to `client/tests/e2e/**`, `scripts/qa/run-business-flow-gates.sh`, and frontend route/permission assertions. ### 2. Signatures - QA command: `BUSINESS_FLOW_GROUPS= bash scripts/qa/run-business-flow-gates.sh local`. - Frozen-module API expectation: non-admin launch roles may receive `403` for frozen module list/create/submit endpoints. - Enabled workflow test data sources should use active entities such as leave, reimbursement or procurement unless the task explicitly reopens the frozen module. ### 3. Contracts - Do not use a frozen module as fixture setup for an unrelated enabled feature. Example: mobile approval offline sync should not create a travel request when travel permissions are intentionally frozen. - Permission direct-access tests must assert the frozen contract directly, such as employee `GET /api/travel-requests?...` returning `403`. - UI route smoke may still verify that a frozen page displays a boundary state without entering a management or write-capable mode. - Do not loosen roles or seed permissions merely to make old E2E data setup pass. ### 4. Validation & Error Matrix - Frozen role calls frozen module create/submit/list endpoint -> `403` or the documented feature-gate status. - Enabled workflow feature needs pending task data -> create data through an enabled workflow entity. - E2E fails with `PERM_001` while setting up unrelated feature data -> update the test data source before changing app permissions. ### 5. Good/Base/Bad Cases - Good: mobile approval offline test creates a submitted leave request, then verifies pending-task deep link, offline queue, sync success and conflict. - Base: travel-specific tests are skipped or admin-scoped while travel remains frozen. - Bad: grant employee `travel.create` only so a mobile approval test can build a fixture. ### 6. Tests Required - Focused E2E group that previously failed. - Full affected business-flow group after the focused fix. - `cd client && npm run typecheck && npm run build` when TypeScript test code changes. ### 7. Wrong vs Correct #### Wrong ```ts await createSubmittedTravelRequestViaApi({ user: EMPLOYEE }); ``` #### Correct ```ts await createSubmittedLeaveViaApi({ user: EMPLOYEE }); ``` ## Convention: PC Operation List Density **What**: PC list/workflow pages that combine status metrics, tabs/filters, range controls, export and table/list content should reuse the shared operation classes in `client/src/index.css`: - `ops-status-strip` for compact status metrics. - `ops-command-bar`, `ops-command-bar__row`, `ops-command-bar__tabs`, `ops-command-bar__actions` and `ops-filter-label` for tabs, filters and secondary actions. - `ops-table-focus` for the primary desktop table container. - `ops-inline-alert` for temporary mode hints such as batch operation notices. - `PrimaryTable` already applies `ops-table-focus` by default; page code may add responsive visibility classes such as `hidden md:block`, but should not recreate a separate table frame. - Finance/admin status summaries should prefer the shared `finance-status-strip` and `finance-metric-card` classes unless the task introduces a new reusable metric component. **Why**: This keeps high-frequency PC pages dense and predictable without recreating page-local Tailwind command bars. It also lets `frontend-design` change the visual treatment once while preserving component contracts. **Example**: ```tsx
待处理
...
... ``` **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright screenshot coverage when changing login, Portal, primary PC list pages or command-bar/table styling. ## Convention: Global Shell And Page Header Baseline **What**: PC page redesigns should preserve the shared Wave0-2 shell and header baseline instead of recreating page-local wrappers: - `AppShellLayout` owns the PC shell background and content offset through `app-shell` and `app-shell-main`. - `Sidebar` and `NavLinks` own primary navigation grouping. The mental model is `工作` -> `业务` -> `财务` -> `管理` -> collapsed `更多`. - `Topbar` is a compact command surface: page title, group badge, user context, global search and notifications. Do not expand it back into a large hero. - `PageHeader` and `WorkspaceHeader` should use `page-header-shell`, `page-header-shell__eyebrow`, `page-header-shell__title`, `page-header-shell__subtitle` and `page-header-shell__actions`. - Auth guidance and step hints may use `ux-command-note`, `ux-step-list` and `ux-step-item` when they explain the next action without adding page-local warning cards. **Why**: The shell/header baseline gives Wave3-5 pages a stable visual entry point and prevents each route from inventing a different title/action layout. **Example**: ```tsx ``` **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright coverage when changing `AppShellLayout`, `Sidebar`, `Topbar`, `NavLinks`, `PageHeader`, `WorkspaceHeader`, login, Portal or other A-class pages. ## Convention: A-Class PC Task-First Pages **What**: A-class PC pages such as Portal, approvals, reimbursement list and reimbursement detail should make the current user task obvious before exposing secondary operations: - First visible task surface should answer: what needs attention, what can be started, and where recent progress lives. - Keep one primary action in the first screen. Allow at most two secondary entries; move export, batch, delete, templates, complex filters, statistics and admin/finance tools into `更多`, `高级 / 台账`, detail actions, role-only panels or confirmation dialogs. - Explanation text should only be default-visible for risk, exception or empty states. Do not use repeated subtitles or notice cards to explain normal workflow steps that the layout can express. - Low-frequency capabilities are hidden or moved, not removed, unless the current Trellis task explicitly deletes the capability. **Why**: hyb-oa serves small teams with overlapping roles. Core pages must make the next click clear for ordinary employees and approvers, while keeping finance and admin tools available without dominating the default path. **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright or screenshot checks for changed A-class PC pages, asserting the task surface, primary action and secondary/advanced entry behavior. ## Convention: Detail And Mobile Command Surfaces **What**: PC detail pages and notification-like flows should reuse the Wave3 surface classes in `client/src/index.css` before adding page-local Tailwind card systems: - `detail-workspace-grid` for the main PC detail two-column workspace. - `detail-command-panel`, `detail-fact-grid` and `detail-fact-card` for compact status, summary, payment, export and evidence facts. - `detail-evidence-card` for attachments, invoices and other proof material. - `detail-timeline` and `detail-timeline-item` for approval progress and history. - `detail-action-stack` and `detail-action-card` for approve/reject/return, payment and other high-risk command groups. - `notification-inbox`, `notification-row-card` and `notification-row-card--unread` for PC notification streams; avoid reverting notifications to a desktop table unless a task explicitly requires tabular comparison. Mobile key pages should reuse the mobile command classes in `client/src/styles/mobile-touch.css`: - `mobile-focus-card` for the current task, current list or account summary. - `mobile-command-surface` for tabs, search and filters. - `mobile-list-card--focus` and `mobile-list-card--unread` for state emphasis. **Why**: Detail pages should feel like quiet command surfaces: status, summary, primary action, evidence and history have predictable places. Mobile pages should stay card/list based, with no PC tables, no horizontal overflow and no button text squeeze. **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright screenshot coverage for changed PC detail, notification and mobile pages. - UI design rules check when changing shared visual classes. ## Scenario: Auth Pages And PWA Updates ### 1. Scope / Trigger - Trigger: login, password change, password recovery or other unauthenticated forms are active while the PWA service worker finds a new frontend version. - Applies to `client/src/pwa.ts`, `client/src/layouts/AuthLayout.tsx`, and auth routes such as `/login`, `/change-password`, `/forgot-password`, and future reset-password pages. ### 2. Signatures - Event name: `hyb-oa:pwa-update-ready`. - Event detail: `{ applyUpdate?: () => void | Promise }`. - Route predicate: auth input pages must be checked by pathname before calling `updateServiceWorker(true)`. ### 3. Contracts - Auth input pages must not auto-reload when `onNeedRefresh()` fires. - Auth input pages must show an explicit update prompt with a user-triggered refresh action. - Non-auth pages may keep automatic service-worker update behavior when the task does not change broader runtime policy. - Passwords and verification codes must stay only in React component state; do not write them to `localStorage`, `sessionStorage`, URL params, reports, or Trellis task evidence. - Password visibility controls must use icon buttons with accessible labels and preserve the current input value. ### 4. Validation & Error Matrix - PWA update on `/login` -> dispatch update-ready event and keep form state. - PWA update on `/forgot-password` -> dispatch update-ready event and keep email/code/password fields in memory. - User clicks refresh in the prompt -> run the captured update handler. - User dismisses prompt -> no reload and no form reset. - Password reset request returns success for any email -> show generic sent message; do not reveal whether the account exists. ### 5. Good/Base/Bad Cases - Good: user is typing a password, update prompt appears, typed values remain. - Base: user is on a normal portal page, PWA update can refresh per existing runtime behavior. - Bad: service-worker update auto-refreshes an auth form and clears credentials. - Bad: tests use real-looking personal email addresses or persist example passwords outside the test file. ### 6. Tests Required - Frontend typecheck and build. - Focused Playwright auth UX test asserting: - login password can be shown/hidden without losing value; - forgot-password flow calls request-code and reset endpoints; - auth-page PWA update prompt appears without clearing inputs. - UI design rules check when auth page layout changes. - Any Playwright test that renders `/login`, `/forgot-password` or another auth route with mocked `/api/*` responses must mock `/api/auth/capabilities` with `emailDelivery.ready`, `emailLoginCode.enabled` and `passwordReset.enabled`. Returning `{}` for unknown auth APIs can crash auth pages before the visual or navigation assertion actually runs. ### 7. Wrong vs Correct #### Wrong ```ts onNeedRefresh() { void updateServiceWorker?.(true); } ``` #### Correct ```ts onNeedRefresh() { if (isAuthInputPath(window.location.pathname)) { window.dispatchEvent(new CustomEvent(PWA_UPDATE_READY_EVENT, { detail: { applyUpdate } })); return; } applyUpdate(); } ``` ## Scenario: Auth Page Layout And Login Entry Hierarchy ### 1. Scope / Trigger - Trigger: login, password recovery, forced password change or future unauthenticated auth forms need layout changes. - Applies to `client/src/layouts/AuthLayout.tsx`, shared auth components under `client/src/components/auth/`, and auth routes such as `/login`, `/forgot-password` and `/change-password`. ### 2. Component Contract - Auth routes should use one shared auth panel for brand, page title, subtitle, content and optional footer links. - `AuthLayout` owns only the auth page shell: background, width constraint, centering, PWA update prompt and route outlet. - Page implementations own only their form fields, submit actions, validation messages and route-specific login-entry choices. ### 3. Visual Contracts - Do not nest a form card inside another login card. - Put the brand block inside the auth panel so logo, system name, title and form share one visual axis. - Keep the panel width stable around the current auth-shell width; auth pages should feel like an OA workstation entry, not a marketing split hero. - Place `忘记密码?` beside the password label or directly below the password input on the right; do not bury it in help text or page footer. - Keep the DOM/tab order aligned with the main form flow even when CSS places `忘记密码?` visually beside the password label: username/email input -> password input -> secondary controls. Do not render the forgot-password link before the password input in DOM order. - Use password visibility icon buttons with accessible labels and preserve the current input value. ### 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. - 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 unless the task explicitly approves backend OAuth, binding or WeCom API work. - Email verification-code login is a separate login mode. Do not infer it from password-recovery verification-code flows without a backend login-code contract and abuse-control plan. ### 5. Tests Required - Frontend typecheck and build. - Focused auth E2E covering: - password visibility and forgot-password navigation on `/login`; - 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; - 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. ### 6. Wrong vs Correct #### Wrong ```tsx ``` #### Correct ```tsx ``` #### Wrong ```tsx 忘记密码? ``` #### Correct ```tsx 忘记密码? ``` ## Convention: Finance And Admin Console Surfaces **What**: PC finance and C-class admin pages should reuse Wave4 shared classes from `client/src/index.css` before creating page-local card/table layouts: - `finance-status-strip`, `finance-metric-card`, `finance-metric-card__label` and `finance-metric-card__value` for compact five-column status summaries. - `finance-workspace-grid`, `finance-command-panel`, `finance-list-card` and `finance-list-card--active` for payment/AP/invoice operational workspaces. - `admin-command-panel`, `admin-tile-grid`, `admin-tile-card` and `admin-workspace-grid` for settings, workflow, feature-flag, user, master data, notification-channel and audit pages. **Why**: Finance/admin pages are lower-frequency but high-risk operational surfaces. They need dense scanability, stable command regions and clear risk hierarchy without turning every page into a bespoke Tailwind card system. **Example**: ```tsx
可处理
{actionableCount}
...
...
``` **Tests Required**: - `cd client && npm run typecheck` - `cd client && npm run build` - Focused Playwright coverage for changed finance/admin pages. The Wave4 baseline test is `client/tests/e2e/pc-finance-admin-visual-wave4.spec.ts`. - UI design rules check when changing these shared classes.