Browse Source

添加会议助手数据同步

weicu
tanlongsheng 1 year ago
parent
commit
c67293de8c
  1. 85
      lib/core/utils/synchrodata.dart
  2. 52
      lib/data/services/db/sqflite_api.dart
  3. 26
      lib/data/services/network/api.dart
  4. 46
      lib/modules/meeting/controllers/meeting_controller.dart
  5. 37
      lib/modules/meeting/views/meeting_view.dart

85
lib/core/utils/synchrodata.dart

@ -0,0 +1,85 @@
import 'package:get_storage/get_storage.dart';
import '../../data/services/network/api.dart';
class Synchrodata {
static final GetStorage _storage = GetStorage();
static List _records = _storage.read("operation_records") ?? [];
static List _delids = _storage.read("operation_delids") ?? [];
static bool _isSynchro = false;
// 保存操作记录
static Future saveOperationRecord(
String method,
dynamic params,
) async {
String userId = '';
Map? userInfo = _storage.read("user_info");
if (userInfo != null) {
userId = userInfo['user']['uid'];
}
String id = '${userId}_${params['id']}';
if (params['type'] != null) {
params['rtype'] = params['type'];
}
switch (method) {
case 'insert':
_records.add({
...params,
'id': id,
'number': params['id'],
'uid': userId,
});
_storage.write("operation_records", _records);
break;
case 'update':
Map? foundElement = _records.firstWhere(
(element) => element['id'] == id,
orElse: () => null,
);
if (foundElement != null) {
foundElement.addAll({
...params,
'id': id,
});
} else {
_records.add({
...params,
'id': id,
'number': params['id'],
'uid': userId,
});
}
_storage.write("operation_records", _records);
break;
case 'delete':
_delids.add(id);
_storage.write("operation_delids", _delids);
break;
default:
break;
}
}
// 获取操作记录
static Future startSynchro() async {
if (_isSynchro) return;
_isSynchro = true;
if (_records.isNotEmpty || _delids.isNotEmpty) {
var result = await Api.putOperationRecord({
'delids': _delids,
'records': _records,
});
if (result != null) {
_records = [];
_delids = [];
_storage.write("operation_records", _records);
_storage.write("operation_delids", _delids);
}
}
var result = await Api.getOperationRecord();
_isSynchro = false;
}
}

52
lib/data/services/db/sqflite_api.dart

@ -1,49 +1,10 @@
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/utils/synchrodata.dart';
import 'database_helper.dart'; import 'database_helper.dart';
class SqfliteApi { class SqfliteApi {
// 保存操作记录
static Future saveMeetingOperationRecord(
String method,
dynamic params,
) async {
GetStorage storage = GetStorage();
String userId = '';
Map? userInfo = storage.read("user_info");
if (userInfo != null) {
userId = userInfo['user']['uid'];
}
final db = await DatabaseHelper().database;
String data = '';
if (method == 'records') {
Map records = {
...params,
'id': '${userId}_${params['id']}',
'number': params['id'],
'uid': userId,
};
data = jsonEncode(records);
} else {
data = params;
}
db.insert('operationrecord', {
'method': method,
'data': data,
});
}
// 操作记录列表
static Future getMeetingOperationRecord() async {
final db = await DatabaseHelper().database;
return await db.query('operationrecord');
}
// 获取商务会议助手列表 // 获取商务会议助手列表
static Future getMeetingList(int offset) async { static Future getMeetingList(int offset) async {
final db = await DatabaseHelper().database; final db = await DatabaseHelper().database;
@ -112,6 +73,10 @@ class SqfliteApi {
'summary': '', 'summary': '',
'mindmap': '', 'mindmap': '',
}); });
Synchrodata.saveOperationRecord('insert', {
...meeting,
'id': id,
});
}); });
return id; return id;
} catch (e) { } catch (e) {
@ -205,6 +170,10 @@ class SqfliteApi {
static Future editMeetingTitle(id, Map<String, Object?> meeting) async { static Future editMeetingTitle(id, Map<String, Object?> meeting) async {
final db = await DatabaseHelper().database; final db = await DatabaseHelper().database;
await db.update('meeting', meeting, where: 'id = ?', whereArgs: [id]); await db.update('meeting', meeting, where: 'id = ?', whereArgs: [id]);
Synchrodata.saveOperationRecord('update', {
...meeting,
'id': id,
});
} }
// 删除商务会议助手 // 删除商务会议助手
@ -216,6 +185,9 @@ class SqfliteApi {
.delete('meetingdetails', where: 'meetingid = ?', whereArgs: [id]); .delete('meetingdetails', where: 'meetingid = ?', whereArgs: [id]);
await txn await txn
.delete('meetingspeaker', where: 'meetingid = ?', whereArgs: [id]); .delete('meetingspeaker', where: 'meetingid = ?', whereArgs: [id]);
Synchrodata.saveOperationRecord('delete', {
'id': id,
});
}); });
} }

26
lib/data/services/network/api.dart

@ -44,14 +44,6 @@ class Api {
'/api/home/user_setting', '/api/home/user_setting',
params: params, params: params,
); );
// options: params is dio.FormData
// ? Options(
// headers: {
// 'Content-Type': 'multipart/form-data',
// },
// )
// : null,
// );
} }
//注销账号 //注销账号
@ -107,4 +99,22 @@ class Api {
params: params, params: params,
); );
} }
// 上传会议助手操作记录
static putOperationRecord([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/record_put',
params: params,
);
}
// 获取会议助手数据
static getOperationRecord([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/record_get',
params: params,
);
}
} }

46
lib/modules/meeting/controllers/meeting_controller.dart

@ -12,6 +12,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import '../../../core/utils/logger.dart'; import '../../../core/utils/logger.dart';
import '../../../core/utils/synchrodata.dart';
import '../../../core/utils/upload_oss.dart'; import '../../../core/utils/upload_oss.dart';
import '../../../data/services/db/sqflite_api.dart'; import '../../../data/services/db/sqflite_api.dart';
import '../../../core/utils/permission_util.dart'; import '../../../core/utils/permission_util.dart';
@ -32,9 +33,6 @@ class MeetingController extends GetxController {
List<String> selected = []; List<String> selected = [];
final appDocDir = getApplicationDocumentsDirectory(); final appDocDir = getApplicationDocumentsDirectory();
//final appopus = getExternalStorageDirectories();
// final directory = Directory(
// '/storage/emulated/0/Android/data/com.yunqiinnovation.deepsound/files');
List<FileSystemEntity> files = []; List<FileSystemEntity> files = [];
TextEditingController titleController = TextEditingController(); // 录音标题 TextEditingController titleController = TextEditingController(); // 录音标题
@ -55,7 +53,6 @@ class MeetingController extends GetxController {
super.onInit(); super.onInit();
listController.addListener(_onScroll); listController.addListener(_onScroll);
_requestStoragePermission(); _requestStoragePermission();
//Permission.storage.request();
_headers = { _headers = {
'Authorization': 'Bearer; $_token', 'Authorization': 'Bearer; $_token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -64,7 +61,7 @@ class MeetingController extends GetxController {
addMeetingAudio(); addMeetingAudio();
final Map<String, dynamic> args = Get.arguments ?? {}; final Map<String, dynamic> args = Get.arguments ?? {};
// 检查参数是否存在且包含有效路径 // 检查参数是否存在且包含有效路径
if (args != null && if (args.isNotEmpty &&
args.containsKey('filePath') && args.containsKey('filePath') &&
args['filePath'] is String && args['filePath'] is String &&
args['filePath'].isNotEmpty) { args['filePath'].isNotEmpty) {
@ -82,6 +79,10 @@ class MeetingController extends GetxController {
super.onClose(); super.onClose();
} }
void onPopInvokedWithResult(didPop, result) {
Synchrodata.startSynchro();
}
void _onScroll() { void _onScroll() {
if (isGetMore && if (isGetMore &&
!isLoading && !isLoading &&
@ -109,11 +110,8 @@ class MeetingController extends GetxController {
// 请求存储权限 // 请求存储权限
void _requestStoragePermission() async { void _requestStoragePermission() async {
// final BuildContext context = Get.overlayContext!;
PermissionUtil.instance PermissionUtil.instance
.requestPermission( .requestPermission(
// context: context,
permissionType: Permission.storage, permissionType: Permission.storage,
permissionName: "存储", permissionName: "存储",
explanationText: "我们需要访问存储权限,以便您可以选择并上传音频文件。", explanationText: "我们需要访问存储权限,以便您可以选择并上传音频文件。",
@ -124,18 +122,14 @@ class MeetingController extends GetxController {
Logger.d("Permission", "用户授予了存储权限"); Logger.d("Permission", "用户授予了存储权限");
} else { } else {
Logger.d("Permission", "用户未授予存储权限"); Logger.d("Permission", "用户未授予存储权限");
// 可以提示用户无法进行文件操作
} }
}); });
} }
void loadTranslatopus() async { void loadTranslatopus() async {
// final appDir = await appopus; // 先 await 获取目录
final dir = final dir =
Directory("/data/user/0/com.yunqiinnovation.deepsound/files/OpusAudio"); Directory("/data/user/0/com.yunqiinnovation.deepsound/files/OpusAudio");
print("appDocDir=${dir?.path}");
files = dir files = dir
.listSync() .listSync()
.where((f) => f is File && (f.path.endsWith('.opus'))) .where((f) => f is File && (f.path.endsWith('.opus')))
@ -147,15 +141,12 @@ class MeetingController extends GetxController {
final appDir = await appDocDir; // 先 await 获取目录 final appDir = await appDocDir; // 先 await 获取目录
final dir = Directory("${appDir.path}/TranslatAudio"); final dir = Directory("${appDir.path}/TranslatAudio");
print("appDocDir=${dir?.path}");
// Create directory if it doesn't exist
if (!await dir.exists()) { if (!await dir.exists()) {
await dir.create(recursive: true); // Create directory tree if needed await dir.create(recursive: true);
files = []; // No files exist in new directory files = [];
return; return;
} }
// Directory exis
files = dir files = dir
.listSync() .listSync()
.where((f) => .where((f) =>
@ -168,20 +159,12 @@ class MeetingController extends GetxController {
f.path.endsWith('.mov'))) f.path.endsWith('.mov')))
.toList(); .toList();
} catch (e) { } catch (e) {
print("Error loading files: $e"); files = [];
files = []; // Return empty list on error
} }
} }
// 导入音频文件
Future<void> shareAllTranslatAudio() async { Future<void> shareAllTranslatAudio() async {
final filePath = selected[0]; final filePath = selected[0];
// for (final filePath in selected) {
// if (filePath.isEmpty) {
// EasyLoading.showToast('没有可分享的音频文件');
// return;
// }
// }
try { try {
await Share.shareXFiles( await Share.shareXFiles(
[XFile(filePath)], [XFile(filePath)],
@ -216,7 +199,7 @@ class MeetingController extends GetxController {
final files = final files =
await sourceDir.list().where((entity) => entity is File).toList(); await sourceDir.list().where((entity) => entity is File).toList();
int addQuantity = 0; int addUp = 0;
for (final fileEntity in files) { for (final fileEntity in files) {
try { try {
final file = File(fileEntity.path); final file = File(fileEntity.path);
@ -225,8 +208,6 @@ class MeetingController extends GetxController {
// 设置音频源获取时长 // 设置音频源获取时长
await _audioPlayer.setAudioSource(AudioSource.file(filePath)); await _audioPlayer.setAudioSource(AudioSource.file(filePath));
print(
"_audioPlayer$_audioPlayer,filePath=$filePath,_audioPlayer.duration?.inSeconds${_audioPlayer.duration?.inSeconds}");
int seconds = _audioPlayer.duration?.inSeconds ?? 0; int seconds = _audioPlayer.duration?.inSeconds ?? 0;
// 获取文件修改时间 // 获取文件修改时间
@ -251,7 +232,6 @@ class MeetingController extends GetxController {
'tasktype': 0, 'tasktype': 0,
'creationtime': creationTime, 'creationtime': creationTime,
}; };
print("导入数据: $data");
// 插入数据库 // 插入数据库
final meetingId = await SqfliteApi.insertMeeting(data); final meetingId = await SqfliteApi.insertMeeting(data);
@ -268,12 +248,13 @@ class MeetingController extends GetxController {
await file.delete(); await file.delete();
addQuantity++; addQuantity++;
addUp++;
} }
} catch (e) { } catch (e) {
print("文件处理失败: ${fileEntity.path}, 错误: $e"); print("文件处理失败: ${fileEntity.path}, 错误: $e");
} }
} }
if (addQuantity > 0) EasyLoading.showSuccess('成功导入本地 $addQuantity 条录音'); if (addUp > 0) EasyLoading.showSuccess('成功导入本地 $addUp 条录音');
} catch (e) { } catch (e) {
EasyLoading.showError('导入失败: $e'); EasyLoading.showError('导入失败: $e');
} finally { } finally {
@ -292,7 +273,6 @@ class MeetingController extends GetxController {
filepath: filePath, rootDir: 'TranslatAudio'); filepath: filePath, rootDir: 'TranslatAudio');
int seconds = _audioPlayer.duration?.inSeconds ?? 0; int seconds = _audioPlayer.duration?.inSeconds ?? 0;
final fileName = filePath.split('/').last; final fileName = filePath.split('/').last;
// int creationTime = DateTime.now().millisecondsSinceEpoch;
Map<String, Object?> data = { Map<String, Object?> data = {
'title': fileName, 'title': fileName,
'type': 'TRANSLAT', 'type': 'TRANSLAT',
@ -302,7 +282,6 @@ class MeetingController extends GetxController {
'tasktype': 0, 'tasktype': 0,
'creationtime': creationTime, 'creationtime': creationTime,
}; };
print("data=$data");
final meetingId = await SqfliteApi.insertMeeting(data); final meetingId = await SqfliteApi.insertMeeting(data);
if (meetingId != null) { if (meetingId != null) {
dataList.insert(0, { dataList.insert(0, {
@ -314,7 +293,6 @@ class MeetingController extends GetxController {
} }
} catch (e) { } catch (e) {
Logger.error('导入文件失败: $filePath, error: $e'); Logger.error('导入文件失败: $filePath, error: $e');
// 可选:继续导入下一个文件
} }
} }
EasyLoading.dismiss(); EasyLoading.dismiss();

37
lib/modules/meeting/views/meeting_view.dart

@ -11,27 +11,30 @@ import '../model/meeting_model.dart';
class MeetingView extends GetView<MeetingController> { class MeetingView extends GetView<MeetingController> {
const MeetingView({super.key}); const MeetingView({super.key});
static OverlayEntry? _recordingOverlayEntry;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark; final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold( return PopScope(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], onPopInvokedWithResult: controller.onPopInvokedWithResult,
appBar: _buildAppBar(context, isDarkMode), child: Scaffold(
body: _buildBody(context, isDarkMode), backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
floatingActionButton: Column( appBar: _buildAppBar(context, isDarkMode),
mainAxisSize: MainAxisSize.min, body: _buildBody(context, isDarkMode),
crossAxisAlignment: CrossAxisAlignment.end, floatingActionButton: Column(
children: [ mainAxisSize: MainAxisSize.min,
FloatingActionButton( crossAxisAlignment: CrossAxisAlignment.end,
heroTag: "addAudio", children: [
onPressed: () { FloatingActionButton(
_showAddAudioMenu(context, isDarkMode); heroTag: "addAudio",
}, onPressed: () {
child: const Icon(Icons.add), _showAddAudioMenu(context, isDarkMode);
), },
], child: const Icon(Icons.add),
),
],
),
), ),
); );
} }

Loading…
Cancel
Save