feat(app): login page with dev-token flow and profile with quota cards(F1)
登录页(LoginPage): - 品牌区 + 设备标识输入(随机生成一次并持久化到 preferences,可改可重生成) - 高级设置折叠区:展示/编辑 baseUrl(AuthStore.setBaseUrl),带格式校验与恢复默认 - 登录闭环:loading 态 → AuthStore.loginByDevToken → 成功 router.replaceUrl 首页; 失败 catch ApiError 用 ErrorBanner 展示 message+hint;已登录态进入直接跳首页 个人页(ProfilePage): - 用户 ID 脱敏(前 6 后 4)+ 登出(AlertDialog 确认 → AuthStore.logout → 回登录页) - agent_chat/tryon/report_basic 三配额卡并行拉取,进度条 used/(limit+bonus), 剩余数大字;周期文案:日配额=明日恢复、report_basic=一次性额度、月度=日期 - 最近流水(limit=10):tx_type 中文映射(消耗/退还/奖励),status 徽标配色区分 - Refresh 下拉刷新(加分项) 共享组件 components/f1/:ErrorBanner、QuotaCard、LedgerItem 偏差说明: - 设备标识在 @State 之外额外持久化(meida_login/device_key),保证跨启动稳定不重生 - Scroll 隐藏滚动条用 .scrollBar(BarState.Off)(本 SDK 无 scrollBarBarState 属性) - router.replaceUrl / AlertDialog.show 有 deprecation WARN,属规程指定路由方式,构建门禁通过
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* QuotaCardView(F1)—— 配额卡片:剩余数大字 + 进度条 + 周期文案。
|
||||
*
|
||||
* 数据契约(对齐后端 GET /api/v1/quota):
|
||||
* used / (limit_value + bonus_granted) 为进度;remaining 为剩余额度。
|
||||
* 周期文案由父层根据 quota_key + reset_at 算好传入(日=明日恢复/终身=一次性)。
|
||||
*/
|
||||
|
||||
@Component
|
||||
export struct QuotaCardView {
|
||||
@Prop title: string = ''
|
||||
@Prop remaining: number = 0
|
||||
@Prop used: number = 0
|
||||
@Prop total: number = 0
|
||||
@Prop resetText: string = ''
|
||||
@Prop loaded: boolean = false
|
||||
@Prop errorText: string = ''
|
||||
@Prop accent: string = '#C2185B'
|
||||
|
||||
build() {
|
||||
Column({ space: 6 }) {
|
||||
Text(this.title)
|
||||
.fontSize(13)
|
||||
.fontColor('#8A8A8A')
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
|
||||
if (!this.loaded) {
|
||||
LoadingProgress()
|
||||
.width(28)
|
||||
.height(28)
|
||||
.color('#CCCCCC')
|
||||
.margin({ top: 10, bottom: 14 })
|
||||
} else if (this.errorText !== '') {
|
||||
Text(this.errorText)
|
||||
.fontSize(13)
|
||||
.fontColor('#C0392B')
|
||||
.maxLines(2)
|
||||
.margin({ top: 6, bottom: 8 })
|
||||
.textAlign(TextAlign.Center)
|
||||
} else {
|
||||
Text(`${this.remaining}`)
|
||||
.fontSize(34)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.fontColor(this.accent)
|
||||
Text('剩余次数')
|
||||
.fontSize(11)
|
||||
.fontColor('#AAAAAA')
|
||||
Progress({ value: this.used, total: Math.max(this.total, 1), type: ProgressType.Linear })
|
||||
.width('100%')
|
||||
.height(6)
|
||||
.borderRadius(3)
|
||||
.color(this.accent)
|
||||
.backgroundColor('#F1E7EB')
|
||||
.margin({ top: 4 })
|
||||
Text(`已用 ${this.used}/${this.total}`)
|
||||
.fontSize(11)
|
||||
.fontColor('#999999')
|
||||
Text(this.resetText)
|
||||
.fontSize(10)
|
||||
.fontColor('#B3B3B3')
|
||||
.maxLines(1)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.padding(12)
|
||||
.borderRadius(16)
|
||||
.backgroundColor('#FFFFFF')
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user