diff --git a/lib/constants/api.dart b/lib/constants/api.dart index 9b66826e..695e092b 100644 --- a/lib/constants/api.dart +++ b/lib/constants/api.dart @@ -18,6 +18,7 @@ class API { static _Upload upload = _Upload(); static _Community community = _Community(); static _Message message = _Message(); + static _Market market = _Market(); } class _Login { @@ -255,6 +256,10 @@ class _Community { String get signUpActivity => '/user/activity/signUp'; } +class _Market { + String get category => '/user/shop/findAllCategory'; +} + class _Upload { ///上传咨询建议照片 String get uploadAdvice => '/user/upload/uploadAdvice'; diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index 8e0b1cb0..222a4e7a 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -6,12 +6,13 @@ import 'package:device_info_plus_web/device_info_plus_web.dart'; import 'package:firebase_core_web/firebase_core_web.dart'; -import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:image_picker_for_web/image_picker_for_web.dart'; import 'package:package_info_plus_web/package_info_plus_web.dart'; import 'package:shared_preferences_web/shared_preferences_web.dart'; import 'package:url_launcher_web/url_launcher_web.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + // ignore: public_member_api_docs void registerPlugins(Registrar registrar) { DeviceInfoPlusPlugin.registerWith(registrar); diff --git a/lib/models/market/display_category_model.dart b/lib/models/market/display_category_model.dart new file mode 100644 index 00000000..ccc75b3c --- /dev/null +++ b/lib/models/market/display_category_model.dart @@ -0,0 +1,33 @@ +import 'package:aku_community/constants/api.dart'; +import 'package:aku_community/models/market/market_category_model.dart'; +import 'package:aku_community/utils/network/base_model.dart'; +import 'package:aku_community/utils/network/net_util.dart'; + +class DisplayCategoryModel { + final MarketCategoryModel model; + final List children; + DisplayCategoryModel({ + required this.model, + required this.children, + }); + + static Future> get top8 async { + List models = await fetchCategory(0); + if (models.length >= 8) + return models.getRange(0, 8).toList(); + else + return models; + } + + ///获取分类列表 + static Future> fetchCategory(int parentId) async { + BaseModel model = await NetUtil().get( + API.market.category, + params: {'parentId': parentId}, + ); + if (model.data == null) return []; + return (model.data as List) + .map((e) => MarketCategoryModel.fromJson(e)) + .toList(); + } +} diff --git a/lib/models/market/market_category_model.dart b/lib/models/market/market_category_model.dart new file mode 100644 index 00000000..9be19759 --- /dev/null +++ b/lib/models/market/market_category_model.dart @@ -0,0 +1,23 @@ +import 'package:equatable/equatable.dart'; + +import 'package:aku_community/model/common/img_model.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'market_category_model.g.dart'; + +@JsonSerializable() +class MarketCategoryModel extends Equatable { + final int id; + final String name; + final List imgList; + MarketCategoryModel({ + required this.id, + required this.name, + required this.imgList, + }); + @override + List get props => [id]; + + factory MarketCategoryModel.fromJson(Map json) => + _$MarketCategoryModelFromJson(json); +} diff --git a/lib/models/market/market_category_model.g.dart b/lib/models/market/market_category_model.g.dart new file mode 100644 index 00000000..a56d8934 --- /dev/null +++ b/lib/models/market/market_category_model.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'market_category_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +MarketCategoryModel _$MarketCategoryModelFromJson(Map json) { + return MarketCategoryModel( + id: json['id'] as int, + name: json['name'] as String, + imgList: (json['imgList'] as List) + .map((e) => ImgModel.fromJson(e as Map)) + .toList(), + ); +} diff --git a/lib/ui/market/category/category_card.dart b/lib/ui/market/category/category_card.dart new file mode 100644 index 00000000..14d976c2 --- /dev/null +++ b/lib/ui/market/category/category_card.dart @@ -0,0 +1,43 @@ +import 'package:aku_community/constants/api.dart'; +import 'package:aku_community/model/common/img_model.dart'; +import 'package:aku_community/models/market/market_category_model.dart'; +import 'package:aku_community/ui/market/goods/goods_list_view.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:aku_community/utils/headers.dart'; + +class CategoryCard extends StatelessWidget { + final MarketCategoryModel model; + const CategoryCard({Key? key, required this.model}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialButton( + child: Column( + children: [ + Spacer(), + FadeInImage.assetNetwork( + image: API.image(ImgModel.first(model.imgList)), + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, + height: 75.w, + width: 75.w, + ), + 12.hb, + Text( + model.name, + style: TextStyle( + fontSize: 24.sp, + color: Color(0xFF4A4B51), + ), + ), + Spacer(), + ], + ), + onPressed: () { + Get.to( + () => GoodsListView(), + ); + }, + ); + } +} diff --git a/lib/ui/market/category/category_page.dart b/lib/ui/market/category/category_page.dart index 82e7c172..ad96c6d9 100644 --- a/lib/ui/market/category/category_page.dart +++ b/lib/ui/market/category/category_page.dart @@ -1,19 +1,37 @@ +import 'package:aku_community/models/market/market_category_model.dart'; +import 'package:aku_community/ui/market/category/category_sub_view.dart'; +import 'package:aku_community/ui/market/search/search_goods_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:aku_community/base/base_style.dart'; import 'package:aku_community/utils/headers.dart'; import 'package:aku_community/widget/bee_scaffold.dart'; +import 'package:get/get.dart'; class CategoryPage extends StatefulWidget { - CategoryPage({Key? key}) : super(key: key); + final List models; + CategoryPage({Key? key, required this.models}) : super(key: key); @override _CategoryPageState createState() => _CategoryPageState(); } -class _CategoryPageState extends State { +class _CategoryPageState extends State + with TickerProviderStateMixin { int _index = 0; + late TabController _tabController; + @override + void initState() { + super.initState(); + _tabController = TabController(length: widget.models.length, vsync: this); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { @@ -22,7 +40,9 @@ class _CategoryPageState extends State { actions: [ IconButton( icon: Icon(CupertinoIcons.search), - onPressed: () {}, + onPressed: () { + Get.to(() => SearchGoodsPage()); + }, ), ], bgColor: Colors.white, @@ -35,8 +55,10 @@ class _CategoryPageState extends State { SizedBox( width: 203.w, child: ListView.builder( + physics: ClampingScrollPhysics(), itemBuilder: (context, index) { bool sameIndex = index == _index; + final item = widget.models[index]; return Stack( children: [ MaterialButton( @@ -44,10 +66,11 @@ class _CategoryPageState extends State { minWidth: double.infinity, onPressed: () { _index = index; + _tabController.animateTo(index); setState(() {}); }, child: Text( - 'TEST', + item.name, style: TextStyle( color: sameIndex ? kPrimaryColor : ktextPrimary, ), @@ -55,8 +78,8 @@ class _CategoryPageState extends State { ), AnimatedPositioned( left: sameIndex ? 0 : -8.w, - top: sameIndex ? 20.w : 10.w, - bottom: sameIndex ? 20.w : 10.w, + top: sameIndex ? 20.w : 30.w, + bottom: sameIndex ? 20.w : 30.w, duration: Duration(milliseconds: 300), curve: Curves.easeInOutCubic, child: Container( @@ -68,7 +91,7 @@ class _CategoryPageState extends State { ], ); }, - itemCount: 10, + itemCount: widget.models.length, ), ), VerticalDivider( @@ -76,6 +99,12 @@ class _CategoryPageState extends State { width: 1, thickness: 1, ), + TabBarView( + controller: _tabController, + physics: NeverScrollableScrollPhysics(), + children: + widget.models.map((e) => CategorySubView(id: e.id)).toList(), + ).expand(), ], ), ); diff --git a/lib/ui/market/category/category_sub_card.dart b/lib/ui/market/category/category_sub_card.dart new file mode 100644 index 00000000..0140173b --- /dev/null +++ b/lib/ui/market/category/category_sub_card.dart @@ -0,0 +1,43 @@ +import 'package:aku_community/constants/api.dart'; +import 'package:aku_community/model/common/img_model.dart'; +import 'package:aku_community/models/market/market_category_model.dart'; +import 'package:aku_community/ui/market/goods/goods_list_view.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:aku_community/utils/headers.dart'; + +class CategorySubCard extends StatelessWidget { + final MarketCategoryModel model; + const CategorySubCard({Key? key, required this.model}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialButton( + child: Column( + children: [ + Spacer(), + FadeInImage.assetNetwork( + image: API.image(ImgModel.first(model.imgList)), + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, + height: 75.w, + width: 75.w, + ), + 12.hb, + Text( + model.name, + style: TextStyle( + fontSize: 24.sp, + color: Color(0xFF4A4B51), + ), + ), + Spacer(), + ], + ), + onPressed: () { + Get.to( + () => GoodsListView(), + ); + }, + ); + } +} diff --git a/lib/ui/market/category/category_sub_view.dart b/lib/ui/market/category/category_sub_view.dart new file mode 100644 index 00000000..20b24f7b --- /dev/null +++ b/lib/ui/market/category/category_sub_view.dart @@ -0,0 +1,38 @@ +import 'package:aku_community/models/market/display_category_model.dart'; +import 'package:aku_community/models/market/market_category_model.dart'; +import 'package:aku_community/ui/market/category/category_sub_card.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; + +class CategorySubView extends StatefulWidget { + final int id; + CategorySubView({Key? key, required this.id}) : super(key: key); + + @override + _CategorySubViewState createState() => _CategorySubViewState(); +} + +class _CategorySubViewState extends State { + List _models = []; + @override + Widget build(BuildContext context) { + return EasyRefresh( + header: MaterialHeader(), + firstRefresh: true, + onRefresh: () async { + _models = await DisplayCategoryModel.fetchCategory(widget.id); + setState(() {}); + }, + child: GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + ), + itemBuilder: (context, index) { + final model = _models[index]; + return CategorySubCard(model: model); + }, + itemCount: _models.length, + ), + ); + } +} diff --git a/lib/ui/market/market_page.dart b/lib/ui/market/market_page.dart index 5ca3f99b..957d6f3c 100644 --- a/lib/ui/market/market_page.dart +++ b/lib/ui/market/market_page.dart @@ -1,3 +1,7 @@ +import 'package:aku_community/models/market/display_category_model.dart'; +import 'package:aku_community/models/market/market_category_model.dart'; +import 'package:aku_community/ui/market/category/category_card.dart'; +import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -21,10 +25,15 @@ class MarketPage extends StatefulWidget { class _MarketPageState extends State with AutomaticKeepAliveClientMixin, TickerProviderStateMixin { late TabController _tabController; + List _marketModels = []; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); + DisplayCategoryModel.top8.then((value) { + _marketModels = value; + setState(() {}); + }); } @override @@ -43,7 +52,13 @@ class _MarketPageState extends State MaterialButton( minWidth: 108.w, padding: EdgeInsets.zero, - onPressed: () => Get.to(() => CategoryPage()), + onPressed: () async { + final cancel = BotToast.showLoading(); + List models = + await DisplayCategoryModel.fetchCategory(0); + cancel(); + Get.to(() => CategoryPage(models: models)); + }, child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, @@ -88,8 +103,8 @@ class _MarketPageState extends State childAspectRatio: 1, ), shrinkWrap: true, - children: mockableMarketData - .map((e) => MockableMarketWidget(data: e)) + children: _marketModels + .map((e) => CategoryCard(model: e)) .toList(), ), ), diff --git a/lib/utils/network/net_util.dart b/lib/utils/network/net_util.dart index ca82b336..29b92c6e 100644 --- a/lib/utils/network/net_util.dart +++ b/lib/utils/network/net_util.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:aku_community/utils/developer_util.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:dio/dio.dart'; import 'package:flustars/flustars.dart'; @@ -139,7 +140,10 @@ class NetUtil { _parseErr(DioError err) { LoggerData.addData(err); _makeToast(String message) { - BotToast.showText(text: '$message\_${err.response?.statusCode ?? ''}'); + if (DeveloperUtil.dev) + BotToast.showText(text: '$message\_${err.response?.statusCode ?? ''}'); + else + BotToast.showText(text: '网络出现问题'); } switch (err.type) {