#1 商城v1.0

Merged
lyq merged 2 commits from lyq/develop into lyq/master 5 years ago
66 changed files with 3385 additions and 203 deletions
  1. 40 0
      README_cn.md
  2. 21 7
      android/app/build.gradle
  3. 6 1
      android/app/src/main/AndroidManifest.xml
  4. 10 0
      android/app/src/main/java/me/yoqi/flutternote/FlutterNoteApplication.java
  5. 11 0
      android/app/src/main/java/me/yoqi/flutternote/View/SecondActivity.java
  6. 5 0
      android/app/src/main/java/me/yoqi/flutternote/model/Movie.java
  7. 3 3
      android/build.gradle
  8. 2 0
      android/gradle.properties
  9. 1 1
      android/gradle/wrapper/gradle-wrapper.properties
  10. 0 0
      android/sign/release.jks
  11. BIN
      images/avatar.jpg
  12. BIN
      images/empty.png
  13. 14 0
      lib/config/http_headers.dart
  14. 8 0
      lib/config/service_url.dart
  15. 40 109
      lib/main.dart
  16. 10 0
      lib/model/base.dart
  17. 47 0
      lib/model/category_goods_model.dart
  18. 69 0
      lib/model/category_model.dart
  19. 140 0
      lib/model/goods_detail_model.dart
  20. 481 0
      lib/model/home_page_model.dart
  21. 64 0
      lib/model/hot_goods_model.dart
  22. 41 0
      lib/model/shopping_cart_model.dart
  23. 23 0
      lib/provide/cart_count_provide.dart
  24. 159 0
      lib/provide/cart_provide.dart
  25. 32 0
      lib/provide/goods_detail_provide.dart
  26. 74 0
      lib/provide/home_provide.dart
  27. 34 0
      lib/provide/mall_goods_provide.dart
  28. 13 0
      lib/provide/page_index_provide.dart
  29. 59 0
      lib/provide/sub_category_provide.dart
  30. 7 0
      lib/routers/application.dart
  31. 16 0
      lib/routers/router_handler.dart
  32. 21 0
      lib/routers/routers.dart
  33. 33 0
      lib/service/service_method.dart
  34. 16 0
      lib/shop_app.dart
  35. 56 0
      lib/utils/preference_utils.dart
  36. 56 0
      lib/views/cartpage/bottom_summary.dart
  37. 66 0
      lib/views/cartpage/cart_count.dart
  38. 27 0
      lib/views/cartpage/cart_page.dart
  39. 36 0
      lib/views/cartpage/empty_cart.dart
  40. 131 0
      lib/views/cartpage/shopping_cart_list.dart
  41. 258 0
      lib/views/category_page.dart
  42. 61 0
      lib/views/deatilspage/details_page.dart
  43. 54 0
      lib/views/deatilspage/goods_comments.dart
  44. 28 0
      lib/views/deatilspage/goods_detail.dart
  45. 173 0
      lib/views/deatilspage/goods_handler.dart
  46. 129 0
      lib/views/deatilspage/sliver_header_bar.dart
  47. 12 0
      lib/views/homepage/ad_banner.dart
  48. 33 0
      lib/views/homepage/banner_diy.dart
  49. 59 0
      lib/views/homepage/floor_part.dart
  50. 164 0
      lib/views/homepage/home_page.dart
  51. 58 0
      lib/views/homepage/hot_part.dart
  52. 22 0
      lib/views/homepage/lead_phone.dart
  53. 74 0
      lib/views/homepage/mall_recommend.dart
  54. 49 0
      lib/views/homepage/top_nativator.dart
  55. 45 0
      lib/views/index_page.dart
  56. 49 0
      lib/views/map_page.dart
  57. 25 0
      lib/views/mempage/mem_header.dart
  58. 44 0
      lib/views/mempage/mem_page.dart
  59. 19 0
      lib/views/mempage/mem_tile.dart
  60. 26 0
      lib/views/mempage/order_grid.dart
  61. 47 0
      lib/views/my_home_page.dart
  62. 44 0
      lib/views/settings_page.dart
  63. 15 0
      lib/widgets/404.dart
  64. 20 52
      pubspec.yaml
  65. 0 30
      test/widget_test.dart
  66. 5 0
      tools/run_flutter.sh

+ 40 - 0
README_cn.md

@@ -0,0 +1,40 @@
+# flutter_note
+
+Flutter 学习工具,主要开发 android UI。
+
+## 开始
+
+* 项目结构:
+
+```
+./android              android项目
+./ios                  ios项目
+./lib                  flutter公共项目
+    ./lib/routers
+    ./lib/views          (pages)
+    ./lib/model
+    ./lib/main.dart
+    ./lib/widgets
+    ./lib/service
+    ./lib/env.dart
+    ./lib/utils
+    ./lib/components
+    ./lib/blocs
+./pubspec.yaml         flutter配置
+./README.md
+./test
+```
+
+## 开发
+
+
+
+## 注意事项
+
+1、依赖有严格要求:
+```
+ext.kotlin_version = '1.2.71'
+
+classpath 'com.android.tools.build:gradle:3.2.0'
+```
+

+ 21 - 7
android/app/build.gradle

@@ -26,8 +26,22 @@ apply plugin: 'kotlin-android'
 apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
 
 android {
-    compileSdkVersion 27
-
+    compileSdkVersion 28
+    signingConfigs {
+        release {
+            storeFile file("../sign/release.jks")
+            keyAlias "alias_release"
+            keyPassword "123456"
+            storePassword "123456"
+        }
+//        debug {
+//            storeFile file("../sign/debug.jks")
+//            keyAlias "alias_debug"
+//            keyPassword "123456"
+//            storePassword "123456"
+//        }
+    }
+    signingConfig signingConfigs.release
     sourceSets {
         main.java.srcDirs += 'src/main/kotlin'
     }
@@ -40,10 +54,10 @@ android {
         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
         applicationId "yoqi.me.flutternote"
         minSdkVersion 16
-        targetSdkVersion 27
+        targetSdkVersion 28
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+//        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     buildTypes {
@@ -61,7 +75,7 @@ flutter {
 
 dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-    testImplementation 'junit:junit:4.12'
-    androidTestImplementation 'com.android.support.test:runner:1.0.2'
-    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+//    testImplementation 'junit:junit:4.12'
+//    androidTestImplementation 'com.android.support.test:runner:1.0.2'
+//    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
 }

+ 6 - 1
android/app/src/main/AndroidManifest.xml

@@ -6,7 +6,9 @@
          to allow setting breakpoints, to provide hot reload, etc.
     -->
     <uses-permission android:name="android.permission.INTERNET"/>
-
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <!-- io.flutter.app.FlutterApplication is an android.app.Application that
          calls FlutterMain.startInitialization(this); in its onCreate method.
          In most cases you can leave this as-is, but you if you want to provide
@@ -16,6 +18,9 @@
         android:name="io.flutter.app.FlutterApplication"
         android:label="flutter_note"
         android:icon="@mipmap/ic_launcher">
+        <meta-data
+            android:name="com.amap.api.v2.apikey"
+            android:value="14ece3f2826950a4250d19726c8436ff" />
         <activity
             android:name=".MainActivity"
             android:launchMode="singleTop"

+ 10 - 0
android/app/src/main/java/me/yoqi/flutternote/FlutterNoteApplication.java

@@ -0,0 +1,10 @@
+package me.yoqi.flutternote;
+
+import android.app.Application;
+
+public class FlutterNoteApplication extends Application {
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+}

+ 11 - 0
android/app/src/main/java/me/yoqi/flutternote/View/SecondActivity.java

@@ -0,0 +1,11 @@
+package me.yoqi.flutternote.View;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class SecondActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+}

+ 5 - 0
android/app/src/main/java/me/yoqi/flutternote/model/Movie.java

@@ -0,0 +1,5 @@
+package me.yoqi.flutternote.model;
+
+public class Movie {
+
+}

+ 3 - 3
android/build.gradle

@@ -2,11 +2,11 @@ buildscript {
     ext.kotlin_version = '1.2.71'
     repositories {
         google()
-        jcenter()
+        maven{url'http://maven.aliyun.com/nexus/content/groups/public/'}
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.2.1'
+        classpath 'com.android.tools.build:gradle:3.2.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
@@ -14,7 +14,7 @@ buildscript {
 allprojects {
     repositories {
         google()
-        jcenter()
+        maven{url'http://maven.aliyun.com/nexus/content/groups/public/'}
     }
 }
 

+ 2 - 0
android/gradle.properties

@@ -1 +1,3 @@
+android.enableJetifier=true
+android.useAndroidX=true
 org.gradle.jvmargs=-Xmx1536M

+ 1 - 1
android/gradle/wrapper/gradle-wrapper.properties

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip

+ 0 - 0
android/sign/release.jks


BIN
images/avatar.jpg


BIN
images/empty.png


+ 14 - 0
lib/config/http_headers.dart

@@ -0,0 +1,14 @@
+const httpHeaders = {
+  'Accept': 'application/json, text/plain, */*',
+  'Accept-Encoding': 'gzip, deflate, br',
+  'Accept-Language': 'zh-CN,zh;q=0.9',
+  'Connection': 'keep-alive',
+  'Content-Type': 'application/json',
+  'Cookie':
+      '_ga=GA1.2.676402787.1548321037; GCID=9d149c5-11cb3b3-80ad198-04b551d; _gid=GA1.2.359074521.1550799897; _gat=1; Hm_lvt_022f847c4e3acd44d4a2481d9187f1e6=1550106367,1550115714,1550123110,1550799897; SERVERID=1fa1f330efedec1559b3abbcb6e30f50|1550799909|1550799898; Hm_lpvt_022f847c4e3acd44d4a2481d9187f1e6=1550799907',
+  'Host': 'time.geekbang.org',
+  'Origin': 'https://time.geekbang.org',
+  'Referer': 'https://time.geekbang.org/',
+  'User-Agent':
+      'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
+};

+ 8 - 0
lib/config/service_url.dart

@@ -0,0 +1,8 @@
+const serviceUrl = 'http://v.jspang.com:8088/baixing';
+const servicePath = {
+  'homePageContext': serviceUrl + '/wxmini/homePageContent', // 商家首页信息
+  'homePageBelowConten': serviceUrl + '/wxmini/homePageBelowConten', //商城首页热卖商品拉取
+  'getCategory': serviceUrl + '/wxmini/getCategory', //商品类别信息
+  'getMallGoods': serviceUrl + '/wxmini/getMallGoods', //商品分类的商品列表
+  'getGoodDetailById': serviceUrl + '/wxmini/getGoodDetailById', //商品详细信息列表
+};

+ 40 - 109
lib/main.dart

@@ -1,111 +1,42 @@
+import 'dart:io';
+import 'package:fluro/fluro.dart';
 import 'package:flutter/material.dart';
-
-void main() => runApp(MyApp());
-
-class MyApp extends StatelessWidget {
-  // This widget is the root of your application.
-  @override
-  Widget build(BuildContext context) {
-    return MaterialApp(
-      title: 'Flutter Demo',
-      theme: ThemeData(
-        // This is the theme of your application.
-        //
-        // Try running your application with "flutter run". You'll see the
-        // application has a blue toolbar. Then, without quitting the app, try
-        // changing the primarySwatch below to Colors.green and then invoke
-        // "hot reload" (press "r" in the console where you ran "flutter run",
-        // or simply save your changes to "hot reload" in a Flutter IDE).
-        // Notice that the counter didn't reset back to zero; the application
-        // is not restarted.
-        primarySwatch: Colors.blue,
-      ),
-      home: MyHomePage(title: 'Flutter Demo Home Page'),
-    );
-  }
-}
-
-class MyHomePage extends StatefulWidget {
-  MyHomePage({Key key, this.title}) : super(key: key);
-
-  // This widget is the home page of your application. It is stateful, meaning
-  // that it has a State object (defined below) that contains fields that affect
-  // how it looks.
-
-  // This class is the configuration for the state. It holds the values (in this
-  // case the title) provided by the parent (in this case the App widget) and
-  // used by the build method of the State. Fields in a Widget subclass are
-  // always marked "final".
-
-  final String title;
-
-  @override
-  _MyHomePageState createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State<MyHomePage> {
-  int _counter = 0;
-
-  void _incrementCounter() {
-    setState(() {
-      // This call to setState tells the Flutter framework that something has
-      // changed in this State, which causes it to rerun the build method below
-      // so that the display can reflect the updated values. If we changed
-      // _counter without calling setState(), then the build method would not be
-      // called again, and so nothing would appear to happen.
-      _counter++;
-    });
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    // This method is rerun every time setState is called, for instance as done
-    // by the _incrementCounter method above.
-    //
-    // The Flutter framework has been optimized to make rerunning build methods
-    // fast, so that you can just rebuild anything that needs updating rather
-    // than having to individually change instances of widgets.
-    return Scaffold(
-      appBar: AppBar(
-        // Here we take the value from the MyHomePage object that was created by
-        // the App.build method, and use it to set our appbar title.
-        title: Text(widget.title),
-      ),
-      body: Center(
-        // Center is a layout widget. It takes a single child and positions it
-        // in the middle of the parent.
-        child: Column(
-          // Column is also layout widget. It takes a list of children and
-          // arranges them vertically. By default, it sizes itself to fit its
-          // children horizontally, and tries to be as tall as its parent.
-          //
-          // Invoke "debug painting" (press "p" in the console, choose the
-          // "Toggle Debug Paint" action from the Flutter Inspector in Android
-          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
-          // to see the wireframe for each widget.
-          //
-          // Column has various properties to control how it sizes itself and
-          // how it positions its children. Here we use mainAxisAlignment to
-          // center the children vertically; the main axis here is the vertical
-          // axis because Columns are vertical (the cross axis would be
-          // horizontal).
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            Text(
-              'You have pushed the button this many times:',
-            ),
-            Text(
-              '$_counter',
-              style: Theme.of(context).textTheme.display1,
-            ),
-          ],
-        ),
-      ),
-      floatingActionButton: FloatingActionButton(
-        onPressed: _incrementCounter,
-        tooltip: 'Increment',
-        child: Icon(Icons.add),
-      ), // This trailing comma makes auto-formatting nicer for build methods.
-    );
-  }
+import 'package:flutter/services.dart';
+import 'package:provide/provide.dart';
+
+import 'package:flutter_note/routers/application.dart';
+import 'package:flutter_note/routers/routers.dart';
+import 'package:flutter_note/shop_app.dart';
+
+import 'package:flutter_note/provide/cart_count_provide.dart';
+import 'package:flutter_note/provide/cart_provide.dart';
+import 'package:flutter_note/provide/home_provide.dart';
+import 'package:flutter_note/provide/page_index_provide.dart';
+import 'package:flutter_note/provide/goods_detail_provide.dart';
+import 'package:flutter_note/provide/mall_goods_provide.dart';
+import 'package:flutter_note/provide/sub_category_provide.dart';
+//程序入口
+void main() {
+  final providers = Providers()
+    ..provide(Provider.function((_) => HomeProvide())) // 主页面
+    ..provide(Provider.function((_) => PageIndexProvide())) // 主页面 tab 切换
+    ..provide(Provider.function((_) => CartCountProvide())) // 详情页面购物车数量修改
+    ..provide(Provider.function((_) => SubCategoryProvide())) // 分类页面切换
+    ..provide(Provider.function((_) => MallGoodsProvide())) // 分类页面刷新加载
+    ..provide(Provider.function((_) => GoodsDetailProvide())) // 商品详情页面
+    ..provide(Provider.function((_) => CartProvide())); // 购物车持久化
+
+  final Router router = Router();
+  Routers.configureRouters(router);
+  Application.router = router;
+
+  // 强制竖屏
+  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitDown, DeviceOrientation.portraitUp]).then((_) {
+    runApp(ProviderNode(child: ShopApp(), providers: providers));
+
+    // android 下透明状态栏
+    if (Platform.isAndroid) {
+      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(statusBarColor: Colors.transparent));
+    }
+  });
 }

+ 10 - 0
lib/model/base.dart

@@ -0,0 +1,10 @@
+import 'package:sqflite/sqflite.dart';
+
+class BaseModel{
+  Database db;
+  final String table = '';
+  var query;
+  BaseModel(this.db){
+    query = db.query;
+  }
+}

+ 47 - 0
lib/model/category_goods_model.dart

@@ -0,0 +1,47 @@
+class CategoryGoodsModel {
+  String code;
+  String message;
+  List<CategoryGoodsInfo> data;
+
+  static CategoryGoodsModel fromMap(Map<String, dynamic> map) {
+    CategoryGoodsModel bean = new CategoryGoodsModel();
+    bean.code = map['code'];
+    bean.message = map['message'];
+    bean.data = CategoryGoodsInfo.fromMapList(map['data']);
+    return bean;
+  }
+
+  static List<CategoryGoodsModel> fromMapList(dynamic mapList) {
+    List<CategoryGoodsModel> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}
+
+class CategoryGoodsInfo {
+  String image;
+  String goodsId;
+  String goodsName;
+  double oriPrice;
+  double presentPrice;
+
+  static CategoryGoodsInfo fromMap(Map<String, dynamic> map) {
+    CategoryGoodsInfo dataListBean = new CategoryGoodsInfo();
+    dataListBean.image = map['image'];
+    dataListBean.goodsId = map['goodsId'];
+    dataListBean.goodsName = map['goodsName'];
+    dataListBean.oriPrice = map['oriPrice'] + 0.0;
+    dataListBean.presentPrice = map['presentPrice'] + 0.0;
+    return dataListBean;
+  }
+
+  static List<CategoryGoodsInfo> fromMapList(dynamic mapList) {
+    List<CategoryGoodsInfo> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}

+ 69 - 0
lib/model/category_model.dart

@@ -0,0 +1,69 @@
+class CategoryModel {
+  String code;
+  String message;
+  List<CategoryData> data;
+
+  static CategoryModel fromMap(Map<String, dynamic> map) {
+    CategoryModel category = new CategoryModel();
+    category.code = map['code'];
+    category.message = map['message'];
+    category.data = CategoryData.fromMapList(map['data']);
+    return category;
+  }
+
+  static List<CategoryModel> fromMapList(dynamic mapList) {
+    List<CategoryModel> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}
+
+class CategoryData {
+  String mallCategoryId;
+  String mallCategoryName;
+  String image;
+  List<BxMallSubDtoListBean> bxMallSubDto;
+
+  static CategoryData fromMap(Map<String, dynamic> map) {
+    CategoryData dataListBean = new CategoryData();
+    dataListBean.mallCategoryId = map['mallCategoryId'];
+    dataListBean.mallCategoryName = map['mallCategoryName'];
+    dataListBean.image = map['image'];
+    dataListBean.bxMallSubDto = BxMallSubDtoListBean.fromMapList(map['bxMallSubDto']);
+    return dataListBean;
+  }
+
+  static List<CategoryData> fromMapList(dynamic mapList) {
+    List<CategoryData> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}
+
+class BxMallSubDtoListBean {
+  String mallSubId;
+  String mallCategoryId;
+  String mallSubName;
+  String comments;
+
+  static BxMallSubDtoListBean fromMap(Map<String, dynamic> map) {
+    BxMallSubDtoListBean bxMallSubDtoListBean = new BxMallSubDtoListBean();
+    bxMallSubDtoListBean.mallSubId = map['mallSubId'];
+    bxMallSubDtoListBean.mallCategoryId = map['mallCategoryId'];
+    bxMallSubDtoListBean.mallSubName = map['mallSubName'];
+    bxMallSubDtoListBean.comments = map['comments'];
+    return bxMallSubDtoListBean;
+  }
+
+  static List<BxMallSubDtoListBean> fromMapList(dynamic mapList) {
+    List<BxMallSubDtoListBean> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}

+ 140 - 0
lib/model/goods_detail_model.dart

@@ -0,0 +1,140 @@
+class GoodsDetailModel {
+  String code;
+  String message;
+  GoodsDetailInfo data;
+
+  static GoodsDetailModel fromMap(Map<String, dynamic> map) {
+    GoodsDetailModel model = new GoodsDetailModel();
+    model.code = map['code'];
+    model.message = map['message'];
+    model.data = GoodsDetailInfo.fromMap(map['data']);
+    return model;
+  }
+
+  static List<GoodsDetailModel> fromMapList(dynamic mapList) {
+    List<GoodsDetailModel> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}
+
+class GoodsDetailInfo {
+  AdvertesPictureBean advertesPicture;
+  GoodInfoBean goodInfo;
+  List<GoodCommentsListBean> goodComments;
+
+  static GoodsDetailInfo fromMap(Map<String, dynamic> map) {
+    GoodsDetailInfo dataBean = new GoodsDetailInfo();
+    dataBean.advertesPicture = AdvertesPictureBean.fromMap(map['advertesPicture']);
+    dataBean.goodInfo = GoodInfoBean.fromMap(map['goodInfo']);
+    dataBean.goodComments = GoodCommentsListBean.fromMapList(map['goodComments']);
+    return dataBean;
+  }
+
+  static List<GoodsDetailInfo> fromMapList(dynamic mapList) {
+    List<GoodsDetailInfo> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}
+
+class AdvertesPictureBean {
+  // ignore: non_constant_identifier_names
+  String PICTURE_ADDRESS;
+
+  // ignore: non_constant_identifier_names
+  String TO_PLACE;
+
+  static AdvertesPictureBean fromMap(Map<String, dynamic> map) {
+    AdvertesPictureBean advertesPictureBean = new AdvertesPictureBean();
+    advertesPictureBean.PICTURE_ADDRESS = map['PICTURE_ADDRESS'];
+    advertesPictureBean.TO_PLACE = map['TO_PLACE'];
+    return advertesPictureBean;
+  }
+
+  static List<AdvertesPictureBean> fromMapList(dynamic mapList) {
+    List<AdvertesPictureBean> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}
+
+class GoodInfoBean {
+  String image5;
+  String image3;
+  String image4;
+  String goodsId;
+  String isOnline;
+  String image1;
+  String image2;
+  String goodsSerialNumber;
+  String comPic;
+  String shopId;
+  String goodsName;
+  String goodsDetail;
+  int amount;
+  double oriPrice;
+  double presentPrice;
+  int state;
+
+  static GoodInfoBean fromMap(Map<String, dynamic> map) {
+    GoodInfoBean goodInfoBean = new GoodInfoBean();
+    goodInfoBean.image5 = map['image5'];
+    goodInfoBean.image3 = map['image3'];
+    goodInfoBean.image4 = map['image4'];
+    goodInfoBean.goodsId = map['goodsId'];
+    goodInfoBean.isOnline = map['isOnline'];
+    goodInfoBean.image1 = map['image1'];
+    goodInfoBean.image2 = map['image2'];
+    goodInfoBean.goodsSerialNumber = map['goodsSerialNumber'];
+    goodInfoBean.comPic = map['comPic'];
+    goodInfoBean.shopId = map['shopId'];
+    goodInfoBean.goodsName = map['goodsName'];
+    goodInfoBean.goodsDetail = map['goodsDetail'];
+    goodInfoBean.amount = map['amount'];
+    goodInfoBean.oriPrice = map['oriPrice'] + 0.0;
+    goodInfoBean.presentPrice = map['presentPrice'] + 0.0;
+    goodInfoBean.state = map['state'];
+    return goodInfoBean;
+  }
+
+  static List<GoodInfoBean> fromMapList(dynamic mapList) {
+    List<GoodInfoBean> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}
+
+class GoodCommentsListBean {
+  String comments;
+  String userName;
+
+  // ignore: non_constant_identifier_names
+  int SCORE;
+  int discussTime;
+
+  static GoodCommentsListBean fromMap(Map<String, dynamic> map) {
+    GoodCommentsListBean goodCommentsListBean = new GoodCommentsListBean();
+    goodCommentsListBean.comments = map['comments'];
+    goodCommentsListBean.userName = map['userName'];
+    goodCommentsListBean.SCORE = map['SCORE'];
+    goodCommentsListBean.discussTime = map['discussTime'];
+    return goodCommentsListBean;
+  }
+
+  static List<GoodCommentsListBean> fromMapList(dynamic mapList) {
+    List<GoodCommentsListBean> list = new List(mapList.length);
+    for (int i = 0; i < mapList.length; i++) {
+      list[i] = fromMap(mapList[i]);
+    }
+    return list;
+  }
+}

+ 481 - 0
lib/model/home_page_model.dart

@@ -0,0 +1,481 @@
+class HomePageModel {
+  String code;
+  String message;
+  HomeData data;
+
+  HomePageModel({this.code, this.message, this.data});
+
+  HomePageModel.fromJson(Map<String, dynamic> json) {
+    code = json['code'];
+    message = json['message'];
+    data = json['data'] != null ? new HomeData.fromJson(json['data']) : null;
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['code'] = this.code;
+    data['message'] = this.message;
+    if (this.data != null) {
+      data['data'] = this.data.toJson();
+    }
+    return data;
+  }
+}
+
+class HomeData {
+  List<Slides> slides;
+  ShopInfo shopInfo;
+  IntegralMallPic integralMallPic;
+  ToShareCode toShareCode;
+  List<Recommend> recommend;
+  AdvertesPicture advertesPicture;
+  List<Floor> floor1;
+  List<Floor> floor2;
+  List<Floor> floor3;
+  Saoma saoma;
+  NewUser newUser;
+  Floor1Pic floor1Pic;
+  Floor2Pic floor2Pic;
+  FloorName floorName;
+  List<Category> category;
+  Floor3Pic floor3Pic;
+
+  HomeData(
+      {this.slides,
+      this.shopInfo,
+      this.integralMallPic,
+      this.toShareCode,
+      this.recommend,
+      this.advertesPicture,
+      this.floor1,
+      this.floor2,
+      this.floor3,
+      this.saoma,
+      this.newUser,
+      this.floor1Pic,
+      this.floor2Pic,
+      this.floorName,
+      this.category,
+      this.floor3Pic});
+
+  HomeData.fromJson(Map<String, dynamic> json) {
+    if (json['slides'] != null) {
+      slides = new List<Slides>();
+      json['slides'].forEach((v) {
+        slides.add(new Slides.fromJson(v));
+      });
+    }
+    shopInfo = json['shopInfo'] != null ? new ShopInfo.fromJson(json['shopInfo']) : null;
+    integralMallPic = json['integralMallPic'] != null ? new IntegralMallPic.fromJson(json['integralMallPic']) : null;
+    toShareCode = json['toShareCode'] != null ? new ToShareCode.fromJson(json['toShareCode']) : null;
+    if (json['recommend'] != null) {
+      recommend = new List<Recommend>();
+      json['recommend'].forEach((v) {
+        recommend.add(new Recommend.fromJson(v));
+      });
+    }
+    advertesPicture = json['advertesPicture'] != null ? new AdvertesPicture.fromJson(json['advertesPicture']) : null;
+    if (json['floor1'] != null) {
+      floor1 = new List<Floor>();
+      json['floor1'].forEach((v) {
+        floor1.add(new Floor.fromJson(v));
+      });
+    }
+    if (json['floor2'] != null) {
+      floor2 = new List<Floor>();
+      json['floor2'].forEach((v) {
+        floor2.add(new Floor.fromJson(v));
+      });
+    }
+    if (json['floor3'] != null) {
+      floor3 = new List<Floor>();
+      json['floor3'].forEach((v) {
+        floor3.add(new Floor.fromJson(v));
+      });
+    }
+    saoma = json['saoma'] != null ? new Saoma.fromJson(json['saoma']) : null;
+    newUser = json['newUser'] != null ? new NewUser.fromJson(json['newUser']) : null;
+    floor1Pic = json['floor1Pic'] != null ? new Floor1Pic.fromJson(json['floor1Pic']) : null;
+    floor2Pic = json['floor2Pic'] != null ? new Floor2Pic.fromJson(json['floor2Pic']) : null;
+    floorName = json['floorName'] != null ? new FloorName.fromJson(json['floorName']) : null;
+    if (json['category'] != null) {
+      category = new List<Category>();
+      json['category'].forEach((v) {
+        category.add(new Category.fromJson(v));
+      });
+    }
+    floor3Pic = json['floor3Pic'] != null ? new Floor3Pic.fromJson(json['floor3Pic']) : null;
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    if (this.slides != null) {
+      data['slides'] = this.slides.map((v) => v.toJson()).toList();
+    }
+    if (this.shopInfo != null) {
+      data['shopInfo'] = this.shopInfo.toJson();
+    }
+    if (this.integralMallPic != null) {
+      data['integralMallPic'] = this.integralMallPic.toJson();
+    }
+    if (this.toShareCode != null) {
+      data['toShareCode'] = this.toShareCode.toJson();
+    }
+    if (this.recommend != null) {
+      data['recommend'] = this.recommend.map((v) => v.toJson()).toList();
+    }
+    if (this.advertesPicture != null) {
+      data['advertesPicture'] = this.advertesPicture.toJson();
+    }
+    if (this.floor1 != null) {
+      data['floor1'] = this.floor1.map((v) => v.toJson()).toList();
+    }
+    if (this.floor2 != null) {
+      data['floor2'] = this.floor2.map((v) => v.toJson()).toList();
+    }
+    if (this.floor3 != null) {
+      data['floor3'] = this.floor3.map((v) => v.toJson()).toList();
+    }
+    if (this.saoma != null) {
+      data['saoma'] = this.saoma.toJson();
+    }
+    if (this.newUser != null) {
+      data['newUser'] = this.newUser.toJson();
+    }
+    if (this.floor1Pic != null) {
+      data['floor1Pic'] = this.floor1Pic.toJson();
+    }
+    if (this.floor2Pic != null) {
+      data['floor2Pic'] = this.floor2Pic.toJson();
+    }
+    if (this.floorName != null) {
+      data['floorName'] = this.floorName.toJson();
+    }
+    if (this.category != null) {
+      data['category'] = this.category.map((v) => v.toJson()).toList();
+    }
+    if (this.floor3Pic != null) {
+      data['floor3Pic'] = this.floor3Pic.toJson();
+    }
+    return data;
+  }
+}
+
+class Slides {
+  String image;
+  String goodsId;
+
+  Slides({this.image, this.goodsId});
+
+  Slides.fromJson(Map<String, dynamic> json) {
+    image = json['image'];
+    goodsId = json['goodsId'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['image'] = this.image;
+    data['goodsId'] = this.goodsId;
+    return data;
+  }
+}
+
+class ShopInfo {
+  String leaderImage;
+  String leaderPhone;
+
+  ShopInfo({this.leaderImage, this.leaderPhone});
+
+  ShopInfo.fromJson(Map<String, dynamic> json) {
+    leaderImage = json['leaderImage'];
+    leaderPhone = json['leaderPhone'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['leaderImage'] = this.leaderImage;
+    data['leaderPhone'] = this.leaderPhone;
+    return data;
+  }
+}
+
+class IntegralMallPic {
+  String pICTUREADDRESS;
+  String tOPLACE;
+
+  IntegralMallPic({this.pICTUREADDRESS, this.tOPLACE});
+
+  IntegralMallPic.fromJson(Map<String, dynamic> json) {
+    pICTUREADDRESS = json['PICTURE_ADDRESS'];
+    tOPLACE = json['TO_PLACE'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['PICTURE_ADDRESS'] = this.pICTUREADDRESS;
+    data['TO_PLACE'] = this.tOPLACE;
+    return data;
+  }
+}
+
+class ToShareCode {
+  String pICTUREADDRESS;
+  String tOPLACE;
+
+  ToShareCode({this.pICTUREADDRESS, this.tOPLACE});
+
+  ToShareCode.fromJson(Map<String, dynamic> json) {
+    pICTUREADDRESS = json['PICTURE_ADDRESS'];
+    tOPLACE = json['TO_PLACE'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['PICTURE_ADDRESS'] = this.pICTUREADDRESS;
+    data['TO_PLACE'] = this.tOPLACE;
+    return data;
+  }
+}
+
+class Recommend {
+  String image;
+  double mallPrice;
+  String goodsName;
+  String goodsId;
+  double price;
+
+  Recommend({this.image, this.mallPrice, this.goodsName, this.goodsId, this.price});
+
+  Recommend.fromJson(Map<String, dynamic> json) {
+    image = json['image'];
+    mallPrice = json['mallPrice'] + 0.0;
+    goodsName = json['goodsName'];
+    goodsId = json['goodsId'];
+    price = json['price'] + 0.0;
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['image'] = this.image;
+    data['mallPrice'] = this.mallPrice;
+    data['goodsName'] = this.goodsName;
+    data['goodsId'] = this.goodsId;
+    data['price'] = this.price;
+    return data;
+  }
+}
+
+class AdvertesPicture {
+  String pICTUREADDRESS;
+  String tOPLACE;
+
+  AdvertesPicture({this.pICTUREADDRESS, this.tOPLACE});
+
+  AdvertesPicture.fromJson(Map<String, dynamic> json) {
+    pICTUREADDRESS = json['PICTURE_ADDRESS'];
+    tOPLACE = json['TO_PLACE'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['PICTURE_ADDRESS'] = this.pICTUREADDRESS;
+    data['TO_PLACE'] = this.tOPLACE;
+    return data;
+  }
+}
+
+class Floor {
+  String image;
+  String goodsId;
+
+  Floor({this.image, this.goodsId});
+
+  Floor.fromJson(Map<String, dynamic> json) {
+    image = json['image'];
+    goodsId = json['goodsId'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['image'] = this.image;
+    data['goodsId'] = this.goodsId;
+    return data;
+  }
+}
+
+class Saoma {
+  String pICTUREADDRESS;
+  String tOPLACE;
+
+  Saoma({this.pICTUREADDRESS, this.tOPLACE});
+
+  Saoma.fromJson(Map<String, dynamic> json) {
+    pICTUREADDRESS = json['PICTURE_ADDRESS'];
+    tOPLACE = json['TO_PLACE'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['PICTURE_ADDRESS'] = this.pICTUREADDRESS;
+    data['TO_PLACE'] = this.tOPLACE;
+    return data;
+  }
+}
+
+class NewUser {
+  String pICTUREADDRESS;
+  String tOPLACE;
+
+  NewUser({this.pICTUREADDRESS, this.tOPLACE});
+
+  NewUser.fromJson(Map<String, dynamic> json) {
+    pICTUREADDRESS = json['PICTURE_ADDRESS'];
+    tOPLACE = json['TO_PLACE'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['PICTURE_ADDRESS'] = this.pICTUREADDRESS;
+    data['TO_PLACE'] = this.tOPLACE;
+    return data;
+  }
+}
+
+class Floor1Pic {
+  String pICTUREADDRESS;
+  String tOPLACE;
+
+  Floor1Pic({this.pICTUREADDRESS, this.tOPLACE});
+
+  Floor1Pic.fromJson(Map<String, dynamic> json) {
+    pICTUREADDRESS = json['PICTURE_ADDRESS'];
+    tOPLACE = json['TO_PLACE'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['PICTURE_ADDRESS'] = this.pICTUREADDRESS;
+    data['TO_PLACE'] = this.tOPLACE;
+    return data;
+  }
+}
+
+class Floor2Pic {
+  String pICTUREADDRESS;
+  String tOPLACE;
+
+  Floor2Pic({this.pICTUREADDRESS, this.tOPLACE});
+
+  Floor2Pic.fromJson(Map<String, dynamic> json) {
+    pICTUREADDRESS = json['PICTURE_ADDRESS'];
+    tOPLACE = json['TO_PLACE'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['PICTURE_ADDRESS'] = this.pICTUREADDRESS;
+    data['TO_PLACE'] = this.tOPLACE;
+    return data;
+  }
+}
+
+class FloorName {
+  String floor1;
+  String floor2;
+  String floor3;
+
+  FloorName({this.floor1, this.floor2, this.floor3});
+
+  FloorName.fromJson(Map<String, dynamic> json) {
+    floor1 = json['floor1'];
+    floor2 = json['floor2'];
+    floor3 = json['floor3'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['floor1'] = this.floor1;
+    data['floor2'] = this.floor2;
+    data['floor3'] = this.floor3;
+    return data;
+  }
+}
+
+class Category {
+  String mallCategoryId;
+  String mallCategoryName;
+  List<BxMallSubDto> bxMallSubDto;
+  Null comments;
+  String image;
+
+  Category({this.mallCategoryId, this.mallCategoryName, this.bxMallSubDto, this.comments, this.image});
+
+  Category.fromJson(Map<String, dynamic> json) {
+    mallCategoryId = json['mallCategoryId'];
+    mallCategoryName = json['mallCategoryName'];
+    if (json['bxMallSubDto'] != null) {
+      bxMallSubDto = new List<BxMallSubDto>();
+      json['bxMallSubDto'].forEach((v) {
+        bxMallSubDto.add(new BxMallSubDto.fromJson(v));
+      });
+    }
+    comments = json['comments'];
+    image = json['image'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['mallCategoryId'] = this.mallCategoryId;
+    data['mallCategoryName'] = this.mallCategoryName;
+    if (this.bxMallSubDto != null) {
+      data['bxMallSubDto'] = this.bxMallSubDto.map((v) => v.toJson()).toList();
+    }
+    data['comments'] = this.comments;
+    data['image'] = this.image;
+    return data;
+  }
+}
+
+class BxMallSubDto {
+  String mallSubId;
+  String mallCategoryId;
+  String mallSubName;
+  String comments;
+
+  BxMallSubDto({this.mallSubId, this.mallCategoryId, this.mallSubName, this.comments});
+
+  BxMallSubDto.fromJson(Map<String, dynamic> json) {
+    mallSubId = json['mallSubId'];
+    mallCategoryId = json['mallCategoryId'];
+    mallSubName = json['mallSubName'];
+    comments = json['comments'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['mallSubId'] = this.mallSubId;
+    data['mallCategoryId'] = this.mallCategoryId;
+    data['mallSubName'] = this.mallSubName;
+    data['comments'] = this.comments;
+    return data;
+  }
+}
+
+class Floor3Pic {
+  String pICTUREADDRESS;
+  String tOPLACE;
+
+  Floor3Pic({this.pICTUREADDRESS, this.tOPLACE});
+
+  Floor3Pic.fromJson(Map<String, dynamic> json) {
+    pICTUREADDRESS = json['PICTURE_ADDRESS'];
+    tOPLACE = json['TO_PLACE'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['PICTURE_ADDRESS'] = this.pICTUREADDRESS;
+    data['TO_PLACE'] = this.tOPLACE;
+    return data;
+  }
+}

+ 64 - 0
lib/model/hot_goods_model.dart

@@ -0,0 +1,64 @@
+class HotGoodsModel {
+  String code;
+  String message;
+  List<HotGoodsData> data;
+
+  HotGoodsModel({this.code, this.message, this.data});
+
+  HotGoodsModel.fromJson(Map<String, dynamic> json) {
+    code = json['code'];
+    message = json['message'];
+    if (json['data'] != null) {
+      data = new List<HotGoodsData>();
+      json['data'].forEach((v) {
+        data.add(new HotGoodsData.fromJson(v));
+      });
+    }
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['code'] = this.code;
+    data['message'] = this.message;
+    if (this.data != null) {
+      data['data'] = this.data.map((v) => v.toJson()).toList();
+    }
+    return data;
+  }
+}
+
+class HotGoodsData {
+  String name;
+  String image;
+  double mallPrice;
+  String goodsId;
+  double price;
+
+  HotGoodsData({this.name, this.image, this.mallPrice, this.goodsId, this.price});
+
+  HotGoodsData.fromJson(Map<String, dynamic> json) {
+    name = json['name'];
+    image = json['image'];
+    mallPrice = json['mallPrice'] + 0.0;
+    goodsId = json['goodsId'];
+    price = json['price'] + 0.0;
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['name'] = this.name;
+    data['image'] = this.image;
+    data['mallPrice'] = this.mallPrice;
+    data['goodsId'] = this.goodsId;
+    data['price'] = this.price;
+    return data;
+  }
+
+  static List<HotGoodsData> fromMapList(dynamic mapList) {
+    List<HotGoodsData> list = [];
+    mapList.forEach((map) {
+      list.add(HotGoodsData.fromJson(map));
+    });
+    return list;
+  }
+}

+ 41 - 0
lib/model/shopping_cart_model.dart

@@ -0,0 +1,41 @@
+class ShoppingCartModel {
+  String goodsName;
+  String goodsId;
+  String goodsImg;
+  double orgPrice;
+  double price;
+  int count;
+  bool isChecked;
+
+  ShoppingCartModel({this.goodsName, this.goodsId, this.goodsImg, this.orgPrice, this.price, this.count, this.isChecked});
+
+  ShoppingCartModel.fromJson(Map<String, dynamic> json) {
+    goodsName = json['goodsName'];
+    goodsId = json['goodsId'];
+    goodsImg = json['goodsImg'];
+    orgPrice = json['orgPrice'] + 0.0;
+    price = json['price'] + 0.0;
+    count = json['count'];
+    isChecked = json['isChecked'];
+  }
+
+  static List<ShoppingCartModel> fromJsonList(dynamic maps) {
+    List<ShoppingCartModel> list = List(maps.length);
+    for (int i = 0; i < maps.length; i++) {
+      list[i] = ShoppingCartModel.fromJson(maps[i]);
+    }
+    return list;
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['goodsName'] = this.goodsName;
+    data['goodsId'] = this.goodsId;
+    data['goodsImg'] = this.goodsImg;
+    data['orgPrice'] = this.orgPrice;
+    data['price'] = this.price;
+    data['count'] = this.count;
+    data['isChecked'] = this.isChecked;
+    return data;
+  }
+}

+ 23 - 0
lib/provide/cart_count_provide.dart

@@ -0,0 +1,23 @@
+import 'package:flutter/material.dart';
+
+/// 用于购物车的选择数量
+class CartCountProvide with ChangeNotifier {
+  int _count = 1;
+
+  int get shopCount => _count;
+
+  initCount() {
+    _count = 1; // 打开时候初始化
+    notifyListeners();
+  }
+
+  increase() {
+    _count += 1; // 增加按钮
+    notifyListeners();
+  }
+
+  decrease() {
+    _count -= 1; // 减少按钮
+    notifyListeners();
+  }
+}

+ 159 - 0
lib/provide/cart_provide.dart

@@ -0,0 +1,159 @@
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_note/model/goods_detail_model.dart';
+import 'package:flutter_note/model/shopping_cart_model.dart';
+import 'package:flutter_note/utils/preference_utils.dart';
+
+class CartProvide with ChangeNotifier {
+  bool _isAllChecked = false; // 是否全选
+  int _allSelectedCount = 0; // 选中的物品数量
+  int _allCartCount = 0; // 购物车内全部的物品数量
+  double _allSelectedPrice = 0.0; // 选中物品的全部价格
+  String _shopCartList = '[]'; // 用于持久化
+  List<ShoppingCartModel> _shopCarts = []; // 购物车物品列表
+
+  bool get allCheckedState => _isAllChecked;
+
+  int get allCartCount => _allCartCount;
+
+  int get allCheckedCount => _allSelectedCount;
+
+  double get allCheckedPrice => _allSelectedPrice;
+
+  List<ShoppingCartModel> get shopCarts => _shopCarts;
+
+  CartProvide() {
+    PreferenceUtils.instance.getString('shop_cart', '[]').then((value) {
+      _shopCartList = value;
+      _shopCarts.clear();
+      _shopCarts.addAll(_shopCartList == '[]'
+          ? []
+          : ShoppingCartModel.fromJsonList(json.decode(_shopCartList)));
+      _allInfoStateCheck();
+      notifyListeners();
+    });
+  }
+
+  /// 保存物品到购物车,可随意选择数量
+  saveCarts(GoodInfoBean info, int count) {
+    List<dynamic> carts =
+        _shopCartList == '[]' ? [] : json.decode(_shopCartList);
+
+    var included = false;
+
+    if (carts.isNotEmpty) {
+      carts.forEach((cart) {
+        // 不是空列表的情况下,判断是否已经存在该物品,存在则添加,并设置状态位
+        if (cart['goodsId'] == info.goodsId) {
+          cart['count'] += count;
+          included = true;
+        }
+      });
+    }
+
+    // 不存在该商品的时候则全部加入到列表
+    if (!included) {
+      carts.add({
+        'goodsName': info.goodsName,
+        'goodsId': info.goodsId,
+        'goodsImg': info.image1,
+        'orgPrice': info.oriPrice,
+        'price': info.presentPrice,
+        'count': count,
+        'isChecked': true,
+      });
+    }
+
+    _notifyChanges(carts);
+  }
+
+  /// 增加/减少商品数量
+  increaseOrReduceOperation(String goodsId, bool isIncrease) {
+    List<dynamic> carts = json.decode(_shopCartList);
+
+    // 已经存在的情况下才增加减少,修改数量值
+    carts.forEach((cart) {
+      if (cart['goodsId'] == goodsId) {
+        if (isIncrease) {
+          cart['count'] += 1;
+        } else {
+          cart['count'] -= 1;
+        }
+      }
+    });
+
+    _notifyChanges(carts);
+  }
+
+  /// 移除购物车内的某个商品
+  removeCarts(String goodsId) {
+    List<dynamic> carts =
+        _shopCartList == '[]' ? [] : json.decode(_shopCartList);
+
+    if (carts.isNotEmpty) {
+      carts.removeWhere((e) => e['goodsId'] == goodsId);
+    }
+
+    _notifyChanges(carts);
+  }
+
+  /// 修改特定商品在购物车的选中状态
+  changeCartState(String goodsId, bool checked) {
+    List<dynamic> carts =
+        _shopCartList == '[]' ? [] : json.decode(_shopCartList);
+
+    if (carts.isNotEmpty) {
+      carts.forEach((cart) {
+        if (cart['goodsId'] == goodsId) {
+          cart['isChecked'] = checked;
+        }
+      });
+    }
+
+    _notifyChanges(carts);
+  }
+
+  /// 全选状态修改
+  allCheckStateChange(bool checkState) {
+    List<dynamic> carts =
+        _shopCartList == '[]' ? [] : json.decode(_shopCartList);
+
+    if (carts.isNotEmpty) {
+      carts.forEach((cart) {
+        cart['isChecked'] = checkState; // 所有状态跟随全选修改
+      });
+    }
+
+    _notifyChanges(carts);
+  }
+
+  /// 更新购物车状态封装方法
+  _notifyChanges(List carts) {
+    PreferenceUtils.instance.saveString('shop_cart', json.encode(carts));
+    _shopCartList = json.encode(carts);
+    _shopCarts.clear();
+    _shopCarts
+        .addAll(carts.isEmpty ? [] : ShoppingCartModel.fromJsonList(carts));
+    _allInfoStateCheck();
+    notifyListeners();
+  }
+
+  /// 数量,全选状态修改封装
+  void _allInfoStateCheck() {
+    _allCartCount = 0;
+    _allSelectedCount = 0;
+    _allSelectedPrice = 0.0;
+    _isAllChecked = true;
+
+    _shopCarts.forEach((e) {
+      _allCartCount += e.count; // 全部数量
+      if (!e.isChecked) {
+        _isAllChecked = false; // 如果一个未选中,则全选为 false
+      } else {
+        _allSelectedCount += e.count;
+        _allSelectedPrice += e.count * e.price;
+      }
+    });
+  }
+}

+ 32 - 0
lib/provide/goods_detail_provide.dart

@@ -0,0 +1,32 @@
+import 'dart:convert';
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_note/config/service_url.dart';
+import 'package:flutter_note/model/goods_detail_model.dart';
+import 'package:flutter_note/service/service_method.dart';
+
+class GoodsDetailProvide with ChangeNotifier {
+  GoodsDetailModel _detail; // 商品详情
+  int _detailIndex; // 详情页的 tabIndex
+
+  GoodsDetailModel get detail => _detail;
+
+  int get detailIndex => _detailIndex;
+
+  changeDetails(String id) async {
+    _detail = await getGoodsDetail(id);
+    notifyListeners();
+  }
+
+  changeIndex(int index) {
+    _detailIndex = index;
+    notifyListeners();
+  }
+
+  Future<GoodsDetailModel> getGoodsDetail(String id) async {
+    var response = await request(servicePath['getGoodDetailById'],
+        formData: {'goodId': id});
+    return GoodsDetailModel.fromMap(json.decode(response.data));
+  }
+}

+ 74 - 0
lib/provide/home_provide.dart

@@ -0,0 +1,74 @@
+import 'dart:convert';
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_note/config/service_url.dart';
+import 'package:flutter_note/model/home_page_model.dart';
+import 'package:flutter_note/model/hot_goods_model.dart';
+import 'package:flutter_note/service/service_method.dart';
+
+class HomeProvide with ChangeNotifier {
+  HomePageModel _homeEntity; // 首页显示内容
+  List<HotGoodsData> _hotGoodsList = []; // 火爆专区
+  int _page = 0;
+  bool _showBack = false;
+  String _district = '定位失败';
+  double _longitude = 115.02932;
+  double _latitude = 35.76189;
+
+  HomePageModel get homeEntity => _homeEntity;
+
+  List<HotGoodsData> get hodGoodsList => _hotGoodsList;
+
+  bool get showBack => _showBack;
+
+  String get district => _district;
+
+  double get longitude => _longitude;
+
+  double get latitude => _latitude;
+
+  changeDistrict(String value, double longitude, double latitude) {
+    _district = value;
+    _longitude = longitude;
+    _latitude = latitude;
+    notifyListeners();
+  }
+
+  initHomeEntity(double lon, double lat) async {
+    _homeEntity = await _getHomePageContent(lon, lat);
+    notifyListeners();
+  }
+
+  initHotGoodsList() async {
+    _page = 0;
+    var hot = await _getHomePageHots(_page);
+    _hotGoodsList.clear();
+    _hotGoodsList.addAll(hot.data);
+    notifyListeners();
+  }
+
+  loadMoreHotGoods() async {
+    _page++;
+    var moreHot = await _getHomePageHots(_page);
+    _hotGoodsList.addAll(moreHot.data);
+    notifyListeners();
+  }
+
+  enableBack(bool state) {
+    _showBack = state;
+    notifyListeners();
+  }
+
+  Future<HomePageModel> _getHomePageContent(double lon, double lat) async {
+    var response = await request(servicePath['homePageContent'],
+        formData: {'lon': /*'115.02932'*/ lon, 'lat': /*'35.76189'*/ lat });
+    return HomePageModel.fromJson(json.decode(response.data.toString()));
+  }
+
+  Future<HotGoodsModel> _getHomePageHots(int page) async {
+    var response =
+        await request(servicePath['homePageHotPart'], formData: {'page': page});
+    return HotGoodsModel.fromJson(json.decode(response.data));
+  }
+}

+ 34 - 0
lib/provide/mall_goods_provide.dart

@@ -0,0 +1,34 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/model/category_goods_model.dart';
+
+/// 分类页面商品列表加载
+class MallGoodsProvide with ChangeNotifier {
+  var _page = 1;
+
+  List<CategoryGoodsInfo> _goodsList = [];
+
+  List<CategoryGoodsInfo> get goodList => _goodsList;
+
+  int get page => _page;
+
+  void increasePage() {
+    _page++;
+  }
+
+  void initialPage() {
+    _page = 1;
+  }
+
+  // 更换商品大小类别调用
+  void changeGoodsList(List<CategoryGoodsInfo> list) {
+    _goodsList.clear();
+    _goodsList.addAll(list);
+    notifyListeners();
+  }
+
+  // 上拉加载更多
+  void loadMoreGoodsList(List<CategoryGoodsInfo> list) {
+    _goodsList.addAll(list);
+    notifyListeners();
+  }
+}

+ 13 - 0
lib/provide/page_index_provide.dart

@@ -0,0 +1,13 @@
+import 'package:flutter/material.dart';
+
+/// 首页 tab 切换
+class PageIndexProvide with ChangeNotifier {
+  int _page = 0;
+
+  int get page => _page;
+
+  changePage(int page) {
+    _page = page;
+    notifyListeners();
+  }
+}

+ 59 - 0
lib/provide/sub_category_provide.dart

@@ -0,0 +1,59 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/model/category_model.dart';
+
+class SubCategoryProvide with ChangeNotifier {
+  // 商品列表
+  List<BxMallSubDtoListBean> _bxMallSubs = [];
+
+  // 大类 id
+  var _categoryId = '';
+
+  // 小类 id
+  var _subCategoryId = '';
+
+  // 当前选择的小类 item index
+  var _subIndex = 0;
+
+  List<BxMallSubDtoListBean> get subCategories => _bxMallSubs;
+
+  String get categoryId => _categoryId;
+
+  String get subCategoryId => _subCategoryId;
+
+  int get subIndex => _subIndex;
+
+  // 修改左侧栏
+  void changeLeftHeadCategories(List<BxMallSubDtoListBean> categories) {
+    BxMallSubDtoListBean allSubDto = BxMallSubDtoListBean()
+      ..mallCategoryId = ''
+      ..mallSubId = null
+      ..comments = ''
+      ..mallSubName = '全部';
+
+    _bxMallSubs.clear();
+    _bxMallSubs.add(allSubDto);
+    _bxMallSubs.addAll(categories);
+    _subCategoryId = '';
+    _subIndex = 0;
+
+    notifyListeners();
+  }
+
+  // 修改大类
+  void changeCategory(String categoryId) {
+    _categoryId = categoryId;
+    notifyListeners();
+  }
+
+  // 修改小类
+  void changeSubCategorySelect(String subCategoryId) {
+    _subCategoryId = subCategoryId;
+    notifyListeners();
+  }
+
+  // 小类 index
+  void changeSubCategoryIndex(int index) {
+    _subIndex = index;
+    notifyListeners();
+  }
+}

+ 7 - 0
lib/routers/application.dart

@@ -0,0 +1,7 @@
+import 'package:fluro/fluro.dart';
+//import 'package:jpush_flutter/jpush_flutter.dart';
+
+class Application {
+  static Router router;
+//  static JPush jPush;
+}

+ 16 - 0
lib/routers/router_handler.dart

@@ -0,0 +1,16 @@
+import 'package:fluro/fluro.dart';
+import '../views/index_page.dart';
+import '../views/map_page.dart';
+import '../views/deatilspage/details_page.dart';
+import '../views/settings_page.dart';
+
+Handler rootHandler = new Handler(handlerFunc: (_, params) => IndexPage());
+
+Handler detailHandler = new Handler(handlerFunc: (context, param) {
+  String goodsId = param['id']?.first;
+  return DetailsPage(goodsId: goodsId);
+});
+
+Handler mapHandler = new Handler(handlerFunc: (_, param) => MapPage());
+
+Handler settingHandler = new Handler(handlerFunc: (_, param) => SettingsPage());

+ 21 - 0
lib/routers/routers.dart

@@ -0,0 +1,21 @@
+import 'package:fluro/fluro.dart';
+import 'router_handler.dart';
+
+class Routers {
+  static String root = '/';
+  static String details = '/details';
+  static String map = '/map';
+  static String settings = '/settings';
+
+  static void configureRouters(Router router) {
+    router.notFoundHandler = Handler(handlerFunc: (_, params) {
+      print('not found');
+    });
+    router.define(root, handler: rootHandler);
+    router.define(details, handler: detailHandler);
+    router.define(map, handler: mapHandler);
+    router.define(settings, handler: settingHandler);
+  }
+
+  static String generateDetailsRouterPath(String id) => '$details?id=$id';
+}

+ 33 - 0
lib/service/service_method.dart

@@ -0,0 +1,33 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:dio/dio.dart';
+import '../config/service_url.dart';
+
+//获得火爆专区商品的方法
+Future<Response> getCategories() async => request(servicePath['getCategory']);
+//获得商城首页信息的方法
+Future<Response> getMallGoods(String categoryId, String categorySubId, int page) async=> request(servicePath['getMallGoods'],
+    formData:
+    categorySubId != null ? {'categoryId': categoryId, 'categorySubId': categorySubId, 'page': page} : {'categoryId': categoryId, 'page': page});
+
+Future<Response> request(String url, {Map formData}) async {
+  try {
+    Response response;
+    Dio dio = Dio();
+    dio.options.contentType = ContentType.parse('application/x-www-form-urlencoded');
+    if (formData == null) {
+      response = await dio.post(url);
+    } else {
+      response = await dio.post(url, data: formData);
+    }
+    if (response.statusCode == 200) {
+      return response;
+    } else {
+      throw Exception('后端接口出现异常,请检测代码和服务器情况.........');
+    }
+  } catch (e) {
+    print('ERROR: $e');
+    return null;
+  }
+}

+ 16 - 0
lib/shop_app.dart

@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/routers/application.dart';
+
+class ShopApp extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return new Container(
+      child: MaterialApp(
+        onGenerateRoute: Application.router.generator,
+        debugShowCheckedModeBanner: false,
+        title: 'Flutter Shop',
+        theme: ThemeData(primaryColor: Colors.pink),
+      ),
+    );
+  }
+}

+ 56 - 0
lib/utils/preference_utils.dart

@@ -0,0 +1,56 @@
+import 'package:shared_preferences/shared_preferences.dart';
+import 'dart:async';
+
+/// shared_preferences 管理类
+class PreferenceUtils {
+  static PreferenceUtils _instance;
+
+  static PreferenceUtils get instance => PreferenceUtils();
+
+  PreferenceUtils._internal();
+
+  factory PreferenceUtils() {
+    if (_instance == null) _instance = PreferenceUtils._internal();
+    return _instance;
+  }
+
+  saveInteger(String key, int value) => SharedPreferences.getInstance().then((sp) => sp.setInt(key, value));
+
+  saveString(String key, String value) => SharedPreferences.getInstance().then((sp) => sp.setString(key, value));
+
+  saveBool(String key, bool value) => SharedPreferences.getInstance().then((sp) => sp.setBool(key, value));
+
+  saveDouble(String key, double value) => SharedPreferences.getInstance().then((sp) => sp.setDouble(key, value));
+
+  saveStringList(String key, List<String> value) => SharedPreferences.getInstance().then((sp) => sp.setStringList(key, value));
+
+  Future<int> getInteger(String key, [int defaultValue = 0]) async {
+    var sp = await SharedPreferences.getInstance();
+    var value = sp.getInt(key);
+    return value ?? defaultValue;
+  }
+
+  Future<String> getString(String key, [String defaultValue = '']) async {
+    var sp = await SharedPreferences.getInstance();
+    var value = sp.getString(key);
+    return value ?? defaultValue;
+  }
+
+  Future<bool> getBool(String key, [bool defaultValue = false]) async {
+    var sp = await SharedPreferences.getInstance();
+    var value = sp.getBool(key);
+    return value ?? defaultValue;
+  }
+
+  Future<double> getDouble(String key, [double defaultValue = 0.0]) async {
+    var sp = await SharedPreferences.getInstance();
+    var value = sp.getDouble(key);
+    return value ?? defaultValue;
+  }
+
+  Future<List<String>> getStringList(String key, [List<String> defaultValue = const <String>[]]) async {
+    var sp = await SharedPreferences.getInstance();
+    var value = sp.getStringList(key);
+    return value ?? defaultValue;
+  }
+}

+ 56 - 0
lib/views/cartpage/bottom_summary.dart

@@ -0,0 +1,56 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/provide/cart_provide.dart';
+
+class BottomCartSummary extends StatelessWidget {
+  final CartProvide cartProvide;
+
+  BottomCartSummary({Key key, this.cartProvide}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
+      height: 60.0,
+      child:
+          Row(crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[
+        Checkbox(
+            value: cartProvide.allCheckedState,
+            onChanged: (checkState) {
+              cartProvide.allCheckStateChange(checkState);
+            },
+            activeColor: Colors.pink),
+        Text('全选', style: TextStyle(color: Colors.black, fontSize: 15.0)),
+        // 合计价格
+        Expanded(
+            child: Container(
+                padding: const EdgeInsets.symmetric(horizontal: 12.0),
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.end,
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: <Widget>[
+                    Row(
+                      mainAxisAlignment: MainAxisAlignment.end,
+                      children: <Widget>[
+                        Text('合计:',
+                            style:
+                                TextStyle(color: Colors.black, fontSize: 18.0)),
+                        Text('¥${cartProvide.allCheckedPrice}',
+                            style: TextStyle(
+                                color: Colors.red[700], fontSize: 16.0)),
+                      ],
+                    ),
+                    Text('满10元免费配送,预购免费配送',
+                        style: TextStyle(color: Colors.black, fontSize: 10.0))
+                  ],
+                ))),
+        // 结算按钮
+        RaisedButton(
+          onPressed: () {},
+          child: Text('结算(${cartProvide.allCheckedCount})',
+              style: TextStyle(color: Colors.white)),
+          color: Colors.pink,
+        )
+      ]),
+    );
+  }
+}

+ 66 - 0
lib/views/cartpage/cart_count.dart

@@ -0,0 +1,66 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/provide/cart_provide.dart';
+
+class CartCountWidget extends StatelessWidget {
+  final int count;
+  final String goodsId;
+  final CartProvide cartProvide;
+
+  CartCountWidget({Key key, this.count, this.goodsId, this.cartProvide})
+      : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      width: 120.0,
+      height: 30.0,
+      decoration: ShapeDecoration(
+        shape: RoundedRectangleBorder(
+            borderRadius: BorderRadius.all(Radius.circular(2.0)),
+            side: BorderSide(color: Colors.black54)),
+      ),
+      child: Row(
+        crossAxisAlignment: CrossAxisAlignment.center,
+        children: <Widget>[
+          // 减值操作,数量为 1 停止
+          Expanded(
+            child: InkWell(
+              onTap: count == 1
+                  ? null
+                  : () => cartProvide.increaseOrReduceOperation(goodsId, false),
+              child: DecoratedBox(
+                  decoration: BoxDecoration(
+                    border: Border(
+                        right: BorderSide(color: Colors.black54, width: 1.0)),
+                  ),
+                  child: Center(
+                      child: Text('-',
+                          style:
+                              TextStyle(fontSize: 16.0, color: Colors.black)))),
+            ),
+          ),
+          Expanded(
+              child: Center(
+                  child: Text('$count',
+                      style: TextStyle(fontSize: 14.0, color: Colors.black))),
+              flex: 2),
+          // 加值操作
+          Expanded(
+            child: InkWell(
+              onTap: () => cartProvide.increaseOrReduceOperation(goodsId, true),
+              child: DecoratedBox(
+                  decoration: BoxDecoration(
+                    border: Border(
+                        left: BorderSide(color: Colors.black54, width: 1.0)),
+                  ),
+                  child: Center(
+                      child: Text('+',
+                          style:
+                              TextStyle(fontSize: 16.0, color: Colors.black)))),
+            ),
+          )
+        ],
+      ),
+    );
+  }
+}

+ 27 - 0
lib/views/cartpage/cart_page.dart

@@ -0,0 +1,27 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_note/views/cartpage/bottom_summary.dart';
+import 'package:flutter_note/views/cartpage/empty_cart.dart';
+import 'package:flutter_note/views/cartpage/shopping_cart_list.dart';
+import 'package:flutter_note/provide/cart_provide.dart';
+import 'package:provide/provide.dart';
+
+class CartPage extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return Provide<CartProvide>(
+        builder: (_, child, cartProvide) => Scaffold(
+              appBar: AppBar(title: Text('购物车'), centerTitle: true),
+              body: cartProvide.shopCarts.isEmpty
+                  // 购物车为空情况
+                  ? EmptyShoppingCart()
+                  // 购物车非空情况
+                  : ShoppingCartList(cartProvide: cartProvide),
+              bottomNavigationBar: cartProvide.shopCarts.isEmpty
+                  ? null
+                  : BottomAppBar(
+                      child: BottomCartSummary(cartProvide: cartProvide),
+                    ),
+            ));
+  }
+}

+ 36 - 0
lib/views/cartpage/empty_cart.dart

@@ -0,0 +1,36 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_note/provide/page_index_provide.dart';
+import 'package:provide/provide.dart';
+
+class EmptyShoppingCart extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      alignment: Alignment.center,
+      child: Column(
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: <Widget>[
+          DecoratedBox(
+              decoration:
+                  ShapeDecoration(shape: CircleBorder(), color: Colors.black12),
+              child: Padding(
+                padding: const EdgeInsets.all(8.0),
+                child: Icon(CupertinoIcons.shopping_cart,
+                    size: 50.0, color: Colors.white),
+              )),
+          Padding(
+            padding: const EdgeInsets.symmetric(vertical: 4.0),
+            child: Text('购物车还空着,快去挑选商品吧~',
+                style: TextStyle(fontSize: 12.0, color: Colors.black26)),
+          ),
+          RaisedButton(
+              onPressed: () =>
+                  Provide.value<PageIndexProvide>(context).changePage(0),
+              child: Text('随便逛逛', style: TextStyle(color: Colors.white)),
+              color: Colors.pink)
+        ],
+      ),
+    );
+  }
+}

+ 131 - 0
lib/views/cartpage/shopping_cart_list.dart

@@ -0,0 +1,131 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_note/model/shopping_cart_model.dart';
+import 'package:flutter_note/views/cartpage/cart_count.dart';
+import 'package:flutter_note/provide/cart_provide.dart';
+
+class ShoppingCartList extends StatelessWidget {
+  final CartProvide cartProvide;
+
+  ShoppingCartList({Key key, this.cartProvide}) : super(key: key);
+
+  /// 列表小计
+  Widget _cartSummaryItem() {
+    return Container(
+      color: Colors.white,
+      padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: <Widget>[
+          Text(
+            '共${cartProvide.allCheckedCount}件商品',
+            style: TextStyle(color: Colors.black),
+          ),
+          Text(
+            '小计:¥${cartProvide.allCheckedPrice}',
+            style: TextStyle(color: Colors.red[700]),
+          )
+        ],
+      ),
+    );
+  }
+
+  /// 前置部分,checkbox image
+  Widget _leadingPart(ShoppingCartModel entity) {
+    return Row(
+      children: <Widget>[
+        Checkbox(
+            value: entity.isChecked,
+            onChanged: (checkState) {
+              // 修改商品选择状态
+              cartProvide.changeCartState(entity.goodsId, checkState);
+            },
+            activeColor: Colors.pink),
+        // 商品图标
+        DecoratedBox(
+          decoration: ShapeDecoration(
+              shape: RoundedRectangleBorder(), color: Colors.black12),
+          child: Padding(
+            padding: const EdgeInsets.all(1.0),
+            child: Image.network(entity.goodsImg, height: 80.0, width: 80.0),
+          ),
+        )
+      ],
+    );
+  }
+
+  /// 中间部分,商品名 计数器
+  Widget _middlePart(ShoppingCartModel entity) {
+    return Expanded(
+      child: Container(
+        height: 80.0, // 该部件同图片同高
+        padding: const EdgeInsets.symmetric(horizontal: 8.0),
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: <Widget>[
+            Text(
+              entity.goodsName,
+              style: TextStyle(color: Colors.black, fontSize: 16.0),
+              maxLines: 1,
+              overflow: TextOverflow.ellipsis,
+            ),
+            // 数量管理器
+            CartCountWidget(
+              count: entity.count,
+              goodsId: entity.goodsId,
+              cartProvide: cartProvide,
+            )
+          ],
+        ),
+      ),
+    );
+  }
+
+  /// 尾部价格部分
+  Widget _trailingPart(ShoppingCartModel entity) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.end,
+      children: <Widget>[
+        Text(
+          '¥${(entity.count * entity.price).toStringAsFixed(2)}',
+          style: TextStyle(color: Colors.black, fontSize: 16.0),
+        ),
+        Text(
+          '¥${(entity.count * entity.orgPrice).toStringAsFixed(2)}',
+          style: TextStyle(
+              color: Colors.black54,
+              fontSize: 14.0,
+              decoration: TextDecoration.lineThrough),
+        ),
+        InkWell(
+            child: Icon(CupertinoIcons.delete, size: 32.0),
+            onTap: () {
+              cartProvide.removeCarts(entity.goodsId);
+            })
+      ],
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ListView.separated(
+      itemBuilder: (_, index) => index == cartProvide.shopCarts.length
+          ? _cartSummaryItem()
+          : Container(
+              color: Colors.white,
+              padding: const EdgeInsets.all(12.0),
+              child: Row(
+                children: <Widget>[
+                  _leadingPart(cartProvide.shopCarts[index]),
+                  _middlePart(cartProvide.shopCarts[index]),
+                  _trailingPart(cartProvide.shopCarts[index])
+                ],
+              ),
+            ),
+      separatorBuilder: (_, index) =>
+          Divider(height: 1.0, color: Colors.black26),
+      itemCount: cartProvide.shopCarts.length + 1,
+    );
+  }
+}

+ 258 - 0
lib/views/category_page.dart

@@ -0,0 +1,258 @@
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_easyrefresh/ball_pulse_footer.dart';
+import 'package:flutter_easyrefresh/ball_pulse_header.dart';
+import 'package:flutter_easyrefresh/easy_refresh.dart';
+import 'package:flutter_note/routers/application.dart';
+import 'package:flutter_note/model/category_model.dart';
+import 'package:flutter_note/model/category_goods_model.dart';
+import 'package:flutter_note/provide/mall_goods_provide.dart';
+import 'package:flutter_note/provide/sub_category_provide.dart';
+import 'package:flutter_note/routers/routers.dart';
+import 'package:flutter_note/service/service_method.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:provide/provide.dart';
+
+class CategoryPage extends StatefulWidget {
+  @override
+  _CategoryPageState createState() => _CategoryPageState();
+}
+
+class _CategoryPageState extends State<CategoryPage> {
+  List<CategoryData> categories = <CategoryData>[];
+  GlobalKey<EasyRefreshState> _refreshKey = GlobalKey();
+  GlobalKey<RefreshHeaderState> _headerKey = GlobalKey();
+  GlobalKey<RefreshFooterState> _footerKey = GlobalKey();
+  ScrollController _gridController = ScrollController();
+  ScrollController _topNavController = ScrollController();
+  int selectPosition = 0;
+
+  @override
+  void initState() {
+    super.initState();
+    _requestCategories();
+  }
+
+  @override
+  void dispose() {
+    _gridController.dispose();
+    _topNavController.dispose();
+    super.dispose();
+  }
+
+  void _requestCategories() {
+    getCategories().then((response) {
+      setState(() {
+        categories
+            .addAll(CategoryModel.fromMap(json.decode(response.data)).data);
+        // 默认初始值列表
+        Provide.value<SubCategoryProvide>(context)
+            .changeLeftHeadCategories(categories[0].bxMallSubDto);
+        Provide.value<SubCategoryProvide>(context)
+            .changeCategory(categories[0].mallCategoryId);
+        _requestGoodsList();
+      });
+    });
+  }
+
+  // 获取右侧标签下的商品列表
+  void _requestGoodsList() {
+    getMallGoods(
+            Provide.value<SubCategoryProvide>(context).categoryId,
+            Provide.value<SubCategoryProvide>(context).subCategoryId,
+            Provide.value<MallGoodsProvide>(context).page)
+        .then((response) {
+      Map<String, dynamic> jsonFormat = json.decode(response.data);
+      // 返回有数据才解析
+      if (jsonFormat['data'] != null) {
+        CategoryGoodsModel goods = CategoryGoodsModel.fromMap(jsonFormat);
+        if (Provide.value<MallGoodsProvide>(context).page == 1) {
+          Provide.value<MallGoodsProvide>(context).changeGoodsList(goods.data);
+        } else {
+          Provide.value<MallGoodsProvide>(context)
+              .loadMoreGoodsList(goods.data);
+        }
+        Provide.value<MallGoodsProvide>(context).increasePage();
+      } else {
+        // 无数据返回情况
+        if (Provide.value<MallGoodsProvide>(context).page == 1)
+          Provide.value<MallGoodsProvide>(context).changeGoodsList([]);
+        else {
+          Fluttertoast.showToast(msg: '没有更多啦~');
+          Provide.value<MallGoodsProvide>(context).loadMoreGoodsList([]);
+        }
+      }
+    });
+  }
+
+  // 左侧大类导航列表 item
+  InkWell _leftCategoryItem(int index, BuildContext context) {
+    return InkWell(
+      onTap: () {
+        setState(() => selectPosition = index);
+        Provide.value<SubCategoryProvide>(context)
+            .changeLeftHeadCategories(categories[index].bxMallSubDto);
+        Provide.value<SubCategoryProvide>(context)
+            .changeCategory(categories[index].mallCategoryId);
+        Provide.value<MallGoodsProvide>(context).initialPage();
+        _requestGoodsList();
+        _gridController.animateTo(0,
+            duration: Duration(milliseconds: 500), curve: Curves.decelerate);
+        _topNavController.animateTo(0,
+            duration: Duration(milliseconds: 300), curve: Curves.decelerate);
+      },
+      child: Container(
+        color: index == selectPosition ? Colors.black12 : Colors.white,
+        height: 60.0,
+        child: Text(categories[index].mallCategoryName,
+            style: TextStyle(fontSize: 15.0, color: Colors.black)),
+        alignment: Alignment.centerLeft,
+        padding: const EdgeInsets.symmetric(horizontal: 8.0),
+      ),
+    );
+  }
+
+  // 右侧头部导航列表 item
+  Widget _subCategoryNav(int index, BxMallSubDtoListBean subDto) {
+    return InkWell(
+        onTap: () {
+          Provide.value<SubCategoryProvide>(context)
+              .changeSubCategorySelect(subDto.mallSubId);
+          Provide.value<SubCategoryProvide>(context)
+              .changeSubCategoryIndex(index);
+          Provide.value<MallGoodsProvide>(context).initialPage();
+          _requestGoodsList();
+          _gridController.animateTo(0,
+              duration: Duration(milliseconds: 500), curve: Curves.decelerate);
+        },
+        child: Container(
+          alignment: Alignment.center,
+          padding: const EdgeInsets.symmetric(horizontal: 8.0),
+          child: Text(
+            subDto.mallSubName,
+            style: TextStyle(
+                color:
+                    index == Provide.value<SubCategoryProvide>(context).subIndex
+                        ? Colors.pink
+                        : Colors.black),
+          ),
+        ));
+  }
+
+  // 右侧商品列表 item
+  Widget _goodsItem(CategoryGoodsInfo info, BuildContext context) {
+    return InkWell(
+      onTap: () => Application.router
+          .navigateTo(context, Routers.generateDetailsRouterPath(info.goodsId)),
+      child: Container(
+        margin: const EdgeInsets.all(2.0),
+        alignment: Alignment.center,
+        color: Colors.white,
+        child: Column(
+          children: <Widget>[
+            Image.network(info.image,
+                width: MediaQuery.of(context).size.width * 0.4,
+                height: MediaQuery.of(context).size.width * 0.4),
+            Text('${info.goodsName}',
+                style: TextStyle(fontSize: 14.0, color: Colors.black),
+                overflow: TextOverflow.ellipsis),
+            Row(
+                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                crossAxisAlignment: CrossAxisAlignment.end,
+                children: <Widget>[
+                  Text('¥${info.presentPrice}',
+                      style: TextStyle(fontSize: 14.0)),
+                  Text('¥${info.oriPrice}',
+                      style: TextStyle(
+                          color: Colors.black26,
+                          decoration: TextDecoration.lineThrough,
+                          fontSize: 12.0))
+                ])
+          ],
+        ),
+      ),
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(title: Text('商品分类'), centerTitle: true),
+      body: Row(children: <Widget>[
+        // 左侧栏
+        Container(
+          width: 100.0,
+          child: ListView.separated(
+              itemBuilder: (context, index) =>
+                  _leftCategoryItem(index, context),
+              separatorBuilder: (context, index) =>
+                  Divider(height: 1.0, color: Colors.black12),
+              itemCount: categories.length),
+        ),
+        // 分割线
+        VerticalDivider(width: 1.0, color: Colors.black12),
+        // 右侧栏
+        Expanded(
+            child: Column(
+          children: <Widget>[
+            // 头部导航
+            Provide<SubCategoryProvide>(
+              builder: (_, child, subCategories) => Container(
+                    color: Colors.white,
+                    height: 50.0,
+                    child: ListView.builder(
+                      controller: _topNavController,
+                      scrollDirection: Axis.horizontal,
+                      itemBuilder: (_, index) => _subCategoryNav(
+                          index, subCategories.subCategories[index]),
+                      itemCount: subCategories.subCategories.length,
+                    ),
+                  ),
+            ),
+            Divider(height: 1.0, color: Colors.black12),
+            // 物品展示
+            Expanded(
+              child: Provide<MallGoodsProvide>(
+                builder: (context, widget, goodsProvide) =>
+                    goodsProvide.goodList.isEmpty
+                        // 当前商品分类无商品情况
+                        ? Center(
+                            child: Column(
+                                mainAxisAlignment: MainAxisAlignment.center,
+                                children: <Widget>[
+                                  Image.asset('images/empty.png',
+                                      width: 60.0, height: 60.0),
+                                  Text('啊哦...目前未找到该分类下的商品'),
+                                ]),
+                          )
+                        // 当前商品列表下有数据情况
+                        : EasyRefresh(
+                            key: _refreshKey,
+                            refreshHeader: BallPulseHeader(
+                                key: _headerKey, color: Colors.pink),
+                            refreshFooter: BallPulseFooter(
+                                key: _footerKey, color: Colors.pink),
+                            loadMore: () {
+                              _requestGoodsList();
+                            },
+                            child: GridView.builder(
+                                controller: _gridController,
+                                itemCount: goodsProvide.goodList.length,
+                                gridDelegate:
+                                    SliverGridDelegateWithFixedCrossAxisCount(
+                                        crossAxisCount: 2,
+                                        childAspectRatio: 2 / 3,
+                                        mainAxisSpacing: 1.0,
+                                        crossAxisSpacing: 1.0),
+                                itemBuilder: (_, index) => _goodsItem(
+                                    goodsProvide.goodList[index], context)),
+                          ),
+              ),
+            )
+          ],
+        ))
+      ]),
+    );
+  }
+}

+ 61 - 0
lib/views/deatilspage/details_page.dart

@@ -0,0 +1,61 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_note/views/deatilspage/goods_comments.dart';
+import 'package:flutter_note/views/deatilspage/goods_detail.dart';
+import 'package:flutter_note/views/deatilspage/goods_handler.dart';
+import 'package:flutter_note/views/deatilspage/sliver_header_bar.dart';
+import 'package:flutter_note/provide/goods_detail_provide.dart';
+import 'package:provide/provide.dart';
+
+class DetailsPage extends StatelessWidget {
+  final String goodsId;
+  final _tabs = ['详情', '评论'];
+
+  DetailsPage({Key key, this.goodsId}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    Provide.value<GoodsDetailProvide>(context)
+      ..changeDetails(goodsId)
+      ..changeIndex(0);
+
+    return Provide<GoodsDetailProvide>(builder: (_, widget, detailProvide) {
+      var _detail = detailProvide.detail;
+
+      return Scaffold(
+        body: Container(
+          alignment: Alignment.center,
+          child: _detail == null ||
+                  _detail.data == null ||
+                  _detail.data.goodInfo == null
+              ? CupertinoActivityIndicator(radius: 12.0) // 无商品情况使用加载
+              // 使用横向滑动列表展示不同页面
+              : DefaultTabController(
+                  length: _tabs.length,
+                  child: NestedScrollView(
+                    headerSliverBuilder: (context, innerScrolled) => [
+                          SliverOverlapAbsorber(
+                            handle:
+                                NestedScrollView.sliverOverlapAbsorberHandleFor(
+                                    context),
+                            child: SliverHeaderBar(
+                                detailProvide: detailProvide,
+                                tabs: _tabs,
+                                innerScrolled: innerScrolled),
+                          )
+                        ],
+                    // 详情页面和评论页面列表
+                    body: TabBarView(
+                      children: [
+                        GoodsDetail(detailProvide: detailProvide),
+                        GoodsComments(detailProvide: detailProvide)
+                      ],
+                    ),
+                  ),
+                ),
+        ),
+        bottomNavigationBar: GoodsHandler(detailProvide: detailProvide),
+      );
+    });
+  }
+}

+ 54 - 0
lib/views/deatilspage/goods_comments.dart

@@ -0,0 +1,54 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/provide/goods_detail_provide.dart';
+
+class GoodsComments extends StatelessWidget {
+  final GoodsDetailProvide detailProvide;
+
+  GoodsComments({Key key, this.detailProvide}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    var _detail = detailProvide.detail.data;
+
+    return Builder(builder: (ctx) {
+      return CustomScrollView(
+        slivers: <Widget>[
+          SliverOverlapInjector(
+              handle: NestedScrollView.sliverOverlapAbsorberHandleFor(ctx)),
+          _detail.goodComments.isEmpty
+              // 无评论
+              ? SliverToBoxAdapter(
+                  child: Container(
+                      alignment: Alignment.center,
+                      height: 60.0,
+                      child: Text('暂时没有评论哦~')))
+              // 评论列表
+              : SliverFixedExtentList(
+                  delegate: SliverChildBuilderDelegate(
+                      (_, index) => Container(
+                            color: Colors.white,
+                            padding: const EdgeInsets.only(left: 12.0),
+                            child: Column(
+                              mainAxisAlignment: MainAxisAlignment.center,
+                              crossAxisAlignment: CrossAxisAlignment.start,
+                              children: <Widget>[
+                                Text(
+                                    '${_detail.goodComments[index].userName}'), // 评论者昵称
+                                Text(
+                                    '${_detail.goodComments[index].comments}'), // 评论信息
+                                Text(
+                                    '${DateTime.fromMillisecondsSinceEpoch(_detail.goodComments[index].discussTime)}'
+                                        .split('.')
+                                        .first), // 评论时间
+                              ],
+                            ),
+                          ),
+                      childCount: _detail.goodComments.length),
+                  itemExtent: 80.0),
+          SliverToBoxAdapter(
+              child: Image.network(_detail.advertesPicture.PICTURE_ADDRESS))
+        ],
+      );
+    });
+  }
+}

+ 28 - 0
lib/views/deatilspage/goods_detail.dart

@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_html/flutter_html.dart';
+import 'package:flutter_note/provide/goods_detail_provide.dart';
+
+class GoodsDetail extends StatelessWidget {
+  final GoodsDetailProvide detailProvide;
+
+  GoodsDetail({Key key, this.detailProvide}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Builder(builder: (ctx) {
+      var _detail = detailProvide.detail.data;
+
+      return CustomScrollView(
+        slivers: <Widget>[
+          SliverOverlapInjector(
+              handle: NestedScrollView.sliverOverlapAbsorberHandleFor(ctx)),
+          // H5 详情
+          SliverToBoxAdapter(child: Html(data: _detail.goodInfo.goodsDetail)),
+          // 广告条
+          SliverToBoxAdapter(
+              child: Image.network(_detail.advertesPicture.PICTURE_ADDRESS))
+        ],
+      );
+    });
+  }
+}

+ 173 - 0
lib/views/deatilspage/goods_handler.dart

@@ -0,0 +1,173 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_note/provide/cart_count_provide.dart';
+import 'package:flutter_note/provide/cart_provide.dart';
+import 'package:flutter_note/provide/goods_detail_provide.dart';
+import 'package:flutter_note/provide/page_index_provide.dart';
+import 'package:provide/provide.dart';
+
+class GoodsHandler extends StatelessWidget {
+  final GoodsDetailProvide detailProvide;
+
+  GoodsHandler({Key key, this.detailProvide}) : super(key: key);
+
+  Widget _countOperator(CartCountProvide cartCount) {
+    return Row(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      children: <Widget>[
+        Expanded(
+          child: InkWell(
+            onTap:
+                cartCount.shopCount == 1 ? () {} : () => cartCount.decrease(),
+            child: DecoratedBox(
+                decoration: BoxDecoration(
+                  border: Border(
+                      right: BorderSide(color: Colors.black54, width: 1.0)),
+                ),
+                child: Center(
+                    child: Text('-',
+                        style:
+                            TextStyle(fontSize: 16.0, color: Colors.black)))),
+          ),
+        ),
+        Expanded(
+            child: Center(
+                child: Text('${cartCount.shopCount}',
+                    style: TextStyle(fontSize: 14.0, color: Colors.black))),
+            flex: 2),
+        Expanded(
+          child: InkWell(
+            onTap: () => cartCount.increase(),
+            child: DecoratedBox(
+                decoration: BoxDecoration(
+                  border: Border(
+                      left: BorderSide(color: Colors.black54, width: 1.0)),
+                ),
+                child: Center(
+                    child: Text('+',
+                        style:
+                            TextStyle(fontSize: 16.0, color: Colors.black)))),
+          ),
+        )
+      ],
+    );
+  }
+
+  _countModalSheet(BuildContext ctx) {
+    Provide.value<CartCountProvide>(ctx).initCount(); // 购买数量初始化为 1
+    showModalBottomSheet(
+      context: ctx,
+      builder: (context) =>
+          Provide<CartCountProvide>(builder: (_, child, cartCount) {
+            return Container(
+              padding:
+                  const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
+              height: 100.0,
+              color: Colors.white,
+              child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                children: <Widget>[
+                  Text('购买数量',
+                      style: TextStyle(color: Colors.black, fontSize: 12.0)),
+                  Row(children: <Widget>[
+                    Container(
+                      width: 120.0,
+                      height: 30.0,
+                      decoration: ShapeDecoration(
+                        shape: RoundedRectangleBorder(
+                          borderRadius: BorderRadius.all(Radius.circular(2.0)),
+                          side: BorderSide(color: Colors.black54),
+                        ),
+                      ),
+                      child: _countOperator(cartCount),
+                    ),
+
+                    // 加入购物车按钮
+                    Padding(
+                      padding: const EdgeInsets.only(left: 30.0),
+                      child: OutlineButton(
+                          child: Text('确定加入购物车'),
+                          onPressed: () {
+                            Provide.value<CartProvide>(context).saveCarts(
+                                detailProvide.detail.data.goodInfo,
+                                cartCount.shopCount);
+                            Navigator.pop(context);
+                          }),
+                    )
+                  ])
+                ],
+              ),
+            );
+          }),
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return BottomAppBar(
+      child: Container(
+        height: 60.0,
+        child: Card(
+          margin: const EdgeInsets.all(0.0),
+          child: Row(children: <Widget>[
+            // 购物车按钮
+            Stack(
+              alignment: Alignment.topRight,
+              children: <Widget>[
+                IconButton(
+                    icon: Icon(CupertinoIcons.shopping_cart,
+                        size: 32.0, color: Colors.pink),
+                    onPressed: () {
+                      Navigator.pop(context);
+                      Provide.value<PageIndexProvide>(context).changePage(2);
+                    }),
+                Provide<CartProvide>(
+                  builder: (_, child, carts) => DecoratedBox(
+                        decoration: BoxDecoration(
+                          color: Colors.pink,
+                          borderRadius: BorderRadius.all(Radius.circular(12.0)),
+                        ),
+                        child: Padding(
+                          padding: const EdgeInsets.only(
+                              top: 2.0, bottom: 2.0, left: 4.0, right: 4.0),
+                          child: Text('${carts.allCartCount}',
+                              style: TextStyle(color: Colors.white)),
+                        ),
+                      ),
+                )
+              ],
+            ),
+            // 加入购物车
+            Expanded(
+              child: Builder(
+                builder: (ctx) => InkWell(
+                      child: Container(
+                          color: Colors.green,
+                          alignment: Alignment.center,
+                          child: Text('加入购物车',
+                              style: TextStyle(
+                                  color: Colors.white, fontSize: 18.0))),
+                      onTap: () {
+                        _countModalSheet(ctx);
+                      },
+                    ),
+              ),
+            ),
+            // 立即购买
+            Expanded(
+              child: InkWell(
+                  child: Container(
+                    color: Colors.red,
+                    alignment: Alignment.center,
+                    child: Text('立即购买',
+                        style: TextStyle(color: Colors.white, fontSize: 18.0)),
+                  ),
+                  onTap: () {}),
+            )
+          ]),
+        ),
+      ),
+    );
+  }
+}

+ 129 - 0
lib/views/deatilspage/sliver_header_bar.dart

@@ -0,0 +1,129 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/provide/goods_detail_provide.dart';
+
+class SliverHeaderBar extends StatelessWidget {
+  final GoodsDetailProvide detailProvide;
+  final List<String> tabs;
+  final bool innerScrolled;
+  final double _expandedHeight = 560.0;
+
+  SliverHeaderBar({Key key, this.detailProvide, this.tabs, this.innerScrolled})
+      : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    var _detail = detailProvide.detail;
+    return SliverAppBar(
+      pinned: true,
+      centerTitle: true,
+      // 商品名
+      title: Text(
+        _detail.data.goodInfo.goodsName,
+        maxLines: 1,
+        overflow: TextOverflow.ellipsis,
+      ),
+      forceElevated: innerScrolled,
+      // 折叠头部信息
+      flexibleSpace: HeaderFlex(
+          detailProvide: detailProvide, expandedHeight: _expandedHeight),
+      // 折叠高度
+      expandedHeight: _expandedHeight,
+      bottom: TabBar(
+          indicator: BoxDecoration(color: Colors.transparent),
+          labelColor: Colors.pink,
+          indicatorWeight: .0,
+          indicatorColor: Colors.pink,
+          indicatorSize: TabBarIndicatorSize.label,
+          unselectedLabelColor: Colors.black,
+          labelPadding: EdgeInsets.zero,
+          tabs: tabs
+              .map((tab) => Container(
+                    height: 60.0,
+                    color: Colors.white,
+                    alignment: Alignment.center,
+                    child: Text(tab, style: TextStyle(fontSize: 18.0)),
+                  ))
+              .toList()),
+    );
+  }
+}
+
+class HeaderFlex extends StatelessWidget {
+  final GoodsDetailProvide detailProvide;
+  final double expandedHeight;
+
+  HeaderFlex({Key key, this.detailProvide, this.expandedHeight})
+      : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    var _detail = detailProvide.detail.data;
+
+    return FlexibleSpaceBar(
+      collapseMode: CollapseMode.pin,
+      background: Container(
+        alignment: Alignment.center,
+        color: Colors.white,
+        height: expandedHeight,
+        child: Column(
+          children: <Widget>[
+            Image.network(_detail.goodInfo.image1, height: 340), // 图片
+            Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: <Widget>[
+                // 商品名
+                Padding(
+                  padding:
+                      const EdgeInsets.only(top: 20.0, left: 12.0, right: 12.0),
+                  child: Text(
+                    _detail.goodInfo.goodsName,
+                    style: TextStyle(fontSize: 18.0, color: Colors.black),
+                  ),
+                ),
+                // 商品编号
+                Padding(
+                  padding:
+                      const EdgeInsets.only(top: 12.0, left: 12.0, right: 12.0),
+                  child: Text('编号:${_detail.goodInfo.goodsSerialNumber}'),
+                ),
+                // 商品价格
+                Padding(
+                  padding:
+                      const EdgeInsets.only(top: 8.0, left: 12.0, right: 12.0),
+                  child: Row(
+                      crossAxisAlignment: CrossAxisAlignment.end,
+                      children: <Widget>[
+                        Text('¥${_detail.goodInfo.presentPrice}',
+                            style:
+                                TextStyle(fontSize: 16.0, color: Colors.red)),
+                        Padding(
+                            padding: const EdgeInsets.only(left: 16.0),
+                            child: Text('市场价:',
+                                style: TextStyle(color: Colors.black))),
+                        Text('¥${_detail.goodInfo.oriPrice}',
+                            style: TextStyle(
+                                decoration: TextDecoration.lineThrough,
+                                color: Colors.black26)),
+                      ]),
+                ),
+                Container(
+                  height: 8.0,
+                  color: Colors.black12,
+                  margin: const EdgeInsets.only(top: 4.0),
+                ),
+                Container(
+                  alignment: Alignment.centerLeft,
+                  padding: const EdgeInsets.all(12.0),
+                  child: Text('说明:>急速送达 >正品保证',
+                      style: TextStyle(fontSize: 16.0, color: Colors.red)),
+                ),
+                Container(height: 8.0, color: Colors.black12)
+              ],
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 12 - 0
lib/views/homepage/ad_banner.dart

@@ -0,0 +1,12 @@
+import 'package:flutter/material.dart';
+
+class AdBanner extends StatelessWidget {
+  final String bannerUrl;
+
+  AdBanner({Key key, @required this.bannerUrl}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return SliverToBoxAdapter(child: Image.network(bannerUrl));
+  }
+}

+ 33 - 0
lib/views/homepage/banner_diy.dart

@@ -0,0 +1,33 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/routers/application.dart';
+import 'package:flutter_note/model/home_page_model.dart';
+import 'package:flutter_note/routers/routers.dart';
+import 'package:flutter_swiper/flutter_swiper.dart';
+
+class BannerDiy extends StatelessWidget {
+  final List<Slides> bannerImages;
+
+  BannerDiy({Key key, @required this.bannerImages}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return SliverToBoxAdapter(
+      child: Container(
+        height: 180.0,
+        child: Swiper(
+          itemCount: bannerImages.length,
+          itemBuilder: (context, int index) => InkWell(
+                child: Image.network('${bannerImages[index].image}',
+                    fit: BoxFit.fill),
+                onTap: () => Application.router.navigateTo(
+                    context,
+                    Routers.generateDetailsRouterPath(
+                        bannerImages[index].goodsId)),
+              ),
+          pagination: SwiperPagination(),
+          autoplay: true,
+        ),
+      ),
+    );
+  }
+}

+ 59 - 0
lib/views/homepage/floor_part.dart

@@ -0,0 +1,59 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/routers/application.dart';
+import 'package:flutter_note/model/home_page_model.dart';
+import 'package:flutter_note/routers/routers.dart';
+
+class FloorTitle extends StatelessWidget {
+  final String floorPic;
+
+  FloorTitle({Key key, @required this.floorPic}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return SliverToBoxAdapter(
+        child: Container(
+            child: Image.network(floorPic),
+            padding: const EdgeInsets.symmetric(vertical: 12.0)));
+  }
+}
+
+class FloorContent extends StatelessWidget {
+  final List<Floor> floorContent;
+
+  FloorContent({Key key, @required this.floorContent}) : super(key: key);
+
+  Widget _goodsImg(Floor floorItem, context) {
+    return InkWell(
+        child: Image.network(floorItem.image,
+            width: MediaQuery.of(context).size.width / 2),
+        onTap: () => Application.router.navigateTo(
+            context, Routers.generateDetailsRouterPath(floorItem.goodsId)));
+  }
+
+  Widget _topRow(context) {
+    return Row(children: <Widget>[
+      _goodsImg(floorContent[0], context),
+      Column(children: <Widget>[
+        _goodsImg(floorContent[1], context),
+        _goodsImg(floorContent[2], context),
+      ])
+    ]);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return SliverToBoxAdapter(
+        child: InkWell(
+      child: Container(
+        child: Column(children: <Widget>[
+          _topRow(context),
+          Row(children: <Widget>[
+            _goodsImg(floorContent[3], context),
+            _goodsImg(floorContent[4], context),
+          ])
+        ]),
+      ),
+      onTap: () {},
+    ));
+  }
+}

+ 164 - 0
lib/views/homepage/home_page.dart

@@ -0,0 +1,164 @@
+import 'dart:ui';
+
+import 'package:amap_base/amap_base.dart';
+import 'package:fluro/fluro.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_easyrefresh/ball_pulse_footer.dart';
+import 'package:flutter_easyrefresh/ball_pulse_header.dart';
+import 'package:flutter_easyrefresh/easy_refresh.dart';
+import 'package:flutter_note/routers/application.dart';
+import 'package:flutter_note/views/homepage/ad_banner.dart';
+import 'package:flutter_note/views/homepage/banner_diy.dart';
+import 'package:flutter_note/views/homepage/floor_part.dart';
+import 'package:flutter_note/views/homepage/hot_part.dart';
+import 'package:flutter_note/views/homepage/lead_phone.dart';
+import 'package:flutter_note/views/homepage/mall_recommend.dart';
+import 'package:flutter_note/views/homepage/top_nativator.dart';
+import 'package:flutter_note/provide/home_provide.dart';
+import 'package:flutter_note/routers/routers.dart';
+import 'package:provide/provide.dart';
+
+class HomePage extends StatelessWidget {
+  final GlobalKey<EasyRefreshState> _refreshKey = GlobalKey();
+  final GlobalKey<RefreshHeaderState> _headerKey = GlobalKey();
+  final GlobalKey<RefreshFooterState> _footerKey = GlobalKey();
+  final ScrollController _outController = ScrollController();
+  final _mapLocation = AMapLocation();
+
+  @override
+  Widget build(BuildContext context) {
+    _mapLocation.init();
+
+    Permissions().requestPermission().then((granted) {
+      if (granted) {
+        _mapLocation
+            .getLocation(LocationClientOptions(
+          isOnceLocation: true,
+          isNeedAddress: true,
+          locatingWithReGeocode: true,
+        ))
+            .then((location) {
+          print(
+              'location:(${location.longitude}, ${location.latitude}), ${location.district}');
+          Provide.value<HomeProvide>(context)
+            ..initHomeEntity(location.longitude, location.latitude)
+            ..changeDistrict(
+                location.district, location.longitude, location.latitude);
+        });
+      } else {
+        Provide.value<HomeProvide>(context).initHomeEntity(115.02932, 35.76189);
+      }
+    });
+
+    Provide.value<HomeProvide>(context).initHotGoodsList();
+
+    _outController.addListener(() {
+      Provide.value<HomeProvide>(context).enableBack(
+          _outController.position.pixels >= window.physicalSize.height);
+    });
+
+    return Theme(
+      data: ThemeData(
+          primarySwatch: Colors.pink,
+          iconTheme: IconThemeData(color: Colors.pink)),
+      child: Provide<HomeProvide>(
+          builder: (_, widget, homeProvide) => Scaffold(
+                appBar: AppBar(
+                  title: Text('百姓生活+'),
+                  centerTitle: true,
+                  leading: InkWell(
+                    child: Padding(
+                      padding: const EdgeInsets.all(4.0),
+                      child: Row(
+                        children: <Widget>[
+                          Icon(Icons.location_on,
+                              color: Colors.white, size: 12.0),
+                          Expanded(
+                            child: Text(homeProvide.district,
+                                style: TextStyle(fontSize: 12.0),
+                                overflow: TextOverflow.ellipsis,
+                                maxLines: 1),
+                          )
+                        ],
+                      ),
+                    ),
+                    onTap: () => Application.router.navigateTo(
+                        context, Routers.map,
+                        transition: TransitionType.fadeIn),
+                  ),
+                ),
+                body: homeProvide.homeEntity == null
+                    ? Center(child: CupertinoActivityIndicator(radius: 12.0))
+                    : EasyRefresh(
+                        key: _refreshKey,
+                        refreshHeader: BallPulseHeader(
+                            key: _headerKey, color: Colors.pink),
+                        refreshFooter: BallPulseFooter(
+                            key: _footerKey, color: Colors.pink),
+                        loadMore: () => homeProvide.loadMoreHotGoods(),
+                        child: CustomScrollView(
+                          controller: _outController,
+                          physics: BouncingScrollPhysics(),
+                          slivers: <Widget>[
+                            BannerDiy(
+                                bannerImages:
+                                    homeProvide.homeEntity.data.slides),
+                            TopNavigatorBar(
+                                categories:
+                                    homeProvide.homeEntity.data.category),
+                            AdBanner(
+                                bannerUrl: homeProvide.homeEntity.data
+                                    .advertesPicture.pICTUREADDRESS),
+                            LeaderPhone(
+                              imageUrl: homeProvide
+                                  .homeEntity.data.shopInfo.leaderImage,
+                              phone: homeProvide
+                                  .homeEntity.data.shopInfo.leaderPhone,
+                            ),
+                            RecommendWidget(
+                                recommendList:
+                                    homeProvide.homeEntity.data.recommend),
+                            FloorTitle(
+                                floorPic: homeProvide
+                                    .homeEntity.data.floor1Pic.pICTUREADDRESS),
+                            FloorContent(
+                                floorContent:
+                                    homeProvide.homeEntity.data.floor1),
+                            FloorTitle(
+                                floorPic: homeProvide
+                                    .homeEntity.data.floor2Pic.pICTUREADDRESS),
+                            FloorContent(
+                                floorContent:
+                                    homeProvide.homeEntity.data.floor2),
+                            FloorTitle(
+                                floorPic: homeProvide
+                                    .homeEntity.data.floor3Pic.pICTUREADDRESS),
+                            FloorContent(
+                                floorContent:
+                                    homeProvide.homeEntity.data.floor3),
+                            HotGoodsTitle(),
+                            SliverGrid.count(
+                              crossAxisCount: 2,
+                              childAspectRatio: 0.7,
+                              children: homeProvide.hodGoodsList
+                                  .map((hot) => HotItem(hot: hot))
+                                  .toList(),
+                            )
+                          ],
+                        ),
+                      ),
+                floatingActionButton: homeProvide.showBack
+                    ? FloatingActionButton(
+                        onPressed: () {
+                          _outController.animateTo(0.0,
+                              duration: Duration(milliseconds: 500),
+                              curve: Curves.decelerate);
+                        },
+                        mini: true,
+                        child: Icon(Icons.vertical_align_top))
+                    : null,
+              )),
+    );
+  }
+}

+ 58 - 0
lib/views/homepage/hot_part.dart

@@ -0,0 +1,58 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/routers/application.dart';
+import 'package:flutter_note/model/hot_goods_model.dart';
+import 'package:flutter_note/routers/routers.dart';
+
+/// 火爆专区标题
+class HotGoodsTitle extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return SliverToBoxAdapter(
+      child: Container(
+        alignment: Alignment.center,
+        child: Text('火爆专区', style: TextStyle(color: Colors.black)),
+        padding: const EdgeInsets.symmetric(vertical: 8.0),
+      ),
+    );
+  }
+}
+
+/// 火爆专区
+class HotItem extends StatelessWidget {
+  final HotGoodsData hot;
+
+  HotItem({Key key, this.hot}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return InkWell(
+      onTap: () {
+        Application.router.navigateTo(
+            context, Routers.generateDetailsRouterPath(hot.goodsId));
+      },
+      child: Container(
+        color: Colors.white,
+        alignment: Alignment.center,
+        margin: const EdgeInsets.only(left: 4.0, right: 4.0, bottom: 8.0),
+        padding: const EdgeInsets.all(4.0),
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: <Widget>[
+            Image.network(hot.image),
+            Text(hot.name, textAlign: TextAlign.center, maxLines: 1),
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceAround,
+              children: <Widget>[
+                Text('¥${hot.mallPrice}'),
+                Text('¥${hot.price}',
+                    style: TextStyle(
+                        color: Colors.black45,
+                        decoration: TextDecoration.lineThrough))
+              ],
+            )
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 22 - 0
lib/views/homepage/lead_phone.dart

@@ -0,0 +1,22 @@
+import 'package:flutter/material.dart';
+import 'package:url_launcher/url_launcher.dart';
+
+class LeaderPhone extends StatelessWidget {
+  final String imageUrl;
+  final String phone;
+
+  LeaderPhone({Key key, @required this.imageUrl, @required this.phone}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return SliverToBoxAdapter(
+        child: Container(
+      child: InkWell(
+          child: Image.network(imageUrl, fit: BoxFit.cover),
+          onTap: () async {
+            var url = 'tel:$phone';
+            if (await canLaunch(url)) launch(url);
+          }),
+    ));
+  }
+}

+ 74 - 0
lib/views/homepage/mall_recommend.dart

@@ -0,0 +1,74 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/routers/application.dart';
+import 'package:flutter_note/model/home_page_model.dart';
+import 'package:flutter_note/routers/routers.dart';
+
+class RecommendWidget extends StatelessWidget {
+  final List<Recommend> recommendList;
+
+  RecommendWidget({Key key, @required this.recommendList}) : super(key: key);
+
+  Widget _recommendTitle() {
+    return Container(
+      alignment: Alignment.center,
+      padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0),
+      decoration: BoxDecoration(
+          border:
+              Border(bottom: BorderSide(color: Colors.black12, width: 1.0))),
+      child: Text('商品推荐', style: TextStyle(color: Colors.pink)),
+    );
+  }
+
+  Widget _recommendItem(BuildContext context, int index) {
+    return InkWell(
+      onTap: () {
+        Application.router.navigateTo(context,
+            Routers.generateDetailsRouterPath(recommendList[index].goodsId));
+      },
+      child: Container(
+        width: MediaQuery.of(context).size.width / 3,
+        height: 180.0,
+        alignment: Alignment.center,
+        decoration: BoxDecoration(
+            border: Border(
+              left: BorderSide(color: Colors.black12),
+              bottom: BorderSide(color: Colors.black12),
+            ),
+            color: Colors.white),
+        child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: <Widget>[
+              Image.network(recommendList[index].image, height: 120.0),
+              Text('¥${recommendList[index].mallPrice}',
+                  style: TextStyle(fontSize: 16.0)),
+              Text('¥${recommendList[index].price}',
+                  style: TextStyle(
+                      decoration: TextDecoration.lineThrough,
+                      decorationColor: Colors.black45))
+            ]),
+      ),
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return SliverToBoxAdapter(
+      child: Container(
+        alignment: Alignment.center,
+        margin: const EdgeInsets.only(top: 6.0),
+        child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: <Widget>[
+              _recommendTitle(),
+              SizedBox(
+                height: 180.0,
+                child: ListView.builder(
+                    itemBuilder: _recommendItem,
+                    itemCount: this.recommendList.length,
+                    scrollDirection: Axis.horizontal),
+              )
+            ]),
+      ),
+    );
+  }
+}

+ 49 - 0
lib/views/homepage/top_nativator.dart

@@ -0,0 +1,49 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/model/home_page_model.dart';
+import 'package:flutter_note/provide/page_index_provide.dart';
+import 'package:provide/provide.dart';
+
+class TopNavigatorBar extends StatelessWidget {
+  final List<Category> categories;
+
+  TopNavigatorBar({Key key, @required this.categories}) : super(key: key);
+
+  Widget _buildCategoryItem(BuildContext context, Category item) {
+    return InkWell(
+      onTap: () {
+        Provide.value<PageIndexProvide>(context).changePage(1);
+      },
+      child: Column(
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: [
+          Image.network(item.image,
+              width: MediaQuery.of(context).size.width / 8),
+          Padding(
+            padding: const EdgeInsets.only(top: 4.0),
+            child: Text(item.mallCategoryName,
+                style: TextStyle(color: Colors.black)),
+          ),
+        ],
+      ),
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    if (categories.length > 10) categories.removeRange(10, categories.length);
+    return SliverToBoxAdapter(
+      child: SizedBox(
+        height: MediaQuery.of(context).size.width * 2 / 5,
+        child: GridView.count(
+          padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
+          childAspectRatio: 1.0,
+          physics: NeverScrollableScrollPhysics(),
+          crossAxisCount: 5,
+          children: categories
+              .map((item) => _buildCategoryItem(context, item))
+              .toList(),
+        ),
+      ),
+    );
+  }
+}

+ 45 - 0
lib/views/index_page.dart

@@ -0,0 +1,45 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_note/views/cartpage/cart_page.dart';
+import 'package:flutter_note/views/category_page.dart';
+import 'package:flutter_note/views/homepage/home_page.dart';
+import 'package:flutter_note/views/mempage/mem_page.dart';
+import 'package:flutter_note/provide/page_index_provide.dart';
+import 'package:provide/provide.dart';
+
+class IndexPage extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    final _bottomTabs = <BottomNavigationBarItem>[
+      BottomNavigationBarItem(
+          icon: Icon(CupertinoIcons.home), title: Text('首页')),
+      BottomNavigationBarItem(
+          icon: Icon(CupertinoIcons.search), title: Text('分类')),
+      BottomNavigationBarItem(
+          icon: Icon(CupertinoIcons.shopping_cart), title: Text('购物车')),
+      BottomNavigationBarItem(
+          icon: Icon(CupertinoIcons.profile_circled), title: Text('会员中心'))
+    ];
+
+    final _tabPages = <Widget>[
+      HomePage(),
+      CategoryPage(),
+      CartPage(),
+      MemPage()
+    ];
+
+    return Provide<PageIndexProvide>(
+        builder: (_, child, pageProvide) => Scaffold(
+              backgroundColor: Color.fromRGBO(244, 245, 245, 1.0),
+              body: IndexedStack(index: pageProvide.page, children: _tabPages),
+              bottomNavigationBar: BottomNavigationBar(
+                items: _bottomTabs,
+                type: BottomNavigationBarType.fixed,
+                currentIndex: pageProvide.page,
+                onTap: (value) {
+                  Provide.value<PageIndexProvide>(context).changePage(value);
+                },
+              ),
+            ));
+  }
+}

+ 49 - 0
lib/views/map_page.dart

@@ -0,0 +1,49 @@
+import 'package:flutter/material.dart';
+import 'package:amap_base/amap_base.dart';
+import 'package:flutter_note/provide/home_provide.dart';
+import 'package:provide/provide.dart';
+
+class MapPage extends StatefulWidget {
+  @override
+  _MapPageState createState() => _MapPageState();
+}
+
+class _MapPageState extends State<MapPage> {
+  AMapController _controller;
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    _controller.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    var provide = Provide.value<HomeProvide>(context);
+    return Scaffold(
+      appBar: AppBar(
+        title: Text('Map'),
+      ),
+      body: AMapView(
+        onAMapViewCreated: (controller) {
+          _controller = controller;
+          _controller.showIndoorMap(true);
+          _controller.setZoomLevel(19);
+        },
+        amapOptions: AMapOptions(
+          compassEnabled: false,
+          zoomControlsEnabled: true,
+          logoPosition: LOGO_POSITION_BOTTOM_LEFT,
+          camera: CameraPosition(
+              target:
+                  LatLng(provide.latitude, provide.longitude) /*, zoom: 15.0*/),
+        ),
+      ),
+    );
+  }
+}

+ 25 - 0
lib/views/mempage/mem_header.dart

@@ -0,0 +1,25 @@
+import 'package:flutter/material.dart';
+
+class MemHeader extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      alignment: Alignment.center,
+      padding: const EdgeInsets.symmetric(vertical: 40.0),
+      decoration: BoxDecoration(
+        gradient: LinearGradient(colors: [Colors.pink[300], Colors.blue[200]], begin: Alignment.topLeft, end: Alignment.bottomRight),
+      ),
+      child: Column(
+        children: <Widget>[
+          ClipOval(
+            child: Image.asset('images/avatar.jpg', width: 100.0, height: 100.0),
+          ),
+          Padding(
+            padding: const EdgeInsets.all(8.0),
+            child: Text('Kuky_xs', style: TextStyle(color: Colors.black, fontSize: 18.0)),
+          )
+        ],
+      ),
+    );
+  }
+}

+ 44 - 0
lib/views/mempage/mem_page.dart

@@ -0,0 +1,44 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_note/routers/application.dart';
+import 'package:flutter_note/views/mempage/mem_header.dart';
+import 'package:flutter_note/views/mempage/mem_tile.dart';
+import 'package:flutter_note/views/mempage/order_grid.dart';
+import 'package:flutter_note/routers/routers.dart';
+
+class MemPage extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text('会员中心'),
+        centerTitle: true,
+      ),
+      body: ListView(
+        children: <Widget>[
+          MemHeader(),
+          MemTile(leading: Icons.border_all, title: "我的订单", action: () {}),
+          Divider(height: 2.0, color: Colors.black38),
+          OrderGrid(),
+          Container(height: 8.0, color: Colors.black12),
+          MemTile(
+              leading: Icons.bookmark_border, title: "领取优惠券", action: () {}),
+          Divider(height: 2.0, color: Colors.black38),
+          MemTile(
+              leading: Icons.bookmark_border, title: "已领取优惠券", action: () {}),
+          Divider(height: 2.0, color: Colors.black38),
+          MemTile(leading: Icons.my_location, title: "地址管理", action: () {}),
+          Container(height: 8.0, color: Colors.black12),
+          MemTile(leading: Icons.phone, title: "客服电话", action: () {}),
+          Divider(height: 2.0, color: Colors.black38),
+          MemTile(leading: Icons.info_outline, title: "关于商城", action: () {}),
+          Container(height: 8.0, color: Colors.black12),
+          MemTile(
+              leading: Icons.settings,
+              title: "设置",
+              action: () =>
+                  Application.router.navigateTo(context, Routers.settings)),
+        ],
+      ),
+    );
+  }
+}

+ 19 - 0
lib/views/mempage/mem_tile.dart

@@ -0,0 +1,19 @@
+import 'package:flutter/material.dart';
+
+class MemTile extends StatelessWidget {
+  final IconData leading;
+  final String title;
+  final VoidCallback action;
+
+  MemTile({Key key, this.leading, this.title, this.action}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return ListTile(
+      leading: Icon(leading),
+      title: Text(title, style: TextStyle(color: Colors.black, fontSize: 16.0)),
+      trailing: Icon(Icons.arrow_forward_ios),
+      onTap: action,
+    );
+  }
+}

+ 26 - 0
lib/views/mempage/order_grid.dart

@@ -0,0 +1,26 @@
+import 'package:flutter/material.dart';
+
+class OrderGrid extends StatelessWidget {
+  final _icons = [Icons.payment, Icons.timer, Icons.airport_shuttle, Icons.textsms];
+  final _titles = ['待付款', '待发货', '待收货', '待评价'];
+
+  @override
+  Widget build(BuildContext context) {
+    return SizedBox(
+      height: MediaQuery.of(context).size.width / 4,
+      child: GridView.count(
+        crossAxisCount: _icons.length,
+        children: List.generate(
+            _icons.length,
+            (index) => InkWell(
+                  child: Column(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: <Widget>[Icon(_icons[index]), Padding(padding: const EdgeInsets.all(4.0), child: Text(_titles[index]))],
+                  ),
+                  onTap: () {},
+                )),
+        physics: NeverScrollableScrollPhysics(),
+      ),
+    );
+  }
+}

+ 47 - 0
lib/views/my_home_page.dart

@@ -0,0 +1,47 @@
+import 'package:flutter/material.dart';
+
+class MyHomePage extends StatefulWidget {
+  MyHomePage({Key key, this.title}) : super(key: key);
+  final String title;
+
+  @override
+  _MyHomePageState createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State<MyHomePage> {
+  int _counter = 0;
+
+  void _incrementCounter() {
+    setState(() {
+      _counter++;
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(widget.title),
+      ),
+      body: Center(
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: <Widget>[
+            Text(
+              '您点击+号多次:',
+            ),
+            Text(
+              '$_counter',
+              style: Theme.of(context).textTheme.display1,
+            ),
+          ],
+        ),
+      ),
+      floatingActionButton: FloatingActionButton(
+        onPressed: _incrementCounter,
+        tooltip: 'Increment',
+        child: Icon(Icons.add),
+      ), // This trailing comma makes auto-formatting nicer for build methods.
+    );
+  }
+}

+ 44 - 0
lib/views/settings_page.dart

@@ -0,0 +1,44 @@
+import 'package:flutter/material.dart';
+
+class SettingsPage extends StatefulWidget {
+  @override
+  _SettingsPageState createState() => _SettingsPageState();
+}
+
+class _SettingsPageState extends State<SettingsPage> {
+  bool _openNotification = true;
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Theme(
+        data: ThemeData(primaryColor: Colors.pink, iconTheme: IconThemeData(color: Colors.pink)),
+        child: Scaffold(
+          appBar: AppBar(
+            title: Text('设置'),
+          ),
+          body: ListView(
+            children: <Widget>[
+              SwitchListTile(
+                  activeColor: Colors.pink,
+                  title: Text('是否接收通知'),
+                  value: _openNotification,
+                  onChanged: (value) {
+                    setState(() {
+                      this._openNotification = value;
+                    });
+                  })
+            ],
+          ),
+        ));
+  }
+}

+ 15 - 0
lib/widgets/404.dart

@@ -0,0 +1,15 @@
+import 'package:flutter/material.dart';
+
+class WidgetNotFound extends StatelessWidget {
+    @override
+    Widget build(BuildContext context) {
+      return Scaffold(
+          appBar: AppBar(
+            title: Text("widget not found"),
+          ),
+          body: Container(
+              child:  Text("widget not found")
+          )
+      );
+    }
+}

+ 20 - 52
pubspec.yaml

@@ -1,68 +1,36 @@
 name: flutter_note
-description: Some notes about Flutter application.
-
-# The following defines the version and build number for your application.
-# A version number is three numbers separated by dots, like 1.2.43
-# followed by an optional build number separated by a +.
-# Both the version and the builder number may be overridden in flutter
-# build by specifying --build-name and --build-number, respectively.
-# Read more about versioning at semver.org.
+description: Flutter 工作中不断总结.
 version: 1.0.0+1
-
 environment:
   sdk: ">=2.0.0-dev.68.0 <3.0.0"
 
 dependencies:
   flutter:
     sdk: flutter
-
-  # The following adds the Cupertino Icons font to your application.
-  # Use with the CupertinoIcons class for iOS style icons.
+  sqflite: ^1.1.5
+  shared_preferences: ^0.4.3
+  fluro: ^1.4.0
   cupertino_icons: ^0.1.2
+  dio: ^2.1.2
+  flutter_easyrefresh: ^1.2.7
+  flutter_swiper: ^1.1.6
+  flutter_html: ^0.9.6
+  url_launcher: ^5.0.2
+  path_provider: ^0.5.0+1
+  provide: ^1.0.2
+#  jpush_flutter: ^0.0.11
+
+  fluttertoast: ^3.0.3
+  amap_base: ^0.3.5
+
+  flutter_localizations: # 国际化
+    sdk: flutter
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
 
-
-# For information on the generic Dart part of this file, see the
-# following page: https://www.dartlang.org/tools/pub/pubspec
-
-# The following section is specific to Flutter.
 flutter:
-
-  # The following line ensures that the Material Icons font is
-  # included with your application, so that you can use the icons in
-  # the material Icons class.
   uses-material-design: true
-
-  # To add assets to your application, add an assets section, like this:
-  # assets:
-  #  - images/a_dot_burr.jpeg
-  #  - images/a_dot_ham.jpeg
-
-  # An image asset can refer to one or more resolution-specific "variants", see
-  # https://flutter.io/assets-and-images/#resolution-aware.
-
-  # For details regarding adding assets from package dependencies, see
-  # https://flutter.io/assets-and-images/#from-packages
-
-  # To add custom fonts to your application, add a fonts section here,
-  # in this "flutter" section. Each entry in this list should have a
-  # "family" key with the font family name, and a "fonts" key with a
-  # list giving the asset and other descriptors for the font. For
-  # example:
-  # fonts:
-  #   - family: Schyler
-  #     fonts:
-  #       - asset: fonts/Schyler-Regular.ttf
-  #       - asset: fonts/Schyler-Italic.ttf
-  #         style: italic
-  #   - family: Trajan Pro
-  #     fonts:
-  #       - asset: fonts/TrajanPro.ttf
-  #       - asset: fonts/TrajanPro_Bold.ttf
-  #         weight: 700
-  #
-  # For details regarding fonts from package dependencies,
-  # see https://flutter.io/custom-fonts/#from-packages
+  assets:
+  - images/

+ 0 - 30
test/widget_test.dart

@@ -1,30 +0,0 @@
-// This is a basic Flutter widget test.
-//
-// To perform an interaction with a widget in your test, use the WidgetTester
-// utility that Flutter provides. For example, you can send tap and scroll
-// gestures. You can also use WidgetTester to find child widgets in the widget
-// tree, read text, and verify that the values of widget properties are correct.
-
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-import 'package:flutter_note/main.dart';
-
-void main() {
-  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
-    // Build our app and trigger a frame.
-    await tester.pumpWidget(MyApp());
-
-    // Verify that our counter starts at 0.
-    expect(find.text('0'), findsOneWidget);
-    expect(find.text('1'), findsNothing);
-
-    // Tap the '+' icon and trigger a frame.
-    await tester.tap(find.byIcon(Icons.add));
-    await tester.pump();
-
-    // Verify that our counter has incremented.
-    expect(find.text('0'), findsNothing);
-    expect(find.text('1'), findsOneWidget);
-  });
-}

+ 5 - 0
tools/run_flutter.sh

@@ -0,0 +1,5 @@
+set PUB_HOSTED_URL=https://pub.flutter-io.cn
+set FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
+D:\Program-Files\flutter\bin\flutter.bat packages get
+
+D:\Program-Files\flutter\bin\flutter.bat run main.dark