修改交互

This commit is contained in:
zhx 2026-07-17 19:39:15 +08:00
parent 42e9eb0804
commit e915a16cb3
3 changed files with 55 additions and 2 deletions

View File

@ -520,8 +520,8 @@ export function OpsCenterApp({ can = denyPermission }) {
<UserProfilesView
apps={data.apps}
defaultAppCode={defaultAppCode}
key={profileRefreshKey}
poolIDsByApp={poolIDsByApp}
refreshKey={profileRefreshKey}
/>
</Suspense>
) : null}

View File

@ -9,6 +9,8 @@ import {
fetchLuckyGiftDraws,
fetchLuckyGiftConfigVersions,
fetchLuckyGiftExperiments,
fetchLuckyGiftUserProfile,
fetchLuckyGiftUserProfiles,
fetchOpsDashboard,
rollbackLuckyGiftConfig,
saveLuckyGiftConfig,
@ -25,6 +27,8 @@ vi.mock("./api.js", () => ({
fetchLuckyGiftDraws: vi.fn(),
fetchLuckyGiftConfigVersions: vi.fn(),
fetchLuckyGiftExperiments: vi.fn(),
fetchLuckyGiftUserProfile: vi.fn(),
fetchLuckyGiftUserProfiles: vi.fn(),
fetchOpsDashboard: vi.fn(),
luckyGiftPoolKey: (item = {}) =>
`${item.app_code || item.appCode}:${item.pool_id || item.poolId}:${item.strategy_version || item.strategyVersion || "fixed_v2"}`,
@ -83,6 +87,16 @@ beforeEach(() => {
pageSize: 20,
total: 1,
});
fetchLuckyGiftUserProfile.mockResolvedValue({});
fetchLuckyGiftUserProfiles.mockResolvedValue({
hasMore: false,
items: [],
nextCursor: "",
page: 1,
pageSize: 20,
snapshotAtMs: 1767000000000,
total: 0,
});
fetchOpsDashboard.mockResolvedValue({
experiments: [mockRunningExperiment()],
giftHostDiamondRatiosByApp: {
@ -297,6 +311,34 @@ test("opens the requested config view from the legacy admin document redirect",
expect(screen.getAllByText("lucky").length).toBeGreaterThan(0);
});
test("refreshes user profiles with the active filters instead of resetting the view", async () => {
renderApp();
await screen.findByText("运营应用");
fireEvent.click(screen.getByRole("button", { name: /用户画像/ }));
await waitFor(() => expect(fetchLuckyGiftUserProfiles).toHaveBeenCalledTimes(1));
fireEvent.mouseDown(screen.getByLabelText("用户来源"));
fireEvent.click(await screen.findByRole("option", { name: "内部用户" }));
const keywordInput = screen.getByPlaceholderText("短号 / 长号 / 靓号");
fireEvent.change(keywordInput, { target: { value: "163001" } });
fireEvent.click(screen.getByRole("button", { name: "查询" }));
await waitFor(() =>
expect(fetchLuckyGiftUserProfiles).toHaveBeenLastCalledWith(
expect.objectContaining({ identityType: "internal", keyword: "163001" }),
),
);
const requestCountBeforeRefresh = fetchLuckyGiftUserProfiles.mock.calls.length;
fireEvent.click(screen.getByRole("button", { name: "刷新" }));
await waitFor(() => expect(fetchLuckyGiftUserProfiles).toHaveBeenCalledTimes(requestCountBeforeRefresh + 1));
expect(fetchLuckyGiftUserProfiles).toHaveBeenLastCalledWith(
expect.objectContaining({ identityType: "internal", keyword: "163001", page: 1 }),
);
expect(screen.getByLabelText("用户来源")).toHaveTextContent("内部用户");
expect(keywordInput).toHaveValue("163001");
});
test("lists every pool config including published non-default pools", async () => {
renderApp();
await screen.findByText("运营应用");

View File

@ -44,7 +44,7 @@ const SORT_DIRECTION_OPTIONS = [
["asc", "从低到高 / 从旧到新"],
];
export function UserProfilesView({ apps, defaultAppCode, poolIDsByApp }) {
export function UserProfilesView({ apps, defaultAppCode, poolIDsByApp, refreshKey = 0 }) {
const [appCode, setAppCode] = useState(defaultAppCode);
const [poolId, setPoolId] = useState("");
const [identityType, setIdentityType] = useState("all");
@ -58,6 +58,7 @@ export function UserProfilesView({ apps, defaultAppCode, poolIDsByApp }) {
const [reloadKey, setReloadKey] = useState(0);
const [expandedKey, setExpandedKey] = useState("");
const [details, setDetails] = useState({});
const handledRefreshKey = useRef(refreshKey);
// DataTable 使 owner cursor
// OFFSET
const cursorsByPage = useRef({ 1: "" });
@ -167,6 +168,16 @@ export function UserProfilesView({ apps, defaultAppCode, poolIDsByApp }) {
setReloadKey((current) => current + 1);
}, []);
useEffect(() => {
if (handledRefreshKey.current === refreshKey) {
return;
}
handledRefreshKey.current = refreshKey;
//
// React key
reloadProfiles();
}, [refreshKey, reloadProfiles]);
const changeAppCode = useCallback(
(nextAppCode) => {
setAppCode(nextAppCode);