Commit 075991052ccffde24b784e5c2b48abeecc4cf261

Authored by 吴启风
1 parent 4224b3f8

feat:商品列表请求&路由

lib/common/request/apis.dart
... ... @@ -82,4 +82,7 @@ class Apis {
82 82  
83 83 /// 退出课堂
84 84 static const String exitClass = 'course/exit/class';
  85 +
  86 + /// 商品列表
  87 + static const String productList = 'order/course/combo/list';
85 88 }
... ...
lib/generated/json/product_entity.g.dart
... ... @@ -3,31 +3,96 @@ import 'package:wow_english/models/product_entity.dart';
3 3  
4 4 ProductEntity $ProductEntityFromJson(Map<String, dynamic> json) {
5 5 final ProductEntity productEntity = ProductEntity();
  6 + final int? id = jsonConvert.convert<int>(json['id']);
  7 + if (id != null) {
  8 + productEntity.id = id;
  9 + }
6 10 final String? name = jsonConvert.convert<String>(json['name']);
7 11 if (name != null) {
8 12 productEntity.name = name;
9 13 }
  14 + final String? title = jsonConvert.convert<String>(json['title']);
  15 + if (title != null) {
  16 + productEntity.title = title;
  17 + }
10 18 final double? price = jsonConvert.convert<double>(json['price']);
11 19 if (price != null) {
12 20 productEntity.price = price;
13 21 }
  22 + final String? picUrl = jsonConvert.convert<String>(json['picUrl']);
  23 + if (picUrl != null) {
  24 + productEntity.picUrl = picUrl;
  25 + }
  26 + final String? bannerPicUrl = jsonConvert.convert<String>(
  27 + json['bannerPicUrl']);
  28 + if (bannerPicUrl != null) {
  29 + productEntity.bannerPicUrl = bannerPicUrl;
  30 + }
  31 + final String? detailPicUrl = jsonConvert.convert<String>(
  32 + json['detailPicUrl']);
  33 + if (detailPicUrl != null) {
  34 + productEntity.detailPicUrl = detailPicUrl;
  35 + }
  36 + final int? saleType = jsonConvert.convert<int>(json['saleType']);
  37 + if (saleType != null) {
  38 + productEntity.saleType = saleType;
  39 + }
  40 + final int? status = jsonConvert.convert<int>(json['status']);
  41 + if (status != null) {
  42 + productEntity.status = status;
  43 + }
  44 + final int? sortOrder = jsonConvert.convert<int>(json['sortOrder']);
  45 + if (sortOrder != null) {
  46 + productEntity.sortOrder = sortOrder;
  47 + }
  48 + final int? validityType = jsonConvert.convert<int>(json['validityType']);
  49 + if (validityType != null) {
  50 + productEntity.validityType = validityType;
  51 + }
14 52 return productEntity;
15 53 }
16 54  
17 55 Map<String, dynamic> $ProductEntityToJson(ProductEntity entity) {
18 56 final Map<String, dynamic> data = <String, dynamic>{};
  57 + data['id'] = entity.id;
19 58 data['name'] = entity.name;
  59 + data['title'] = entity.title;
20 60 data['price'] = entity.price;
  61 + data['picUrl'] = entity.picUrl;
  62 + data['bannerPicUrl'] = entity.bannerPicUrl;
  63 + data['detailPicUrl'] = entity.detailPicUrl;
  64 + data['saleType'] = entity.saleType;
  65 + data['status'] = entity.status;
  66 + data['sortOrder'] = entity.sortOrder;
  67 + data['validityType'] = entity.validityType;
21 68 return data;
22 69 }
23 70  
24 71 extension ProductEntityExtension on ProductEntity {
25 72 ProductEntity copyWith({
  73 + int? id,
26 74 String? name,
  75 + String? title,
27 76 double? price,
  77 + String? picUrl,
  78 + String? bannerPicUrl,
  79 + String? detailPicUrl,
  80 + int? saleType,
  81 + int? status,
  82 + int? sortOrder,
  83 + int? validityType,
28 84 }) {
29 85 return ProductEntity()
  86 + ..id = id ?? this.id
30 87 ..name = name ?? this.name
31   - ..price = price ?? this.price;
  88 + ..title = title ?? this.title
  89 + ..price = price ?? this.price
  90 + ..picUrl = picUrl ?? this.picUrl
  91 + ..bannerPicUrl = bannerPicUrl ?? this.bannerPicUrl
  92 + ..detailPicUrl = detailPicUrl ?? this.detailPicUrl
  93 + ..saleType = saleType ?? this.saleType
  94 + ..status = status ?? this.status
  95 + ..sortOrder = sortOrder ?? this.sortOrder
  96 + ..validityType = validityType ?? this.validityType;
32 97 }
33 98 }
34 99 \ No newline at end of file
... ...
lib/models/product_entity.dart
... ... @@ -5,9 +5,30 @@ export &#39;package:wow_english/generated/json/product_entity.g.dart&#39;;
5 5  
6 6 @JsonSerializable()
7 7 class ProductEntity {
8   - late String name;
9   - late double price;
10   - late String url;
  8 +
  9 + int? id;
  10 +
  11 + String? name;
  12 +
  13 + String? title;
  14 +
  15 + /// 售卖价格
  16 + double? price;
  17 + /// 商品图片
  18 + String? picUrl;
  19 + /// 商品banner图片
  20 + String? bannerPicUrl;
  21 + /// 商品详情图片
  22 + String? detailPicUrl;
  23 + /// 销售类型
  24 + int? saleType;
  25 + /// 状态
  26 + int? status;
  27 + /// 序号
  28 + int? sortOrder;
  29 + /// 有效期类型
  30 + int? validityType;
  31 +
11 32  
12 33 ProductEntity();
13 34  
... ...
lib/pages/home/widgets/home_tab_header_widget.dart
... ... @@ -104,14 +104,14 @@ class HomeTabHeaderWidget extends StatelessWidget {
104 104 }
105 105 },
106 106 icon: Image.asset('listen'.assetPng)),
107   - // IconButton(
108   - // onPressed: (){
109   - // if(actionTap != null) {
110   - // actionTap!(HeaderActionType.shop);
111   - // }
112   - // },
113   - // icon: Image.asset('shop'.assetPng)
114   - // ),
  107 + IconButton(
  108 + onPressed: (){
  109 + if(actionTap != null) {
  110 + actionTap!(HeaderActionType.shop);
  111 + }
  112 + },
  113 + icon: Image.asset('shop'.assetPng)
  114 + ),
115 115 ScreenUtil().bottomBarHeight.horizontalSpace,
116 116 ],
117 117 )
... ...
lib/pages/shop/home/bloc/shop_home_bloc.dart
1 1  
2 2 import 'package:bloc/bloc.dart';
3 3 import 'package:meta/meta.dart';
  4 +import 'package:wow_english/common/request/dao/shop_dao.dart';
  5 +import 'package:wow_english/models/product_entity.dart';
  6 +
  7 +import '../../../../common/request/exception.dart';
  8 +import '../../../../utils/loading.dart';
  9 +import '../../../../utils/toast_util.dart';
4 10  
5 11 part 'shop_home_event.dart';
6 12 part 'shop_home_state.dart';
7 13  
8 14 class ShopHomeBloc extends Bloc<ShopHomeEvent, ShopHomeState> {
  15 +
  16 + List<ProductEntity?> _productDatas = [];
  17 +
  18 + List<ProductEntity?> get productDatas => _productDatas;
  19 +
9 20 ShopHomeBloc() : super(ShopHomeInitial()) {
10 21 on<ShopHomeEvent>((event, emit) {
11 22 // TODO: implement event handler
12 23 });
  24 + on<RequestDataEvent>(_requestData);
  25 + }
  26 +
  27 + void _requestData(RequestDataEvent event, Emitter<ShopHomeState> emitter) async {
  28 + try {
  29 + await loading(() async {
  30 + _productDatas = await ShopDao.productList() ?? [];
  31 + emitter(RequestListenDataState());
  32 + });
  33 + } catch (e) {
  34 + if (e is ApiException) {
  35 + showToast(e.message ?? '请求失败,请检查网络连接');
  36 + }
  37 + }
13 38 }
14 39 }
... ...
lib/pages/shop/home/bloc/shop_home_event.dart
... ... @@ -2,3 +2,5 @@ part of &#39;shop_home_bloc.dart&#39;;
2 2  
3 3 @immutable
4 4 abstract class ShopHomeEvent {}
  5 +
  6 +class RequestDataEvent extends ShopHomeEvent {}
... ...
lib/pages/shop/home/bloc/shop_home_state.dart
... ... @@ -4,3 +4,5 @@ part of &#39;shop_home_bloc.dart&#39;;
4 4 abstract class ShopHomeState {}
5 5  
6 6 class ShopHomeInitial extends ShopHomeState {}
  7 +
  8 +class RequestListenDataState extends ShopHomeState {}
7 9 \ No newline at end of file
... ...
lib/pages/shop/home/shop_home_page.dart
... ... @@ -3,7 +3,7 @@ import &#39;package:flutter_bloc/flutter_bloc.dart&#39;;
3 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
4 4 import 'package:wow_english/common/extension/string_extension.dart';
5 5 import 'package:wow_english/common/widgets/we_app_bar.dart';
6   -import 'package:wow_english/pages/shop/home/widgets/lesson_card_item.dart';
  6 +import 'package:wow_english/pages/shop/home/widgets/product_item.dart';
7 7 import 'package:wow_english/route/route.dart';
8 8 import 'package:wow_english/utils/toast_util.dart';
9 9  
... ... @@ -15,7 +15,7 @@ class ShopHomePage extends StatelessWidget {
15 15 @override
16 16 Widget build(BuildContext context) {
17 17 return BlocProvider(
18   - create: (context) => ShopHomeBloc(),
  18 + create: (context) => ShopHomeBloc()..add(RequestDataEvent()),
19 19 child: _ShopHomeView(),
20 20 );
21 21 }
... ... @@ -30,7 +30,9 @@ class _ShopHomeView extends StatelessWidget {
30 30 );
31 31 }
32 32  
33   - Widget _shopHomeWidget() => BlocBuilder<ShopHomeBloc, ShopHomeState>(builder: (context, state) {
  33 + Widget _shopHomeWidget() =>
  34 + BlocBuilder<ShopHomeBloc, ShopHomeState>(builder: (context, state) {
  35 + final bloc = BlocProvider.of<ShopHomeBloc>(context);
34 36 return Scaffold(
35 37 appBar: WEAppBar(
36 38 actions: [
... ... @@ -62,7 +64,7 @@ class _ShopHomeView extends StatelessWidget {
62 64 child: Padding(
63 65 padding: EdgeInsets.symmetric(vertical: 25.h, horizontal: 25.w),
64 66 child: GridView.builder(
65   - itemCount: 4,
  67 + itemCount: bloc.productDatas.length,
66 68 gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
67 69 crossAxisCount: 2,
68 70 childAspectRatio: 2,
... ... @@ -70,10 +72,10 @@ class _ShopHomeView extends StatelessWidget {
70 72 crossAxisSpacing: 4.5.w,
71 73 ),
72 74 itemBuilder: (BuildContext context, int index) {
73   - return LessonCardItem(onTap: () {
74   - showToast('购买');
75   - pushNamed(AppRouteName.pay);
76   - });
  75 + final productEntity = bloc.productDatas[index];
  76 + return ProductItem(onTap: () {
  77 + pushNamed(AppRouteName.pay, arguments: productEntity);
  78 + }, entity: productEntity);
77 79 }),
78 80 ),
79 81 ),
... ...
lib/pages/shop/home/widgets/lesson_card_item.dart deleted
1   -import 'package:flutter/material.dart';
2   -import 'package:flutter_screenutil/flutter_screenutil.dart';
3   -
4   -class LessonCardItem extends StatelessWidget {
5   - const LessonCardItem({super.key, required this.onTap});
6   -
7   - final Function() onTap;
8   -
9   - @override
10   - Widget build(BuildContext context) {
11   - return Container(
12   - decoration: BoxDecoration(
13   - borderRadius: BorderRadius.circular(10.r),
14   - color: Colors.blue,
15   - border: Border.all(
16   - width: 1.0,
17   - color: Colors.black
18   - )
19   - // image: DecorationImage(
20   - // image: AssetImage(
21   - // ''.assetPng,
22   - // ),
23   - // fit: BoxFit.fill
24   - // )
25   - ),
26   - padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 16.h),
27   - child: Row(
28   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
29   - children: [
30   - Container(
31   - width: 124.w,
32   - decoration: BoxDecoration(
33   - border: Border.all(
34   - width: 1.0,
35   - color: const Color(0xFF333333),
36   - ),
37   - image: const DecorationImage(
38   - fit: BoxFit.fill,
39   - image: NetworkImage('https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Faa1c2213-820a-4223-8757-5f8cee318a28%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1688713226&t=192b18a613683bcdc5bd76f65c9ff032'),
40   - )
41   - ),
42   - ),
43   - 21.5.horizontalSpace,
44   - Expanded(
45   - child: Column(
46   - mainAxisAlignment: MainAxisAlignment.spaceBetween,
47   - crossAxisAlignment: CrossAxisAlignment.end,
48   - children: [
49   - Text(
50   - 'Wow English 课程年卡',
51   - softWrap: true,
52   - textAlign: TextAlign.left,
53   - style: TextStyle(
54   - fontSize: 12.sp,
55   - color: const Color(0xFF333333)
56   - ),
57   - ),
58   - RichText(
59   - text: TextSpan(
60   - children:[
61   - TextSpan(
62   - text: '¥',
63   - style: TextStyle(
64   - fontSize: 21.sp,
65   - color: const Color(0xFFF51A1A),
66   - )
67   - ),
68   - TextSpan(
69   - text: '998',
70   - style: TextStyle(
71   - fontSize: 40.sp,
72   - color: const Color(0xFFF51A1A),
73   - ),
74   - )
75   - ]
76   - ),
77   - ),
78   - GestureDetector(
79   - onTap: () {
80   - onTap();
81   - },
82   - child: Container(
83   - decoration: BoxDecoration(
84   - color: const Color(0xFFF5C51F),
85   - borderRadius: BorderRadius.circular(5.r),
86   - border: Border.all(
87   - color: const Color(0xFF333333),
88   - width: 1.0,
89   - )
90   - ),
91   - padding: EdgeInsets.symmetric(
92   - vertical: 1.h,
93   - horizontal: 26.5.w,
94   - ),
95   - child: Text(
96   - '立即购买',
97   - style: TextStyle(
98   - fontSize: 10.sp,
99   - color: const Color(0xFF333333)
100   - ),
101   - ),
102   - ),
103   - )
104   - ],
105   - ),
106   - )
107   - ],
108   - ),
109   - );
110   - }
111   -}
112 0 \ No newline at end of file
lib/pages/shopping/bloc.dart
... ... @@ -16,7 +16,7 @@ class ShoppingBloc extends Bloc&lt;ShoppingEvent, ShoppingState&gt; {
16 16 PaymentChannel get curPaymentChannel => _curPaymentChannel;
17 17  
18 18  
19   - ShoppingBloc() : super(ShoppingState().init()) {
  19 + ShoppingBloc(this._productData) : super(ShoppingState().init()) {
20 20 //页面初始化时刻
21 21 on<InitEvent>(_init);
22 22 on<ChangePaymentChannelEvent>(_changePaymentChannel);
... ...
lib/pages/shopping/view.dart
... ... @@ -3,6 +3,7 @@ import &#39;package:flutter/material.dart&#39;;
3 3 import 'package:flutter_bloc/flutter_bloc.dart';
4 4 import 'package:flutter_screenutil/flutter_screenutil.dart';
5 5 import 'package:wow_english/common/extension/string_extension.dart';
  6 +import 'package:wow_english/models/product_entity.dart';
6 7  
7 8 import '../../common/core/assets_const.dart';
8 9 import '../../common/widgets/we_app_bar.dart';
... ... @@ -45,13 +46,15 @@ Widget buildRadioOption({
45 46 }
46 47  
47 48 class ShoppingPage extends StatelessWidget {
48   - const ShoppingPage({super.key});
  49 + const ShoppingPage({super.key, this.productEntity});
  50 +
  51 + final ProductEntity? productEntity;
49 52  
50 53 @override
51 54 Widget build(BuildContext context) {
52 55 return BlocProvider(
53 56 create: (BuildContext context) =>
54   - ShoppingBloc()
  57 + ShoppingBloc(productEntity)
55 58 ..add(InitEvent()),
56 59 child: _ShoppingView(),
57 60 );
... ... @@ -77,7 +80,7 @@ class _ShoppingView extends StatelessWidget {
77 80 crossAxisAlignment: CrossAxisAlignment.start,
78 81 children: [
79 82 CachedNetworkImage(
80   - imageUrl: "${bloc.productData?.url}",
  83 + imageUrl: "${bloc.productData?.detailPicUrl}",
81 84 imageBuilder: (context, imageProvider) =>
82 85 Container(
83 86 decoration: BoxDecoration(
... ... @@ -111,7 +114,7 @@ Widget _paymentWidget() =&gt;
111 114 return Column(
112 115 crossAxisAlignment: CrossAxisAlignment.start,
113 116 children: [
114   - Text('套餐价格:${bloc.productData?.price ?? "199(记得删除)"}',
  117 + Text('套餐价格:${bloc.productData?.price ?? ''}',
115 118 style: TextStyle(
116 119 color: const Color(0xFF333333), fontSize: 16.sp)),
117 120 const SizedBox(height: 15.0),
... ...
lib/route/route.dart
... ... @@ -2,6 +2,7 @@ import &#39;package:flutter/cupertino.dart&#39;;
2 2 import 'package:flutter/material.dart';
3 3 import 'package:wow_english/app/splash_page.dart';
4 4 import 'package:wow_english/common/pages/wow_web_page.dart';
  5 +import 'package:wow_english/models/product_entity.dart';
5 6 import 'package:wow_english/pages/home/home_page.dart';
6 7 import 'package:wow_english/pages/lessons/lesson_page.dart';
7 8 import 'package:wow_english/pages/listen/listen_page.dart';
... ... @@ -26,6 +27,7 @@ import &#39;../pages/reading/reading_page.dart&#39;;
26 27 import '../pages/shopping/view.dart';
27 28 import '../pages/user/setting/delete_account_page.dart';
28 29 import '../pages/user/setting/reback_page.dart';
  30 +import '../utils/log_util.dart';
29 31  
30 32 class AppRouteName {
31 33 static const String splash = 'splash';
... ... @@ -104,7 +106,11 @@ class AppRouter {
104 106 case AppRouteName.shop:
105 107 return CupertinoPageRoute(builder: (_) => const ShopHomePage());
106 108 case AppRouteName.pay:
107   - return CupertinoPageRoute(builder: (_) => const ShoppingPage());
  109 + var productEntity = ProductEntity();
  110 + if (settings.arguments != null && settings.arguments is ProductEntity) {
  111 + productEntity = settings.arguments as ProductEntity;
  112 + }
  113 + return CupertinoPageRoute(builder: (_) => ShoppingPage(productEntity: productEntity));
108 114 case AppRouteName.exLesson:
109 115 return CupertinoPageRoute(builder: (_) => const ExchangeLessonPage());
110 116 case AppRouteName.exList:
... ...