表格工资相关

This commit is contained in:
zhx 2026-06-15 00:37:46 +08:00
parent 79da033dc9
commit aa7ce50e4f
7 changed files with 77 additions and 33 deletions

View File

@ -71,7 +71,6 @@ const historyColumns = [
export function SalaryWalletCell({ role, userId, userLabel, wallet }) {
const [open, setOpen] = useState(false);
const balance = Number(wallet?.availableAmount || 0);
const assetType = wallet?.assetType || salaryWalletAssetType(role);
return (
<>
@ -81,7 +80,6 @@ export function SalaryWalletCell({ role, userId, userLabel, wallet }) {
onClick={() => setOpen(true)}
>
<span className={styles.salaryWalletAmount}>{formatSalaryWalletAmount(balance)}</span>
<span className={styles.salaryWalletAsset}>{assetType || "-"}</span>
</button>
<SalaryWalletHistoryDrawer
open={open}
@ -163,10 +161,9 @@ export function SalaryWalletAdjustButton({ disabled = false, onAdjusted, role, u
onSubmit={submit}
>
<AdminFormSection title="目标身份">
<AdminFormFieldGrid columns="repeat(3, minmax(0, 1fr))">
<AdminFormFieldGrid columns="repeat(2, minmax(0, 1fr))">
<AdminFormReadOnlyField label="身份" value={salaryWalletRoleLabel(role)} />
<AdminFormReadOnlyField label="用户" value={userLabel || userId || "-"} />
<AdminFormReadOnlyField label="钱包" value={salaryWalletAssetType(role) || "-"} />
</AdminFormFieldGrid>
</AdminFormSection>
<AdminFormSection title="操作信息">
@ -260,7 +257,6 @@ function SalaryWalletHistoryDrawer({ onClose, open, role, userId, userLabel }) {
<div className={styles.salaryWalletSummary}>
<AccountBalanceWalletOutlined fontSize="small" />
<span>{salaryWalletRoleLabel(role)}</span>
<span>{salaryWalletAssetType(role) || "-"}</span>
</div>
<DataState error={error} loading={loading} onRetry={loadHistory}>
<DataTable
@ -317,21 +313,6 @@ function parseSalaryUSDMinor(value) {
return amountMinor;
}
function salaryWalletAssetType(role) {
switch (role) {
case "host":
return "HOST_SALARY_USD";
case "agency":
return "AGENCY_SALARY_USD";
case "bd":
return "BD_SALARY_USD";
case "bd_leader":
return "ADMIN_SALARY_USD";
default:
return "";
}
}
function salaryWalletRoleLabel(role) {
switch (role) {
case "host":

View File

@ -307,15 +307,6 @@
white-space: nowrap;
}
.salaryWalletAsset {
max-width: 100%;
overflow: hidden;
color: var(--text-tertiary);
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.salaryWalletDrawer.salaryWalletDrawer {
width: min(980px, calc(100vw - 32px));
}

View File

@ -80,6 +80,9 @@ export function DataTable({
);
const gridTemplate = preparedColumns.map((column) => column.width).join(" ");
const tableContentWidth = `${Math.ceil(
preparedColumns.reduce((total, column) => total + readMinWidth(column.width), 0)
)}px`;
const activeFilterColumn = preparedColumns.find((column) => column.key === filterMenu.columnKey && column.filter) || null;
const activeFilter = activeFilterColumn?.filter || null;
const activeFilterIsText = activeFilter?.type === "text";
@ -267,7 +270,11 @@ export function DataTable({
<div className="table-scroll" ref={scrollRef}>
<div
className={["admin-table", resizeSession ? "admin-table--resizing" : "", tableClassName].filter(Boolean).join(" ")}
style={{ "--admin-table-columns": gridTemplate, "--admin-table-min-width": minWidth }}
style={{
"--admin-table-columns": gridTemplate,
"--admin-table-content-width": tableContentWidth,
"--admin-table-min-width": minWidth
}}
>
<div className="admin-row admin-row--head">
{preparedColumns.map((column, index) => {

View File

@ -61,6 +61,22 @@ test("only shows the table filter reset action when filters are active", () => {
expect(screen.getByRole("button", { name: "重置筛选" })).toBeInTheDocument();
});
test("expands table background to the minimum width required by columns", () => {
const columns = [
{ key: "user", label: "用户", width: "minmax(220px, 1fr)" },
{ key: "createdAt", label: "创建时间", width: "minmax(180px, 1fr)" },
{ key: "actions", label: "操作" }
];
render(
<TimeZoneProvider>
<DataTable columns={columns} items={[{ createdAt: "2026-06-15", id: 1, user: "admin" }]} minWidth="300px" rowKey={(item) => item.id} />
</TimeZoneProvider>
);
expect(document.querySelector(".admin-table")?.style.getPropertyValue("--admin-table-content-width")).toBe("512px");
});
function TimezoneTableFixture() {
const { setTimeZone } = useTimeZone();
const columns = [

View File

@ -8,7 +8,7 @@ export function ToastProvider({ children }) {
const [toast, setToast] = useState(null);
const showToast = useCallback((message, severity = "info") => {
setToast({ message, severity });
setToast(normalizeToast(message, severity));
}, []);
const value = useMemo(() => ({ showToast }), [showToast]);
@ -39,3 +39,16 @@ export function useToast() {
}
return context;
}
function normalizeToast(message, severity) {
if (message && typeof message === "object") {
return {
message: String(message.message || "操作失败"),
severity: message.severity || severity || "info"
};
}
return {
message: String(message || "操作失败"),
severity: severity || "info"
};
}

View File

@ -0,0 +1,36 @@
import { fireEvent, render, screen } from "@testing-library/react";
import { expect, test } from "vitest";
import { ToastProvider, useToast } from "./ToastProvider.jsx";
function ToastTrigger({ payload, severity }) {
const { showToast } = useToast();
return (
<button type="button" onClick={() => showToast(payload, severity)}>
show
</button>
);
}
test("renders object-style toast payloads as text", () => {
render(
<ToastProvider>
<ToastTrigger payload={{ message: "工资结算失败", severity: "error" }} />
</ToastProvider>,
);
fireEvent.click(screen.getByRole("button", { name: "show" }));
expect(screen.getByText("工资结算失败")).toBeInTheDocument();
});
test("keeps tuple-style toast payloads working", () => {
render(
<ToastProvider>
<ToastTrigger payload="区域已更新" severity="success" />
</ToastProvider>,
);
fireEvent.click(screen.getByRole("button", { name: "show" }));
expect(screen.getByText("区域已更新")).toBeInTheDocument();
});

View File

@ -1546,9 +1546,9 @@
--admin-table-cell-x: var(--space-3);
display: flex;
flex-direction: column;
width: max(100%, var(--admin-table-min-width, 900px));
width: max(100%, var(--admin-table-min-width, 900px), var(--admin-table-content-width, 0px));
min-height: 100%;
min-width: max(100%, var(--admin-table-min-width, 900px));
min-width: max(100%, var(--admin-table-min-width, 900px), var(--admin-table-content-width, 0px));
}
.admin-row {