fix: implement resource reconciliation and update handling in media supply favorites
Frontend CI / Frontend (push) Successful in 2m55s
Backend CI / Backend (push) Failing after 8m41s

This commit is contained in:
2026-06-23 23:34:45 +08:00
parent 04bd3e42e0
commit a406971187
6 changed files with 167 additions and 14 deletions
@@ -163,6 +163,33 @@ export function mergeMediaSupplyFavoriteResourceSnapshots(
})
}
export function reconcileMediaSupplyFavoriteResources(
groups: MediaSupplyFavoriteGroup[],
resources: MediaSupplyFavoriteResourceInput[],
): MediaSupplyFavoriteGroup[] {
const snapshots = resources
.map((resource) => normalizeResourceSnapshot(resource))
.filter((resource): resource is MediaSupplyFavoriteResourceSnapshot => Boolean(resource))
const snapshotById = new Map(snapshots.map((resource) => [resource.id, resource]))
const now = new Date().toISOString()
return (groups.length > 0 ? groups : [defaultGroup()]).map((group) => {
const resourceIds = group.resourceIds.filter((resourceId) => snapshotById.has(resourceId))
const changed =
resourceIds.length !== group.resourceIds.length ||
resourceIds.some((resourceId, index) => resourceId !== group.resourceIds[index])
return {
...group,
resourceIds,
resources: resourceIds
.map((resourceId) => snapshotById.get(resourceId))
.filter((resource): resource is MediaSupplyFavoriteResourceSnapshot => Boolean(resource)),
updatedAt: changed ? now : group.updatedAt,
}
})
}
function normalizeGroup(value: unknown): MediaSupplyFavoriteGroup | null {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return null
@@ -15,7 +15,7 @@ import { mediaSupplyApi } from '@/lib/api'
import { formatDateTime } from '@/lib/display'
import {
loadMediaSupplyFavoriteGroups,
mergeMediaSupplyFavoriteResourceSnapshots,
reconcileMediaSupplyFavoriteResources,
removeMediaSupplyFavorite,
saveMediaSupplyFavoriteGroups,
type MediaSupplyFavoriteGroup,
@@ -81,11 +81,16 @@ watch(
watch(
() => resourceDetailsQuery.data.value?.items,
(items) => {
if (!items?.length) {
if (!items || allResourceIds.value.length === 0) {
return
}
groups.value = mergeMediaSupplyFavoriteResourceSnapshots(groups.value, items)
const before = allResourceIds.value.length
groups.value = reconcileMediaSupplyFavoriteResources(groups.value, items)
persist()
const removed = before - allResourceIds.value.length
if (removed > 0) {
message.info(`已移除 ${removed} 个已下架常发媒体`)
}
},
)
@@ -19,6 +19,7 @@ import { mediaSupplyApi } from '@/lib/api'
import { formatDateTime } from '@/lib/display'
import {
loadMediaSupplyFavoriteGroups,
reconcileMediaSupplyFavoriteResources,
removeMediaSupplyFavorite,
saveMediaSupplyFavoriteGroups,
toggleMediaSupplyFavorite,
@@ -309,6 +310,18 @@ const ledgerQuery = useQuery({
queryFn: () => mediaSupplyApi.listWalletLedgers({ page: ledgerPage.value, page_size: 10 }),
enabled: computed(() => ledgerDrawerOpen.value),
})
const favoriteReconcileInFlight = ref(false)
watch(
() => resourcesQuery.data.value?.items,
(items) => {
const favoriteIds = [...new Set(favoriteGroups.value.flatMap((group) => group.resourceIds))]
if (!items || favoriteIds.length === 0) {
return
}
void reconcileFavoriteResources()
},
)
const resources = computed<MediaSupplyResourceRow[]>(() =>
(resourcesQuery.data.value?.items ?? []).map(toResourceRow),
@@ -403,6 +416,7 @@ const ledgerColumns = [
function refresh(): void {
void resourcesQuery.refetch()
void walletQuery.refetch()
void reconcileFavoriteResources()
}
function applyFilters(): void {
@@ -489,6 +503,27 @@ function toggleFavorite(resource: MediaSupplyResourceRow): void {
favoriteModalOpen.value = true
}
async function reconcileFavoriteResources(): Promise<void> {
if (favoriteReconcileInFlight.value) {
return
}
const favoriteIds = [...new Set(favoriteGroups.value.flatMap((group) => group.resourceIds))]
if (favoriteIds.length === 0) {
return
}
favoriteReconcileInFlight.value = true
try {
const detail = await mediaSupplyApi.listResourcesByIds(favoriteIds, MODEL_ID_AUTHORITY_NEWS)
const before = favoriteIds.length
favoriteGroups.value = reconcileMediaSupplyFavoriteResources(favoriteGroups.value, detail.items)
if (before !== favoriteGroups.value.flatMap((group) => group.resourceIds).length) {
saveMediaSupplyFavoriteGroups(authStore.user?.id, favoriteGroups.value)
}
} finally {
favoriteReconcileInFlight.value = false
}
}
function confirmAddFavorite(): void {
const resource = pendingFavoriteResource.value
if (!resource) {