feat:二维码支付

This commit is contained in:
dzc committed 2025-09-01 19:40:47 +08:00
1 parent 2f1c98392f
commit c94a909bfe
7 files changed
+195 -11

No files matched your search

+5 -2
View File
@@ -10,9 +10,12 @@ class Constants {
static const pwdEncKey = 'pigxpigxpigxpigx';
/// 服务 url 线上
// static const apiUrl = 'https://stgl.pj.gov.cn/api';
static const apiUrl = 'https://stgl.pj.gov.cn/api';
static const apiUrl = 'http://192.168.101.196:9999';
// static const apiUrl = 'http://192.168.101.196:9999';
/// h5 支付页面
static const h5PayUrl = "https://stgl.pj.gov.cn/h5/#/pages/pay/scanPay";
/// 静态资源 url
static const ossUrl = apiUrl;
@@ -0,0 +1,171 @@
import 'dart:async';
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:pretty_qr_code/pretty_qr_code.dart';
Future<T?> showQrCodeDialog<T>(
BuildContext context, {
required String qrData,
int countDownSeconds = 30,
required VoidCallback onFinished,
}) {
return showDialog<T?>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AppQrCodeDialog(
qrData: qrData,
countDownSeconds: countDownSeconds,
onFinished: onFinished,
);
},
);
}
// 二维码弹窗
class AppQrCodeDialog extends StatefulWidget {
const AppQrCodeDialog({
super.key,
required this.qrData,
required this.countDownSeconds,
required this.onFinished,
});
final String qrData;
final int countDownSeconds;
final VoidCallback onFinished;
@override
State<AppQrCodeDialog> createState() => _AppQrCodeDialogState();
}
class _AppQrCodeDialogState extends State<AppQrCodeDialog> {
// 当前的倒计时秒数
late int _currentSeconds;
// 倒计时
Timer? _countdownTimer;
// 倒计时是否运行中
bool _isRunning = false;
@override
void initState() {
super.initState();
_currentSeconds = widget.countDownSeconds;
// 创建倒计时
_createCountDown();
}
@override
void dispose() {
_destroyCountDown();
super.dispose();
}
// 创建倒计时
void _createCountDown() {
if (_isRunning) return;
_isRunning = true;
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (_currentSeconds <= 0) {
_countdownTimer?.cancel();
_isRunning = false;
// 倒计时结束回调
widget.onFinished.call();
Navigator.of(context).pop();
return;
}
setState(() {
_currentSeconds--;
});
});
}
// 销毁倒计时
void _destroyCountDown() {
_countdownTimer?.cancel();
_countdownTimer = null;
}
@override
Widget build(BuildContext context) {
final theme = FTheme.of(context);
final qrCode = QrCode(
16,
QrErrorCorrectLevel.H,
)..addData(widget.qrData);
// 宽高
final dialogWidth = MediaQuery.of(context).size.width * 0.5;
final dialogHeight = MediaQuery.of(context).size.height * 0.7;
return FDialog(
title: Text(
"扫一扫支付",
style: theme.typography.xl3,
).center().marginOnly(bottom: 20.h),
style: theme.dialogStyle.copyWith(
insetPadding: EdgeInsets.zero,
maxWidth: dialogWidth,
minWidth: dialogHeight,
horizontalStyle: theme.dialogStyle.horizontalStyle.copyWith(
padding: EdgeInsets.all(20.w),
),
),
body: <Widget>[
Text(
'请打开"浙政钉"或"诗画浦江"点击右上角扫一扫图标',
style: theme.typography.xl.copyWith(
height: 1,
),
),
Stack(
children: [
PrettyQrView(
qrImage: QrImage(qrCode),
decoration: const PrettyQrDecoration(),
),
Positioned(
left: 0,
top: 0,
right: 0,
bottom: 0,
child: <Widget>[
FIcon(
FAssets.icons.check,
size: theme.typography.xl4.fontSize,
color: Colors.white,
)
.paddingAll(20.w)
.decorated(
color: Colors.greenAccent[200],
)
.clipOval(),
Text(
"扫码成功",
style: theme.typography.xl3.copyWith(
color: Colors.greenAccent[200],
fontWeight: FontWeight.bold,
),
),
]
.toColumn(mainAxisAlignment: MainAxisAlignment.center)
.center()
.decorated(color: Colors.black45)
.offstage(offstage: true),
),
],
).marginSymmetric(horizontal: 100.w, vertical: 50.h),
Text(
'请在$_currentSeconds秒内完成扫码支付',
style: theme.typography.xl2.copyWith(
color: theme.colorScheme.error,
height: 1,
),
),
].toColumn(),
actions: [],
);
}
}
+1
View File
@@ -14,6 +14,7 @@ export './app/app_logo.dart';
export './app/app_message_dialog.dart';
export './app/app_page.dart';
export './app/app_price.dart';
export './app/app_qr_code_dialog.dart';
export './app/app_radio_hour_type_dialog.dart';
export './app/app_title.dart';
export './app/app_wallet_selector.dart';
+8 -8
View File
@@ -21,7 +21,7 @@ class PanelController extends GetxController {
PanelItem(title: "开卡管理", visible: true, type: PanelType.cardActive),
PanelItem(title: "设置", visible: true, type: PanelType.setting),
PanelItem(title: "退出登录", visible: true, type: PanelType.logout),
// PanelItem(title: "测试", visible: true, type: PanelType.test),
PanelItem(title: "测试", visible: true, type: PanelType.test),
].obs;
final canteenMenus = [
@@ -142,13 +142,13 @@ class PanelController extends GetxController {
Get.offAndToNamed(RouteNames.login);
break;
case PanelType.test:
// await CashBoxManage.openCT1();
// await CashBoxManage.openCT2();
// final status = await CashBoxManage.checkStatus();
// logger.e(status);
String phon1 = TtsManage.numberToChineseReading("3144");
String phon2 = TtsManage.numberToChineseReading("3155");
TtsManage.speak("请手机尾号,$phon1、$phon2,的用户取餐");
final qrData =
"${Constants.h5PayUrl}?action=hardQrCodePay&orderId=123&mchId=123";
showQrCodeDialog(
Get.context!,
qrData: qrData,
onFinished: () {},
);
break;
default:
break;
-1
View File
@@ -1,5 +1,4 @@
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:forui/forui.dart';
import 'package:get/get.dart';
+8
View File
@@ -1026,6 +1026,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.1"
pretty_qr_code:
dependency: "direct main"
description:
name: pretty_qr_code
sha256: "2291db3f68d70a3dcd46c6bd599f30991ae4c02f27f36215fbb3f4865a609259"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.5.0"
printing:
dependency: "direct main"
description:
+2
View File
@@ -38,6 +38,8 @@ dependencies:
syncfusion_flutter_datepicker: ^28.2.11
# tts转语音
flutter_tts: ^4.2.2
# 二维码
pretty_qr_code: ^3.5.0
# 权限判断
permission_handler: ^11.4.0