SDK 里写得很清楚:`@ohos.promptAction.d.ts` 的全局 `showToast` 标着 `@deprecated since 18`, 替代品是 `UIContext.getPromptAction()`。仓库里有 23 处这种调用(6 个页面,历史遗留)—— 这一轮既然在按"用系统方案"整理鸿蒙侧,就一次扫干净,并加判据挡住回潮。 - `promptAction.showToast(...)` → `this.getUIContext().getPromptAction().showToast(...)`(23 处) - 清掉不再需要的 `promptAction` import(多个 → 只留 `router` 等) - 新增判据:不得再用全局写法。防的不是这次,而是**新增页面照抄旧代码**这条回退路径 —— 它编译照样通过、只在真机上行为不同。自检同时验"认得出旧写法"与"不误伤新写法"。 - 顺带把权限徽标那条"点它弹说明"的判据改成钉**非废弃**写法(原来是 `promptAction.showToast(`)。 变异验证:把 `SettingsPage` 的一处改回全局写法 → 判红并点出文件。 验证:`hvigorw assembleHap` BUILD SUCCESSFUL;`npm test` 退出码 0(harmony-logic 20 条)。
270 lines
9.7 KiB
Plaintext
270 lines
9.7 KiB
Plaintext
/*
|
||
* AgentMail 鸿蒙客户端 — 设置页(账号管理)
|
||
* 多账号列表 / 添加新账号 / 删除 / 切换默认账号
|
||
*/
|
||
import { ApiClient, ApiError } from '../api/ApiClient';
|
||
import { Theme } from '../common/Theme';
|
||
import { AuthApi } from '../api/AuthApi';
|
||
import { AccountManager, AccountInfo } from '../api/AccountManager';
|
||
import { SseService } from '../api/SseService';
|
||
|
||
@Entry
|
||
@Component
|
||
struct SettingsPage {
|
||
@State accounts: AccountInfo[] = [];
|
||
@State activeId: string = '';
|
||
@State showAddDialog: boolean = false;
|
||
@State newDisplayName: string = '';
|
||
@State newServer: string = '';
|
||
@State newUsername: string = '';
|
||
@State newToken: string = '';
|
||
@State adding: boolean = false;
|
||
|
||
private client: ApiClient | null = null;
|
||
private acctMgr: AccountManager | null = null;
|
||
|
||
aboutToAppear(): void {
|
||
const ctx = this.getUIContext().getHostContext();
|
||
if (ctx !== undefined) {
|
||
this.client = ApiClient.getInstance(ctx);
|
||
this.acctMgr = AccountManager.getInstance(ctx);
|
||
this.acctMgr.load().then(() => {
|
||
this.refreshList();
|
||
});
|
||
}
|
||
}
|
||
|
||
refreshList(): void {
|
||
const manager: AccountManager | null = this.acctMgr;
|
||
if (manager === null) {
|
||
return;
|
||
}
|
||
this.accounts = manager.getAccounts();
|
||
this.activeId = manager.getActiveId();
|
||
}
|
||
|
||
normalizeServer(server: string): string {
|
||
let normalized: string = server.trim();
|
||
while (normalized.length > 0 && normalized.endsWith('/')) {
|
||
normalized = normalized.substring(0, normalized.length - 1);
|
||
}
|
||
return normalized;
|
||
}
|
||
|
||
async switchTo(accountId: string): Promise<void> {
|
||
const manager: AccountManager | null = this.acctMgr;
|
||
const client: ApiClient | null = this.client;
|
||
if (manager === null || client === null) {
|
||
return;
|
||
}
|
||
const switched: boolean = await manager.switchAccount(accountId);
|
||
if (!switched) {
|
||
return;
|
||
}
|
||
const account: AccountInfo | null = manager.getActiveAccount();
|
||
if (account !== null) {
|
||
client.setBase(account.server);
|
||
client.setToken(account.token);
|
||
this.getUIContext().getPromptAction().showToast({ message: '默认发信账号已设为 ' + account.displayName });
|
||
}
|
||
this.refreshList();
|
||
}
|
||
|
||
async removeAccount(accountId: string): Promise<void> {
|
||
const manager: AccountManager | null = this.acctMgr;
|
||
const client: ApiClient | null = this.client;
|
||
if (manager === null) {
|
||
return;
|
||
}
|
||
const removed: boolean = await manager.removeAccount(accountId);
|
||
if (!removed) {
|
||
return;
|
||
}
|
||
SseService.getInstance().disconnectAccount(accountId);
|
||
const active: AccountInfo | null = manager.getActiveAccount();
|
||
if (client !== null) {
|
||
if (active !== null) {
|
||
client.setBase(active.server);
|
||
client.setToken(active.token);
|
||
} else {
|
||
client.setToken('');
|
||
}
|
||
}
|
||
this.refreshList();
|
||
this.getUIContext().getPromptAction().showToast({ message: '账号已删除' });
|
||
}
|
||
|
||
async addNewAccount(): Promise<void> {
|
||
const manager: AccountManager | null = this.acctMgr;
|
||
const ctx = this.getUIContext().getHostContext();
|
||
if (manager === null || ctx === undefined || this.adding) {
|
||
return;
|
||
}
|
||
const displayName: string = this.newDisplayName.trim();
|
||
const server: string = this.normalizeServer(this.newServer);
|
||
const token: string = this.newToken.trim();
|
||
const optionalUsername: string = this.newUsername.trim();
|
||
if (displayName.length === 0 || server.length === 0 || token.length === 0) {
|
||
this.getUIContext().getPromptAction().showToast({ message: '请填写显示名称、Gateway 地址和 user_key' });
|
||
return;
|
||
}
|
||
|
||
this.adding = true;
|
||
try {
|
||
const validationClient: ApiClient = new ApiClient(ctx);
|
||
validationClient.setBase(server);
|
||
validationClient.setToken(token);
|
||
const user = await new AuthApi(validationClient).me();
|
||
const username: string = optionalUsername.length > 0 ? optionalUsername : user.username;
|
||
const account: AccountInfo = await manager.addAccount(server, username, token, displayName);
|
||
SseService.getInstance().connectForAccount(account.id, account.server, account.token);
|
||
this.getUIContext().getPromptAction().showToast({ message: '✅ 添加成功: ' + account.displayName });
|
||
this.showAddDialog = false;
|
||
this.newDisplayName = '';
|
||
this.newServer = '';
|
||
this.newUsername = '';
|
||
this.newToken = '';
|
||
this.refreshList();
|
||
} catch (e) {
|
||
const apiError = e as ApiError;
|
||
this.getUIContext().getPromptAction().showToast({ message: '验证失败: ' + apiError.message });
|
||
} finally {
|
||
this.adding = false;
|
||
}
|
||
}
|
||
|
||
build() {
|
||
Column() {
|
||
Row() {
|
||
Text('‹').fontSize(24).fontColor(Theme.accent).width(40).height(40)
|
||
.textAlign(TextAlign.Center)
|
||
.onClick(() => { this.getUIContext().getRouter().back(); })
|
||
Text('账号管理').fontSize(16).fontWeight(FontWeight.Bold).fontColor(Theme.textPrimary)
|
||
.layoutWeight(1)
|
||
Text('+').fontSize(24).fontColor(Theme.accent).width(40).height(40)
|
||
.textAlign(TextAlign.Center)
|
||
.onClick(() => { this.showAddDialog = true; })
|
||
}
|
||
.width('100%').height(56).padding({ left: 8, right: 8 })
|
||
.backgroundColor(Theme.surface)
|
||
|
||
Divider().color(Theme.border)
|
||
|
||
if (this.accounts.length === 0) {
|
||
Column() {
|
||
Text('📭 暂无账号').fontSize(16).fontColor(Theme.textMuted)
|
||
Button('添加第一个账号')
|
||
.margin({ top: 16 }).backgroundColor(Theme.accent)
|
||
.onClick(() => { this.showAddDialog = true; })
|
||
}
|
||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||
} else {
|
||
List({ space: 1 }) {
|
||
ForEach(this.accounts, (account: AccountInfo) => {
|
||
ListItem() {
|
||
this.AccountItem(account)
|
||
}
|
||
.height(72)
|
||
}, (account: AccountInfo) => account.id)
|
||
}
|
||
.width('100%').layoutWeight(1)
|
||
.divider({ strokeWidth: 1, color: Theme.border, startMargin: 16, endMargin: 16 })
|
||
}
|
||
|
||
if (this.showAddDialog) {
|
||
Column() {
|
||
Column()
|
||
.width('100%').layoutWeight(1)
|
||
.backgroundColor(Theme.overlay)
|
||
.onClick(() => { this.showAddDialog = false; })
|
||
|
||
Column() {
|
||
Text('添加新账号').fontSize(16).fontWeight(FontWeight.Bold).fontColor(Theme.textPrimary)
|
||
.margin({ bottom: 16 })
|
||
|
||
TextInput({ placeholder: '显示名称(必填)', text: this.newDisplayName })
|
||
.width('100%').height(44).margin({ bottom: 10 })
|
||
.onChange((value: string) => { this.newDisplayName = value; })
|
||
|
||
TextInput({ placeholder: 'Gateway 地址(必填)', text: this.newServer })
|
||
.width('100%').height(44).margin({ bottom: 10 })
|
||
.onChange((value: string) => { this.newServer = value; })
|
||
|
||
TextInput({ placeholder: '用户名(可选)', text: this.newUsername })
|
||
.width('100%').height(44).margin({ bottom: 10 })
|
||
.onChange((value: string) => { this.newUsername = value; })
|
||
|
||
TextInput({ placeholder: 'user_key(必填)', text: this.newToken })
|
||
.width('100%').height(44).margin({ bottom: 16 })
|
||
.type(InputType.Password)
|
||
.onChange((value: string) => { this.newToken = value; })
|
||
|
||
Row() {
|
||
Button('取消')
|
||
.width(80).height(36).backgroundColor(Theme.surfaceMuted).fontColor(Theme.textMuted)
|
||
.onClick(() => { this.showAddDialog = false; })
|
||
Blank()
|
||
Button(this.adding ? '验证中…' : '添加')
|
||
.width(80).height(36).backgroundColor(Theme.accent)
|
||
.enabled(!this.adding)
|
||
.onClick(() => { this.addNewAccount(); })
|
||
}
|
||
.width('100%')
|
||
}
|
||
.width('100%').height('68%')
|
||
.padding(16).backgroundColor(Theme.surface)
|
||
.borderRadius({ topLeft: 12, topRight: 12 })
|
||
}
|
||
.width('100%').height('100%')
|
||
.position({ x: 0, y: 0 })
|
||
}
|
||
}
|
||
.width('100%').height('100%')
|
||
.backgroundColor(Theme.pageBg)
|
||
}
|
||
|
||
@Builder
|
||
AccountItem(account: AccountInfo) {
|
||
Row() {
|
||
Column() {
|
||
Row() {
|
||
Text(account.displayName)
|
||
.fontSize(15).fontWeight(FontWeight.Bold)
|
||
.fontColor(account.id === this.activeId ? Theme.accent : Theme.textPrimary)
|
||
if (account.id === this.activeId) {
|
||
Text(' 默认')
|
||
.fontSize(11).fontColor(Theme.accent)
|
||
.backgroundColor(Theme.accentSoft).borderRadius(4)
|
||
.padding({ left: 4, right: 4, top: 1, bottom: 1 })
|
||
.margin({ left: 6 })
|
||
}
|
||
}
|
||
.width('100%')
|
||
|
||
Text((account.username.length > 0 ? account.username + ' · ' : '') + account.server)
|
||
.fontSize(12).fontColor(Theme.textMuted)
|
||
.margin({ top: 3 })
|
||
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
|
||
}
|
||
.layoutWeight(1).height('100%')
|
||
.alignItems(HorizontalAlign.Start)
|
||
.justifyContent(FlexAlign.Center)
|
||
|
||
if (account.id !== this.activeId) {
|
||
Text('设为默认')
|
||
.fontSize(12).fontColor(Theme.accent)
|
||
.margin({ right: 12 })
|
||
.onClick(() => { this.switchTo(account.id); })
|
||
}
|
||
|
||
Text('删除')
|
||
.fontSize(12).fontColor(Theme.danger)
|
||
.onClick(() => { this.removeAccount(account.id); })
|
||
}
|
||
.width('100%').height('100%')
|
||
.padding({ left: 16, right: 16 })
|
||
.alignItems(VerticalAlign.Center)
|
||
.backgroundColor(account.id === this.activeId ? Theme.accentSoft : Theme.surface)
|
||
}
|
||
}
|