agent_chat_store.dart
3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import 'dart:convert';
import 'package:path/path.dart' as p;
import 'package:sqflite/sqflite.dart';
/// 会话持久化记录,结构保持简单,页面负责与 UI 模型互转。
class AgentChatRecord {
AgentChatRecord({
required this.id,
required this.role,
required this.content,
this.card,
required this.ts,
required this.status,
});
final String id;
final String role;
final String content;
final Map<String, dynamic>? card;
final int ts;
final String status;
factory AgentChatRecord.fromDbMap(Map<String, dynamic> map) {
final dynamic cardValue = map['card'];
return AgentChatRecord(
id: map['id'] as String,
role: map['role'] as String,
content: map['content'] as String? ?? '',
card: cardValue == null
? null
: jsonDecode(cardValue as String) as Map<String, dynamic>,
ts: map['ts'] as int,
status: map['status'] as String? ?? 'done',
);
}
Map<String, dynamic> toDbMap(String storeId) {
return <String, dynamic>{
'id': id,
'store_id': storeId,
'role': role,
'content': content,
'card': card == null ? null : jsonEncode(card),
'ts': ts,
'status': status,
};
}
}
/// 按门店隔离的本地会话存储。
class AgentChatStore {
AgentChatStore._();
static final AgentChatStore instance = AgentChatStore._();
static const String _dbName = 'agent_chat.db';
static const String _table = 'agent_messages';
Database? _db;
Future<Database> _open() async {
if (_db != null) return _db!;
final String path = p.join(await getDatabasesPath(), _dbName);
_db = await openDatabase(
path,
version: 1,
onCreate: (Database db, int version) async {
await db.execute('''
CREATE TABLE $_table(
id TEXT PRIMARY KEY,
store_id TEXT NOT NULL,
role TEXT NOT NULL,
content TEXT NOT NULL,
card TEXT,
ts INTEGER NOT NULL,
status TEXT NOT NULL
)
''');
await db.execute(
'CREATE INDEX idx_agent_store_ts ON $_table(store_id, ts)',
);
},
);
return _db!;
}
Future<List<AgentChatRecord>> load(String storeId) async {
final Database db = await _open();
final List<Map<String, dynamic>> rows = await db.query(
_table,
where: 'store_id = ?',
whereArgs: <Object?>[storeId],
orderBy: 'ts ASC',
);
return rows
.map((Map<String, dynamic> row) => AgentChatRecord.fromDbMap(row))
.toList();
}
Future<void> save(String storeId, List<AgentChatRecord> records) async {
final Database db = await _open();
final Batch batch = db.batch();
batch.delete(_table, where: 'store_id = ?', whereArgs: <Object?>[storeId]);
for (final AgentChatRecord record in records) {
batch.insert(
_table,
record.toDbMap(storeId),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
await batch.commit(noResult: true);
}
Future<void> clearAll() async {
final Database db = await _open();
await db.delete(_table);
}
}