fix: implement resource reconciliation and update handling in media supply favorites
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user