|
|
|
@ -4,6 +4,7 @@ import 'package:get/get.dart'; |
|
|
|
import '../../../core/theme/app_colors.dart'; |
|
|
|
import '../controllers/meeting_stats_controller.dart'; |
|
|
|
import '../../../data/models/user_Info.dart'; |
|
|
|
import '../../../data/models/meeting_usage_stats.dart'; |
|
|
|
|
|
|
|
class MeetingStatsView extends GetView<MeetingStatsController> { |
|
|
|
const MeetingStatsView({Key? key}) : super(key: key); |
|
|
|
@ -14,14 +15,14 @@ class MeetingStatsView extends GetView<MeetingStatsController> { |
|
|
|
|
|
|
|
return Scaffold( |
|
|
|
backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.grey[50], |
|
|
|
appBar: _buildAppBar(isDarkMode), |
|
|
|
appBar: _buildAppBar(context, isDarkMode), |
|
|
|
body: Obx(() => controller.isLoading.value |
|
|
|
? const Center(child: CircularProgressIndicator()) |
|
|
|
: _buildBody(isDarkMode)), |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
PreferredSizeWidget _buildAppBar(bool isDarkMode) { |
|
|
|
PreferredSizeWidget _buildAppBar(BuildContext context, bool isDarkMode) { |
|
|
|
return AppBar( |
|
|
|
leading: IconButton( |
|
|
|
icon: Icon(Icons.arrow_back_ios, |
|
|
|
@ -39,6 +40,27 @@ class MeetingStatsView extends GetView<MeetingStatsController> { |
|
|
|
), |
|
|
|
centerTitle: true, |
|
|
|
actions: [ |
|
|
|
IconButton( |
|
|
|
icon: Icon(Icons.date_range, |
|
|
|
color: isDarkMode ? Colors.white : Colors.black), |
|
|
|
onPressed: () async { |
|
|
|
final now = DateTime.now(); |
|
|
|
final initialStart = controller.rangeStart.value ?? |
|
|
|
DateTime(now.year, now.month, now.day); |
|
|
|
final initialEnd = controller.rangeEnd.value ?? |
|
|
|
DateTime(now.year, now.month, now.day); |
|
|
|
final picked = await showDateRangePicker( |
|
|
|
context: context, |
|
|
|
firstDate: DateTime(now.year - 1), |
|
|
|
lastDate: DateTime(now.year + 1), |
|
|
|
initialDateRange: |
|
|
|
DateTimeRange(start: initialStart, end: initialEnd), |
|
|
|
); |
|
|
|
if (picked != null) { |
|
|
|
await controller.setCustomRangeDates(picked.start, picked.end); |
|
|
|
} |
|
|
|
}, |
|
|
|
), |
|
|
|
IconButton( |
|
|
|
icon: Icon(Icons.refresh, |
|
|
|
color: isDarkMode ? Colors.white : Colors.black), |
|
|
|
@ -49,16 +71,32 @@ class MeetingStatsView extends GetView<MeetingStatsController> { |
|
|
|
} |
|
|
|
|
|
|
|
Widget _buildBody(bool isDarkMode) { |
|
|
|
final hasRange = controller.rangeStart.value != null && |
|
|
|
controller.rangeEnd.value != null; |
|
|
|
final historyTitle = hasRange |
|
|
|
? "${'history'.tr} (${controller.formatDate(controller.rangeStart.value!)} ~ ${controller.formatDate(controller.rangeEnd.value!)})" |
|
|
|
: 'history'.tr; |
|
|
|
return Column( |
|
|
|
children: [ |
|
|
|
_buildIntegralRow(isDarkMode), |
|
|
|
_buildTimeRangeSelector(isDarkMode), |
|
|
|
Expanded( |
|
|
|
child: SingleChildScrollView( |
|
|
|
padding: EdgeInsets.all(16.w), |
|
|
|
child: Column( |
|
|
|
children: [ |
|
|
|
_buildOverviewCard(isDarkMode), |
|
|
|
_buildOverviewCard( |
|
|
|
'today'.tr, // 今日 |
|
|
|
isDarkMode, |
|
|
|
controller.todayStats.value, |
|
|
|
controller.todayStorageStats.value, |
|
|
|
), |
|
|
|
SizedBox(height: 16.h), |
|
|
|
_buildOverviewCard( |
|
|
|
historyTitle, |
|
|
|
isDarkMode, |
|
|
|
controller.rangeStats.value, |
|
|
|
controller.rangeStorageStats.value, |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
@ -112,60 +150,12 @@ class MeetingStatsView extends GetView<MeetingStatsController> { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
Widget _buildTimeRangeSelector(bool isDarkMode) { |
|
|
|
return Container( |
|
|
|
margin: EdgeInsets.all(16.w), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: isDarkMode ? AppColors.cardBackground : Colors.white, |
|
|
|
borderRadius: BorderRadius.circular(12.r), |
|
|
|
boxShadow: [ |
|
|
|
BoxShadow( |
|
|
|
color: Colors.black.withValues(alpha: 0.05), |
|
|
|
blurRadius: 10, |
|
|
|
offset: const Offset(0, 2)), |
|
|
|
], |
|
|
|
), |
|
|
|
child: Obx(() => Row( |
|
|
|
children: [ |
|
|
|
_buildTimeRangeTab('today'.tr, 0, isDarkMode), // 今日 |
|
|
|
_buildTimeRangeTab('thisWeek'.tr, 1, isDarkMode), // 本周 |
|
|
|
_buildTimeRangeTab('thisMonth'.tr, 2, isDarkMode), // 本月 |
|
|
|
_buildTimeRangeTab('history'.tr, 3, isDarkMode), // 历史 |
|
|
|
], |
|
|
|
)), |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
Widget _buildTimeRangeTab(String title, int index, bool isDarkMode) { |
|
|
|
final isSelected = controller.selectedTabIndex.value == index; |
|
|
|
|
|
|
|
return Expanded( |
|
|
|
child: GestureDetector( |
|
|
|
onTap: () => controller.switchTimeRange(index), |
|
|
|
child: Container( |
|
|
|
padding: EdgeInsets.symmetric(vertical: 12.h), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: isSelected ? AppColors.primary : Colors.transparent, |
|
|
|
borderRadius: BorderRadius.circular(12.r), |
|
|
|
), |
|
|
|
child: Text( |
|
|
|
title, |
|
|
|
textAlign: TextAlign.center, |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 14.sp, |
|
|
|
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, |
|
|
|
color: isSelected |
|
|
|
? Colors.white |
|
|
|
: (isDarkMode ? Colors.white70 : Colors.black54), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
Widget _buildOverviewCard(bool isDarkMode) { |
|
|
|
final stats = controller.currentStats; |
|
|
|
Widget _buildOverviewCard( |
|
|
|
String title, |
|
|
|
bool isDarkMode, |
|
|
|
MeetingAsrHistoryStats asrStats, |
|
|
|
MeetingStorageHistoryStats storageStats, |
|
|
|
) { |
|
|
|
return Container( |
|
|
|
padding: EdgeInsets.all(16.w), |
|
|
|
decoration: BoxDecoration( |
|
|
|
@ -185,13 +175,13 @@ class MeetingStatsView extends GetView<MeetingStatsController> { |
|
|
|
children: [ |
|
|
|
Icon(Icons.dashboard, color: AppColors.primary, size: 20.sp), |
|
|
|
SizedBox(width: 8.w), |
|
|
|
Obx(() => Text( |
|
|
|
'${controller.selectedTimeRange.value}${'overview'.tr}', |
|
|
|
Text( |
|
|
|
'$title${'overview'.tr}', |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 16.sp, |
|
|
|
fontWeight: FontWeight.w600, |
|
|
|
color: isDarkMode ? Colors.white : Colors.black), |
|
|
|
)), |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
SizedBox(height: 16.h), |
|
|
|
@ -200,13 +190,13 @@ class MeetingStatsView extends GetView<MeetingStatsController> { |
|
|
|
Expanded( |
|
|
|
child: _buildStatItem( |
|
|
|
'asrApiCalls'.tr, // ASR调用次数 |
|
|
|
controller.formatNumber(stats.allAsrCalls), |
|
|
|
controller.formatNumber(asrStats.allAsrCalls), |
|
|
|
Icons.api, |
|
|
|
isDarkMode)), |
|
|
|
Expanded( |
|
|
|
child: _buildStatItem( |
|
|
|
'totalAudioDuration'.tr, // 音频总时长 |
|
|
|
controller.formatDuration(stats.allAudioSeconds), |
|
|
|
controller.formatDuration(asrStats.allAudioSeconds), |
|
|
|
Icons.mic, |
|
|
|
isDarkMode)), |
|
|
|
], |
|
|
|
@ -217,17 +207,34 @@ class MeetingStatsView extends GetView<MeetingStatsController> { |
|
|
|
Expanded( |
|
|
|
child: _buildStatItem( |
|
|
|
'audioFileSize'.tr, // 音频文件大小 |
|
|
|
controller.formatBytes(stats.allAudioFileBytes), |
|
|
|
controller.formatBytes(asrStats.allAudioFileBytes), |
|
|
|
Icons.folder, |
|
|
|
isDarkMode)), |
|
|
|
Expanded( |
|
|
|
child: _buildStatItem( |
|
|
|
'transcriptBytes'.tr, // 转写字节 |
|
|
|
controller.formatNumber(stats.allTranscriptBytes), |
|
|
|
controller.formatNumber(asrStats.allTranscriptBytes), |
|
|
|
Icons.text_snippet, |
|
|
|
isDarkMode)), |
|
|
|
], |
|
|
|
), |
|
|
|
SizedBox(height: 12.h), |
|
|
|
Row( |
|
|
|
children: [ |
|
|
|
Expanded( |
|
|
|
child: _buildStatItem( |
|
|
|
'storageUploads'.tr, // 对象存储上传次数 |
|
|
|
controller.formatNumber(storageStats.allStorageUploads), |
|
|
|
Icons.cloud_upload, |
|
|
|
isDarkMode)), |
|
|
|
Expanded( |
|
|
|
child: _buildStatItem( |
|
|
|
'storageBytes'.tr, // 对象存储总大小 |
|
|
|
controller.formatBytes(storageStats.allStorageBytes), |
|
|
|
Icons.cloud, |
|
|
|
isDarkMode)), |
|
|
|
], |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
); |
|
|
|
|