diff --git a/src/account.rs b/src/account.rs index a3adaa5..186007b 100644 --- a/src/account.rs +++ b/src/account.rs @@ -97,36 +97,36 @@ fn print_accounts(store: &Store, json: bool) -> Result<()> { println!("没有保存的账号。可使用 `cdxs import auth` 导入。"); return Ok(()); } - println!( - "{:<3} {:<22} {:<34} {:<10} {:<12} {}", - "", "ID", "Email", "Mode", "Plan", "Quota" - ); - for account in &store.accounts { + print_account_table_border(); + print_account_table_row("", "ID", "Email", "Mode", "Plan", "5h", "Week"); + print_account_table_border(); + let current_account_id = store.meta.current_account_id.as_deref(); + let mut accounts = store.accounts.iter().collect::>(); + accounts.sort_by_key(|account| { + if Some(account.id.as_str()) == current_account_id { + 0 + } else { + 1 + } + }); + for account in accounts { let current = if store.meta.current_account_id.as_deref() == Some(account.id.as_str()) { "*" } else { "" }; - let quota = account - .quota - .as_ref() - .map(|q| { - format!( - "5h={}%, weekly={}%", - q.primary_remaining_percent, q.secondary_remaining_percent - ) - }) - .unwrap_or_else(|| "-".to_string()); - println!( - "{:<3} {:<22} {:<34} {:<10} {:<12} {}", + let (primary_quota, secondary_quota) = format_quota_cells(account); + print_account_table_row( current, - shorten(&account.id, 22), - shorten(&account.email, 34), + &account.id, + &account.email, auth_file::account_auth_mode_name(account), account.plan_type.as_deref().unwrap_or("-"), - quota + &primary_quota, + &secondary_quota, ); } + print_account_table_border(); Ok(()) } @@ -633,6 +633,103 @@ fn format_quota(account: &Account) -> String { .unwrap_or_else(|| "-".to_string()) } +fn format_quota_cells(account: &Account) -> (String, String) { + let Some(quota) = account.quota.as_ref() else { + return ("-".to_string(), "-".to_string()); + }; + ( + format_quota_cell( + quota.primary_remaining_percent, + quota.primary_reset_time, + format_reset_time, + ), + format_quota_cell( + quota.secondary_remaining_percent, + quota.secondary_reset_time, + format_week_reset_time, + ), + ) +} + +fn format_quota_cell( + remaining_percent: i32, + reset_time: Option, + format_reset: fn(i64) -> String, +) -> String { + format!( + "{:>3}% / {}", + remaining_percent, + reset_time + .map(format_reset) + .unwrap_or_else(|| "-".to_string()) + ) +} + +fn format_reset_time(reset_time: i64) -> String { + let now = Utc::now().timestamp(); + let seconds = reset_time.saturating_sub(now); + if seconds <= 0 { + return "now".to_string(); + } + + let days = seconds / 86_400; + let hours = (seconds % 86_400) / 3_600; + let minutes = (seconds % 3_600) / 60; + if days > 0 { + format!("{days}d{hours}h") + } else if hours > 0 { + format!("{hours}h{minutes:02}m") + } else { + format!("{minutes}m") + } +} + +fn format_week_reset_time(reset_time: i64) -> String { + let now = Utc::now().timestamp(); + let seconds = reset_time.saturating_sub(now); + if seconds <= 0 { + return "now".to_string(); + } + + let days = seconds / 86_400; + let hours = (seconds % 86_400) / 3_600; + format!("{days}d{hours:02}h") +} + +fn print_account_table_border() { + println!( + "+{}+{}+{}+{}+{}+{}+{}+", + "-".repeat(3), + "-".repeat(24), + "-".repeat(30), + "-".repeat(8), + "-".repeat(8), + "-".repeat(14), + "-".repeat(14) + ); +} + +fn print_account_table_row( + marker: &str, + id: &str, + email: &str, + mode: &str, + plan: &str, + primary_quota: &str, + secondary_quota: &str, +) { + println!( + "| {:<1} | {:<22} | {:<28} | {:<6} | {:<6} | {:<12} | {:<12} |", + shorten(marker, 1), + shorten(id, 22), + shorten(email, 28), + shorten(mode, 6), + shorten(plan, 6), + shorten(primary_quota, 12), + shorten(secondary_quota, 12) + ); +} + fn shorten(value: &str, width: usize) -> String { if value.chars().count() <= width { return value.to_string();