fix: 统一报销与付款详情整体宽度(09-04-reimbursement-state-gap-finance-view)
这个提交包含在:
@@ -14,7 +14,7 @@ and verification contracts. Do not copy broad aesthetic guidance from
|
||||
|
||||
## Convention: Reimbursement Payment Handoff Consistency
|
||||
|
||||
- Reimbursement desktop shells and payment detail opt into `detail-workspace-grid--payment`: a 320px aside at lg and above, single column below lg. A shared proportional grid does not guarantee equal asides when parent max-width differs. Verify actual widths on both pages at 1280/1440, not only matching class names; leave unrelated detail grids unchanged.
|
||||
- Reimbursement desktop shells and payment detail opt into `detail-workspace-grid--payment`: a 320px aside at lg and above, single column below lg. Both fill the same outer page width; do not add a reimbursement-only `max-w-7xl` or centered inner wrapper. Verify both workspace left/right boundaries, reimbursement hero alignment and 320px asides at 1280/1440/1920, plus narrow-screen overflow. Equal aside widths alone do not prove equal page widths; smaller viewports can hide a max-width defect. Leave unrelated detail grids unchanged.
|
||||
- `BusinessDetailActionPanel({ inlineActions: true })` puts the primary action followed by the More trigger in a wrapping, content-width row. The default layout stays unchanged. Both detail pages use the existing DropdownMenu; menu items are portalled outside the card, so test via page-level menu roles. Keep disabled states, permission conditions, confirmations and mobile payment actions intact. Do not pass known-empty action components as children: a React element that renders null is still a nonempty slot and otherwise creates a phantom divider.
|
||||
- Linked reimbursement invoices use a desktop table with number preview, seller, date and right-aligned amount; narrow rows stack without duplicating IDs or preview controls. Keep OCR warnings, unlinked correction cards, attachment delete confirmation and evidence anchors. Test five synthetic invoices, long names/numbers, empty attachments, preview calls, narrow layout and the existing approval/detail consumers.
|
||||
- A compact payee-account reveal control stays beside the masked value as a 44px Eye button with title and aria-label `查看完整账号`. Preserve role/permission/status/account gates and the reason/audit dialog; icon clicks must not immediately request plaintext. Layout measurements wait for fonts and compare aligned centers; round subpixel box heights to hundredths before checking the 44px minimum (Chromium can return 43.99994 for a CSS 44px target).
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 报销状态空隙与财务处理视角:设计
|
||||
|
||||
## 2026-09-12 修正整体宽度遗漏
|
||||
|
||||
此前仅统一侧栏,保留报销正文max-w-7xl而标题与付款正文未限宽;1920px时出现正文内缩。本次移除共享报销桌面壳的mx-auto/w-full/max-w-7xl,完全复用付款同款grid与外层PageScaffold。共享壳覆盖报销详情及审批工作台,不改全站容器或手机断点。测试除侧栏宽度外须比较两页grid左右边界及报销hero左右边界,不能只测1280/1440时尚未触发的最大宽度。
|
||||
|
||||
## 2026-09-11 等宽侧栏与票据表格
|
||||
|
||||
动作卡通过可选inlineActions布局主动作和更多,默认合同不变。两页更多复用现有Radix DropdownMenu,Portal渲染后测试按page.getByRole("menuitem")定位,而不是动作卡内找按钮。业务回调和确认对话框不变;报销调用方仅在有撤回或动作错误时传ReimbursementActions,避免React组件返回null但外层误判为有内容而生成空分隔线。
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# 报销状态空隙与财务处理视角:实施计划
|
||||
|
||||
## 2026-09-12 整体宽度修正
|
||||
|
||||
本地验证后用户明确同意复核并提交这六个文件、准备发布。本轮仅提交该增量,不推送、不部署;下文未提交状态为验证结束时的历史记录,实际提交标识以Git及本地发布准备回执为准。
|
||||
|
||||
- [x] 在旧构建复现1920px正文内缩并让整体边界断言失败。
|
||||
- [x] 移除报销共享壳多余限宽;1280/1440/1920px两页整体对齐、320px侧栏、390px溢出与既有交互回归。
|
||||
- [x] typecheck/build、定向浏览器与规约检查;仅本地实施,提交/推送/部署另批。
|
||||
|
||||
旧构建1920px测试退出1,报销grid与hero左边界差136px;本次不是只凭源码推断。运行时只移除共享壳的mx-auto/w-full/max-w-7xl,付款页、全局容器及业务逻辑未改。frontend-design不可用,按已批方案维护现有布局,无新视觉体系。
|
||||
|
||||
在本独立副本client执行npm run build(包含typecheck)退出0;本地preview配合合成mock API,执行 `npx playwright test tests/e2e/system-action-confirmation.spec.ts --grep '侧栏等宽|创建批次按钮短文案|票据紧凑展示|制单后返回报销|账号查看图标' --workers=1 --reporter=list`,12/12通过、退出0。覆盖1280/1440/1920两页grid左右边界、报销hero对齐、320px侧栏、主按钮/更多,以及390px票据/预览与手机交接。已视觉核看1920报销截图。构建、浏览器、UI strict、Trellis治理、process-contract日志位于artifacts/qa-layout/overall-width-*.log;各检查通过,git diff --check通过。
|
||||
|
||||
主会话复核通过,不冒充独立review。共享壳同时被审批适配器引用,其类型构建已验证;本轮未额外执行真实审批业务链或生产测试,截图仅合成数据。无后端/迁移/权限变化,未提交/推送/部署;下一步复核此六文件增量,获授权后提交发布。
|
||||
|
||||
## 2026-09-11 备注精简增量(本地验证完成,已获提交授权)
|
||||
|
||||
用户随后明确同意复核、提交这六个文件并准备发布。本轮仅提交这一增量,不推送、不连接生产、不部署;实际提交标识以Git记录及本地发布准备回执为准。下文“未提交”描述的是本地验证结束时的历史阶段,不是提交完成后的状态。
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
## Goal
|
||||
|
||||
### 2026-09-12 整体宽度统一(已批准本地实施)
|
||||
|
||||
报销详情标题与正文、付款详情使用同一外层宽度和边距,移除报销正文独有的1280px居中限制。正文自适应、桌面侧栏320px及手机单列不变。复用当前任务;验收1280/1440/1920px两页整体左右边界及报销标题/正文边界,390px无横向溢出。只维护现有布局,不引入新视觉方案;不改权限或业务动作,提交、部署另批。
|
||||
|
||||
### 2026-09-11 最新确认:制单备注只保留报销编号
|
||||
|
||||
用户批准用途为“报销款”、备注仅完整报销编号;一张报销单对应一行银行转账,同一付款批次允许多张单,同人同账号不合并。本次复用当前任务承接,付款模板事实同步09-08任务,不新建task。只修改备注映射及回归,不改编号、权限、审批或生产数据;提交、推送和部署另批。
|
||||
|
||||
@@ -30,7 +30,7 @@ export function ReimbursementDesktopWorkspaceShell({ model, capabilities, slots
|
||||
)}
|
||||
/>
|
||||
{slots.transientFeedback}
|
||||
<BusinessDetailWorkspace className="detail-workspace-grid--payment mx-auto w-full max-w-7xl">
|
||||
<BusinessDetailWorkspace className="detail-workspace-grid--payment">
|
||||
<BusinessDetailMain>
|
||||
{slots.headerDetails}
|
||||
{slots.beforeEvidence}
|
||||
|
||||
@@ -762,12 +762,13 @@ test.describe("报销付款交接一致性", () => {
|
||||
});
|
||||
}
|
||||
|
||||
for (const width of [1280, 1440]) {
|
||||
for (const width of [1280, 1440, 1920]) {
|
||||
test(`桌面${width}付款与报销侧栏等宽且更多紧随主按钮`, async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 960 });
|
||||
await mockSystemActionApis(page, { reimbursementStatus: "approved", reimbursementProgress: () => progress("reviewed") });
|
||||
await login(page, user);
|
||||
const widths: number[] = [];
|
||||
const boundaries: { left: number; right: number }[] = [];
|
||||
for (const [url, panelId] of [
|
||||
[`/reimbursements/${reimbursementId}`, "reimbursement-action-panel"],
|
||||
[`/payment-batches?id=${paymentBatchId}`, "payment-batch-action-panel"],
|
||||
@@ -776,6 +777,14 @@ test.describe("报销付款交接一致性", () => {
|
||||
const panel = page.getByTestId(panelId);
|
||||
await expect(panel).toBeVisible();
|
||||
await page.evaluate(() => document.fonts.ready);
|
||||
const grid = page.locator(".detail-workspace-grid--payment");
|
||||
const gridBounds = (await grid.boundingBox())!;
|
||||
boundaries.push({ left: gridBounds.x, right: gridBounds.x + gridBounds.width });
|
||||
if (panelId === "reimbursement-action-panel") {
|
||||
const heroBounds = (await page.getByTestId("reimbursement-desktop-workspace").locator(".workbench-hero").boundingBox())!;
|
||||
expect(Math.abs(gridBounds.x - heroBounds.x)).toBeLessThan(2);
|
||||
expect(Math.abs(gridBounds.x + gridBounds.width - heroBounds.x - heroBounds.width)).toBeLessThan(2);
|
||||
}
|
||||
widths.push((await panel.locator("../..").boundingBox())!.width);
|
||||
const row = panel.getByTestId("detail-inline-actions");
|
||||
const primary = await row.locator("a, button").first().boundingBox();
|
||||
@@ -789,6 +798,8 @@ test.describe("报销付款交接一致性", () => {
|
||||
await page.screenshot({ path: testInfo.outputPath(`${panelId}.png`), fullPage: true });
|
||||
}
|
||||
expect(widths).toEqual([320, 320]);
|
||||
expect(Math.abs(boundaries[0].left - boundaries[1].left)).toBeLessThan(2);
|
||||
expect(Math.abs(boundaries[0].right - boundaries[1].right)).toBeLessThan(2);
|
||||
});
|
||||
|
||||
test(`桌面${width}创建批次按钮短文案按内容宽度且只导航不组批`, async ({ page }, testInfo) => {
|
||||
|
||||
在新工单中引用
屏蔽一个用户