新增:健康事件时间线接入真实数据(T2-14 时间线半边)
- 时间线页:occurred_at DESC cursor 分页 + 月分组组头,四态齐备; 六类事件经 RecordTypeDot 映射(增补喂养/洗护/测量三型,色族复用 已审计色对),类型 TagPill 双通道 - 事件录入表单:六类类型选择器、金额以元录入/整数分传输(money.dart 换算)、UTC 时间戳约定与体重表单一致 - 事件编辑页:顶层 PATCH 差量提交(title/notes/amountCents + version), 40902 照 T2-12 模式自动经时间线检索取新 version 重提(保留输入) - 档案页:月度花费卡接 summary.monthlyExpense(分→元展示)、tz 透传 设备时区固定偏移(T2-13 遗留③)、健康时间线导航入口 - 埋点:health_record 域 create 三事件 + viewed(recordType=health_event) 挂通;新增 edit_succeeded/failed 封装(failureReason 含 conflict) - 测试 224 → 250 全绿(+26);analyze 0 问题;format 无 diff Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
/// 体重 / 疫苗展示与输入解析的纯函数集合(列表 / 表单共用,可单测)。
|
||||
/// 体重 / 疫苗 / 健康事件 / 提醒展示与输入解析的纯函数集合
|
||||
/// (列表 / 表单共用,可单测)。
|
||||
library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:patbond_flutter/core/theme/app_theme.dart';
|
||||
import 'package:patbond_flutter/core/widgets/record_type_dot.dart';
|
||||
import 'package:patbond_flutter/features/pets/pet_models.dart';
|
||||
|
||||
/// 体重输入解析:契约区间 (0, 500]、最多两位小数(numeric(6,2))。
|
||||
@@ -84,3 +86,51 @@ String? vaccinationDateRuleError({
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ---- 健康事件(T2-14)----
|
||||
|
||||
/// 契约六类健康事件 → 视觉记录类型(RecordTypeDot 映射唯一出口)。
|
||||
/// note(随手记)归入「其他」视觉族;其余五类各有专属图标。
|
||||
RecordType recordTypeForHealthEvent(HealthEventType type) => switch (type) {
|
||||
HealthEventType.medical => RecordType.medical,
|
||||
HealthEventType.feeding => RecordType.feeding,
|
||||
HealthEventType.deworming => RecordType.deworming,
|
||||
HealthEventType.grooming => RecordType.grooming,
|
||||
HealthEventType.measurement => RecordType.measurement,
|
||||
HealthEventType.note => RecordType.other,
|
||||
};
|
||||
|
||||
/// 六类事件中文文案(类型选择器 / 条目标签共用;
|
||||
/// 图标 + 文字双通道,不单靠颜色区分)。
|
||||
String healthEventTypeLabel(HealthEventType type) => switch (type) {
|
||||
HealthEventType.medical => '就医',
|
||||
HealthEventType.feeding => '喂养',
|
||||
HealthEventType.deworming => '驱虫',
|
||||
HealthEventType.grooming => '洗护',
|
||||
HealthEventType.measurement => '测量',
|
||||
HealthEventType.note => '随手记',
|
||||
};
|
||||
|
||||
/// 事件发生时刻展示:本地时区 `YYYY-MM-DD HH:mm`。
|
||||
String formatOccurredAt(DateTime occurredAt) {
|
||||
final local = occurredAt.toLocal();
|
||||
final h = local.hour.toString().padLeft(2, '0');
|
||||
final min = local.minute.toString().padLeft(2, '0');
|
||||
return '${dateToJson(local)} $h:$min';
|
||||
}
|
||||
|
||||
/// 时间线月分组组头(05 §4.2:「2026 年 9 月」),按本地时区归月。
|
||||
String healthEventMonthHeader(DateTime occurredAt) {
|
||||
final local = occurredAt.toLocal();
|
||||
return '${local.year} 年 ${local.month} 月';
|
||||
}
|
||||
|
||||
/// 设备时区 → summary `tz` 参数(契约接受固定偏移形如 `+08:00`;
|
||||
/// Flutter 无 IANA 名可取,固定偏移语义等价——只作用于月度窗口)。
|
||||
String tzOffsetQueryValue(Duration offset) {
|
||||
final sign = offset.isNegative ? '-' : '+';
|
||||
final abs = offset.abs();
|
||||
final h = abs.inHours.toString().padLeft(2, '0');
|
||||
final m = (abs.inMinutes % 60).toString().padLeft(2, '0');
|
||||
return '$sign$h:$m';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user