fix: 统一报销付款详情布局与票据展示(09-04-reimbursement-state-gap-finance-view)
这个提交包含在:
@@ -680,7 +680,7 @@ test.describe("报销付款交接一致性", () => {
|
||||
const link = page.getByRole("link", { name: "查看所在付款批次", exact: true });
|
||||
await expect(link).toHaveCount(1);
|
||||
const linkBounds = await link.boundingBox();
|
||||
expect(linkBounds!.height).toBeGreaterThanOrEqual(44);
|
||||
expect(Math.round(linkBounds!.height * 100) / 100).toBeGreaterThanOrEqual(44);
|
||||
if (!mobile) expect(linkBounds!.width).toBeLessThan(180);
|
||||
await link.click();
|
||||
await expect(page.getByTestId("payment-batch-processing-panel")).toBeVisible();
|
||||
@@ -698,7 +698,99 @@ test.describe("报销付款交接一致性", () => {
|
||||
});
|
||||
}
|
||||
|
||||
test("账号查看图标紧随脱敏值且确认前不请求完整账号", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 1440, height: 960 });
|
||||
await mockSystemActionApis(page, {
|
||||
canExportPaymentOrder: true,
|
||||
meOverride: { roleCodes: ["finance"], permissions: [...me.permissions, "employee.bank.read"] },
|
||||
});
|
||||
let reveals = 0;
|
||||
page.on("request", (request) => { if (new URL(request.url()).pathname.endsWith("/payee-bank/reveal")) reveals += 1; });
|
||||
await login(page, user);
|
||||
await page.goto(`/payment-batches?id=${paymentBatchId}`);
|
||||
const reveal = page.getByRole("button", { name: "查看完整账号", exact: true });
|
||||
await expect(reveal).toBeVisible();
|
||||
await expect(reveal).toHaveText("");
|
||||
await expect(reveal).toHaveAttribute("title", "查看完整账号");
|
||||
const icon = await reveal.boundingBox();
|
||||
const account = await reveal.locator("..").locator("span").boundingBox();
|
||||
expect(icon!.width).toBeGreaterThanOrEqual(44);
|
||||
expect(icon!.height).toBeGreaterThanOrEqual(44);
|
||||
expect(icon!.x).toBeGreaterThan(account!.x);
|
||||
await reveal.focus();
|
||||
await page.keyboard.press("Enter");
|
||||
const dialog = page.getByRole("dialog");
|
||||
await expect(dialog).toContainText("本次查看会记录");
|
||||
await expect(dialog.getByRole("textbox", { name: "查看收款账号原因" })).toBeVisible();
|
||||
expect(reveals).toBe(0);
|
||||
await dialog.getByRole("button", { name: "返回", exact: true }).click();
|
||||
expect(reveals).toBe(0);
|
||||
});
|
||||
|
||||
for (const width of [390, 1280, 1440]) {
|
||||
test(`票据紧凑展示${width}多张长名称及预览不丢失`, async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 960 });
|
||||
await mockSystemActionApis(page, { reimbursementStatus: "approved" });
|
||||
const detail = reimbursementDetail("approved");
|
||||
const sellerName = "合成开票方长名称".repeat(8);
|
||||
detail.invoices = Array.from({ length: 5 }, (_, index) => ({
|
||||
...detail.invoices[0],
|
||||
id: `invoice-layout-${index}`,
|
||||
invoiceNumber: `SYNTHETIC-LAYOUT-000000000000000000000${index}`,
|
||||
sellerName,
|
||||
}));
|
||||
detail.attachments = [];
|
||||
await page.route(`**/api/reimbursements/${reimbursementId}`, (route) => fulfillJson(route, detail));
|
||||
let previews = 0;
|
||||
await page.route("**/api/invoice-pool/invoice-layout-0/signed-url", async (route) => {
|
||||
previews += 1;
|
||||
await fulfillJson(route, { signedUrl: "about:blank", originalName: "合成预览.pdf", fileSize: 1024 });
|
||||
});
|
||||
await login(page, user);
|
||||
await page.goto(`/reimbursements/${reimbursementId}`);
|
||||
const table = page.getByTestId("reimbursement-invoices-table");
|
||||
await expect(table).toBeVisible();
|
||||
await expect(table.getByTestId("approval-invoice-evidence")).toHaveCount(5);
|
||||
await expect(table.getByText(sellerName, { exact: true })).toHaveCount(5);
|
||||
if (width >= 1024) await expect(table.getByRole("columnheader", { name: "金额" })).toBeVisible();
|
||||
else await expect(table.locator("thead")).toBeHidden();
|
||||
await expect(page.getByText("未上传补充附件", { exact: true })).toBeVisible();
|
||||
await table.getByRole("button", { name: `查看发票:${detail.invoices[0].invoiceNumber}`, exact: true }).click();
|
||||
await expect.poll(() => previews).toBe(1);
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 2)).toBe(true);
|
||||
await table.screenshot({ path: testInfo.outputPath("invoice-table.png") });
|
||||
});
|
||||
}
|
||||
|
||||
for (const width of [1280, 1440]) {
|
||||
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[] = [];
|
||||
for (const [url, panelId] of [
|
||||
[`/reimbursements/${reimbursementId}`, "reimbursement-action-panel"],
|
||||
[`/payment-batches?id=${paymentBatchId}`, "payment-batch-action-panel"],
|
||||
]) {
|
||||
await page.goto(url);
|
||||
const panel = page.getByTestId(panelId);
|
||||
await expect(panel).toBeVisible();
|
||||
await page.evaluate(() => document.fonts.ready);
|
||||
widths.push((await panel.locator("../..").boundingBox())!.width);
|
||||
const row = panel.getByTestId("detail-inline-actions");
|
||||
const primary = await row.locator("a, button").first().boundingBox();
|
||||
const more = await row.getByRole("button", { name: "更多", exact: true }).boundingBox();
|
||||
expect(Math.abs(primary!.y + primary!.height / 2 - more!.y - more!.height / 2)).toBeLessThan(2);
|
||||
expect(more!.x).toBeGreaterThan(primary!.x + primary!.width);
|
||||
await row.getByRole("button", { name: "更多", exact: true }).click();
|
||||
await expect(page.getByRole("menu")).toBeVisible();
|
||||
await page.keyboard.press("Escape");
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 2)).toBe(true);
|
||||
await page.screenshot({ path: testInfo.outputPath(`${panelId}.png`), fullPage: true });
|
||||
}
|
||||
expect(widths).toEqual([320, 320]);
|
||||
});
|
||||
|
||||
test(`桌面${width}创建批次按钮短文案按内容宽度且只导航不组批`, async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 960 });
|
||||
await mockSystemActionApis(page, { reimbursementStatus: "approved", reimbursementProgress: () => progress("none") });
|
||||
@@ -913,13 +1005,13 @@ test.describe("R7E 全站高风险操作二次确认", () => {
|
||||
const actionPanel = page.getByTestId("payment-batch-action-panel");
|
||||
await expect(actionPanel.getByTestId("payment-batch-action-downloadOrder")).toBeVisible();
|
||||
await actionPanel.getByText("更多", { exact: true }).click();
|
||||
await expect(actionPanel.getByRole("button", { name: "上传银行回单" })).toBeVisible();
|
||||
await expect(page.getByRole("menuitem", { name: "上传银行回单" })).toBeVisible();
|
||||
await expect(page.getByTestId("payment-batch-mobile-actions")).toBeHidden();
|
||||
await expect(page.getByTestId("payment-batch-receipt-panel").getByRole("button", { name: "上传银行回单" })).toHaveCount(0);
|
||||
await expect(page.getByRole("button", { name: "登记付款完成" })).toHaveCount(0);
|
||||
|
||||
const desktopFileChooser = page.waitForEvent("filechooser");
|
||||
await actionPanel.getByRole("button", { name: "上传银行回单" }).click();
|
||||
await page.getByRole("menuitem", { name: "上传银行回单" }).click();
|
||||
await (await desktopFileChooser).setFiles({
|
||||
name: "合成银行回单.pdf",
|
||||
mimeType: "application/pdf",
|
||||
@@ -1008,7 +1100,7 @@ test.describe("R7E 全站高风险操作二次确认", () => {
|
||||
await page.screenshot({ path: testInfo.outputPath("after-payment-order.png"), fullPage: true });
|
||||
await actions.getByText("更多", { exact: true }).click();
|
||||
if (mobile) await page.getByRole("menuitem", { name: "重新下载制单" }).click();
|
||||
else await actions.getByTestId("payment-batch-action-redownloadOrder").click();
|
||||
else await page.getByRole("menuitem", { name: "重新下载制单" }).click();
|
||||
await expect(dialog).toContainText("请勿重复提交");
|
||||
await expect(dialog.getByRole("textbox")).toHaveCount(0);
|
||||
const secondDownload = page.waitForEvent("download");
|
||||
|
||||
在新工单中引用
屏蔽一个用户