协议数据模拟测试

This commit is contained in:
chen wei bo
2025-08-29 16:40:14 +08:00
parent 5f51c19bc6
commit 1e7f2cf466
42 changed files with 702 additions and 90 deletions
@@ -1,24 +1,32 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from 'db://assets/Scripts/proto/proto.pb.js';
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IAuthService } from "./IAuthService";
import { HttpAuthService } from "./HttpAuthService";
import { MockAuthService } from "./MockAuthService";
export class AuthService {
// 模拟开关
const USE_MOCK = false;
export class AuthService implements IAuthService {
private static _I: AuthService | null = null;
public static get I(): AuthService {
if (!AuthService._I) AuthService._I = new AuthService();
return AuthService._I;
}
private constructor(private api = ApiClient.I) {}
private impl: IAuthService;
private constructor() {
this.impl = USE_MOCK ? new MockAuthService() : new HttpAuthService();
}
/** 运行期动态切换 */
public switch(useMock: boolean) {
this.impl = useMock ? new MockAuthService() : new HttpAuthService();
}
// 登录
public async login(req: proto.cs.ICSLoginReq): Promise<ApiResponse<proto.cs.ICSLoginRes>> {
let epData: Endpoint<proto.cs.ICSLoginReq, proto.cs.ICSLoginRes> = {
path: "api/acc/login",
method: "POST",
codec: "json",
needsAuth: false
};
return this.api.call(epData, req);
return this.impl.login(req);
}
}
@@ -1,24 +1,33 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
// assets/Scripts/services/logic/ChatService.ts
import type { ApiResponse } from "../client/types";
import proto from 'db://assets/Scripts/proto/proto.pb.js';
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IChatService } from "./IChatService";
import { HttpChatService } from "./HttpChatService";
import { MockChatService } from "./MockChatService";
export class ChatService {
// 模拟开关
const USE_MOCK = true;
export class ChatService implements IChatService {
private static _I: ChatService | null = null;
public static get I(): ChatService {
if (!ChatService._I) ChatService._I = new ChatService();
return ChatService._I;
}
private constructor(private api = ApiClient.I) {}
// 购买聊天次数
private impl: IChatService;
private constructor() {
this.impl = USE_MOCK ? new MockChatService() : new HttpChatService();
}
/** 运行期动态切换 */
public switch(useMock: boolean) {
this.impl = useMock ? new MockChatService() : new HttpChatService();
}
// 对外 API 保持不变
public async reqBuyChat(req: proto.cs.ICSBuyChatReq): Promise<ApiResponse<proto.cs.ICSBuyChatRes>> {
let epData: Endpoint<proto.cs.ICSBuyChatReq, proto.cs.ICSBuyChatRes> = {
path: "api/logic/buyChat",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
return this.impl.reqBuyChat(req);
}
}
@@ -1,46 +1,41 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { IGirlService } from "./IGirlService";
import { HttpGirlService } from "./HttpGirlService";
import { MockGirlService } from "./MockGirlService";
import type { ApiResponse } from "../client/types";
import proto from 'db://assets/Scripts/proto/proto.pb.js';
import proto from "db://assets/Scripts/proto/proto.pb.js";
export class GirlService {
// 模拟开关
const USE_MOCK = false;
export class GirlService implements IGirlService {
private static _I: GirlService | null = null;
public static get I(): GirlService {
if (!GirlService._I) GirlService._I = new GirlService();
return GirlService._I;
}
private constructor(private api = ApiClient.I) {}
private impl: IGirlService;
private constructor() {
this.impl = USE_MOCK ? new MockGirlService() : new HttpGirlService();
}
/** 可运行期切换 */
public switch(useMock: boolean) {
this.impl = useMock ? new MockGirlService() : new HttpGirlService();
}
// 每日推荐
public async reqDailyRecommend(req: proto.cs.ICSDailyRecommendReq): Promise<ApiResponse<proto.cs.ICSDailyRecommendRes>> {
let epData: Endpoint<proto.cs.ICSDailyRecommendReq, proto.cs.ICSDailyRecommendRes> = {
path: "api/logic/dailyRecommend",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
return this.impl.reqDailyRecommend(req);
}
// 获取技师列表
public async reqGetGirlList(req: proto.cs.ICSGetGirlListReq): Promise<ApiResponse<proto.cs.ICSGetGirlListRes>> {
let epData: Endpoint<proto.cs.ICSGetGirlListReq, proto.cs.ICSGetGirlListRes> = {
path: "api/logic/getGirls",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
}
return this.impl.reqGetGirlList(req);
}
// 获取技师详细信息
public async reqGetGirlDetail(req: proto.cs.ICSGetGirlDetailReq): Promise<ApiResponse<proto.cs.ICSGetGirlDetailRes>> {
let epData: Endpoint<proto.cs.ICSGetGirlDetailReq, proto.cs.ICSGetGirlDetailRes> = {
path: "api/logic/girlDetail",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
}
return this.impl.reqGetGirlDetail(req);
}
}
@@ -0,0 +1,20 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IAuthService } from "./IAuthService";
export class HttpAuthService implements IAuthService {
constructor(private api = ApiClient.I) {}
// 登录
async login(req: proto.cs.ICSLoginReq): Promise<ApiResponse<proto.cs.ICSLoginRes>> {
const ep: Endpoint<proto.cs.ICSLoginReq, proto.cs.ICSLoginRes> = {
path: "api/acc/login",
method: "POST",
codec: "json",
needsAuth: false,
};
return this.api.call(ep, req);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "24bc5b19-b50b-417b-a289-6daaf1631e5e",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,20 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IChatService } from "./IChatService";
export class HttpChatService implements IChatService {
constructor(private api = ApiClient.I) {}
// 购买聊天次数
async reqBuyChat(req: proto.cs.ICSBuyChatReq): Promise<ApiResponse<proto.cs.ICSBuyChatRes>> {
const ep: Endpoint<proto.cs.ICSBuyChatReq, proto.cs.ICSBuyChatRes> = {
path: "api/logic/buyChat",
method: "POST",
codec: "json",
needsAuth: true,
};
return this.api.call(ep, req);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "eeceea12-9271-4d6e-accb-6fa845679bae",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,42 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IGirlService } from "./IGirlService";
export class HttpGirlService implements IGirlService {
constructor(private api = ApiClient.I) {}
// 每日推荐
async reqDailyRecommend(req: proto.cs.ICSDailyRecommendReq): Promise<ApiResponse<proto.cs.ICSDailyRecommendRes>> {
let epData: Endpoint<proto.cs.ICSDailyRecommendReq, proto.cs.ICSDailyRecommendRes> = {
path: "api/logic/dailyRecommend",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
}
// 获取技师列表
async reqGetGirlList(req: proto.cs.ICSGetGirlListReq): Promise<ApiResponse<proto.cs.ICSGetGirlListRes>> {
let epData: Endpoint<proto.cs.ICSGetGirlListReq, proto.cs.ICSGetGirlListRes> = {
path: "api/logic/getGirls",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
}
// 获取技师详细信息
async reqGetGirlDetail(req: proto.cs.ICSGetGirlDetailReq): Promise<ApiResponse<proto.cs.ICSGetGirlDetailRes>> {
let epData: Endpoint<proto.cs.ICSGetGirlDetailReq, proto.cs.ICSGetGirlDetailRes> = {
path: "api/logic/girlDetail",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "44a2654f-adcb-429c-9263-1c3af2fe892a",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,20 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IPlayerDataService } from "./IPlayerDataService";
export class HttpPlayerDataService implements IPlayerDataService {
constructor(private api = ApiClient.I) {}
// 获取个人信息
async reqMyInfo(req: proto.cs.ICSMyInfoReq): Promise<ApiResponse<proto.cs.ICSMyInfoRes>> {
const ep: Endpoint<proto.cs.ICSMyInfoReq, proto.cs.ICSMyInfoRes> = {
path: "api/acc/info",
method: "POST",
codec: "json",
needsAuth: true,
};
return this.api.call(ep, req);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "ab96e711-2298-4537-940e-76456dbc0bae",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,20 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IShopService } from "./IShopService";
export class HttpShopService implements IShopService {
constructor(private api = ApiClient.I) {}
// 获取商品列表
async reqShopList(req: proto.cs.ICSGetShopReq): Promise<ApiResponse<proto.cs.ICSGetShopRes>> {
const ep: Endpoint<proto.cs.ICSGetShopReq, proto.cs.ICSGetShopRes> = {
path: "api/logic/shop",
method: "POST",
codec: "json",
needsAuth: true,
};
return this.api.call(ep, req);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "e3cabad6-a951-4c68-9a25-ead65e5e2df1",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,20 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IThemeService } from "./IThemeService";
export class HttpThemeService implements IThemeService {
constructor(private api = ApiClient.I) {}
// 获取大厅分类列表
async reqHallTheme(req: proto.cs.ICSHallThemeReq): Promise<ApiResponse<proto.cs.ICSHallThemeRes>> {
const ep: Endpoint<proto.cs.ICSHallThemeReq, proto.cs.ICSHallThemeRes> = {
path: "api/logic/hallTheme",
method: "POST",
codec: "json",
needsAuth: true,
};
return this.api.call(ep, req);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "6f1c9a8b-d57c-42ba-973c-f766e240c6d9",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,7 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
export interface IAuthService {
// 登录
login(req: proto.cs.ICSLoginReq): Promise<ApiResponse<proto.cs.ICSLoginRes>>;
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "f6cd1a0f-bbf1-4c31-97d3-a38cb289a43b",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,8 @@
// assets/Scripts/services/logic/IChatService.ts
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
export interface IChatService {
// 购买聊天次数
reqBuyChat(req: proto.cs.ICSBuyChatReq): Promise<ApiResponse<proto.cs.ICSBuyChatRes>>;
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "eb6b8f79-cd6e-469f-b0f3-4f7e228f28c2",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,11 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
export interface IGirlService {
// 每日推荐
reqDailyRecommend(req: proto.cs.ICSDailyRecommendReq): Promise<ApiResponse<proto.cs.ICSDailyRecommendRes>>;
// 获取技师列表
reqGetGirlList(req: proto.cs.ICSGetGirlListReq): Promise<ApiResponse<proto.cs.ICSGetGirlListRes>>;
// 获取技师详细信息
reqGetGirlDetail(req: proto.cs.ICSGetGirlDetailReq): Promise<ApiResponse<proto.cs.ICSGetGirlDetailRes>>;
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "7a3984ae-374c-4a29-9829-cc34bf786bd3",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,7 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
export interface IPlayerDataService {
// 获取个人信息
reqMyInfo(req: proto.cs.ICSMyInfoReq): Promise<ApiResponse<proto.cs.ICSMyInfoRes>>;
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "b430ee20-dcca-4283-8c12-05fbaf0ef9cd",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,7 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
export interface IShopService {
// 获取商品列表
reqShopList(req: proto.cs.ICSGetShopReq): Promise<ApiResponse<proto.cs.ICSGetShopRes>>;
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "02999aec-9975-46ba-a11f-af36e470a92f",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,7 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
export interface IThemeService {
// 获取大厅分类列表
reqHallTheme(req: proto.cs.ICSHallThemeReq): Promise<ApiResponse<proto.cs.ICSHallThemeRes>>;
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "2bdda7f1-a550-4f93-8ae7-d21b58e75bf0",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,34 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IAuthService } from "./IAuthService";
export class MockAuthService implements IAuthService {
private delay(ms = 180) { return new Promise<void>(r => setTimeout(r, ms)); }
// 项目里 ApiResponse 结构若固定(code/message 等),把 ok()/err() 调整为你的真实结构即可
private ok<T>(data: T): ApiResponse<T> {
return ({ ok: true, data } as unknown) as ApiResponse<T>;
}
// private err<T = unknown>(message = "mock login error"): ApiResponse<T> {
// return ({ ok: false, error: { message } } as unknown) as ApiResponse<T>;
// }
// 登录
async login(req: proto.cs.ICSLoginReq): Promise<ApiResponse<proto.cs.ICSLoginRes>> {
await this.delay(150);
const name = req?.platType === "guest" ? `guest_${(req?.userId ?? "uid").toString().slice(-6)}` : "tester";
// 注意:protobufjs 会把 int64 表达为 number/Long。这里用「秒」级时间戳更常见
const expireSeconds = Math.floor(Date.now() / 1000) + 7 * 24 * 3600;
// 你的生成器通常会把 refresh_token 转成 refreshTokencamelCase
const res: proto.cs.ICSLoginRes = {
name,
token: `mock_token_${Date.now()}`,
refreshToken: `mock_refresh_${Date.now()}`,
expire: expireSeconds,
};
return this.ok(res);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "2604979a-f511-42c6-acec-8df2728a036b",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,22 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IChatService } from "./IChatService";
export class MockChatService implements IChatService {
private delay(ms = 160) { return new Promise<void>(r => setTimeout(r, ms)); }
// 按你们项目的 ApiResponse 结构调整这里即可
private ok<T>(data: T): ApiResponse<T> {
return ({ ok: true, data } as unknown) as ApiResponse<T>;
}
// private err<T = unknown>(message = "mock buyChat error"): ApiResponse<T> {
// return ({ ok: false, error: { message } } as unknown) as ApiResponse<T>;
// }
async reqBuyChat(_req: proto.cs.ICSBuyChatReq): Promise<ApiResponse<proto.cs.ICSBuyChatRes>> {
await this.delay();
// CSBuyChatRes 在 proto 中为空消息,这里返回 {}
const res: proto.cs.ICSBuyChatRes = {};
return this.ok(res);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "3b9927c4-335d-4593-a646-0136b2f82025",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,63 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IGirlService } from "./IGirlService";
export class MockGirlService implements IGirlService {
private delay(ms = 180) { return new Promise<void>(r => setTimeout(r, ms)); }
private randInt(min: number, max: number) { return Math.floor(Math.random() * (max - min + 1)) + min; }
private pick<T>(arr: T[]) { return arr[this.randInt(0, arr.length - 1)]; }
private ok<T>(data: T): ApiResponse<T> {
return ({ ok: true, data } as unknown) as ApiResponse<T>;
}
private err<T = unknown>(message = "mock error"): ApiResponse<T> {
return ({ ok: false, error: { message } } as unknown) as ApiResponse<T>;
}
private genBrief(id: number): proto.cs.IGirlBrief {
const tags = ["cute", "cool", "elegant", "sporty", "sweet"];
return {
id,
name: `Girl-${id}`,
age: this.randInt(18, 28),
tagKey: this.pick(tags),
priceType: (id % 2) + 1,
price: 50 + (id % 6) * 10,
avatar: `https://dummy.local/avatar/${id}.png`,
star: (id % 5) + 1,
};
}
private genPhoto(idx: number): proto.cs.IGirlPhoto {
return { pic: `https://dummy.local/photo/${idx}.jpg`, isRelease: Math.random() < 0.5, price: 20 + (idx % 5) * 5 };
}
private genDetail(id: number): proto.cs.IGirlDetail {
const photos = Array.from({ length: 4 }, (_, i) => this.genPhoto(id * 10 + i));
return { brief: this.genBrief(id), desc: `Mock detail for ${id}`, photos, isRelease: Math.random() < 0.4, chatCount: this.randInt(0, 5) };
}
// 每日推荐
async reqDailyRecommend(_req: proto.cs.ICSDailyRecommendReq): Promise<ApiResponse<proto.cs.ICSDailyRecommendRes>> {
await this.delay(180);
const count = this.randInt(4, 8);
const girls = Array.from({ length: count }, (_, i) => this.genBrief(100 + i));
return this.ok({ girls });
}
// 获取技师列表
async reqGetGirlList(req: proto.cs.ICSGetGirlListReq): Promise<ApiResponse<proto.cs.ICSGetGirlListRes>> {
await this.delay(200);
const base = (req?.category ?? 0) * 1000 + (req?.page ?? 1) * 100;
const limit = Math.max(1, Math.min(req?.limit ?? 10, 50));
const girls = Array.from({ length: limit }, (_, i) => this.genBrief(base + i));
return this.ok({ girls });
}
// 获取技师详细信息
async reqGetGirlDetail(req: proto.cs.ICSGetGirlDetailReq): Promise<ApiResponse<proto.cs.ICSGetGirlDetailRes>> {
await this.delay(160);
const id = req?.id ?? this.randInt(1, 9999);
return this.ok({ detail: this.genDetail(id) });
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "842792c0-92ee-47f7-adbf-9abe668dd089",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,28 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IPlayerDataService } from "./IPlayerDataService";
export class MockPlayerDataService implements IPlayerDataService {
private delay(ms = 160) { return new Promise<void>(r => setTimeout(r, ms)); }
// 按你项目的 ApiResponse 真实结构调整这里
private ok<T>(data: T): ApiResponse<T> {
return ({ ok: true, data } as unknown) as ApiResponse<T>;
}
// 如需模拟失败
// private err<T = unknown>(message = "mock myInfo error"): ApiResponse<T> {
// return ({ ok: false, error: { message } } as unknown) as ApiResponse<T>;
// }
// 获取个人信息
async reqMyInfo(_req: proto.cs.ICSMyInfoReq): Promise<ApiResponse<proto.cs.ICSMyInfoRes>> {
await this.delay();
// 由于我们并不知道 ICSMyInfoRes 的具体字段,这里提供一个“最安全”的空对象返回;
// 如果你有明确字段(例如 name/diamond/vipExpire 等),可在此构造并 as-cast:
// const res = { name: "Player-001", diamond: 123, vipExpire: Math.floor(Date.now()/1000) } as unknown as proto.cs.ICSMyInfoRes;
const res = ({} as unknown) as proto.cs.ICSMyInfoRes;
return this.ok(res);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "827b309b-4711-4458-8914-edc1d9d9c7c3",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,39 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IShopService } from "./IShopService";
export class MockShopService implements IShopService {
private delay(ms = 180) { return new Promise<void>(r => setTimeout(r, ms)); }
private randInt(min: number, max: number) { return Math.floor(Math.random() * (max - min + 1)) + min; }
private priceUSD(min = 0.99, max = 49.99) {
const v = Math.random() * (max - min) + min;
return v.toFixed(2); // 字符串,保留两位小数
}
private ok<T>(data: T): ApiResponse<T> {
return ({ ok: true, data } as unknown) as ApiResponse<T>;
}
private genGood(id: number, vip = false): proto.cs.IGood {
return {
id,
name: vip ? `VIP-${id}` : `Diamond Pack ${id}`,
desc: vip ? `VIP access for ${this.randInt(24, 168)} hours` : `Diamonds x${this.randInt(60, 2000)}`,
price: this.priceUSD(vip ? 4.99 : 0.99, vip ? 49.99 : 29.99),
count: vip ? this.randInt(24, 168) : this.randInt(60, 2000), // VIP=小时,普通=数量
};
}
// 获取商品列表
async reqShopList(_req: proto.cs.ICSGetShopReq): Promise<ApiResponse<proto.cs.ICSGetShopRes>> {
await this.delay();
// 普通商品(<=2000+ VIP 商品(>2000
const normals: proto.cs.IGood[] = Array.from({ length: 5 }, (_, i) => this.genGood(1000 + i, false));
const vips: proto.cs.IGood[] = Array.from({ length: 3 }, (_, i) => this.genGood(2001 + i, true));
// 注意:你的 proto 定义中字段名为 "Goods"(大写 G
const res: proto.cs.ICSGetShopRes = { Goods: [...normals, ...vips] };
return this.ok(res);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "23c641b5-906c-4623-a581-2152bb42dab3",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,39 @@
import type { ApiResponse } from "../client/types";
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IThemeService } from "./IThemeService";
export class MockThemeService implements IThemeService {
private delay(ms = 160) { return new Promise<void>(r => setTimeout(r, ms)); }
private ok<T>(data: T): ApiResponse<T> {
return ({ ok: true, data } as unknown) as ApiResponse<T>;
}
private makeTheme(id: number, name: string, category: number, isRelease = true): proto.cs.IHallTheme {
return {
id,
key: `theme_${id}`,
name,
category,
isRelease,
path: `https://dummy.local/theme/${id}.png`,
};
// 若你使用资源服路径,可替换 path 为实际地址或 db:// 本地资源
}
// 获取大厅分类列表
async reqHallTheme(_req: proto.cs.ICSHallThemeReq): Promise<ApiResponse<proto.cs.ICSHallThemeRes>> {
await this.delay();
const themes: proto.cs.IHallTheme[] = [
this.makeTheme(1, "Hot", 1, true),
this.makeTheme(2, "New", 2, true),
this.makeTheme(3, "Popular", 3, true),
this.makeTheme(4, "VIP Only", 4, false),
this.makeTheme(5, "Classic", 5, true),
this.makeTheme(6, "Editor Pick",6, true),
];
const res: proto.cs.ICSHallThemeRes = { themes };
return this.ok(res);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "b8fc6f81-7ccf-448d-9591-a1ebccf60bda",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -1,24 +1,32 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from 'db://assets/Scripts/proto/proto.pb.js';
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IPlayerDataService } from "./IPlayerDataService";
import { HttpPlayerDataService } from "./HttpPlayerDataService";
import { MockPlayerDataService } from "./MockPlayerDataService";
export class PlayerDataService {
// 模拟开关
const USE_MOCK = true;
export class PlayerDataService implements IPlayerDataService {
private static _I: PlayerDataService | null = null;
public static get I(): PlayerDataService {
if (!PlayerDataService._I) PlayerDataService._I = new PlayerDataService();
return PlayerDataService._I;
}
private constructor(private api = ApiClient.I) {}
// 获取个人信息
private impl: IPlayerDataService;
private constructor() {
this.impl = USE_MOCK ? new MockPlayerDataService() : new HttpPlayerDataService();
}
/** 运行期切换 */
public switch(useMock: boolean) {
this.impl = useMock ? new MockPlayerDataService() : new HttpPlayerDataService();
}
// 获取个人信息
public async reqMyInfo(req: proto.cs.ICSMyInfoReq): Promise<ApiResponse<proto.cs.ICSMyInfoRes>> {
let epData: Endpoint<proto.cs.ICSMyInfoReq, proto.cs.ICSMyInfoRes> = {
path: "api/acc/info",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
return this.impl.reqMyInfo(req);
}
}
@@ -1,24 +1,32 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from 'db://assets/Scripts/proto/proto.pb.js';
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IShopService } from "./IShopService";
import { HttpShopService } from "./HttpShopService";
import { MockShopService } from "./MockShopService";
export class ShopService {
// 模拟开关
const USE_MOCK = true;
export class ShopService implements IShopService {
private static _I: ShopService | null = null;
public static get I(): ShopService {
if (!ShopService._I) ShopService._I = new ShopService();
return ShopService._I;
}
private constructor(private api = ApiClient.I) {}
private impl: IShopService;
private constructor() {
this.impl = USE_MOCK ? new MockShopService() : new HttpShopService();
}
/** 运行期切换 */
public switch(useMock: boolean) {
this.impl = useMock ? new MockShopService() : new HttpShopService();
}
// 获取商品列表
public async reqShopList(req: proto.cs.ICSGetShopReq): Promise<ApiResponse<proto.cs.ICSGetShopRes>> {
let epData: Endpoint<proto.cs.ICSGetShopReq, proto.cs.ICSGetShopRes> = {
path: "api/logic/shop",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
return this.impl.reqShopList(req);
}
}
@@ -1,24 +1,32 @@
import { ApiClient } from "../client/ApiClient";
import type { Endpoint } from "../client/endpoints";
import type { ApiResponse } from "../client/types";
import proto from 'db://assets/Scripts/proto/proto.pb.js';
import proto from "db://assets/Scripts/proto/proto.pb.js";
import type { IThemeService } from "./IThemeService";
import { HttpThemeService } from "./HttpThemeService";
import { MockThemeService } from "./MockThemeService";
export class ThemeService {
// 模拟开关
const USE_MOCK = true;
export class ThemeService implements IThemeService {
private static _I: ThemeService | null = null;
public static get I(): ThemeService {
if (!ThemeService._I) ThemeService._I = new ThemeService();
return ThemeService._I;
}
private constructor(private api = ApiClient.I) {}
private impl: IThemeService;
private constructor() {
this.impl = USE_MOCK ? new MockThemeService() : new HttpThemeService();
}
/** 运行期切换 */
public switch(useMock: boolean) {
this.impl = useMock ? new MockThemeService() : new HttpThemeService();
}
// 获取大厅分类列表
public async reqHallTheme(req: proto.cs.ICSHallThemeReq): Promise<ApiResponse<proto.cs.ICSHallThemeRes>> {
let epData: Endpoint<proto.cs.ICSHallThemeReq, proto.cs.ICSHallThemeRes> = {
path: "api/logic/hallTheme",
method: "POST",
codec: "json",
needsAuth: true
};
return this.api.call(epData, req);
return this.impl.reqHallTheme(req);
}
}