diff --git a/src/app/chat/chat-screen.tsx b/src/app/chat/chat-screen.tsx index 703a31bd..7ae5b62b 100644 --- a/src/app/chat/chat-screen.tsx +++ b/src/app/chat/chat-screen.tsx @@ -43,10 +43,15 @@ export function ChatScreen() { // isGuest 派生(chat-screen 是唯一知道这个值的地方 —— chat 机器无 isGuest 字段) const isGuest = deriveIsGuest(authState.loginStatus); - // 消息数量限制由后端统一返回 blocked/daily_limit,前端不再处理本地额度。 - const showDailyLimitBanner = + // 消息数量限制由后端统一返回 blocked,前端不再处理本地额度。 + const showMessageLimitBanner = state.paywallTriggered && - state.paywallReason === "daily_limit"; + (state.paywallReason === "daily_limit" || + state.paywallReason === "total_limit"); + const messageLimitTitle = + state.paywallReason === "total_limit" + ? "The limit for free chat times\nhas been reached" + : undefined; const showPhotoPaywallBanner = state.paywallTriggered && state.paywallReason === "photo_paywall"; const showPrivatePaywallBanner = @@ -168,8 +173,9 @@ export function ChatScreen() { /> ) : null} - {showDailyLimitBanner ? ( + {showMessageLimitBanner ? ( ) : ( diff --git a/src/data/mock/chat/responses/send-message-total-limit-blocked.json b/src/data/mock/chat/responses/send-message-total-limit-blocked.json new file mode 100644 index 00000000..348f8e6d --- /dev/null +++ b/src/data/mock/chat/responses/send-message-total-limit-blocked.json @@ -0,0 +1,30 @@ +{ + "code": 200, + "message": "success", + "success": true, + "data": { + "mode": "http", + "type": "text", + "reply": "", + "voiceUrl": "", + "audioUrl": "", + "intimacyChange": 0, + "newIntimacy": 0, + "relationshipStage": "密友", + "currentMood": "happy", + "messageId": "", + "isGuest": true, + "timestamp": 1782197944984, + "blocked": true, + "blockReason": "total_limit", + "blockDetail": { + "type": "guest_total_msg_limit", + "usedTotal": 12, + "limit": 5 + }, + "paywallTriggered": false, + "showUpgrade": false, + "imageType": null, + "imageUrl": null + } +} diff --git a/src/data/schemas/chat/chat_send_response.ts b/src/data/schemas/chat/chat_send_response.ts index 26d489e7..add4757b 100644 --- a/src/data/schemas/chat/chat_send_response.ts +++ b/src/data/schemas/chat/chat_send_response.ts @@ -6,7 +6,8 @@ import { z } from "zod"; export const ChatBlockDetailSchema = z.object({ type: z.string(), - usedToday: z.number(), + usedToday: z.number().optional(), + usedTotal: z.number().optional(), limit: z.number(), }); diff --git a/src/stores/chat/chat-machine.helpers.ts b/src/stores/chat/chat-machine.helpers.ts index 1f31b054..e0fa41a2 100644 --- a/src/stores/chat/chat-machine.helpers.ts +++ b/src/stores/chat/chat-machine.helpers.ts @@ -103,7 +103,12 @@ export function applyHttpSendOutput( ): Partial { const { response, reply } = output; - if (response.blocked === true && response.blockReason === "daily_limit") { + const isMessageLimitBlocked = + response.blocked === true && + (response.blockReason === "daily_limit" || + response.blockReason === "total_limit"); + + if (isMessageLimitBlocked) { const detail = response.blockDetail; const lastMessage = context.messages[context.messages.length - 1]; const messages = @@ -115,9 +120,19 @@ export function applyHttpSendOutput( messages, isReplyingAI: false, paywallTriggered: true, - paywallReason: "daily_limit", + paywallReason: + response.blockReason === "total_limit" ? "total_limit" : "daily_limit", paywallDetail: detail - ? { usedToday: detail.usedToday, limit: detail.limit } + ? { + type: detail.type, + ...(detail.usedToday != null + ? { usedToday: detail.usedToday } + : {}), + ...(detail.usedTotal != null + ? { usedTotal: detail.usedTotal } + : {}), + limit: detail.limit, + } : null, }; } diff --git a/src/stores/chat/chat-state.ts b/src/stores/chat/chat-state.ts index 12e2df89..69c3d2d0 100644 --- a/src/stores/chat/chat-state.ts +++ b/src/stores/chat/chat-state.ts @@ -19,8 +19,20 @@ export interface ChatState { */ wsConnected: boolean; paywallTriggered: boolean; - paywallReason: "daily_limit" | "photo_paywall" | "private_paywall" | null; - paywallDetail: { usedToday: number; limit: number } | null; + paywallReason: + | "daily_limit" + | "total_limit" + | "photo_paywall" + | "private_paywall" + | null; + paywallDetail: + | { + type?: string; + usedToday?: number; + usedTotal?: number; + limit: number; + } + | null; unlockingPrivateMessageId: string | null; isLoadingMore: boolean; hasMore: boolean;