docs(08-05-product-interaction-consistency): 固化交互治理任务规划与规范
这个提交包含在:
@@ -252,13 +252,13 @@ reference, not a copy of Feishu or Ant Design branding.
|
||||
detail panels, confirmations and more menus. Project-specific differences
|
||||
should simplify or hide low-frequency work for small teams, not invent new
|
||||
controls or unusual action flows.
|
||||
- Page titles default to the route name only, such as `工作台`, `待我处理`, `报销`,
|
||||
- Page titles default to the route name only, such as `工作台`, `待我审批`, `报销`,
|
||||
`合同`, `采购`, `资产`, `个人设置` and `通知中心`. Page subtitles are off by default and
|
||||
appear only for exception, empty, permission-denied, Enterprise WeChat/OA
|
||||
boundary, external-system boundary or irreversible-action explanations.
|
||||
- Normal workflows should not be explained in default-visible copy. Do not add
|
||||
subtitles, card descriptions, helper rows or notice bars that restate obvious
|
||||
actions such as "待我处理是处理工作", "查看通知消息", "先核对再处理" or "去处理要做的事".
|
||||
actions such as "待我审批是处理工作", "查看通知消息", "先核对再处理" or "去处理要做的事".
|
||||
- Header primary actions are reserved for creation or a real page-level primary
|
||||
action: `新建报销`, `新建采购`, `新增合同`, `新增资产`, `新建项目`. Workbench,
|
||||
pending-task, notification and read-only record pages must not force a header
|
||||
@@ -274,7 +274,7 @@ reference, not a copy of Feishu or Ant Design branding.
|
||||
`撤回`, `作废`, `归档`, `更多`. Do not use slogan-like or invented labels
|
||||
such as `处理最急的一件`.
|
||||
- Sidebar entries are role-aware common work entries, not an all-permissions
|
||||
module catalog. Direct entries may include `工作台`, `待我处理`, `报销`, `采购`,
|
||||
module catalog. Direct entries may include `工作台`, `待我审批`, `报销`, `采购`,
|
||||
`合同`, `项目`, `资产`, `付款`, `应付账款`, `票据`, `团队`, `请假记录` and `管理`
|
||||
when the current role has real use. Low-frequency, frozen, staged or
|
||||
troubleshooting routes stay in `更多` or the `管理` landing page.
|
||||
@@ -329,13 +329,13 @@ reference, not a copy of Feishu or Ant Design branding.
|
||||
| Surface | Template | First-screen content | Primary action rule |
|
||||
| --- | --- | --- | --- |
|
||||
| `工作台` | 工作台总览 | Compact counts, common entries, real reminders | No forced header action. Use `去处理`, `新建报销`, `查看全部` inside relevant sections; do not show helper sentences for ordinary items. |
|
||||
| `待我处理` | 任务处理列表 | `待处理` / `已处理` tabs, count, minimal filters, task list | Row action is `处理`; `已处理记录` is a tab, not a separate header button. |
|
||||
| `待我审批` | 任务处理列表 | `待处理` / `已处理` tabs, count, minimal filters, task list | Row action is `处理`; `已处理记录` is a tab, not a separate header button. |
|
||||
| `审批详情` | 详情工作区 | Summary, facts/evidence, right summary/action panel, history | One action bar: primary `通过`, secondary `退回`/`驳回`, `转审` in `更多`. |
|
||||
| `报销` / `采购` / `合同` / `项目` / `资产` / `付款` / `应付账款` / `票据` | 业务台账列表 | One-row common filters plus table/card list | Header creation only when the route owns creation; risky tools use `更多`, clearly named role-only actions or detail pages; no default left-list/right-detail split. |
|
||||
| Business details | 详情工作区 | Summary, facts, evidence, relations, history | Right-side state/action panel on PC; bottom primary action on mobile. |
|
||||
| `管理` | 管理配置页 | Grouped landing: `人员组织`, `审批流程`, `基础资料`, `系统设置`, `审计排障` | Management subpages use search/filter, table and right operation column. |
|
||||
| `个人设置` | 管理配置页 variant | `个人资料`, `账号安全`, `通知偏好`, `企业微信绑定` | No employee dossier, permission matrix or org maintenance in the default profile path. |
|
||||
| `通知中心` | 业务台账列表 variant | Event inbox for state changes, reminders, failures and sync results | Notification click deep-links to business detail, workflow task or failure explanation; never duplicates `待我处理`. |
|
||||
| `通知中心` | 业务台账列表 variant | Event inbox for state changes, reminders, failures and sync results | Notification click deep-links to business detail, workflow task or failure explanation; never duplicates `待我审批`. |
|
||||
| `请假记录` / `考勤` | 业务台账列表 or record view | Enterprise WeChat-owned records, mirror status, exceptions and audit | Ordinary users do not see OA daily leave/punch approval creation; OA emergency entry only for authorized emergency/admin scope. |
|
||||
| Mobile routes | Mobile expression of the same template | Top status/focus, card list or sectioned detail | One bottom safe-area primary action; secondary actions in `更多` or confirmation. |
|
||||
|
||||
@@ -682,7 +682,7 @@ point and prevents each route from inventing a different title/action layout.
|
||||
the primary sidebar, including `合同`, `采购`, `资产` and `项目` when relevant.
|
||||
`更多` is for low-frequency, frozen, staged or occasional entries, not a
|
||||
place to bury common work.
|
||||
- Approvers see `待我处理`; ordinary employees should not see `待办` or
|
||||
- Approvers see `待我审批`; ordinary employees should not see `待办` or
|
||||
`审批待办` in the sidebar by default.
|
||||
- PC leave navigation uses `请假记录` unless the current task explicitly opens OA
|
||||
emergency leave submission.
|
||||
@@ -844,11 +844,11 @@ of exposing every allowed tool at once.
|
||||
default.
|
||||
- Initiator views emphasize current status, next step, supplement-material
|
||||
needs, approval/payment progress and whether edit or withdraw is allowed.
|
||||
- Approver and processor views emphasize `待我处理` and the current node task.
|
||||
- Approver and processor views emphasize `待我审批` and the current node task.
|
||||
Show approve, reject, return or transfer actions only when the server-backed
|
||||
task assignment says the current user can act.
|
||||
- Approval actions such as approve, reject, return and transfer execute only in
|
||||
`待我处理`, workflow task detail, mobile approval detail or an explicitly
|
||||
`待我审批`, workflow task detail, mobile approval detail or an explicitly
|
||||
current task-processing panel. Business ledger rows and ordinary business
|
||||
details use `查看处理`, `查看进度`, `补材料` or a link into the workflow task;
|
||||
they must not duplicate approval action buttons.
|
||||
@@ -946,7 +946,7 @@ screen.
|
||||
- Keep 3 to 5 high-frequency filters visible by default. Prioritize search,
|
||||
status, scope and date/time; add business-specific filters such as project,
|
||||
person or type only when they are genuinely frequent.
|
||||
- The default view must match the route's main job: `我的报销`, `待我处理`,
|
||||
- The default view must match the route's main job: `我的报销`, `待我审批`,
|
||||
`合同`, `资产` and similar task nouns. Do not default ordinary users
|
||||
into company-wide management views.
|
||||
- Rows and cards must answer what the object is, current state, why it relates
|
||||
@@ -1349,6 +1349,89 @@ complexity from leaking into WeChat.
|
||||
- If true Enterprise WeChat device validation is unavailable, record it as
|
||||
paused manual validation; do not claim full WebView acceptance.
|
||||
|
||||
## Scenario: Shared Mobile Sticky Action Surface
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: a mobile detail, approval or edit surface needs a bottom fixed
|
||||
primary-action area, or an existing bottom action area is changed.
|
||||
- Applies to mobile consumers and responsive business edit forms; it does not
|
||||
move business permission or state-machine decisions into the shared shell.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Component: `MobileStickyActionBar({ children, className?, contentClassName?, inlineFromMedium?, testId? })` from
|
||||
`client/src/components/patterns/MobileStickyActionBar.tsx`.
|
||||
- Page spacing constant: `MOBILE_STICKY_ACTION_PAGE_CLASS`.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- New or changed mobile bottom actions reuse `MobileStickyActionBar`; do not
|
||||
copy its fixed positioning, safe-area, grid or shadow classes into a page.
|
||||
- When a fixed action bar is rendered, the page's scroll/content container also
|
||||
receives `MOBILE_STICKY_ACTION_PAGE_CLASS` so the final field, evidence card
|
||||
or history row remains above the bar and device safe area.
|
||||
- Apply the page class conditionally when actions are conditional; an absent bar
|
||||
must not leave unexplained fixed-action padding.
|
||||
- The shared component owns coordinates, safe-area treatment, responsive inline
|
||||
conversion and action layout only. Consumers still own button text,
|
||||
permission/state visibility, confirmation, pending and disabled behavior.
|
||||
- `inlineFromMedium` may convert the action surface to an inline desktop/tablet
|
||||
row for shared edit templates; mobile detail routes normally keep the fixed
|
||||
form.
|
||||
- `PaymentBatchesPage` retains its existing responsive payment-specific bar as
|
||||
a known legacy exception until a payment-scoped task proves migration has no
|
||||
business or layout regression. It is not a pattern to copy.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Bar visible + page class present -> final content remains reachable above the
|
||||
fixed surface.
|
||||
- Bar visible + page class missing -> spacing-contract failure.
|
||||
- Bar hidden + unconditional page class -> unnecessary-padding failure.
|
||||
- Consumer moves approval/payment state logic into the shared component ->
|
||||
ownership-contract failure.
|
||||
- Narrow viewport or device safe area -> actions remain readable and are not
|
||||
covered by the home indicator.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: mobile approval and mobile reimbursement share the same action surface
|
||||
while each page keeps its own action matrix and confirmation behavior.
|
||||
- Base: `BusinessEditTemplate` uses `inlineFromMedium` and the same page-spacing
|
||||
constant when bottom actions exist.
|
||||
- Bad: paste a page-local `fixed inset-x-0 bottom-0` wrapper and compensate with
|
||||
an unrelated hard-coded `pb-24`.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- A source contract asserts mobile approval, mobile reimbursement and
|
||||
`BusinessEditTemplate` import the shared component and page-spacing constant.
|
||||
- Focused Playwright covers at least two mobile consumers, including final
|
||||
content reachability, visible/pending/disabled action states and a narrow
|
||||
viewport safe-area regression.
|
||||
- Run `cd client && npm run typecheck && npm run build`.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```tsx
|
||||
<main className="pb-24">
|
||||
...
|
||||
<div className="fixed inset-x-0 bottom-0">{actions}</div>
|
||||
</main>
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```tsx
|
||||
<main className={cn(showActions && MOBILE_STICKY_ACTION_PAGE_CLASS)}>
|
||||
...
|
||||
{showActions ? <MobileStickyActionBar>{actions}</MobileStickyActionBar> : null}
|
||||
</main>
|
||||
```
|
||||
|
||||
## Convention: Notifications Versus Tasks
|
||||
|
||||
**What**: Task queues and notifications have separate jobs. A task queue is for
|
||||
@@ -1356,7 +1439,7 @@ action; a notification center is for event awareness and navigation.
|
||||
|
||||
**Contracts**:
|
||||
|
||||
- `待我处理` is an action list. Include only items that require the current user
|
||||
- `待我审批` is an action list. Include only items that require the current user
|
||||
to process, supplement material, review, pay, approve, confirm or resolve an
|
||||
exception.
|
||||
- Task rows must have a clear next step, object summary, business state and
|
||||
@@ -1482,6 +1565,88 @@ structure.
|
||||
permission-denied pages, notification failure targets or shared error
|
||||
components.
|
||||
|
||||
## Scenario: Ordinary User Error Message Resolution
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: a frontend component catches an API or JavaScript error and needs to
|
||||
show failure feedback on an ordinary employee, approver, finance or mobile
|
||||
path.
|
||||
- Explicit exception: `client/src/pages/AuditLogsPage.tsx` is a permissioned,
|
||||
read-only technical detail surface and may display the minimum API code beside
|
||||
its error message.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Shared resolver:
|
||||
`resolveErrorMessage(error: unknown, fallback = "操作失败,请稍后重试"): string`
|
||||
from `client/src/lib/resolveErrorMessage.ts`.
|
||||
- API business mapping remains
|
||||
`mapApiErrorMessage(code, details, fallbackMessage)` in
|
||||
`client/src/api/errorMessages.ts`.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Ordinary user feedback calls `resolveErrorMessage` instead of concatenating
|
||||
`error.code`, `error.message`, request methods or API paths locally.
|
||||
- API codes may still drive control flow, such as detecting an already-processed
|
||||
task or a disabled capability, but they must not be reused as display copy.
|
||||
- The resolver returns mapped natural Chinese, removes a leading technical code
|
||||
prefix and falls back when the candidate is empty, lacks natural Chinese or
|
||||
resembles a URL, API/filesystem path, HTTP request line, stack frame or raw
|
||||
JSON payload.
|
||||
- Feedback placement remains separate from message parsing: field/material
|
||||
problems are local, region load failures are persistent and retryable, and
|
||||
short success feedback may use toast.
|
||||
- `AuditLogsPage` is the only current code-plus-message exception. New admin or
|
||||
troubleshooting exceptions require an explicit technical detail area and a
|
||||
scoped Trellis decision; do not weaken the shared resolver.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Known API code with a mapped business message -> show the mapped natural
|
||||
Chinese only.
|
||||
- Candidate starts with `VALID_001:` or `500:` -> remove the prefix before
|
||||
display.
|
||||
- Candidate is English-only, contains `/api/`, a full path, HTTP method, stack
|
||||
frame or raw JSON -> show the caller-provided fallback.
|
||||
- Unknown value or empty message -> show the caller-provided fallback.
|
||||
- Audit-log load/export failure caused by `ApiError` -> the read-only audit
|
||||
error area may show `<code>: <message>`; ordinary pages may not.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: a reimbursement page uses
|
||||
`resolveErrorMessage(error, "加载报销失败,请稍后重试")` and keeps the retry
|
||||
action beside the persistent error.
|
||||
- Base: a page uses `isApiError(error)` only to branch on a business condition,
|
||||
then resolves any displayed failure through the shared helper.
|
||||
- Bad: each page removes a code prefix with its own regex or displays
|
||||
`` `${error.code}: ${error.message}` `` on an ordinary path.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- A source contract scans ordinary frontend consumers and rejects local
|
||||
code-plus-message concatenation while listing `AuditLogsPage` as the explicit
|
||||
exception.
|
||||
- Focused tests cover a mapped API error, a leading code prefix, a technical
|
||||
detail fallback and an unknown error.
|
||||
- Run `cd client && npm run typecheck && npm run build`.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```tsx
|
||||
setError(isApiError(error) ? `${error.code}: ${error.message}` : "加载失败");
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```tsx
|
||||
setError(resolveErrorMessage(error, "加载失败,请稍后重试"));
|
||||
```
|
||||
|
||||
## Convention: Dangerous Action Confirmation
|
||||
|
||||
**What**: Destructive, financial, approval, configuration, batch and external
|
||||
@@ -1726,7 +1891,7 @@ training or permission-maintenance surfaces:
|
||||
default. If first-login guidance is needed, use a dismissible welcome dialog
|
||||
with at most three real business entries.
|
||||
- Welcome or onboarding entries must point to executable user tasks, such as
|
||||
`处理待办`, `提交报销` or `请假`; do not use explanatory entries like
|
||||
`待我审批`, `提交报销` or `请假`; do not use explanatory entries like
|
||||
`了解流程`, and do not route users to settings or notifications as a
|
||||
substitute for task guidance.
|
||||
- `个人设置` default content is personal profile, password/security,
|
||||
|
||||
在新工单中引用
屏蔽一个用户