合并主分支
同步主分支资源卡依赖关系与类型分类预览等最新变更 保留并补齐画布快速编辑前后端正向白名单 拒绝图片编辑接口处理单个图标、角色动作、音频、视频及未知类型 修正快速编辑决策记录与现行编辑器文档 补充后端现役类型和未知类型表驱动测试
This commit is contained in:
@@ -538,6 +538,9 @@ export function ImageCanvasEditorView({
|
||||
currentUser: authUi?.user ?? null,
|
||||
});
|
||||
const refreshEditorWalletState = useCallback(() => {
|
||||
if (!authUiRef.current?.canAccessProtectedData || !authUiRef.current.user) {
|
||||
return;
|
||||
}
|
||||
refreshEditorWalletBalance();
|
||||
loadRechargeCenter();
|
||||
}, [loadRechargeCenter, refreshEditorWalletBalance]);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import type { ProfileRechargeCenterResponse } from '../../../packages/shared/src/contracts/runtime';
|
||||
import { usePlatformProfileCenterController } from './usePlatformProfileCenterController';
|
||||
|
||||
const getPlatformProfileRechargeCenterMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('../../services/platform-entry/platformProfileClient', async () => {
|
||||
const actual = await vi.importActual<
|
||||
typeof import('../../services/platform-entry/platformProfileClient')
|
||||
>('../../services/platform-entry/platformProfileClient');
|
||||
return {
|
||||
...actual,
|
||||
getPlatformProfileRechargeCenter: getPlatformProfileRechargeCenterMock,
|
||||
};
|
||||
});
|
||||
|
||||
const rechargeCenter: ProfileRechargeCenterResponse = {
|
||||
walletBalance: 100,
|
||||
mudPointBalance: {
|
||||
totalPoints: 100,
|
||||
permanentPoints: 100,
|
||||
limitedPoints: 0,
|
||||
limitedExpiresAt: null,
|
||||
dailyFreePoints: 0,
|
||||
dailyFreeResetPoints: 0,
|
||||
dailyFreeResetsAt: null,
|
||||
},
|
||||
membership: {
|
||||
status: 'normal',
|
||||
tier: 'normal',
|
||||
startedAt: null,
|
||||
expiresAt: null,
|
||||
updatedAt: null,
|
||||
cycleStartedAt: null,
|
||||
cycleResetsAt: null,
|
||||
cycleGrantedPoints: 0,
|
||||
cycleRemainingPoints: 0,
|
||||
cyclePeriodDays: 30,
|
||||
},
|
||||
pointProducts: [],
|
||||
membershipProducts: [],
|
||||
benefits: [],
|
||||
latestOrder: null,
|
||||
hasPointsRecharged: false,
|
||||
};
|
||||
|
||||
describe('usePlatformProfileCenterController', () => {
|
||||
afterEach(() => {
|
||||
getPlatformProfileRechargeCenterMock.mockReset();
|
||||
});
|
||||
|
||||
it('aborts an unfinished recharge center read when the consumer unmounts', async () => {
|
||||
let resolveRechargeCenter!: (center: ProfileRechargeCenterResponse) => void;
|
||||
const pendingRead = new Promise<ProfileRechargeCenterResponse>((resolve) => {
|
||||
resolveRechargeCenter = resolve;
|
||||
});
|
||||
getPlatformProfileRechargeCenterMock.mockReturnValue(pendingRead);
|
||||
const { result, unmount } = renderHook(() =>
|
||||
usePlatformProfileCenterController({
|
||||
activeTab: 'editor-canvas',
|
||||
isAuthenticated: false,
|
||||
showRechargeEntry: true,
|
||||
requestLogin: vi.fn(),
|
||||
currentUser: null,
|
||||
}),
|
||||
);
|
||||
|
||||
act(() => result.current.loadRechargeCenter());
|
||||
const requestOptions = getPlatformProfileRechargeCenterMock.mock.calls[0]?.[0];
|
||||
expect(requestOptions?.signal.aborted).toBe(false);
|
||||
|
||||
unmount();
|
||||
expect(requestOptions?.signal.aborted).toBe(true);
|
||||
|
||||
resolveRechargeCenter(rechargeCenter);
|
||||
await pendingRead;
|
||||
});
|
||||
});
|
||||
@@ -354,6 +354,16 @@ export function usePlatformProfileCenterController({
|
||||
const pendingWechatRechargeOrderIdRef = useRef<string | null>(null);
|
||||
const confirmingWechatRechargeOrderIdRef = useRef<string | null>(null);
|
||||
const rechargeCenterReadRevisionRef = useRef(0);
|
||||
const rechargeCenterReadAbortControllerRef =
|
||||
useRef<AbortController | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
rechargeCenterReadRevisionRef.current += 1;
|
||||
rechargeCenterReadAbortControllerRef.current?.abort();
|
||||
rechargeCenterReadAbortControllerRef.current = null;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 中文注释:支持带邀请码 query 的直达场景,登录成功后自动打开兑换面板并复用同一套输入状态。
|
||||
useEffect(() => {
|
||||
@@ -398,6 +408,8 @@ export function usePlatformProfileCenterController({
|
||||
const applyRechargeCenter = useCallback(
|
||||
(center: ProfileRechargeCenterResponse) => {
|
||||
rechargeCenterReadRevisionRef.current += 1;
|
||||
rechargeCenterReadAbortControllerRef.current?.abort();
|
||||
rechargeCenterReadAbortControllerRef.current = null;
|
||||
setIsLoadingRechargeCenter(false);
|
||||
setRechargeError(null);
|
||||
setRechargeCenter(center);
|
||||
@@ -407,16 +419,25 @@ export function usePlatformProfileCenterController({
|
||||
|
||||
const loadRechargeCenter = useCallback(() => {
|
||||
const revision = ++rechargeCenterReadRevisionRef.current;
|
||||
rechargeCenterReadAbortControllerRef.current?.abort();
|
||||
const abortController = new AbortController();
|
||||
rechargeCenterReadAbortControllerRef.current = abortController;
|
||||
setRechargeError(null);
|
||||
setIsLoadingRechargeCenter(true);
|
||||
void getPlatformProfileRechargeCenter()
|
||||
void getPlatformProfileRechargeCenter({ signal: abortController.signal })
|
||||
.then((center) => {
|
||||
if (revision === rechargeCenterReadRevisionRef.current) {
|
||||
if (
|
||||
!abortController.signal.aborted &&
|
||||
revision === rechargeCenterReadRevisionRef.current
|
||||
) {
|
||||
setRechargeCenter(center);
|
||||
}
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
if (revision !== rechargeCenterReadRevisionRef.current) {
|
||||
if (
|
||||
abortController.signal.aborted ||
|
||||
revision !== rechargeCenterReadRevisionRef.current
|
||||
) {
|
||||
return;
|
||||
}
|
||||
setRechargeCenter(null);
|
||||
@@ -425,6 +446,9 @@ export function usePlatformProfileCenterController({
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
if (rechargeCenterReadAbortControllerRef.current === abortController) {
|
||||
rechargeCenterReadAbortControllerRef.current = null;
|
||||
}
|
||||
if (revision === rechargeCenterReadRevisionRef.current) {
|
||||
setIsLoadingRechargeCenter(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user