258 lines
8.4 KiB
Dart
258 lines
8.4 KiB
Dart
import 'package:common_utils/common_utils.dart';
|
|
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:forui/forui.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
import 'package:pj_supermarket_cloud/common/index.dart';
|
|
|
|
import '../controller.dart';
|
|
import 'setting_components.dart';
|
|
|
|
Widget settingSync(BuildContext context) {
|
|
final controller = Get.find<SettingController>();
|
|
return Obx(() {
|
|
final sys = controller.sysSetting.value;
|
|
if (sys == null) return const SettingEmpty(message: '暂无同步信息');
|
|
final deviceStatus = AppDeviceStatusTool.status.value;
|
|
final deviceProgress = AppDeviceStatusTool.progress.value;
|
|
final availableDeviceCount = [
|
|
deviceStatus.printerAvailable,
|
|
deviceStatus.steelyardAvailable,
|
|
deviceStatus.cardReaderAvailable,
|
|
deviceStatus.subScreenAvailable,
|
|
].where((available) => available).length;
|
|
final items = <_SyncItem>[
|
|
_SyncItem(
|
|
'deviceStatus',
|
|
'同步设备状态',
|
|
deviceStatus.updatedAt,
|
|
controller.syncDeviceStatus,
|
|
icon: FAssets.icons.hardDrive,
|
|
statusText: deviceProgress.running
|
|
? deviceProgress.message
|
|
: '已连接 $availableDeviceCount/4 个设备',
|
|
warning: availableDeviceCount < 4,
|
|
forceSyncing: deviceProgress.running,
|
|
),
|
|
_SyncItem('config', '同步设备信息', sys.syncTime, controller.syncConfig),
|
|
_SyncItem('mq', '同步长链接', sys.mqSyncTime, controller.syncMq),
|
|
_SyncItem(
|
|
'classify',
|
|
'同步分类',
|
|
sys.sysType == SysType.CANTEEN
|
|
? sys.canteenClassifySyncTime
|
|
: sys.supermarketClassifySyncTime,
|
|
controller.syncClassify,
|
|
),
|
|
_SyncItem(
|
|
'product',
|
|
'同步商品',
|
|
sys.sysType == SysType.CANTEEN
|
|
? sys.canteenProductSyncTime
|
|
: sys.supermarketProductSyncTime,
|
|
controller.syncProduct,
|
|
),
|
|
_SyncItem(
|
|
'offlineOrder',
|
|
'同步离线订单',
|
|
sys.offlineOrderSyncTime,
|
|
controller.syncOfflineOrder,
|
|
icon: FAssets.icons.cloudDownload,
|
|
),
|
|
];
|
|
return Column(
|
|
children: [
|
|
Expanded(
|
|
child: Container(
|
|
key: const ValueKey('setting-sync-list'),
|
|
clipBehavior: Clip.antiAlias,
|
|
decoration: BoxDecoration(
|
|
color: XfjDesignTokens.surface,
|
|
border: Border.all(color: XfjDesignTokens.line),
|
|
borderRadius: BorderRadius.circular(XfjDesignTokens.cardRadius),
|
|
),
|
|
child: ListView.builder(
|
|
padding: EdgeInsets.zero,
|
|
itemCount: items.length,
|
|
itemBuilder: (context, index) {
|
|
final item = items[index];
|
|
final itemSyncing = controller.syncingKey.value == item.key ||
|
|
item.forceSyncing;
|
|
return _SyncRow(
|
|
item: item,
|
|
syncing: itemSyncing,
|
|
failed: controller.syncFailedKeys.contains(item.key),
|
|
enabled: controller.syncingKey.isEmpty ||
|
|
(item.key == 'deviceStatus' &&
|
|
(controller.syncingKey.value == 'deviceStatus' ||
|
|
item.forceSyncing)),
|
|
showDivider: index != items.length - 1,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
SizedBox(height: XfjDesignTokens.cardGap.h),
|
|
const SettingNotice(
|
|
text: '网络接口可用不等于业务服务可用。同步失败时会保留本地数据,可在网络恢复后重新执行。',
|
|
),
|
|
],
|
|
);
|
|
});
|
|
}
|
|
|
|
class _SyncItem {
|
|
const _SyncItem(
|
|
this.key,
|
|
this.title,
|
|
this.time,
|
|
this.action, {
|
|
this.icon,
|
|
this.statusText,
|
|
this.warning = false,
|
|
this.forceSyncing = false,
|
|
});
|
|
|
|
final String key;
|
|
final String title;
|
|
final DateTime? time;
|
|
final Future<void> Function() action;
|
|
final SvgAsset? icon;
|
|
final String? statusText;
|
|
final bool warning;
|
|
final bool forceSyncing;
|
|
}
|
|
|
|
class _SyncRow extends StatelessWidget {
|
|
const _SyncRow({
|
|
required this.item,
|
|
required this.syncing,
|
|
required this.failed,
|
|
required this.enabled,
|
|
required this.showDivider,
|
|
});
|
|
|
|
final _SyncItem item;
|
|
final bool syncing;
|
|
final bool failed;
|
|
final bool enabled;
|
|
final bool showDivider;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = FTheme.of(context);
|
|
final statusColor = failed
|
|
? XfjDesignTokens.danger
|
|
: syncing
|
|
? XfjDesignTokens.primary
|
|
: item.warning
|
|
? XfjDesignTokens.warning
|
|
: XfjDesignTokens.success;
|
|
return Opacity(
|
|
opacity: enabled || syncing ? 1 : 0.55,
|
|
child: InkWell(
|
|
onTap: enabled ? item.action : null,
|
|
child: Container(
|
|
constraints: BoxConstraints(minHeight: 76.h),
|
|
padding: EdgeInsets.symmetric(horizontal: 18.w, vertical: 10.h),
|
|
decoration: BoxDecoration(
|
|
border: showDivider
|
|
? const Border(
|
|
bottom: BorderSide(color: XfjDesignTokens.line),
|
|
)
|
|
: null,
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
width: 44.w,
|
|
height: 44.w,
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
color: XfjDesignTokens.primarySoft,
|
|
borderRadius: BorderRadius.circular(
|
|
XfjDesignTokens.controlRadius,
|
|
),
|
|
),
|
|
child: syncing
|
|
? SizedBox(
|
|
width: 22.w,
|
|
height: 22.w,
|
|
child: const CircularProgressIndicator(strokeWidth: 2),
|
|
)
|
|
: FIcon(
|
|
item.icon ?? FAssets.icons.refreshCw,
|
|
color: XfjDesignTokens.primary,
|
|
size: 24.sp,
|
|
),
|
|
),
|
|
SizedBox(width: 14.w),
|
|
Expanded(
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
item.title,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: theme.typography.base.copyWith(
|
|
color: XfjDesignTokens.ink,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 20.w),
|
|
SizedBox(
|
|
width: 360.w,
|
|
child: Text(
|
|
'最后同步:${_formatTime(item.time)}',
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
textAlign: TextAlign.right,
|
|
style: theme.typography.sm.copyWith(
|
|
color: XfjDesignTokens.muted,
|
|
fontFeatures: const [FontFeature.tabularFigures()],
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 20.w),
|
|
SizedBox(
|
|
width: 320.w,
|
|
child: Text(
|
|
failed
|
|
? '同步失败,点击重试'
|
|
: syncing
|
|
? item.statusText ?? '同步中...'
|
|
: item.statusText ?? '状态正常',
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
textAlign: TextAlign.right,
|
|
style: theme.typography.sm.copyWith(
|
|
color: statusColor,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
SizedBox(width: 14.w),
|
|
FIcon(
|
|
FAssets.icons.chevronRight,
|
|
color: XfjDesignTokens.muted,
|
|
size: 22.sp,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
String _formatTime(DateTime? time) {
|
|
if (time == null) return '未同步';
|
|
return DateUtil.formatDate(time, format: DateFormats.full);
|
|
}
|