Compare commits
2 Commits
288d629f99
...
6629c8047f
| Author | SHA1 | Date | |
|---|---|---|---|
| 6629c8047f | |||
| bfa615a7f4 |
@@ -131,13 +131,13 @@
|
|||||||
<!-- 1. 配置安全密钥 -->
|
<!-- 1. 配置安全密钥 -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window._AMapSecurityConfig = {
|
window._AMapSecurityConfig = {
|
||||||
securityJsCode: '0529b72df6bf0c577ff2182cb8b1d970',
|
securityJsCode: 'aa3a22c19ed76b27f8a587555d6981c8',
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- 2. 加载地图和插件 (去掉了 Geolocation 插件,避免弹窗) -->
|
<!-- 2. 加载地图和插件 (去掉了 Geolocation 插件,避免弹窗) -->
|
||||||
<script
|
<script
|
||||||
src="https://webapi.amap.com/maps?v=2.0&key=2cc1d822e313307fe311c3127a1deeb5&plugin=AMap.MoveAnimation,AMap.Driving,AMap.TruckDriving,AMap.AutoComplete,AMap.ToolBar,AMap.Scale,AMap.Geocoder">
|
src="https://webapi.amap.com/maps?v=2.0&key=ecd74ece8cb14c9dad67675f83c3274d&plugin=AMap.MoveAnimation,AMap.Driving,AMap.TruckDriving,AMap.AutoComplete,AMap.ToolBar,AMap.Scale,AMap.Geocoder">
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:getx_scaffold/getx_scaffold.dart';
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
import 'package:ln_jq_app/common/model/base_model.dart';
|
import 'package:ln_jq_app/common/model/base_model.dart';
|
||||||
import 'package:ln_jq_app/common/styles/theme.dart';
|
import 'package:ln_jq_app/common/styles/theme.dart';
|
||||||
@@ -277,9 +278,10 @@ class SiteController extends GetxController with BaseControllerMixin {
|
|||||||
child: TextField(
|
child: TextField(
|
||||||
controller: amountController,
|
controller: amountController,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
keyboardType: const TextInputType.numberWithOptions(
|
keyboardType: TextInputType.number,
|
||||||
decimal: true,
|
inputFormatters: [
|
||||||
),
|
FilteringTextInputFormatter.digitsOnly, // 只允许数字输入
|
||||||
|
],
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import 'package:ln_jq_app/pages/qr_code/view.dart';
|
|||||||
import 'package:ln_jq_app/storage_service.dart';
|
import 'package:ln_jq_app/storage_service.dart';
|
||||||
|
|
||||||
import '../../../common/styles/theme.dart';
|
import '../../../common/styles/theme.dart';
|
||||||
|
import 'reservation_list_bottomsheet.dart';
|
||||||
|
|
||||||
/// Helper class for managing time slots
|
/// Helper class for managing time slots
|
||||||
class TimeSlot {
|
class TimeSlot {
|
||||||
@@ -547,6 +548,10 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
num maxHydrogen = 0;
|
num maxHydrogen = 0;
|
||||||
String difference = "";
|
String difference = "";
|
||||||
|
|
||||||
|
//用来管理查看预约的弹窗
|
||||||
|
Worker? _sheetWorker;
|
||||||
|
bool init = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get listenLifecycleEvent => true;
|
bool get listenLifecycleEvent => true;
|
||||||
|
|
||||||
@@ -555,6 +560,32 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
super.onInit();
|
super.onInit();
|
||||||
getUserBindCarInfo();
|
getUserBindCarInfo();
|
||||||
getSiteList();
|
getSiteList();
|
||||||
|
|
||||||
|
if (!init) {
|
||||||
|
_setupListener();
|
||||||
|
init = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_sheetWorker?.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setupListener() {
|
||||||
|
_sheetWorker = ever(shouldShowReservationList, (bool shouldShow) {
|
||||||
|
if (shouldShow) {
|
||||||
|
Get.bottomSheet(
|
||||||
|
const ReservationListBottomSheet(),
|
||||||
|
isScrollControlled: true, // 允许弹窗使用更多屏幕高度
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 重要:显示后立即将信号重置为 false,防止不必要的重复弹出
|
||||||
|
shouldShowReservationList.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void getUserBindCarInfo() {
|
void getUserBindCarInfo() {
|
||||||
@@ -628,6 +659,11 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
|
|||||||
final leftHydrogenNum = double.tryParse(leftHydrogen) ?? 0.0;
|
final leftHydrogenNum = double.tryParse(leftHydrogen) ?? 0.0;
|
||||||
difference = (maxHydrogen - leftHydrogenNum).toStringAsFixed(2);
|
difference = (maxHydrogen - leftHydrogenNum).toStringAsFixed(2);
|
||||||
|
|
||||||
|
int flooredDifference = (maxHydrogen - leftHydrogenNum).floor();
|
||||||
|
if (flooredDifference > 0) {
|
||||||
|
amountController.text = flooredDifference.toString();
|
||||||
|
}
|
||||||
|
|
||||||
updateUi();
|
updateUi();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import 'reservation_list_bottomsheet.dart';
|
|||||||
class ReservationPage extends GetView<C_ReservationController> {
|
class ReservationPage extends GetView<C_ReservationController> {
|
||||||
ReservationPage({super.key});
|
ReservationPage({super.key});
|
||||||
|
|
||||||
bool init = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -21,10 +21,7 @@ class ReservationPage extends GetView<C_ReservationController> {
|
|||||||
init: C_ReservationController(),
|
init: C_ReservationController(),
|
||||||
id: 'reservation',
|
id: 'reservation',
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
if (!init) {
|
|
||||||
_setupListener(context);
|
|
||||||
init = true;
|
|
||||||
}
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.grey[100],
|
backgroundColor: Colors.grey[100],
|
||||||
body: GestureDetector(
|
body: GestureDetector(
|
||||||
@@ -335,20 +332,7 @@ class ReservationPage extends GetView<C_ReservationController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setupListener(BuildContext context) {
|
|
||||||
ever(controller.shouldShowReservationList, (bool shouldShow) {
|
|
||||||
if (shouldShow) {
|
|
||||||
Get.bottomSheet(
|
|
||||||
const ReservationListBottomSheet(),
|
|
||||||
isScrollControlled: true, // 允许弹窗使用更多屏幕高度
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 重要:显示后立即将信号重置为 false,防止不必要的重复弹出
|
|
||||||
controller.shouldShowReservationList.value = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 表单中的可点击行 (用于日期和时间选择)
|
// 表单中的可点击行 (用于日期和时间选择)
|
||||||
Widget _buildPickerRow({
|
Widget _buildPickerRow({
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ class QrCodeController extends GetxController
|
|||||||
final RxBool isFlashOn = false.obs;
|
final RxBool isFlashOn = false.obs;
|
||||||
final RxBool isProcessingResult = false.obs;
|
final RxBool isProcessingResult = false.obs;
|
||||||
|
|
||||||
|
final RxBool hasPermission = false.obs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@@ -47,7 +49,6 @@ class QrCodeController extends GetxController
|
|||||||
isProcessingResult.value = true;
|
isProcessingResult.value = true;
|
||||||
scannerController.stop();
|
scannerController.stop();
|
||||||
animationController.stop();
|
animationController.stop();
|
||||||
print("相机识别到的内容: ${barcode.rawValue!}");
|
|
||||||
renderResult(barcode.rawValue!);
|
renderResult(barcode.rawValue!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,10 +58,10 @@ class QrCodeController extends GetxController
|
|||||||
isProcessingResult.value = false;
|
isProcessingResult.value = false;
|
||||||
try {
|
try {
|
||||||
scannerController.start();
|
scannerController.start();
|
||||||
|
animationController.repeat(reverse: false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("无法重启相机: $e");
|
print("无法重启相机: $e");
|
||||||
}
|
}
|
||||||
animationController.repeat(reverse: false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 从相册选择图片并扫描二维码
|
/// 从相册选择图片并扫描二维码
|
||||||
@@ -120,10 +121,19 @@ class QrCodeController extends GetxController
|
|||||||
/// 请求相机权限
|
/// 请求相机权限
|
||||||
void requestPermission() async {
|
void requestPermission() async {
|
||||||
var status = await Permission.camera.request();
|
var status = await Permission.camera.request();
|
||||||
|
|
||||||
|
hasPermission.value = status.isGranted;
|
||||||
|
|
||||||
if (!status.isGranted) {
|
if (!status.isGranted) {
|
||||||
showErrorToast('请授予相机权限以使用扫描功能');
|
if (status.isPermanentlyDenied) {
|
||||||
Get.back();
|
showErrorToast('相机权限已被永久拒绝,请到系统设置中开启');
|
||||||
|
// 延迟一会再引导用户去设置
|
||||||
|
Future.delayed(const Duration(seconds: 2), () => openAppSettings());
|
||||||
|
} else {
|
||||||
|
showErrorToast('请授予相机权限以使用扫描功能');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void requestPhotoPermission() async {
|
void requestPhotoPermission() async {
|
||||||
|
|||||||
@@ -29,27 +29,77 @@ class QrCodePage extends GetView<QrCodeController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Stack(
|
body: Obx(() { // 1. 使用 Obx 包裹整个 body
|
||||||
alignment: Alignment.center,
|
// 根据权限状态来决定显示什么
|
||||||
children: [
|
if (controller.hasPermission.value) {
|
||||||
// 1. 使用 MobileScanner 作为扫描视图
|
// 如果有权限,显示扫描器
|
||||||
MobileScanner(
|
return _buildScannerView(context);
|
||||||
controller: controller.scannerController,
|
} else {
|
||||||
onDetect: controller.onDetect,
|
// 如果没有权限,显示引导界面
|
||||||
// 您可以自定义扫描框的样式
|
return _buildPermissionDeniedView();
|
||||||
scanWindow: Rect.fromCenter(
|
}
|
||||||
center: Offset(
|
}),
|
||||||
MediaQuery.of(context).size.width / 2,
|
);
|
||||||
MediaQuery.of(context).size.height / 2 - 50,
|
}
|
||||||
),
|
Widget _buildScannerView(BuildContext context){
|
||||||
width: 250,
|
if (!controller.animationController.isAnimating) {
|
||||||
height: 250,
|
controller.animationController.repeat(reverse: false);
|
||||||
|
}
|
||||||
|
return Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
// 使用 MobileScanner 作为扫描视图
|
||||||
|
MobileScanner(
|
||||||
|
controller: controller.scannerController,
|
||||||
|
onDetect: controller.onDetect,
|
||||||
|
// 您可以自定义扫描框的样式
|
||||||
|
scanWindow: Rect.fromCenter(
|
||||||
|
center: Offset(
|
||||||
|
MediaQuery.of(context).size.width / 2,
|
||||||
|
MediaQuery.of(context).size.height / 2 - 50,
|
||||||
),
|
),
|
||||||
|
width: 250,
|
||||||
|
height: 250,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 扫描动画和覆盖层
|
||||||
|
_buildScannerOverlay(context),
|
||||||
|
// 底部的功能按钮
|
||||||
|
Positioned(bottom: 80, left: 0, right: 0, child: _buildActionButtons()),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPermissionDeniedView() {
|
||||||
|
// 确保动画是停止的
|
||||||
|
if (controller.animationController.isAnimating) {
|
||||||
|
controller.animationController.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
color: Colors.black,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: const EdgeInsets.all(24.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.no_photography, color: Colors.white70, size: 64),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Text(
|
||||||
|
'需要相机权限',
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const Text(
|
||||||
|
'请授予相机权限以使用扫码功能。',
|
||||||
|
style: TextStyle(color: Colors.white70, fontSize: 14),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: controller.requestPermission, // 点击按钮重新请求权限
|
||||||
|
child: const Text('授予权限'),
|
||||||
),
|
),
|
||||||
// 扫描动画和覆盖层
|
|
||||||
_buildScannerOverlay(context),
|
|
||||||
// 底部的功能按钮
|
|
||||||
Positioned(bottom: 80, left: 0, right: 0, child: _buildActionButtons()),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user