feat(chat): add history unlock api

This commit is contained in:
2026-06-26 19:27:56 +08:00
parent 1b73c3ac10
commit 455204e1e4
10 changed files with 227 additions and 61 deletions
+1
View File
@@ -13,5 +13,6 @@ export * from "./send_message_request";
export * from "./stt_data";
export * from "./sync_message";
export * from "./ui_message";
export * from "./unlock_history_response";
export * from "./unlock_private_request";
export * from "./unlock_private_response";
@@ -0,0 +1,43 @@
/**
* 一键解锁历史锁定消息响应 DTO
*/
import {
UnlockHistoryResponseSchema,
type UnlockHistoryReason,
type UnlockHistoryResponseData,
type UnlockHistoryResponseInput,
} from "@/data/schemas/chat/unlock_history_response";
export class UnlockHistoryResponse {
declare readonly unlocked: boolean;
declare readonly reason: UnlockHistoryReason;
declare readonly totalLocked: number;
declare readonly unlockedCount: number;
declare readonly privateCount: number;
declare readonly imageCount: number;
declare readonly voiceCount: number;
declare readonly requiredCredits: number;
declare readonly currentCredits: number;
declare readonly remainingCredits: number;
declare readonly shortfallCredits: number;
declare readonly costsByMessage: Record<string, number>;
declare readonly messageIds: string[];
private constructor(input: UnlockHistoryResponseInput) {
const data = UnlockHistoryResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: UnlockHistoryResponseInput): UnlockHistoryResponse {
return new UnlockHistoryResponse(input);
}
static fromJson(json: unknown): UnlockHistoryResponse {
return UnlockHistoryResponse.from(json as UnlockHistoryResponseInput);
}
toJson(): UnlockHistoryResponseData {
return UnlockHistoryResponseSchema.parse(this);
}
}
+6
View File
@@ -21,6 +21,7 @@ import {
ChatMessage,
ChatSendResponse,
SendMessageRequest,
UnlockHistoryResponse,
UnlockPrivateRequest,
UnlockPrivateResponse,
} from "@/data/dto/chat";
@@ -68,6 +69,11 @@ export class ChatRepository implements IChatRepository {
);
}
/** 一键解锁历史锁定消息。 */
async unlockHistory(): Promise<Result<UnlockHistoryResponse>> {
return Result.wrap(() => this.api.unlockHistory());
}
/** 把本地缓存中的私密消息标记为已解锁。 */
async markPrivateMessageUnlockedInLocal(
messageId: string,
@@ -16,6 +16,7 @@ import type {
ChatHistoryResponse,
ChatMessage,
ChatSendResponse,
UnlockHistoryResponse,
UnlockPrivateResponse,
} from "@/data/dto/chat";
@@ -32,6 +33,9 @@ export interface IChatRepository {
/** 解锁私密消息。 */
unlockPrivateMessage(messageId: string): Promise<Result<UnlockPrivateResponse>>;
/** 一键解锁历史锁定消息。 */
unlockHistory(): Promise<Result<UnlockHistoryResponse>>;
/** 把本地缓存中的私密消息标记为已解锁。 */
markPrivateMessageUnlockedInLocal(
messageId: string,
+1
View File
@@ -12,5 +12,6 @@ export * from "./image_upload_response";
export * from "./send_message_request";
export * from "./stt_data";
export * from "./sync_message";
export * from "./unlock_history_response";
export * from "./unlock_private_request";
export * from "./unlock_private_response";
@@ -0,0 +1,36 @@
/**
* 一键解锁历史锁定消息响应
*/
import { z } from "zod";
export const UnlockHistoryCostsByMessageSchema = z.record(z.string(), z.number());
export const UnlockHistoryReasonSchema = z.enum([
"ok",
"insufficient_balance",
"no_locked_messages",
]);
export const UnlockHistoryResponseSchema = z.object({
unlocked: z.boolean(),
reason: UnlockHistoryReasonSchema,
totalLocked: z.number().default(0),
unlockedCount: z.number().default(0),
privateCount: z.number().default(0),
imageCount: z.number().default(0),
voiceCount: z.number().default(0),
requiredCredits: z.number().default(0),
currentCredits: z.number().default(0),
remainingCredits: z.number().default(0),
shortfallCredits: z.number().default(0),
costsByMessage: UnlockHistoryCostsByMessageSchema.default({}),
messageIds: z.array(z.string()).default([]),
});
export type UnlockHistoryReason = z.output<typeof UnlockHistoryReasonSchema>;
export type UnlockHistoryResponseInput = z.input<
typeof UnlockHistoryResponseSchema
>;
export type UnlockHistoryResponseData = z.output<
typeof UnlockHistoryResponseSchema
>;
+3
View File
@@ -112,6 +112,9 @@ export class ApiPath {
/** 解锁私密消息 */
static readonly chatUnlockPrivate = `${ApiPath._chat}/unlock-private`;
/** 一键解锁历史锁定消息 */
static readonly chatUnlockHistory = `${ApiPath._chat}/unlock-history`;
// ============ 数据看板相关 ============
private static readonly _metrics = `${ApiPath._baseUrl}/metrics`;
+16
View File
@@ -16,6 +16,7 @@ import {
SendMessageRequest,
SttData,
SyncMessage,
UnlockHistoryResponse,
UnlockPrivateRequest,
UnlockPrivateResponse,
} from "@/data/dto/chat";
@@ -101,6 +102,21 @@ export class ChatApi {
unwrap(env) as Record<string, unknown>,
);
}
/**
* 一键解锁历史锁定消息
*/
async unlockHistory(): Promise<UnlockHistoryResponse> {
const env = await httpClient<ApiEnvelope<unknown>>(
ApiPath.chatUnlockHistory,
{
method: "POST",
},
);
return UnlockHistoryResponse.fromJson(
unwrap(env) as Record<string, unknown>,
);
}
}
/**