358 lines
14 KiB
TypeScript
358 lines
14 KiB
TypeScript
import { apiRequest } from "@/shared/api/request";
|
|
import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints";
|
|
import type { ApiPage, PageQuery } from "@/shared/api/types";
|
|
|
|
export type CPRelationType = "cp" | "brother" | "sister";
|
|
|
|
export interface CPUserProfileDto {
|
|
userId: string;
|
|
displayUserId?: string;
|
|
prettyDisplayUserId?: string;
|
|
prettyId?: string;
|
|
username?: string;
|
|
avatar?: string;
|
|
}
|
|
|
|
export interface CPGiftSnapshotDto {
|
|
giftId: string;
|
|
giftName: string;
|
|
giftIconUrl: string;
|
|
giftAnimationUrl: string;
|
|
giftCount: number;
|
|
giftValue: number;
|
|
billingReceiptId: string;
|
|
}
|
|
|
|
export interface CPRelationshipDto {
|
|
relationshipId: string;
|
|
relationType: CPRelationType;
|
|
status: string;
|
|
userA: CPUserProfileDto;
|
|
userB: CPUserProfileDto;
|
|
intimacyValue: number;
|
|
level: number;
|
|
durationDays: number;
|
|
gift?: CPGiftSnapshotDto;
|
|
formedAtMs: number;
|
|
updatedAtMs: number;
|
|
endedAtMs: number;
|
|
}
|
|
|
|
export interface CPApplicationDto {
|
|
applicationId: string;
|
|
relationType: CPRelationType;
|
|
status: string;
|
|
requester: CPUserProfileDto;
|
|
target: CPUserProfileDto;
|
|
gift: CPGiftSnapshotDto;
|
|
roomId: string;
|
|
roomRegionId: number;
|
|
createdAtMs: number;
|
|
updatedAtMs: number;
|
|
expiresAtMs: number;
|
|
decidedAtMs: number;
|
|
}
|
|
|
|
export interface CPRelationshipPageDto extends ApiPage<CPRelationshipDto> {
|
|
serverTimeMs?: number;
|
|
}
|
|
|
|
export interface CPApplicationPageDto extends ApiPage<CPApplicationDto> {
|
|
serverTimeMs?: number;
|
|
}
|
|
|
|
export interface CPLevelDto {
|
|
level: number;
|
|
intimacyThreshold: number;
|
|
rewardResourceGroupId: number;
|
|
levelIconUrl: string;
|
|
status: string;
|
|
updatedAtMs?: number;
|
|
}
|
|
|
|
export interface CPRelationConfigDto {
|
|
relationType: CPRelationType;
|
|
displayName: string;
|
|
maxCountPerUser: number;
|
|
applicationExpireHours: number;
|
|
breakupCostCoins: number;
|
|
status: string;
|
|
levels: CPLevelDto[];
|
|
updatedAtMs?: number;
|
|
}
|
|
|
|
export interface CPConfigDto {
|
|
appCode: string;
|
|
relations: CPRelationConfigDto[];
|
|
weeklyRank: CPWeeklyRankDto;
|
|
serverTimeMs?: number;
|
|
}
|
|
|
|
export interface CPWeeklyRankRewardDto {
|
|
rankNo: number;
|
|
resourceGroupId: number;
|
|
}
|
|
|
|
export interface CPWeeklyRankDto {
|
|
enabled: boolean;
|
|
relationType: CPRelationType;
|
|
topCount: number;
|
|
rewards: CPWeeklyRankRewardDto[];
|
|
updatedByAdminId?: number;
|
|
createdAtMs?: number;
|
|
updatedAtMs?: number;
|
|
}
|
|
|
|
export interface CPConfigPayload {
|
|
relations: Array<{
|
|
relationType: CPRelationType;
|
|
maxCountPerUser: number;
|
|
applicationExpireHours: number;
|
|
breakupCostCoins: number;
|
|
status: string;
|
|
levels: Array<{
|
|
level: number;
|
|
intimacyThreshold: number;
|
|
rewardResourceGroupId: number;
|
|
levelIconUrl: string;
|
|
status: string;
|
|
}>;
|
|
}>;
|
|
}
|
|
|
|
export function getCPConfig(): Promise<CPConfigDto> {
|
|
const endpoint = API_ENDPOINTS.getCPConfig;
|
|
return apiRequest<RawConfig>(apiEndpointPath(API_OPERATIONS.getCPConfig), { method: endpoint.method }).then(
|
|
normalizeConfig,
|
|
);
|
|
}
|
|
|
|
export function updateCPConfig(payload: CPConfigPayload): Promise<CPConfigDto> {
|
|
const endpoint = API_ENDPOINTS.updateCPConfig;
|
|
return apiRequest<RawConfig, CPConfigPayload>(apiEndpointPath(API_OPERATIONS.updateCPConfig), {
|
|
body: payload,
|
|
method: endpoint.method,
|
|
}).then(normalizeConfig);
|
|
}
|
|
|
|
export function listCPRelationships(query: PageQuery = {}): Promise<CPRelationshipPageDto> {
|
|
const endpoint = API_ENDPOINTS.listCPRelationships;
|
|
return apiRequest<RawRelationshipPage>(apiEndpointPath(API_OPERATIONS.listCPRelationships), {
|
|
method: endpoint.method,
|
|
query,
|
|
}).then(normalizeRelationshipPage);
|
|
}
|
|
|
|
export function listCPApplications(query: PageQuery = {}): Promise<CPApplicationPageDto> {
|
|
const endpoint = API_ENDPOINTS.listCPApplications;
|
|
return apiRequest<RawApplicationPage>(apiEndpointPath(API_OPERATIONS.listCPApplications), {
|
|
method: endpoint.method,
|
|
query,
|
|
}).then(normalizeApplicationPage);
|
|
}
|
|
|
|
type RawConfig = CPConfigDto & Record<string, unknown>;
|
|
type RawRelation = CPRelationConfigDto & Record<string, unknown>;
|
|
type RawLevel = CPLevelDto & Record<string, unknown>;
|
|
type RawWeeklyRank = CPWeeklyRankDto & Record<string, unknown>;
|
|
type RawRelationship = CPRelationshipDto & Record<string, unknown>;
|
|
type RawApplication = CPApplicationDto & Record<string, unknown>;
|
|
type RawUser = CPUserProfileDto & Record<string, unknown>;
|
|
type RawGift = CPGiftSnapshotDto & Record<string, unknown>;
|
|
type RawRelationshipPage = ApiPage<RawRelationship> & {
|
|
relationships?: RawRelationship[];
|
|
page_size?: number | string;
|
|
server_time_ms?: number | string;
|
|
} & Record<string, unknown>;
|
|
type RawApplicationPage = ApiPage<RawApplication> & {
|
|
applications?: RawApplication[];
|
|
page_size?: number | string;
|
|
server_time_ms?: number | string;
|
|
} & Record<string, unknown>;
|
|
|
|
function normalizeConfig(raw: RawConfig): CPConfigDto {
|
|
const item = asRecord(raw) as RawConfig;
|
|
return {
|
|
appCode: stringValue(item.appCode ?? item.app_code),
|
|
relations: arrayValue(item.relations).map(normalizeRelation),
|
|
weeklyRank: normalizeWeeklyRank(item.weeklyRank ?? item.weekly_rank),
|
|
serverTimeMs: numberValue(item.serverTimeMs ?? item.server_time_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeRelation(raw: unknown): CPRelationConfigDto {
|
|
const item = asRecord(raw) as RawRelation;
|
|
const relationType = normalizeRelationType(item.relationType ?? item.relation_type);
|
|
return {
|
|
relationType,
|
|
displayName: stringValue(item.displayName ?? item.display_name) || relationLabel(relationType),
|
|
maxCountPerUser: numberValue(item.maxCountPerUser ?? item.max_count_per_user),
|
|
applicationExpireHours: numberValue(item.applicationExpireHours ?? item.application_expire_hours),
|
|
breakupCostCoins: numberValue(item.breakupCostCoins ?? item.breakup_cost_coins),
|
|
status: stringValue(item.status) || "active",
|
|
levels: arrayValue(item.levels).map(normalizeLevel),
|
|
updatedAtMs: numberValue(item.updatedAtMs ?? item.updated_at_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeWeeklyRank(raw: unknown): CPWeeklyRankDto {
|
|
const item = asRecord(raw) as RawWeeklyRank;
|
|
return {
|
|
enabled: item.enabled !== false,
|
|
relationType: normalizeRelationType(item.relationType ?? item.relation_type),
|
|
topCount: numberValue(item.topCount ?? item.top_count) || 3,
|
|
rewards: arrayValue(item.rewards).map((reward) => {
|
|
const rawReward = asRecord(reward);
|
|
return {
|
|
rankNo: numberValue(rawReward.rankNo ?? rawReward.rank_no),
|
|
resourceGroupId: numberValue(rawReward.resourceGroupId ?? rawReward.resource_group_id),
|
|
};
|
|
}),
|
|
updatedByAdminId: numberValue(item.updatedByAdminId ?? item.updated_by_admin_id),
|
|
createdAtMs: numberValue(item.createdAtMs ?? item.created_at_ms),
|
|
updatedAtMs: numberValue(item.updatedAtMs ?? item.updated_at_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeLevel(raw: unknown): CPLevelDto {
|
|
const item = asRecord(raw) as RawLevel;
|
|
return {
|
|
level: numberValue(item.level),
|
|
intimacyThreshold: numberValue(item.intimacyThreshold ?? item.intimacy_threshold),
|
|
rewardResourceGroupId: numberValue(item.rewardResourceGroupId ?? item.reward_resource_group_id),
|
|
levelIconUrl: stringValue(item.levelIconUrl ?? item.level_icon_url),
|
|
status: stringValue(item.status) || "active",
|
|
updatedAtMs: numberValue(item.updatedAtMs ?? item.updated_at_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeRelationshipPage(page: RawRelationshipPage): CPRelationshipPageDto {
|
|
const response = asRecord(page) as RawRelationshipPage;
|
|
const items = arrayValue(response.items ?? response.relationships).map(normalizeRelationship);
|
|
return {
|
|
items,
|
|
page: numberValue(response.page) || 1,
|
|
pageSize: numberValue(response.pageSize ?? response.page_size) || items.length || 50,
|
|
total: numberValue(response.total),
|
|
serverTimeMs: numberValue(response.serverTimeMs ?? response.server_time_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeApplicationPage(page: RawApplicationPage): CPApplicationPageDto {
|
|
const response = asRecord(page) as RawApplicationPage;
|
|
const items = arrayValue(response.items ?? response.applications).map(normalizeApplication);
|
|
return {
|
|
items,
|
|
page: numberValue(response.page) || 1,
|
|
pageSize: numberValue(response.pageSize ?? response.page_size) || items.length || 50,
|
|
total: numberValue(response.total),
|
|
serverTimeMs: numberValue(response.serverTimeMs ?? response.server_time_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeRelationship(raw: unknown): CPRelationshipDto {
|
|
const item = asRecord(raw) as RawRelationship;
|
|
const userA = normalizeUser(item.userA ?? item.user_a ?? item.me ?? item.requester);
|
|
const userB = normalizeUser(item.userB ?? item.user_b ?? item.partner ?? item.target);
|
|
const gift = normalizeGift(
|
|
item.gift ?? item.sourceGift ?? item.source_gift ?? item.applicationGift ?? item.application_gift,
|
|
);
|
|
return {
|
|
relationshipId: stringValue(item.relationshipId ?? item.relationship_id),
|
|
relationType: normalizeRelationType(item.relationType ?? item.relation_type),
|
|
status: stringValue(item.status) || "active",
|
|
userA,
|
|
userB,
|
|
intimacyValue: numberValue(
|
|
item.intimacyValue ?? item.intimacy_value ?? item.experienceValue ?? item.experience_value,
|
|
),
|
|
level: numberValue(item.level ?? item.levelNo ?? item.level_no),
|
|
durationDays: numberValue(item.durationDays ?? item.duration_days ?? item.days),
|
|
gift: gift.giftId || gift.giftName || gift.giftValue ? gift : undefined,
|
|
formedAtMs: numberValue(item.formedAtMs ?? item.formed_at_ms ?? item.createdAtMs ?? item.created_at_ms),
|
|
updatedAtMs: numberValue(item.updatedAtMs ?? item.updated_at_ms),
|
|
endedAtMs: numberValue(item.endedAtMs ?? item.ended_at_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeApplication(raw: unknown): CPApplicationDto {
|
|
const item = asRecord(raw) as RawApplication;
|
|
return {
|
|
applicationId: stringValue(item.applicationId ?? item.application_id),
|
|
relationType: normalizeRelationType(item.relationType ?? item.relation_type),
|
|
status: stringValue(item.status) || "pending",
|
|
requester: normalizeUser(
|
|
item.requester ?? item.requesterUser ?? item.requester_user ?? item.userA ?? item.user_a,
|
|
),
|
|
target: normalizeUser(item.target ?? item.targetUser ?? item.target_user ?? item.userB ?? item.user_b),
|
|
gift: normalizeGift(item.gift ?? item.sourceGift ?? item.source_gift),
|
|
roomId: stringValue(item.roomId ?? item.room_id),
|
|
roomRegionId: numberValue(item.roomRegionId ?? item.room_region_id),
|
|
createdAtMs: numberValue(item.createdAtMs ?? item.created_at_ms),
|
|
updatedAtMs: numberValue(item.updatedAtMs ?? item.updated_at_ms),
|
|
expiresAtMs: numberValue(item.expiresAtMs ?? item.expires_at_ms),
|
|
decidedAtMs: numberValue(item.decidedAtMs ?? item.decided_at_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeUser(raw: unknown): CPUserProfileDto {
|
|
const item = asRecord(raw) as RawUser;
|
|
return {
|
|
userId: stringValue(item.userId ?? item.user_id),
|
|
displayUserId: optionalString(item.displayUserId ?? item.display_user_id),
|
|
prettyDisplayUserId: optionalString(item.prettyDisplayUserId ?? item.pretty_display_user_id),
|
|
prettyId: optionalString(item.prettyId ?? item.pretty_id),
|
|
username: optionalString(item.username ?? item.name),
|
|
avatar: optionalString(item.avatar),
|
|
};
|
|
}
|
|
|
|
function normalizeGift(raw: unknown): CPGiftSnapshotDto {
|
|
const item = asRecord(raw) as RawGift;
|
|
return {
|
|
giftId: stringValue(item.giftId ?? item.gift_id),
|
|
giftName: stringValue(item.giftName ?? item.gift_name ?? item.name),
|
|
giftIconUrl: stringValue(item.giftIconUrl ?? item.gift_icon_url ?? item.iconUrl ?? item.icon_url),
|
|
giftAnimationUrl: stringValue(
|
|
item.giftAnimationUrl ?? item.gift_animation_url ?? item.animationUrl ?? item.animation_url,
|
|
),
|
|
giftCount: numberValue(item.giftCount ?? item.gift_count ?? item.count),
|
|
giftValue: numberValue(item.giftValue ?? item.gift_value ?? item.value),
|
|
billingReceiptId: stringValue(item.billingReceiptId ?? item.billing_receipt_id),
|
|
};
|
|
}
|
|
|
|
function normalizeRelationType(value: unknown): CPRelationType {
|
|
const relationType = stringValue(value).toLowerCase();
|
|
if (relationType === "brother" || relationType === "sister") {
|
|
return relationType;
|
|
}
|
|
return "cp";
|
|
}
|
|
|
|
function relationLabel(relationType: CPRelationType) {
|
|
return relationType === "brother" ? "兄弟" : relationType === "sister" ? "姐妹" : "CP";
|
|
}
|
|
|
|
function asRecord(value: unknown): Record<string, unknown> {
|
|
return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : {};
|
|
}
|
|
|
|
function arrayValue(value: unknown): unknown[] {
|
|
return Array.isArray(value) ? value : [];
|
|
}
|
|
|
|
function stringValue(value: unknown) {
|
|
return typeof value === "string" ? value : value === undefined || value === null ? "" : String(value);
|
|
}
|
|
|
|
function optionalString(value: unknown) {
|
|
const text = stringValue(value).trim();
|
|
return text || undefined;
|
|
}
|
|
|
|
function numberValue(value: unknown) {
|
|
const number = Number(value || 0);
|
|
return Number.isFinite(number) ? number : 0;
|
|
}
|