From 7acde68d45feb0cb3cb0752793b568bc4f6b5433 Mon Sep 17 00:00:00 2001 From: zetaloop Date: Sun, 3 May 2026 05:48:39 +0800 Subject: [PATCH] refactor(disputes): align type with backend and derive timeline in page --- app/(order)/dispute/[id]/page.tsx | 10 +---- lib/api/disputes.ts | 69 ++++--------------------------- lib/types.ts | 10 +++++ 3 files changed, 20 insertions(+), 69 deletions(-) diff --git a/app/(order)/dispute/[id]/page.tsx b/app/(order)/dispute/[id]/page.tsx index 76d306f..68ea1ab 100644 --- a/app/(order)/dispute/[id]/page.tsx +++ b/app/(order)/dispute/[id]/page.tsx @@ -44,15 +44,7 @@ const disputeStatusVariants: Record = { appealed: "info", } -function deriveMinimalTimeline(dispute: { - id: string - status: string - createdAt: TCreatedAt - timeline?: { id: string; content: string; createdAt: TCreatedAt }[] -}) { - const existing = dispute.timeline - if (existing?.length) return existing - +function deriveMinimalTimeline(dispute: { id: string; status: string; createdAt: string }) { const steps = [ { status: "open", content: "争议已提交" }, { status: "reviewing", content: "平台审核中" }, diff --git a/lib/api/disputes.ts b/lib/api/disputes.ts index 508a96d..da12bd8 100644 --- a/lib/api/disputes.ts +++ b/lib/api/disputes.ts @@ -4,20 +4,6 @@ import type { Dispute } from "@/lib/types" import { httpJson } from "./http" -export type DisputeTimelineItem = { - id: string - content: string - createdAt: string -} - -export type DisputeRecord = Dispute & { - respondentReason?: string - respondentEvidence: string[] - appealReason?: string - appealedAt?: string - timeline: DisputeTimelineItem[] -} - export type ListDisputesOptions = { offset?: number limit?: number @@ -64,49 +50,12 @@ function unwrapDispute(value: unknown): unknown { return value } -function deriveMinimalTimeline(dispute: { - id: string - status: string - createdAt: string - timeline?: DisputeTimelineItem[] -}): DisputeTimelineItem[] { - const existing = dispute.timeline - if (existing?.length) return existing - - const steps = [ - { status: "open", content: "争议已提交" }, - { status: "reviewing", content: "平台审核中" }, - { status: "resolved", content: "争议已解决" }, - { status: "appealed", content: "已发起申诉" }, - ] - - const currentIndex = steps.findIndex((step) => step.status === dispute.status) - const lastIndex = currentIndex >= 0 ? currentIndex : 0 - return steps.slice(0, lastIndex + 1).map((step) => ({ - id: `${dispute.id}-${step.status}`, - content: step.content, - createdAt: dispute.createdAt, - })) -} - -function normalizeDisputeRecord(value: unknown): DisputeRecord { - const dispute = unwrapDispute(value) as DisputeRecord - const respondentEvidence = Array.isArray(dispute.respondentEvidence) - ? dispute.respondentEvidence - : [] - const evidence = Array.isArray(dispute.evidence) ? dispute.evidence : [] - const timeline = deriveMinimalTimeline({ - id: dispute.id, - status: dispute.status, - createdAt: dispute.createdAt, - timeline: dispute.timeline, - }) - +function normalizeDispute(value: unknown): Dispute { + const dispute = unwrapDispute(value) as Dispute return { ...dispute, - evidence, - respondentEvidence, - timeline, + evidence: Array.isArray(dispute.evidence) ? dispute.evidence : [], + respondentEvidence: Array.isArray(dispute.respondentEvidence) ? dispute.respondentEvidence : [], } } @@ -118,20 +67,20 @@ function denyFromError(error: unknown): ApiDecision { return deny(apiError.code, apiError.msg) } -export async function listDisputes(options?: ListDisputesOptions): Promise { - const res = await httpJson | DisputeRecord[]>( +export async function listDisputes(options?: ListDisputesOptions): Promise { + const res = await httpJson | Dispute[]>( withOffsetLimit("/api/v1/disputes", options), { cache: "no-store" }, ) - return unwrapItems(res).map((item) => normalizeDisputeRecord(item)) + return unwrapItems(res).map((item) => normalizeDispute(item)) } -export async function getDisputeByOrderId(orderId: string): Promise { +export async function getDisputeByOrderId(orderId: string): Promise { try { const res = await httpJson(`/api/v1/orders/${encodeURIComponent(orderId)}/dispute`, { cache: "no-store", }) - return normalizeDisputeRecord(res) + return normalizeDispute(res) } catch (error) { const apiError = isApiError(error) ? error : toApiError(error) if (apiError.code === 404) return undefined diff --git a/lib/types.ts b/lib/types.ts index 577468b..7f752d9 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -120,11 +120,21 @@ export interface Review { export interface Dispute { id: SnowflakeId orderId: SnowflakeId + initiatorId?: SnowflakeId + initiatorName?: string + respondentId?: SnowflakeId reason: string evidence: string[] status: "open" | "reviewing" | "resolved" | "appealed" result?: "full_refund" | "full_payment" | "partial_refund" + respondentReason?: string + respondentEvidence: string[] + appealReason?: string + appealedAt?: string + resolvedBy?: SnowflakeId + resolvedAt?: string createdAt: string + updatedAt: string } export interface ChatParticipant {