Codex/generation task reliability #20
@@ -19,10 +19,10 @@ import { ossAssets } from "../data/ossAssets";
|
|||||||
import { canManageCommunityCases, canReviewCommunity } from "../features/community-review/communityPermissions";
|
import { canManageCommunityCases, canReviewCommunity } from "../features/community-review/communityPermissions";
|
||||||
import type { WebNavItem, WebNotification, WebUsageSummary, WebUserSession, WebViewKey } from "../types";
|
import type { WebNavItem, WebNotification, WebUsageSummary, WebUserSession, WebViewKey } from "../types";
|
||||||
import NotificationCenter from "./NotificationCenter";
|
import NotificationCenter from "./NotificationCenter";
|
||||||
import { RechargeModal } from "./RechargeModal/RechargeModal";
|
|
||||||
import { AnimatedPanel } from "./AnimatedPanel";
|
import { AnimatedPanel } from "./AnimatedPanel";
|
||||||
import AdminMonitor from "./AdminMonitor";
|
import AdminMonitor from "./AdminMonitor";
|
||||||
import CookieConsentBanner from "./CookieConsentBanner";
|
import CookieConsentBanner from "./CookieConsentBanner";
|
||||||
|
import { loadRechargeModal, type RechargeModalComponent } from "./RechargeModal/loadRechargeModal";
|
||||||
|
|
||||||
interface AppShellProps {
|
interface AppShellProps {
|
||||||
activeView: WebViewKey;
|
activeView: WebViewKey;
|
||||||
@@ -93,6 +93,7 @@ function AppShell({
|
|||||||
const submenuHideTimerRef = useRef<number | null>(null);
|
const submenuHideTimerRef = useRef<number | null>(null);
|
||||||
const [profileOpen, setProfileOpen] = useState(false);
|
const [profileOpen, setProfileOpen] = useState(false);
|
||||||
const [rechargeOpen, setRechargeOpen] = useState(false);
|
const [rechargeOpen, setRechargeOpen] = useState(false);
|
||||||
|
const [RechargeModal, setRechargeModal] = useState<RechargeModalComponent | null>(null);
|
||||||
const [infoOpen, setInfoOpen] = useState(false);
|
const [infoOpen, setInfoOpen] = useState(false);
|
||||||
const infoRef = useRef<HTMLDivElement>(null);
|
const infoRef = useRef<HTMLDivElement>(null);
|
||||||
const [openSubmenuKey, setOpenSubmenuKey] = useState<WebViewKey | null>(null);
|
const [openSubmenuKey, setOpenSubmenuKey] = useState<WebViewKey | null>(null);
|
||||||
@@ -192,6 +193,21 @@ function AppShell({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!rechargeOpen || RechargeModal) return;
|
||||||
|
|
||||||
|
let cancelled = false;
|
||||||
|
void loadRechargeModal().then((component) => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setRechargeModal(() => component);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [RechargeModal, rechargeOpen]);
|
||||||
|
|
||||||
const showSubmenu = (key: WebViewKey) => {
|
const showSubmenu = (key: WebViewKey) => {
|
||||||
if (submenuHideTimerRef.current) {
|
if (submenuHideTimerRef.current) {
|
||||||
window.clearTimeout(submenuHideTimerRef.current);
|
window.clearTimeout(submenuHideTimerRef.current);
|
||||||
@@ -491,7 +507,9 @@ function AppShell({
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
{session?.user.role === "admin" ? <AdminMonitor /> : null}
|
{session?.user.role === "admin" ? <AdminMonitor /> : null}
|
||||||
|
{rechargeOpen && RechargeModal ? (
|
||||||
<RechargeModal open={rechargeOpen} onClose={() => setRechargeOpen(false)} currentBalance={displayedBalanceCents} />
|
<RechargeModal open={rechargeOpen} onClose={() => setRechargeOpen(false)} currentBalance={displayedBalanceCents} />
|
||||||
|
) : null}
|
||||||
<CookieConsentBanner />
|
<CookieConsentBanner />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { CheckCircleOutlined, CloseOutlined, CrownOutlined, RocketOutlined } from "@ant-design/icons";
|
import { CheckCircleOutlined, CloseOutlined, CrownOutlined, RocketOutlined } from "@ant-design/icons";
|
||||||
import { useMemo, useState, type ReactNode } from "react";
|
import { useMemo, useState, type ReactNode } from "react";
|
||||||
|
import "../../styles/components/recharge-modal.css";
|
||||||
import { keyServerClient, type RechargeOrderResult } from "../../api/keyServerClient";
|
import { keyServerClient, type RechargeOrderResult } from "../../api/keyServerClient";
|
||||||
import { toast } from "../toast/toastStore";
|
import { toast } from "../toast/toastStore";
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ const paymentMethods: Array<{ id: PaymentMethod; label: string; hint: string }>
|
|||||||
{ id: "bank", label: "对公转账", hint: "企业客户可联系客服确认" },
|
{ id: "bank", label: "对公转账", hint: "企业客户可联系客服确认" },
|
||||||
];
|
];
|
||||||
|
|
||||||
interface RechargeModalProps {
|
export interface RechargeModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
currentBalance?: number;
|
currentBalance?: number;
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import type { ComponentType } from "react";
|
||||||
|
import type { RechargeModalProps } from "./RechargeModal";
|
||||||
|
|
||||||
|
export type RechargeModalComponent = ComponentType<RechargeModalProps>;
|
||||||
|
|
||||||
|
let rechargeModalPromise: Promise<RechargeModalComponent> | null = null;
|
||||||
|
|
||||||
|
export function loadRechargeModal(): Promise<RechargeModalComponent> {
|
||||||
|
if (!rechargeModalPromise) {
|
||||||
|
rechargeModalPromise = import("./RechargeModal").then((module) => module.RechargeModal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rechargeModalPromise;
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ import { claimGenerationSlot, getActiveGenerationTaskCount, getGenerationUserKey
|
|||||||
import { preUploadReference, resolvePreUploadedUrl } from "../../api/referenceUploadService";
|
import { preUploadReference, resolvePreUploadedUrl } from "../../api/referenceUploadService";
|
||||||
import { assetClient } from "../../api/assetClient";
|
import { assetClient } from "../../api/assetClient";
|
||||||
import { communityClient } from "../../api/communityClient";
|
import { communityClient } from "../../api/communityClient";
|
||||||
import { RechargeModal } from "../../components/RechargeModal/RechargeModal";
|
import { loadRechargeModal, type RechargeModalComponent } from "../../components/RechargeModal/loadRechargeModal";
|
||||||
import { useGenerationTasks } from "../../hooks/useGenerationTasks";
|
import { useGenerationTasks } from "../../hooks/useGenerationTasks";
|
||||||
|
|
||||||
import { conversationClient, type ConversationSummary } from "../../api/conversationClient";
|
import { conversationClient, type ConversationSummary } from "../../api/conversationClient";
|
||||||
@@ -268,6 +268,7 @@ function WorkbenchPage({
|
|||||||
const [isGenerating, setIsGenerating] = useState(false);
|
const [isGenerating, setIsGenerating] = useState(false);
|
||||||
const [generationStatus, setGenerationStatus] = useState("准备就绪");
|
const [generationStatus, setGenerationStatus] = useState("准备就绪");
|
||||||
const [showRechargeModal, setShowRechargeModal] = useState(false);
|
const [showRechargeModal, setShowRechargeModal] = useState(false);
|
||||||
|
const [RechargeModal, setRechargeModal] = useState<RechargeModalComponent | null>(null);
|
||||||
const [savedAssetMentionItems, setSavedAssetMentionItems] = useState<
|
const [savedAssetMentionItems, setSavedAssetMentionItems] = useState<
|
||||||
Pick<ReferenceItem, "id" | "kind" | "name" | "previewUrl" | "remoteUrl" | "token">[]
|
Pick<ReferenceItem, "id" | "kind" | "name" | "previewUrl" | "remoteUrl" | "token">[]
|
||||||
>([]);
|
>([]);
|
||||||
@@ -291,6 +292,21 @@ function WorkbenchPage({
|
|||||||
activeConversationIdRef.current = activeConversationId;
|
activeConversationIdRef.current = activeConversationId;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!showRechargeModal || RechargeModal) return;
|
||||||
|
|
||||||
|
let cancelled = false;
|
||||||
|
void loadRechargeModal().then((component) => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setRechargeModal(() => component);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [RechargeModal, showRechargeModal]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isAuthenticated) return;
|
if (!isAuthenticated) return;
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
@@ -3191,7 +3207,9 @@ function WorkbenchPage({
|
|||||||
|
|
||||||
{renderMessagePreviewOverlay()}
|
{renderMessagePreviewOverlay()}
|
||||||
{renderDeleteDialog()}
|
{renderDeleteDialog()}
|
||||||
|
{showRechargeModal && RechargeModal ? (
|
||||||
<RechargeModal open={showRechargeModal} onClose={() => setShowRechargeModal(false)} currentBalance={session?.user?.balanceCents} />
|
<RechargeModal open={showRechargeModal} onClose={() => setShowRechargeModal(false)} currentBalance={session?.user?.balanceCents} />
|
||||||
|
) : null}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
@import "./shell/app-shell.css";
|
@import "./shell/app-shell.css";
|
||||||
@import "./components/primitives.css";
|
@import "./components/primitives.css";
|
||||||
@import "./components/legacy-components.css";
|
@import "./components/legacy-components.css";
|
||||||
@import "./components/recharge-modal.css";
|
|
||||||
@import "./components/toast.css";
|
@import "./components/toast.css";
|
||||||
@import "./components/page-transition.css";
|
@import "./components/page-transition.css";
|
||||||
@import "./components/motion.css";
|
@import "./components/motion.css";
|
||||||
|
|||||||
Reference in New Issue
Block a user