605 lines
28 KiB
Java
605 lines
28 KiB
Java
package com.hyzq.boss;
|
||
|
||
import android.os.Bundle;
|
||
import android.text.InputType;
|
||
import android.widget.ArrayAdapter;
|
||
import android.widget.Button;
|
||
import android.widget.EditText;
|
||
import android.widget.LinearLayout;
|
||
import android.widget.Spinner;
|
||
|
||
import androidx.annotation.Nullable;
|
||
import androidx.appcompat.app.AlertDialog;
|
||
import androidx.appcompat.widget.SwitchCompat;
|
||
|
||
import org.json.JSONArray;
|
||
import org.json.JSONObject;
|
||
|
||
public class AiAccountsActivity extends BossScreenActivity {
|
||
private static final String[] ROLE_VALUES = {"primary", "backup", "api_fallback"};
|
||
private static final String[] ROLE_LABELS = {"主 GPT", "备用 GPT", "API 容灾"};
|
||
private static final String[] PROVIDER_VALUES = {"master_codex_node", "openai_api"};
|
||
private static final String[] PROVIDER_LABELS = {"Master Codex Node", "OpenAI API"};
|
||
|
||
@Override
|
||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
configureScreen("AI 账号", "OpenAI API / Master Codex Node");
|
||
setHeaderAction("新增", v -> openAccountEditor(null, null));
|
||
replaceContent();
|
||
reload();
|
||
}
|
||
|
||
@Override
|
||
protected void reload() {
|
||
setRefreshing(true);
|
||
executor.execute(() -> {
|
||
try {
|
||
BossApiClient.ApiResponse response = apiClient.getAccounts();
|
||
if (!response.ok()) throw new IllegalStateException(response.message());
|
||
runOnUiThread(() -> renderAccounts(response.json));
|
||
} catch (Exception error) {
|
||
runOnUiThread(() -> {
|
||
setRefreshing(false);
|
||
replaceContent(BossUi.buildEmptyCard(this, "AI 账号加载失败:" + error.getMessage()));
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
private void renderAccounts(JSONObject payload) {
|
||
JSONArray accounts = payload.optJSONArray("accounts");
|
||
JSONObject activeIdentity = payload.optJSONObject("activeIdentity");
|
||
replaceContent();
|
||
appendContent(BossUi.buildWechatMenuRow(
|
||
this,
|
||
"AI 账号",
|
||
"这里统一管理主 GPT、备用 GPT 与 API 容灾账号。",
|
||
"OpenAI API 可以在手机直接登录;Master Codex Node 仍然在绑定设备上完成登录。",
|
||
null,
|
||
null
|
||
));
|
||
appendContent(buildActiveIdentityCard(activeIdentity));
|
||
appendContent(buildOnboardingEntrySection());
|
||
appendContent(buildAccountsSection(accounts));
|
||
setRefreshing(false);
|
||
}
|
||
|
||
private LinearLayout buildActiveIdentityCard(@Nullable JSONObject activeIdentity) {
|
||
if (activeIdentity == null) {
|
||
return BossUi.buildWechatMenuRow(
|
||
this,
|
||
"当前主控身份",
|
||
"当前没有可用账号。",
|
||
"请先新增或启用一个账号。",
|
||
null,
|
||
null
|
||
);
|
||
}
|
||
String subtitle = activeIdentity.optString("label", "AI 账号")
|
||
+ " · " + activeIdentity.optString("displayName", "-");
|
||
String meta = activeIdentity.optString("roleLabel", "-")
|
||
+ " · " + activeIdentity.optString("providerLabel", "-")
|
||
+ " · " + activeIdentity.optString("statusLabel", "-");
|
||
return BossUi.buildWechatMenuRow(
|
||
this,
|
||
"当前主控身份",
|
||
subtitle,
|
||
meta,
|
||
null,
|
||
null
|
||
);
|
||
}
|
||
|
||
private LinearLayout buildAccountsSection(@Nullable JSONArray accounts) {
|
||
LinearLayout section = new LinearLayout(this);
|
||
section.setOrientation(LinearLayout.VERTICAL);
|
||
|
||
section.addView(BossUi.buildWechatMenuRow(
|
||
this,
|
||
"账号列表",
|
||
accounts == null || accounts.length() == 0 ? "当前还没有 AI 账号。" : "点开可编辑,按钮可激活、校验或删除。",
|
||
null,
|
||
null,
|
||
null
|
||
));
|
||
|
||
if (accounts == null || accounts.length() == 0) {
|
||
section.addView(BossUi.buildEmptyCard(this, "尚未配置任何 AI 账号。"));
|
||
return section;
|
||
}
|
||
|
||
for (int i = 0; i < accounts.length(); i++) {
|
||
JSONObject account = accounts.optJSONObject(i);
|
||
if (account == null) continue;
|
||
section.addView(buildAccountCard(account));
|
||
}
|
||
return section;
|
||
}
|
||
|
||
private LinearLayout buildOnboardingEntrySection() {
|
||
LinearLayout section = new LinearLayout(this);
|
||
section.setOrientation(LinearLayout.VERTICAL);
|
||
|
||
section.addView(BossUi.buildWechatMenuRow(
|
||
this,
|
||
"登录 OpenAI 平台账号",
|
||
"填写 API Key 后直接设为当前主控。",
|
||
"适合手机端直连主 Agent。",
|
||
"推荐",
|
||
v -> openOpenAiOnboardingDialog()
|
||
));
|
||
|
||
section.addView(BossUi.buildWechatMenuRow(
|
||
this,
|
||
"绑定电脑上的 Codex 节点",
|
||
"把这台 Mac 上的 Codex / ChatGPT Plus 节点接回主 Agent。",
|
||
"登录发生在绑定设备上。",
|
||
null,
|
||
v -> openMasterNodeOnboardingDialog()
|
||
));
|
||
|
||
return section;
|
||
}
|
||
|
||
private LinearLayout buildAccountCard(JSONObject account) {
|
||
String statusLabel = account.optString("statusLabel", account.optString("status", "-"));
|
||
String meta = account.optString("roleLabel", "-")
|
||
+ " · " + account.optString("providerLabel", "-")
|
||
+ " · " + statusLabel
|
||
+ (account.optBoolean("apiKeyConfigured") ? " · 已配置 Key" : "");
|
||
StringBuilder subtitle = new StringBuilder(account.optString("displayName", "-"));
|
||
if (!account.optString("accountIdentifier").isEmpty()) {
|
||
subtitle.append(" · ").append(account.optString("accountIdentifier", "-"));
|
||
}
|
||
if (!account.optString("nodeLabel").isEmpty()) {
|
||
subtitle.append(" · ").append(account.optString("nodeLabel", "-"));
|
||
}
|
||
|
||
LinearLayout card = new LinearLayout(this);
|
||
card.setOrientation(LinearLayout.VERTICAL);
|
||
card.addView(BossUi.buildWechatMenuRow(
|
||
this,
|
||
account.optString("label", "未命名账号"),
|
||
subtitle.toString(),
|
||
meta,
|
||
account.optBoolean("isActive") ? "当前" : null,
|
||
v -> openAccountEditor(account, null)
|
||
));
|
||
|
||
Button activate = BossUi.buildMiniActionButton(this, account.optBoolean("isActive") ? "当前主控" : "设为当前", !account.optBoolean("isActive"));
|
||
activate.setEnabled(!account.optBoolean("isActive"));
|
||
activate.setOnClickListener(v -> activateAccount(account));
|
||
|
||
Button loginGuide = null;
|
||
if ("master_codex_node".equals(account.optString("provider"))) {
|
||
loginGuide = BossUi.buildMiniActionButton(this, "登录指引", false);
|
||
loginGuide.setOnClickListener(v -> showMasterNodeLoginGuide(account));
|
||
}
|
||
|
||
Button validate = BossUi.buildMiniActionButton(this, "校验连接", false);
|
||
validate.setOnClickListener(v -> validateAccount(account));
|
||
|
||
Button delete = BossUi.buildMiniActionButton(this, "删除账号", false);
|
||
delete.setOnClickListener(v -> confirmDeleteAccount(account));
|
||
card.addView(loginGuide == null
|
||
? BossUi.buildInlineActionRow(this, activate, validate, delete)
|
||
: BossUi.buildInlineActionRow(this, activate, loginGuide, validate, delete));
|
||
|
||
return card;
|
||
}
|
||
|
||
private void showMasterNodeLoginGuide(JSONObject account) {
|
||
String nodeLabel = account.optString("nodeLabel");
|
||
if (nodeLabel == null || nodeLabel.trim().isEmpty()) {
|
||
nodeLabel = account.optString("nodeId");
|
||
}
|
||
if (nodeLabel == null || nodeLabel.trim().isEmpty()) {
|
||
nodeLabel = "绑定设备";
|
||
}
|
||
|
||
String message = "主 GPT 不在手机里直接登录。\n\n"
|
||
+ "请到绑定设备 " + nodeLabel + " 上打开 Codex / ChatGPT Plus 会话完成登录。\n"
|
||
+ "登录完成后,回到这里点“校验连接”,确认主 Agent relay 已经接通。";
|
||
|
||
new AlertDialog.Builder(this)
|
||
.setTitle("主 GPT 登录指引")
|
||
.setMessage(message)
|
||
.setPositiveButton("知道了", null)
|
||
.show();
|
||
}
|
||
|
||
private void openOpenAiOnboardingDialog() {
|
||
final EditText labelInput = BossUi.buildInput(this, "标签,例如 主 GPT", false);
|
||
labelInput.setText("主 GPT");
|
||
final EditText displayNameInput = BossUi.buildInput(this, "显示名称", false);
|
||
displayNameInput.setText("OpenAI 平台账号");
|
||
final EditText accountIdentifierInput = BossUi.buildInput(this, "账号标识 / 备注", false);
|
||
final EditText modelInput = BossUi.buildInput(this, "模型,例如 gpt-5.4", false);
|
||
modelInput.setText("gpt-5.4");
|
||
final EditText apiKeyInput = BossUi.buildInput(this, "OpenAI API Key", false);
|
||
apiKeyInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||
|
||
LinearLayout form = new LinearLayout(this);
|
||
form.setOrientation(LinearLayout.VERTICAL);
|
||
form.addView(BossUi.buildFormCell(this, "标签", "建议使用 主 GPT", labelInput));
|
||
form.addView(BossUi.buildFormCell(this, "显示名称", "会展示在账号列表中", displayNameInput));
|
||
form.addView(BossUi.buildFormCell(this, "账号标识", "可填邮箱、账号名或自定义备注", accountIdentifierInput));
|
||
form.addView(BossUi.buildFormCell(this, "模型", "例如 gpt-5.4", modelInput));
|
||
form.addView(BossUi.buildFormCell(this, "API Key", "填写后会直接登录并设为当前主控", apiKeyInput));
|
||
|
||
new AlertDialog.Builder(this)
|
||
.setTitle("登录 OpenAI 平台账号")
|
||
.setMessage("手机端直接输入 OpenAI API Key,登录成功后立即设为当前主控。")
|
||
.setView(form)
|
||
.setNegativeButton("取消", null)
|
||
.setPositiveButton("登录", (dialog, which) -> submitOpenAiOnboarding(
|
||
labelInput.getText().toString().trim(),
|
||
displayNameInput.getText().toString().trim(),
|
||
accountIdentifierInput.getText().toString().trim(),
|
||
modelInput.getText().toString().trim(),
|
||
apiKeyInput.getText().toString().trim()
|
||
))
|
||
.show();
|
||
}
|
||
|
||
private void openMasterNodeOnboardingDialog() {
|
||
final EditText labelInput = BossUi.buildInput(this, "标签,例如 主 GPT", false);
|
||
labelInput.setText("主 GPT");
|
||
final EditText displayNameInput = BossUi.buildInput(this, "显示名称", false);
|
||
displayNameInput.setText("绑定电脑上的 Codex 节点");
|
||
final EditText accountIdentifierInput = BossUi.buildInput(this, "账号标识 / 备注", false);
|
||
final EditText nodeIdInput = BossUi.buildInput(this, "节点 ID", false);
|
||
final EditText nodeLabelInput = BossUi.buildInput(this, "节点名称", false);
|
||
final EditText modelInput = BossUi.buildInput(this, "模型,例如 gpt-5.4", false);
|
||
modelInput.setText("gpt-5.4");
|
||
|
||
LinearLayout form = new LinearLayout(this);
|
||
form.setOrientation(LinearLayout.VERTICAL);
|
||
form.addView(BossUi.buildFormCell(this, "标签", "建议使用 主 GPT", labelInput));
|
||
form.addView(BossUi.buildFormCell(this, "显示名称", "会展示在账号列表中", displayNameInput));
|
||
form.addView(BossUi.buildFormCell(this, "账号标识", "可填账号名或自定义备注", accountIdentifierInput));
|
||
form.addView(BossUi.buildFormCell(this, "节点 ID", "本机 Codex 节点的唯一标识", nodeIdInput));
|
||
form.addView(BossUi.buildFormCell(this, "节点名称", "例如 Mac Studio", nodeLabelInput));
|
||
form.addView(BossUi.buildFormCell(this, "模型", "例如 gpt-5.4", modelInput));
|
||
|
||
new AlertDialog.Builder(this)
|
||
.setTitle("绑定电脑上的 Codex 节点")
|
||
.setMessage("主 GPT 不在手机里直接登录,请在绑定设备上的 Codex / ChatGPT Plus 会话里登录后再回来校验。")
|
||
.setView(form)
|
||
.setNegativeButton("取消", null)
|
||
.setPositiveButton("绑定", (dialog, which) -> submitMasterNodeOnboarding(
|
||
labelInput.getText().toString().trim(),
|
||
displayNameInput.getText().toString().trim(),
|
||
accountIdentifierInput.getText().toString().trim(),
|
||
nodeIdInput.getText().toString().trim(),
|
||
nodeLabelInput.getText().toString().trim(),
|
||
modelInput.getText().toString().trim()
|
||
))
|
||
.show();
|
||
}
|
||
|
||
private void submitOpenAiOnboarding(
|
||
String label,
|
||
String displayName,
|
||
String accountIdentifier,
|
||
String model,
|
||
String apiKey
|
||
) {
|
||
if (label.isEmpty() || displayName.isEmpty() || apiKey.isEmpty()) {
|
||
showMessage("标签、显示名称和 API Key 不能为空");
|
||
return;
|
||
}
|
||
setRefreshing(true);
|
||
executor.execute(() -> {
|
||
try {
|
||
JSONObject payload = new JSONObject();
|
||
payload.put("label", label);
|
||
payload.put("displayName", displayName);
|
||
payload.put("accountIdentifier", accountIdentifier);
|
||
payload.put("model", model);
|
||
payload.put("apiKey", apiKey);
|
||
payload.put("enabled", true);
|
||
payload.put("setActive", true);
|
||
payload.put("provider", "openai_api");
|
||
payload.put("role", "primary");
|
||
|
||
BossApiClient.ApiResponse response = apiClient.onboardOpenAiApiAccount(payload);
|
||
if (!response.ok()) throw new IllegalStateException(response.message());
|
||
|
||
String accountId = extractAccountId(response.json);
|
||
if (accountId.isEmpty()) {
|
||
runOnUiThread(() -> {
|
||
showMessage("OpenAI 平台账号已登录,并设为当前主控。");
|
||
reload();
|
||
});
|
||
return;
|
||
}
|
||
|
||
BossApiClient.ApiResponse validation = apiClient.validateAccount(accountId);
|
||
runOnUiThread(() -> {
|
||
showMessage(validation.ok()
|
||
? validation.message()
|
||
: "登录完成,但校验失败:" + validation.message());
|
||
reload();
|
||
});
|
||
} catch (Exception error) {
|
||
runOnUiThread(() -> {
|
||
setRefreshing(false);
|
||
showMessage("登录失败:" + error.getMessage());
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
private void submitMasterNodeOnboarding(
|
||
String label,
|
||
String displayName,
|
||
String accountIdentifier,
|
||
String nodeId,
|
||
String nodeLabel,
|
||
String model
|
||
) {
|
||
if (label.isEmpty() || displayName.isEmpty() || nodeId.isEmpty()) {
|
||
showMessage("标签、显示名称和节点 ID 不能为空");
|
||
return;
|
||
}
|
||
setRefreshing(true);
|
||
executor.execute(() -> {
|
||
try {
|
||
JSONObject payload = new JSONObject();
|
||
payload.put("label", label);
|
||
payload.put("displayName", displayName);
|
||
payload.put("accountIdentifier", accountIdentifier);
|
||
payload.put("nodeId", nodeId);
|
||
payload.put("nodeLabel", nodeLabel);
|
||
payload.put("model", model);
|
||
payload.put("enabled", true);
|
||
payload.put("setActive", true);
|
||
payload.put("provider", "master_codex_node");
|
||
payload.put("role", "primary");
|
||
|
||
BossApiClient.ApiResponse response = apiClient.onboardMasterNodeAccount(payload);
|
||
if (!response.ok()) throw new IllegalStateException(response.message());
|
||
|
||
String accountId = extractAccountId(response.json);
|
||
if (accountId.isEmpty()) {
|
||
runOnUiThread(() -> {
|
||
showMessage("Master Codex Node 已绑定,并设为当前主控。");
|
||
reload();
|
||
});
|
||
return;
|
||
}
|
||
|
||
BossApiClient.ApiResponse validation = apiClient.validateAccount(accountId);
|
||
runOnUiThread(() -> {
|
||
showMessage(validation.ok()
|
||
? validation.message()
|
||
: "绑定完成,但校验失败:" + validation.message());
|
||
reload();
|
||
});
|
||
} catch (Exception error) {
|
||
runOnUiThread(() -> {
|
||
setRefreshing(false);
|
||
showMessage("绑定失败:" + error.getMessage());
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
private String extractAccountId(JSONObject json) {
|
||
if (json == null) {
|
||
return "";
|
||
}
|
||
String accountId = json.optString("accountId", "");
|
||
if (!accountId.isEmpty()) {
|
||
return accountId;
|
||
}
|
||
JSONObject account = json.optJSONObject("account");
|
||
if (account != null) {
|
||
return account.optString("accountId", "");
|
||
}
|
||
return "";
|
||
}
|
||
|
||
private void openAccountEditor(@Nullable JSONObject existing, @Nullable String apiKeyHint) {
|
||
final android.widget.EditText labelInput = BossUi.buildInput(this, "标签,例如 主 GPT", false);
|
||
final android.widget.EditText displayNameInput = BossUi.buildInput(this, "显示名称", false);
|
||
final android.widget.EditText accountIdentifierInput = BossUi.buildInput(this, "账号标识 / 邮箱 / 登录名", false);
|
||
final android.widget.EditText nodeIdInput = BossUi.buildInput(this, "节点 ID", false);
|
||
final android.widget.EditText nodeLabelInput = BossUi.buildInput(this, "节点名称", false);
|
||
final android.widget.EditText modelInput = BossUi.buildInput(this, "模型,例如 gpt-5.4", false);
|
||
final android.widget.EditText apiKeyInput = BossUi.buildInput(this, "API Key", false);
|
||
final android.widget.EditText loginStatusInput = BossUi.buildInput(this, "登录状态备注", true);
|
||
final Spinner roleSpinner = new Spinner(this);
|
||
roleSpinner.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, ROLE_LABELS));
|
||
final Spinner providerSpinner = new Spinner(this);
|
||
providerSpinner.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, PROVIDER_LABELS));
|
||
final SwitchCompat enabledSwitch = new SwitchCompat(this);
|
||
enabledSwitch.setText("启用");
|
||
enabledSwitch.setChecked(existing == null || existing.optBoolean("enabled", true));
|
||
final SwitchCompat setActiveSwitch = new SwitchCompat(this);
|
||
setActiveSwitch.setText("保存后设为当前主控");
|
||
setActiveSwitch.setChecked(existing != null ? existing.optBoolean("isActive") : false);
|
||
|
||
if (existing != null) {
|
||
labelInput.setText(existing.optString("label", ""));
|
||
displayNameInput.setText(existing.optString("displayName", ""));
|
||
accountIdentifierInput.setText(existing.optString("accountIdentifier", ""));
|
||
nodeIdInput.setText(existing.optString("nodeId", ""));
|
||
nodeLabelInput.setText(existing.optString("nodeLabel", ""));
|
||
modelInput.setText(existing.optString("model", ""));
|
||
loginStatusInput.setText(existing.optString("loginStatusNote", ""));
|
||
roleSpinner.setSelection(indexOf(ROLE_VALUES, existing.optString("role", "primary")));
|
||
providerSpinner.setSelection(indexOf(PROVIDER_VALUES, existing.optString("provider", "master_codex_node")));
|
||
}
|
||
if (apiKeyHint != null && !apiKeyHint.isEmpty()) {
|
||
apiKeyInput.setText(apiKeyHint);
|
||
}
|
||
|
||
LinearLayout form = new LinearLayout(this);
|
||
form.setOrientation(LinearLayout.VERTICAL);
|
||
form.addView(BossUi.buildFormCell(this, "标签", "例如 主 GPT", labelInput));
|
||
form.addView(BossUi.buildFormCell(this, "显示名称", "会展示在账号列表中", displayNameInput));
|
||
form.addView(BossUi.buildFormCell(this, "账号标识", "邮箱、登录名或备注信息", accountIdentifierInput));
|
||
form.addView(BossUi.buildFormCell(this, "节点 ID", "Master Codex Node 的唯一标识", nodeIdInput));
|
||
form.addView(BossUi.buildFormCell(this, "节点名称", "用于快速识别节点", nodeLabelInput));
|
||
form.addView(BossUi.buildFormCell(this, "模型", "例如 gpt-5.4", modelInput));
|
||
form.addView(BossUi.buildFormCell(this, "API Key", "仅 OpenAI API 模式需要", apiKeyInput));
|
||
form.addView(BossUi.buildFormCell(this, "登录状态备注", "可记录 Plus、有无风控等状态", loginStatusInput));
|
||
form.addView(BossUi.buildFormCell(this, "账号角色", null, roleSpinner));
|
||
form.addView(BossUi.buildFormCell(this, "提供方", null, providerSpinner));
|
||
form.addView(BossUi.buildFormCell(this, "启用状态", null, enabledSwitch));
|
||
form.addView(BossUi.buildFormCell(this, "保存后动作", null, setActiveSwitch));
|
||
|
||
new AlertDialog.Builder(this)
|
||
.setTitle(existing == null ? "新增 AI 账号" : "编辑 AI 账号")
|
||
.setView(form)
|
||
.setNegativeButton("取消", null)
|
||
.setPositiveButton("保存", (dialog, which) -> saveAccount(
|
||
existing,
|
||
labelInput.getText().toString().trim(),
|
||
displayNameInput.getText().toString().trim(),
|
||
accountIdentifierInput.getText().toString().trim(),
|
||
nodeIdInput.getText().toString().trim(),
|
||
nodeLabelInput.getText().toString().trim(),
|
||
modelInput.getText().toString().trim(),
|
||
apiKeyInput.getText().toString().trim(),
|
||
loginStatusInput.getText().toString().trim(),
|
||
enabledSwitch.isChecked(),
|
||
setActiveSwitch.isChecked(),
|
||
ROLE_VALUES[roleSpinner.getSelectedItemPosition()],
|
||
PROVIDER_VALUES[providerSpinner.getSelectedItemPosition()]
|
||
))
|
||
.show();
|
||
}
|
||
|
||
private void saveAccount(
|
||
@Nullable JSONObject existing,
|
||
String label,
|
||
String displayName,
|
||
String accountIdentifier,
|
||
String nodeId,
|
||
String nodeLabel,
|
||
String model,
|
||
String apiKey,
|
||
String loginStatusNote,
|
||
boolean enabled,
|
||
boolean setActive,
|
||
String role,
|
||
String provider
|
||
) {
|
||
if (label.isEmpty() || displayName.isEmpty()) {
|
||
showMessage("标签和显示名称不能为空");
|
||
return;
|
||
}
|
||
setRefreshing(true);
|
||
executor.execute(() -> {
|
||
try {
|
||
JSONObject payload = new JSONObject();
|
||
payload.put("label", label);
|
||
payload.put("displayName", displayName);
|
||
payload.put("accountIdentifier", accountIdentifier);
|
||
payload.put("nodeId", nodeId);
|
||
payload.put("nodeLabel", nodeLabel);
|
||
payload.put("model", model);
|
||
payload.put("apiKey", apiKey);
|
||
payload.put("loginStatusNote", loginStatusNote);
|
||
payload.put("enabled", enabled);
|
||
payload.put("setActive", setActive);
|
||
payload.put("role", role);
|
||
payload.put("provider", provider);
|
||
|
||
BossApiClient.ApiResponse response = existing == null
|
||
? apiClient.createAccount(payload)
|
||
: apiClient.updateAccount(existing.optString("accountId"), payload);
|
||
if (!response.ok()) throw new IllegalStateException(response.message());
|
||
runOnUiThread(() -> {
|
||
showMessage(existing == null ? "AI 账号已新增" : "AI 账号已更新");
|
||
reload();
|
||
});
|
||
} catch (Exception error) {
|
||
runOnUiThread(() -> {
|
||
setRefreshing(false);
|
||
showMessage("保存失败:" + error.getMessage());
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
private int indexOf(String[] values, String target) {
|
||
for (int i = 0; i < values.length; i++) {
|
||
if (values[i].equals(target)) {
|
||
return i;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
private void activateAccount(JSONObject account) {
|
||
setRefreshing(true);
|
||
executor.execute(() -> {
|
||
try {
|
||
BossApiClient.ApiResponse response = apiClient.activateAccount(account.optString("accountId"), "原生页面手动切换");
|
||
if (!response.ok()) throw new IllegalStateException(response.message());
|
||
runOnUiThread(() -> {
|
||
showMessage("已切换当前主控");
|
||
reload();
|
||
});
|
||
} catch (Exception error) {
|
||
runOnUiThread(() -> {
|
||
setRefreshing(false);
|
||
showMessage("切换失败:" + error.getMessage());
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
private void validateAccount(JSONObject account) {
|
||
setRefreshing(true);
|
||
executor.execute(() -> {
|
||
try {
|
||
BossApiClient.ApiResponse response = apiClient.validateAccount(account.optString("accountId"));
|
||
if (!response.ok()) throw new IllegalStateException(response.message());
|
||
runOnUiThread(() -> {
|
||
showMessage(response.message());
|
||
reload();
|
||
});
|
||
} catch (Exception error) {
|
||
runOnUiThread(() -> {
|
||
setRefreshing(false);
|
||
showMessage("校验失败:" + error.getMessage());
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
private void confirmDeleteAccount(JSONObject account) {
|
||
new AlertDialog.Builder(this)
|
||
.setTitle("删除 AI 账号")
|
||
.setMessage("确认删除 " + account.optString("label", "该账号") + " 吗?")
|
||
.setNegativeButton("取消", null)
|
||
.setPositiveButton("删除", (dialog, which) -> deleteAccount(account))
|
||
.show();
|
||
}
|
||
|
||
private void deleteAccount(JSONObject account) {
|
||
setRefreshing(true);
|
||
executor.execute(() -> {
|
||
try {
|
||
BossApiClient.ApiResponse response = apiClient.deleteAccount(account.optString("accountId"));
|
||
if (!response.ok()) throw new IllegalStateException(response.message());
|
||
runOnUiThread(() -> {
|
||
showMessage("AI 账号已删除");
|
||
reload();
|
||
});
|
||
} catch (Exception error) {
|
||
runOnUiThread(() -> {
|
||
setRefreshing(false);
|
||
showMessage("删除失败:" + error.getMessage());
|
||
});
|
||
}
|
||
});
|
||
}
|
||
}
|