From 075991052ccffde24b784e5c2b48abeecc4cf261 Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Mon, 22 Apr 2024 00:04:15 +0800 Subject: [PATCH] feat:商品列表请求&路由 --- lib/common/request/apis.dart | 3 +++ lib/generated/json/product_entity.g.dart | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- lib/models/product_entity.dart | 27 ++++++++++++++++++++++++--- lib/pages/home/widgets/home_tab_header_widget.dart | 16 ++++++++-------- lib/pages/shop/home/bloc/shop_home_bloc.dart | 25 +++++++++++++++++++++++++ lib/pages/shop/home/bloc/shop_home_event.dart | 2 ++ lib/pages/shop/home/bloc/shop_home_state.dart | 2 ++ lib/pages/shop/home/shop_home_page.dart | 18 ++++++++++-------- lib/pages/shop/home/widgets/lesson_card_item.dart | 111 --------------------------------------------------------------------------------------------------------------- lib/pages/shopping/bloc.dart | 2 +- lib/pages/shopping/view.dart | 11 +++++++---- lib/route/route.dart | 8 +++++++- 12 files changed, 155 insertions(+), 137 deletions(-) delete mode 100644 lib/pages/shop/home/widgets/lesson_card_item.dart diff --git a/lib/common/request/apis.dart b/lib/common/request/apis.dart index f994eab..c078760 100644 --- a/lib/common/request/apis.dart +++ b/lib/common/request/apis.dart @@ -82,4 +82,7 @@ class Apis { /// 退出课堂 static const String exitClass = 'course/exit/class'; + + /// 商品列表 + static const String productList = 'order/course/combo/list'; } diff --git a/lib/generated/json/product_entity.g.dart b/lib/generated/json/product_entity.g.dart index 229d457..b91e1a1 100644 --- a/lib/generated/json/product_entity.g.dart +++ b/lib/generated/json/product_entity.g.dart @@ -3,31 +3,96 @@ import 'package:wow_english/models/product_entity.dart'; ProductEntity $ProductEntityFromJson(Map json) { final ProductEntity productEntity = ProductEntity(); + final int? id = jsonConvert.convert(json['id']); + if (id != null) { + productEntity.id = id; + } final String? name = jsonConvert.convert(json['name']); if (name != null) { productEntity.name = name; } + final String? title = jsonConvert.convert(json['title']); + if (title != null) { + productEntity.title = title; + } final double? price = jsonConvert.convert(json['price']); if (price != null) { productEntity.price = price; } + final String? picUrl = jsonConvert.convert(json['picUrl']); + if (picUrl != null) { + productEntity.picUrl = picUrl; + } + final String? bannerPicUrl = jsonConvert.convert( + json['bannerPicUrl']); + if (bannerPicUrl != null) { + productEntity.bannerPicUrl = bannerPicUrl; + } + final String? detailPicUrl = jsonConvert.convert( + json['detailPicUrl']); + if (detailPicUrl != null) { + productEntity.detailPicUrl = detailPicUrl; + } + final int? saleType = jsonConvert.convert(json['saleType']); + if (saleType != null) { + productEntity.saleType = saleType; + } + final int? status = jsonConvert.convert(json['status']); + if (status != null) { + productEntity.status = status; + } + final int? sortOrder = jsonConvert.convert(json['sortOrder']); + if (sortOrder != null) { + productEntity.sortOrder = sortOrder; + } + final int? validityType = jsonConvert.convert(json['validityType']); + if (validityType != null) { + productEntity.validityType = validityType; + } return productEntity; } Map $ProductEntityToJson(ProductEntity entity) { final Map data = {}; + data['id'] = entity.id; data['name'] = entity.name; + data['title'] = entity.title; data['price'] = entity.price; + data['picUrl'] = entity.picUrl; + data['bannerPicUrl'] = entity.bannerPicUrl; + data['detailPicUrl'] = entity.detailPicUrl; + data['saleType'] = entity.saleType; + data['status'] = entity.status; + data['sortOrder'] = entity.sortOrder; + data['validityType'] = entity.validityType; return data; } extension ProductEntityExtension on ProductEntity { ProductEntity copyWith({ + int? id, String? name, + String? title, double? price, + String? picUrl, + String? bannerPicUrl, + String? detailPicUrl, + int? saleType, + int? status, + int? sortOrder, + int? validityType, }) { return ProductEntity() + ..id = id ?? this.id ..name = name ?? this.name - ..price = price ?? this.price; + ..title = title ?? this.title + ..price = price ?? this.price + ..picUrl = picUrl ?? this.picUrl + ..bannerPicUrl = bannerPicUrl ?? this.bannerPicUrl + ..detailPicUrl = detailPicUrl ?? this.detailPicUrl + ..saleType = saleType ?? this.saleType + ..status = status ?? this.status + ..sortOrder = sortOrder ?? this.sortOrder + ..validityType = validityType ?? this.validityType; } } \ No newline at end of file diff --git a/lib/models/product_entity.dart b/lib/models/product_entity.dart index 98c6366..7f18480 100644 --- a/lib/models/product_entity.dart +++ b/lib/models/product_entity.dart @@ -5,9 +5,30 @@ export 'package:wow_english/generated/json/product_entity.g.dart'; @JsonSerializable() class ProductEntity { - late String name; - late double price; - late String url; + + int? id; + + String? name; + + String? title; + + /// 售卖价格 + double? price; + /// 商品图片 + String? picUrl; + /// 商品banner图片 + String? bannerPicUrl; + /// 商品详情图片 + String? detailPicUrl; + /// 销售类型 + int? saleType; + /// 状态 + int? status; + /// 序号 + int? sortOrder; + /// 有效期类型 + int? validityType; + ProductEntity(); diff --git a/lib/pages/home/widgets/home_tab_header_widget.dart b/lib/pages/home/widgets/home_tab_header_widget.dart index 1b9a63b..d77785a 100644 --- a/lib/pages/home/widgets/home_tab_header_widget.dart +++ b/lib/pages/home/widgets/home_tab_header_widget.dart @@ -104,14 +104,14 @@ class HomeTabHeaderWidget extends StatelessWidget { } }, icon: Image.asset('listen'.assetPng)), - // IconButton( - // onPressed: (){ - // if(actionTap != null) { - // actionTap!(HeaderActionType.shop); - // } - // }, - // icon: Image.asset('shop'.assetPng) - // ), + IconButton( + onPressed: (){ + if(actionTap != null) { + actionTap!(HeaderActionType.shop); + } + }, + icon: Image.asset('shop'.assetPng) + ), ScreenUtil().bottomBarHeight.horizontalSpace, ], ) diff --git a/lib/pages/shop/home/bloc/shop_home_bloc.dart b/lib/pages/shop/home/bloc/shop_home_bloc.dart index cac863c..6a97c42 100644 --- a/lib/pages/shop/home/bloc/shop_home_bloc.dart +++ b/lib/pages/shop/home/bloc/shop_home_bloc.dart @@ -1,14 +1,39 @@ import 'package:bloc/bloc.dart'; import 'package:meta/meta.dart'; +import 'package:wow_english/common/request/dao/shop_dao.dart'; +import 'package:wow_english/models/product_entity.dart'; + +import '../../../../common/request/exception.dart'; +import '../../../../utils/loading.dart'; +import '../../../../utils/toast_util.dart'; part 'shop_home_event.dart'; part 'shop_home_state.dart'; class ShopHomeBloc extends Bloc { + + List _productDatas = []; + + List get productDatas => _productDatas; + ShopHomeBloc() : super(ShopHomeInitial()) { on((event, emit) { // TODO: implement event handler }); + on(_requestData); + } + + void _requestData(RequestDataEvent event, Emitter emitter) async { + try { + await loading(() async { + _productDatas = await ShopDao.productList() ?? []; + emitter(RequestListenDataState()); + }); + } catch (e) { + if (e is ApiException) { + showToast(e.message ?? '请求失败,请检查网络连接'); + } + } } } diff --git a/lib/pages/shop/home/bloc/shop_home_event.dart b/lib/pages/shop/home/bloc/shop_home_event.dart index f35f8fd..06185bb 100644 --- a/lib/pages/shop/home/bloc/shop_home_event.dart +++ b/lib/pages/shop/home/bloc/shop_home_event.dart @@ -2,3 +2,5 @@ part of 'shop_home_bloc.dart'; @immutable abstract class ShopHomeEvent {} + +class RequestDataEvent extends ShopHomeEvent {} diff --git a/lib/pages/shop/home/bloc/shop_home_state.dart b/lib/pages/shop/home/bloc/shop_home_state.dart index d0b3c17..09081e1 100644 --- a/lib/pages/shop/home/bloc/shop_home_state.dart +++ b/lib/pages/shop/home/bloc/shop_home_state.dart @@ -4,3 +4,5 @@ part of 'shop_home_bloc.dart'; abstract class ShopHomeState {} class ShopHomeInitial extends ShopHomeState {} + +class RequestListenDataState extends ShopHomeState {} \ No newline at end of file diff --git a/lib/pages/shop/home/shop_home_page.dart b/lib/pages/shop/home/shop_home_page.dart index ede8e6d..4c2789e 100644 --- a/lib/pages/shop/home/shop_home_page.dart +++ b/lib/pages/shop/home/shop_home_page.dart @@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:wow_english/common/extension/string_extension.dart'; import 'package:wow_english/common/widgets/we_app_bar.dart'; -import 'package:wow_english/pages/shop/home/widgets/lesson_card_item.dart'; +import 'package:wow_english/pages/shop/home/widgets/product_item.dart'; import 'package:wow_english/route/route.dart'; import 'package:wow_english/utils/toast_util.dart'; @@ -15,7 +15,7 @@ class ShopHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => ShopHomeBloc(), + create: (context) => ShopHomeBloc()..add(RequestDataEvent()), child: _ShopHomeView(), ); } @@ -30,7 +30,9 @@ class _ShopHomeView extends StatelessWidget { ); } - Widget _shopHomeWidget() => BlocBuilder(builder: (context, state) { + Widget _shopHomeWidget() => + BlocBuilder(builder: (context, state) { + final bloc = BlocProvider.of(context); return Scaffold( appBar: WEAppBar( actions: [ @@ -62,7 +64,7 @@ class _ShopHomeView extends StatelessWidget { child: Padding( padding: EdgeInsets.symmetric(vertical: 25.h, horizontal: 25.w), child: GridView.builder( - itemCount: 4, + itemCount: bloc.productDatas.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 2, @@ -70,10 +72,10 @@ class _ShopHomeView extends StatelessWidget { crossAxisSpacing: 4.5.w, ), itemBuilder: (BuildContext context, int index) { - return LessonCardItem(onTap: () { - showToast('购买'); - pushNamed(AppRouteName.pay); - }); + final productEntity = bloc.productDatas[index]; + return ProductItem(onTap: () { + pushNamed(AppRouteName.pay, arguments: productEntity); + }, entity: productEntity); }), ), ), diff --git a/lib/pages/shop/home/widgets/lesson_card_item.dart b/lib/pages/shop/home/widgets/lesson_card_item.dart deleted file mode 100644 index 8e42403..0000000 --- a/lib/pages/shop/home/widgets/lesson_card_item.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; - -class LessonCardItem extends StatelessWidget { - const LessonCardItem({super.key, required this.onTap}); - - final Function() onTap; - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.r), - color: Colors.blue, - border: Border.all( - width: 1.0, - color: Colors.black - ) - // image: DecorationImage( - // image: AssetImage( - // ''.assetPng, - // ), - // fit: BoxFit.fill - // ) - ), - padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 16.h), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 124.w, - decoration: BoxDecoration( - border: Border.all( - width: 1.0, - color: const Color(0xFF333333), - ), - image: const DecorationImage( - fit: BoxFit.fill, - 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'), - ) - ), - ), - 21.5.horizontalSpace, - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - 'Wow English 课程年卡', - softWrap: true, - textAlign: TextAlign.left, - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF333333) - ), - ), - RichText( - text: TextSpan( - children:[ - TextSpan( - text: '¥', - style: TextStyle( - fontSize: 21.sp, - color: const Color(0xFFF51A1A), - ) - ), - TextSpan( - text: '998', - style: TextStyle( - fontSize: 40.sp, - color: const Color(0xFFF51A1A), - ), - ) - ] - ), - ), - GestureDetector( - onTap: () { - onTap(); - }, - child: Container( - decoration: BoxDecoration( - color: const Color(0xFFF5C51F), - borderRadius: BorderRadius.circular(5.r), - border: Border.all( - color: const Color(0xFF333333), - width: 1.0, - ) - ), - padding: EdgeInsets.symmetric( - vertical: 1.h, - horizontal: 26.5.w, - ), - child: Text( - '立即购买', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF333333) - ), - ), - ), - ) - ], - ), - ) - ], - ), - ); - } -} \ No newline at end of file diff --git a/lib/pages/shopping/bloc.dart b/lib/pages/shopping/bloc.dart index 8f81254..e56c61f 100644 --- a/lib/pages/shopping/bloc.dart +++ b/lib/pages/shopping/bloc.dart @@ -16,7 +16,7 @@ class ShoppingBloc extends Bloc { PaymentChannel get curPaymentChannel => _curPaymentChannel; - ShoppingBloc() : super(ShoppingState().init()) { + ShoppingBloc(this._productData) : super(ShoppingState().init()) { //页面初始化时刻 on(_init); on(_changePaymentChannel); diff --git a/lib/pages/shopping/view.dart b/lib/pages/shopping/view.dart index 1ee7d0a..5237fe9 100644 --- a/lib/pages/shopping/view.dart +++ b/lib/pages/shopping/view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:wow_english/common/extension/string_extension.dart'; +import 'package:wow_english/models/product_entity.dart'; import '../../common/core/assets_const.dart'; import '../../common/widgets/we_app_bar.dart'; @@ -45,13 +46,15 @@ Widget buildRadioOption({ } class ShoppingPage extends StatelessWidget { - const ShoppingPage({super.key}); + const ShoppingPage({super.key, this.productEntity}); + + final ProductEntity? productEntity; @override Widget build(BuildContext context) { return BlocProvider( create: (BuildContext context) => - ShoppingBloc() + ShoppingBloc(productEntity) ..add(InitEvent()), child: _ShoppingView(), ); @@ -77,7 +80,7 @@ class _ShoppingView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ CachedNetworkImage( - imageUrl: "${bloc.productData?.url}", + imageUrl: "${bloc.productData?.detailPicUrl}", imageBuilder: (context, imageProvider) => Container( decoration: BoxDecoration( @@ -111,7 +114,7 @@ Widget _paymentWidget() => return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('套餐价格:${bloc.productData?.price ?? "199(记得删除)"}', + Text('套餐价格:${bloc.productData?.price ?? ''}', style: TextStyle( color: const Color(0xFF333333), fontSize: 16.sp)), const SizedBox(height: 15.0), diff --git a/lib/route/route.dart b/lib/route/route.dart index e2850b4..2865611 100644 --- a/lib/route/route.dart +++ b/lib/route/route.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:wow_english/app/splash_page.dart'; import 'package:wow_english/common/pages/wow_web_page.dart'; +import 'package:wow_english/models/product_entity.dart'; import 'package:wow_english/pages/home/home_page.dart'; import 'package:wow_english/pages/lessons/lesson_page.dart'; import 'package:wow_english/pages/listen/listen_page.dart'; @@ -26,6 +27,7 @@ import '../pages/reading/reading_page.dart'; import '../pages/shopping/view.dart'; import '../pages/user/setting/delete_account_page.dart'; import '../pages/user/setting/reback_page.dart'; +import '../utils/log_util.dart'; class AppRouteName { static const String splash = 'splash'; @@ -104,7 +106,11 @@ class AppRouter { case AppRouteName.shop: return CupertinoPageRoute(builder: (_) => const ShopHomePage()); case AppRouteName.pay: - return CupertinoPageRoute(builder: (_) => const ShoppingPage()); + var productEntity = ProductEntity(); + if (settings.arguments != null && settings.arguments is ProductEntity) { + productEntity = settings.arguments as ProductEntity; + } + return CupertinoPageRoute(builder: (_) => ShoppingPage(productEntity: productEntity)); case AppRouteName.exLesson: return CupertinoPageRoute(builder: (_) => const ExchangeLessonPage()); case AppRouteName.exList: -- libgit2 0.22.2