Flutter 商城结算页面开发:地址选择、支付方式选择和订单提交

本教程将带你使用 Flutter 开发一个完整的商城结算页面,包含地址选择、支付方式选择和订单提交功能。我们将使用 API 接口进行数据交互,并提供完整的代码示例。

页面功能:

  • 地址选择:
    • 获取用户地址列表,展示地址信息。
    • 支持默认地址标识。
    • 新增地址功能,通过 API 接口提交地址信息。
  • 支付方式选择:
    • 支持支付宝和微信支付方式选择。
  • 订单提交:
    • 提交选择的地址和支付方式信息。
    • 生成支付二维码。
    • 轮询订单状态,并根据状态展示支付结果。

代码示例:

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:your_app_name/api_service.dart';
import 'package:your_app_name/models/address.dart';

class CheckoutPage extends StatefulWidget {
  @override
  _CheckoutPageState createState() => _CheckoutPageState();
}

class _CheckoutPageState extends State<CheckoutPage> {
  List<Address> _addresses = [];
  Address _selectedAddress;
  String _paymentMethod = '支付宝';

  @override
  void initState() {
    super.initState();
    _getAddresses();
  }

  Future<void> _getAddresses() async {
    try {
      final addresses = await ApiService.getAddresses();
      setState(() {
        _addresses = addresses;
        _selectedAddress = _addresses.firstWhere(
            (address) => address.isDefault == 1,
            orElse: () => null);
      });
    } catch (e) {
      Fluttertoast.showToast(msg: '获取地址失败');
    }
  }

  Future<void> _addAddress() async {
    try {
      final address = await ApiService.addAddress(
        addressId: '',
        provience: '黑龙江省',
        city: '哈尔滨市',
        district: '五常市',
        addressLine: '五常镇广场小区',
        phone: '12345678',
        isDefault: 1,
        name: '宋涛',
      );
      setState(() {
        _addresses.add(address);
        _selectedAddress = address;
      });
    } catch (e) {
      Fluttertoast.showToast(msg: '新增地址失败');
    }
  }

  Future<void> _submitOrder() async {
    try {
      final result = await ApiService.submitOrder(
          _selectedAddress.id, _paymentMethod);
      final response = json.decode(result);
      final qrCodeUrl = response[0];
      final orderId = response[1];
      _pollOrderStatus(orderId);
      // TODO: 显示支付二维码
    } catch (e) {
      Fluttertoast.showToast(msg: '提交订单失败');
    }
  }

  Future<void> _pollOrderStatus(int orderId) async {
    while (true) {
      try {
        final status = await ApiService.queryOrderStatus(orderId);
        if (status == '支付成功') {
          Fluttertoast.showToast(msg: '支付成功');
          // TODO: 跳转回订单列表页面
          break;
        } else if (status == '查询返回该订单支付失败或被关闭') {
          Fluttertoast.showToast(msg: '支付失败');
          break;
        } else {
          await Future.delayed(Duration(seconds: 5));
        }
      } catch (e) {
        Fluttertoast.showToast(msg: '查询订单状态失败');
        break;
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('结算'),
      ),
      body: _buildBody(),
    );
  }

  Widget _buildBody() {
    return SingleChildScrollView(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: EdgeInsets.all(16),
            child: Text(
              '选择收货地址',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          _buildAddressList(),
          Padding(
            padding: EdgeInsets.all(16),
            child: Text(
              '选择支付方式',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          _buildPaymentMethod(),
          SizedBox(height: 16),
          _buildCheckoutButton(),
        ],
      ),
    );
  }

  Widget _buildAddressList() {
    if (_addresses.isEmpty) {
      return Padding(
        padding: EdgeInsets.all(16),
        child: Text('您还没有添加收货地址'),
      );
    } else {
      return ListView.separated(
        shrinkWrap: true,
        physics: NeverScrollableScrollPhysics(),
        itemCount: _addresses.length + 1,
        separatorBuilder: (context, index) => Divider(height: 1),
        itemBuilder: (context, index) {
          if (index == _addresses.length) {
            return ListTile(
              title: Text('新增地址'),
              trailing: Icon(Icons.keyboard_arrow_right),
              onTap: _addAddress,
            );
          } else {
            final address = _addresses[index];
            return ListTile(
              title: Text(address.toString()),
              subtitle: address.isDefault == 1 ? Text('默认地址') : null,
              trailing: _selectedAddress == address
                  ? Icon(Icons.check_circle, color: Colors.green)
                  : null,
              onTap: () {
                setState(() {
                  _selectedAddress = address;
                });
              },
            );
          }
        },
      );
    }
  }

  Widget _buildPaymentMethod() {
    return Row(
      children: [
        Radio(
          value: '支付宝',
          groupValue: _paymentMethod,
          onChanged: (value) {
            setState(() {
              _paymentMethod = value;
            });
          },
        ),
        Text('支付宝'),
        Radio(
          value: '微信',
          groupValue: _paymentMethod,
          onChanged: (value) {
            setState(() {
              _paymentMethod = value;
            });
          },
        ),
        Text('微信'),
      ],
    );
  }

  Widget _buildCheckoutButton() {
    return Padding(
      padding: EdgeInsets.all(16),
      child: SizedBox(
        width: double.infinity,
        height: 48,
        child: RaisedButton(
          child: Text('结算'),
          onPressed: _selectedAddress == null
              ? null
              : () {
                  showDialog(
                    context: context,
                    builder: (context) => AlertDialog(
                      title: Text('确认支付'),
                      content: Text('确定要支付吗?'),
                      actions: [
                        FlatButton(
                          child: Text('取消'),
                          onPressed: () {
                            Navigator.pop(context);
                          },
                        ),
                        FlatButton(
                          child: Text('确定'),
                          onPressed: () {
                            Navigator.pop(context);
                            _submitOrder();
                          },
                        ),
                      ],
                    ),
                  );
                },
        ),
      ),
    );
  }
}

Address类的代码:

class Address {
  int id;
  String name;
  String phone;
  String provience;
  String city;
  String district;
  String addressLine;
  int isDefault;

  Address.fromJson(Map<String, dynamic> json)
      : id = json['id'],
        name = json['name'],
        phone = json['phone'],
        provience = json['provience'],
        city = json['city'],
        district = json['district'],
        addressLine = json['addressLine'],
        isDefault = json['isDefault'];

  @override
  String toString() {
    return '$provience $city $district $addressLine $name $phone';
  }
}

API 接口:

  • 获取用户地址列表:

    • GET 请求:http://book.musecloud.tech/getaddresses
    • 返回数据格式:[{"addressLine":"五常市","city":"天津市","country":"中国","district":"和平区","id":1012,"isDefault":0,"name":"宋涛","phone":"15678880290","provience":"天津市","userId":624971778},{"addressLine":"dsadsa","city":"天津市","country":"中国","district":"和平区","id":1013,"isDefault":1,"name":"dsadsa","phone":"dasda","provience":"天津市","userId":624971778}]
  • 新增地址:

    • GET 请求:http://book.musecloud.tech/?addressId=&provience=%E9%BB%91%E9%BE%99%E6%B1%9F%E7%9C%81&city=%E5%93%88%E5%B0%94%E6%BB%A8%E5%B8%82&district=%E4%BA%94%E5%B8%B8%E5%B8%82&address_line=%E4%BA%94%E5%B8%B8%E9%95%87%E5%B9%BF%E5%9C%BA%E5%B0%8F%E5%8C%BA&phone=12345678&isdefault=1&name=%E5%AE%8B%E6%B6%9B
  • 提交订单:

    • GET 请求:http://book.musecloud.tech/submitorder?addressId=1013&paymentMethod=支付宝
    • 返回数据格式:["https://qr.alipay.com/bax00504ukzmhjvoztnv0088",178812488]
  • 查询订单状态:

    • GET 请求:http://book.musecloud.tech/order/queryOrderStatus?orderSn=178812488
    • 返回数据格式:查询返回该订单支付成功/失败/被关闭

ApiService 代码:

// 提交订单
static Future<String> submitOrder(int addressId, String paymentMethod) async {
  try {
    Response response = await dioWithCookie.get(
      '$baseUrl/submitorder',
      queryParameters: {
        'addressId': addressId,
        'paymentMethod': paymentMethod,
      },
    );
    String result = response.data;
    return result;
  } catch (e) {
    throw e;
  }
}

注意:

  • your_app_name 请替换为你的应用名称。
  • dioWithCookie 是你的网络请求库实例。
  • baseUrl 是你的 API 接口地址。
  • 代码中的 // TODO 部分需要根据实际情况进行补充。

本教程仅提供了一个简单的结算页面开发示例,你可以根据自己的需求进行扩展和修改。

Flutter 商城结算页面开发:地址选择、支付方式选择和订单提交

原文地址: https://www.cveoy.top/t/topic/oi40 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录