Files
pj_supermarket_cloud/lib/pages/setting/view.dart
T
2026-10-28 19:11:38 +08:00

204 lines
7.1 KiB
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 'package:pj_supermarket_cloud/pages/setting/widgets/index.dart';
import 'package:pj_supermarket_cloud/pages/setting/widgets/setting_components.dart';
import 'index.dart';
class SettingPage extends GetView<SettingController> {
const SettingPage({super.key});
/// 沿用原有业务设置的设备绑定要求,本地配置与诊断入口继续允许未绑定访问。
static const _requiresBinding = {
SettingMenuType.syncSetting,
SettingMenuType.paySetting,
SettingMenuType.faceSetting,
SettingMenuType.productSetting,
SettingMenuType.facePluginSetting,
SettingMenuType.versionSetting,
};
// 主视图
Widget _buildView() {
final context = Get.context!;
final width = Get.context!.sizes.width;
final theme = FTheme.of(context);
return <Widget>[
_buildMenu().width(width * 0.2).height(double.infinity),
FDivider(
axis: Axis.vertical,
style: theme.dividerStyles.verticalStyle.copyWith(
color: theme.colorScheme.primary,
),
),
Obx(() => _buildDetail(context, controller.cuurentMenuType.value))
.marginSymmetric(horizontal: 10.w)
.expanded(),
]
.toRow(crossAxisAlignment: CrossAxisAlignment.stretch)
.height(double.infinity);
}
Widget _buildMenu() {
final theme = FTheme.of(Get.context!);
return Obx(
() => controller.menuList
.map((v) {
final isSelect = controller.cuurentMenuType.value == v.type;
return <Widget>[
FIcon(
v.prefixIcon,
color: isSelect
? theme.colorScheme.secondary
: theme.colorScheme.primary,
),
Flexible(
// 窄屏放大字体时只约束长菜单标题,不能把确认图标挤出侧栏。
child: Text(
v.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.typography.xl.copyWith(
color: isSelect
? theme.colorScheme.secondary
: theme.colorScheme.primary,
),
).paddingHorizontal(20.w),
),
isSelect
? FIcon(
FAssets.icons.check,
color: theme.colorScheme.secondary,
)
: SizedBox.shrink(),
]
.toRow(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
)
.decorated(
color: isSelect
? theme.colorScheme.primary
: theme.colorScheme.secondary,
border: Border.all(
color: theme.colorScheme.primary,
width: 1,
),
borderRadius: theme.style.borderRadius,
)
.onTap(() => controller.doMenu(v));
})
.toList()
.toColumnSpace(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
space: 10.h,
)
.height(double.infinity),
);
}
/// 绑定校验的等待、失败与未绑定均显示明确状态,避免用空组件掩盖访问原因。
Widget _buildDetail(BuildContext context, SettingMenuType type) {
return FutureBuilder<bool>(
future: controller.checkIsBind(),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
SizedBox(height: 16.h),
Text('正在读取设备配置…', style: FTheme.of(context).typography.base),
],
),
);
}
if (snapshot.hasError) {
return _accessNotice(
message: '设备配置读取失败,请重试',
actionLabel: '重试',
// 重建当前设置页以重新创建读取 Future,不能继续复用失败的快照。
onTap: () => controller.update(['setting']),
);
}
if (snapshot.data != true && _requiresBinding.contains(type)) {
return _accessNotice(
message: '设备尚未绑定商户,请先在“基本信息”中完成绑定',
actionLabel: '前往基本信息',
onTap: () => controller.openMenu(SettingMenuType.baseInfo),
);
}
switch (type) {
case SettingMenuType.baseInfo:
return settingBaseInfo(context);
case SettingMenuType.backup:
return settingBackup(context);
case SettingMenuType.syncSetting:
return settingSync(context);
case SettingMenuType.paySetting:
return settingPay(context);
case SettingMenuType.offlineUserSetting:
return settingOfflineUser(context);
case SettingMenuType.faceSetting:
return settingFace(context);
case SettingMenuType.mealPeriodSetting:
return const SettingMealPeriods();
case SettingMenuType.productSetting:
return settingProduct(context);
case SettingMenuType.logPreview:
return const SettingLogPreview();
case SettingMenuType.facePluginSetting:
return settingFacePlugin(context);
case SettingMenuType.versionSetting:
return settingVersionSetting(context);
}
},
);
}
/// 复用设置页空状态与操作按钮,为未绑定和读取失败提供可执行的恢复入口。
Widget _accessNotice({
required String message,
required String actionLabel,
required VoidCallback onTap,
}) =>
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SettingEmpty(message: message),
SizedBox(height: 16.h),
SettingActionButton(
label: actionLabel, onTap: onTap, primary: true),
],
),
);
@override
Widget build(BuildContext context) {
return GetBuilder<SettingController>(
id: "setting",
builder: (_) {
// FScaffold 不会创建 Material;正文与恢复按钮的 InkWell 需要统一的涟漪宿主。
return Material(
type: MaterialType.transparency,
child: FScaffold(
// 标题与返回入口由终端外壳顶栏统一提供;设置模块自身的分区菜单
// 保留在内容区并直接贴紧顶栏。
content: _buildView(),
contentPad: true,
resizeToAvoidBottomInset: false,
),
);
},
);
}
}