Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions apps/src-tauri/src/commands/account/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,59 @@ pub async fn service_account_warmup(
rpc_call_in_background("account/warmup", addr, Some(params)).await
}

/// 函数 `service_account_test_start`
///
/// 作者: gaohongshun
///
/// 时间: 2026-08-26
///
/// # 参数
/// - addr: 参数 addr
/// - account_id: 参数 account_id
/// - model: 参数 model
/// - prompt: 参数 prompt
/// - kind: 参数 kind
///
/// # 返回
/// 返回函数执行结果
#[tauri::command]
pub async fn service_account_test_start(
addr: Option<String>,
account_id: String,
model: Option<String>,
prompt: Option<String>,
kind: Option<String>,
) -> Result<serde_json::Value, String> {
let params = serde_json::json!({
"accountId": account_id,
"model": model,
"prompt": prompt,
"kind": kind,
});
rpc_call_in_background("account/test", addr, Some(params)).await
}

/// 函数 `service_account_test_cancel`
///
/// 作者: gaohongshun
///
/// 时间: 2026-08-26
///
/// # 参数
/// - addr: 参数 addr
/// - account_id: 参数 account_id
///
/// # 返回
/// 返回函数执行结果
#[tauri::command]
pub async fn service_account_test_cancel(
addr: Option<String>,
account_id: String,
) -> Result<serde_json::Value, String> {
let params = serde_json::json!({ "accountId": account_id });
rpc_call_in_background("account/test/cancel", addr, Some(params)).await
}

#[tauri::command]
pub async fn service_account_proxy_get(
addr: Option<String>,
Expand Down
2 changes: 2 additions & 0 deletions apps/src-tauri/src/commands/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ macro_rules! invoke_handler {
crate::commands::account::remote::service_account_update,
crate::commands::account::remote::service_account_update_sorts,
crate::commands::account::remote::service_account_warmup,
crate::commands::account::remote::service_account_test_start,
crate::commands::account::remote::service_account_test_cancel,
crate::commands::account::remote::service_account_proxy_get,
crate::commands::account::remote::service_account_proxy_set,
crate::commands::account::remote::service_account_proxy_clear,
Expand Down
7 changes: 7 additions & 0 deletions apps/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use app_shell::{
};

const USAGE_REFRESH_COMPLETED_EVENT: &str = "usage-refresh-completed";
const ACCOUNT_TEST_EVENT: &str = "account-test-event";
#[cfg(target_os = "linux")]
const AYATANA_APPINDICATOR_LOG_DOMAIN: &str = "libayatana-appindicator";
#[cfg(target_os = "linux")]
Expand Down Expand Up @@ -209,6 +210,12 @@ pub fn run() {
log::warn!("emit usage refresh completed event failed: {}", err);
}
});
let account_test_event_app = app.handle().clone();
codexmanager_service::set_account_test_event_handler(move |event| {
if let Err(err) = account_test_event_app.emit(ACCOUNT_TEST_EVENT, &event) {
log::warn!("emit account test event failed: {}", err);
}
});
if let Err(err) = setup_tray(app.handle()) {
TRAY_AVAILABLE.store(false, std::sync::atomic::Ordering::Relaxed);
CLOSE_TO_TRAY_ON_CLOSE.store(false, std::sync::atomic::Ordering::Relaxed);
Expand Down
20 changes: 20 additions & 0 deletions apps/src/app/accounts/accounts-page-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
import { AddAccountModal } from "@/components/modals/add-account-modal";
import { AccountResetCreditControl } from "@/components/account-reset-credit-control";
import { ConfirmDialog } from "@/components/modals/confirm-dialog";
import { AccountTestModal } from "@/components/modals/account-test-modal";
import UsageModal from "@/components/modals/usage-modal";
import { Button, buttonVariants } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
Expand Down Expand Up @@ -160,6 +161,10 @@ export interface AccountsPageViewProps {
proxySourceDraft: AccountProxySource;
proxyProfileIdDraft: string;
proxyUrlDraft: string;
accountTestAccount: Account | null;
openAccountTest: (account: Account) => void;
handleAccountTestOpenChange: (open: boolean) => void;
onAccountTestFinished: (accountId: string) => void;
selectedAccount: Account | null;
accountEditorState: AccountEditorState | null;
deleteDialogState: DeleteDialogState;
Expand Down Expand Up @@ -375,6 +380,7 @@ export function AccountsPageView(props: AccountsPageViewProps) {
importByFile,
importByDirectory,
refreshAccount,
onAccountTestFinished,
clearPreferredAccount,
setPreferredAccount,
toggleAccountStatus,
Expand Down Expand Up @@ -548,6 +554,14 @@ export function AccountsPageView(props: AccountsPageViewProps) {
<Network className="h-4 w-4" />
{t("账号代理")}
</DropdownMenuItem>
<DropdownMenuItem
className="gap-2"
disabled={!isServiceReady}
onClick={() => props.openAccountTest(account)}
>
<Zap className="h-4 w-4" />
{t("测试账号")}
</DropdownMenuItem>
<DropdownMenuItem
className="gap-2"
disabled={
Expand Down Expand Up @@ -1560,6 +1574,12 @@ export function AccountsPageView(props: AccountsPageViewProps) {
</DialogFooter>
</DialogContent>
</Dialog>
<AccountTestModal
account={props.accountTestAccount}
open={isPageActive && Boolean(props.accountTestAccount)}
onOpenChange={props.handleAccountTestOpenChange}
onFinished={onAccountTestFinished}
/>
<ConfirmDialog
open={isPageActive && Boolean(deleteDialogState)}
onOpenChange={(open) => {
Expand Down
34 changes: 34 additions & 0 deletions apps/src/app/accounts/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export default function AccountsPage() {
refreshAllAccountRt,
refreshAllAccounts,
refreshAccountList,
refreshAccountsSilently,
deleteAccount,
deleteManyAccounts,
cleanupAccountsByStatuses,
Expand Down Expand Up @@ -141,6 +142,19 @@ export default function AccountsPage() {
useState<AccountProxySource>("custom");
const [proxyProfileIdDraft, setProxyProfileIdDraft] = useState("");
const [proxyUrlDraft, setProxyUrlDraft] = useState("");
const [accountTestAccountId, setAccountTestAccountId] = useState<string | null>(
null,
);
const [accountTestAccountSnapshot, setAccountTestAccountSnapshot] =
useState<Account | null>(null);
// 从最新账号列表派生弹窗里的账号,测试结束后状态徽章可自动刷新;
// 列表短暂重取时回退到快照,避免弹窗闪烁关闭。
const accountTestAccount = useMemo(
() =>
accounts.find((account) => account.id === accountTestAccountId) ??
accountTestAccountSnapshot,
[accounts, accountTestAccountId, accountTestAccountSnapshot],
);

const [accountEditorState, setAccountEditorState] =
useState<AccountEditorState | null>(null);
Expand Down Expand Up @@ -556,6 +570,22 @@ const toggleCleanupStatus = (rawStatus: string) => {
setProxyUrlDraft("");
};

const openAccountTest = (account: Account) => {
setAccountTestAccountId(account.id);
setAccountTestAccountSnapshot(account);
};

const handleAccountTestOpenChange = (open: boolean) => {
if (open) return;
setAccountTestAccountId(null);
setAccountTestAccountSnapshot(null);
};

// 测试结束后静默刷新账号状态(不弹「账号用量已刷新」),让弹窗徽章与列表同步。
const handleAccountTestFinished = () => {
void refreshAccountsSilently();
};

const handleTestProxySettings = async () => {
if (!proxyDialogAccount) return;
try {
Expand Down Expand Up @@ -877,6 +907,7 @@ const toggleCleanupStatus = (rawStatus: string) => {
proxyDialogAccount={proxyDialogAccount}
proxySettings={proxySettings}
proxyProfiles={proxyProfiles}
accountTestAccount={accountTestAccount}
isProxySettingsLoading={isProxySettingsLoading}
proxyEnabledDraft={proxyEnabledDraft}
proxySourceDraft={proxySourceDraft}
Expand Down Expand Up @@ -949,6 +980,9 @@ const toggleCleanupStatus = (rawStatus: string) => {
handleDeleteSingle={handleDeleteSingle}
openProxyDialog={openProxyDialog}
handleProxyDialogOpenChange={handleProxyDialogOpenChange}
openAccountTest={openAccountTest}
handleAccountTestOpenChange={handleAccountTestOpenChange}
onAccountTestFinished={handleAccountTestFinished}
handleSaveProxySettings={handleSaveProxySettings}
handleClearProxySettings={handleClearProxySettings}
handleTestProxySettings={handleTestProxySettings}
Expand Down
Loading
Loading