mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-29 09:37:37 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 179f72da93 | |||
| 3023dc14e0 |
@@ -312,6 +312,12 @@ pub const TIER_WEEKLY_LIMIT: &str = "weekly_limit";
|
|||||||
/// 映射到 `subscription.monthly`。
|
/// 映射到 `subscription.monthly`。
|
||||||
pub const TIER_MONTHLY: &str = "monthly";
|
pub const TIER_MONTHLY: &str = "monthly";
|
||||||
|
|
||||||
|
/// Codex 免费方案的 30 天(月)滚动窗口 tier 名。付费方案的次要窗口是 7 天
|
||||||
|
/// (`seven_day`),免费方案则是 30 天。由 `window_seconds_to_tier_name` 产出、
|
||||||
|
/// tray 的月分组渲染、前端 `TIER_I18N_KEYS` 映射到 `subscription.thirtyDay`
|
||||||
|
/// 三处共用同一标识。见 #3651。
|
||||||
|
pub const TIER_THIRTY_DAY: &str = "30_day";
|
||||||
|
|
||||||
/// Gemini 用量分组名称(按模型而非时间窗口)。`classify_gemini_model` 输出。
|
/// Gemini 用量分组名称(按模型而非时间窗口)。`classify_gemini_model` 输出。
|
||||||
pub const TIER_GEMINI_PRO: &str = "gemini_pro";
|
pub const TIER_GEMINI_PRO: &str = "gemini_pro";
|
||||||
pub const TIER_GEMINI_FLASH: &str = "gemini_flash";
|
pub const TIER_GEMINI_FLASH: &str = "gemini_flash";
|
||||||
@@ -632,8 +638,12 @@ struct CodexUsageResponse {
|
|||||||
/// 根据窗口秒数映射到 tier 名称(与 Claude 的命名兼容以复用前端 i18n)
|
/// 根据窗口秒数映射到 tier 名称(与 Claude 的命名兼容以复用前端 i18n)
|
||||||
fn window_seconds_to_tier_name(secs: i64) -> String {
|
fn window_seconds_to_tier_name(secs: i64) -> String {
|
||||||
match secs {
|
match secs {
|
||||||
18000 => "five_hour".to_string(),
|
18000 => TIER_FIVE_HOUR.to_string(),
|
||||||
604800 => "seven_day".to_string(),
|
604800 => TIER_SEVEN_DAY.to_string(),
|
||||||
|
// Codex 免费方案的 30 天窗口。显式映射到常量,与 tray 月分组、前端
|
||||||
|
// TIER_I18N_KEYS 保持同一标识(否则动态回退虽也得到 "30_day",但字符串
|
||||||
|
// 分散在多处、易和托盘/前端白名单脱节)。见 #3651。
|
||||||
|
2_592_000 => TIER_THIRTY_DAY.to_string(),
|
||||||
s => {
|
s => {
|
||||||
let hours = s / 3600;
|
let hours = s / 3600;
|
||||||
if hours >= 24 {
|
if hours >= 24 {
|
||||||
@@ -1340,3 +1350,21 @@ fn now_millis() -> i64 {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.as_millis() as i64
|
.as_millis() as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn window_seconds_map_to_expected_tier_names() {
|
||||||
|
// 官方特例窗口
|
||||||
|
assert_eq!(window_seconds_to_tier_name(18000), TIER_FIVE_HOUR);
|
||||||
|
assert_eq!(window_seconds_to_tier_name(604800), TIER_SEVEN_DAY);
|
||||||
|
// Codex 免费方案的次要窗口是 30 天(30 * 24 * 3600 = 2_592_000 秒)。
|
||||||
|
// 前端 TIER_I18N_KEYS 与 tray 月分组都需要认得 "30_day",见 #3651。
|
||||||
|
assert_eq!(window_seconds_to_tier_name(2_592_000), TIER_THIRTY_DAY);
|
||||||
|
// 其他窗口按小时/天回退命名
|
||||||
|
assert_eq!(window_seconds_to_tier_name(3600), "1_hour");
|
||||||
|
assert_eq!(window_seconds_to_tier_name(86400), "1_day");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+18
-3
@@ -19,8 +19,13 @@ const W_TIER_NAMES: &[&str] = &[
|
|||||||
crate::services::subscription::TIER_SEVEN_DAY_OPUS,
|
crate::services::subscription::TIER_SEVEN_DAY_OPUS,
|
||||||
crate::services::subscription::TIER_SEVEN_DAY_SONNET,
|
crate::services::subscription::TIER_SEVEN_DAY_SONNET,
|
||||||
];
|
];
|
||||||
// 火山方舟 Agent/Coding Plan 的月窗口(5h/周/月 三档)。
|
// 月窗口分组:火山方舟 Agent/Coding Plan 的月窗口(5h/周/月 三档),
|
||||||
const M_TIER_NAMES: &[&str] = &[crate::services::subscription::TIER_MONTHLY];
|
// 以及 Codex 免费方案的 30 天窗口(#3651)——两者都归入 "m" 档,避免免费
|
||||||
|
// Codex 账号在托盘里空白(前端 footer 能看到、托盘却不显示的不对称)。
|
||||||
|
const M_TIER_NAMES: &[&str] = &[
|
||||||
|
crate::services::subscription::TIER_MONTHLY,
|
||||||
|
crate::services::subscription::TIER_THIRTY_DAY,
|
||||||
|
];
|
||||||
const GEMINI_PRO_TIER_NAMES: &[&str] = &[crate::services::subscription::TIER_GEMINI_PRO];
|
const GEMINI_PRO_TIER_NAMES: &[&str] = &[crate::services::subscription::TIER_GEMINI_PRO];
|
||||||
const GEMINI_FLASH_TIER_NAMES: &[&str] = &[crate::services::subscription::TIER_GEMINI_FLASH];
|
const GEMINI_FLASH_TIER_NAMES: &[&str] = &[crate::services::subscription::TIER_GEMINI_FLASH];
|
||||||
const GEMINI_FLASH_LITE_TIER_NAMES: &[&str] =
|
const GEMINI_FLASH_LITE_TIER_NAMES: &[&str] =
|
||||||
@@ -882,7 +887,7 @@ mod tests {
|
|||||||
use crate::services::subscription::{
|
use crate::services::subscription::{
|
||||||
CredentialStatus, QuotaTier, SubscriptionQuota, TIER_FIVE_HOUR, TIER_GEMINI_FLASH,
|
CredentialStatus, QuotaTier, SubscriptionQuota, TIER_FIVE_HOUR, TIER_GEMINI_FLASH,
|
||||||
TIER_GEMINI_FLASH_LITE, TIER_GEMINI_PRO, TIER_MONTHLY, TIER_SEVEN_DAY, TIER_SEVEN_DAY_OPUS,
|
TIER_GEMINI_FLASH_LITE, TIER_GEMINI_PRO, TIER_MONTHLY, TIER_SEVEN_DAY, TIER_SEVEN_DAY_OPUS,
|
||||||
TIER_SEVEN_DAY_SONNET, TIER_WEEKLY_LIMIT,
|
TIER_SEVEN_DAY_SONNET, TIER_THIRTY_DAY, TIER_WEEKLY_LIMIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -964,6 +969,16 @@ mod tests {
|
|||||||
assert!(s.contains("l80%"), "expected l80% in {s}");
|
assert!(s.contains("l80%"), "expected l80% in {s}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn codex_summary_thirty_day_only_still_renders() {
|
||||||
|
// Codex 免费方案的唯一 tier 是 30 天窗口。前端 footer 已能显示(TIER_I18N_KEYS
|
||||||
|
// 有 "30_day"),托盘也必须能显示——否则就是这条不变量要防的非对称:footer
|
||||||
|
// 能看到、托盘却空白。30_day 归入 "m" 月分组。见 #3651。
|
||||||
|
let quota = make_quota("codex", true, vec![tier(TIER_THIRTY_DAY, 85.0)]);
|
||||||
|
let s = format_subscription_summary("a).expect("should format");
|
||||||
|
assert!(s.contains("m85%"), "expected m85% in {s}");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gemini_summary_emoji_reflects_highest_tier_including_lite() {
|
fn gemini_summary_emoji_reflects_highest_tier_including_lite() {
|
||||||
// lite 是利用率最高的那条 → emoji 必须是红色,不能被 pro/flash 掩盖。
|
// lite 是利用率最高的那条 → emoji 必须是红色,不能被 pro/flash 掩盖。
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ export const TIER_I18N_KEYS: Record<string, string> = {
|
|||||||
seven_day: "subscription.sevenDay",
|
seven_day: "subscription.sevenDay",
|
||||||
seven_day_opus: "subscription.sevenDayOpus",
|
seven_day_opus: "subscription.sevenDayOpus",
|
||||||
seven_day_sonnet: "subscription.sevenDaySonnet",
|
seven_day_sonnet: "subscription.sevenDaySonnet",
|
||||||
|
// Codex 免费方案的次要窗口是 30 天(付费方案为 7 天)
|
||||||
|
"30_day": "subscription.thirtyDay",
|
||||||
// Gemini 模型分类
|
// Gemini 模型分类
|
||||||
gemini_pro: "subscription.geminiPro",
|
gemini_pro: "subscription.geminiPro",
|
||||||
gemini_flash: "subscription.geminiFlash",
|
gemini_flash: "subscription.geminiFlash",
|
||||||
|
|||||||
@@ -2903,6 +2903,7 @@
|
|||||||
"sevenDay": "7-Day",
|
"sevenDay": "7-Day",
|
||||||
"sevenDayOpus": "7-Day (Opus)",
|
"sevenDayOpus": "7-Day (Opus)",
|
||||||
"sevenDaySonnet": "7-Day (Sonnet)",
|
"sevenDaySonnet": "7-Day (Sonnet)",
|
||||||
|
"thirtyDay": "30-Day",
|
||||||
"geminiPro": "Pro",
|
"geminiPro": "Pro",
|
||||||
"geminiFlash": "Flash",
|
"geminiFlash": "Flash",
|
||||||
"geminiFlashLite": "Flash Lite",
|
"geminiFlashLite": "Flash Lite",
|
||||||
|
|||||||
@@ -2903,6 +2903,7 @@
|
|||||||
"sevenDay": "7日間",
|
"sevenDay": "7日間",
|
||||||
"sevenDayOpus": "7日間(Opus)",
|
"sevenDayOpus": "7日間(Opus)",
|
||||||
"sevenDaySonnet": "7日間(Sonnet)",
|
"sevenDaySonnet": "7日間(Sonnet)",
|
||||||
|
"thirtyDay": "30日間",
|
||||||
"geminiPro": "Pro",
|
"geminiPro": "Pro",
|
||||||
"geminiFlash": "Flash",
|
"geminiFlash": "Flash",
|
||||||
"geminiFlashLite": "Flash Lite",
|
"geminiFlashLite": "Flash Lite",
|
||||||
|
|||||||
@@ -2875,6 +2875,7 @@
|
|||||||
"sevenDay": "7 天",
|
"sevenDay": "7 天",
|
||||||
"sevenDayOpus": "7 天 (Opus)",
|
"sevenDayOpus": "7 天 (Opus)",
|
||||||
"sevenDaySonnet": "7 天 (Sonnet)",
|
"sevenDaySonnet": "7 天 (Sonnet)",
|
||||||
|
"thirtyDay": "30 天",
|
||||||
"geminiPro": "Pro",
|
"geminiPro": "Pro",
|
||||||
"geminiFlash": "Flash",
|
"geminiFlash": "Flash",
|
||||||
"geminiFlashLite": "Flash Lite",
|
"geminiFlashLite": "Flash Lite",
|
||||||
|
|||||||
@@ -2903,6 +2903,7 @@
|
|||||||
"sevenDay": "7天",
|
"sevenDay": "7天",
|
||||||
"sevenDayOpus": "7天(Opus)",
|
"sevenDayOpus": "7天(Opus)",
|
||||||
"sevenDaySonnet": "7天(Sonnet)",
|
"sevenDaySonnet": "7天(Sonnet)",
|
||||||
|
"thirtyDay": "30天",
|
||||||
"geminiPro": "Pro",
|
"geminiPro": "Pro",
|
||||||
"geminiFlash": "Flash",
|
"geminiFlash": "Flash",
|
||||||
"geminiFlashLite": "Flash Lite",
|
"geminiFlashLite": "Flash Lite",
|
||||||
|
|||||||
Reference in New Issue
Block a user