256 lines
8.7 KiB
TypeScript
256 lines
8.7 KiB
TypeScript
import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints";
|
|
import { apiRequest } from "@/shared/api/request";
|
|
import type { EntityId, PageQuery } from "@/shared/api/types";
|
|
|
|
export type LevelTrackCode = "wealth" | "game" | "charm";
|
|
export type LevelConfigStatus = "active" | "disabled";
|
|
|
|
export interface LevelRuleDto {
|
|
createdAtMs?: number;
|
|
displayConfigJson?: string;
|
|
level: number;
|
|
avatarFrameResourceId?: number;
|
|
longBadgeResourceId?: number;
|
|
name?: string;
|
|
requiredValue: number;
|
|
rewardResourceGroupId?: number;
|
|
shortBadgeResourceId?: number;
|
|
sortOrder?: number;
|
|
status?: LevelConfigStatus | string;
|
|
track: LevelTrackCode;
|
|
updatedAtMs?: number;
|
|
}
|
|
|
|
export interface LevelTierDto {
|
|
createdAtMs?: number;
|
|
displayAvatarFrameResourceId?: number;
|
|
displayBadgeResourceId?: number;
|
|
displayConfigJson?: string;
|
|
maxLevel: number;
|
|
minLevel: number;
|
|
name?: string;
|
|
rewardResourceGroupId?: number;
|
|
status?: LevelConfigStatus | string;
|
|
tierId: number;
|
|
track: LevelTrackCode;
|
|
updatedAtMs?: number;
|
|
}
|
|
|
|
export interface LevelTrackDto {
|
|
createdAtMs?: number;
|
|
displayConfigJson?: string;
|
|
name?: string;
|
|
rules: LevelRuleDto[];
|
|
sortOrder?: number;
|
|
status?: LevelConfigStatus | string;
|
|
tiers: LevelTierDto[];
|
|
track: LevelTrackCode;
|
|
updatedAtMs?: number;
|
|
}
|
|
|
|
export interface LevelConfigDto {
|
|
serverTimeMs?: number;
|
|
tracks: LevelTrackDto[];
|
|
}
|
|
|
|
export interface LevelTrackPayload {
|
|
display_config_json?: string;
|
|
name: string;
|
|
sort_order: number;
|
|
status: LevelConfigStatus;
|
|
}
|
|
|
|
export interface LevelRulePayload {
|
|
avatar_frame_resource_id?: number;
|
|
long_badge_resource_id?: number;
|
|
name: string;
|
|
required_value: number;
|
|
reward_resource_group_id?: number;
|
|
short_badge_resource_id?: number;
|
|
sort_order: number;
|
|
status: LevelConfigStatus;
|
|
}
|
|
|
|
export interface LevelTierPayload {
|
|
display_avatar_frame_resource_id?: number;
|
|
display_badge_resource_id?: number;
|
|
display_config_json?: string;
|
|
max_level: number;
|
|
min_level: number;
|
|
name: string;
|
|
reward_resource_group_id?: number;
|
|
status: LevelConfigStatus;
|
|
track: LevelTrackCode;
|
|
}
|
|
|
|
type AnyRecord = Record<string, unknown>;
|
|
|
|
export function listLevelConfig(query: PageQuery = {}): Promise<LevelConfigDto> {
|
|
const endpoint = API_ENDPOINTS.listLevelConfig;
|
|
return apiRequest<unknown>(apiEndpointPath(API_OPERATIONS.listLevelConfig), {
|
|
method: endpoint.method,
|
|
query,
|
|
}).then(normalizeLevelConfig);
|
|
}
|
|
|
|
export function updateTrack(track: LevelTrackCode, payload: LevelTrackPayload): Promise<LevelTrackDto> {
|
|
const endpoint = API_ENDPOINTS.updateTrack;
|
|
return apiRequest<unknown, LevelTrackPayload>(apiEndpointPath(API_OPERATIONS.updateTrack, { track }), {
|
|
body: payload,
|
|
method: endpoint.method,
|
|
}).then(normalizeTrack);
|
|
}
|
|
|
|
export function upsertRule(
|
|
track: LevelTrackCode,
|
|
level: EntityId,
|
|
payload: LevelRulePayload,
|
|
): Promise<LevelRuleDto> {
|
|
const endpoint = API_ENDPOINTS.upsertRule;
|
|
return apiRequest<unknown, LevelRulePayload>(
|
|
apiEndpointPath(API_OPERATIONS.upsertRule, { level, track }),
|
|
{
|
|
body: payload,
|
|
method: endpoint.method,
|
|
},
|
|
).then(normalizeRule);
|
|
}
|
|
|
|
export function createTier(payload: LevelTierPayload): Promise<LevelTierDto> {
|
|
const endpoint = API_ENDPOINTS.createTier;
|
|
return apiRequest<unknown, LevelTierPayload>(apiEndpointPath(API_OPERATIONS.createTier), {
|
|
body: payload,
|
|
method: endpoint.method,
|
|
}).then(normalizeTier);
|
|
}
|
|
|
|
export function updateTier(tierId: EntityId, payload: LevelTierPayload): Promise<LevelTierDto> {
|
|
const endpoint = API_ENDPOINTS.updateTier;
|
|
return apiRequest<unknown, LevelTierPayload>(apiEndpointPath(API_OPERATIONS.updateTier, { tier_id: tierId }), {
|
|
body: payload,
|
|
method: endpoint.method,
|
|
}).then(normalizeTier);
|
|
}
|
|
|
|
function normalizeLevelConfig(raw: unknown): LevelConfigDto {
|
|
const source = asRecord(raw);
|
|
return {
|
|
serverTimeMs: numberValue(source.serverTimeMs ?? source.server_time_ms),
|
|
tracks: arrayValue(source.tracks).map(normalizeTrack),
|
|
};
|
|
}
|
|
|
|
function normalizeTrack(raw: unknown): LevelTrackDto {
|
|
const source = asRecord(raw);
|
|
return {
|
|
createdAtMs: numberValue(source.createdAtMs ?? source.created_at_ms),
|
|
displayConfigJson: jsonString(source.displayConfigJson ?? source.display_config_json),
|
|
name: stringValue(source.name),
|
|
rules: arrayValue(source.rules).map(normalizeRule),
|
|
sortOrder: numberValue(source.sortOrder ?? source.sort_order),
|
|
status: stringValue(source.status),
|
|
tiers: arrayValue(source.tiers).map(normalizeTier),
|
|
track: stringValue(source.track) as LevelTrackCode,
|
|
updatedAtMs: numberValue(source.updatedAtMs ?? source.updated_at_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeRule(raw: unknown): LevelRuleDto {
|
|
const source = asRecord(raw);
|
|
const displayConfig = source.displayConfigJson ?? source.display_config_json;
|
|
const displayConfigObject = parseDisplayConfig(displayConfig);
|
|
|
|
return {
|
|
createdAtMs: numberValue(source.createdAtMs ?? source.created_at_ms),
|
|
displayConfigJson: jsonString(displayConfig),
|
|
level: numberValue(source.level),
|
|
avatarFrameResourceId: numberValue(
|
|
source.avatarFrameResourceId ??
|
|
source.avatar_frame_resource_id ??
|
|
displayConfigObject.avatarFrameResourceId ??
|
|
displayConfigObject.avatar_frame_resource_id,
|
|
),
|
|
longBadgeResourceId: numberValue(
|
|
source.longBadgeResourceId ??
|
|
source.long_badge_resource_id ??
|
|
displayConfigObject.longBadgeResourceId ??
|
|
displayConfigObject.long_badge_resource_id,
|
|
),
|
|
name: stringValue(source.name),
|
|
requiredValue: numberValue(source.requiredValue ?? source.required_value),
|
|
rewardResourceGroupId: numberValue(source.rewardResourceGroupId ?? source.reward_resource_group_id),
|
|
shortBadgeResourceId: numberValue(
|
|
source.shortBadgeResourceId ??
|
|
source.short_badge_resource_id ??
|
|
displayConfigObject.shortBadgeResourceId ??
|
|
displayConfigObject.short_badge_resource_id,
|
|
),
|
|
sortOrder: numberValue(source.sortOrder ?? source.sort_order),
|
|
status: stringValue(source.status),
|
|
track: stringValue(source.track) as LevelTrackCode,
|
|
updatedAtMs: numberValue(source.updatedAtMs ?? source.updated_at_ms),
|
|
};
|
|
}
|
|
|
|
function normalizeTier(raw: unknown): LevelTierDto {
|
|
const source = asRecord(raw);
|
|
return {
|
|
createdAtMs: numberValue(source.createdAtMs ?? source.created_at_ms),
|
|
displayAvatarFrameResourceId: numberValue(
|
|
source.displayAvatarFrameResourceId ?? source.display_avatar_frame_resource_id,
|
|
),
|
|
displayBadgeResourceId: numberValue(source.displayBadgeResourceId ?? source.display_badge_resource_id),
|
|
displayConfigJson: jsonString(source.displayConfigJson ?? source.display_config_json),
|
|
maxLevel: numberValue(source.maxLevel ?? source.max_level),
|
|
minLevel: numberValue(source.minLevel ?? source.min_level),
|
|
name: stringValue(source.name),
|
|
rewardResourceGroupId: numberValue(source.rewardResourceGroupId ?? source.reward_resource_group_id),
|
|
status: stringValue(source.status),
|
|
tierId: numberValue(source.tierId ?? source.tier_id),
|
|
track: stringValue(source.track) as LevelTrackCode,
|
|
updatedAtMs: numberValue(source.updatedAtMs ?? source.updated_at_ms),
|
|
};
|
|
}
|
|
|
|
function asRecord(value: unknown): AnyRecord {
|
|
return value && typeof value === "object" && !Array.isArray(value) ? (value as AnyRecord) : {};
|
|
}
|
|
|
|
function arrayValue(value: unknown): unknown[] {
|
|
return Array.isArray(value) ? value : [];
|
|
}
|
|
|
|
function numberValue(value: unknown): number {
|
|
if (value === undefined || value === null || value === "") {
|
|
return 0;
|
|
}
|
|
const numeric = Number(value);
|
|
return Number.isFinite(numeric) ? numeric : 0;
|
|
}
|
|
|
|
function stringValue(value: unknown): string {
|
|
return value === undefined || value === null ? "" : String(value);
|
|
}
|
|
|
|
function jsonString(value: unknown): string {
|
|
if (value === undefined || value === null || value === "") {
|
|
return "";
|
|
}
|
|
if (typeof value === "string") {
|
|
return value;
|
|
}
|
|
return JSON.stringify(value);
|
|
}
|
|
|
|
function parseDisplayConfig(value: unknown): AnyRecord {
|
|
const raw = jsonString(value).trim();
|
|
if (!raw) {
|
|
return {};
|
|
}
|
|
try {
|
|
return asRecord(JSON.parse(raw));
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|