fix: keep cp gift relation type

This commit is contained in:
zhx 2026-06-08 17:35:25 +08:00
parent 4520e16470
commit ae8ae7db55
5 changed files with 56 additions and 15 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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),

View File

@ -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"}',

View File

@ -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 (
<div className={styles.stack}>
<span>{giftTypeLabel(gift.giftTypeCode, giftTypeOptions)}</span>
{relationType ? <span className="admin-tag">{cpRelationTypeLabels[relationType] || relationType}</span> : null}
</div>
);
const typeLabel = giftTypeLabel(gift.giftTypeCode, giftTypeOptions);
const relationType = gift.giftTypeCode === "cp" ? cpRelationTypeFromGift(gift) || "cp" : "";
const relationLabel = relationType ? cpRelationTypeShortLabel(relationType) : "";
return <span>{relationLabel ? `${typeLabel}${relationLabel}` : typeLabel}</span>;
}
function giftPriceLabel(gift) {