UI6 优化移动首页快捷卡视觉
这个提交包含在:
@@ -130,18 +130,25 @@ function ActionTile({ action }: { action: MobileAction }) {
|
|||||||
to={action.to}
|
to={action.to}
|
||||||
className={
|
className={
|
||||||
isPrimary
|
isPrimary
|
||||||
? "flex min-h-24 flex-col justify-between rounded-lg border border-primary-100 bg-primary-50 p-3 text-primary shadow-sm"
|
? "relative flex min-h-24 flex-col justify-between rounded-lg border border-primary-100 bg-primary-50 p-3 pr-14 text-primary shadow-sm"
|
||||||
: isWarning
|
: isWarning
|
||||||
? "flex min-h-24 flex-col justify-between rounded-lg border border-amber-200 bg-amber-50 p-3 text-amber-900"
|
? "relative flex min-h-24 flex-col justify-between rounded-lg border border-amber-200 bg-amber-50 p-3 pr-14 text-amber-900"
|
||||||
: "flex min-h-24 flex-col justify-between rounded-lg border border-zinc-200 bg-white p-3 text-zinc-900 shadow-sm"
|
: "relative flex min-h-24 flex-col justify-between rounded-lg border border-zinc-200 bg-white p-3 pr-14 text-zinc-900 shadow-sm"
|
||||||
}
|
}
|
||||||
data-testid={`mobile-action-${action.key}`}
|
data-testid={`mobile-action-${action.key}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="min-w-0">
|
||||||
<span className="text-sm font-semibold">{action.label}</span>
|
<span className="block min-w-0 whitespace-nowrap text-base font-semibold leading-6" data-testid={`mobile-action-${action.key}-label`}>
|
||||||
<span className="material-symbols-outlined text-[20px]">{action.icon}</span>
|
{action.label}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={isPrimary ? "text-xs text-primary/70" : "text-xs text-zinc-500"}>{action.meta}</div>
|
<span
|
||||||
|
className="material-symbols-outlined absolute right-3 top-3 flex size-8 items-center justify-center rounded-md bg-white/70 text-[21px] leading-none shadow-sm"
|
||||||
|
data-testid={`mobile-action-${action.key}-icon`}
|
||||||
|
>
|
||||||
|
{action.icon}
|
||||||
|
</span>
|
||||||
|
<div className={isPrimary ? "truncate text-xs text-primary/70" : "truncate text-xs text-zinc-500"}>{action.meta}</div>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -263,6 +263,25 @@ async function collectMobileMetrics(page: Page) {
|
|||||||
document.querySelector("[data-testid='mobile-reimbursement-sticky-invoice-add']"),
|
document.querySelector("[data-testid='mobile-reimbursement-sticky-invoice-add']"),
|
||||||
document.querySelector("[data-testid='reimbursement-submit']"),
|
document.querySelector("[data-testid='reimbursement-submit']"),
|
||||||
].filter(Boolean).map((element) => element!.getBoundingClientRect());
|
].filter(Boolean).map((element) => element!.getBoundingClientRect());
|
||||||
|
const actionLabels = Array.from(document.querySelectorAll("[data-testid^='mobile-action-'][data-testid$='-label']")).map((element) => {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
const style = window.getComputedStyle(element);
|
||||||
|
const key = element.getAttribute("data-testid")?.replace(/^mobile-action-/, "").replace(/-label$/, "") ?? "";
|
||||||
|
const icon = document.querySelector(`[data-testid='mobile-action-${key}-icon']`);
|
||||||
|
const iconRect = icon?.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
text: element.textContent?.trim() ?? "",
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
right: rect.right,
|
||||||
|
lineHeight: Number.parseFloat(style.lineHeight) || 24,
|
||||||
|
whiteSpace: style.whiteSpace,
|
||||||
|
iconLeft: iconRect?.left ?? null,
|
||||||
|
iconWidth: iconRect?.width ?? 0,
|
||||||
|
iconHeight: iconRect?.height ?? 0,
|
||||||
|
gapToIcon: iconRect ? iconRect.left - rect.right : null,
|
||||||
|
};
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight,
|
height: window.innerHeight,
|
||||||
@@ -278,6 +297,7 @@ async function collectMobileMetrics(page: Page) {
|
|||||||
stickyButtons.length === 2 ? Math.abs(stickyButtons[0].top - stickyButtons[1].top) <= 2 : stickyButtons.length <= 1,
|
stickyButtons.length === 2 ? Math.abs(stickyButtons[0].top - stickyButtons[1].top) <= 2 : stickyButtons.length <= 1,
|
||||||
stickyButtonMinHeight: stickyButtons.length ? Math.min(...stickyButtons.map((rect) => rect.height)) : 0,
|
stickyButtonMinHeight: stickyButtons.length ? Math.min(...stickyButtons.map((rect) => rect.height)) : 0,
|
||||||
stickyButtonMinWidth: stickyButtons.length ? Math.min(...stickyButtons.map((rect) => rect.width)) : 0,
|
stickyButtonMinWidth: stickyButtons.length ? Math.min(...stickyButtons.map((rect) => rect.width)) : 0,
|
||||||
|
actionLabels,
|
||||||
text: document.body?.innerText ?? "",
|
text: document.body?.innerText ?? "",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -314,6 +334,16 @@ test.describe("R5 真机反馈移动交互", () => {
|
|||||||
expect(homeMetrics.bottomNavBottomGap).not.toBeNull();
|
expect(homeMetrics.bottomNavBottomGap).not.toBeNull();
|
||||||
expect(homeMetrics.bottomNavBottomGap!).toBeLessThanOrEqual(2);
|
expect(homeMetrics.bottomNavBottomGap!).toBeLessThanOrEqual(2);
|
||||||
expect(homeMetrics.scrollWidth).toBeLessThanOrEqual(homeMetrics.width + 2);
|
expect(homeMetrics.scrollWidth).toBeLessThanOrEqual(homeMetrics.width + 2);
|
||||||
|
expect(homeMetrics.actionLabels.length).toBeGreaterThanOrEqual(4);
|
||||||
|
for (const label of homeMetrics.actionLabels) {
|
||||||
|
expect(label.whiteSpace, `${device.label} ${label.text} action label no wrap`).toBe("nowrap");
|
||||||
|
expect(label.height, `${device.label} ${label.text} action label single line`).toBeLessThanOrEqual(label.lineHeight + 2);
|
||||||
|
expect(label.width, `${device.label} ${label.text} action label readable width`).toBeGreaterThanOrEqual(40);
|
||||||
|
expect(label.iconWidth, `${device.label} ${label.text} action icon width`).toBeGreaterThanOrEqual(28);
|
||||||
|
expect(label.iconHeight, `${device.label} ${label.text} action icon height`).toBeGreaterThanOrEqual(28);
|
||||||
|
expect(label.gapToIcon, `${device.label} ${label.text} action label/icon spacing`).not.toBeNull();
|
||||||
|
expect(label.gapToIcon!, `${device.label} ${label.text} action label/icon spacing`).toBeGreaterThanOrEqual(6);
|
||||||
|
}
|
||||||
for (const item of homeMetrics.navItems) {
|
for (const item of homeMetrics.navItems) {
|
||||||
expect(item.visible, `${device.label} ${item.key} nav item visible`).toBe(true);
|
expect(item.visible, `${device.label} ${item.key} nav item visible`).toBe(true);
|
||||||
expect(item.width, `${device.label} ${item.key} nav item touch width`).toBeGreaterThanOrEqual(44);
|
expect(item.width, `${device.label} ${item.key} nav item touch width`).toBeGreaterThanOrEqual(44);
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户