249 lines
8.1 KiB
Dart
249 lines
8.1 KiB
Dart
import 'package:autosos_flutter/model/base_response.dart';
|
||
import 'package:autosos_flutter/model/order.dart';
|
||
import 'package:autosos_flutter/model/payment.dart';
|
||
import 'package:autosos_flutter/provider/providers.dart';
|
||
import 'package:autosos_flutter/util/toast.dart';
|
||
import 'package:autosos_flutter/widget/qr_image.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:fluwx/fluwx.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
|
||
/// 收款页(对应 Android FinishOrderMoneyActivity)
|
||
/// 三种方式:微信支付(技师端唤起收款码让客户扫)/ 现金收款 / 已扫码后回调
|
||
class CollectionPage extends ConsumerStatefulWidget {
|
||
final int orderId;
|
||
const CollectionPage({super.key, required this.orderId});
|
||
|
||
@override
|
||
ConsumerState<CollectionPage> createState() => _CollectionPageState();
|
||
}
|
||
|
||
class _CollectionPageState extends ConsumerState<CollectionPage> {
|
||
Order? _order;
|
||
final TextEditingController _amountCtrl = TextEditingController();
|
||
String _qrUrl = '';
|
||
bool _loading = false;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_load();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_amountCtrl.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _load() async {
|
||
try {
|
||
final resp =
|
||
await ref.read(orderApiProvider).orderDetail(widget.orderId);
|
||
if (!mounted) return;
|
||
if (!resp.isSuccess || resp.data == null) {
|
||
Toast.error('订单不存在');
|
||
return;
|
||
}
|
||
setState(() {
|
||
_order = resp.data;
|
||
_amountCtrl.text = resp.data!.amount.toStringAsFixed(2);
|
||
});
|
||
} catch (e) {
|
||
Toast.error('加载失败:$e');
|
||
}
|
||
}
|
||
|
||
Future<void> _wxPay() async {
|
||
final amount = double.tryParse(_amountCtrl.text.trim());
|
||
if (amount == null || amount <= 0) {
|
||
Toast.error('请输入有效金额');
|
||
return;
|
||
}
|
||
setState(() => _loading = true);
|
||
EasyLoading.show(status: '生成中…');
|
||
try {
|
||
final BaseResponse<String> resp = await ref
|
||
.read(orderApiProvider)
|
||
.createPayQrCode(widget.orderId, amount);
|
||
if (!resp.isSuccess) {
|
||
EasyLoading.dismiss();
|
||
Toast.error(resp.message ?? '生成失败');
|
||
return;
|
||
}
|
||
setState(() => _qrUrl = resp.data ?? '');
|
||
EasyLoading.dismiss();
|
||
} catch (e) {
|
||
EasyLoading.dismiss();
|
||
Toast.error('生成失败:$e');
|
||
} finally {
|
||
if (mounted) setState(() => _loading = false);
|
||
}
|
||
}
|
||
|
||
Future<void> _wxPayNative() async {
|
||
final amount = double.tryParse(_amountCtrl.text.trim());
|
||
if (amount == null || amount <= 0) {
|
||
Toast.error('请输入有效金额');
|
||
return;
|
||
}
|
||
setState(() => _loading = true);
|
||
EasyLoading.show(status: '调起微信…');
|
||
try {
|
||
final BaseResponse<WxPay> resp = await ref
|
||
.read(orderApiProvider)
|
||
.createWxPay(widget.orderId, amount);
|
||
EasyLoading.dismiss();
|
||
if (!resp.isSuccess || resp.data == null) {
|
||
Toast.error(resp.message ?? '下单失败');
|
||
return;
|
||
}
|
||
final pay = resp.data!;
|
||
await Fluwx().pay(
|
||
which: Payment(
|
||
appId: pay.appId,
|
||
partnerId: pay.partnerId,
|
||
prepayId: pay.prepayId,
|
||
packageValue: pay.packageValue,
|
||
nonceStr: pay.nonceStr,
|
||
timestamp: int.tryParse(pay.timeStamp) ?? 0,
|
||
sign: pay.sign,
|
||
),
|
||
);
|
||
} catch (e) {
|
||
EasyLoading.dismiss();
|
||
Toast.error('调起失败:$e');
|
||
} finally {
|
||
if (mounted) setState(() => _loading = false);
|
||
}
|
||
}
|
||
|
||
Future<void> _cashPay() async {
|
||
final amount = double.tryParse(_amountCtrl.text.trim());
|
||
if (amount == null || amount <= 0) {
|
||
Toast.error('请输入有效金额');
|
||
return;
|
||
}
|
||
final ok = await showDialog<bool>(
|
||
context: context,
|
||
builder: (ctx) => AlertDialog(
|
||
title: const Text('现金收款确认'),
|
||
content: Text('确认已收到客户现金 ¥${amount.toStringAsFixed(2)}?'),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () => Navigator.pop(ctx, false),
|
||
child: const Text('取消'),
|
||
),
|
||
ElevatedButton(
|
||
onPressed: () => Navigator.pop(ctx, true),
|
||
child: const Text('确认'),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
if (ok != true) return;
|
||
setState(() => _loading = true);
|
||
try {
|
||
final resp = await ref
|
||
.read(orderApiProvider)
|
||
.confirmCashPay(widget.orderId, amount);
|
||
if (!resp.isSuccess) {
|
||
Toast.error(resp.message ?? '提交失败');
|
||
return;
|
||
}
|
||
Toast.success('已记录现金收款');
|
||
if (mounted) context.pop(true);
|
||
} catch (e) {
|
||
Toast.error('提交失败:$e');
|
||
} finally {
|
||
if (mounted) setState(() => _loading = false);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(title: const Text('客户付款')),
|
||
body: _order == null
|
||
? const Center(child: CircularProgressIndicator())
|
||
: Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
children: [
|
||
Text(
|
||
'订单号:${_order!.orderNo}',
|
||
style: const TextStyle(fontSize: 13),
|
||
),
|
||
const SizedBox(height: 16),
|
||
TextField(
|
||
controller: _amountCtrl,
|
||
keyboardType: const TextInputType.numberWithOptions(
|
||
decimal: true,
|
||
),
|
||
decoration: const InputDecoration(
|
||
labelText: '收款金额',
|
||
prefixText: '¥ ',
|
||
border: OutlineInputBorder(),
|
||
),
|
||
style: const TextStyle(
|
||
fontSize: 28,
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.red,
|
||
),
|
||
),
|
||
const SizedBox(height: 24),
|
||
if (_qrUrl.isNotEmpty) ...[
|
||
Center(
|
||
child: QrImageView(
|
||
data: _qrUrl,
|
||
size: 220,
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
const Center(
|
||
child: Text(
|
||
'请客户扫码支付',
|
||
style: TextStyle(color: Colors.grey),
|
||
),
|
||
),
|
||
const SizedBox(height: 16),
|
||
],
|
||
ElevatedButton.icon(
|
||
onPressed: _loading ? null : _wxPay,
|
||
icon: const Icon(Icons.qr_code_2),
|
||
label: const Text('生成收款二维码'),
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.green,
|
||
minimumSize: const Size.fromHeight(48),
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
OutlinedButton.icon(
|
||
onPressed: _loading ? null : _wxPayNative,
|
||
icon: const Icon(Icons.wechat),
|
||
label: const Text('调起微信收款'),
|
||
style: OutlinedButton.styleFrom(
|
||
side: const BorderSide(color: Colors.green),
|
||
foregroundColor: Colors.green,
|
||
minimumSize: const Size.fromHeight(48),
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
OutlinedButton.icon(
|
||
onPressed: _loading ? null : _cashPay,
|
||
icon: const Icon(Icons.money),
|
||
label: const Text('现金收款确认'),
|
||
style: OutlinedButton.styleFrom(
|
||
minimumSize: const Size.fromHeight(48),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|