返回 AiToEarn
useDraftGenerationPricing.ts
根目录 / project / aitoearn-web / src / hooks / useDraftGenerationPricing.ts
1 /**
2 * useDraftGenerationPricing - AI 草稿生成定价数据 Hook
3 * 复用 ai/draft-generation/pricing 接口,提供模块级缓存与防重复请求
4 */
5
6 import type { DraftGenerationPricingVo } from '@/api/ai/ai.types'
7 import { useEffect, useState } from 'react'
8 import { apiGetDraftGenerationPricing } from '@/api/ai/ai.api'
9
10 interface DraftGenerationPricingCache {
11 data: DraftGenerationPricingVo | null
12 promise: Promise<DraftGenerationPricingVo | null> | null
13 }
14
15 const globalPricingCache = globalThis as typeof globalThis & {
16 __draftGenerationPricingCache?: DraftGenerationPricingCache
17 }
18
19 function normalizePricingData(data: DraftGenerationPricingVo): DraftGenerationPricingVo {
20 return {
21 ...data,
22 imageModels: (data.imageModels ?? []).map(model => ({
23 ...model,
24 pricing: model.pricing ?? [],
25 tags: model.tags ?? [],
26 })),
27 videoModels: (data.videoModels ?? []).map(model => ({
28 ...model,
29 modes: model.modes ?? [],
30 resolutions: model.resolutions ?? [],
31 durations: model.durations ?? [],
32 aspectRatios: model.aspectRatios ?? [],
33 tags: model.tags ?? [],
34 defaults: model.defaults ?? {},
35 pricing: model.pricing ?? [],
36 })),
37 }
38 }
39
40 function getPricingCache() {
41 if (!globalPricingCache.__draftGenerationPricingCache) {
42 globalPricingCache.__draftGenerationPricingCache = {
43 data: null,
44 promise: null,
45 }
46 }
47
48 return globalPricingCache.__draftGenerationPricingCache
49 }
50
51 async function fetchPricing(): Promise<DraftGenerationPricingVo | null> {
52 const cache = getPricingCache()
53 if (cache.data) {
54 return cache.data
55 }
56 if (cache.promise) {
57 return cache.promise
58 }
59
60 cache.promise = apiGetDraftGenerationPricing()
61 .then((res) => {
62 if (res?.data) {
63 cache.data = normalizePricingData(res.data)
64 return cache.data
65 }
66 return null
67 })
68 .catch(() => {
69 return null
70 })
71 .finally(() => {
72 cache.promise = null
73 })
74
75 return cache.promise
76 }
77
78 export function useDraftGenerationPricing() {
79 const [pricingData, setPricingData] = useState<DraftGenerationPricingVo | null>(() => getPricingCache().data)
80 const [isLoading, setIsLoading] = useState(() => !getPricingCache().data)
81 const [error, setError] = useState(false)
82
83 useEffect(() => {
84 const cache = getPricingCache()
85 if (cache.data) {
86 setPricingData(cache.data)
87 setIsLoading(false)
88 return
89 }
90
91 let cancelled = false
92 setIsLoading(true)
93
94 fetchPricing().then((data) => {
95 if (cancelled) {
96 return
97 }
98
99 if (data) {
100 setPricingData(data)
101 }
102 else {
103 setError(true)
104 }
105
106 setIsLoading(false)
107 })
108
109 return () => {
110 cancelled = true
111 }
112 }, [])
113
114 return { pricingData, isLoading, error }
115 }
116
116 lines TYPESCRIPT