Added Task number

This commit is contained in:
2026-02-21 21:37:36 +08:00
parent 8bb69a80af
commit 6238c701c0
7 changed files with 272 additions and 14 deletions
+82 -8
View File
@@ -153,7 +153,8 @@ final tasksProvider = StreamProvider<List<Task>>((ref) {
.where(
(t) =>
t.title.toLowerCase().contains(q) ||
t.description.toLowerCase().contains(q),
t.description.toLowerCase().contains(q) ||
(t.taskNumber?.toLowerCase().contains(q) ?? false),
)
.toList();
}
@@ -253,15 +254,88 @@ class TasksController {
payload['request_category'] = requestCategory;
}
final data = await _client
.from('tasks')
.insert(payload)
.select('id')
.single();
final taskId = data['id'] as String?;
// Prefer server RPC that atomically generates `task_number` and inserts
// the task; fallback to client-side insert with retry on duplicate-key.
String? taskId;
String? assignedNumber;
try {
final rpcParams = {
'p_title': title,
'p_description': description,
'p_office_id': officeId,
'p_ticket_id': ticketId,
'p_request_type': requestType,
'p_request_type_other': requestTypeOther,
'p_request_category': requestCategory,
'p_creator_id': actorId,
};
// Retry RPC on duplicate-key (23505) errors which may occur
// transiently due to concurrent inserts; prefer RPC always.
const int rpcMaxAttempts = 3;
Map<String, dynamic>? rpcRow;
for (var attempt = 0; attempt < rpcMaxAttempts; attempt++) {
try {
final rpcRes = await _client
.rpc('insert_task_with_number', rpcParams)
.single();
if (rpcRes is Map) {
rpcRow = Map<String, dynamic>.from(rpcRes);
} else if (rpcRes is List &&
rpcRes.isNotEmpty &&
rpcRes.first is Map) {
rpcRow = Map<String, dynamic>.from(rpcRes.first as Map);
}
break;
} catch (err) {
final msg = err.toString();
final isDuplicateKey =
msg.contains('duplicate key value') || msg.contains('23505');
if (!isDuplicateKey || attempt == rpcMaxAttempts - 1) {
rethrow;
}
await Future.delayed(Duration(milliseconds: 150 * (attempt + 1)));
// retry
}
}
if (rpcRow != null) {
taskId = rpcRow['id'] as String?;
assignedNumber = rpcRow['task_number'] as String?;
}
// ignore: avoid_print
print('createTask via RPC assigned number=$assignedNumber id=$taskId');
} catch (e) {
// RPC not available or failed; fallback to client insert with retry
const int maxAttempts = 3;
Map<String, dynamic>? insertData;
for (var attempt = 0; attempt < maxAttempts; attempt++) {
try {
insertData = await _client
.from('tasks')
.insert(payload)
.select('id, task_number')
.single();
break;
} catch (err) {
final msg = err.toString();
final isDuplicateKey =
msg.contains('duplicate key value') || msg.contains('23505');
if (!isDuplicateKey || attempt == maxAttempts - 1) {
rethrow;
}
await Future.delayed(Duration(milliseconds: 150 * (attempt + 1)));
}
}
taskId = insertData == null ? null : insertData['id'] as String?;
assignedNumber = insertData == null
? null
: insertData['task_number'] as String?;
// ignore: avoid_print
print('createTask fallback assigned number=$assignedNumber id=$taskId');
}
if (taskId == null) return;
// Activity log: created
try {
await _client.from('task_activity_logs').insert({
'task_id': taskId,