用户:「安排对齐」。 ## 先量差距(不靠感觉) 鸿蒙侧的调色板与 WebUI **根本不同**:`#1A73E8`(Google 蓝)vs 品牌 `#2563EB`、 `#333333` vs slate-900 `#0F172A`、`#F5F7FA` vs `#F8FAFC`、`#FF4444` vs red-600… 共 217 处硬编码色值散在 7 个页面里。 功能面:鸿蒙是 收件箱/会话/联系人 三个 tab,**缺 发件箱 / 授权 / 日历 / 管理**, 也没有玻璃悬浮底栏、主题壁纸同步、Composer 共用组件。 ## 第一阶段(已完成并可验收) - `common/Theme.ets` 补齐文字/浅底/语义令牌,页面里的旧调色板**全量替换为令牌** (共 203 处),`hvigorw assembleHap` **BUILD SUCCESSFUL**。 - 判据:`cross-client-theme.test.mjs` 新增"鸿蒙页面里不得再出现旧调色板色值" (6 条全绿,含扰动自检)。这条防的是**新页面又随手写个"差不多"的颜色** —— 漂移就是这么开始的,而此前没有任何判据会红。 ## 计划文档:docs/HARMONY-ALIGN-PLAN.md 写清两件事,免得每轮重新猜"还差什么": - **差距表**(逐项,标出"缺页面/交互不同/观感不同"的性质); - **分期**:P2 发件箱(与收件箱同构,风险最低)→ P3 授权页(备注必须随决策送达模型 —— WebUI 侧踩过这个坑)→ P4 主题/壁纸同步(服务端"无记录"时以本地为准) → P5 玻璃悬浮导航 → P6 日历(最大,单独排)。 ## 如实说明 鸿蒙**视觉未验证**:本机 `hdc list targets` 为空、HAP 未签名 ⇒ 只能保证编译通过 + 令牌一致,观感需要设备或签名后由人眼确认。文档里也把这条写进"验收纪律"。
154 lines
4.9 KiB
Plaintext
154 lines
4.9 KiB
Plaintext
/*
|
|
* AgentMail 鸿蒙客户端 — 会话列表页
|
|
* GET /me/sessions 展示所有会话摘要
|
|
*/
|
|
import { ApiClient, ApiError } from '../api/ApiClient';
|
|
import { Theme } from '../common/Theme';
|
|
import { MailApi } from '../api/MailApi';
|
|
import { Session } from '../model/Models';
|
|
|
|
@Entry
|
|
@Component
|
|
struct SessionsPage {
|
|
@State sessions: Session[] = [];
|
|
@State loading: boolean = false;
|
|
@State error: string = '';
|
|
|
|
private client: ApiClient | null = null;
|
|
private mailApi: MailApi | null = null;
|
|
|
|
aboutToAppear(): void {
|
|
const ctx = this.getUIContext().getHostContext();
|
|
if (ctx !== undefined) {
|
|
const client: ApiClient = ApiClient.getInstance(ctx);
|
|
this.client = client;
|
|
this.mailApi = new MailApi(client);
|
|
this.loadSessions();
|
|
}
|
|
}
|
|
|
|
async loadSessions(): Promise<void> {
|
|
const m: MailApi | null = this.mailApi;
|
|
if (m === null) {
|
|
return;
|
|
}
|
|
this.loading = true;
|
|
this.error = '';
|
|
try {
|
|
const resp = await m.sessions();
|
|
this.sessions = resp.sessions;
|
|
} catch (e) {
|
|
const ae = e as ApiError;
|
|
this.error = ae.code === 0 ? ae.message : '加载失败';
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
}
|
|
|
|
build() {
|
|
Column() {
|
|
// 顶栏
|
|
Row() {
|
|
Text('会话')
|
|
.fontSize(20).fontWeight(FontWeight.Bold).fontColor(Theme.textPrimary)
|
|
}
|
|
.width('100%').height(56)
|
|
.padding({ left: 16 })
|
|
.backgroundColor(Theme.surface)
|
|
|
|
if (this.loading) {
|
|
Column() {
|
|
LoadingProgress().width(40).height(40)
|
|
Text('加载中…').fontSize(14).fontColor(Theme.textSubtle).margin({ top: 8 })
|
|
}
|
|
.width('100%').layoutWeight(1)
|
|
.justifyContent(FlexAlign.Center)
|
|
} else if (this.error.length > 0) {
|
|
Column() {
|
|
Text(this.error).fontSize(14).fontColor(Theme.danger)
|
|
Button('重试').margin({ top: 12 }).onClick(() => { this.loadSessions(); })
|
|
}
|
|
.width('100%').layoutWeight(1)
|
|
.justifyContent(FlexAlign.Center)
|
|
} else if (this.sessions.length === 0) {
|
|
Column() {
|
|
Text('📭 暂无会话').fontSize(16).fontColor(Theme.textSubtle)
|
|
}
|
|
.width('100%').layoutWeight(1)
|
|
.justifyContent(FlexAlign.Center)
|
|
} else {
|
|
List({ space: 1 }) {
|
|
ForEach(this.sessions, (s: Session) => {
|
|
ListItem() {
|
|
this.SessionItem(s)
|
|
}
|
|
.height(90)
|
|
}, (s: Session) => s.session_id)
|
|
}
|
|
.width('100%').layoutWeight(1)
|
|
.divider({ strokeWidth: 1, color: Theme.border, startMargin: 16, endMargin: 16 })
|
|
}
|
|
|
|
// 底栏
|
|
Row() {
|
|
Text('共 ' + this.sessions.length + ' 个会话').fontSize(12).fontColor(Theme.textSubtle)
|
|
}
|
|
.width('100%').height(40).padding({ left: 16 })
|
|
.backgroundColor(Theme.surface)
|
|
}
|
|
.width('100%').height('100%')
|
|
.backgroundColor(Theme.pageBg)
|
|
}
|
|
|
|
@Builder
|
|
SessionItem(s: Session) {
|
|
Row() {
|
|
Column() {
|
|
Row() {
|
|
Text(s.session_alias.length > 0 ? s.session_alias : s.subject)
|
|
.fontSize(14).fontWeight(FontWeight.Bold).fontColor(Theme.textPrimary)
|
|
.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 ? Theme.danger : Theme.textMuted)
|
|
.backgroundColor(s.used_rounds >= s.max_rounds ? Theme.dangerBg : Theme.surfaceMuted)
|
|
.borderRadius(4).padding({ left: 4, right: 4, top: 1, bottom: 1 })
|
|
}
|
|
|
|
// 未读
|
|
if (s.unread_count > 0) {
|
|
Text(s.unread_count + '')
|
|
.fontSize(11).fontColor(Theme.surface)
|
|
.backgroundColor(Theme.danger)
|
|
.borderRadius(10).width(20).height(20)
|
|
.textAlign(TextAlign.Center)
|
|
.margin({ left: 6 })
|
|
}
|
|
}
|
|
.width('100%')
|
|
|
|
Text('对方: ' + s.from_agent).fontSize(12).fontColor(Theme.textMuted).margin({ top: 4 })
|
|
|
|
Row() {
|
|
Text(s.permission_mode.length > 0 ? s.permission_mode : '—')
|
|
.fontSize(11).fontColor(Theme.textMuted)
|
|
.backgroundColor(Theme.border).borderRadius(4)
|
|
.padding({ left: 4, right: 4, top: 1, bottom: 1 })
|
|
Blank()
|
|
Text(s.mail_count + ' 封').fontSize(11).fontColor(Theme.textSubtle)
|
|
Text(' · ' + s.status).fontSize(11).fontColor(s.status === 'active' ? Theme.approve : Theme.textSubtle)
|
|
}
|
|
.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)
|
|
}
|
|
} |