refactor(chat): 重构聊天模块并集成历史消息加载功能

- 删除冗余的 chat_history_repository 和 home_mock_data
- 简化 ag_ui_event fromJson 使用工厂映射表
- 提取 ChatBloc 事件处理方法,添加 loadHistory/loadMoreHistory
- HomeScreen 集成 ChatBloc 实现历史消息加载和下拉刷新
- 更新 AGENTS.md 文档约束
This commit is contained in:
qzl
2026-03-02 15:05:10 +08:00
parent 6b32990986
commit e161ca22c4
16 changed files with 915 additions and 752 deletions
@@ -44,8 +44,6 @@ class AgUiService {
Future<void> loadHistory({DateTime? beforeDate}) async {
if (Env.isMockApi) {
await _mockLoadHistory(beforeDate: beforeDate);
} else {
throw UnimplementedError('Real API not implemented');
}
}
@@ -58,8 +56,10 @@ class AgUiService {
final runId = '$_runIdPrefix${DateTime.now().millisecondsSinceEpoch}';
onEvent(RunStartedEvent(threadId: threadId, runId: runId));
await Future.delayed(const Duration(milliseconds: 10));
DateTime targetDate;
// Determine target date, end early if no earlier history
final DateTime targetDate;
if (beforeDate != null) {
final prevDate = _historyService.getPreviousDay(beforeDate);
if (prevDate == null) {
@@ -72,9 +72,8 @@ class AgUiService {
}
final messages = _historyService.getHistoryForDay(targetDate);
onEvent(MessagesSnapshotEvent(messages: messages));
await Future.delayed(const Duration(milliseconds: 10));
onEvent(RunFinishedEvent(threadId: threadId, runId: runId));
}
@@ -6,40 +6,35 @@ class MockHistoryService {
factory MockHistoryService() => _instance;
MockHistoryService._internal();
/// Normalize DateTime to date-only (midnight)
DateTime _toDateOnly(DateTime date) =>
DateTime(date.year, date.month, date.day);
List<SnapshotMessage> getHistoryForDay(DateTime date) {
final dayStart = DateTime(date.year, date.month, date.day);
final dayStart = _toDateOnly(date);
final allHistory = _generateAllHistory();
return allHistory.where((msg) {
if (msg.ui != null) {
final data = msg.ui!.data;
final startAtStr = data['startAt'] as String?;
if (startAtStr != null) {
try {
final startAt = DateTime.parse(startAtStr);
final msgDate = DateTime(startAt.year, startAt.month, startAt.day);
return msgDate == dayStart;
} catch (_) {}
}
}
return false;
if (msg.timestamp == null) return false;
final msgDate = _toDateOnly(msg.timestamp!);
return msgDate == dayStart;
}).toList();
}
DateTime? getLatestHistoryDate() {
final now = DateTime.now();
return DateTime(now.year, now.month, now.day);
final allHistory = _generateAllHistory();
if (allHistory.isEmpty) return null;
return allHistory
.where((msg) => msg.timestamp != null)
.map((msg) => _toDateOnly(msg.timestamp!))
.reduce((a, b) => a.isAfter(b) ? a : b);
}
DateTime? getPreviousDay(DateTime currentDate) {
final allDates = _getAllHistoryDates();
final sortedDates = allDates.toList()..sort((a, b) => b.compareTo(a));
final currentDateOnly = DateTime(
currentDate.year,
currentDate.month,
currentDate.day,
);
final currentDateOnly = _toDateOnly(currentDate);
for (final date in sortedDates) {
if (date.isBefore(currentDateOnly)) {
@@ -51,29 +46,35 @@ class MockHistoryService {
bool hasEarlierHistory(DateTime fromDate) {
final allDates = _getAllHistoryDates();
final fromDateOnly = DateTime(fromDate.year, fromDate.month, fromDate.day);
final fromDateOnly = _toDateOnly(fromDate);
return allDates.any((date) => date.isBefore(fromDateOnly));
}
Set<DateTime> _getAllHistoryDates() {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
final today = _toDateOnly(now);
final yesterday = today.subtract(const Duration(days: 1));
return {today, yesterday};
}
List<SnapshotMessage> _generateAllHistory() {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
final today = _toDateOnly(now);
final yesterday = today.subtract(const Duration(days: 1));
return [
SnapshotMessage(id: 'hist-m1', role: 'user', content: '明天提醒我开会'),
SnapshotMessage(
id: 'hist-m1',
role: 'user',
content: '明天提醒我开会',
timestamp: today.add(const Duration(hours: 10)),
),
SnapshotMessage(
id: 'hist-t1',
role: 'tool',
toolCallId: 'hist-tc1',
timestamp: today.add(const Duration(hours: 10)),
ui: UiCard(
cardType: 'calendar_card.v1',
data: CalendarCardData(
@@ -104,21 +105,26 @@ class MockHistoryService {
id: 'hist-m2',
role: 'assistant',
content: '已为你创建日程"产品评审会议",明天上午10:00。我还会提前15分钟提醒你。',
timestamp: today.add(const Duration(hours: 10)),
),
SnapshotMessage(
id: 'hist-m3',
role: 'user',
content: '下周一之前提交项目报告',
timestamp: yesterday.add(const Duration(hours: 14)),
),
SnapshotMessage(id: 'hist-m3', role: 'user', content: '下周一之前提交项目报告'),
SnapshotMessage(
id: 'hist-t2',
role: 'tool',
toolCallId: 'hist-tc2',
timestamp: yesterday.add(const Duration(hours: 14)),
ui: UiCard(
cardType: 'calendar_card.v1',
data: CalendarCardData(
id: 'hist-s2',
title: '提交项目报告',
description: '完成并提交Q2项目报告',
startAt: yesterday
.subtract(const Duration(days: 3))
.toIso8601String(),
startAt: yesterday.add(const Duration(days: 5)).toIso8601String(),
endAt: null,
timezone: 'Asia/Shanghai',
location: null,
@@ -138,11 +144,13 @@ class MockHistoryService {
id: 'hist-m4',
role: 'assistant',
content: '好的,我已帮你创建待办事项"提交项目报告",截止日期为下周一。我还会提醒你完成这项任务。',
timestamp: yesterday.add(const Duration(hours: 14)),
),
SnapshotMessage(
id: 'hist-m5',
role: 'assistant',
content: '你好,我有什么可以帮你的?',
timestamp: yesterday.add(const Duration(hours: 9)),
),
];
}