feat(dashboard): useDashboardData composable(7接口并发+section级refresh)
This commit is contained in:
parent
a48b6fd8fb
commit
ea62b609af
120
frontend/composables/useDashboardData.js
Normal file
120
frontend/composables/useDashboardData.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { dashboardApi } from '@/utils/api'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据看板聚合 composable
|
||||||
|
* - 7 个接口并发(Promise.allSettled,单失败不阻塞)
|
||||||
|
* - 按 section 维度暴露 loading/error/data
|
||||||
|
* - 30 分钟内 refresh 不重发请求(lastFetched 缓存)
|
||||||
|
*
|
||||||
|
* @param {object} options
|
||||||
|
* @param {number|null} options.starId 顶粉星城 ID
|
||||||
|
*/
|
||||||
|
export function useDashboardData({ starId = null } = {}) {
|
||||||
|
const loading = ref({
|
||||||
|
overall: false,
|
||||||
|
today: false,
|
||||||
|
curve: false,
|
||||||
|
exhibition: false,
|
||||||
|
likeIncome: false,
|
||||||
|
topAssets: false,
|
||||||
|
levels: false,
|
||||||
|
upgrades: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const error = ref({
|
||||||
|
today: null,
|
||||||
|
curve: null,
|
||||||
|
exhibition: null,
|
||||||
|
likeIncome: null,
|
||||||
|
topAssets: null,
|
||||||
|
levels: null,
|
||||||
|
upgrades: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = ref({
|
||||||
|
today: null,
|
||||||
|
curve: null,
|
||||||
|
exhibition: null,
|
||||||
|
likeIncome: null,
|
||||||
|
topAssets: null,
|
||||||
|
levels: null,
|
||||||
|
upgrades: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
const lastFetched = ref(0)
|
||||||
|
const STALE_MS = 30 * 60 * 1000
|
||||||
|
|
||||||
|
const isReady = computed(() =>
|
||||||
|
Object.values(data.value).every((v) => v !== null && v !== undefined)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 内部辅助:单 section 加载,data 解包在 boundary 处进行
|
||||||
|
async function loadSection(section, fetcher) {
|
||||||
|
loading.value[section] = true
|
||||||
|
error.value[section] = null
|
||||||
|
try {
|
||||||
|
const result = await fetcher(starId)
|
||||||
|
data.value[section] = result?.data ?? result
|
||||||
|
} catch (e) {
|
||||||
|
error.value[section] = e?.message || '加载失败'
|
||||||
|
data.value[section] = null
|
||||||
|
} finally {
|
||||||
|
loading.value[section] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全量加载
|
||||||
|
async function loadAll(force = false) {
|
||||||
|
if (!force && Date.now() - lastFetched.value < STALE_MS) return
|
||||||
|
loading.value.overall = true
|
||||||
|
try {
|
||||||
|
await Promise.allSettled([
|
||||||
|
loadSection('today', dashboardApi.getTodayOverview),
|
||||||
|
loadSection('curve', dashboardApi.get7DayIncomeCurve),
|
||||||
|
loadSection('exhibition', dashboardApi.getExhibitionSummary),
|
||||||
|
loadSection('likeIncome', dashboardApi.getLikeIncomeByLevel),
|
||||||
|
loadSection('topAssets', dashboardApi.getTopAssets),
|
||||||
|
loadSection('levels', dashboardApi.getLevelDistribution),
|
||||||
|
loadSection('upgrades', dashboardApi.getUpgradeProgress),
|
||||||
|
])
|
||||||
|
lastFetched.value = Date.now()
|
||||||
|
} finally {
|
||||||
|
loading.value.overall = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 局部刷新:refresh('curve') 只刷一个;refresh() 全量 cache-aware;refresh(true) 全量强制
|
||||||
|
async function refresh(section, force = false) {
|
||||||
|
if (section) {
|
||||||
|
const fetcherMap = {
|
||||||
|
today: dashboardApi.getTodayOverview,
|
||||||
|
curve: dashboardApi.get7DayIncomeCurve,
|
||||||
|
exhibition: dashboardApi.getExhibitionSummary,
|
||||||
|
likeIncome: dashboardApi.getLikeIncomeByLevel,
|
||||||
|
topAssets: dashboardApi.getTopAssets,
|
||||||
|
levels: dashboardApi.getLevelDistribution,
|
||||||
|
upgrades: dashboardApi.getUpgradeProgress,
|
||||||
|
}
|
||||||
|
if (!fetcherMap[section]) return
|
||||||
|
return loadSection(section, fetcherMap[section])
|
||||||
|
}
|
||||||
|
return loadAll(force)
|
||||||
|
}
|
||||||
|
|
||||||
|
function dispose() {
|
||||||
|
// ref 状态由 Vue 自动 GC;保留接口给未来清理(如取消 in-flight 请求)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAll()
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
data,
|
||||||
|
refresh,
|
||||||
|
isReady,
|
||||||
|
lastFetched,
|
||||||
|
dispose,
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user