chore: directory migration - gateway→server, web→client/electron
This commit is contained in:
648
client/harmony/entry/src/main/ets/pages/MainPage.ets
Normal file
648
client/harmony/entry/src/main/ets/pages/MainPage.ets
Normal file
@ -0,0 +1,648 @@
|
||||
/*
|
||||
* AgentMail 鸿蒙客户端 — 主框架(底部 Tab 导航)
|
||||
* 收件箱 / 会话 / 联系人 三个 TabContent
|
||||
*/
|
||||
import { ApiClient, ApiError } from '../api/ApiClient';
|
||||
import { MailApi, InboxResponse } from '../api/MailApi';
|
||||
import { AccountManager, AccountInfo } from '../api/AccountManager';
|
||||
import { SseService, SseEvent } from '../api/SseService';
|
||||
import { MailSummary, Session, Contact } from '../model/Models';
|
||||
import { MailDetailParams, ComposeParams } from '../model/RouteParams';
|
||||
import { promptAction } from '@kit.ArkUI';
|
||||
|
||||
@Component
|
||||
struct InboxTab {
|
||||
@State mails: MailSummary[] = [];
|
||||
@State loading: boolean = false;
|
||||
@State total: number = 0;
|
||||
@State unread: number = 0;
|
||||
@State error: string = '';
|
||||
@State accountName: string = '';
|
||||
@State accountFilter: string = 'all'; // 'all' 或 accountId
|
||||
@State showAccountPicker: boolean = false;
|
||||
@State accountList: AccountInfo[] = [];
|
||||
private sseService: SseService | null = null;
|
||||
|
||||
aboutToAppear(): void {
|
||||
const ctx = this.getUIContext().getHostContext();
|
||||
if (ctx !== undefined) {
|
||||
this.sseService = SseService.getInstance();
|
||||
// 加载账号列表
|
||||
const acctMgr: AccountManager = AccountManager.getInstance(ctx);
|
||||
acctMgr.load().then(() => {
|
||||
const active = acctMgr.getActiveAccount();
|
||||
if (active !== null) {
|
||||
this.accountName = active.displayName;
|
||||
}
|
||||
this.accountList = acctMgr.getAccounts();
|
||||
if (this.accountList.length <= 1) {
|
||||
this.accountFilter = 'all';
|
||||
}
|
||||
});
|
||||
this.loadData();
|
||||
// 全局 SSE 监听(所有账号的事件都会收到);保存同一函数引用以便页面退出时移除。
|
||||
this.sseService.addListener(this.onSseEvent);
|
||||
}
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
if (this.sseService !== null) {
|
||||
this.sseService.removeListener(this.onSseEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private onSseEvent = (event: SseEvent): void => {
|
||||
if (event.type === 'new_mail') {
|
||||
let sourceName: string = '';
|
||||
for (let i = 0; i < this.accountList.length; i++) {
|
||||
if (this.accountList[i].id === event.accountId) {
|
||||
sourceName = this.accountList[i].displayName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
promptAction.showToast({ message: sourceName.length > 0 ? '📨 ' + sourceName + ' 收到新邮件' : '📨 新邮件到达' });
|
||||
this.loadData();
|
||||
}
|
||||
};
|
||||
|
||||
async loadData(): Promise<void> {
|
||||
const ctx = this.getUIContext().getHostContext();
|
||||
if (ctx === undefined) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.error = '';
|
||||
try {
|
||||
const acctMgr: AccountManager = AccountManager.getInstance(ctx);
|
||||
await acctMgr.load();
|
||||
const allAccounts: AccountInfo[] = acctMgr.getAccounts();
|
||||
this.accountList = allAccounts;
|
||||
|
||||
let filterExists: boolean = this.accountFilter === 'all';
|
||||
for (let i = 0; i < allAccounts.length; i++) {
|
||||
if (allAccounts[i].id === this.accountFilter) {
|
||||
filterExists = true;
|
||||
this.accountName = allAccounts[i].displayName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!filterExists) {
|
||||
this.accountFilter = 'all';
|
||||
this.accountName = '全部邮箱';
|
||||
}
|
||||
|
||||
const mergedMails: MailSummary[] = [];
|
||||
let mergedTotal: number = 0;
|
||||
|
||||
for (let i = 0; i < allAccounts.length; i++) {
|
||||
const acct: AccountInfo = allAccounts[i];
|
||||
if (this.accountFilter !== 'all' && this.accountFilter !== acct.id) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const accountClient: ApiClient = new ApiClient(ctx);
|
||||
accountClient.setBase(acct.server);
|
||||
accountClient.setToken(acct.token);
|
||||
const response: InboxResponse = await new MailApi(accountClient).inbox('all', 50);
|
||||
for (let j = 0; j < response.mails.length; j++) {
|
||||
const mail: MailSummary = response.mails[j];
|
||||
mail.source_account_id = acct.id;
|
||||
mail.source_account_name = acct.displayName;
|
||||
mergedMails.push(mail);
|
||||
}
|
||||
mergedTotal += response.total;
|
||||
} catch (e) {
|
||||
if (this.accountFilter !== 'all') {
|
||||
throw e as ApiError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mergedMails.sort((a: MailSummary, b: MailSummary) => {
|
||||
if (a.created_at > b.created_at) {
|
||||
return -1;
|
||||
}
|
||||
if (a.created_at < b.created_at) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
this.mails = mergedMails;
|
||||
this.total = mergedTotal;
|
||||
|
||||
let unreadCount: number = 0;
|
||||
for (let i = 0; i < this.mails.length; i++) {
|
||||
if (this.mails[i].status === 'unread') {
|
||||
unreadCount++;
|
||||
}
|
||||
}
|
||||
this.unread = unreadCount;
|
||||
} catch (e) {
|
||||
const ae = e as ApiError;
|
||||
this.error = ae.message.length > 0 ? ae.message : '加载失败';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
openCompose(): void {
|
||||
let accountId: string = this.accountFilter === 'all' ? '' : this.accountFilter;
|
||||
if (accountId.length === 0) {
|
||||
const ctx = this.getUIContext().getHostContext();
|
||||
if (ctx !== undefined) {
|
||||
accountId = AccountManager.getInstance(ctx).getActiveId();
|
||||
}
|
||||
}
|
||||
const params: ComposeParams = {
|
||||
to: '',
|
||||
reply_to: '',
|
||||
session_alias: '',
|
||||
account_id: accountId
|
||||
};
|
||||
this.getUIContext().getRouter().pushUrl({ url: 'pages/ComposePage', params: params });
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Row() {
|
||||
Column() {
|
||||
Row() {
|
||||
Text('收件箱').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#333333')
|
||||
if (this.accountList.length > 1) {
|
||||
Text(' ▾').fontSize(14).fontColor('#999999')
|
||||
.onClick(() => { this.showAccountPicker = !this.showAccountPicker; })
|
||||
}
|
||||
}
|
||||
Text(this.accountFilter === 'all' ? '全部邮箱' : this.accountName)
|
||||
.fontSize(11).fontColor('#999999').margin({ top: 2 })
|
||||
.onClick(() => { if (this.accountList.length > 1) { this.showAccountPicker = !this.showAccountPicker; } })
|
||||
}
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
Blank()
|
||||
if (this.unread > 0) {
|
||||
Text(this.unread + ' 未读')
|
||||
.fontSize(13).fontColor('#FFFFFF')
|
||||
.backgroundColor('#FF4444')
|
||||
.borderRadius(10)
|
||||
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
|
||||
}
|
||||
Text('⚙')
|
||||
.fontSize(20).fontColor('#666666')
|
||||
.width(36).height(36).textAlign(TextAlign.Center)
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({ url: 'pages/SettingsPage' });
|
||||
})
|
||||
}
|
||||
.width('100%').height(56).padding({ left: 16, right: 8 })
|
||||
.backgroundColor('#FFFFFF')
|
||||
|
||||
// 账号选择器下拉
|
||||
if (this.showAccountPicker && this.accountList.length > 1) {
|
||||
Column() {
|
||||
Text('全部邮箱')
|
||||
.fontSize(14).fontColor(this.accountFilter === 'all' ? '#1A73E8' : '#333333')
|
||||
.fontWeight(this.accountFilter === 'all' ? FontWeight.Bold : FontWeight.Normal)
|
||||
.width('100%').height(40).padding({ left: 16 })
|
||||
.backgroundColor(this.accountFilter === 'all' ? '#F0F7FF' : '#FFFFFF')
|
||||
.onClick(() => {
|
||||
this.accountFilter = 'all';
|
||||
this.accountName = '全部邮箱';
|
||||
this.showAccountPicker = false;
|
||||
this.loadData();
|
||||
})
|
||||
ForEach(this.accountList, (acct: AccountInfo) => {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(acct.displayName)
|
||||
.fontSize(14)
|
||||
.fontColor(this.accountFilter === acct.id ? '#1A73E8' : '#333333')
|
||||
.fontWeight(this.accountFilter === acct.id ? FontWeight.Bold : FontWeight.Normal)
|
||||
Text(acct.username)
|
||||
.fontSize(11).fontColor('#999999')
|
||||
}
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.layoutWeight(1)
|
||||
}
|
||||
.width('100%').height(48).padding({ left: 16 })
|
||||
.backgroundColor(this.accountFilter === acct.id ? '#F0F7FF' : '#FFFFFF')
|
||||
.onClick(() => {
|
||||
this.accountFilter = acct.id;
|
||||
this.accountName = acct.displayName;
|
||||
this.showAccountPicker = false;
|
||||
this.loadData();
|
||||
})
|
||||
}, (acct: AccountInfo) => acct.id)
|
||||
}
|
||||
.width('100%')
|
||||
.backgroundColor('#FFFFFF')
|
||||
.border({ width: { bottom: 1 }, color: '#EEEEEE' })
|
||||
}
|
||||
|
||||
if (this.loading) {
|
||||
Column() {
|
||||
LoadingProgress().width(40).height(40)
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else if (this.error.length > 0) {
|
||||
Column() {
|
||||
Text(this.error).fontSize(14).fontColor('#FF4444')
|
||||
Button('重试').margin({ top: 12 }).onClick(() => { this.loadData(); })
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else if (this.mails.length === 0) {
|
||||
Column() {
|
||||
Text('📭 收件箱为空').fontSize(16).fontColor('#999999')
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else {
|
||||
List({ space: 1 }) {
|
||||
ForEach(this.mails, (mail: MailSummary) => {
|
||||
ListItem() {
|
||||
this.MailItem(mail)
|
||||
}
|
||||
.height(80)
|
||||
.backgroundColor(mail.status === 'unread' ? '#F0F7FF' : '#FFFFFF')
|
||||
.onClick(() => {
|
||||
const params: MailDetailParams = {
|
||||
mail_id: mail.mail_id,
|
||||
account_id: mail.source_account_id
|
||||
};
|
||||
this.getUIContext().getRouter().pushUrl({
|
||||
url: 'pages/MailDetailPage',
|
||||
params: params
|
||||
});
|
||||
})
|
||||
}, (mail: MailSummary) => mail.source_account_id + ':' + mail.mail_id)
|
||||
}
|
||||
.width('100%').layoutWeight(1)
|
||||
.divider({ strokeWidth: 1, color: '#EEEEEE', startMargin: 16, endMargin: 16 })
|
||||
}
|
||||
|
||||
// 底部信息栏 + 悬浮写邮件按钮
|
||||
Stack({ alignContent: Alignment.BottomEnd }) {
|
||||
Row() {
|
||||
Text('共 ' + this.total + ' 封').fontSize(12).fontColor('#999999')
|
||||
Blank()
|
||||
Text('未读 ' + this.unread).fontSize(12).fontColor('#999999')
|
||||
}
|
||||
.width('100%').height(36).padding({ left: 16, right: 16 })
|
||||
.backgroundColor('#FFFFFF')
|
||||
|
||||
Text('+')
|
||||
.fontSize(28).fontColor('#FFFFFF')
|
||||
.width(56).height(56)
|
||||
.borderRadius(28)
|
||||
.backgroundColor('#1A73E8')
|
||||
.textAlign(TextAlign.Center)
|
||||
.margin({ right: 20, bottom: 44 })
|
||||
.onClick(() => {
|
||||
this.openCompose();
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.width('100%').height('100%')
|
||||
.backgroundColor('#F5F7FA')
|
||||
.bindSheet($$this.composeVisible, this.ComposeSheet())
|
||||
}
|
||||
|
||||
@State composeVisible: boolean = false;
|
||||
|
||||
@Builder
|
||||
ComposeSheet() {
|
||||
Column() {
|
||||
Text('写邮件').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#333333')
|
||||
.margin({ top: 16, bottom: 8 })
|
||||
Button('新建邮件')
|
||||
.width('90%').height(44).backgroundColor('#1A73E8')
|
||||
.onClick(() => {
|
||||
this.composeVisible = false;
|
||||
this.openCompose();
|
||||
})
|
||||
Button('取消')
|
||||
.width('90%').height(40).backgroundColor('#F5F5F5').fontColor('#666666')
|
||||
.margin({ top: 8 })
|
||||
.onClick(() => { this.composeVisible = false; })
|
||||
}
|
||||
.width('100%').height(180).padding(16)
|
||||
}
|
||||
|
||||
@Builder
|
||||
MailItem(mail: MailSummary) {
|
||||
Row() {
|
||||
Column() {
|
||||
if (mail.status === 'unread') {
|
||||
Circle({ width: 8, height: 8 }).fill('#1A73E8')
|
||||
}
|
||||
}
|
||||
.width(20).height('100%').justifyContent(FlexAlign.Center)
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text(mail.from_name).fontSize(14).fontWeight(mail.status === 'unread' ? FontWeight.Bold : FontWeight.Normal).fontColor('#333333')
|
||||
if (this.accountFilter === 'all' && mail.source_account_name.length > 0) {
|
||||
Text(mail.source_account_name)
|
||||
.fontSize(10).fontColor('#1A73E8')
|
||||
.backgroundColor('#E8F0FE').borderRadius(4)
|
||||
.padding({ left: 5, right: 5, top: 1, bottom: 1 })
|
||||
.margin({ left: 6 })
|
||||
}
|
||||
Blank()
|
||||
Text(mail.created_at).fontSize(11).fontColor('#999999')
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
Text(mail.subject).fontSize(13).fontColor('#333333')
|
||||
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.margin({ top: 2 })
|
||||
Text(mail.body_preview).fontSize(12).fontColor('#999999')
|
||||
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.margin({ top: 2 })
|
||||
}
|
||||
.layoutWeight(1).height('100%')
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.padding({ left: 8 })
|
||||
|
||||
if (mail.permission_mode.length > 0) {
|
||||
Text(mail.permission_mode)
|
||||
.fontSize(10).fontColor('#666666')
|
||||
.backgroundColor('#EEEEEE').borderRadius(4)
|
||||
.padding({ left: 4, right: 4, top: 1, bottom: 1 })
|
||||
}
|
||||
}
|
||||
.width('100%').height('100%')
|
||||
.padding({ left: 12, right: 12 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
struct SessionsTab {
|
||||
@State sessions: Session[] = [];
|
||||
@State loading: boolean = false;
|
||||
@State error: string = '';
|
||||
private mailApi: MailApi | null = null;
|
||||
|
||||
aboutToAppear(): void {
|
||||
const ctx = this.getUIContext().getHostContext();
|
||||
if (ctx !== undefined) {
|
||||
this.mailApi = new MailApi(ApiClient.getInstance(ctx));
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
|
||||
async loadData(): Promise<void> {
|
||||
const m: MailApi | null = this.mailApi;
|
||||
if (m === null) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const resp = await m.sessions();
|
||||
this.sessions = resp.sessions;
|
||||
} catch (e) {
|
||||
const ae = e as ApiError;
|
||||
this.error = ae.message.length > 0 ? ae.message : '加载失败';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Row() {
|
||||
Text('会话').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#333333')
|
||||
}
|
||||
.width('100%').height(56).padding({ left: 16 })
|
||||
.backgroundColor('#FFFFFF')
|
||||
|
||||
if (this.loading) {
|
||||
Column() {
|
||||
LoadingProgress().width(40).height(40)
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else if (this.error.length > 0) {
|
||||
Column() {
|
||||
Text(this.error).fontSize(14).fontColor('#FF4444')
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else if (this.sessions.length === 0) {
|
||||
Column() {
|
||||
Text('📭 暂无会话').fontSize(16).fontColor('#999999')
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else {
|
||||
List({ space: 1 }) {
|
||||
ForEach(this.sessions, (s: Session, idx: number) => {
|
||||
ListItem() {
|
||||
this.SessionItem(s, idx)
|
||||
}
|
||||
.height(90)
|
||||
}, (_s: Session, idx: number) => idx.toString())
|
||||
}
|
||||
.width('100%').layoutWeight(1)
|
||||
.divider({ strokeWidth: 1, color: '#EEEEEE', startMargin: 16, endMargin: 16 })
|
||||
}
|
||||
}
|
||||
.width('100%').height('100%')
|
||||
.backgroundColor('#F5F7FA')
|
||||
}
|
||||
|
||||
@Builder
|
||||
SessionItem(s: Session, idx: number) {
|
||||
Row() {
|
||||
Column() {
|
||||
Row() {
|
||||
Text(s.session_alias.length > 0 ? s.session_alias : ('会话 #' + (idx + 1)))
|
||||
.fontSize(14).fontWeight(FontWeight.Bold).fontColor('#333333')
|
||||
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.layoutWeight(1)
|
||||
if (s.max_rounds > 0) {
|
||||
Text(s.used_rounds + '/' + s.max_rounds)
|
||||
.fontSize(11).fontColor(s.used_rounds >= s.max_rounds ? '#FF4444' : '#666666')
|
||||
.backgroundColor(s.used_rounds >= s.max_rounds ? '#FFEBEE' : '#F5F5F5')
|
||||
.borderRadius(4).padding({ left: 4, right: 4, top: 1, bottom: 1 })
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
Text('对方: ' + s.from_agent).fontSize(12).fontColor('#666666').margin({ top: 4 })
|
||||
|
||||
Row() {
|
||||
Text(s.permission_mode.length > 0 ? s.permission_mode : '—')
|
||||
.fontSize(11).fontColor('#666666')
|
||||
.backgroundColor('#F0F0F0').borderRadius(4)
|
||||
.padding({ left: 4, right: 4, top: 1, bottom: 1 })
|
||||
Blank()
|
||||
Text(s.mail_count + ' 封').fontSize(11).fontColor('#999999')
|
||||
Text(' · ' + s.status).fontSize(11).fontColor(s.status === 'active' ? '#4CAF50' : '#999999')
|
||||
}
|
||||
.width('100%').margin({ top: 4 })
|
||||
}
|
||||
.layoutWeight(1).height('100%')
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.justifyContent(FlexAlign.SpaceBetween)
|
||||
}
|
||||
.width('100%').height('100%')
|
||||
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
struct ContactsTab {
|
||||
@State contacts: Contact[] = [];
|
||||
@State loading: boolean = false;
|
||||
@State error: string = '';
|
||||
private mailApi: MailApi | null = null;
|
||||
|
||||
aboutToAppear(): void {
|
||||
const ctx = this.getUIContext().getHostContext();
|
||||
if (ctx !== undefined) {
|
||||
this.mailApi = new MailApi(ApiClient.getInstance(ctx));
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
|
||||
async loadData(): Promise<void> {
|
||||
const m: MailApi | null = this.mailApi;
|
||||
if (m === null) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
try {
|
||||
const resp = await m.contacts();
|
||||
this.contacts = resp.contacts;
|
||||
} catch (e) {
|
||||
const ae = e as ApiError;
|
||||
this.error = ae.message.length > 0 ? ae.message : '加载失败';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Row() {
|
||||
Text('联系人').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#333333')
|
||||
}
|
||||
.width('100%').height(56).padding({ left: 16 })
|
||||
.backgroundColor('#FFFFFF')
|
||||
|
||||
if (this.loading) {
|
||||
Column() {
|
||||
LoadingProgress().width(40).height(40)
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else if (this.error.length > 0) {
|
||||
Column() {
|
||||
Text(this.error).fontSize(14).fontColor('#FF4444')
|
||||
Button('重试').margin({ top: 12 }).onClick(() => { this.loadData(); })
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else if (this.contacts.length === 0) {
|
||||
Column() {
|
||||
Text('📭 暂无联系人').fontSize(16).fontColor('#999999')
|
||||
}
|
||||
.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)
|
||||
} else {
|
||||
List({ space: 1 }) {
|
||||
ForEach(this.contacts, (c: Contact, idx: number) => {
|
||||
ListItem() {
|
||||
this.ContactItem(c, idx)
|
||||
}
|
||||
.height(85)
|
||||
}, (_c: Contact, idx: number) => idx.toString())
|
||||
}
|
||||
.width('100%').layoutWeight(1)
|
||||
.divider({ strokeWidth: 1, color: '#EEEEEE', startMargin: 16, endMargin: 16 })
|
||||
}
|
||||
}
|
||||
.width('100%').height('100%')
|
||||
.backgroundColor('#F5F7FA')
|
||||
}
|
||||
|
||||
@Builder
|
||||
ContactItem(c: Contact, idx: number) {
|
||||
Row() {
|
||||
Column() {
|
||||
Row() {
|
||||
Text(c.agent_name).fontSize(14).fontWeight(FontWeight.Bold).fontColor('#333333')
|
||||
Blank()
|
||||
if (c.unread_count > 0) {
|
||||
Text(c.unread_count + '')
|
||||
.fontSize(11).fontColor('#FFFFFF')
|
||||
.backgroundColor('#FF4444')
|
||||
.borderRadius(10).width(20).height(20)
|
||||
.textAlign(TextAlign.Center)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
Text(c.subject.length > 0 ? c.subject : c.session_alias)
|
||||
.fontSize(12).fontColor('#666666')
|
||||
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.margin({ top: 3 })
|
||||
|
||||
Row() {
|
||||
Text(c.permission_mode.length > 0 ? c.permission_mode : '—')
|
||||
.fontSize(10).fontColor('#666666')
|
||||
.backgroundColor('#F0F0F0').borderRadius(4)
|
||||
.padding({ left: 4, right: 4, top: 1, bottom: 1 })
|
||||
Blank()
|
||||
Text(c.last_preview.length > 0 ? c.last_preview : '—')
|
||||
.fontSize(11).fontColor('#999999')
|
||||
.maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.layoutWeight(1)
|
||||
}
|
||||
.width('100%').margin({ top: 3 })
|
||||
}
|
||||
.layoutWeight(1).height('100%')
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.justifyContent(FlexAlign.SpaceBetween)
|
||||
}
|
||||
.width('100%').height('100%')
|
||||
.padding({ left: 16, right: 16, top: 10, bottom: 10 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
}
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct MainPage {
|
||||
@State currentIndex: number = 0;
|
||||
|
||||
@Builder
|
||||
TabBarBuilder(title: string, icon: string) {
|
||||
Column() {
|
||||
Text(icon).fontSize(20)
|
||||
Text(title).fontSize(11).fontColor(this.currentIndex === 0 ? '#1A73E8' : '#666666')
|
||||
}
|
||||
.width('100%')
|
||||
.justifyContent(FlexAlign.Center)
|
||||
}
|
||||
|
||||
build() {
|
||||
Tabs({ barPosition: BarPosition.End }) {
|
||||
TabContent() {
|
||||
InboxTab()
|
||||
}
|
||||
.tabBar(this.TabBarBuilder('收件箱', '📬'))
|
||||
|
||||
TabContent() {
|
||||
SessionsTab()
|
||||
}
|
||||
.tabBar(this.TabBarBuilder('会话', '💬'))
|
||||
|
||||
TabContent() {
|
||||
ContactsTab()
|
||||
}
|
||||
.tabBar(this.TabBarBuilder('联系人', '👤'))
|
||||
}
|
||||
.onChange((index: number) => {
|
||||
this.currentIndex = index;
|
||||
})
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user