From ae8ae7db55420c1f4efaa167868667391752278c Mon Sep 17 00:00:00 2001 From: zhx Date: Mon, 8 Jun 2026 17:35:25 +0800 Subject: [PATCH] fix: keep cp gift relation type --- src/features/resources/api.test.ts | 2 ++ src/features/resources/api.ts | 2 ++ .../resources/hooks/useResourcePages.js | 29 +++++++++++++++---- .../resources/hooks/useResourcePages.test.js | 20 +++++++++++++ src/features/resources/pages/GiftListPage.jsx | 18 ++++++------ 5 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/features/resources/api.test.ts b/src/features/resources/api.test.ts index 0b10654..eb46ecf 100644 --- a/src/features/resources/api.test.ts +++ b/src/features/resources/api.test.ts @@ -81,6 +81,7 @@ test("resource APIs use generated admin paths", async () => { await createGift({ chargeAssetType: "COIN", coinPrice: 10, + cpRelationType: "", effectiveAtMs: 1777766400000, effectiveFromMs: 0, effectiveToMs: 0, @@ -131,6 +132,7 @@ test("resource APIs use generated admin paths", async () => { await updateGift("rose", { chargeAssetType: "COIN", coinPrice: 10, + cpRelationType: "", effectiveAtMs: 1777766400000, effectiveFromMs: 0, effectiveToMs: 0, diff --git a/src/features/resources/api.ts b/src/features/resources/api.ts index 30b3633..9d9c941 100644 --- a/src/features/resources/api.ts +++ b/src/features/resources/api.ts @@ -126,6 +126,7 @@ export interface GiftDto { presentationJson?: string; priceVersion?: string; giftTypeCode?: string; + cpRelationType?: string; chargeAssetType?: string; coinPrice?: number; effectiveFromMs?: number; @@ -158,6 +159,7 @@ export interface GiftPayload { presentationJson: string; priceVersion: string; giftTypeCode: string; + cpRelationType: string; chargeAssetType: string; coinPrice: number; effectiveAtMs: number; diff --git a/src/features/resources/hooks/useResourcePages.js b/src/features/resources/hooks/useResourcePages.js index 67e1039..a3030ce 100644 --- a/src/features/resources/hooks/useResourcePages.js +++ b/src/features/resources/hooks/useResourcePages.js @@ -122,14 +122,11 @@ const emptyGroupWalletAssetItem = (walletAssetType) => ({ const emptyGiftForm = (gift = {}) => { const giftTypeCode = gift.giftTypeCode || "normal"; const presentationJson = gift.presentationJson || "{}"; - const cpRelationType = - giftTypeCode === cpGiftTypeCode - ? cpRelationTypeFromPresentationJson(presentationJson) || defaultCPRelationType - : ""; + const cpRelationType = cpRelationTypeFromGift({ ...gift, giftTypeCode, presentationJson }) || defaultCPRelationType; return { chargeAssetType: gift.chargeAssetType || "COIN", coinPrice: gift.coinPrice === 0 || gift.coinPrice ? String(gift.coinPrice) : "", - cpRelationType, + cpRelationType: giftTypeCode === cpGiftTypeCode ? cpRelationType : "", effectTypes: gift.effectTypes || [], effectiveFrom: msToDatetimeLocal(gift.effectiveFromMs), effectiveTo: msToDatetimeLocal(gift.effectiveToMs), @@ -174,6 +171,18 @@ export function cpRelationTypeFromPresentationJson(presentationJson) { return relationType || ""; } +export function cpRelationTypeFromGift(gift = {}) { + if (gift?.giftTypeCode !== cpGiftTypeCode) { + return ""; + } + return validCPRelationType(gift.cpRelationType) || cpRelationTypeFromPresentationJson(gift.presentationJson); +} + +export function cpRelationTypeShortLabel(value) { + const label = cpRelationTypeLabels[validCPRelationType(value)] || String(value || "").trim(); + return label.endsWith("礼物") ? label.slice(0, -2) : label; +} + export function normalizeGiftPresentationJson(presentationJson, giftTypeCode, cpRelationType) { const rawValue = String(presentationJson || "").trim(); const isCPGift = giftTypeCode === cpGiftTypeCode; @@ -239,8 +248,12 @@ function parseGiftPresentationObject(presentationJson) { } function normalizedCPRelationType(value) { + return validCPRelationType(value) || defaultCPRelationType; +} + +function validCPRelationType(value) { const relationType = String(value || "").trim().toLowerCase(); - return cpRelationTypeValues.has(relationType) ? relationType : defaultCPRelationType; + return cpRelationTypeValues.has(relationType) ? relationType : ""; } function cpPresentationJson(basePresentation, cpRelationType) { @@ -1629,9 +1642,11 @@ function buildResourceGroupPayload(form) { } function buildGiftPayload(form) { + const cpRelationType = form.giftTypeCode === cpGiftTypeCode ? normalizedCPRelationType(form.cpRelationType) : ""; return { chargeAssetType: form.chargeAssetType, coinPrice: Number(form.coinPrice), + cpRelationType, effectiveAtMs: Date.now(), effectiveFromMs: datetimeLocalToMs(form.effectiveFrom), effectiveToMs: datetimeLocalToMs(form.effectiveTo), @@ -1649,9 +1664,11 @@ function buildGiftPayload(form) { } function buildGiftInlineSortPayload(gift, sortOrder) { + const cpRelationType = cpRelationTypeFromGift(gift); return { chargeAssetType: gift.chargeAssetType || "COIN", coinPrice: Number(gift.coinPrice || 0), + cpRelationType: gift.giftTypeCode === cpGiftTypeCode ? cpRelationType || defaultCPRelationType : "", effectiveAtMs: Date.now(), effectiveFromMs: Number(gift.effectiveFromMs || 0), effectiveToMs: Number(gift.effectiveToMs || 0), diff --git a/src/features/resources/hooks/useResourcePages.test.js b/src/features/resources/hooks/useResourcePages.test.js index 6dbda4c..4f85e70 100644 --- a/src/features/resources/hooks/useResourcePages.test.js +++ b/src/features/resources/hooks/useResourcePages.test.js @@ -2,7 +2,9 @@ import { expect, test, vi } from "vitest"; import { applyGiftPriceDefaults, applyGiftResourceSelection, + cpRelationTypeFromGift, cpRelationTypeFromPresentationJson, + cpRelationTypeShortLabel, fetchAllOptionPages, normalizeGiftPresentationJson, } from "./useResourcePages.js"; @@ -67,6 +69,24 @@ test("reads CP relation type from gift presentation json", () => { expect(cpRelationTypeFromPresentationJson('{"cp_relation_type":"unknown"}')).toBe(""); }); +test("prefers explicit CP relation type and formats compact list label", () => { + expect( + cpRelationTypeFromGift({ + cpRelationType: "brother", + giftTypeCode: "cp", + presentationJson: '{"cp_relation_type":"sister"}', + }), + ).toBe("brother"); + expect( + cpRelationTypeFromGift({ + giftTypeCode: "cp", + presentationJson: '{"cp_relation_type":"sister"}', + }), + ).toBe("sister"); + expect(cpRelationTypeShortLabel("brother")).toBe("兄弟"); + expect(cpRelationTypeShortLabel("cp")).toBe("CP"); +}); + test("normalizes CP gift presentation json for submit", () => { const nextJson = normalizeGiftPresentationJson( '{"other":1,"cp_relation_type":"brother","cpRelationLabel":"old"}', diff --git a/src/features/resources/pages/GiftListPage.jsx b/src/features/resources/pages/GiftListPage.jsx index 99d9a6a..e04582f 100644 --- a/src/features/resources/pages/GiftListPage.jsx +++ b/src/features/resources/pages/GiftListPage.jsx @@ -34,14 +34,17 @@ import { createRegionColumnFilter } from "@/shared/ui/RegionFilterControl.jsx"; import { createOptionsColumnFilter, createTextColumnFilter } from "@/shared/ui/tableFilters.js"; import { formatMillis } from "@/shared/utils/time.js"; import { - cpRelationTypeLabels, cpRelationTypeOptions, defaultGiftTypeOptions, resourceStatusFilters, } from "@/features/resources/constants.js"; import { GiftTypeConfigDialog } from "@/features/resources/components/GiftTypeConfigDialog.jsx"; import { ResourceSelectField } from "@/features/resources/components/ResourceSelectDrawer.jsx"; -import { cpRelationTypeFromPresentationJson, useGiftListPage } from "@/features/resources/hooks/useResourcePages.js"; +import { + cpRelationTypeFromGift, + cpRelationTypeShortLabel, + useGiftListPage, +} from "@/features/resources/hooks/useResourcePages.js"; import styles from "@/features/resources/resources.module.css"; const effectOptions = [ @@ -667,13 +670,10 @@ function giftTypeLabel(value, options = defaultGiftTypeOptions) { } function GiftTypeIdentity({ gift, giftTypeOptions }) { - const relationType = gift.giftTypeCode === "cp" ? cpRelationTypeFromPresentationJson(gift.presentationJson) : ""; - return ( -
- {giftTypeLabel(gift.giftTypeCode, giftTypeOptions)} - {relationType ? {cpRelationTypeLabels[relationType] || relationType} : null} -
- ); + const typeLabel = giftTypeLabel(gift.giftTypeCode, giftTypeOptions); + const relationType = gift.giftTypeCode === "cp" ? cpRelationTypeFromGift(gift) || "cp" : ""; + const relationLabel = relationType ? cpRelationTypeShortLabel(relationType) : ""; + return {relationLabel ? `${typeLabel}(${relationLabel})` : typeLabel}; } function giftPriceLabel(gift) {