492 行
19 KiB
Markdown
492 行
19 KiB
Markdown
# 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=<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
|
|
<StatStrip columns={4} className="ops-status-strip">
|
|
<MetricCard title="待办总数" value={summary.pendingTotal} />
|
|
</StatStrip>
|
|
|
|
<FilterBar className="ops-command-bar !p-3 md:!p-3.5">
|
|
<div className="ops-command-bar__row">
|
|
<Tabs value={status}>
|
|
<TabsList className="ops-command-bar__tabs !h-auto !justify-start !bg-slate-50">
|
|
<TabsTrigger value="pending">待处理</TabsTrigger>
|
|
</TabsList>
|
|
</Tabs>
|
|
<div className="ops-command-bar__actions">...</div>
|
|
</div>
|
|
</FilterBar>
|
|
|
|
<PrimaryTable className="hidden md:block">...</PrimaryTable>
|
|
```
|
|
|
|
**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
|
|
<WorkspaceHeader
|
|
eyebrow="审批"
|
|
title="审批中心"
|
|
subtitle="先看待处理,再进入详情核对依据。"
|
|
/>
|
|
```
|
|
|
|
**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<void> }`.
|
|
- 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
|
|
<AuthLayout>
|
|
<Card>
|
|
<Card>
|
|
<LoginForm />
|
|
</Card>
|
|
</Card>
|
|
</AuthLayout>
|
|
```
|
|
|
|
#### Correct
|
|
|
|
```tsx
|
|
<AuthPanel title="登录工作台" subtitle="账号密码登录">
|
|
<LoginForm />
|
|
<SecondaryLoginMethods />
|
|
</AuthPanel>
|
|
```
|
|
|
|
#### Wrong
|
|
|
|
```tsx
|
|
<Label htmlFor="login-password">密码</Label>
|
|
<Link to="/forgot-password">忘记密码?</Link>
|
|
<PasswordInput id="login-password" />
|
|
```
|
|
|
|
#### Correct
|
|
|
|
```tsx
|
|
<Label htmlFor="login-password">密码</Label>
|
|
<PasswordInput id="login-password" />
|
|
<Link className="row-start-1" to="/forgot-password">忘记密码?</Link>
|
|
```
|
|
|
|
## 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
|
|
<div className="finance-status-strip" data-testid="payment-batches-summary">
|
|
<div className="finance-metric-card">
|
|
<div className="finance-metric-card__label">可处理</div>
|
|
<div className="finance-metric-card__value">{actionableCount}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="finance-workspace-grid">
|
|
<section className="finance-command-panel">...</section>
|
|
<section className="finance-command-panel">...</section>
|
|
</div>
|
|
```
|
|
|
|
**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.
|