feat(app): 任务换额度+端侧埋点+试穿限次+报告反馈预约卡+网络错误态——PM/开发双Agent迭代2-3

- 新增 core/Tracker.ets:埋点唯一入口,事件名正则校验,preferences 队列(≥20立即/
  30s节流/后台flush,每批50,上限200丢最旧),PII 键剔除,失败静默;首批10点位
- 新增 core/DailyLimiter.ets:试穿/试戴各3次/日本地软限制,自然日重置,失败不计数;
  setBonus 支持服务端 bonus_granted 加成,「做任务多换几次」真兑现
- 新增 components/f1/TaskBonusPanel.ets + core/TaskBonusState.ets:签到真实 claim
  链路,40910/40310 处理,已领态面板与报告页互通;个人中心与对话耗尽态接入
- 报告页:维度「准/不准」反馈卡(DimensionCard 无网络走回调)+ 静默 claim
  report_feedback 闭环;全面报告预约留资卡(card_view/reserve_result 埋点)
- 新增 components/f2/NetworkBanner.ets:首页/对话/个人中心三处网络错误统一横幅+重试;
  对话耗尽横幅恢复 reset_at 时间显示
- 文案纪律:无价格/购买/会员/升级字样;hvigor assembleHap 构建 0 error
- 子模块 meida_backend 指向 7bcbb8d(迭代1-3 后端)
This commit is contained in:
xsl
2026-09-11 21:51:25 +08:00
parent 9228f67820
commit a850735d60
17 changed files with 1433 additions and 29 deletions
@@ -16,7 +16,13 @@ const CARD_PRIMARY_COLOR: string = COLOR_PRIMARY
@Component
export struct DimensionCard {
dim: DimensionWire = EMPTY_DIMENSION
/** 已提交的反馈判定('' = 未反馈;'accurate' / 'inaccurate' 高亮已选项,宿主回显用)。 */
feedbackVerdict: string = ''
/** 提交反馈(组件保持无网络):宿主调 POST /reports/{id}/feedback。 */
onFeedback: (dimKey: string, verdict: string, correction: string) => void = () => {}
@State ruleExpanded: boolean = false
@State correctionOpen: boolean = false // 「不准」展开的行内修正输入
@State correctionText: string = ''
private isSkipped(): boolean {
return this.dim.status !== 'ok'
@@ -63,6 +69,26 @@ export struct DimensionCard {
return '本期未采集到足够信息'
}
/** 反馈区可用条件(T-P3-21):仅 status=ok 且有 key 的维度卡。 */
private feedbackable(): boolean {
const k = this.dim.key
return !this.isSkipped() && k !== undefined && k !== ''
}
private dimKey(): string {
return this.dim.key ?? ''
}
private submitFeedback(verdict: string): void {
if (verdict === 'inaccurate' && !this.correctionOpen) {
// 点「不准」先展开行内修正输入(可选,≤100 字),再点「提交」才上报
this.correctionOpen = true
return
}
this.correctionOpen = false
this.onFeedback(this.dimKey(), verdict, verdict === 'inaccurate' ? this.correctionText.trim() : '')
}
build() {
Column({ space: 8 }) {
Row({ space: 8 }) {
@@ -129,6 +155,65 @@ export struct DimensionCard {
.alignItems(HorizontalAlign.Start)
}
}
// 结论反馈区(T-P3-21):仅 ok 维度;已选项高亮,再点另一项即改判
if (this.feedbackable()) {
Row({ space: 10 }) {
Text('这个结论准吗?')
.fontSize(12)
.fontColor('#8A9099')
.layoutWeight(1)
Text('准 👍')
.fontSize(12)
.fontColor(this.feedbackVerdict === 'accurate' ? '#FFFFFF' : CARD_PRIMARY_COLOR)
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.borderRadius(14)
.backgroundColor(this.feedbackVerdict === 'accurate' ? CARD_PRIMARY_COLOR : '#F7E3EA')
.onClick(() => {
this.submitFeedback('accurate')
})
Text('不准 👎')
.fontSize(12)
.fontColor(this.feedbackVerdict === 'inaccurate' ? '#FFFFFF' : '#666666')
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.borderRadius(14)
.backgroundColor(this.feedbackVerdict === 'inaccurate' ? '#666666' : '#F5F5F7')
.onClick(() => {
this.submitFeedback('inaccurate')
})
}
.width('100%')
.alignItems(VerticalAlign.Center)
.margin({ top: 4 })
// 「不准」的行内修正输入(可选,≤100 字)
if (this.correctionOpen) {
TextArea({ text: this.correctionText, placeholder: '你觉得应该是?(可选)' })
.width('100%')
.height(72)
.fontSize(13)
.maxLength(100)
.backgroundColor('#F5F5F7')
.borderRadius(8)
.onChange((v: string) => {
this.correctionText = v
})
Row() {
Blank()
Text('提交')
.fontSize(13)
.fontColor(Color.White)
.padding({ left: 20, right: 20, top: 6, bottom: 6 })
.borderRadius(16)
.backgroundColor(CARD_PRIMARY_COLOR)
.onClick(() => {
this.onFeedback(this.dimKey(), 'inaccurate', this.correctionText.trim())
this.correctionOpen = false
})
}
.width('100%')
}
}
}
.width('100%')
.padding(12)