合并主分支

解决合并冲突
This commit is contained in:
2026-08-08 10:47:31 +08:00
140 changed files with 11920 additions and 2046 deletions
@@ -23,7 +23,7 @@ import {
loadEditorProject,
} from '../../services/image-editor/editorProjectClient';
import { shouldShowRechargeEntry } from '../../services/payment/paymentPlatform';
import { getPlatformProfileDashboard } from '../../services/platform-entry/platformProfileClient';
import { usePlatformWalletStore } from '../../stores/usePlatformWalletStore';
import { useAuthUi } from '../auth/AuthUiContext';
import { PlatformDangerConfirmDialog } from '../common/PlatformDangerConfirmDialog';
import { PlatformProfileRewardCodeRedeemModal } from '../platform-entry/PlatformProfileRewardCodeRedeemModal';
@@ -126,7 +126,8 @@ type CanvasStartupTool =
| 'ui-design'
| 'background-music'
| 'image'
| 'publication-cover';
| 'publication-cover'
| 'scene';
const CANVAS_STARTUP_TOOLS: CanvasStartupTool[] = [
'character-spec',
@@ -135,9 +136,11 @@ const CANVAS_STARTUP_TOOLS: CanvasStartupTool[] = [
'background-music',
'image',
'publication-cover',
'scene',
];
type ImageCanvasEditorViewProps = {
legacyWalletBalance?: number | null;
onProjectAccessLost?: () => void;
};
@@ -192,6 +195,10 @@ function openCanvasStartupTool(
generationSurface.openBackgroundMusicGenerationDialog();
return;
}
if (tool === 'scene') {
generationSurface.openSceneGenerationDialog();
return;
}
if (tool === 'publication-cover') {
generationSurface.openPublicationGenerationDialog(
'publication-cover-image',
@@ -321,12 +328,50 @@ const DEAD_INLINE_PLACEHOLDER_NOTICE =
'上次的完美像素处理未完成,画布占位已清理。请确认素材库是否已生成派生图。';
export function ImageCanvasEditorView({
legacyWalletBalance = null,
onProjectAccessLost,
}: ImageCanvasEditorViewProps = {}) {
const authUi = useAuthUi();
const [, setGenerationPricingVersion] = useState(0);
const [walletBalance, setWalletBalance] = useState<number | null>(null);
const [isWalletBalanceLoading, setIsWalletBalanceLoading] = useState(false);
const walletOwnerUserId = usePlatformWalletStore(
(state) => state.ownerUserId,
);
const storedMudPointBalance = usePlatformWalletStore(
(state) => state.mudPointBalance,
);
const storedLegacyWalletBalance = usePlatformWalletStore(
(state) => state.legacyWalletBalance,
);
const storedMudPointBalanceStatus = usePlatformWalletStore(
(state) => state.mudPointBalanceStatus,
);
const storedMudPointBalanceError = usePlatformWalletStore(
(state) => state.mudPointBalanceError,
);
const onWalletBalanceMayHaveChanged = usePlatformWalletStore(
(state) => state.onWalletBalanceMayHaveChanged,
);
const currentWalletOwnerUserId =
authUi?.canAccessProtectedData && authUi.user?.id ? authUi.user.id : null;
const walletOwnerMatchesCurrentUser =
Boolean(currentWalletOwnerUserId) &&
walletOwnerUserId === currentWalletOwnerUserId;
const mudPointBalance = walletOwnerMatchesCurrentUser
? storedMudPointBalance
: null;
const mudPointBalanceError = walletOwnerMatchesCurrentUser
? storedMudPointBalanceError
: '';
const walletBalance =
mudPointBalance?.totalPoints ??
(walletOwnerMatchesCurrentUser
? (storedLegacyWalletBalance ?? legacyWalletBalance)
: null);
const isWalletBalanceLoading =
Boolean(currentWalletOwnerUserId) &&
(!walletOwnerMatchesCurrentUser ||
storedMudPointBalanceStatus === 'idle' ||
storedMudPointBalanceStatus === 'loading');
const editorRootRef = useRef<HTMLElement | null>(null);
const canvasViewportRef = useRef<HTMLDivElement | null>(null);
const assetListRef = useRef<HTMLDivElement | null>(null);
@@ -509,21 +554,6 @@ export function ImageCanvasEditorView({
},
[],
);
const refreshEditorWalletBalance = useCallback(() => {
if (!authUiRef.current?.canAccessProtectedData || !authUiRef.current.user) {
return;
}
void getPlatformProfileDashboard({
authImpact: 'local',
skipRefresh: true,
notifyAuthStateChange: false,
clearAuthOnUnauthorized: false,
})
.then((dashboard) => {
setWalletBalance(dashboard.walletBalance);
})
.catch(() => undefined);
}, []);
const {
buyRechargeProduct,
closeNativeWechatPayment,
@@ -559,7 +589,6 @@ export function ImageCanvasEditorView({
activeTab: 'editor-canvas',
isAuthenticated: Boolean(authUi?.user),
showRechargeEntry,
onRechargeSuccess: refreshEditorWalletBalance,
requestLogin: () => authUiRef.current?.openLoginModal(),
currentUser: authUi?.user ?? null,
});
@@ -567,9 +596,8 @@ export function ImageCanvasEditorView({
if (!authUiRef.current?.canAccessProtectedData || !authUiRef.current.user) {
return;
}
refreshEditorWalletBalance();
loadRechargeCenter();
}, [loadRechargeCenter, refreshEditorWalletBalance]);
void onWalletBalanceMayHaveChanged();
}, [onWalletBalanceMayHaveChanged]);
const isAccountPaymentModalOpen =
isRewardCodeOpen ||
isRechargeOpen ||
@@ -591,66 +619,6 @@ export function ImageCanvasEditorView({
window.location.reload();
});
}, [authUi]);
useEffect(() => {
if (!authUi?.canAccessProtectedData || !authUi.user?.id) {
setWalletBalance(null);
setIsWalletBalanceLoading(false);
return;
}
let isMounted = true;
let requestId = 0;
const refreshWalletBalance = () => {
const currentRequestId = requestId + 1;
requestId = currentRequestId;
setIsWalletBalanceLoading(true);
void getPlatformProfileDashboard({
authImpact: 'local',
skipRefresh: true,
notifyAuthStateChange: false,
clearAuthOnUnauthorized: false,
})
.then((dashboard) => {
if (!isMounted || currentRequestId !== requestId) {
return;
}
setWalletBalance(dashboard.walletBalance);
})
.catch(() => {
if (!isMounted || currentRequestId !== requestId) {
return;
}
setWalletBalance(null);
})
.finally(() => {
if (!isMounted || currentRequestId !== requestId) {
return;
}
setIsWalletBalanceLoading(false);
});
};
refreshWalletBalance();
const handleWindowFocus = () => {
refreshWalletBalance();
};
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
refreshWalletBalance();
}
};
window.addEventListener('focus', handleWindowFocus);
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
isMounted = false;
window.removeEventListener('focus', handleWindowFocus);
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, [authUi?.canAccessProtectedData, authUi?.user?.id]);
const {
projectTitle,
setProjectTitle,
@@ -1083,8 +1051,10 @@ export function ImageCanvasEditorView({
layer.assetKind === 'character-animation' &&
(persistedAssetKind !== 'character-animation' ||
(asset.imageSequenceFrames?.length ?? 0) < 2 ||
!(asset.imageSequenceDurationMs &&
asset.imageSequenceDurationMs > 0))
!(
asset.imageSequenceDurationMs &&
asset.imageSequenceDurationMs > 0
))
) {
throw new Error('服务器未返回完整的角色动作正式字段');
}
@@ -1515,9 +1485,8 @@ export function ImageCanvasEditorView({
if (warning) {
showGenerationWarning(warning);
}
refreshEditorWalletState();
},
[projectId, refreshEditorWalletState, showGenerationWarning],
[projectId, showGenerationWarning],
);
const effectiveIsAgentConversationOpen =
isAgentConversationEnabled && isAgentConversationOpen;
@@ -2516,10 +2485,10 @@ export function ImageCanvasEditorView({
projectRenameError,
layers,
walletBalance,
walletBreakdown: rechargeCenter?.mudPointBalance ?? null,
walletBreakdown: mudPointBalance,
isWalletBalanceLoading,
isWalletDetailsLoading: isLoadingRechargeCenter,
walletDetailsError: rechargeError,
walletDetailsError: rechargeError || mudPointBalanceError || null,
currentUser: authUi?.user,
assetExportStatus,
isExportingAssets,
@@ -2627,6 +2596,7 @@ export function ImageCanvasEditorView({
onActivateGenerationDialog: activateCanvasGenerationDialog,
onFocusExternalTask: focusExternalGenerationTask,
onExternalTasksCompleted: handleExternalGenerationTasksCompleted,
onExternalTaskWalletMayHaveChanged: refreshEditorWalletState,
onEditorAgentConfirmSent: handleEditorAgentConfirmSent,
onToggleTaskSidebar: toggleTaskSidebar,
onToggleAgentConversation: toggleAgentConversation,