Browse Source

refactor(meeting): 重构音频导入逻辑并改进日志记录

- 将print语句替换为Logger进行统一日志管理
- 重构addMeetingAudio方法,添加详细注释并优化文件处理流程
- 新增_archiveTranslatToLocal方法处理翻译音频归档
- 改进addTranslatAudio方法,支持可选归档到LocalAudio目录
- 为控制器类添加文档注释
newdev_shunjiawei
lxm 11 months ago
parent
commit
61a6746e56
  1. 1
      lib/data/services/meeting/meeting_upload_service.dart
  2. 1
      lib/modules/meeting/controllers/meeting_details_controller.dart
  3. 130
      lib/modules/meeting/controllers/meeting_home_controller.dart
  4. 1
      lib/modules/meeting/controllers/mind_map_controller.dart
  5. 8
      lib/modules/translation/controllers/translation_list_controller.dart

1
lib/data/services/meeting/meeting_upload_service.dart

@ -29,6 +29,7 @@ class MeetingUploadService extends GetxService {
executeUpload(); executeUpload();
} }
/// 添加待上传的音频文件
void addUpload( void addUpload(
int id, int id,
String filePath, String filePath,

1
lib/modules/meeting/controllers/meeting_details_controller.dart

@ -18,6 +18,7 @@ import '../../../data/services/meeting/meeting_upload_service.dart';
import '../model/meeting_details_model.dart'; import '../model/meeting_details_model.dart';
import '../model/meeting_model.dart'; import '../model/meeting_model.dart';
/// 会议详情控制器
class MeetingDetailsController extends GetxController class MeetingDetailsController extends GetxController
with GetTickerProviderStateMixin { with GetTickerProviderStateMixin {
late TabController tabController; late TabController tabController;

130
lib/modules/meeting/controllers/meeting_home_controller.dart

@ -41,7 +41,7 @@ class MeetingHomeController extends GetxController {
RxList originalDataList = [].obs; RxList originalDataList = [].obs;
RxList dataList = [].obs; RxList dataList = [].obs;
RxString filtrateType = ''.obs; RxString filtrateType = ''.obs;
bool isAsc = false; bool isAsc = false; // 是否升序排序
TextEditingController filtrateController = TextEditingController(); TextEditingController filtrateController = TextEditingController();
// 蓝牙服务 // 蓝牙服务
@ -178,15 +178,16 @@ class MeetingHomeController extends GetxController {
} }
} }
// 核心方法:导入本地录音文件到统一目录
void addMeetingAudio() async { void addMeetingAudio() async {
EasyLoading.show(status: 'importingLocalRecordings'.tr); // 对应中文:正在导入本地录音... EasyLoading.show(status: 'importingLocalRecordings'.tr); // 对应中文:正在导入本地录音...
try { try {
int addUp = 0; int addUp = 0; // 新增计数
final appDir = await appDocDir; final appDir = await appDocDir; // 获取应用文档目录
final sourceDirs = [ final sourceDirs = [
Directory("${appDir.path}/MeetingAudio/"), Directory("${appDir.path}/MeetingAudio/"), // 会议录音目录
Directory("${appDir.path}/DestAudio/"), Directory("${appDir.path}/DestAudio/"), // 目标录音目录
]; ];
// 目标目录:LocalAudio // 目标目录:LocalAudio
@ -200,31 +201,33 @@ class MeetingHomeController extends GetxController {
for (final dir in sourceDirs) { for (final dir in sourceDirs) {
if (await dir.exists()) { if (await dir.exists()) {
//遍历每个源目录,筛选出文件实体(仅包含文件,不包含子目录)
final files = final files =
await dir.list().where((entity) => entity is File).toList(); await dir.list().where((entity) => entity is File).toList();
allFiles.addAll(files); allFiles.addAll(files); //合并到总文件列表
} }
} }
// 遍历所有文件实体
for (final fileEntity in allFiles) { for (final fileEntity in allFiles) {
try { try {
final file = File(fileEntity.path); final file = File(fileEntity.path); //将文件实体转换为具体文件操作对象
final filePath = file.path; final filePath = file.path;
// 设置音频源获取时长 // 使用just_audio库加载音频文件以获取时长
await _audioPlayer.setAudioSource(AudioSource.file(filePath)); await _audioPlayer.setAudioSource(AudioSource.file(filePath));
int seconds = _audioPlayer.duration?.inSeconds ?? 0; int seconds =
_audioPlayer.duration?.inSeconds ?? 0; //获取音频时长(秒),若为空则设为0
// 获取文件修改时间 // 获取文件修改时间
final fileStat = await file.stat(); final fileStat = await file.stat(); //获取文件状态信息,包含修改时间等
final creationTime = fileStat.changed.millisecondsSinceEpoch; final creationTime = fileStat.changed.millisecondsSinceEpoch;
// 准备新路径 // 准备新路径
final fileName = filePath.split('/').last; final fileName = filePath.split('/').last; //获取文件名(包含扩展名)
final newPath = "${destDir.path}/$fileName"; final newPath = "${destDir.path}/$fileName"; //构建新路径,保持原文件名
// 构建数据 // 构建要存入数据库的音频文件抽象对象
Map<String, Object?> data = { Map<String, Object?> data = {
'title': fileName, 'title': fileName,
'type': 'LOCAL', 'type': 'LOCAL',
@ -238,7 +241,7 @@ class MeetingHomeController extends GetxController {
// 插入数据库 // 插入数据库
final meetingId = await SqfliteApi.insertMeeting(data); final meetingId = await SqfliteApi.insertMeeting(data);
if (meetingId != null) { if (meetingId != null) {
// 上传OSS // 安排后台上传任务
meetingUploadService.addUpload(meetingId, newPath, 'LocalAudio'); meetingUploadService.addUpload(meetingId, newPath, 'LocalAudio');
originalDataList.insert(0, { originalDataList.insert(0, {
@ -259,8 +262,8 @@ class MeetingHomeController extends GetxController {
} }
// 移动文件 // 移动文件
await file.copy(newPath); await file.copy(newPath); // 复制到新路径
await file.delete(); await file.delete(); // 删除原文件
addUp++; addUp++;
} }
@ -272,10 +275,11 @@ class MeetingHomeController extends GetxController {
e.toString())); // 对应中文:文件处理失败: {filePath}, 错误: {error} e.toString())); // 对应中文:文件处理失败: {filePath}, 错误: {error}
} }
} }
if (addUp > 0) if (addUp > 0) {
EasyLoading.showSuccess('importSuccess' EasyLoading.showSuccess('importSuccess'
.tr .tr
.replaceAll('{count}', '$addUp')); // 对应中文:成功导入本地 {count} 条录音 .replaceAll('{count}', '$addUp')); // 对应中文:成功导入本地 {count} 条录音
}
} catch (e) { } catch (e) {
EasyLoading.showError('importError' EasyLoading.showError('importError'
.tr .tr
@ -285,50 +289,88 @@ class MeetingHomeController extends GetxController {
} }
} }
void addTranslatAudio() async { // 新增:将翻译音频归档到 LocalAudio 并返回新路径(优先 rename,失败再 copy+delete)
Future<String> _archiveTranslatToLocal(String srcPath) async {
// 中文注释:获取应用文档目录并确保 LocalAudio 目录存在
final appDir = await appDocDir;
final destDir = Directory(path.join(appDir.path, 'LocalAudio'));
if (!await destDir.exists()) {
await destDir.create(recursive: true);
}
// 中文注释:目标文件名与路径,处理重名冲突
final fileName = path.basename(srcPath);
final baseName = path.basenameWithoutExtension(fileName);
final ext = path.extension(fileName);
String destPath = path.join(destDir.path, fileName);
if (await File(destPath).exists()) {
final ts = DateTime.now().millisecondsSinceEpoch;
destPath = path.join(destDir.path, '$baseName\_$ts$ext');
}
// 中文注释:尝试 rename(更快),失败则 copy + delete
final srcFile = File(srcPath);
try {
await srcFile.rename(destPath);
return destPath;
} catch (_) {
await srcFile.copy(destPath);
await srcFile.delete();
return destPath;
}
}
// 修改:翻译音频导入支持归档到 LocalAudio(智能转写默认归档以隐藏原翻译目录)
void addTranslatAudio({bool archiveToLocal = true}) async {
EasyLoading.show(status: 'batchImporting'.tr); // 对应中文:正在批量导入... EasyLoading.show(status: 'batchImporting'.tr); // 对应中文:正在批量导入...
for (final filePath in selected) { for (final originalPath in selected) {
try { try {
await _audioPlayer.setAudioSource(AudioSource.file(filePath)); // 中文注释:根据开关决定是否将翻译音频迁移到 LocalAudio
final fileStat = await File(filePath).stat(); final usePath =
final creationTime = fileStat.changed.millisecondsSinceEpoch; // 时间戳 archiveToLocal ? await _archiveTranslatToLocal(originalPath) : originalPath;
int seconds = _audioPlayer.duration?.inSeconds ?? 0;
final fileName = filePath.split('/').last; // 中文注释:计算音频时长与创建时间
Map<String, Object?> data = { await _audioPlayer.setAudioSource(AudioSource.file(usePath));
final fileStat = await File(usePath).stat();
final creationTime = fileStat.changed.millisecondsSinceEpoch;
final seconds = _audioPlayer.duration?.inSeconds ?? 0;
final fileName = path.basename(usePath);
// 中文注释:归档则统一标记为 LOCAL,未归档则保留 TRANSLAT
final String recordType = archiveToLocal ? 'LOCAL' : 'TRANSLAT';
// 中文注释:写入数据库
final Map<String, Object?> data = {
'title': fileName, 'title': fileName,
'type': 'TRANSLAT', 'type': recordType,
'seconds': seconds, 'seconds': seconds,
'filepath': filePath, 'filepath': usePath,
'audiourl': '', 'audiourl': '',
'tasktype': 0, 'tasktype': 0,
'creationtime': creationTime, 'creationtime': creationTime,
}; };
final meetingId = await SqfliteApi.insertMeeting(data); final meetingId = await SqfliteApi.insertMeeting(data);
if (meetingId != null) { if (meetingId != null) {
meetingUploadService.addUpload(meetingId, filePath, 'TranslatAudio'); // 中文注释:上传分类按目录区分
final uploadBucket = archiveToLocal ? 'LocalAudio' : 'TranslatAudio';
meetingUploadService.addUpload(meetingId, usePath, uploadBucket);
originalDataList.insert(0, { // 中文注释:更新列表(保持现有排序逻辑)
'id': meetingId, final record = {'id': meetingId, ...data};
...data, originalDataList.insert(0, record);
});
if (isAsc) { if (isAsc) {
dataList.add({ dataList.add(record);
'id': meetingId,
...data,
});
} else { } else {
dataList.insert(0, { dataList.insert(0, record);
'id': meetingId,
...data,
});
} }
} }
} catch (e) { } catch (e) {
Logger.error('importFailed' Logger.error('importFailed'
.tr .tr
.replaceAll('{filePath}', filePath) .replaceAll('{filePath}', originalPath)
.replaceAll('{error}', .replaceAll('{error}', e.toString())); // 对应中文:导入文件失败: {filePath}, error: {error}
e.toString())); // 对应中文:导入文件失败: {filePath}, error: {error}
} }
} }
EasyLoading.dismiss(); EasyLoading.dismiss();

1
lib/modules/meeting/controllers/mind_map_controller.dart

@ -12,6 +12,7 @@ import 'package:webview_flutter/webview_flutter.dart';
import 'meeting_details_controller.dart'; import 'meeting_details_controller.dart';
/// 思维导图控制器
class MindMapController extends GetxController { class MindMapController extends GetxController {
late final WebViewController webViewController; late final WebViewController webViewController;
final _meetingDetailsController = Get.find<MeetingDetailsController>(); final _meetingDetailsController = Get.find<MeetingDetailsController>();

8
lib/modules/translation/controllers/translation_list_controller.dart

@ -86,7 +86,7 @@ class TranslationListController extends GetxController {
await audioPlayer.setFilePath(filePath); await audioPlayer.setFilePath(filePath);
await audioPlayer.play(); await audioPlayer.play();
} catch (e) { } catch (e) {
print("播放失败: $e"); Logger.e("AudioPlayer", "播放失败: $e");
currentPlayingPath.value = ''; currentPlayingPath.value = '';
} }
} }
@ -146,7 +146,7 @@ class TranslationListController extends GetxController {
audioDurations[filePath] = duration; audioDurations[filePath] = duration;
return duration; return duration;
} catch (e) { } catch (e) {
print("获取音频时长失败: $e"); Logger.e("AudioPlayer", "获取音频时长失败: $e");
return Duration.zero; return Duration.zero;
} }
} }
@ -156,7 +156,7 @@ class TranslationListController 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}"); Logger.d("AudioPlayer", "appDocDir=${dir?.path}");
// Create directory if it doesn't exist // 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); // Create directory tree if needed
@ -186,7 +186,7 @@ class TranslationListController extends GetxController {
files.value = audioFiles; files.value = audioFiles;
} catch (e) { } catch (e) {
print("Error loading files: $e"); Logger.e("AudioPlayer", "Error loading files: $e");
files.value = []; // Return empty list on error files.value = []; // Return empty list on error
} }
} }

Loading…
Cancel
Save