feat: 创作主题保存/加载 + 支付二维码过期提示

- ScriptCreation: 大类/小类 selection 持久化到 project meta
- ProjectMeta: 新增 subcategoryCode 字段
- projectStore: 新增 setSubcategoryCode action
- localStorage: orderedMeta 补全 categoryCode/subcategoryCode
- RechargeModal: 过期后点击'我已支付'给出 toast 提示,按钮禁用并显示'二维码已过期'
This commit is contained in:
小鱼开发
2026-05-17 20:48:57 +08:00
parent 43e736c32d
commit aff4ca59ab
6 changed files with 39 additions and 6 deletions
@@ -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}
+8
View File
@@ -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 });
},
}),
{
+1
View File
@@ -82,6 +82,7 @@ export interface ProjectMeta {
// === 创作参数 ===
topic?: string;
categoryCode?: string;
subcategoryCode?: string;
// === 素材选择 ===
selectedVoiceId?: string;
+1
View File
@@ -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,