fix(chat): use weekly limit for message quota

This commit is contained in:
2026-06-29 18:40:44 +08:00
parent a821d01834
commit cee63e8658
8 changed files with 20 additions and 20 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ export function ChatScreen() {
// 消息数量限制由后端统一返回 lockDetail,前端不再处理本地额度。 // 消息数量限制由后端统一返回 lockDetail,前端不再处理本地额度。
const showMessageLimitBanner = const showMessageLimitBanner =
state.upgradePromptVisible && state.upgradeReason === "daily_limit"; state.upgradePromptVisible && state.upgradeReason === "weekly_limit";
const messageLimitTitle = "The limit for free chat times\nhas been reached"; const messageLimitTitle = "The limit for free chat times\nhas been reached";
const externalBrowserPromptShownRef = useRef(false); const externalBrowserPromptShownRef = useRef(false);
@@ -3,7 +3,7 @@
* ChatQuotaExhaustedBanner 游客配额耗尽横幅 * ChatQuotaExhaustedBanner 游客配额耗尽横幅
* *
* 何时显示: * 何时显示:
* - 后端返回 lockDetail.reason="daily_limit" 且 showUpgrade=true * - 后端返回 lockDetail.reason="weekly_limit" 且 showUpgrade=true
* *
* 视觉规格(与设计稿对齐): * 视觉规格(与设计稿对齐):
* - 粉→品红渐变背景(与 splash 渐变一致) * - 粉→品红渐变背景(与 splash 渐变一致)
@@ -132,7 +132,7 @@ describe("sendResponseToUiMessage", () => {
}); });
describe("applyHttpSendOutput", () => { describe("applyHttpSendOutput", () => {
it("removes the optimistic user message when the daily limit is reached", () => { it("removes the optimistic user message when the weekly limit is reached", () => {
const context = makeChatState({ const context = makeChatState({
messages: [ messages: [
{ {
@@ -151,11 +151,11 @@ describe("applyHttpSendOutput", () => {
locked: true, locked: true,
showContent: false, showContent: false,
showUpgrade: true, showUpgrade: true,
reason: "daily_limit", reason: "weekly_limit",
hint: "Free message limit reached.", hint: "Free message limit reached.",
detail: { detail: {
type: "daily_msg_limit", type: "weekly_msg_limit",
usedToday: 3, usedThisWeek: 3,
limit: 3, limit: 3,
}, },
}, },
@@ -166,7 +166,7 @@ describe("applyHttpSendOutput", () => {
expect(nextState.messages).toEqual([]); expect(nextState.messages).toEqual([]);
expect(nextState.isReplyingAI).toBe(false); expect(nextState.isReplyingAI).toBe(false);
expect(nextState.upgradePromptVisible).toBe(true); expect(nextState.upgradePromptVisible).toBe(true);
expect(nextState.upgradeReason).toBe("daily_limit"); expect(nextState.upgradeReason).toBe("weekly_limit");
}); });
}); });
@@ -262,7 +262,7 @@ describe("countLockedHistoryMessages", () => {
isFromAI: true, isFromAI: true,
date: "2026-06-29", date: "2026-06-29",
locked: true, locked: true,
lockReason: "daily_limit", lockReason: "weekly_limit",
}, },
{ {
content: "user text", content: "user text",
@@ -437,7 +437,7 @@ describe("chatMachine transitions", () => {
actor.stop(); actor.stop();
}); });
it("clears the daily limit prompt after payment succeeds", async () => { it("clears the weekly limit prompt after payment succeeds", async () => {
const actor = createActor(createTestChatMachine()).start(); const actor = createActor(createTestChatMachine()).start();
actor.send({ type: "ChatUserLogin", token: "token" }); actor.send({ type: "ChatUserLogin", token: "token" });
@@ -459,11 +459,11 @@ describe("chatMachine transitions", () => {
locked: true, locked: true,
showContent: false, showContent: false,
showUpgrade: true, showUpgrade: true,
reason: "daily_limit", reason: "weekly_limit",
hint: "Free message limit reached.", hint: "Free message limit reached.",
detail: { detail: {
type: "daily_msg_limit", type: "weekly_msg_limit",
usedToday: 3, usedThisWeek: 3,
limit: 3, limit: 3,
}, },
}, },
@@ -473,7 +473,7 @@ describe("chatMachine transitions", () => {
}); });
expect(actor.getSnapshot().context.upgradePromptVisible).toBe(true); expect(actor.getSnapshot().context.upgradePromptVisible).toBe(true);
expect(actor.getSnapshot().context.upgradeReason).toBe("daily_limit"); expect(actor.getSnapshot().context.upgradeReason).toBe("weekly_limit");
actor.send({ type: "ChatPaymentSucceeded" }); actor.send({ type: "ChatPaymentSucceeded" });
+3 -3
View File
@@ -156,12 +156,12 @@ async function sendMessageViaHttp(content: string): Promise<{
log.error("[chat-machine] sendMessageHttpActor failed", { error: result.error }); log.error("[chat-machine] sendMessageHttpActor failed", { error: result.error });
throw result.error; throw result.error;
} }
const isDailyLimit = const isMessageLimit =
result.data.lockDetail.locked && result.data.lockDetail.locked &&
result.data.lockDetail.showUpgrade && result.data.lockDetail.showUpgrade &&
result.data.lockDetail.reason === "daily_limit"; result.data.lockDetail.reason === "weekly_limit";
return { return {
response: result.data, response: result.data,
reply: isDailyLimit ? null : sendResponseToUiMessage(result.data), reply: isMessageLimit ? null : sendResponseToUiMessage(result.data),
}; };
} }
+2 -2
View File
@@ -173,7 +173,7 @@ export function applyHttpSendOutput(
const isMessageLimitBlocked = const isMessageLimitBlocked =
lockDetail.locked && lockDetail.locked &&
lockDetail.showUpgrade && lockDetail.showUpgrade &&
lockDetail.reason === "daily_limit"; lockDetail.reason === "weekly_limit";
if (isMessageLimitBlocked) { if (isMessageLimitBlocked) {
const lastMessage = context.messages[context.messages.length - 1]; const lastMessage = context.messages[context.messages.length - 1];
@@ -186,7 +186,7 @@ export function applyHttpSendOutput(
messages, messages,
...finishPendingReply(context), ...finishPendingReply(context),
upgradePromptVisible: true, upgradePromptVisible: true,
upgradeReason: "daily_limit", upgradeReason: "weekly_limit",
}; };
} }
+1 -1
View File
@@ -23,7 +23,7 @@
* *
* 配额: * 配额:
* - 前端不再处理本地消息额度;游客 / 注册用户均以后端响应为准。 * - 前端不再处理本地消息额度;游客 / 注册用户均以后端响应为准。
* - 后端返回 `lockDetail.reason="daily_limit"` 且需要升级时展示会员引导。 * - 后端返回 `lockDetail.reason="weekly_limit"` 且需要升级时展示会员引导。
* *
*/ */
+1 -1
View File
@@ -5,7 +5,7 @@ export interface ChatState {
isReplyingAI: boolean; isReplyingAI: boolean;
pendingReplyCount: number; pendingReplyCount: number;
upgradePromptVisible: boolean; upgradePromptVisible: boolean;
upgradeReason: "daily_limit" | null; upgradeReason: "weekly_limit" | null;
isLoadingMore: boolean; isLoadingMore: boolean;
hasMore: boolean; hasMore: boolean;
historyOffset: number; historyOffset: number;