feat: 创作主题保存/加载 + 支付二维码过期提示
- ScriptCreation: 大类/小类 selection 持久化到 project meta - ProjectMeta: 新增 subcategoryCode 字段 - projectStore: 新增 setSubcategoryCode action - localStorage: orderedMeta 补全 categoryCode/subcategoryCode - RechargeModal: 过期后点击'我已支付'给出 toast 提示,按钮禁用并显示'二维码已过期'
This commit is contained in:
@@ -93,6 +93,8 @@ export const localProjectApi = {
|
||||
id: meta.id,
|
||||
title: meta.title,
|
||||
topic: meta.topic,
|
||||
categoryCode: meta.categoryCode,
|
||||
subcategoryCode: meta.subcategoryCode,
|
||||
status: meta.status,
|
||||
currentStep: meta.currentStep,
|
||||
createdAt: meta.createdAt,
|
||||
|
||||
@@ -179,10 +179,11 @@ export default function RechargeModal({
|
||||
const orderId = orderIdRef.current;
|
||||
if (!orderId) {return;}
|
||||
|
||||
// 二维码已过期,直接提示
|
||||
if (Date.now() >= expireAtRef.current) {
|
||||
// 二维码已过期,明确提示用户
|
||||
if (isExpired || Date.now() >= expireAtRef.current) {
|
||||
clearTimers();
|
||||
setIsExpired(true);
|
||||
toast.info('二维码已过期,请点击刷新二维码或重新下单');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -353,9 +354,9 @@ export default function RechargeModal({
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onClick={handleQueryPayment}
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || isExpired}
|
||||
>
|
||||
{isLoading ? '查询中...' : '我已支付'}
|
||||
{isLoading ? '查询中...' : isExpired ? '二维码已过期' : '我已支付'}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-ghost"
|
||||
|
||||
@@ -21,8 +21,11 @@ export default function ScriptCreation() {
|
||||
const segments = useProjectStore(state => state.segments);
|
||||
const setSegments = useProjectStore(state => state.setSegments);
|
||||
const updateSegment = useProjectStore(state => state.updateSegment);
|
||||
const categoryCode = useProjectStore(state => state.categoryCode);
|
||||
const subcategoryCode = useProjectStore(state => state.subcategoryCode);
|
||||
const setTopic = useProjectStore(state => state.setTopic);
|
||||
const setCategoryCode = useProjectStore(state => state.setCategoryCode);
|
||||
const setSubcategoryCode = useProjectStore(state => state.setSubcategoryCode);
|
||||
|
||||
const [generating, setGenerating] = useState(false);
|
||||
const requestLock = useRef(false);
|
||||
@@ -30,8 +33,8 @@ export default function ScriptCreation() {
|
||||
// 分类列表(从后端动态加载)
|
||||
const [categories, setCategories] = useState<CategoryItem[]>([]);
|
||||
// 选中的大类和小类
|
||||
const [selectedCategory, setSelectedCategory] = useState<string>('');
|
||||
const [selectedSubcategory, setSelectedSubcategory] = useState<string>('');
|
||||
const [selectedCategory, setSelectedCategory] = useState<string>(categoryCode || '');
|
||||
const [selectedSubcategory, setSelectedSubcategory] = useState<string>(subcategoryCode || '');
|
||||
|
||||
// 加载分类列表(带本地缓存 + 静默刷新)
|
||||
useEffect(() => {
|
||||
@@ -50,6 +53,22 @@ export default function ScriptCreation() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 分类列表加载后,恢复之前保存的选中状态
|
||||
useEffect(() => {
|
||||
if (categories.length === 0) {return;}
|
||||
if (categoryCode && subcategoryCode) {
|
||||
// 验证保存的 code 是否在当前分类列表中有效
|
||||
const catExists = categories.some(c => c.code === categoryCode);
|
||||
const subExists = categories.some(c =>
|
||||
c.code === categoryCode && c.subcategories.some(s => s.code === subcategoryCode)
|
||||
);
|
||||
if (catExists && subExists) {
|
||||
setSelectedCategory(categoryCode);
|
||||
setSelectedSubcategory(subcategoryCode);
|
||||
}
|
||||
}
|
||||
}, [categories, categoryCode, subcategoryCode]);
|
||||
|
||||
// 编辑状态:存储正在编辑的字段键(如 "1-scene", "2-voiceover")
|
||||
const [editingFields, setEditingFields] = useState<Set<string>>(new Set());
|
||||
|
||||
@@ -336,6 +355,7 @@ export default function ScriptCreation() {
|
||||
setSelectedSubcategory(sub.code);
|
||||
setTopic(sub.name);
|
||||
setCategoryCode(cat.code);
|
||||
setSubcategoryCode(sub.code);
|
||||
}}
|
||||
>
|
||||
{sub.name}
|
||||
|
||||
@@ -31,6 +31,7 @@ interface ProjectActions {
|
||||
setVoiceVolume: (_volume: number) => void;
|
||||
setVoicePitch: (_pitch: number) => void;
|
||||
setCategoryCode: (_code: string) => void;
|
||||
setSubcategoryCode: (_code: string) => void;
|
||||
setIsLoading: (_loading: boolean) => void;
|
||||
setHasHydrated: (_hydrated: boolean) => void;
|
||||
}
|
||||
@@ -231,6 +232,13 @@ export const useProjectStore = create<ProjectStore>()(
|
||||
});
|
||||
saveMetaToLocalFile({ categoryCode: code });
|
||||
},
|
||||
setSubcategoryCode: code => {
|
||||
set(state => {
|
||||
state.subcategoryCode = code;
|
||||
state.updatedAt = Date.now();
|
||||
});
|
||||
saveMetaToLocalFile({ subcategoryCode: code });
|
||||
},
|
||||
|
||||
}),
|
||||
{
|
||||
|
||||
@@ -82,6 +82,7 @@ export interface ProjectMeta {
|
||||
// === 创作参数 ===
|
||||
topic?: string;
|
||||
categoryCode?: string;
|
||||
subcategoryCode?: string;
|
||||
|
||||
// === 素材选择 ===
|
||||
selectedVoiceId?: string;
|
||||
|
||||
@@ -140,6 +140,7 @@ export function migrateMeta(raw: unknown): Partial<ProjectMeta> {
|
||||
export const BLANK_META_OVERRIDES: MetaOverrides = {
|
||||
topic: undefined,
|
||||
categoryCode: undefined,
|
||||
subcategoryCode: undefined,
|
||||
selectedVoiceId: undefined,
|
||||
finalVideoPath: undefined,
|
||||
coverPath: undefined,
|
||||
|
||||
Reference in New Issue
Block a user