瀏覽代碼

20230807初始化

15143018065 1 年之前
當前提交
cc816ed1b4
共有 100 個文件被更改,包括 23171 次插入0 次删除
  1. 5 0
      .gitignore
  2. 1677 0
      App.vue
  3. 21 0
      LICENSE
  4. 55 0
      README.md
  5. 165 0
      changelog.md
  6. 86 0
      common/css/business.css
  7. 259 0
      common/css/lib.css
  8. 847 0
      common/css/page.css
  9. 258 0
      common/css/plugins.css
  10. 76 0
      common/css/theme/black.css
  11. 76 0
      common/css/theme/blue.css
  12. 76 0
      common/css/theme/brown.css
  13. 76 0
      common/css/theme/green.css
  14. 76 0
      common/css/theme/orange.css
  15. 76 0
      common/css/theme/purple.css
  16. 76 0
      common/css/theme/red.css
  17. 76 0
      common/css/theme/yellow.css
  18. 82 0
      common/js/common/base.js
  19. 47 0
      common/js/common/share.js
  20. 8 0
      common/js/lib/base64.js
  21. 52 0
      components/activity-list/activity-list.vue
  22. 52 0
      components/badge/badge.vue
  23. 96 0
      components/binding-list/binding-list.vue
  24. 588 0
      components/blog-comments/blog-comments.vue
  25. 97 0
      components/blog-list/blog-list.vue
  26. 48 0
      components/bottom-line/bottom-line.vue
  27. 103 0
      components/cart-para-curve/cart-para-curve.vue
  28. 735 0
      components/cart/cart.vue
  29. 31 0
      components/copyright/copyright.vue
  30. 212 0
      components/countdown/countdown.vue
  31. 94 0
      components/emoji-popup/emoji-popup.vue
  32. 498 0
      components/goods-batch-buy/goods-batch-buy.vue
  33. 755 0
      components/goods-buy/goods-buy.vue
  34. 275 0
      components/goods-list/goods-list.vue
  35. 355 0
      components/goods-spec-choice/goods-spec-choice.vue
  36. 77 0
      components/icon-nav/icon-nav.vue
  37. 1357 0
      components/layout/layout.vue
  38. 89 0
      components/no-data/no-data.vue
  39. 290 0
      components/online-service/online-service.vue
  40. 152 0
      components/popup/popup.vue
  41. 242 0
      components/quick-nav/quick-nav.vue
  42. 193 0
      components/realstore-list/realstore-list.vue
  43. 119 0
      components/search/search.vue
  44. 185 0
      components/share-popup/share-popup.vue
  45. 78 0
      components/shop-list/shop-list.vue
  46. 63 0
      components/slider/slider.vue
  47. 25 0
      components/status-bar-height/status-bar-height.vue
  48. 199 0
      components/switch/switch.vue
  49. 553 0
      components/time-select/time-select.vue
  50. 89 0
      components/trn-nav/trn-nav.vue
  51. 17 0
      main.js
  52. 121 0
      manifest.json
  53. 12 0
      node_modules/.package-lock.json
  54. 30 0
      node_modules/jweixin-module/README.md
  55. 1 0
      node_modules/jweixin-module/lib/index.js
  56. 26 0
      node_modules/jweixin-module/package.json
  57. 24 0
      package-lock.json
  58. 5 0
      package.json
  59. 912 0
      pages.json
  60. 143 0
      pages/answer-form/answer-form.vue
  61. 4 0
      pages/answer-list/answer-list.css
  62. 165 0
      pages/answer-list/answer-list.vue
  63. 233 0
      pages/article-category/article-category.vue
  64. 3 0
      pages/article-detail/article-detail.css
  65. 142 0
      pages/article-detail/article-detail.vue
  66. 238 0
      pages/buy/buy.css
  67. 865 0
      pages/buy/buy.vue
  68. 39 0
      pages/cart-page/cart-page.vue
  69. 39 0
      pages/cart/cart.vue
  70. 41 0
      pages/common/open-setting-location/open-setting-location.css
  71. 118 0
      pages/common/open-setting-location/open-setting-location.vue
  72. 135 0
      pages/design/design.vue
  73. 67 0
      pages/error/error.vue
  74. 15 0
      pages/extraction-address/extraction-address.css
  75. 268 0
      pages/extraction-address/extraction-address.vue
  76. 206 0
      pages/goods-category/goods-category.css
  77. 1064 0
      pages/goods-category/goods-category.vue
  78. 53 0
      pages/goods-comment/goods-comment.css
  79. 252 0
      pages/goods-comment/goods-comment.vue
  80. 591 0
      pages/goods-detail/goods-detail.css
  81. 1407 0
      pages/goods-detail/goods-detail.vue
  82. 137 0
      pages/goods-search/goods-search.css
  83. 568 0
      pages/goods-search/goods-search.vue
  84. 186 0
      pages/index/index.css
  85. 557 0
      pages/index/index.vue
  86. 79 0
      pages/login/login.css
  87. 1346 0
      pages/login/login.vue
  88. 3 0
      pages/logout/logout.css
  89. 155 0
      pages/logout/logout.vue
  90. 168 0
      pages/message/message.vue
  91. 21 0
      pages/paytips/paytips.css
  92. 94 0
      pages/paytips/paytips.vue
  93. 4 0
      pages/personal/personal.css
  94. 268 0
      pages/personal/personal.vue
  95. 16 0
      pages/plugins/activity/detail/detail.css
  96. 171 0
      pages/plugins/activity/detail/detail.vue
  97. 17 0
      pages/plugins/activity/index/index.css
  98. 256 0
      pages/plugins/activity/index/index.vue
  99. 69 0
      pages/plugins/binding/detail/detail.css
  100. 0 0
      pages/plugins/binding/detail/detail.vue

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+.DS_Store
+.hbuilderx
+*.log
+unpackage
+sitemap.json

文件差異過大導致無法顯示
+ 1677 - 0
App.vue


+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 ShopXO免费开源商城
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 55 - 0
README.md

@@ -0,0 +1,55 @@
+# ShopXO开源商城uniapp端
+
+#### 介绍
+
+* 后端支持依托于ShopXO免费开源电商系统开发的uniapp端主题源码
+* 内置8中搭配主色(可自行扩展更多配色)、自由快捷切换适应各大行业需求
+* 已支持小程序(微信、QQ、百度、支付宝、头条&抖音、快手)+ H5,(APP正在紧急适配中)
+
+#### 使用教程
+
+`程序打包操作需要有一定的编程技术基础、如需帮助请到git平台提issues寻求帮助`
+* 打包教程 [https://doc.shopxo.net/article/1/293727233598554112.html](https://doc.shopxo.net/article/1/293727233598554112.html)
+
+1. 先安装ShopXO免费开源系统 [http://install.shopxo.net/](http://install.shopxo.net/)
+2. 将该源码导入HBuilderX开发工具、顶部工具栏 `运行->运行到小程序模拟器->(根据支持平台自行选择、如 微信开发者工具)`
+3. App.vue中修改 request_url 和 static_url 地址为自己的商城地址即可使用
+4. 主题默认为黄色(yellow),如更改主题 App.vue文件中 default_theme + 底部css引入,pages.json文件中 tabBar选中图标+selectedColor选中颜色
+5. 发布、HBuilderX开发工具、顶部工具栏 `发行->(根据支持平台自行选择、如 微信开发者工具)`
+
+#### 官方QQ群、答案`shopxo.net`
+* 官方uniapp群:679303149
+
+#### 体验码
+
+![二维码.jpg](https://doc.shopxo.net/upload/image/20211211/1639234221484373.jpg)
+
+
+#### 当前项目源代码平台
+
+* Gitee:[https://gitee.com/zongzhige/shopxo-uniapp](https://gitee.com/zongzhige/shopxo-uniapp)
+* GitHub:[https://github.com/gongfuxiang/shopxo-uniapp](https://github.com/gongfuxiang/shopxo-uniapp)
+* Coding:[https://zongzhige.coding.net/public/shopxo/uniapp/git](https://zongzhige.coding.net/public/shopxo/uniapp/git)
+* GitCode:[https://gitcode.net/zongzhige/shopxo-uniapp](https://gitcode.net/zongzhige/shopxo-uniapp)
+* uni-app:[https://ext.dcloud.net.cn/plugin?id=6380](https://ext.dcloud.net.cn/plugin?id=6380)
+
+#### ShopXO后端源代码平台
+
+* Gitee:[https://gitee.com/zongzhige/shopxo](https://gitee.com/zongzhige/shopxo)
+* GitHub:[https://github.com/gongfuxiang/shopxo](https://github.com/gongfuxiang/shopxo)
+* Coding:[https://zongzhige.coding.net/public/shopxo/shopxo/git](https://zongzhige.coding.net/public/shopxo/shopxo/git)
+* GitCode:[https://gitcode.net/zongzhige/shopxo](https://gitcode.net/zongzhige/shopxo)
+
+#### API接口文档
+
+* [https://doc.shopxo.net/article/2.html](https://doc.shopxo.net/article/2.html)
+
+#### 支持多种配色
+
+![配色](https://doc.shopxo.net/upload/image/20211023/1634962774958024.jpg)
+
+#### 效果图片
+
+![主要部分](https://doc.shopxo.net/upload/image/20211023/1634962851731604.jpg)
+![扩展部分](https://doc.shopxo.net/upload/image/20211023/1634962862173709.jpg)
+![多门店](https://doc.shopxo.net/upload/image/20220406/1649233148208137.jpg)

+ 165 - 0
changelog.md

@@ -0,0 +1,165 @@
+## v2.3.3(2023-04-10)
+* 商品列表使用统一组件
+* 商品参数新增弹窗展示
+* 初始访问登录页面优化
+* 公共url打开支持地图、电话、外部小程序协议方式
+* 适配手机底部横线
+* 轮播兼容iphone圆角失效问题
+* 用户中心菜单支持列表展示样式
+* 搜索页面支持九方格和列表展示样式
+* 分类支持参数指定跳转
+* icon导航图标支持纯图片
+* 分类和门店详情适配规格起购数及限购数
+* 起购数和限购数提升 到商品规格级别
+* 地址新增编号快速搜索选择
+* 订单售后页面新增客服展示
+* 购买和加购分离统一组件
+* 提现初始错误修复
+* 立即购买支持多商品
+* 积分使用兑换不足提示
+* 博客新增评论、点赞
+* 新增组合搭配
+* 新增列表快捷加入购物车
+* 商品列表新增错误提示
+* 商家详情新增搜索全站开关控制
+* 门店详情新增扫码开关控制
+* 新增多规格批量下单
+* 插件分包处理
+
+
+## v2.3.2(2022-11-30)
+* 门店详情支持多规格直接加购
+* 分类页面支持多规格直接加购+购物车操作
+* 新增会员码
+* 新增钱包付款码
+* 新增个人资料修改
+* 新增手机号码修改
+* 新增账号注销
+* 新增条码二维码生成组件
+* 新增用户ID展示
+* 购物车分离优化
+* 适配微信小程序登录新规
+* 可视化新增图文、图片魔方、自定义html组件,商品支持左图右文样式
+* 下单时间优化、支持默认提示
+
+
+## v2.3.1(2022-10-23)
+* 支付宝获取地图权限优化
+* 头条小程序分类不铺满问题修复
+* 优化商品分类滑动方案
+* 位置选择优化
+
+
+## v2.3.0(2022-08-16)
+* 左右滚动最后一个元素显示不全修复
+* 适配paypal支付
+* 会员购买支付优化
+* 去除头条小程序自定义导航
+* 新增虚拟订单快速提交订单
+* 头条小程序支持一键获取手机号码登录
+* 多商户首页支持自动模式
+* 优惠券支持多商户
+* 商品错误情况下新增返回按钮
+* 限时秒杀优化
+* 博客搜索页面分享优化
+
+
+## v2.2.9(2022-07-11)
+* 首页插件数据支持按顺序渲染
+* 商品分类支持商品列表模式展示
+* 商品详情支持默认选中第一个有效规格
+* 商品详情快捷加购自动返回
+* 下单地址限制优化
+* 多商户首页支持多种样式展示
+* 商品url地址使用后端生成、购买导航新增url事件、左侧返回优化
+* 登录绑定手机返回优化
+* 搜索页面优化、避免返回事件重复加载
+
+
+## v2.2.8(2022-05-20)
+* 活动配置首页推荐支持(图文、九方格、左右滚动)样式展示
+* 多商户新增店铺认证资质展示
+* 门店详情支持二级分类
+* 可视化数据处理错误修复
+* 退出仅清除用户信息、微信自动登录强制绑定账号循环修复
+* 主题色样式class错误修复
+* 适配快手小程序
+
+
+## v2.2.7(2022-04-22)
+* 用户地址支持地理位置选择和地址信息智能识别
+* 登录返回上一页,h5支持微信自动登录
+* 门店首页新增地理位置选择弹窗、门店详情优化
+* 商品详情页面导航返回逻辑优化
+* 首页搜索和导航固定控制优化
+* 博客详情新增分享入口
+* 门店详情新增返回按钮关闭开关(适合独立打包)
+
+
+## v2.2.6(2022-04-07)
+* 集成新的客服系统、商品页调整为底部导航入口
+* 下单可直接使用门店次卡消费
+* 门店详情数据改为分页模式、提高效率
+* 商品详情新增相关门店列表入口
+* 商品详情底部导航购物车新增可控开关
+* 商品详情页提示优化
+* 新增可关闭原始购买功能、仅可进入门店购买
+* 标签详情分享地址id为空修复
+* 支持设置默认下单类型
+* 新增商品详情购物车展示开关(App.vue中设置)
+* 新增分享及转发使用页面设置的默认图片及系统默认图片开关(App.vue中设置)
+
+
+## v2.2.5(2022-03-10)
+* 基础组件类库更新
+* 商品详情新增智能工具插件信息提示
+* 订单取消后隐藏支付按钮,细节优化
+* 登录加提现优化
+* 去除微信圈子组件
+* 分享默认地址优化
+* 新增门店独立首页和搜索页
+* 新增分享及转发使用页面设置的图片开关
+
+
+## v2.2.4(2022-02-16)
+* 商品海报配置优化
+* 博客支持首页展示及优化
+* 新增门店列表和详情
+* 商品支持自定义返回
+* 支持自定义购买模式
+* 适配第三方登录插件
+* 下单支持0元不用选择支付方式
+* 下单页面支持指定时间选择
+* 系统参数读取优化
+
+
+## v2.2.3(2021-12-13)
+* 整体适配H5端
+* 订单、钱包、会员等级支付优化适配
+* 支持(账号、手机、邮箱)登录注册方式
+* 分享逻辑优化全局处理
+* 分销新增上级用户、阶梯返佣提示
+* 新增独立新增错误页面
+* 适配第三方登录插件
+* 支持线下支付自定义信息展示
+* 规格切换购买数量错误修复
+* 富文本详情支持视频、超链接、图片预览
+
+
+## v2.2.2(2021-11-23)
+* 限时秒杀插件支持独立首页
+* 活动配置插件支持优惠价格设定
+* 标签插件
+* 中间广告插件
+* 弹屏广告插件
+* 哀悼插件
+* 文章支持分类页面
+* 博客插件
+* 分销、会员等级增强版、钱包全面支持小程序
+* 用户授权获取用户信息API
+* 可视化索引读取错误修复
+* 支持菜鸟物流查询
+
+
+## v2.2.1(2021-10-24)
+* 支持微信小程序(首页、分类、购物车、用户中心、商品搜索、商品详情、订单确认、授权登陆、订单管理、订单售后、商品收藏、商品足迹、直播、签到、积分商城、多商户、钱包、批发)

+ 86 - 0
common/css/business.css

@@ -0,0 +1,86 @@
+/**
+ * 商品评价
+ */
+.goods-comment-item {
+    padding-bottom: 10rpx;
+}
+.goods-comment-item .avatar {
+    width: 50rpx;
+    height: 50rpx;
+    border-radius: 50%;
+    border: 1px solid #e2e2e2;
+}
+.goods-comment-item .base-nav {
+    width: calc(100% - 90rpx);
+    line-height: 50rpx;
+}
+.goods-comment-item .base-nav text:not(:last-child) {
+    margin-right: 5rpx;
+}
+.goods-comment-item .base-content .content,
+.goods-comment-item .base-content .reply {
+    line-height: 46rpx;
+}
+.goods-comment-item .base-content .images image {
+    width: 100rpx;
+    height: 100rpx;
+}
+.goods-comment-item .base-content .images image:not(:last-child) {
+    margin-right: 10rpx;
+}
+
+/*
+* 面板信息 - 文本
+*/
+.panel-item .panel-content .item:last-child {
+    border: 0 !important;
+    padding-bottom: 0 !important;
+}
+.panel-item .panel-content .item .title {
+    width: 25%;
+}
+.panel-item .panel-content .item .content {
+    width: calc(75% - 44rpx);
+    min-height: 46rpx;
+    word-wrap: break-word;
+    word-break: normal;
+}
+.panel-item .panel-content .item .title,
+.panel-item .panel-content .item .content {
+    line-height: 46rpx;
+}
+.panel-item-only .panel-content .item .content {
+    width: 100%;
+}
+
+/*
+* 面板信息 - 图片
+*/
+.panel-item .panel-content-images .item {
+    margin: 20rpx 20rpx 0 0;
+}
+.panel-item .panel-content-images .item:last-child {
+    margin-right: 0;;
+}
+.panel-item .panel-content-images .item image {
+    width: 120rpx;
+    height: 120rpx !important;
+}
+
+/**
+ * 地址边线
+ */
+.address-divider {
+    height: 4px;
+    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAAAECAYAAADWIIyPAAAAkklEQVR42mP4jwR+7tr1/4OzM1Xwt46O/6SA3Yd//HeLeU0V3DXjE0H7GGCMvw8f/v/o5UUVT39KTPz/78cPoj398Omf/75Jb6ji6ZSyd/9//PxHnMdBjvyUlEQVT4MC7++DB0R7GuTIlPJ3VPE0KPAePvlDlL1gj3/r6qJaEv+5YwdJSbxn5meqJfGdh74TbS8A1dn662xhNdIAAAAASUVORK5CYII=");
+    background-repeat-y: no-repeat;
+}
+
+/**
+ * 支付html弹窗
+ */
+.popup-pay-html-content {
+    max-height: 80vh;
+    overflow-y: scroll;
+    overflow-x: hidden;
+}

+ 259 - 0
common/css/lib.css

@@ -0,0 +1,259 @@
+/**
+ * 公共类样式
+ */
+.margin-0 {
+    margin: 0 !important;
+}
+.margin-xs {
+    margin: 5rpx;
+}
+.margin-sm {
+    margin: 10rpx;
+}
+.margin,
+.margin-default {
+    margin: 15rpx;
+}
+.margin-lg {
+    margin: 20rpx;
+}
+.margin-xl {
+    margin: 25rpx;
+}
+.margin-xxl {
+    margin: 30rpx;
+}
+.margin-xxxl {
+    margin: 40rpx;
+}
+.margin-top-xs {
+    margin-top: 5rpx;
+}
+.margin-top-sm {
+    margin-top: 10rpx;
+}
+.margin-top,
+.margin-top-default {
+    margin-top: 15rpx;
+}
+.margin-top-lg {
+    margin-top: 20rpx;
+}
+.margin-top-xl {
+    margin-top: 25rpx;
+}
+.margin-top-xxl {
+    margin-top: 30rpx;
+}
+.margin-top-xxxl {
+    margin-top: 40rpx;
+}
+.margin-right-xs {
+    margin-right: 5rpx;
+}
+.margin-right-sm {
+    margin-right: 10rpx;
+}
+.margin-right,
+.margin-right-default {
+    margin-right: 15rpx;
+}
+.margin-right-lg {
+    margin-right: 20rpx;
+}
+.margin-right-xl {
+    margin-right: 25rpx;
+}
+.margin-right-xxl {
+    margin-right: 30rpx;
+}
+.margin-right-xxxl {
+    margin-right: 40rpx;
+}
+.margin-left-xs {
+    margin-left: 5rpx;
+}
+.margin-left-sm {
+    margin-left: 10rpx;
+}
+.margin-left,
+.margin-left-default {
+    margin-left: 15rpx;
+}
+.margin-left-lg {
+    margin-left: 20rpx;
+}
+.margin-left-xl {
+    margin-left: 25rpx;
+}
+.margin-left-xxl {
+    margin-left: 30rpx;
+}
+.margin-left-xxxl {
+    margin-left: 40rpx;
+}
+.margin-bottom-xs {
+    margin-bottom: 5rpx;
+}
+.margin-bottom-sm {
+    margin-bottom: 10rpx;
+}
+.margin-bottom,
+.margin-bottom-default {
+    margin-bottom: 15rpx;
+}
+.margin-bottom-lg {
+    margin-bottom: 20rpx;
+}
+.margin-bottom-xl {
+    margin-bottom: 25rpx;
+}
+.margin-bottom-xxl {
+    margin-bottom: 30rpx;
+}
+.margin-bottom-xxxl {
+    margin-bottom: 40rpx;
+}
+
+.padding-0 {
+    padding: 0 !important;
+}
+.padding-xs {
+    padding: 5rpx;
+}
+.padding-sm {
+    padding: 10rpx;
+}
+.padding,
+.padding-default {
+    padding: 15rpx;
+}
+.padding-lg {
+    padding: 20rpx;
+}
+.padding-xl {
+    padding: 25rpx;
+}
+.padding-xxl {
+    padding: 30rpx;
+}
+.padding-xxxl {
+    padding: 40rpx;
+}
+.padding-top-xs {
+    padding-top: 5rpx;
+}
+.padding-top-sm {
+    padding-top: 10rpx;
+}
+.padding-top,
+.padding-top-default {
+    padding-top: 15rpx;
+}
+.padding-top-lg {
+    padding-top: 20rpx;
+}
+.padding-top-xl {
+   padding-top: 25rpx;
+}
+.padding-top-xxl {
+    padding-top: 30rpx;
+}
+.padding-top-xxxl {
+    padding-top: 40rpx;
+}
+.padding-right-xs {
+    padding-right: 5rpx;
+}
+.padding-right-sm {
+    padding-right: 10rpx;
+}
+.padding-right,
+.padding-right-default {
+    padding-right: 15rpx;
+}
+.padding-right-lg {
+    padding-right: 20rpx;
+}
+.padding-right-xl {
+    padding-right: 25rpx;
+}
+.padding-right-xxl {
+    padding-right: 30rpx;
+}
+.padding-right-xxxl {
+    padding-right: 40rpx;
+}
+.padding-left-xs {
+    padding-left: 5rpx;
+}
+.padding-left-sm {
+    padding-left: 10rpx;
+}
+.padding-left,
+.padding-left-default {
+    padding-left: 15rpx;
+}
+.padding-left-lg {
+    padding-left: 20rpx;
+}
+.padding-left-xl {
+    padding-left: 25rpx;
+}
+.padding-left-xxl {
+    padding-left: 30rpx;
+}
+.padding-left-xxxl {
+    padding-left: 40rpx;
+}
+.padding-bottom-xs {
+    padding-bottom: 5rpx;
+}
+.padding-bottom-sm {
+    padding-bottom: 10rpx;
+}
+.padding-bottom,
+.padding-bottom-default {
+    padding-bottom: 15rpx;
+}
+.padding-bottom-lg {
+    padding-bottom: 20rpx;
+}
+.padding-bottom-xl {
+    padding-bottom: 25rpx;
+}
+.padding-bottom-xxl {
+    padding-bottom: 30rpx;
+}
+.padding-bottom-xxxl {
+    padding-bottom: 40rpx;
+}
+
+/**
+ * 字体大小
+ */
+.text-size-xs {
+    font-size: 24rpx !important;
+}
+.text-size-sm {
+    font-size: 26rpx !important;
+}
+.text-size-md {
+    font-size: 28rpx !important;
+}
+.text-size,
+.text-size-default {
+    font-size: 32rpx !important;
+}
+.text-size-lg {
+    font-size: 36rpx !important;
+}
+.text-size-xl {
+    font-size: 42rpx !important;
+}
+.text-size-xxl {
+    font-size: 62rpx !important;
+}
+.text-size-xxxl {
+    font-size: 82rpx !important;
+}

文件差異過大導致無法顯示
+ 847 - 0
common/css/page.css


文件差異過大導致無法顯示
+ 258 - 0
common/css/plugins.css


+ 76 - 0
common/css/theme/black.css

@@ -0,0 +1,76 @@
+/**
+ * 边线 搭配色、次主色、主色
+ */
+.border-color-main-pair {
+    border-color: #009688 !important;
+}
+.border-color-main-light {
+    border-color: #dcdcdc !important;
+}
+.border-color-main {
+    border-color: #333333 !important;
+}
+
+/**
+ * 边框 搭配色、次主色、主色
+ */
+.br-main-pair {
+    border: 1px solid #009688 !important;
+}
+.br-main-light {
+    border: solid 1px #dcdcdc !important;
+}
+.br-main {
+    border: 1px solid #333333 !important;
+}
+
+/**
+ * 虚线边框 搭配色、次主色、主色
+ */
+.br-dashed-main-pair {
+    border: dashed 1px #009688 !important;
+}
+.br-dashed-main-light {
+    border: dashed 1px #dcdcdc !important;
+}
+.br-dashed-main {
+    border: dashed 1px #333333 !important;
+}
+
+/**
+ * 文本颜色 搭配色、次主色、主色
+ */
+.cr-main-pair {
+    color: #009688 !important;
+}
+.cr-main-light {
+    color: #dcdcdc !important;
+}
+.cr-main {
+    color: #333333 !important;
+}
+
+/**
+ * 背景色 搭配色、次主色、主色
+ */
+.bg-main-pair {
+    background-color: #009688 !important;
+}
+.bg-main-light {
+    background-color: #dcdcdc !important;
+}
+.bg-main {
+    background-color: #333333 !important;
+}
+button[disabled].bg-main-pair {
+    background-color: #bdece8 !important;
+    color: #edfbf9 !important;
+}
+button[disabled].bg-main-light {
+    background-color: #efefef !important;
+    color: #b7b7b7 !important;
+}
+button[disabled].bg-main {
+    background-color: #c7c7c7 !important;
+    color: #e2e2e2 !important;
+}

+ 76 - 0
common/css/theme/blue.css

@@ -0,0 +1,76 @@
+/**
+ * 边线 搭配色、次主色、主色
+ */
+.border-color-main-pair {
+    border-color: #d300f7 !important;
+}
+.border-color-main-light {
+    border-color: #d1e4ff !important;
+}
+.border-color-main {
+    border-color: #1677ff !important;
+}
+
+/**
+ * 边框 搭配色、次主色、主色
+ */
+.br-main-pair {
+    border: 1px solid #d300f7 !important;
+}
+.br-main-light {
+    border: solid 1px #d1e4ff !important;
+}
+.br-main {
+    border: 1px solid #1677ff !important;
+}
+
+/**
+ * 虚线边框 搭配色、次主色、主色
+ */
+.br-dashed-main-pair {
+    border: dashed 1px #d300f7 !important;
+}
+.br-dashed-main-light {
+    border: dashed 1px #d1e4ff !important;
+}
+.br-dashed-main {
+    border: dashed 1px #1677ff !important;
+}
+
+/**
+ * 文本颜色 搭配色、次主色、主色
+ */
+.cr-main-pair {
+    color: #d300f7 !important;
+}
+.cr-main-light {
+    color: #d1e4ff !important;
+}
+.cr-main {
+    color: #1677ff !important;
+}
+
+/**
+ * 背景色 搭配色、次主色、主色
+ */
+.bg-main-pair {
+    background-color: #d300f7 !important;
+}
+.bg-main-light {
+    background-color: #d1e4ff !important;
+}
+.bg-main {
+    background-color: #1677ff !important;
+}
+button[disabled].bg-main-pair {
+    background-color: #efcbf5 !important;
+    color: #faf1fb !important;
+}
+button[disabled].bg-main-light {
+    background-color: #e3eefd !important;
+    color: #b9d3f7 !important;
+}
+button[disabled].bg-main {
+    background-color: #bcd3f5 !important;
+    color: #eef4fd !important;
+}

+ 76 - 0
common/css/theme/brown.css

@@ -0,0 +1,76 @@
+/**
+ * 边线 搭配色、次主色、主色
+ */
+.border-color-main-pair {
+    border-color: #08b7a7 !important;
+}
+.border-color-main-light {
+    border-color: #eadcd2 !important;
+}
+.border-color-main {
+    border-color: #8B4513 !important;
+}
+
+/**
+ * 边框 搭配色、次主色、主色
+ */
+.br-main-pair {
+    border: 1px solid #08b7a7 !important;
+}
+.br-main-light {
+    border: solid 1px #eadcd2 !important;
+}
+.br-main {
+    border: 1px solid #8B4513 !important;
+}
+
+/**
+ * 虚线边框 搭配色、次主色、主色
+ */
+.br-dashed-main-pair {
+    border: dashed 1px #08b7a7 !important;
+}
+.br-dashed-main-light {
+    border: dashed 1px #eadcd2 !important;
+}
+.br-dashed-main {
+    border: dashed 1px #8B4513 !important;
+}
+
+/**
+ * 文本颜色 搭配色、次主色、主色
+ */
+.cr-main-pair {
+    color: #08b7a7 !important;
+}
+.cr-main-light {
+    color: #eadcd2 !important;
+}
+.cr-main {
+    color: #8B4513 !important;
+}
+
+/**
+ * 背景色 搭配色、次主色、主色
+ */
+.bg-main-pair {
+    background-color: #08b7a7 !important;
+}
+.bg-main-light {
+    background-color: #eadcd2 !important;
+}
+.bg-main {
+    background-color: #8B4513 !important;
+}
+button[disabled].bg-main-pair {
+    background-color: #a6ded9 !important;
+    color: #dff1ef !important;
+}
+button[disabled].bg-main-light {
+    background-color: #f1e6de !important;
+    color: #d6bdad !important;
+}
+button[disabled].bg-main {
+    background-color: #e4cdbc !important;
+    color: #f9f4f0 !important;
+}

+ 76 - 0
common/css/theme/green.css

@@ -0,0 +1,76 @@
+/**
+ * 边线 搭配色、次主色、主色
+ */
+.border-color-main-pair {
+    border-color: #9933CC !important;
+}
+.border-color-main-light {
+    border-color: #cce8d2 !important;
+}
+.border-color-main {
+    border-color: #20a53a !important;
+}
+
+/**
+ * 边框 搭配色、次主色、主色
+ */
+.br-main-pair {
+    border: 1px solid #9933CC !important;
+}
+.br-main-light {
+    border: solid 1px #cce8d2 !important;
+}
+.br-main {
+    border: 1px solid #20a53a !important;
+}
+
+/**
+ * 虚线边框 搭配色、次主色、主色
+ */
+.br-dashed-main-pair {
+    border: dashed 1px #9933CC !important;
+}
+.br-dashed-main-light {
+    border: dashed 1px #cce8d2 !important;
+}
+.br-dashed-main {
+    border: dashed 1px #20a53a !important;
+}
+
+/**
+ * 文本颜色 搭配色、次主色、主色
+ */
+.cr-main-pair {
+    color: #9933CC !important;
+}
+.cr-main-light {
+    color: #cce8d2 !important;
+}
+.cr-main {
+    color: #20a53a !important;
+}
+
+/**
+ * 背景色 搭配色、次主色、主色
+ */
+.bg-main-pair {
+    background-color: #9933CC !important;
+}
+.bg-main-light {
+    background-color: #cce8d2 !important;
+}
+.bg-main {
+    background-color: #20a53a !important;
+}
+button[disabled].bg-main-pair {
+    background-color: #cfaae2 !important;
+    color: #e6deea !important;
+}
+button[disabled].bg-main-light {
+    background-color: #daeade !important;
+    color: #9dcaa6 !important;
+}
+button[disabled].bg-main {
+    background-color: #a8c5ae !important;
+    color: #d8eadc !important;
+}

+ 76 - 0
common/css/theme/orange.css

@@ -0,0 +1,76 @@
+/**
+ * 边线 搭配色、次主色、主色
+ */
+.border-color-main-pair {
+    border-color: #795548 !important;
+}
+.border-color-main-light {
+    border-color: #fde4d1 !important;
+}
+.border-color-main {
+    border-color: #fe6f04 !important;
+}
+
+/**
+ * 边框 搭配色、次主色、主色
+ */
+.br-main-pair {
+    border: 1px solid #795548 !important;
+}
+.br-main-light {
+    border: solid 1px #fde4d1 !important;
+}
+.br-main {
+    border: 1px solid #fe6f04 !important;
+}
+
+/**
+ * 虚线边框 搭配色、次主色、主色
+ */
+.br-dashed-main-pair {
+    border: dashed 1px #795548 !important;
+}
+.br-dashed-main-light {
+    border: dashed 1px #fde4d1 !important;
+}
+.br-dashed-main {
+    border: dashed 1px #fe6f04 !important;
+}
+
+/**
+ * 文本颜色 搭配色、次主色、主色
+ */
+.cr-main-pair {
+    color: #795548 !important;
+}
+.cr-main-light {
+    color: #fde4d1 !important;
+}
+.cr-main {
+    color: #fe6f04 !important;
+}
+
+/**
+ * 背景色 搭配色、次主色、主色
+ */
+.bg-main-pair {
+    background-color: #795548 !important;
+}
+.bg-main-light {
+    background-color: #fde4d1 !important;
+}
+.bg-main {
+    background-color: #fe6f04 !important;
+}
+button[disabled].bg-main-pair {
+    background-color: #b5a29c !important;
+    color: #8c766f !important;
+}
+button[disabled].bg-main-light {
+    background-color: #fbe9dc !important;
+    color: #f7c49e !important;
+}
+button[disabled].bg-main {
+    background-color: #f7cdad !important;
+    color: #f7efea !important;
+}

+ 76 - 0
common/css/theme/purple.css

@@ -0,0 +1,76 @@
+/**
+ * 边线 搭配色、次主色、主色
+ */
+.border-color-main-pair {
+    border-color: #993399 !important;
+}
+.border-color-main-light {
+    border-color: #d6cbfb !important;
+}
+.border-color-main {
+    border-color: #623cec !important;
+}
+
+/**
+ * 边框 搭配色、次主色、主色
+ */
+.br-main-pair {
+    border: 1px solid #993399 !important;
+}
+.br-main-light {
+    border: solid 1px #d6cbfb !important;
+}
+.br-main {
+    border: 1px solid #623cec !important;
+}
+
+/**
+ * 虚线边框 搭配色、次主色、主色
+ */
+.br-dashed-main-pair {
+    border: dashed 1px #993399 !important;
+}
+.br-dashed-main-light {
+    border: dashed 1px #d6cbfb !important;
+}
+.br-dashed-main {
+    border: dashed 1px #623cec !important;
+}
+
+/**
+ * 文本颜色 搭配色、次主色、主色
+ */
+.cr-main-pair {
+    color: #993399 !important;
+}
+.cr-main-light {
+    color: #d6cbfb !important;
+}
+.cr-main {
+    color: #623cec !important;
+}
+
+/**
+ * 背景色 搭配色、次主色、主色
+ */
+.bg-main-pair {
+    background-color: #993399 !important;
+}
+.bg-main-light {
+    background-color: #d6cbfb !important;
+}
+.bg-main {
+    background-color: #623cec !important;
+}
+button[disabled].bg-main-pair {
+    background-color: #d8aed8 !important;
+    color: #efe4ef !important;
+}
+button[disabled].bg-main-light {
+    background-color: #dcd6f1 !important;
+    color: #b2a7dc !important;
+}
+button[disabled].bg-main {
+    background-color: #bdb0ef !important;
+    color: #e7e4f1 !important;
+}

+ 76 - 0
common/css/theme/red.css

@@ -0,0 +1,76 @@
+/**
+ * 边线 搭配色、次主色、主色
+ */
+.border-color-main-pair {
+    border-color: #3F51B5 !important;
+}
+.border-color-main-light {
+    border-color: #ffdbe2 !important;
+}
+.border-color-main {
+    border-color: #ff0036 !important;
+}
+
+/**
+ * 边框 搭配色、次主色、主色
+ */
+.br-main-pair {
+    border: 1px solid #3F51B5 !important;
+}
+.br-main-light {
+    border: solid 1px #ffdbe2 !important;
+}
+.br-main {
+    border: 1px solid #ff0036 !important;
+}
+
+/**
+ * 虚线边框 搭配色、次主色、主色
+ */
+.br-dashed-main-pair {
+    border: dashed 1px #3F51B5 !important;
+}
+.br-dashed-main-light {
+    border: dashed 1px #ffdbe2 !important;
+}
+.br-dashed-main {
+    border: dashed 1px #ff0036 !important;
+}
+
+/**
+ * 文本颜色 搭配色、次主色、主色
+ */
+.cr-main-pair {
+    color: #3F51B5 !important;
+}
+.cr-main-light {
+    color: #ffdbe2 !important;
+}
+.cr-main {
+    color: #ff0036 !important;
+}
+
+/**
+ * 背景色 搭配色、次主色、主色
+ */
+.bg-main-pair {
+    background-color: #3F51B5 !important;
+}
+.bg-main-light {
+    background-color: #ffdbe2 !important;
+}
+.bg-main {
+    background-color: #ff0036 !important;
+}
+button[disabled].bg-main-pair {
+    background-color: #d0cbca !important;
+    color: #eaeaea !important;
+}
+button[disabled].bg-main-light {
+    background-color: #ffe9ed !important;
+    color: #ffa5b7 !important;
+}
+button[disabled].bg-main {
+    background-color: #ffa7ba !important;
+    color: #fff5f7 !important;
+}

+ 76 - 0
common/css/theme/yellow.css

@@ -0,0 +1,76 @@
+/**
+ * 边线 搭配色、次主色、主色
+ */
+.border-color-main-pair {
+    border-color: #795548 !important;
+}
+.border-color-main-light {
+    border-color: #ffebd2 !important;
+}
+.border-color-main {
+    border-color: #f6c133 !important;
+}
+
+/**
+ * 边框 搭配色、次主色、主色
+ */
+.br-main-pair {
+    border: 1px solid #795548 !important;
+}
+.br-main-light {
+    border: solid 1px #ffebd2 !important;
+}
+.br-main {
+    border: 1px solid #f6c133 !important;
+}
+
+/**
+ * 虚线边框 搭配色、次主色、主色
+ */
+.br-dashed-main-pair {
+    border: dashed 1px #795548 !important;
+}
+.br-dashed-main-light {
+    border: dashed 1px #ffebd2 !important;
+}
+.br-dashed-main {
+    border: dashed 1px #f6c133 !important;
+}
+
+/**
+ * 文本颜色 搭配色、次主色、主色
+ */
+.cr-main-pair {
+    color: #795548 !important;
+}
+.cr-main-light {
+    color: #ffebd2 !important;
+}
+.cr-main {
+    color: #f6c133 !important;
+}
+
+/**
+ * 背景色 搭配色、次主色、主色
+ */
+.bg-main-pair {
+    background-color: #795548 !important;
+}
+.bg-main-light {
+    background-color: #ffebd2 !important;
+}
+.bg-main {
+    background-color: #f6c133 !important;
+}
+button[disabled].bg-main-pair {
+    background-color: #b5a29c !important;
+    color: #8c766f !important;
+}
+button[disabled].bg-main-light {
+    background-color: #fbebd6 !important;
+    color: #ffcc40 !important;
+}
+button[disabled].bg-main {
+    background-color: #fdd178 !important;
+    color: #fff7e7 !important;
+}

+ 82 - 0
common/js/common/base.js

@@ -0,0 +1,82 @@
+export default {
+    methods: {
+        //转义符换成普通字符
+        escape2Html(str) {
+            if (!str) return str;
+            var arrEntities = {
+                'lt': '<',
+                'gt': '>',
+                'nbsp': ' ',
+                'amp': '&',
+                'quot': '"'
+            };
+            return str.replace(/&(lt|gt|nbsp|amp|quot);/ig, function(all, t) {
+                return arrEntities[t];
+            });
+        },
+        //普通字符转换成转义符
+        html2Escape(sHtml) {
+            if (!sHtml) return sHtml;
+            return sHtml.replace(/[<>&"]/g, function(c) {
+                return {
+                    '<': '&lt;',
+                    '>': '&gt;',
+                    '&': '&amp;',
+                    '"': '&quot;'
+                } [c];
+            });
+        },
+        //setData polyfill 勿删!!!   (用于转换后的uniapp的项目能直接使用this.setData()函数)
+        setData: function(obj, callback) {
+            let that = this;
+            const handleData = (tepData, tepKey, afterKey) => {
+                var tepData2 = tepData;
+                tepKey = tepKey.split('.');
+                tepKey.forEach(item => {
+                    if (tepData[item] === null || tepData[item] === undefined) {
+                        let reg = /^[0-9]+$/;
+                        tepData[item] = reg.test(afterKey) ? [] : {};
+                        tepData2 = tepData[item];
+                    } else {
+                        tepData2 = tepData[item];
+                    }
+                });
+                return tepData2;
+            };
+            const isFn = function(value) {
+                return typeof value == 'function' || false;
+            };
+            Object.keys(obj).forEach(function(key) {
+                let val = obj[key];
+                key = key.replace(/\]/g, '').replace(/\[/g, '.');
+                let front, after;
+                let index_after = key.lastIndexOf('.');
+                if (index_after != -1) {
+                    after = key.slice(index_after + 1);
+                    front = handleData(that, key.slice(0, index_after), after);
+                } else {
+                    after = key;
+                    front = that;
+                }
+                if (front.$data && front.$data[after] === undefined) {
+                    Object.defineProperty(front, after, {
+                        get() {
+                            return front.$data[after];
+                        },
+                        set(newValue) {
+                            front.$data[after] = newValue;
+                            that.hasOwnProperty("$forceUpdate") && that.$forceUpdate();
+                        },
+                        enumerable: true,
+                        configurable: true
+                    });
+                    front[after] = val;
+                } else {
+                    that.$set(front, after, val);
+                }
+            });
+            this.$forceUpdate();
+            isFn(callback) && this.$nextTick(callback);
+        }
+    }
+}

+ 47 - 0
common/js/common/share.js

@@ -0,0 +1,47 @@
+export default {
+    data(){
+        return {
+            // 设置默认的分享参数、页面可自定义以下数据
+            // 如果页面不设置share,就触发这个默认的分享
+            // 标题、关键字、描述、地址、参数、封面图片、视频
+            share_info: {
+                title: '',
+                kds: '',
+                desc: '',
+                path: '',
+                query: '',
+                img: '',
+                video: ''
+            }
+        }
+    },
+
+    // 分享给好友
+    onShareAppMessage() {
+        var app = getApp();
+        var share = app.globalData.share_content_handle(this.share_info || {});
+        var data = {
+            title: share.title,
+            desc: share.desc,
+            path: share.path + share.query
+        }
+        if(app.globalData.data.is_share_use_image == 1) {
+            data['imageUrl'] = share.img;
+        }
+        return data;
+    },
+
+    // 分享朋友圈
+    onShareTimeline() {
+        var app = getApp();
+        var share = app.globalData.share_content_handle(this.share_info || {});
+        var data = {
+            title: share.title,
+            query: ((share.query || null) != null && share.query.substr(0, 1) == '?') ? share.query.slice(1) : share.query
+        };
+        if(app.globalData.data.is_share_use_image == 1) {
+            data['imageUrl'] = share.img;
+        }
+        return data;
+    }
+}

文件差異過大導致無法顯示
+ 8 - 0
common/js/lib/base64.js


+ 52 - 0
components/activity-list/activity-list.vue

@@ -0,0 +1,52 @@
+<template>
+    <view>
+        <view v-if="(propConfig || null) != null && (propData || null) != null && propData.length > 0">
+            <block v-for="(floor, index) in propData" :key="index">
+                <block v-if="floor.goods_list.length > 0 && floor.home_data_location == propLocation">
+                    <component-goods-list :propData="floor" propMoreUrlKey="url" :propLabel="propLabel" :propIsAutoPlay="(propConfig.is_home_auto_play || 0) == 1" :propCurrencySymbol="propCurrencySymbol" :propIsCartParaCurve="propIsCartParaCurve"></component-goods-list>
+                </block>
+            </block>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentGoodsList from "../goods-list/goods-list";
+    export default {
+        data() {
+            return {};
+        },
+        components: {
+            componentGoodsList
+        },
+        props: {
+            propCurrencySymbol: {
+                type: String,
+                default: app.globalData.data.currency_symbol
+            },
+            propLocation: {
+            	type: [String,Number],
+            	default: 0
+            },
+            propConfig: {
+            	type: [String,Object],
+            	default: null
+            },
+            propData: {
+            	type: Array,
+            	default: []
+            },
+            propLabel: {
+                type: [Array,Object,String],
+                default: null
+            },
+            propIsCartParaCurve: {
+                type: Boolean,
+                default: false
+            }
+        },
+        methods: {}
+    };
+</script>
+<style>
+</style>

+ 52 - 0
components/badge/badge.vue

@@ -0,0 +1,52 @@
+<template>
+    <view>
+        <view v-if="propNumber != 0" class="am-badge">
+            <view :class="'am-badge-text ' + ((propNumber > 99) ? 'am-badge-text-max' : '')">
+                <text>{{(propNumber > 99) ? '99+' : propNumber}}</text>
+            </view>
+        </view>
+    </view>
+</template>
+<script>
+    export default {
+        data() {
+            return {};
+        },
+        components: {},
+        props: {
+            propNumber: {
+            	type: [Number,String],
+            	default: 0
+            }
+        },
+        methods: {}
+    };
+</script>
+<style>
+    .am-badge {
+        display: inline-block;
+        position: relative;
+        vertical-align: middle;
+    }
+    .am-badge-text {
+        display: inline-block;
+        position: absolute;
+        right: 0;
+        transform: translate(50%, -50%);
+        top: 0px;
+        min-width: 14px;
+        padding: 0;
+        height: 14px;
+        line-height: 14px;
+        text-align: center;
+        background-color: #FF3B30;
+        border-radius: 20px;
+        color: #fff;
+        font-size: 10px;
+        padding: 1px 1px;
+        box-shadow: 0 0 5px rgb(0 0 0 / 60%);
+    }
+    .am-badge-text-max {
+        padding: 1px 2px;
+    }
+</style>

+ 96 - 0
components/binding-list/binding-list.vue

@@ -0,0 +1,96 @@
+<template>
+    <view>
+        <view v-if="((propData || null) != null)" class="plugins-binding-container">
+            <!-- 组合搭配 -->
+            <block v-if="((propData.binding_list || null) != null)">
+                <block v-for="(bv, bi) in propData.binding_list" :key="bi">
+                    <view v-if="((bv.goods || null) != null) && bv.goods.length > 0" class="plugins-binding-list padding-horizontal-main border-radius-main oh spacing-mb">
+                        <view class="spacing-nav-title oh">
+                            <text class="text-wrapper">{{bv.title}}</text>
+                            <view v-if="(bv.estimate_discount_price || 0) != 0" class="estimate-discount-price fr">
+                                <text class="discount-icon cr-white text-size-xs">节省</text>
+                                <text class="cr-green text-size-lg va-m">{{propCurrencySymbol}}{{bv.estimate_discount_price}}</text>
+                            </view>
+                        </view>
+                        <view class="left-content fl">
+                            <component-goods-list :propData="{style_type: 2, goods_list: bv.goods, multiple_items: 2}" :propLabel="propLabel" :propCurrencySymbol="propCurrencySymbol" :propIsAutoPlay="(propData.config.is_auto_play || 0) == 1"></component-goods-list>
+                        </view>
+                        <view class="right-content fr bs-bb padding-left-main tc">
+                            <button type="default" size="mini" class="bg-main br-main cr-white text-size-xs round" :data-value="'/pages/plugins/binding/detail/detail?id='+bv.id" @tap="url_event">{{bv.buy_button_text}}</button>
+                            <view class="sales-price margin-top-sm">{{propCurrencySymbol}}{{bv.estimate_price}}</view>
+                            <view v-if="(bv.estimate_original_price || 0) != 0" class="original-price margin-top-sm">{{propCurrencySymbol}}{{bv.estimate_original_price}}</view>
+                        </view>
+                    </view>
+                </block>
+            </block>
+
+            <!-- 商品关联 -->
+            <view v-if="((propData.relevant_data || null) != null)">
+                <component-goods-list :propData="{title: propData.relevant_data.name, style_type: 2, goods_list: propData.relevant_data.data}" :propLabel="propLabel" :propCurrencySymbol="propCurrencySymbol" :propIsAutoPlay="(propData.config.is_auto_play_relevant || 0) == 1"></component-goods-list>
+            </view>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentGoodsList from "../goods-list/goods-list";
+    export default {
+        data() {
+            return {};
+        },
+        components: {
+            componentGoodsList
+        },
+        props: {
+            propCurrencySymbol: {
+                type: String,
+                default: app.globalData.data.currency_symbol
+            },
+            propData: {
+            	type: [Array,Object],
+            	default: []
+            },
+            propLabel: {
+                type: [Array,Object,String],
+                default: null
+            }
+        },
+        methods: {
+            // url事件
+            url_event(e) {
+                app.globalData.url_event(e);
+            }
+        }
+    };
+</script>
+<style>
+    .plugins-binding-list {
+        background: linear-gradient(to right, rgb(255 235 220), rgb(241 235 255));
+    }
+    .plugins-binding-list .left-content {
+        width: 65%;
+    }
+    .plugins-binding-list .right-content {
+        width: 35%;
+        padding-top: 100rpx;
+    }
+    .plugins-binding-list .estimate-discount-price .discount-icon {
+        border-top-right-radius: 30rpx;
+        border-bottom-left-radius: 30rpx;
+        background-image: linear-gradient(45deg,#a3f9a3,#248828,#8bc34a,#d2374c,#9c27b0);
+        background-size: 400%;
+        animation: gradient 5s ease infinite;
+        padding: 0 16rpx;
+    }
+    @keyframes gradient {
+        0% {
+            background-position: 0% 50%;
+        }
+        50% {
+            background-position: 100% 50%;
+        }
+        100% {
+            background-position: 0% 50%;
+        }
+    }
+</style>

+ 588 - 0
components/blog-comments/blog-comments.vue

@@ -0,0 +1,588 @@
+<template>
+    <view>
+        <view v-if="(data || null) != null && (data_base || null) != null" class="padding-vertical-main">
+            <view class="padding-horizontal-main">
+                <!-- 点赞、评论、分享 -->
+                <view v-if="propType == 'detail'" class="tc padding-vertical-main blog-comments-bottom-container">
+                    <view v-if="(data_base.is_blog_comments_show || 0) == 1" class="item dis-inline-block" :data-value="'/pages/plugins/blog/comments/comments?id='+data.id" @tap="url_event">
+                        <view class="va-m dis-inline-block">
+                            <uni-icons type="chat" size="30rpx" color="#999"></uni-icons>
+                        </view>
+                        <text class="cr-gray va-m text-size-xs">评论({{data.comments_count}})</text>
+                    </view>
+                    <view v-if="(data_base.is_blog_give_thumbs || 0) == 1" class="item dis-inline-block" :data-blogid="data.id" @tap="give_thumbs_event">
+                        <view class="va-m dis-inline-block">
+                            <uni-icons type="hand-up" size="30rpx" :styleClass="'cr-'+((data.is_give_thumbs || 0) == 1 ? 'main' : 'gray')"></uni-icons>
+                        </view>
+                        <text :class="'va-m text-size-xs cr-'+((data.is_give_thumbs || 0) == 1 ? 'main' : 'gray')">点赞({{data.give_thumbs_count}})</text>
+                    </view>
+                    <view class="item dis-inline-block" @tap="popup_share_event">
+                        <view class="va-m dis-inline-block">
+                            <uni-icons type="redo" size="30rpx" color="#999"></uni-icons>
+                        </view>
+                        <text class="cr-gray va-m text-size-xs">分享</text>
+                    </view>
+                </view>
+                <!-- 评论回复表单 -->
+                <view v-if="(data_base.is_blog_comments_add || 0) == 1 && !input_comments_modal_status" class="padding-top-lg margin-bottom-xl oh padding-bottom-xl blog-comments-reply-container">
+                    <image :src="avatar" mode="aspectFill" class="user-avatar fl circle"></image>
+                    <view class="right-base fr">
+                        <view class="bg-white border-radius-main padding-main">
+                            <textarea placeholder="期待您的发言..." placeholder-class="cr-grey" class="wh-auto" :value="input_comments_value" :maxlength="input_comments_length_max" @input="comments_input_event" @blur="comments_input_event"></textarea>
+                        </view>
+                        <view class="margin-top-lg oh">
+                            <image :src="common_static_url+'emoji-icon.png'" mode="aspectFill" class="emoji-icon va-m" @tap="emoji_event"></image>
+                            <view class="fr">
+                                <text class="va-m text-size-xs cr-grey margin-right-lg">剩余{{input_comments_length_value}}字</text>
+                                <button type="default" size="mini" class="bg-main br-main cr-white round text-size-xs va-m" @tap="comments_event">评论</button>
+                            </view>
+                        </view>
+                    </view>
+                </view>
+                <!-- 评论回复内容 -->
+                <view v-if="(data_base.is_blog_comments_show || 0) == 1 && (data.comments_list || null) != null && data.comments_list.length > 0" class="blog-comments-list bg-white border-radius-main margin-bottom-xxxl">
+                    <block v-for="(item, index) in data.comments_list" :key="index">
+                        <view class="item oh padding-horizontal-main padding-top-xxl padding-bottom-xxl text-size-xs">
+                            <image :src="item.user.avatar" mode="aspectFill" class="user-avatar circle fl"></image>
+                            <view class="fr right-content">
+                                <view class="comments-base oh">
+                                    <span class="username cr-base">{{item.user.user_name_view}}</span>
+                                    <span class="cr-grey margin-left-lg">{{item.add_time}}</span>
+                                    <view class="fr blog-comments-right-content-operate">
+                                        <view v-if="(data_base.is_blog_comments_show || 0) == 1" class="item dis-inline-block" :data-index="index" :data-username="item.user.user_name_view" :data-blogcommentsid="item.id" @tap="modal_open_event">
+                                            <view class="va-m dis-inline-block">
+                                                <uni-icons type="chat" size="30rpx" color="#999"></uni-icons>
+                                            </view>
+                                            <text class="cr-gray va-m">回复({{item.comments_count}})</text>
+                                        </view>
+                                        <view v-if="(data_base.is_blog_give_thumbs || 0) == 1" class="item dis-inline-block">
+                                            <view class="va-m dis-inline-block">
+                                                <uni-icons type="hand-up" size="30rpx" :styleClass="'cr-'+((item.is_give_thumbs || 0) == 1 ? 'main' : 'gray')"></uni-icons>
+                                            </view>
+                                            <text :class="'va-m cr-'+((item.is_give_thumbs || 0) == 1 ? 'main' : 'gray')" data-type="1" :data-index="index" :data-blogid="item.blog_id" :data-blogcommentsid="item.id" @tap="give_thumbs_event">点赞({{item.give_thumbs_count}})</text>
+                                        </view>
+                                    </view>
+                                </view>
+                                <view class="margin-top-xs cr-base comments-content">{{item.content}}</view>
+                                <view v-if="(item.reply_comments_list || null) != null && item.reply_comments_list.length > 0" class="reply-blog-comments-list">
+                                    <block v-for="(comments, index2) in item.reply_comments_list" :key="index2">
+                                        <view class="item margin-top-xl padding-bottom-lg oh">
+                                            <image :src="comments.user.avatar" mode="aspectFill" class="user-avatar circle fl"></image>
+                                            <view class="fr right-content">
+                                                <view class="comments-reply-base oh">
+                                                    <span class="username cr-base">{{comments.user.user_name_view}}</span>
+                                                    <span class="cr-grey margin-left-sm">{{comments.add_time}}</span>
+                                                    <view class="fr blog-comments-right-content-operate">
+                                                        <view v-if="(data_base.is_blog_comments_show || 0) == 1" class="item dis-inline-block" :data-index="index" :data-username="comments.user.user_name_view" :data-blogcommentsid="comments.blog_comments_id" :data-replycommentsid="comments.id" @tap="modal_open_event">
+                                                            <view class="va-m dis-inline-block">
+                                                                <uni-icons type="chat" size="30rpx" color="#999"></uni-icons>
+                                                            </view>
+                                                            <text class="cr-gray va-m text-size-xs">回复({{comments.comments_count}})</text>
+                                                        </view>
+                                                        <view v-if="(data_base.is_blog_give_thumbs || 0) == 1" class="item dis-inline-block">
+                                                            <view class="va-m dis-inline-block">
+                                                                <uni-icons type="hand-up" size="30rpx" :styleClass="'cr-'+((comments.is_give_thumbs || 0) == 1 ? 'main' : 'gray')"></uni-icons>
+                                                            </view>
+                                                            <text :class="'va-m cr-'+((comments.is_give_thumbs || 0) == 1 ? 'main' : 'gray')" data-type="2" :data-index="index" :data-indexs="index2" :data-blogid="comments.blog_id" :data-blogcommentsid="comments.id" :data-replycommentsid="comments.blog_comments_id" @tap="give_thumbs_event">点赞({{comments.give_thumbs_count}})</text>
+                                                        </view>
+                                                    </view>
+                                                </view>
+                                                <view v-if="(comments.reply_comments_text || null) != null" class="margin-top-sm border-radius-main padding-main reply-content">{{comments.reply_comments_text}}</view>
+                                                <view class="margin-top-sm cr-base">{{comments.content}}</view>
+                                            </view>
+                                        </view>
+                                    </block>
+                                </view>
+                                <view v-if="(item.comments_count || 0) > 0 && (item.is_comments_list_submit == undefined || item.is_comments_list_submit == 1)" class="margin-top-lg">
+                                    <text :data-index="index" :data-blogid="item.blog_id" :data-blogcommentsid="item.id" @tap="comments_list_reply_event">
+                                        <text v-if="item.is_comments_list_submit == undefined" class="cr-grey">查看全部{{item.comments_count}}条回复</text>
+                                        <text v-else class="cr-grey">查看更多回复</text>
+                                        <text class="arrow-bottom padding-horizontal-main"></text>
+                                    </text>
+                                </view>
+                            </view>
+                        </view>
+                    </block>
+                    <block v-if="((data_base.blog_detail_comments_more_page_number || 0) == 0 && (data.comments_count || 0) > 20) || ((data_base.blog_detail_comments_more_page_number || 0) > 0 && data.comments_count > data_base.blog_detail_comments_more_page_number)">
+                        <view v-if="propType == 'detail'" class="margin-top-xxl tc padding-bottom-xxl">
+                            <text :data-value="'/pages/plugins/blog/comments/comments?id='+data.id" @tap="url_event">
+                                <text class="cr-base fw-b">查看全部{{data.comments_count}}条评论</text>
+                                <text class="arrow-right padding-horizontal-main"></text>
+                            </text>
+                        </view>
+                        <view v-if="propType == 'comments' && (data.is_comments_list_submit == undefined || data.is_comments_list_submit == 1)" class="margin-top-xxl tc padding-bottom-xxl">
+                            <text :data-blogid="data.id" @tap="comments_list_reply_event">
+                                <text class="cr-base fw-b">查看更多评论</text>
+                                <text class="arrow-bottom padding-horizontal-main"></text>
+                            </text>
+                        </view>
+                    </block>
+                </view>
+            </view>
+            <!-- 回复弹窗 -->
+            <view v-if="input_comments_modal_status" class="blog-comments-modal pf">
+                <view class="blog-comments-modal-content bg-white border-radius-main pr">
+                    <view class="tc margin-bottom-lg">
+                        <text>回复 @{{input_comments_modal_username}}</text>
+                        <view class="close pa">
+                            <view @tap.stop="modal_close_event">
+                                <icon type="clear" size="20"></icon>
+                            </view>
+                        </view>
+                    </view>
+                    <textarea placeholder="期待您的发言..." placeholder-class="cr-grey" class="wh-auto br padding-main" :value="input_comments_value" :maxlength="input_comments_length_max" @input="comments_input_event" @blur="comments_input_event"></textarea>
+                    <view class="margin-top-lg oh">
+                        <image :src="common_static_url+'emoji-icon.png'" mode="aspectFill" class="emoji-icon va-m" @tap="emoji_event"></image>
+                        <view class="fr">
+                            <text class="va-m text-size-xs cr-grey margin-right-lg">剩余{{input_comments_length_value}}字</text>
+                            <button type="default" size="mini" class="bg-main br-main cr-white round text-size-xs va-m" @tap="comments_event">评论</button>
+                        </view>
+                    </view>
+                </view>
+            </view>
+
+            <!-- 表情弹窗 -->
+            <component-emoji-popup ref="emoji" v-on:choiceConfirmEvent="emoji_choice_confirm_event"></component-emoji-popup>
+
+            <!-- 分享弹窗 -->
+            <component-share-popup ref="share"></component-share-popup>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    var common_static_url = app.globalData.get_static_url('common');
+    import componentPopup from "../../components/popup/popup";
+    import componentSharePopup from "../../components/share-popup/share-popup";
+    import componentEmojiPopup from "../../components/emoji-popup/emoji-popup";
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                avatar: app.globalData.data.default_user_head_src,
+                user: null,
+                data_base: null,
+                data: null,
+                emoji_list: [],
+                input_comments_value: '',
+                input_comments_cursor: 0,
+                input_comments_length_value: 500,
+                input_comments_length_max: 500,
+                input_comments_modal_status: false,
+                input_comments_modal_index: 0,
+                input_comments_modal_username: '',
+                input_comments_modal_blog_comments_id: 0,
+                input_comments_modal_reply_comments_id: 0
+            };
+        },
+        props: {
+            propType: {
+            	type: String,
+            	default: 'detail'
+            },
+            propData: {
+            	type: [Object,null],
+            	default: null
+            },
+            propDataBase: {
+            	type: [Object,null],
+            	default: null
+            },
+            propEmojiList: {
+            	type: [Array,null],
+            	default: []
+            }
+        },
+        components: {
+            componentPopup,
+            componentSharePopup,
+            componentEmojiPopup
+        },
+
+        // 页面被展示
+        created: function(e) {
+            var avatar = app.globalData.data.default_user_head_src;
+            var user = app.globalData.get_user_cache_info() || null;
+            this.setData({
+                user: user,
+                avatar: (user == null) ? avatar : (user.avatar || avatar),
+                data: this.propData,
+                data_base: this.propDataBase,
+                emoji_list: this.propEmojiList
+            });
+        },
+
+        methods: {
+            // 分享开启弹层
+            popup_share_event(e) {
+                if((this.$refs.share || null) != null) {
+                    this.$refs.share.init();
+                }
+            },
+
+            // 评论弹窗关闭
+            modal_close_event(e) {
+                this.setData({
+                    input_comments_modal_status: false,
+                    input_comments_modal_index: 0,
+                    input_comments_modal_username: '',
+                    input_comments_modal_blog_comments_id: 0,
+                    input_comments_modal_reply_comments_id: 0
+                });
+            },
+
+            // 评论弹窗开启
+            modal_open_event(e) {
+                if(!app.globalData.is_single_page_check()) {
+                    return false;
+                }
+                var user = app.globalData.get_user_info();
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.navigateTo({
+                            url: "/pages/login/login?event_callback=favor_event"
+                        });
+                        return false;
+                    } else {
+                        var index = parseInt(e.currentTarget.dataset.index || 0);
+                        var username = e.currentTarget.dataset.username;
+                        var blog_comments_id = e.currentTarget.dataset.blogcommentsid || 0;
+                        var reply_comments_id = e.currentTarget.dataset.replycommentsid || 0;
+                        this.setData({
+                            input_comments_modal_status: true,
+                            input_comments_modal_index: index,
+                            input_comments_modal_username: username,
+                            input_comments_modal_blog_comments_id: blog_comments_id,
+                            input_comments_modal_reply_comments_id: reply_comments_id
+                        });
+                    }
+                }
+            },
+
+            // 表情选择事件
+            emoji_event() {
+                if(this.input_comments_length_value == 0) {
+                    app.globalData.showToast('已超过最大输入字符限制');
+                    return false;
+                }
+                if((this.$refs.emoji || null) != null) {
+                    this.$refs.emoji.init({emoji_list: this.emoji_list});
+                }
+            },
+            
+            // 评论输入和失去焦点事件
+            comments_input_event(e) {
+                var value = e.detail.value.trim();
+                var length = this.input_comments_length_max-value.length;
+                this.setData({
+                    input_comments_cursor: e.detail.cursor || 0,
+                    input_comments_value: value,
+                    input_comments_length_value: (length <= 0) ? 0 : length
+                });
+            },
+            
+            // 表情选择确认事件
+            emoji_choice_confirm_event(emoji) {
+                var value = this.input_comments_value;
+                var cursor = parseInt(this.input_comments_cursor || 0);
+                if(value != '') {
+                    if(cursor == 0) {
+                        value = emoji+value;
+                    } else {
+                        var first = value.substr(0, cursor);
+                        var last = value.substr(cursor, value.length);
+                        value = first+emoji+last;
+                    }
+                } else {
+                    value = emoji;
+                }
+                var length = this.input_comments_length_max-value.length;
+                this.setData({
+                    input_comments_value: value,
+                    input_comments_length_value: (length <= 0) ? 0 : length
+                });
+            },
+
+            // 获取评论列表
+            comments_list_reply_event(e) {
+                var temp_data = this.data;
+                var page = 1;
+                var index = parseInt(e.currentTarget.dataset.index || 0);
+                var blog_id = e.currentTarget.dataset.blogid;
+                var blog_comments_id = e.currentTarget.dataset.blogcommentsid || 0;
+                if(blog_comments_id == 0) {
+                    if((temp_data['page'] || null) == null) {
+                        temp_data['page'] = 1;
+                    } else {
+                        temp_data['page'] += 1;
+                    }
+                    page = temp_data['page'];
+                } else {
+                    if((temp_data['comments_list'][index]['page'] || null) == null) {
+                        temp_data['comments_list'][index]['page'] = 1;
+                    } else {
+                        temp_data['comments_list'][index]['page'] += 1;
+                    }
+                    page = temp_data['comments_list'][index]['page'];
+                }
+                uni.showLoading({
+                    title: '加载中...'
+                });
+                uni.request({
+                    url: app.globalData.get_request_url("commentsreplylist", "index", "blog"),
+                    method: 'POST',
+                    data: {
+                        blog_id: blog_id,
+                        blog_comments_id: blog_comments_id,
+                        page: page
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        if (res.data.code == 0) {
+                            if(blog_comments_id == 0) {
+                                var temp_list = temp_data['comments_list'] || [];
+                            } else {
+                                var temp_list = temp_data['comments_list'][index]['reply_comments_list'] || [];
+                            }
+                            var data = res.data.data.data;
+                            for (var i in data) {
+                                temp_list.push(data[i]);
+                            }
+                            if(blog_comments_id == 0) {
+                                temp_data['comments_list'] = temp_list;
+                                temp_data['is_comments_list_submit'] = (res.data.data.page >= res.data.data.page_total) ? 0 : 1;
+                            } else {
+                                temp_data['comments_list'][index]['reply_comments_list'] = temp_list;
+                                temp_data['comments_list'][index]['is_comments_list_submit'] = (res.data.data.page >= res.data.data.page_total) ? 0 : 1;
+                            }
+                            this.setData({data: temp_data});
+                        } else {
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 评论
+            comments_event() {
+                if(!app.globalData.is_single_page_check()) {
+                    return false;
+                }
+                var user = app.globalData.get_user_info();
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.navigateTo({
+                            url: "/pages/login/login?event_callback=favor_event"
+                        });
+                        return false;
+                    } else {
+                        if(this.input_comments_value == '') {
+                            app.globalData.showToast('请填写评论内容');
+                            return false;
+                        }
+                        uni.showLoading({
+                            title: '提交中...'
+                        });
+                        uni.request({
+                            url: app.globalData.get_request_url("comments", "index", "blog"),
+                            method: 'POST',
+                            data: {
+                                blog_id: this.data.id,
+                                content: this.input_comments_value,
+                                blog_comments_id: this.input_comments_modal_blog_comments_id,
+                                reply_comments_id: this.input_comments_modal_reply_comments_id
+                            },
+                            dataType: 'json',
+                            success: res => {
+                                uni.hideLoading();
+                                if (res.data.code == 0) {
+                                    var temp_data = this.data;
+                                    if((this.input_comments_modal_blog_comments_id || 0) == 0) {
+                                        var temp_list = temp_data.comments_list || [];
+                                        temp_list.splice(0, 0, res.data.data);
+                                        temp_data['comments_list'] = temp_list;
+                                        temp_data['comments_count'] = parseInt(temp_data['comments_count'])+1;
+                                    } else {
+                                        var index = this.input_comments_modal_index;
+                                        var temp_list = temp_data.comments_list[index]['reply_comments_list'] || [];
+                                        temp_list.splice(0, 0, res.data.data);
+                                        if((this.input_comments_modal_reply_comments_id || 0) != 0) {
+                                            for(var i in temp_list) {
+                                                if(temp_list[i]['id'] == this.input_comments_modal_reply_comments_id) {
+                                                    temp_list[i]['comments_count'] = parseInt(temp_list[i]['comments_count'])+1;
+                                                    break;
+                                                }
+                                            }
+                                        }
+                                        temp_data.comments_list[index]['reply_comments_list'] = temp_list;
+                                        temp_data.comments_list[index]['comments_count'] = parseInt(temp_data.comments_list[index]['comments_count'])+1;
+                                    }
+                                    this.setData({
+                                        data: temp_data,
+                                        input_comments_value: '',
+                                        input_comments_length_value: this.input_comments_length_max,
+                                        input_comments_modal_status: false
+                                    });
+                                } else {
+                                    app.globalData.showToast(res.data.msg);
+                                }
+                            },
+                            fail: () => {
+                                uni.hideLoading();
+                                app.globalData.showToast('服务器请求出错');
+                            }
+                        });
+                    }
+                }
+            },
+
+            // 点赞
+            give_thumbs_event(e) {
+                if(!app.globalData.is_single_page_check()) {
+                    return false;
+                }
+                var user = app.globalData.get_user_info();
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.navigateTo({
+                            url: "/pages/login/login?event_callback=favor_event"
+                        });
+                        return false;
+                    } else {
+                        var type = parseInt(e.currentTarget.dataset.type || 0);
+                        var blog_id = e.currentTarget.dataset.blogid;
+                        var blog_comments_id = e.currentTarget.dataset.blogcommentsid || 0;
+                        var reply_comments_id = e.currentTarget.dataset.replycommentsid || 0;
+                        uni.request({
+                            url: app.globalData.get_request_url("givethumbs", "index", "blog"),
+                            method: 'POST',
+                            data: {
+                                blog_id: blog_id,
+                                blog_comments_id: blog_comments_id,
+                                reply_comments_id: reply_comments_id
+                            },
+                            dataType: 'json',
+                            success: res => {
+                                if (res.data.code == 0) {
+                                    var data = res.data.data;
+                                    var temp_data = this.data;
+                                    switch(type) {
+                                        // 博客
+                                        case 0 :
+                                            temp_data.is_give_thumbs = data.is_active;
+                                            temp_data.give_thumbs_count = data.count;
+                                            break;
+                                        // 博客评论
+                                        case 1 :
+                                            var index = parseInt(e.currentTarget.dataset.index || 0);
+                                            temp_data['comments_list'][index]['is_give_thumbs'] = data.is_active;
+                                            temp_data['comments_list'][index]['give_thumbs_count'] = data.count;
+                                            break;
+                                        // 博客评论回复
+                                        case 2 :
+                                            var index = parseInt(e.currentTarget.dataset.index || 0);
+                                            var indexs = parseInt(e.currentTarget.dataset.indexs || 0);
+                                            temp_data['comments_list'][index]['reply_comments_list'][indexs]['is_give_thumbs'] = data.is_active;
+                                            temp_data['comments_list'][index]['reply_comments_list'][indexs]['give_thumbs_count'] = data.count;
+                                            break;
+                                    }
+                                    this.setData({data: temp_data});
+                                } else {
+                                    if (app.globalData.is_login_check(res.data)) {
+                                        app.globalData.showToast(res.data.msg);
+                                    }
+                                }
+                            },
+                            fail: () => {
+                                app.globalData.showToast('服务器请求出错');
+                            }
+                        });
+                    }
+                }
+            },
+
+            // url事件
+            url_event(e) {
+                app.globalData.url_event(e);
+            }
+        }
+    };
+</script>
+<style>
+    /**
+     * 聚合点赞、评论、分享
+     */
+    .blog-comments-bottom-container .item:not(:last-child) {
+        margin-right: 50rpx;
+    }
+    .blog-comments-reply-container .emoji-icon,
+    .blog-comments-modal .emoji-icon {
+        width: 40rpx;
+        height: 40rpx !important;
+    }
+    .blog-comments-reply-container .user-avatar {
+        width: 100rpx;
+        height: 100rpx !important;
+        border:1px solid #eee;
+    }
+    .blog-comments-reply-container .right-base {
+        width: calc(100% - 130rpx);
+    }
+    .blog-comments-reply-container .right-base textarea {
+        height: 120rpx;
+    }
+    .blog-comments-modal {
+        top: 0;
+        left: 0;
+        width: calc(100% - 80rpx);
+        height: 100%;
+        background: rgba(0, 0, 0, 0.6);
+        padding: 40rpx;
+        z-index: 10;
+    }
+    .blog-comments-modal-content {
+        padding: 10px;
+        border-radius: 10px;
+        margin: 0 auto;
+        margin-top: 30%;
+        max-width: calc(800px - 180rpx);
+    }
+    .blog-comments-modal-content textarea {
+        height: 200rpx;
+    }
+    .blog-comments-modal-content .close {
+        top: 8rpx;
+        right: 14rpx;
+    }
+    
+    /**
+     * 评论列表
+     */
+    .blog-comments-list > .item .user-avatar {
+        width: 50rpx;
+        height: 50rpx;
+        border:1px solid #eee;
+    }
+    .blog-comments-list > .item:not(:last-child) {
+        border-bottom: 1px dashed #f6f6f6;
+    }
+    .blog-comments-list > .item .right-content {
+        width: calc(100% - 70rpx);
+    }
+    .blog-comments-list > .item .right-content .reply-content {
+        background: #f3fafc;
+        border: 1px solid #e5f6ff;
+        color: #617580;
+    }
+    .blog-comments-right-content-operate > .item:not(:last-child) {
+        margin-right: 30rpx;
+    }
+</style>

+ 97 - 0
components/blog-list/blog-list.vue

@@ -0,0 +1,97 @@
+<template>
+    <view>
+        <view v-if="(propConfig || null) != null && (propData || null) != null && propData.length > 0">
+            <block v-for="(floor, index) in propData" :key="index">
+                <block v-if="floor.blog_list.length > 0 && floor.home_data_location == propLocation">
+                    <view class="spacing-nav-title">
+                        <text class="text-wrapper" :style="'color:'+(floor.color || '#333')+';'">{{floor.title}}</text>
+                        <text v-if="(floor.vice_title || null) != null" class="vice-name margin-left-lg cr-gray">{{floor.vice_title}}</text>
+                        <navigator :url="floor.more_url" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr">更多</navigator>
+                    </view>
+                    <view class="wh-auto oh pr">
+                        <view v-if="floor.keywords_arr.length > 0" class="word-list scroll-view-horizontal margin-bottom-lg">
+                            <scroll-view scroll-x>
+                                <block v-for="(kv, ki) in floor.keywords_arr" :key="ki">
+                                    <navigator :url="'/pages/plugins/blog/search/search?keywords=' + kv" hover-class="none" class="word-icon dis-inline-block bg-main-light text-size-xs cr-main round padding-top-xs padding-bottom-xs padding-left padding-right">{{kv}}</navigator>
+                                </block>
+                            </scroll-view>
+                        </view>
+                        <block v-if="floor.blog_list.length > 0">
+                            <!-- 默认图文 -->
+                            <block v-if="(floor.style_type || 0) == 0">
+                                <view class="plugins-blog-list">
+                                    <view v-for="(item, index) in floor.blog_list" :key="index" class="item oh padding-main border-radius-main bg-white spacing-mb">
+                                        <navigator :url="item.url" hover-class="none">
+                                            <image class="blog-img fl radius" :src="item.cover" mode="aspectFill"></image>
+                                            <view class="base fr">
+                                                <view class="single-text text-size">{{item.title}}</view>
+                                                <view class="cr-grey margin-top-sm">{{item.add_time_date_cn}}</view>
+                                                <view class="cr-base text-size-sm multi-text margin-top-sm">{{item.describe}}</view>
+                                            </view>
+                                        </navigator>
+                                    </view>
+                                </view>
+                            </block>
+                            <!-- 九方格 -->
+                            <block v-else-if="floor.style_type == 1">
+                                <view class="plugins-blog-grid-list">
+                                    <view v-for="(item, index) in floor.blog_list" :key="index" class="item oh border-radius-main bg-white spacing-mb">
+                                        <navigator :url="item.url" hover-class="none">
+                                            <image class="blog-img dis-block" :src="item.cover" mode="aspectFit"></image>
+                                            <view class="base padding-horizontal-main margin-top-sm">
+                                                <view class="goods-title multi-text margin-bottom-sm">{{item.title}}</view>
+                                                <view class="cr-grey">{{item.add_time_date_cn}}</view>
+                                            </view>
+                                        </navigator>
+                                    </view>
+                                </view>
+                            </block>
+                            <!-- 滚动 -->
+                            <view v-else-if="floor.style_type == 2" class="rolling-horizontal border-radius-main oh spacing-mb">
+                                <view class="plugins-blog-rolling-list scroll-view-horizontal">
+                                    <swiper :vertical="false" :autoplay="(propConfig.is_home_hot_auto_play || 0) == 1" :circular="false" :display-multiple-items="floor.blog_list.length < 3 ? floor.blog_list.length : 3" interval="3000">
+                                        <block v-for="(item, index) in floor.blog_list" :key="index">
+                                            <swiper-item>
+                                                <view class="item bg-white border-radius-main margin-right-main oh pr ht-auto pr">
+                                                    <navigator :url="item.url" hover-class="none">
+                                                        <image class="blog-img dis-block wh-auto" :src="item.cover" mode="aspectFill"></image>
+                                                        <view class="blog-title pa single-text cr-white padding-horizontal-main padding-top-sm padding-bottom-sm">{{item.title}}</view>
+                                                    </navigator>
+                                                </view>
+                                            </swiper-item>
+                                        </block>
+                                    </swiper>
+                                </view>
+                            </view>
+                        </block>
+                    </view>
+                </block>
+            </block>
+        </view>
+    </view>
+</template>
+<script>
+    export default {
+        data() {
+            return {};
+        },
+        components: {},
+        props: {
+            propLocation: {
+            	type: [String,Number],
+            	default: 0
+            },
+            propConfig: {
+            	type: [String,Object],
+            	default: null
+            },
+            propData: {
+            	type: Array,
+            	default: []
+            }
+        },
+        methods: {}
+    };
+</script>
+<style>
+</style>

+ 48 - 0
components/bottom-line/bottom-line.vue

@@ -0,0 +1,48 @@
+<template>
+    <view>
+        <view v-if="(propStatus || false)" class="data-bottom-line">
+            <view class="left"></view>
+            <view class="msg">{{propMsg || '我是有底线的'}}</view>
+            <view class="right"></view>
+        </view>
+    </view>
+</template>
+<script>
+    export default {
+        data() {
+            return {};
+        },
+        components: {},
+        props: {
+            propStatus: Boolean,
+            propMsg: String
+        },
+        methods: {}
+    };
+</script>
+<style>
+    .data-bottom-line {
+        padding: 40rpx;
+        overflow: hidden;
+    }
+    .data-bottom-line view {
+        width: 33.3%;
+    }
+    .data-bottom-line .left,
+    .data-bottom-line .right {
+        margin-top: 8px;
+        border-bottom: 1px solid #e1e1e1;
+    }
+    .data-bottom-line .msg {
+        color: #999;
+        text-align: center;
+        font-size: 24rpx;
+    }
+    .data-bottom-line .left,
+    .data-bottom-line .msg {
+        float: left;
+    }
+    .data-bottom-line .right {
+        float: right;
+    }
+</style>

+ 103 - 0
components/cart-para-curve/cart-para-curve.vue

@@ -0,0 +1,103 @@
+<template>
+    <view>
+        <view v-if="cart_icon_data != null && (cart_icon_data.status || 0) == 1" class="cart-para-curve-container pf round" :style="cart_icon_data.style">
+            <image v-if="(cart_icon_data.icon || null) != null" class="cart-para-curve-icon round br" :src="cart_icon_data.icon"></image>
+            <view v-else class="cart-para-curve-icon bg-red padding dis-inline-block round br"></view>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    export default {
+        data() {
+            return {
+                cart_icon_data: null
+            };
+        },
+        components: {},
+        props: {
+            propBtnHeight: {
+            	type: Number,
+            	default: 30
+            },
+            propBtnWidth: {
+            	type: Number,
+            	default: 30
+            },
+            propCart: {
+            	type: String,
+            	default: ''
+            },
+        },
+        methods: {
+            // 初始(购物车对象、当前点击对象、图标)
+            init(cart, pos, icon = '') {
+                if((pos || null) != null) {
+                    var self = this;
+                    var btn_size = this.propBtnHeight;
+                    var btn_width = this.propBtnWidth;
+                    // 未指定购物车对象则读取tabbar数据自动计算购物车位置
+                    if((cart || null) == null || (cart[0] || null) == null) {
+                        var info = uni.getSystemInfoSync();
+                        var tabbar = app.globalData.data.tabbar_pages;
+                        // 无购物车菜单则结束执行
+                        var tabbar_cart_pos = tabbar.indexOf('/pages/cart/cart');
+                        if(tabbar_cart_pos == -1) {
+                            return false;
+                        }
+                        // 计算购物车菜单位置
+                        var tabbar_count = tabbar.length;
+                        var cart_top = info.screenHeight;
+                        var cart_width = info.screenWidth/tabbar_count;
+                        var cart_left = cart_width*tabbar_cart_pos;
+                    } else {
+                        var temp = cart[0];
+                        var cart_width = temp.width;
+                        var cart_left = temp.left;
+                        var cart_top = temp.top;
+                    }
+                    var left = pos.changedTouches[0].clientX + btn_width/2 - btn_size/2;
+                    var top = pos.changedTouches[0].clientY - btn_size;
+                    var x = cart_left + cart_width/2 - btn_size/2 - left;
+                    var y = cart_top - btn_size - top;
+                     if(self.cart_icon_data == null || (self.cart_icon_data.status || 0) == 0) {
+                        self.setData({cart_icon_data: {
+                            status: 1,
+                            style: `--left:${left}px;--top:${top}px;--x:${x}px;--y:${y}px;`,
+                            icon: icon,
+                        }});
+                        setTimeout(function(){
+                            self.setData({ cart_icon_data: {status: 0}});
+                        }, 495);
+                    }
+                }
+            }
+        }
+    };
+</script>
+<style>
+    @keyframes moveY {
+        to {
+            transform: translateY(var(--y));
+        }
+    }
+    @keyframes moveX {
+        to {
+            transform: translateX(var(--x));
+        }
+    }
+    .cart-para-curve-container {
+        width: 60rpx;
+        height: 60rpx;
+        z-index: 10;
+        left: var(--left);
+        top: var(--top);
+        --duration: 0.5s;
+        animation: moveY var(--duration) cubic-bezier(0.5, -0.25, 1, 1);
+    }
+    .cart-para-curve-container .cart-para-curve-icon {
+        max-width: 100%;
+        max-height: 100%;
+        animation: moveX var(--duration) linear;
+    }
+</style>

+ 735 - 0
components/cart/cart.vue

@@ -0,0 +1,735 @@
+<template>
+    <view>
+        <view v-if="data_list.length > 0" class="cart-page">
+            <!-- 数据列表 -->
+            <view :class="'padding-horizontal-main padding-top-main '+(source_type != 'cart' ? 'bottom-line-exclude' : '')">
+                <uni-swipe-action>
+                    <view v-for="(item, index) in data_list" :key="index" class="oh border-radius-main bg-white spacing-mb">
+                        <uni-swipe-action-item :right-options="swipe_options" @click="swipe_opt_event" @change="swipe_change($event, index)">
+                            <view :class="'cart-goods-item padding-main pr ' + (common_site_type == 1 ? 'cart-exhibition-mode-data' : '')">
+                                <!-- 选择 -->
+                                <view v-if="common_site_type != 1" @tap="selected_event" data-type="node" :data-index="index" class="fl cart-selected">
+                                    <image v-if="(item.is_error || 0) != 1" class="icon" :src="common_static_url+'select' + ((item.is_error || 0) == 1 ? '-disabled' : ((item.selected || false) ? '-active' : '')) + '-icon.png'" mode="widthFix"></image>
+                                    <text v-if="(item.is_error || 0) == 1" class="cr-grey">失效</text>
+                                </view>
+
+                                <view class="items oh padding-left-sm">
+                                    <view  class="fl">
+                                        <navigator :url="item.goods_url" hover-class="none">
+                                            <!-- 图片 -->
+                                            <image :class="'cart-goods-image fl radius '+((item.is_error || 0) == 1 ? 'opacity' : '')" :src="item.images" mode="aspectFill"></image>
+                                            <!-- 错误 -->
+                                            <view v-if="(item.is_error || 0) == 1" class="error-msg pa tc text-size-xs">
+                                                <text class="cr-red tc bg-white round">{{item.error_msg}}</text>
+                                            </view>
+                                        </navigator>
+                                    </view>
+
+                                    <!-- 基础 -->
+                                    <view class="cart-goods-base fr">
+                                        <!-- 标题、规格 -->
+                                        <navigator :url="item.goods_url" hover-class="none">
+                                            <view :class="'cart-goods-title multi-text margin-bottom-sm '+((item.is_error || 0) == 1 ? 'cr-grey' : '')">{{item.title}}</view>
+                                        </navigator>
+                                        <view v-if="item.spec != null" class="margin-bottom-sm">
+                                            <block v-for="(sv, si) in item.spec" :key="si">
+                                                <text v-if="si > 0" class="cr-grey padding-left-xs padding-right-xs">;</text>
+                                                <text class="cr-gray">{{sv.value}}</text>
+                                            </block>
+                                        </view>
+
+                                        <!-- 底部内容 -->
+                                        <view class="goods-bottom pr margin-top-sm">
+                                            <!-- 价格 -->
+                                            <text class="sales-price">{{currency_symbol}}{{item.price}}</text>
+                                        
+                                            <!-- 数量 -->
+                                            <view v-if="(item.is_error || 0) != 1 && common_site_type != 1" class="cart-number-content pa tc oh round br">
+                                                <view @tap="goods_buy_number_event" class="number-submit tc cr-gray fl va-m" :data-index="index" data-type="0">-</view>
+                                                <input @blur="goods_buy_number_blur" class="tc cr-gray fl va-m bg-white radius-0" type="number" :value="item.stock" :data-index="index">
+                                                <view @tap="goods_buy_number_event" class="number-submit tc cr-gray fl va-m" :data-index="index" data-type="1">+</view>
+                                            </view>
+                                        </view>
+                                    </view>
+                                </view>
+                            </view>
+                        </uni-swipe-action-item>
+                    </view>
+                </uni-swipe-action>
+            </view>
+
+            <!-- 操作导航 -->
+            <!-- 展示型 -->
+            <view v-if="common_site_type == 1" :class="'cart-buy-nav oh wh-auto '+(source_type != 'cart' ? 'bottom-line-exclude' : '')">
+                <view class="cart-exhibition-mode padding-horizontal-main">
+                    <button class="bg-main cr-white round wh-auto text-size-sm" type="default" @tap="exhibition_submit_event" hover-class="none">
+                        <view class="dis-inline-block va-m margin-right-xl">
+                            <uni-icons type="phone" size="14" color="#fff" />
+                        </view>
+                        <text class="va-m">{{common_is_exhibition_mode_btn_text}}</text>
+                    </button>
+                </view>
+            </view>
+            <!-- 销售,自提,虚拟销售 -->
+            <view v-else :class="'cart-buy-nav oh wh-auto br-t bg-white '+(source_type != 'cart' ? 'bottom-line-exclude' : '')">
+                <view class="cart-nav-base fl single-text padding-left">
+                    <view @tap="selected_event" data-type="all" class="fl cart-selected">
+                        <image class="icon va-m" :src="common_static_url+'select' + (is_selected_all ? '-active' : '') + '-icon.png'" mode="widthFix"></image>
+                        <text v-if="!already_selected_status" class="va-m cr-base">全选</text>
+                    </view>
+                    <view v-if="already_selected_status" @tap="cart_all_remove_event" class="cart-nav-remove-submit pa bg-white cr-red br-red round cp">删除</view>
+                    <view class="fr price">
+                        <view class="sales-price single-text fr">{{currency_symbol}}{{total_price}}</view>
+                        <view class="fr">合计:</view>
+                    </view>
+                </view>
+                <view class="fr cart-nav-submit padding-top padding-bottom padding-horizontal-main">
+                    <button class="bg-main cr-white round text-size-lg" type="default" @tap="buy_submit_event" :disabled="!already_selected_status" hover-class="none">结算</button>
+                </view>
+            </view>
+        </view>
+
+        <!-- 空购物车 -->
+        <view v-if="data_list.length == 0 && data_list_loding_status == 0" class="cart-no-data-box tc">
+            <image :src="common_static_url+'cart-empty.png'" mode="widthFix" class="margin-bottom-lg"></image>
+            <view class="cr-grey text-size-sm">{{data_list_loding_msg || '购物车空空如也'}}</view>
+            <navigator class="dis-inline-block" :url="home_page_url" open-type="switchTab" hover-class="none">
+                <button class="bg-main br-main cr-white text-size round margin-top-xxl" type="default" size="mini" hover-class="none">去逛逛</button>
+            </navigator>
+        </view>
+
+        <!-- 提示信息 -->
+        <block v-if="data_list.length == 0 && data_list_loding_status != 0">
+            <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+        </block>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import base64 from '../../common/js/lib/base64.js';
+    import componentNoData from "../../components/no-data/no-data";
+
+    var common_static_url = app.globalData.get_static_url('common');
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                data_bottom_line_status: false,
+                data_list: [],
+                total_price: '0.00',
+                is_selected_all: false,
+                already_selected_status: false,
+                source_type: null,
+                // 基础配置
+                currency_symbol: app.globalData.data.currency_symbol,
+                common_site_type: 0,
+                common_is_exhibition_mode_btn_text: null,
+                common_app_customer_service_tel: null,
+                swipe_item_index: null,
+                swipe_options:[
+                    {
+                        text: '收藏',
+                        style: {
+                            backgroundColor: '#1AAD19'
+                        }
+                    },{
+                        text: '删除',
+                        style: {
+                            backgroundColor: '#E64340'
+                        }
+                    }
+                ],
+                // 首页地址
+                home_page_url: app.globalData.data.tabbar_pages[0]
+            };
+        },
+
+        components: {
+            componentNoData
+        },
+        props: {},
+
+        created: function() {
+            // 数据加载
+            this.init();
+
+            // 初始化配置
+            this.init_config();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.init();
+        },
+
+        methods: {
+            // 初始化配置
+            init_config(status) {
+                if ((status || false) == true) {
+                    this.setData({
+                        currency_symbol: app.globalData.get_config('currency_symbol'),
+                        common_site_type: app.globalData.get_config('config.common_site_type'),
+                        common_is_exhibition_mode_btn_text: app.globalData.get_config('config.common_is_exhibition_mode_btn_text', '立即咨询'),
+                        common_app_customer_service_tel: app.globalData.get_config('config.common_app_customer_service_tel')
+                    });
+                } else {
+                    app.globalData.is_config(this, 'init_config');
+                }
+            },
+
+            // 获取数据
+            init(source_type = null) {
+                this.setData({source_type: source_type});
+                var user = app.globalData.get_user_info(this, "init");
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.stopPullDownRefresh();
+                        uni.showModal({
+                            title: '温馨提示',
+                            content: '绑定手机号码',
+                            confirmText: '确认',
+                            cancelText: '暂不',
+                            success: result => {
+                                if (result.confirm) {
+                                    uni.navigateTo({
+                                        url: "/pages/login/login?event_callback=init"
+                                    });
+                                } else {
+                                    this.setData({
+                                        data_list_loding_status: 0,
+                                        data_bottom_line_status: false,
+                                        data_list_loding_msg: '请绑定手机号码'
+                                    });
+                                }
+                            }
+                        });
+
+                        // 分享菜单处理
+                        app.globalData.page_share_handle();
+                    } else {
+                        this.get_data();
+                    }
+                } else {
+                    uni.stopPullDownRefresh();
+                    this.setData({
+                        data_list_loding_status: 0,
+                        data_bottom_line_status: false,
+                        data_list_loding_msg: '请先授权用户信息'
+                    });
+
+                    // 分享菜单处理
+                    app.globalData.page_share_handle();
+                }
+            },
+
+            // 获取数据
+            get_data() {
+                this.setData({
+                    total_price: '0.00',
+                    is_selected_all: false,
+                    already_selected_status: false
+                });
+                uni.request({
+                    url: app.globalData.get_request_url("index", "cart"),
+                    method: 'POST',
+                    data: {},
+                    dataType: 'json',
+                    success: res => {
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            var data_list = data.data || [];
+                            this.setData({
+                                data_list: data_list,
+                                data_list_loding_status: data_list.length == 0 ? 0 : 3,
+                                data_bottom_line_status: true,
+                                data_list_loding_msg: '购物车空空如也'
+                            });
+
+                            // 导航购物车处理
+                            var cart_total = data.buy_number || 0;
+                            if (cart_total <= 0) {
+                                app.globalData.set_tab_bar_badge(2, 0);
+                            } else {
+                                app.globalData.set_tab_bar_badge(2, 1, cart_total);
+                            }
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 2,
+                                data_bottom_line_status: false,
+                                data_list_loding_msg: res.data.msg
+                            });
+                            if (app.globalData.is_login_check(res.data, this, 'get_data')) {
+                                app.globalData.showToast(res.data.msg);
+                            }
+                        }
+
+                        // 分享菜单处理、延时执行,确保基础数据已加载完成
+                        setTimeout(function() {
+                            app.globalData.page_share_handle();
+                        }, 3000);
+                    },
+                    fail: () => {
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2,
+                            data_bottom_line_status: false,
+                            data_list_loding_msg: '服务器请求出错'
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 数量输入事件
+            goods_buy_number_blur(e) {
+                var index = e.currentTarget.dataset.index || 0;
+                var buy_number = parseInt(e.detail.value) || 1;
+                this.goods_buy_number_func(index, buy_number);
+            },
+
+            // 数量操作事件
+            goods_buy_number_event(e) {
+                var index = e.currentTarget.dataset.index || 0;
+                var type = parseInt(e.currentTarget.dataset.type) || 0;
+                var temp_number = parseInt(this.data_list[index]['stock']);
+                var buy_number = (type == 0) ? temp_number - 1 : temp_number + 1;
+                this.goods_buy_number_func(index, buy_number);
+            },
+
+            // 数量处理方法
+            goods_buy_number_func(index, buy_number) {
+                var temp_data_list = this.data_list;
+                var buy_min_number = parseInt(temp_data_list[index]['buy_min_number']) || 1;
+                var buy_max_number = parseInt(temp_data_list[index]['buy_max_number']) || 0;
+                var inventory = parseInt(temp_data_list[index]['inventory']);
+                var inventory_unit = temp_data_list[index]['inventory_unit'];
+                if (buy_number < buy_min_number) {
+                    buy_number = buy_min_number;
+                    if (buy_min_number > 1) {
+                        app.globalData.showToast('起购' + buy_min_number + inventory_unit);
+                        return false;
+                    }
+                }
+
+                if (buy_max_number > 0 && buy_number > buy_max_number) {
+                    buy_number = buy_max_number;
+                    app.globalData.showToast('限购' + buy_max_number + inventory_unit);
+                    return false;
+                }
+
+                if (buy_number > inventory) {
+                    buy_number = inventory;
+                    app.globalData.showToast('库存数量' + inventory + inventory_unit);
+                    return false;
+                }
+
+                if (temp_data_list[index]['stock'] == 1 && buy_number == 1) {
+                    return false;
+                }
+                
+                // 更新数据库
+                uni.showLoading({
+                    title: '处理中...',
+                    mask: true
+                });
+                uni.request({
+                    url: app.globalData.get_request_url("stock", "cart"),
+                    method: 'POST',
+                    data: {
+                        "id": temp_data_list[index]['id'],
+                        "goods_id": temp_data_list[index]['goods_id'],
+                        "stock": buy_number
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            temp_data_list[index]['stock'] = data.stock;
+                            temp_data_list[index]['original_price'] = data.original_price;
+                            temp_data_list[index]['price'] = data.price;
+                            this.setData({
+                                data_list: temp_data_list
+                            });
+                            
+                            // 选择处理
+                            this.cart_selected_calculate();
+                        } else {
+                            if (app.globalData.is_login_check(res.data)) {
+                                app.globalData.showToast(res.data.msg);
+                            } else {
+                                app.globalData.showToast('提交失败,请重试!');
+                            }
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 收藏+删除
+            goods_favor_delete(id, goods_id, type) {
+                uni.request({
+                    url: app.globalData.get_request_url('favor', 'goods'),
+                    method: 'POST',
+                    data: {
+                        "id": goods_id,
+                        "is_mandatory_favor": 1
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        if (res.data.code == 0) {
+                            this.cart_delete(id, type);
+                        } else {
+                            if (app.globalData.is_login_check(res.data)) {
+                                app.globalData.showToast(res.data.msg);
+                            } else {
+                                app.globalData.showToast('提交失败,请重试!');
+                            }
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+            
+            // 批量删除操作
+            cart_all_remove_event(e) {
+                uni.showModal({
+                    title: '温馨提示',
+                    content: '挑了这么久,真的要删除吗?',
+                    confirmText: '确认',
+                    cancelText: '暂不',
+                    success: result => {
+                        if (result.confirm) {
+                            var data = [];
+                            var temp_data_list = this.data_list || [];
+                            for (var i in temp_data_list) {                
+                                if ((temp_data_list[i]['selected'] || false) == true) {
+                                    data.push(temp_data_list[i]['id']);
+                                }
+                            }
+                            if(data.length <= 0) {
+                                app.globalData.showToast('请先选择数据');
+                                return false;
+                            }
+                            this.cart_delete(data.join(','), 'delete');
+                        }
+                    }
+                });
+            },
+            
+            // 滑动事件
+            swipe_change(e, v) {
+                this.setData({
+                   swipe_item_index:  (e == 'none') ? null : v
+                });
+            },
+
+            // 移除操作事件
+            swipe_opt_event(e) {
+                var index = e.index || 0;
+                var temp_data_list = this.data_list;
+                if(this.swipe_item_index === null) {
+                    app.globalData.showToast("请先滑动要操作的数据");
+                    return false;
+                }
+                if((temp_data_list[this.swipe_item_index] || null) == null) {
+                    app.globalData.showToast("数据不存在");
+                    return false;
+                }
+
+                // 根据操作类型处理数据
+                var id = temp_data_list[this.swipe_item_index]['id'];
+                if (index == 0) {
+                    var goods_id = temp_data_list[this.swipe_item_index]['goods_id'];
+                    this.goods_favor_delete(id, goods_id, 'favor');
+                } else {
+                    this.cart_delete(id, 'delete');
+                }
+            },
+
+            // 购物车删除
+            cart_delete(id, type) {
+                uni.request({
+                    url: app.globalData.get_request_url('delete', 'cart'),
+                    method: 'POST',
+                    data: {
+                        "id": id
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        if (res.data.code == 0) {
+                            var temp_list = [];
+                            var temp_id_arr = id.split(',');
+                            var temp_data_list = this.data_list;
+                            for(var i in temp_data_list) {
+                                if(temp_id_arr.indexOf(temp_data_list[i]['id']) == -1) {
+                                    temp_list.push(temp_data_list[i]);
+                                }
+                            }
+                            this.setData({
+                                data_list: temp_list,
+                                data_list_loding_status: temp_list.length == 0 ? 0 : this.data_list_loding_status
+                            });
+                            app.globalData.showToast(type == 'delete' ? '删除成功' : '收藏成功', 'success');
+
+                            // 选择处理
+                            this.cart_selected_calculate();
+                        } else {
+                            if (app.globalData.is_login_check(res.data)) {
+                                app.globalData.showToast(type == 'delete' ? '删除失败' : '收藏失败');
+                            } else {
+                                app.globalData.showToast('提交失败,请重试!');
+                            }
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 选中处理
+            selected_event(e) {
+                var type = e.currentTarget.dataset.type || null;
+                if (type != null) {
+                    var temp_data_list = this.data_list;
+                    var temp_is_selected_all = this.is_selected_all;
+                    switch (type) {
+                        // 批量操作
+                        case 'all':
+                            temp_is_selected_all = temp_is_selected_all == true ? false : true;
+                            for (var i in temp_data_list) {
+                                if (temp_data_list[i]['is_error'] != 1) {
+                                    temp_data_list[i]['selected'] = temp_is_selected_all;
+                                }
+                            }
+                            break;
+                            // 节点操作
+                        case 'node':
+                            var index = e.currentTarget.dataset.index || 0;
+                            if (temp_data_list[index]['is_error'] != 1) {
+                                temp_data_list[index]['selected'] = temp_data_list[index]['selected'] == true ? false : true;
+                            }
+                            break;
+                    }
+
+                    this.setData({
+                        data_list: temp_data_list,
+                        is_selected_all: temp_is_selected_all
+                    });
+
+                    // 选择处理
+                    this.cart_selected_calculate();
+                }
+            },
+
+            // 选中计算
+            cart_selected_calculate() {
+                var cart_total = 0;
+                var total_price = 0;
+                var data_count = 0;
+                var selected_count = 0;
+                var temp_data_list = this.data_list;
+                for (var i in temp_data_list) {
+                    if ((temp_data_list[i]['is_error'] || 0) == 0) {
+                        data_count++;
+                    }
+                    if ((temp_data_list[i]['selected'] || false) == true) {
+                        total_price += parseInt(temp_data_list[i]['stock']) * parseFloat(temp_data_list[i]['price']);
+                        selected_count++;
+                    }
+                    cart_total += parseInt(temp_data_list[i]['stock']);
+                }
+
+                this.setData({
+                    total_price: total_price.toFixed(2),
+                    already_selected_status: selected_count > 0,
+                    is_selected_all: selected_count > 0 && selected_count >= data_count
+                });
+                if (cart_total <= 0) {
+                    app.globalData.set_tab_bar_badge(2, 0);
+                } else {
+                    app.globalData.set_tab_bar_badge(2, 1, cart_total);
+                }
+            },
+
+            // 结算
+            buy_submit_event(e) {
+                var selected_count = 0;
+                var ids = [];
+                var temp_data_list = this.data_list || [];
+                for (var i in temp_data_list) {
+                    if ((temp_data_list[i]['selected'] || false) == true) {
+                        ids.push(temp_data_list[i]['id']);
+                        selected_count++;
+                    }
+                }
+                if (selected_count <= 0) {
+                    app.globalData.showToast('请先选择商品');
+                    return false;
+                }
+
+                // 进入订单确认页面
+                var data = {
+                    "buy_type": "cart",
+                    "ids": ids.join(',')
+                };
+                uni.navigateTo({
+                    url: '/pages/buy/buy?data=' + encodeURIComponent(base64.encode(JSON.stringify(data)))
+                });
+            },
+
+            // 展示型事件
+            exhibition_submit_event(e) {
+                app.globalData.call_tel(this.common_app_customer_service_tel);
+            }
+        }
+    };
+</script>
+<style>
+    /**
+    * 商品列表
+    */
+    .cart-page {
+        padding-bottom: 100rpx;
+    }
+    .cart-goods-title {
+        line-height: 44rpx;
+        min-height: 86rpx;
+    }
+    .cart-goods-image {
+        width: 155rpx;
+        height: 155rpx;
+    }
+    .cart-goods-base {
+        width: calc(100% - 170rpx);
+    }
+    .cart-goods-item .selected {
+        margin-top: 60rpx;
+    }
+    
+    /**
+     * 错误提示
+     */
+    .cart-goods-item .error-msg {
+        left: 80rpx;
+        top: 78rpx;
+        width: 160rpx;
+        filter: blur(0.3px);
+    }
+    .cart-goods-item .error-msg text {
+        padding: 2rpx 10rpx;
+        box-shadow: 0 2px 10px rgb(181 181 181 / 95%);
+    }
+    
+    /**
+     * 底部
+     */
+    .cart-goods-item .goods-bottom {
+        height: 58rpx;
+    }
+    
+    /**
+    * 数量操作
+    */
+    .cart-number-content {
+        right: 0;
+        top: 0;
+    }
+    .cart-number-content .number-submit {
+        width: 60rpx;
+        font-weight: bold;
+    }
+    .cart-number-content input {
+        width: 30px;
+        border-width: 0 1px;
+        border-style: solid;
+        border-color: #efefef;
+    }
+    .cart-number-content .number-submit,
+    .cart-number-content input {
+        padding: 0;
+        height: 50rpx;
+        line-height: 50rpx;
+    }
+    
+    /**
+    * 空购物车
+    */
+    .cart-no-data-box {
+        padding: 30% 0 0 0;
+    }
+    .cart-no-data-box image {
+        width: 160rpx;
+    }
+    
+    /**
+    * 操作导航
+    */
+    .cart-buy-nav {
+        position: fixed;
+        z-index: 2;
+        left: 0;
+        bottom: 0;
+        /* #ifdef H5 || APP */
+        bottom: var(--window-bottom);
+        /* #endif */
+    }
+    .cart-buy-nav,
+    .cart-nav-base {
+        height: 100rpx;
+        line-height: 100rpx;
+    }
+    .cart-nav-submit button {
+        height: 72rpx;
+        line-height: 72rpx;
+    }
+    .cart-nav-base {
+        width: calc(75% - 20rpx);
+    }
+    .cart-nav-submit {
+        width: calc(25% - 40rpx);
+    }
+    .cart-nav-submit button {
+        border-radius: 0;
+    }
+    .cart-selected .icon {
+        width: 35rpx;
+        height: 35rpx !important;
+        margin: 0 10rpx;
+    }
+    .cart-buy-nav .price {
+        width: calc(100% - 140rpx);
+    }
+    .cart-buy-nav .sales-price {
+        max-width: calc(100% - 40px);
+    }
+    .cart-nav-remove-submit {
+        top: 38rpx;
+        left: 76rpx;
+        padding: 0rpx 20rpx;
+        line-height: 36rpx;
+    }
+    
+    /*
+    * 展示型
+    */
+    .cart-exhibition-mode button {
+        line-height: 80rpx;
+    }
+    .cart-exhibition-mode-data .items {
+        padding-left: 0;
+    }
+    .cart-exhibition-mode-data .error-msg {
+        left: 26rpx;
+    }
+</style>

+ 31 - 0
components/copyright/copyright.vue

@@ -0,0 +1,31 @@
+<template>
+    <view>
+        <view class="copyright">
+            <view class="text">Powered by ShopXO {{version}}</view>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    export default {
+        data() {
+            return {
+                version: app.globalData.data.version
+            };
+        },
+        components: {},
+        props: {},
+        methods: {}
+    };
+</script>
+<style>
+    .copyright {
+        color: #cfcfcf;
+        text-align: center;
+        padding: 20rpx 0;
+    }
+    .copyright .text {
+        font-size: 26rpx;
+        font-weight: 400;
+    }
+</style>

+ 212 - 0
components/countdown/countdown.vue

@@ -0,0 +1,212 @@
+<template>
+    <view>
+        <view class="countdown" v-if="is_show && !is_end">
+            <block v-if="propMsecShow">
+                <view class="time" :style="time_style">{{msec}}</view>
+                <view class="ds" :style="ds_style">{{propSecondDs}}</view>
+            </block>
+            <view class="time" :style="time_style">{{second}}</view>
+            <view class="ds" :style="ds_style">{{propMinuteDs}}</view>
+            <view class="time" :style="time_style">{{minute}}</view>
+            <view class="ds" :style="ds_style">{{propHourDs}}</view>
+            <view class="time" :style="time_style">{{hour}}</view>
+        </view>
+        <view v-if="is_show && is_end" class="timer-title">{{propMsg}}</view>
+    </view>
+</template>
+<script>
+    export default {
+        data() {
+            return {
+                hour: '00',
+                minute: '00',
+                second: '00',
+                msec: 0,
+                is_show: true,
+                is_end: false,
+                timer: null,
+                timers: null,
+                time_style: '',
+                ds_style: '',
+            };
+        },
+        components: {},
+        props: {
+            propHour: {
+				type: [String,Number],
+				default: '00'
+			},
+            propMinute: {
+				type: [String,Number],
+				default: '00'
+			},
+            propSecond: {
+				type: [String,Number],
+				default: '00'
+			},
+            propEndShow: {
+				type: Boolean,
+				default: false
+			},
+            propMsecShow: {
+            	type: Boolean,
+            	default: false
+            },
+            propMsg: {
+				type: String,
+				default: '已结束'
+			},
+            propHourDs: {
+            	type: String,
+            	default: ':'
+            },
+            propMinuteDs: {
+            	type: String,
+            	default: ':'
+            },
+            propSecondDs: {
+            	type: String,
+            	default: ':'
+            },
+            propTimePadding: {
+            	type: [Number,String],
+            	default: 8
+            },
+            propTimeSize: {
+            	type: [Number,String],
+            	default: 24
+            },
+            propTimeBackgroundColor: {
+            	type: String,
+            	default: '#F80001'
+            },
+            propTimeColor: {
+            	type: String,
+            	default: '#FFF'
+            },
+            propTimeWeight: {
+            	type: [Number,String],
+            	default: '400'
+            },
+            propDsColor: {
+            	type: String,
+            	default: '#4B5459'
+            },
+            propDsSize: {
+            	type: [Number,String],
+            	default: 24
+            },
+            propDsWeight: {
+            	type: [Number,String],
+            	default: '400'
+            }
+        },
+        created: function(e) {
+            // 样式拼接
+            this.time_style = 'padding: 0 '+this.propTimePadding+'rpx;background-color:'+this.propTimeBackgroundColor+';color:'+this.propTimeColor+';font-size:'+this.propTimeSize+'rpx;font-weight:'+this.propTimeWeight;
+            this.ds_style = 'color:'+this.propDsColor+';font-size:'+this.propDsSize+'rpx;font-weight:'+this.propDsWeight;
+            
+            // 参数处理
+            this.hour = this.propHour;
+            this.minute = this.propMinute;
+            this.second = this.propSecond;
+
+            // 定时处理
+        	this.countdown()
+        },
+        // #ifndef VUE2
+        destroyed() {
+        	clearInterval(this.timer);
+            clearInterval(this.timers);
+        },
+        // #endif
+        // #ifdef VUE3
+        unmounted() {
+        	clearInterval(this.timer);
+            clearInterval(this.timers);
+        },
+
+        // #endif
+        methods: {
+            // 倒计时处理
+            countdown() {
+                // 销毁之前的任务
+                clearInterval(this.timer);
+                clearInterval(this.timers);
+            
+                // 秒
+                var self = this;
+                var hour = parseInt(self.hour);
+                var minute = parseInt(self.minute);
+                var second = parseInt(self.second);
+                self.timer = setInterval(function() {
+                    if (second <= 0) {
+                        if (minute > 0) {
+                            minute--;
+                            second = 59;
+                        } else if (hour > 0) {
+                            hour--;
+                            minute = 59;
+                            second = 59;
+                        }
+                    } else {
+                        second--;
+                    }
+        
+                    self.hour = hour < 10 ? '0' + hour : hour;
+                    self.minute = minute < 10 ? '0' + minute : minute;
+                    self.second = second < 10 ? '0' + second : second;  
+                    if(self.propHour <= 0 && self.propMinute <= 0 && self.propSecond <= 0) {
+                        // 停止时间
+                        clearInterval(self.timer);
+                        clearInterval(self.timers);
+                        self.is_end = true;
+        
+                        // 活动已结束、是否结束还展示
+                        if(!self.propEndShow) {
+                            self.is_show = false;
+                        }
+                    }
+                }, 1000);
+                
+                // 毫秒
+                var count = 0;
+                self.timers = setInterval(function() {
+                    count++;
+                    self.msec = count;
+                    if(count > 9) {
+                        count = 0;
+                    }
+                    if(!self.is_show) {
+                        clearInterval(self.timers);
+                    }
+                }, 100);
+            }
+        }
+    };
+</script>
+<style>
+    .countdown {
+        line-height: 38rpx;
+    }
+    .countdown view {
+        float: right;
+    }
+    .countdown .timer-title {
+        color: #666;
+        margin-right: 10rpx;
+    }
+    .countdown .time {
+        padding: 0 8rpx;
+        -moz-border-radius: 8rpx;
+        border-radius: 8rpx;
+        background-color: #F80001;
+        color: #fff;
+        min-width: 40rpx;
+        text-align: center;
+    }
+    .countdown .ds {
+        color: #4B5459;
+        padding: 0 8rpx;
+    }
+</style>

+ 94 - 0
components/emoji-popup/emoji-popup.vue

@@ -0,0 +1,94 @@
+<template>
+    <view>
+        <component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event">
+            <view class="emoji-popup bg-white">
+                <view class="close fr oh">
+                    <view class="fr" @tap.stop="popup_close_event">
+                        <icon type="clear" size="20"></icon>
+                    </view>
+                </view>
+                <view class="emoji-popup-content oh tc">
+                    <block v-if="emoji_list.length > 0">
+                        <block v-for="(item, index) in emoji_list" :key="index">
+                            <view class="emoji-item fl bs-bb text-size-xxxl" @tap="choice_confirm_event" :data-value="item.emoji">{{item.emoji}}</view>
+                        </block>
+                    </block>
+                </view>
+            </view>
+        </component-popup>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    var common_static_url = app.globalData.get_static_url('common');
+    import componentPopup from "../../components/popup/popup";
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                popup_status: false,
+                emoji_list: []
+            };
+        },
+
+        components: {
+            componentPopup
+        },
+
+        created: function() {},
+
+        methods: {
+            // 初始配置
+            init(config = {}) {
+                if(!app.globalData.is_single_page_check()) {
+                    return false;
+                }
+                this.setData({
+                    popup_status: config.status == undefined ? true : config.status,
+                    emoji_list: config.emoji_list || [],
+                });
+            },
+
+            // 弹层关闭
+            popup_close_event(e) {
+                this.setData({
+                    popup_status: false
+                });
+            },
+
+            // 选择确认事件
+            choice_confirm_event(e) {            
+                // 关闭弹窗
+                this.setData({
+                    popup_status: false
+                });
+            
+                // 调用父级
+                this.$emit('choiceConfirmEvent', e.currentTarget.dataset.value);
+            }
+        }
+    };
+</script>
+<style>
+    .emoji-popup {
+        padding: 20rpx 10rpx 0 10rpx;
+        position: relative;
+    }
+    .emoji-popup .close {
+        position: absolute;
+        top: 20rpx;
+        right: 20rpx;
+        z-index: 2;
+    }
+    .emoji-popup-content {
+        max-height: 50vh;
+        overflow-y: scroll;
+        overflow-x: hidden;
+        margin-top: 20rpx;
+    }
+    .emoji-popup-content .emoji-item {
+        height: 130rpx;
+        line-height: 130rpx;
+        width: 25%;
+    }
+</style>

+ 498 - 0
components/goods-batch-buy/goods-batch-buy.vue

@@ -0,0 +1,498 @@
+<template>
+    <view>
+        <component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event">
+            <view class="bg-white">
+                <view class="close oh padding-horizontal-main padding-top-main">
+                    <view class="fr" @tap.stop="popup_close_event">
+                        <icon type="clear" size="20"></icon>
+                    </view>
+                </view>
+                <view class="plugins-batchbuy-container oh">
+                    <block v-if="(goods || null) != null && (batchbuy_data || null) != null && (batchbuy_data.goods_spec_data || null) != null && batchbuy_data.goods_spec_data.length > 0">
+                        <block v-if="batchbuy_data.is_only_level_one == 0">
+                            <view class="left-nav pa bg-base">
+                                <scroll-view :scroll-y="true" class="ht-auto">
+                                    <block v-for="(item, index) in batchbuy_data.goods_spec_data" :key="index">
+                                        <view :class="'padding-top-xxl padding-bottom-xxl tc cp oh pr ' + (nav_active_index == index ? 'bg-white cr-main' : '')" :data-index="index" @tap="nav_event">
+                                            <image v-if="(item.images || null) != null" class="dis-inline-block va-m radius margin-right spec-images" :src="item.images" mode="widthFix"></image>
+                                            <text class="text-size-xs cr-base va-m">{{item.name}}</text>
+                                            <view v-if="(item.badge_total || 0) > 0" class="badge-icon pa">
+                                                <component-badge :propNumber="item.badge_total"></component-badge>
+                                            </view>
+                                        </view>
+                                    </block>
+                                </scroll-view>
+                            </view>
+                            <view class="right-conent ht-auto fr padding-main bs-bb">
+                                <scroll-view :scroll-y="true" class="ht-auto">
+                                    <block v-for="(item, index) in batchbuy_data.goods_spec_data[nav_active_index]['data']" :key="index">
+                                        <view :class="'oh padding-vertical-main '+(index > 0 ? 'br-t' : '')">
+                                            <view class="fl item-left">
+                                                <view class="text-size-xs">{{item.name}}</view>
+                                                <view class="sales-price text-size-xs">{{currency_symbol}}{{item.base.price}}</view>
+                                            </view>
+                                            <view class="tc oh round fr item-right text-size-xs">
+                                                <view @tap="batchbuy_goods_buy_number_event" class="number-submit tc cr-gray fl va-m" data-type="0" :data-index="index">-</view>
+                                                <input @blur="batchbuy_goods_buy_number_blur" class="tc cr-gray bg-white fl va-m radius-0" type="number" :value="(item.buy_number || 0)" :data-index="index">
+                                                <view @tap="batchbuy_goods_buy_number_event" class="number-submit tc cr-gray fl va-m" data-type="1" :data-index="index">+</view>
+                                            </view>
+                                        </view>
+                                    </block>
+                                </scroll-view>
+                            </view>
+                        </block>
+                        <block v-else>
+                            <view class="right-conent ht-auto padding-main bs-bb right-conent-only-level-one">
+                                <scroll-view :scroll-y="true" class="ht-auto">
+                                    <block v-for="(item, index) in batchbuy_data.goods_spec_data" :key="index">
+                                        <view :class="'oh padding-vertical-main '+(index > 0 ? 'br-t' : '')">
+                                            <view class="fl item-left">
+                                                <view>
+                                                    <image v-if="(item.images || null) != null" class="dis-inline-block va-m radius margin-right spec-images" :src="item.images" mode="widthFix"></image>
+                                                    <text class="text-size-xs va-m">{{item.name}}</text>
+                                                </view>
+                                                <view class="sales-price text-size-xs">{{currency_symbol}}{{item.base.price}}</view>
+                                            </view>
+                                            <view class="tc oh round fr item-right text-size-xs margin-top-xs">
+                                                <view @tap="batchbuy_goods_buy_number_event" class="number-submit tc cr-gray fl va-m" data-type="0" :data-index="index">-</view>
+                                                <input @blur="batchbuy_goods_buy_number_blur" class="tc cr-gray bg-white fl va-m radius-0" type="number" :value="(item.buy_number || 0)" :data-index="index">
+                                                <view @tap="batchbuy_goods_buy_number_event" class="number-submit tc cr-gray fl va-m" data-type="1" :data-index="index">+</view>
+                                            </view>
+                                        </view>
+                                    </block>
+                                </scroll-view>
+                            </view>
+                        </block>
+                        <view class="confirm-submit pa wh-auto bottom-line-exclude bg-white padding-top-main">
+                            <view class="oh padding-horizontal-main padding-bottom-main cr-grey">
+                                <text class="text-size-xs">
+                                    <text>已选</text>
+                                    <text class="cr-red padding-left-xs padding-right-xs">{{base_data.kind}}</text>
+                                    <text>种</text>
+                                    <text class="cr-red padding-left-xs padding-right-xs">{{base_data.quantity}}</text>
+                                    <text>{{goods.inventory_unit}}</text>
+                                </text>
+                                <text class="text-size-xs fr">金额:<text class="fw-b sales-price">{{currency_symbol}}{{base_data.amount_money}}</text></text>
+                            </view>
+                            <view v-if="(buy_button.data || null) != null && buy_button.data.length > 0" class="padding-bottom-main">
+                                <view :class="'oh buy-nav-btn-number-' + buy_button.count || 0">
+                                    <block v-for="(item, index) in buy_button.data" :key="index">
+                                        <view v-if="(item.name || null) != null && (item.type || null) != null" class="item fl bs-bb padding-horizontal-main">
+                                            <button :class="'cr-white round text-size-sm bg-' + ((item.color || 'main') == 'main' ? 'main' : 'main-pair')" type="default" @tap="confirm_event" :data-type="item.type" hover-class="none">{{item.name}}</button>
+                                        </view>
+                                    </block>
+                                </view>
+                            </view>
+                        </view>
+                    </block>
+                    <block v-else>
+                        <view class="cr-grey tc padding-top-xl padding-bottom-xxxl">无相关信息</view>
+                    </block>
+                </view>
+            </view>
+        </component-popup>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import base64 from '../../common/js/lib/base64.js';
+    import componentPopup from "../../components/popup/popup";
+    import componentBadge from "../../components/badge/badge";
+    export default {
+        data() {
+            return {
+                currency_symbol: app.globalData.get_config('currency_symbol', app.globalData.data.currency_symbol),
+                popup_status: false,
+                nav_active_index: 0,
+                goods: null,
+                buy_button: null,
+                batchbuy_data: null,
+                back_data: null,
+                base_data: {
+                    kind: 0,
+                    quantity: 0,
+                    amount_money: '0.00',
+                }
+            };
+        },
+
+        components: {
+            componentPopup,
+            componentBadge
+        },
+
+        created: function() {},
+
+        methods: {
+            // 初始化
+            init(goods = null, batchbuy_data = null, buy_button = null, back_data = null) {
+                if(!app.globalData.is_single_page_check()) {
+                    return false;
+                }
+                this.setData({
+                    popup_status: true,
+                    goods: goods || null,
+                    batchbuy_data: batchbuy_data || null,
+                    buy_button: buy_button || null,
+                    back_data: back_data,
+                });
+            },
+
+            // 弹层关闭
+            popup_close_event(e) {
+                this.setData({
+                    popup_status: false
+                });
+            },
+
+            // 弹层导航切换
+            nav_event(e) {
+                this.setData({
+                    nav_active_index: e.currentTarget.dataset.index
+                });
+            },
+
+            // 商品批量下单数量操作事件
+            batchbuy_goods_buy_number_event(e) {
+                var type = e.currentTarget.dataset.type;
+                var index = e.currentTarget.dataset.index;
+                var temp_data = this.batchbuy_data
+                var temp_spec_data = (parseInt(temp_data.is_only_level_one || 0) == 1) ? temp_data.goods_spec_data[index] : temp_data.goods_spec_data[this.nav_active_index]['data'][index];
+                var number = parseInt(temp_spec_data.buy_number || 0);
+                var min = parseInt(temp_spec_data.base.buy_min_number || 0);
+                // 首次增加使用起购数量
+                number = (type == 0) ? number-1 : ((number == 0 && min > 0) ? min : number+1);
+                this.batch_goods_buy_number_handle(temp_data, temp_spec_data, index, number);
+            },
+
+            // 商品批量下单数量输入事件
+            batchbuy_goods_buy_number_blur(e) {
+                var number = parseInt(e.detail.value) || 0;
+                var index = e.currentTarget.dataset.index;
+                var temp_data = this.batchbuy_data
+                var temp_spec_data = (parseInt(temp_data.is_only_level_one || 0) == 1) ? temp_data.goods_spec_data[index] : temp_data.goods_spec_data[this.nav_active_index]['data'][index];
+                if(isNaN(number)) {
+                    number = 0;
+                }
+                this.batch_goods_buy_number_handle(temp_data, temp_spec_data, index, number);
+            },
+
+            // 商品批量下单数量处理
+            batch_goods_buy_number_handle(temp_data, temp_spec_data, index, number) {
+                var min = parseInt(temp_spec_data.base.buy_min_number || 0);
+                var max = parseInt(temp_spec_data.base.buy_max_number || 0);
+                var inventory = parseInt(temp_spec_data.base.inventory || 0);
+                var inventory_unit = this.goods.inventory_unit;
+
+                // 是否负数
+                if(number < 0)
+                {
+                    number = 0;
+                }
+                // 不能小于起购数则0
+                if(number > 0 && min > 0 && number < min)
+                {
+                    number = 0;
+                    app.globalData.showToast('起购' + min + inventory_unit);
+                }
+                // 不能超过最大限购
+                if(max > 0 && number > max)
+                {
+                    number = max;
+                    app.globalData.showToast('限购' + max + inventory_unit);
+                }
+                // 不能超过库存
+                if(number > inventory)
+                {
+                    number = inventory;
+                    app.globalData.showToast('库存数量' + inventory + inventory_unit);
+                }
+                temp_spec_data['buy_number'] = number;
+                if(parseInt(temp_data.is_only_level_one || 0) == 1) {
+                    temp_data.goods_spec_data[index] = temp_spec_data;
+                } else {
+                    temp_data.goods_spec_data[this.nav_active_index]['data'][index] = temp_spec_data
+                }
+
+                // 非仅一级则处理一级总数
+                if(parseInt(temp_data.is_only_level_one || 0) != 1)
+                {
+                    var badge_total = 0;
+                    temp_data.goods_spec_data[this.nav_active_index]['data'].forEach(item => {
+                        var temp_badge = parseInt(item.buy_number || 0);
+                        if(temp_badge > 0) {
+                            badge_total += temp_badge;
+                        }
+                    });
+                    temp_data.goods_spec_data[this.nav_active_index]['badge_total'] = badge_total;
+                }
+
+                // 总数、汇总
+                var stock_total = 0;
+                var kind_total = 0;
+                var amount_money_total = 0;
+                temp_data.goods_spec_data.forEach(item => {
+                    if(parseInt(temp_data.is_only_level_one || 0) == 1) {
+                        var temp_stock = parseInt(item.buy_number || 0);
+                        if(temp_stock > 0) {
+                            stock_total += temp_stock;
+                            kind_total += 1;
+                            amount_money_total += temp_stock*parseFloat(item.base.price);
+                        }
+                    } else {
+                        item.data.forEach(item2 => {
+                            var temp_stock = parseInt(item2.buy_number || 0);
+                            if(temp_stock > 0) {
+                                stock_total += temp_stock;
+                                kind_total += 1;
+                                amount_money_total += temp_stock*parseFloat(item2.base.price);
+                            }
+                        });
+                    }
+                });
+
+                // 设置数据
+                this.setData({
+                    batchbuy_data: temp_data,
+                    base_data: {
+                        kind: kind_total,
+                        quantity: stock_total,
+                        amount_money: app.globalData.price_two_decimal(amount_money_total)
+                    }
+                });
+
+                // 下单数据
+                var goods_data = [];
+                var goods_id = this.goods.id;
+                temp_data.goods_spec_data.forEach(item => {
+                    if(parseInt(temp_data.is_only_level_one || 0) == 1) {
+                        goods_data.push({
+                            id: goods_id,
+                            stock: stock_total,
+                            spec: item.spec || ''
+                        });
+                    } else {
+                        item.data.forEach(item2 => {
+                            goods_data.push({
+                                id: goods_id,
+                                stock: stock_total,
+                                spec: item2.spec || ''
+                            });
+                        });
+                    }
+                });
+
+                // 数量更新获取最新数据
+                uni.request({
+                    url: app.globalData.get_request_url('stock', 'goods'),
+                    method: 'POST',
+                    data: {goods_data: goods_data},
+                    dataType: 'json',
+                    success: res => {
+                        if (res.data.code == 0) {
+                            res.data.data.forEach(item => {
+                                if(item.code == 0)
+                                {
+                                    for(var i1 in temp_data.goods_spec_data) {
+                                        if(parseInt(temp_data.is_only_level_one || 0) == 1) {
+                                            temp_data.goods_spec_data[i1].base.price = item.data.spec_base.price;
+                                            temp_data.goods_spec_data[i1].base.original_price = item.data.spec_base.original_price;
+                                            temp_data.goods_spec_data[i1].base.inventory = item.data.spec_base.inventory;
+                                        } else {
+                                            for(var i2 in temp_data.goods_spec_data[i1].data) {
+                                                if(temp_data.goods_spec_data[i1].data[i2].base.id == item.data.spec_base.id) {
+                                                    temp_data.goods_spec_data[i1].data[i2].base.price = item.data.spec_base.price;
+                                                    temp_data.goods_spec_data[i1].data[i2].base.original_price = item.data.spec_base.original_price;
+                                                    temp_data.goods_spec_data[i1].data[i2].base.inventory = item.data.spec_base.inventory;
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            });
+                            this.setData({
+                                batchbuy_data: temp_data
+                            });
+                        } else {
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 确认事件
+            confirm_event(e) {
+                var user = app.globalData.get_user_info(this, 'confirm_event');
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.navigateTo({
+                            url: "/pages/login/login?event_callback=confirm_event"
+                        });
+                        return false;
+                    } else {
+                        // 获取数据
+                        var goods_data = [];
+                        var goods_id = this.goods.id;
+                        this.batchbuy_data.goods_spec_data.forEach(item => {
+                            if(parseInt(this.batchbuy_data.is_only_level_one || 0) == 1) {
+                                var buy_number = parseInt(item.buy_number || 0);
+                                if(buy_number > 0) {
+                                    goods_data.push({
+                                        goods_id: goods_id,
+                                        stock: buy_number,
+                                        spec: item.spec || ''
+                                    });
+                                }
+                            } else {
+                                item.data.forEach(item2 => {
+                                    var buy_number = parseInt(item2.buy_number || 0);
+                                    if(buy_number > 0) {
+                                        goods_data.push({
+                                            goods_id: goods_id,
+                                            stock: buy_number,
+                                            spec: item2.spec || ''
+                                        });
+                                    }
+                                });
+                            }
+                        });
+                        if(goods_data.length <= 0) {
+                            app.globalData.showToast('请选择规格');
+                            return false;
+                        }
+
+                        // 操作类型
+                        switch (e.currentTarget.dataset.type) {
+                            case 'plugins-batchbuy-button-buy':
+                                // 进入订单确认页面
+                                var data = {
+                                    buy_type: "goods",
+                                    goods_data: encodeURIComponent(base64.encode(JSON.stringify(goods_data)))
+                                };
+                                uni.navigateTo({
+                                    url: '/pages/buy/buy?data=' + encodeURIComponent(base64.encode(JSON.stringify(data)))
+                                });
+                                this.popup_close_event();
+                                break;
+
+                            // 加入购物车
+                            case 'plugins-batchbuy-button-cart':
+                                this.goods_cart_event(goods_data);
+                                break;
+                                        
+                            default:
+                                app.globalData.showToast("操作事件类型有误");
+                        }
+                    }
+                }
+            },
+
+            // 加入购物车事件
+            goods_cart_event(goods_data) {
+                uni.showLoading({
+                    title: '处理中...'
+                });
+                uni.request({
+                    url: app.globalData.get_request_url('save', 'cart'),
+                    method: 'POST',
+                    data: {goods_data: goods_data},
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        if (res.data.code == 0) {
+                            app.globalData.showToast(res.data.msg, 'success');
+
+                            // 调用父级
+                            this.$emit('BatchCartSuccessEvent', {
+                                cart_number: res.data.data.buy_number,
+                                back_data: this.back_data,
+                            });
+
+                            // 关闭购买弹窗窗口
+                            this.popup_close_event();
+                        } else {
+                            if (app.globalData.is_login_check(res.data, this, 'confirm_event')) {
+                                app.globalData.showToast(res.data.msg);
+                            }
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            }
+        }
+    };
+</script>
+<style>
+    .plugins-batchbuy-container {
+        height: 60vh;
+        padding-bottom: 160rpx;
+    }
+    .plugins-batchbuy-container .left-nav {
+        width: 200rpx;
+        top: 0;
+        left: 0;
+        height: calc(100% - 160rpx);
+    }
+    .plugins-batchbuy-container .left-nav .badge-icon {
+        top: 8rpx;
+        right: 36rpx;
+    }
+    .plugins-batchbuy-container .left-nav .spec-images {
+        width: 50rpx;
+        height: 50rpx !important;
+    }
+    .plugins-batchbuy-container .right-conent {
+        width: calc(100% - 200rpx);
+    }
+    .plugins-batchbuy-container .right-conent .item-left {
+        width: calc(100% - 290rpx);
+    }
+    .plugins-batchbuy-container .item-right {
+        background: #fbfbfb;
+        border: 1px solid #f0f0f0;
+    }
+    .plugins-batchbuy-container .item-right .number-submit {
+        width: 80rpx;
+        font-weight: bold;
+    }
+    .plugins-batchbuy-container .item-right input {
+        width: 50px;
+    }
+    .plugins-batchbuy-container .item-right .number-submit,
+    .plugins-batchbuy-container .item-right input {
+        padding: 0;
+        height: 60rpx;
+        line-height: 60rpx;
+    }
+    .plugins-batchbuy-container .right-conent-only-level-one {
+        width: 100%;
+    }
+    .plugins-batchbuy-container .right-conent-only-level-one .spec-images {
+        width: 34rpx;
+        height: 34rpx !important;
+    }
+    .plugins-batchbuy-container .confirm-submit {
+        left: 0;
+        bottom: 0;
+    }
+    .plugins-batchbuy-container .buy-nav-btn-number-0 .item,
+    .plugins-batchbuy-container .buy-nav-btn-number-1 .item {
+        width: 100% !important;
+    }
+    .plugins-batchbuy-container .buy-nav-btn-number-2 .item {
+        width: 50% !important;
+    }
+    .plugins-batchbuy-container .buy-nav-btn-number-3 .item {
+        width: 33.33% !important;
+    }
+    .plugins-batchbuy-container .buy-nav-btn-number-4 .item {
+        width: 25% !important;
+    }
+</style>

+ 755 - 0
components/goods-buy/goods-buy.vue

@@ -0,0 +1,755 @@
+<template>
+    <view>
+        <component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event">
+            <view class="goods-spec-choice-container padding-main bg-white pr">
+                <view class="close fr oh">
+                    <view class="fr" @tap.stop="popup_close_event">
+                        <icon type="clear" size="20"></icon>
+                    </view>
+                </view>
+                <!-- 规格基础信息 -->
+                <view class="goods-spec-base oh br-b pr">
+                    <image :src="goods_spec_base_images" mode="scaleToFill" class="radius br" @tap="goods_detail_images_view_event" :data-value="goods_spec_base_images"></image>
+                    <view class="goods-spec-base-content">
+                        <view class="goods-price">
+                            <view class="sales-price">{{currency_symbol}}{{goods_spec_base_price}}</view>
+                            <view v-if="(goods_spec_base_original_price || null) != null && goods_spec_base_original_price != 0" class="original-price margin-top-sm">{{currency_symbol}}{{goods_spec_base_original_price}}</view>
+                        </view>
+                        <view class="inventory text-size-xs margin-top-xs">
+                            <text class="cr-gray">库存</text>
+                            <text class="cr-base">{{goods_spec_base_inventory}}</text>
+                            <text class="cr-gray">{{goods.inventory_unit}}</text>
+                        </view>
+                    </view>
+                </view>
+                <block v-if="(goods.is_exist_many_spec || 0) == 1 && goods_spec_choose.length == 0">
+                    <view class="padding-top-xxxl padding-bottom-xxxl tc cr-red">规格数据有误</view>
+                </block>
+                <block v-else>
+                    <view class="goods-spec-choice-content">
+                        <!-- 商品规格 -->
+                        <view v-if="goods_spec_choose.length > 0" class="goods-spec-choose">
+                            <view v-for="(item, key) in goods_spec_choose" :key="key" class="item padding-top-xxl padding-bottom-xxl">
+                                <view class="text-size-sm">{{item.name}}</view>
+                                <view v-if="item.value.length > 0" class="spec margin-top-sm">
+                                    <block v-for="(items, keys) in item.value" :key="keys">
+                                        <button @tap.stop="goods_spec_choice_event" :data-key="key" :data-keys="keys" type="default" size="mini" hover-class="none" :class="'round '+items.is_active + ' ' + items.is_dont + ' ' + items.is_disabled">
+                                            <image v-if="(items.images || null) != null" :src="items.images" mode="scaleToFill" class="va-m dis-inline-block round margin-right-sm"></image>
+                                            <text class="va-m">{{items.name}}</text>
+                                        </button>
+                                    </block>
+                                </view>
+                            </view>
+                        </view>
+
+                        <!-- 购买数量 -->
+                        <view class="goods-buy-number oh pr margin-top-xl margin-bottom-xxl">
+                            <view class="fl margin-top">购买数量</view>
+                            <view class="number-content tc oh round">
+                                <view @tap="goods_buy_number_event" class="number-submit tc cr-gray fl va-m" data-type="0">-</view>
+                                <input @blur="goods_buy_number_blur" class="tc cr-gray bg-white fl va-m radius-0" type="number" :value="buy_number">
+                                <view @tap="goods_buy_number_event" class="number-submit tc cr-gray fl va-m" data-type="1">+</view>
+                            </view>
+                        </view>
+                    </view>
+                    <button class="bg-main br-main cr-white text-size-sm round" type="default" @tap.stop="spec_confirm_event" hover-class="none">确定</button>
+                </block>
+            </view>
+        </component-popup>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import base64 from '../../common/js/lib/base64.js';
+    import componentPopup from "../../components/popup/popup";
+    export default {
+        data() {
+            return {
+                currency_symbol: app.globalData.get_config('currency_symbol', app.globalData.data.currency_symbol),
+                params: {},
+                back_data: {},
+                popup_status: false,
+                goods_spec_base_price: 0,
+                goods_spec_base_original_price: 0,
+                goods_spec_base_inventory: 0,
+				goods_spec_base_buy_min_number: 0,
+				goods_spec_base_buy_max_number: 0,
+                goods_spec_base_images: '',
+                goods: {},
+                goods_spec_choose: [],
+                buy_number: 1,
+                buy_event_type: 'cart',
+                is_direct_cart: 0,
+                is_success_tips: 1,
+                // 智能工具插件
+                plugins_intellectstools_config: app.globalData.get_config('plugins_base.intellectstools.data'),
+                plugins_intellectstools_timer: null,
+                plugins_intellectstools_timerout: null,
+            };
+        },
+
+        components: {
+            componentPopup
+        },
+
+        created: function() {},
+
+        methods: {
+            // 初始化
+            init(goods = {}, params = {}, back_data = null) {
+                if(!app.globalData.is_single_page_check()) {
+                    return false;
+                }
+                params = params || {};
+
+                // 状态默认开启弹窗
+                var status = true;
+                // 商品可选规格
+                var goods_spec_choose = ((goods.specifications || null) != null) ? (goods.specifications.choose || []) : [];
+                // 无规格是否直接操作
+                var is_direct_cart = 0;
+                if((params.is_direct_cart || 0) == 1 && parseInt(goods.is_exist_many_spec || 0) == 0 && goods_spec_choose.length == 0) {
+                    status = false;
+                    is_direct_cart = 1;
+                }
+                // 是否成功提示、默认提示
+                var is_success_tips = (params.is_success_tips == undefined) ? 1 : params.is_success_tips || 0;
+                // 直接加购、并且用户已经存在购物车则依次+1
+                if(this.is_direct_cart == 1 && parseInt(this.goods.user_cart_count || 0) > 0) {
+                    var buy_number = 1;
+                } else {
+                    var buy_number = goods.buy_min_number || 1;
+                }
+                // 设置数据
+                this.setData({
+                    popup_status: status,
+                    params: params || {},
+                    back_data: back_data,
+                    goods: goods || {},
+                    goods_spec_choose: goods_spec_choose,
+                    goods_spec_base_price: goods.price,
+                    goods_spec_base_original_price: goods.original_price || 0,
+                    goods_spec_base_inventory: goods.inventory,
+                    goods_spec_base_images: goods.images,
+                    buy_number: buy_number,
+                    buy_event_type: params.buy_event_type || 'cart',
+                    is_direct_cart: is_direct_cart,
+                    is_success_tips: is_success_tips,
+                });
+
+                // 不能选择规格处理
+                this.spec_handle_dont(0, 1);
+
+                // 是否默认选中第一个规格
+                this.plugins_intellectstools_selected_spec_handle();
+
+                // 是否直接操作加入购物车
+                if(is_direct_cart) {
+                    this.spec_confirm_event();
+                }
+            },
+
+            // 默认选中第一个规格
+            plugins_intellectstools_selected_spec_handle() {
+                // 是否已选择
+                var temp_data = this.goods_spec_choose;
+                if (temp_data.length > 0) {
+                    var active_count = 0;
+                    for (var i in temp_data) {
+                        for (var k in temp_data[i]['value']) {
+                            if ((temp_data[i]['value'][k]['is_active'] || null) != null) {
+                                active_count++;
+                            }
+                        }
+                    }
+                    if (active_count > 0) {
+                        return false;
+                    }
+
+                    // 选择处理
+                    var self = this;
+                    // 销毁之前的任务
+                    clearInterval(self.plugins_intellectstools_timer);
+                    clearInterval(self.plugins_intellectstools_timerout);
+                    // 读取智能工具插件配置、是否开启
+                    var config = self.plugins_intellectstools_config || null;
+                    if(config != null && (config.is_goods_detail_selected_first_spec || 0) == 1) {
+                        // 必须存在购买和加入购物车任意一个、规格必须多个
+                        var buy = self.buy_button;
+                        var sku_count = app.globalData.get_length(temp_data);
+                        // 先清除价格展示信息
+                        self.setData({
+                            goods_spec_base_price: '...',
+                            goods_spec_base_original_price: '...'
+                        });
+                        var num = 0;
+                        var timer = setInterval(function() {
+                            for(var i in temp_data) {
+                                // 清除价格展示信息、避免获取价格类型赋值
+                                self.setData({
+                                    goods_spec_base_price: '...',
+                                    goods_spec_base_original_price: '...'
+                                });
+                                // 必须不存在已选择项
+                                var active = temp_data[i]['value'].map(function(v){return v.is_active}).join('') || null;
+                                if(active == null) {
+                                    var status = false;
+                                    for(var k in temp_data[i]['value']) {
+                                        // 必须是可选和未选
+                                        if(!status && (temp_data[i]['value'][k]['is_disabled'] || null) == null && (temp_data[i]['value'][k]['is_dont'] || null) == null) {
+                                            self.goods_spec_choice_handle(i, k);
+                                            status = true;
+                                            num++;
+                                        }
+                                    }
+                                }
+                            }
+                            if(num >= sku_count) {
+                                clearInterval(self.plugins_intellectstools_timer);
+                            }
+                        }, 100);
+                        var timerout = setTimeout(function() {
+                            clearInterval(self.plugins_intellectstools_timerout);
+                        }, 20000);
+                        self.setData({
+                            plugins_intellectstools_timer: timer,
+                            plugins_intellectstools_timerout: timerout
+                        });
+                    }
+                }
+            },
+
+            // 弹层关闭
+            popup_close_event(e) {
+                this.setData({
+                    popup_status: false
+                });
+            },
+
+            // 规格事件
+            goods_spec_choice_event(e) {
+                var key = e.currentTarget.dataset.key || 0;
+                var keys = e.currentTarget.dataset.keys || 0;
+                this.goods_spec_choice_handle(key, keys);
+            },
+
+            // 规格选择处理
+            goods_spec_choice_handle(key, keys) {
+                var temp_spec = this.goods_spec_choose;
+                // 不能选择和禁止选择跳过
+                if ((temp_spec[key]['value'][keys]['is_dont'] || null) == null && (temp_spec[key]['value'][keys]['is_disabled'] || null) == null) {
+                    // 规格选择
+                    for (var i in temp_spec) {
+                        for (var k in temp_spec[i]['value']) {
+                            if ((temp_spec[i]['value'][k]['is_dont'] || null) == null && (temp_spec[i]['value'][k]['is_disabled'] || null) == null) {
+                                if (key == i) {
+                                    if (keys == k && (temp_spec[i]['value'][k]['is_active'] || null) == null) {
+                                        temp_spec[i]['value'][k]['is_active'] = 'cr-white bg-main br-main';
+                                    } else {
+                                        temp_spec[i]['value'][k]['is_active'] = '';
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    this.setData({
+                        spec: temp_spec
+                    });
+
+                    // 不能选择规格处理
+                    this.spec_handle_dont(key);
+
+                    // 获取下一个规格类型
+                    this.get_spec_type(key);
+
+                    // 获取规格详情
+                    this.get_spec_detail();
+                }
+            },
+            
+            // 获取下一个规格类型
+            get_spec_type(key) {
+                var temp_spec = this.goods_spec_choose;
+                var active_index = parseInt(key) + 1;
+                var sku_count = app.globalData.get_length(temp_spec);
+                if (active_index <= 0 || active_index >= sku_count) {
+                    return false;
+                }
+
+                // 获取规格值
+                var spec = [];
+                for (var i in temp_spec) {
+                    for (var k in temp_spec[i]['value']) {
+                        if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
+                            spec.push({
+                                type: temp_spec[i]['name'],
+                                value: temp_spec[i]['value'][k]['name']
+                            });
+                            break;
+                        }
+                    }
+                }
+                if (spec.length <= 0) {
+                    return false;
+                }
+
+                // 获取数据
+                var data = this.params;
+                data['id'] = this.goods.id;
+                data['spec'] = JSON.stringify(spec);
+                uni.request({
+                    url: app.globalData.get_request_url('spectype', 'goods'),
+                    method: 'POST',
+                    data: data,
+                    dataType: 'json',
+                    success: (res) => {
+                        if (res.data.code == 0) {
+                            var spec_type = res.data.data.spec_type;
+                            var spec_count = spec.length;
+                            var index = spec_count > 0 ? spec_count : 0;
+                            if (index < sku_count) {
+                                for (var i in temp_spec) {
+                                    for (var k in temp_spec[i]['value']) {
+                                        if (index == i) {
+                                            temp_spec[i]['value'][k]['is_dont'] = '';
+                                            var temp_value = temp_spec[i]['value'][k]['name'];
+                                            var temp_status = false;
+                                            for (var t in spec_type) {
+                                                if (spec_type[t] == temp_value) {
+                                                    temp_status = true;
+                                                    break;
+                                                }
+                                            }
+                                            if (temp_status == true) {
+                                                temp_spec[i]['value'][k]['is_disabled'] = '';
+                                            } else {
+                                                temp_spec[i]['value'][k]['is_disabled'] = 'spec-items-disabled';
+                                            }
+                                        }
+                                    }
+                                }
+                                this.setData({
+                                    spec: temp_spec
+                                });
+                            }
+                        } else {
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 获取规格详情
+            get_spec_detail() {
+                // 获取规格值
+                var spec = this.goods_selected_spec();
+
+                // 存在规格的时候是否已完全选择规格
+                var sku_count = this.goods_spec_choose.length;
+                var active_count = spec.length;
+                if (spec.length <= 0 || active_count < sku_count) {
+					var buy_number = parseInt(this.buy_number);
+					var buy_min_number = parseInt(this.goods.buy_min_number || 1);
+					var buy_max_number = parseInt(this.goods.buy_max_number || 0);
+					if(buy_number < buy_min_number) {
+						buy_number = buy_min_number;
+					}
+					if(buy_max_number > 0 && buy_number > buy_max_number) {
+						buy_number = buy_max_number;
+					}
+                    this.setData({
+                        goods_spec_base_price: this.goods.price,
+                        goods_spec_base_original_price: this.goods.original_price || 0,
+                        goods_spec_base_inventory: this.goods.inventory,
+						goods_spec_base_buy_min_number : 0,
+						goods_spec_base_buy_max_number : 0,
+						buy_number: buy_number
+                    });
+                    return false;
+                }
+
+                // 获取数据
+                var data = this.params;
+                data['id'] = this.goods.id;
+                data['spec'] = JSON.stringify(spec);
+                data['stock'] = this.buy_number;
+                uni.request({
+                    url: app.globalData.get_request_url('specdetail', 'goods'),
+                    method: 'POST',
+                    data: data,
+                    dataType: 'json',
+                    success: res => {
+                        if (res.data.code == 0) {
+                            this.goods_spec_detail_back_handle(res.data.data);
+                        } else {
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 商品规格详情返回数据处理
+            goods_spec_detail_back_handle(data) {
+                var spec_base = data.spec_base;
+				var buy_number = parseInt(this.buy_number);
+				var spec_buy_min_number = parseInt(spec_base.buy_min_number || 1);
+				var spec_buy_max_number = parseInt(spec_base.buy_max_number || 0);
+				if(spec_buy_min_number > 0 && buy_number < spec_buy_min_number) {
+					buy_number = spec_buy_min_number;
+				}
+				if(spec_buy_max_number > 0 && buy_number > spec_buy_max_number) {
+					buy_number = spec_buy_max_number;
+				}
+                this.setData({
+                    goods_spec_base_price: spec_base.price,
+                    goods_spec_base_original_price: spec_base.original_price || 0,
+                    goods_spec_base_inventory: parseInt(spec_base.inventory || 0),
+					goods_spec_base_buy_min_number: spec_buy_min_number,
+					goods_spec_base_buy_max_number: spec_buy_max_number,
+					buy_number: buy_number
+                });
+            },
+
+            // 已选的商品规格
+            goods_selected_spec() {
+                var spec = [];
+                var temp_spec = this.goods_spec_choose;
+                for (var i in temp_spec) {
+                    for (var k in temp_spec[i]['value']) {
+                        if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
+                            spec.push({
+                                type: temp_spec[i]['name'],
+                                value: temp_spec[i]['value'][k]['name']
+                            });
+                            break;
+                        }
+                    }
+                }
+                return spec;
+            },
+
+            // 不能选择规格处理
+            spec_handle_dont(key, is_init = 0) {
+                var temp_spec = this.goods_spec_choose || [];
+                if (temp_spec.length <= 0) {
+                    return false;
+                }
+
+                // 是否不能选择
+                key = parseInt(key);
+                for (var i in temp_spec) {
+                    for (var k in temp_spec[i]['value']) {
+                        if (i > key) {
+                            temp_spec[i]['value'][k]['is_dont'] = 'spec-dont-choose';
+                            temp_spec[i]['value'][k]['is_disabled'] = '';
+                            temp_spec[i]['value'][k]['is_active'] = '';
+                        } else {
+                            if(is_init == 1) {
+                                temp_spec[i]['value'][k]['is_active'] = '';
+                            }
+                        }
+
+                        // 当只有一个规格的时候
+                        if (key == 0 && temp_spec.length == 1) {
+                            temp_spec[i]['value'][k]['is_disabled'] = (temp_spec[i]['value'][k]['is_only_level_one'] || null) != null && parseInt(temp_spec[i]['value'][k]['inventory'] || 0) <= 0 ? 'spec-items-disabled' : '';
+                        }
+                    }
+                }
+
+                this.setData({
+                    spec: temp_spec
+                });
+            },
+
+            // 数量输入事件
+            goods_buy_number_blur(e) {
+                var number = parseInt(e.detail.value) || 1;
+                if(isNaN(number)) {
+                    number = this.goods.buy_min_number || 1;
+                }
+                this.goods_buy_number_func(number);
+            },
+
+            // 数量操作事件
+            goods_buy_number_event(e) {
+                var type = parseInt(e.currentTarget.dataset.type || 0);
+                var temp_number = parseInt(this.buy_number);
+                var number = (type == 0) ? temp_number - 1 : temp_number + 1;
+                this.goods_buy_number_func(number);
+            },
+
+            // 数量处理方法
+            goods_buy_number_func(number) {
+                var buy_min_number = parseInt(this.goods.buy_min_number || 1);
+                var buy_max_number = parseInt(this.goods.buy_max_number || 0);
+				var spec_buy_min_number = parseInt(this.goods_spec_base_buy_min_number || 0);
+				var spec_buy_max_number = parseInt(this.goods_spec_base_buy_max_number || 0);
+                var inventory = parseInt(this.goods_spec_base_inventory || 0);
+                var inventory_unit = this.goods.inventory_unit;
+
+                // 最小起购数量
+				var min = (spec_buy_min_number > 0) ? spec_buy_min_number : buy_min_number;
+				if (min > 0 && number < min) {
+				    number = min;
+				    app.globalData.showToast('起购' + min + inventory_unit);
+				}
+
+                // 最大购买数量
+				var max = (spec_buy_max_number > 0) ? spec_buy_max_number : buy_max_number;
+				if (max > 0 && number > max) {
+				    number = max;
+				    app.globalData.showToast('限购' + max + inventory_unit);
+				}
+
+                // 是否超过库存数量
+                if (number > inventory) {
+                    number = inventory;
+                    app.globalData.showToast('库存数量' + inventory + inventory_unit);
+                }
+
+                this.setData({buy_number: number});
+
+                // 存在规格的时候是否已完全选择规格
+                var spec = this.goods_selected_spec();
+                var sku_count = this.goods_spec_choose.length;
+                var active_count = spec.length;
+                if (sku_count > 0 && active_count < sku_count) {
+                    return false;
+                }
+
+                // 获取数据
+                var data = this.params;
+                data['id'] = this.goods.id;
+                data['spec'] = spec;
+                data['stock'] = this.buy_number;
+                uni.request({
+                    url: app.globalData.get_request_url('stock', 'goods'),
+                    method: 'POST',
+                    data: data,
+                    dataType: 'json',
+                    success: res => {
+                        if (res.data.code == 0) {
+                            this.goods_spec_detail_back_handle(res.data.data);
+                        } else {
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 详情图片查看
+            goods_detail_images_view_event(e) {
+                var value = e.currentTarget.dataset.value || null;
+                if (value != null) {
+                    uni.previewImage({
+                        current: value,
+                        urls: [value]
+                    });
+                }
+            },
+
+            // 规格确认事件
+            spec_confirm_event(e) {
+                var user = app.globalData.get_user_info(this, 'spec_confirm_event');
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.navigateTo({
+                            url: "/pages/login/login?event_callback=spec_confirm_event"
+                        });
+                        return false;
+                    } else {
+                        // 规格
+                        var temp_data = this.goods_spec_choose;
+                        var sku_count = temp_data.length;
+                        var active_count = 0;
+                        var spec = [];
+                        if (sku_count > 0) {
+                            for (var i in temp_data) {
+                                for (var k in temp_data[i]['value']) {
+                                    if ((temp_data[i]['value'][k]['is_active'] || null) != null) {
+                                        active_count++;
+                                        spec.push({
+                                            type: temp_data[i]['name'],
+                                            value: temp_data[i]['value'][k]['name']
+                                        });
+                                    }
+                                }
+                            }
+                            if (active_count < sku_count) {
+                                app.globalData.showToast('请选择规格');
+                                return false;
+                            }
+                        }
+
+                        // 操作类型
+                        switch (this.buy_event_type) {
+                            case 'buy':
+                                // 进入订单确认页面
+                                var data = {
+                                    buy_type: "goods",
+                                    goods_data: encodeURIComponent(base64.encode(JSON.stringify([{
+                                        goods_id: this.goods.id,
+                                        stock: this.buy_number,
+                                        spec: spec
+                                    }])))
+                                };
+                                uni.navigateTo({
+                                    url: '/pages/buy/buy?data=' + encodeURIComponent(base64.encode(JSON.stringify(data)))
+                                });
+                                this.popup_close_event();
+                                break;
+
+                            // 加入购物车
+                            case 'cart':
+                                this.goods_cart_event(spec);
+                                break;
+                
+                            default:
+                                app.globalData.showToast("操作事件类型有误");
+                        }
+                    }
+                }
+            },
+
+            // 加入购物车事件
+            goods_cart_event(spec) {
+                var data = this.params;
+                data['goods_id'] = this.goods.id;
+                data['spec'] = JSON.stringify(spec);
+                data['stock'] = this.buy_number;
+                uni.request({
+                    url: app.globalData.get_request_url('save', 'cart'),
+                    method: 'POST',
+                    data: data,
+                    dataType: 'json',
+                    success: res => {
+                        if (res.data.code == 0) {
+                            // 是否成功提示
+                            if(this.is_success_tips == 1) {
+                                app.globalData.showToast(res.data.msg, 'success');
+                            }
+                            var cart_number = res.data.data.buy_number;
+
+                            // 调用父级
+                            this.$emit('CartSuccessEvent', {
+                                goods_id: this.goods.id,
+                                spec: spec,
+                                stock: this.buy_number,
+                                cart_number: cart_number,
+                                back_data: this.back_data,
+                            });
+
+                            // 是否返回定义来源返回
+                            if(parseInt(this.params.is_opt_buy_status || 0) == 1 && this.is_opt_back == 1) {
+                                setTimeout(function() {
+                                    uni.navigateBack();;
+                                }, 1000);
+                            } else {
+                                // 关闭购买弹窗窗口
+                                this.popup_close_event();
+                            }
+                        } else {
+                            if (app.globalData.is_login_check(res.data, this, 'spec_confirm_event')) {
+                                app.globalData.showToast(res.data.msg);
+                            }
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            }
+        }
+    };
+</script>
+<style>
+    .goods-spec-choice-container .close {
+        position: absolute;
+        top: 20rpx;
+        right: 20rpx;
+        z-index: 2;
+    }
+    .goods-spec-base {
+        height: 230rpx;
+    }
+    .goods-spec-base image {
+        width: 200rpx;
+        height: 200rpx;
+        position: absolute;
+        left: 0;
+        top: 0;
+    }
+    .goods-spec-base-content {
+        position: absolute;
+        left: 220rpx;
+        top: 0;
+    }
+    .goods-spec-choice-content {
+        max-height: 50vh;
+        overflow-y: scroll;
+        overflow-x: hidden;
+        margin-top: 20rpx;
+    }
+    .goods-spec-choice-container .item .spec button {
+        background-color: #f5f5f5;
+        color: #666;
+        border: 1px solid #ccc;
+    }
+    .goods-spec-choice-container .item .spec button:not(:last-child) {
+        margin-right: 25rpx;
+    }
+    .goods-spec-choice-container .item .spec button image {
+        width: 40rpx;
+        height: 40rpx !important;
+    }
+    .goods-spec-choice-container .spec-dont-choose {
+        color: #b4b3b3 !important;
+        background-color: #ffffff !important;
+        border: 1px solid #ebeaea !important;
+    }
+    .goods-spec-choice-container .spec-dont-choose image {
+        opacity: 0.5;
+    }
+    .goods-spec-choice-container .spec-items-disabled {
+        color: #d2cfcf !important;
+        background-color: #ffffff !important;
+        border: 1px dashed #d5d5d5 !important;
+    }
+    .goods-spec-choice-container .spec-items-disabled image {
+        opacity: 0.3;
+    }
+
+    .goods-spec-choice-container .goods-buy-number {
+        height: 70rpx;
+    }
+    .goods-spec-choice-container .number-content {
+        position: absolute;
+        right: 20rpx;
+        top: 0;
+        background: #eee;
+        border: 1px solid #eee;
+    }
+    .goods-spec-choice-container .number-content .number-submit {
+        width: 80rpx;
+        font-weight: bold;
+    }
+    .goods-spec-choice-container .number-content input {
+        width: 50px;
+    }
+    .goods-spec-choice-container .number-content .number-submit,
+    .goods-spec-choice-container .number-content input {
+        padding: 0;
+        height: 60rpx;
+        line-height: 60rpx;
+    }
+</style>

+ 275 - 0
components/goods-list/goods-list.vue

@@ -0,0 +1,275 @@
+<template>
+    <view>
+        <view v-if="(data || null) != null && (data.goods_list || null) != null && data.goods_list.length > 0">
+            <view v-if="(data.title || null) != null || (data.vice_title || null) != null" class="spacing-nav-title">
+                <text v-if="(data.title || null) != null" class="text-wrapper" :style="'color:'+(data.color || '#333')+';'">{{data.title}}</text>
+                <text v-if="(data.vice_title || null) != null" class="vice-name margin-left-lg cr-gray">{{data.vice_title}}</text>
+                <navigator v-if="(data[propMoreUrlKey] || null) != null" :url="data[propMoreUrlKey]" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr">更多</navigator>
+            </view>
+            <view class="wh-auto oh pr goods-list">
+                <view v-if="(data.keywords_arr || null) != null && data.keywords_arr.length > 0" class="word-list scroll-view-horizontal margin-bottom-lg">
+                    <scroll-view scroll-x>
+                        <block v-for="(kv, ki) in data.keywords_arr" :key="ki">
+                            <navigator v-if="(kv || null) != null" :url="propKeywordsUrl + kv" hover-class="none" class="word-icon dis-inline-block bg-main-light text-size-xs cr-main round padding-top-xs padding-bottom-xs padding-left padding-right">{{kv}}</navigator>
+                        </block>
+                    </scroll-view>
+                </view>
+                <!-- 默认图文 -->
+                <block v-if="(data.style_type || 0) == 0">
+                    <view class="goods-data-list">
+                        <view v-for="(item, index) in data.goods_list" :key="index" class="item oh padding-main border-radius-main bg-white oh pr spacing-mb">
+                            <!-- 商品主体内容 -->
+                            <view class="cp" :data-value="item.goods_url" @tap="url_event">
+                                <image class="goods-img fl radius" :src="item.images" mode="aspectFit"></image>
+                                <view v-if="(item.is_error || 0) == 1" class="error-msg pa cr-gray tc radius">{{item.error_msg}}</view>
+                                <view class="base fr">
+                                    <view class="multi-text">{{item.title}}</view>
+                                    <view v-if="(item.simple_desc || null) != null" class="cr-grey single-text margin-top-sm">{{item.simple_desc}}</view>
+                                    <view class="base-bottom pa">
+                                        <text v-if="propIsShowPriceIcon && (item.price_icon || null) != null" class="bg-red br-red cr-white text-size-xs padding-left-sm padding-right-sm round va-m margin-right-xs">{{item.price_icon}}</text>
+                                        <text class="sales-price va-m">{{propCurrencySymbol}}{{item[propPriceField]}}</text>
+                                    </view>
+                                    <view v-if="(item.is_error || 0) == 0" class="pa bg-white right-cart-icon" :data-index="index" @tap.stop="goods_cart_event">
+                                        <uni-icons type="plus" size="22" color="#1AAD19"></uni-icons>
+                                        <view class="cart-badge-icon pa">
+                                            <component-badge :propNumber="item.user_cart_count || 0"></component-badge>
+                                        </view>
+                                    </view>
+                                </view>
+                            </view>
+                            <!-- 标签插件 -->
+                            <view v-if="(propLabel || null) != null && propLabel.data.length > 0" :class="'plugins-label oh pa plugins-label-'+((propLabel.base.is_user_goods_label_icon || 0) == 0 ? 'text' : 'img')+' plugins-label-'+(propLabel.base.user_goods_show_style || 'top-left')">
+                                <block v-for="(lv,li) in propLabel.data" :key="li">
+                                    <view v-if="(lv.goods_ids || null) != null && lv.goods_ids.indexOf(item.id) != -1" class="lv dis-inline-block va-m" :data-value="((propLabel.base.is_user_goods_label_url || 0) == 1) ? (lv.url || '') : ''" @tap="url_event">
+                                        <view v-if="(propLabel.base.is_user_goods_label_icon || 0) == 0" class="round cr-white bg-main text-size-xs fl" :style="((lv.bg_color || null) != null ? 'background-color:'+ lv.bg_color+' !important;' : '')+((lv.text_color || null) != null ? 'color:'+ lv.text_color+' !important;' : '')">{{lv.name}}</view>
+                                        <image v-else class="dis-block" :src="lv.icon" mode="scaleToFill"></image>
+                                    </view>
+                                </block>
+                            </view>
+                        </view>
+                    </view>
+                </block>
+                <!-- 九方格 -->
+                <block v-else-if="data.style_type == 1">
+                    <view class="goods-data-grid-list">
+                        <view v-for="(item, index) in data.goods_list" :key="index" class="item oh border-radius-main bg-white oh pr spacing-mb">
+                            <!-- 商品主体内容 -->
+                            <view class="cp" :data-value="item.goods_url" @tap="url_event">
+                                <image class="goods-img dis-block wh-auto" :src="item.images" mode="aspectFit"></image>
+                                <view v-if="(item.is_error || 0) == 1" class="error-msg pa cr-gray tc radius wh-auto">{{item.error_msg}}</view>
+                                <view class="base padding-horizontal-main margin-top-sm">
+                                    <view class="goods-title multi-text">{{item.title}}</view>
+                                    <view class="margin-top-sm">
+                                        <view class="fl">
+                                            <text v-if="propIsShowPriceIcon && (item.price_icon || null) != null" class="bg-red br-red cr-white text-size-xs padding-left-sm padding-right-sm round va-m margin-right-xs">{{item.price_icon}}</text>
+                                            <text class="sales-price va-m">{{propCurrencySymbol}}{{item[propPriceField]}}</text>
+                                        </view>
+                                        <view v-if="(item.is_error || 0) == 0" class="pa bg-white right-cart-icon" :data-index="index" @tap.stop="goods_cart_event">
+                                            <uni-icons type="plus" size="22" color="#1AAD19"></uni-icons>
+                                            <view class="cart-badge-icon pa">
+                                                <component-badge :propNumber="item.user_cart_count || 0"></component-badge>
+                                            </view>
+                                        </view>
+                                    </view>
+                                </view>
+                            </view>
+                            <!-- 标签插件 -->
+                            <view v-if="(propLabel || null) != null && propLabel.data.length > 0" :class="'plugins-label oh pa plugins-label-'+((propLabel.base.is_user_goods_label_icon || 0) == 0 ? 'text' : 'img')+' plugins-label-'+(propLabel.base.user_goods_show_style || 'top-left')">
+                                <block v-for="(lv,li) in propLabel.data" :key="li">
+                                    <view v-if="(lv.goods_ids || null) != null && lv.goods_ids.indexOf(item.id) != -1" class="lv dis-inline-block va-m" :data-value="((propLabel.base.is_user_goods_label_url || 0) == 1) ? (lv.url || '') : ''" @tap="url_event">
+                                        <view v-if="(propLabel.base.is_user_goods_label_icon || 0) == 0" class="round cr-white bg-main text-size-xs fl" :style="((lv.bg_color || null) != null ? 'background-color:'+ lv.bg_color+' !important;' : '')+((lv.text_color || null) != null ? 'color:'+ lv.text_color+' !important;' : '')">{{lv.name}}</view>
+                                        <image v-else class="dis-block" :src="lv.icon" mode="scaleToFill"></image>
+                                    </view>
+                                </block>
+                            </view>
+                        </view>
+                    </view>
+                </block>
+                <!-- 滚动 -->
+                <view v-else-if="data.style_type == 2" class="rolling-horizontal border-radius-main oh spacing-mb">
+                    <view class="goods-data-rolling-list scroll-view-horizontal">
+                        <swiper :vertical="false" :autoplay="propIsAutoPlay" :circular="false" :display-multiple-items="((data.multiple_items || null) == null) ? (data.goods_list.length < 3 ? data.goods_list.length : 3) : (data.goods_list.length < data.multiple_items ? data.goods_list.length : data.multiple_items)" interval="3000">
+                            <block v-for="(item, index) in data.goods_list" :key="index">
+                                <swiper-item>
+                                    <view class="item bg-white border-radius-main margin-right-main oh pr ht-auto pr">
+                                        <!-- 商品主体内容 -->
+                                        <view class="cp" :data-value="item.goods_url" @tap="url_event">
+                                            <image class="goods-img dis-block wh-auto" :src="item.images" mode="aspectFit"></image>
+                                            <view v-if="(item.is_error || 0) == 1" class="error-msg pa cr-gray tc radius wh-auto">{{item.error_msg}}</view>
+                                            <view class="padding-left-sm padding-right-sm margin-top-sm">
+                                                <view class="multi-text">{{item.title}}</view>
+                                                <view class="margin-top-sm">
+                                                    <view class="fl">
+                                                        <text v-if="propIsShowPriceIcon && (item.price_icon || null) != null" class="bg-red br-red cr-white text-size-xs padding-left-sm padding-right-sm round va-m margin-right-xs">{{item.price_icon}}</text>
+                                                        <text class="sales-price va-m">{{propCurrencySymbol}}{{item[propPriceField]}}</text>
+                                                    </view>
+                                                    <view v-if="(item.is_error || 0) == 0" class="pa bg-white right-cart-icon" :data-index="index" @tap.stop="goods_cart_event">
+                                                        <uni-icons type="plus" size="22" color="#1AAD19"></uni-icons>
+                                                        <view class="cart-badge-icon pa">
+                                                            <component-badge :propNumber="item.user_cart_count || 0"></component-badge>
+                                                        </view>
+                                                    </view>
+                                                </view>
+                                            </view>
+                                        </view>
+                                        <!-- 标签插件 -->
+                                        <view v-if="(propLabel || null) != null && propLabel.data.length > 0" :class="'plugins-label oh pa plugins-label-'+((propLabel.base.is_user_goods_label_icon || 0) == 0 ? 'text' : 'img')+' plugins-label-'+(propLabel.base.user_goods_show_style || 'top-left')">
+                                            <block v-for="(lv,li) in propLabel.data" :key="li">
+                                                <view v-if="(lv.goods_ids || null) != null && lv.goods_ids.indexOf(item.id) != -1" class="lv dis-inline-block va-m" :data-value="((propLabel.base.is_user_goods_label_url || 0) == 1) ? (lv.url || '') : ''" @tap="url_event">
+                                                    <view v-if="(propLabel.base.is_user_goods_label_icon || 0) == 0" class="round cr-white bg-main text-size-xs fl" :style="((lv.bg_color || null) != null ? 'background-color:'+ lv.bg_color+' !important;' : '')+((lv.text_color || null) != null ? 'color:'+ lv.text_color+' !important;' : '')">{{lv.name}}</view>
+                                                    <image v-else class="dis-block" :src="lv.icon" mode="scaleToFill"></image>
+                                                </view>
+                                            </block>
+                                        </view>
+                                    </view>
+                                </swiper-item>
+                            </block>
+                        </swiper>
+                    </view>
+                </view>
+            </view>
+        </view>
+
+        <!-- 商品购买 -->
+        <component-goods-buy ref="goods_buy" v-on:CartSuccessEvent="goods_cart_back_event"></component-goods-buy>
+
+        <!-- 购物车抛物线 -->
+        <component-cart-para-curve ref="cart_para_curve"></component-cart-para-curve>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentBadge from "../../components/badge/badge";
+    import componentGoodsBuy from "../../components/goods-buy/goods-buy";
+    import componentCartParaCurve from '../../components/cart-para-curve/cart-para-curve';
+    export default {
+        data() {
+            return {
+                data: null,
+            };
+        },
+        components: {
+            componentBadge,
+            componentGoodsBuy,
+            componentCartParaCurve
+        },
+        props: {
+            // 价格符号
+            propCurrencySymbol: {
+                type: String,
+                default: app.globalData.data.currency_symbol
+            },
+            // 列表数据
+            propData: {
+                type: [Array,Object],
+                default: []
+            },
+            // 更多url地址
+            propMoreUrlKey: {
+                type: String,
+                default: 'url'
+            },
+            // 关键字url地址
+            propKeywordsUrl: {
+                type: String,
+                default: '/pages/goods-search/goods-search?keywords='
+            },
+            // 滚动自动播放
+            propIsAutoPlay: {
+                type: Boolean,
+                default: true
+            },
+            // 标签数据
+            propLabel: {
+                type: [Array,Object,String],
+                default: null
+            },
+            // 展示加购抛物线
+            propIsCartParaCurve: {
+                type: Boolean,
+                default: false
+            },
+            // 展示价格icon图标
+            propIsShowPriceIcon: {
+                type: Boolean,
+                default: false
+            },
+            // 展示价格字段
+            propPriceField: {
+                type: String,
+                default: 'min_price'
+            }
+        },
+        // 属性值改变监听
+        watch: {
+            // 数据
+            propData(value, old_value) {
+                this.data = value;
+            }
+        },
+        // 页面被展示
+        created: function() {
+            this.data = this.propData;
+        },
+        methods: {
+            // 加入购物车
+            goods_cart_event(e) {
+                if((this.$refs.goods_buy || null) != null) {
+                    var index = e.currentTarget.dataset.index || 0;
+                    var goods = this.propData.goods_list[index];
+                    // 开启购物车抛物线效果则展示提示操作
+                    var is_success_tips = this.propIsCartParaCurve ? 0 : 1;
+                    this.$refs.goods_buy.init(goods, {buy_event_type: 'cart', is_direct_cart: 1, is_success_tips: is_success_tips}, {index: index, pos: e});
+                }
+            },
+
+            // 加入购物车成功回调
+            goods_cart_back_event(e) {
+                // 增加数量
+                var back = e.back_data;
+                var temp = this.data;
+                var goods = temp['goods_list'][back.index];
+                goods['user_cart_count'] = parseInt(goods['user_cart_count'] || 0)+parseInt(e.stock);
+                if(goods['user_cart_count'] > 99) {
+                    goods['user_cart_count'] = '99+';
+                }
+                temp['goods_list'][back.index] = goods;
+                this.setData({data: temp});
+
+                // 抛物线
+                if(this.propIsCartParaCurve && (this.$refs.cart_para_curve || null) != null) {
+                    this.$refs.cart_para_curve.init(null, back.pos, goods.images);
+                }
+
+                // 导航购物车处理
+                var cart_total = e.cart_number || 0;
+                if (cart_total <= 0) {
+                    app.globalData.set_tab_bar_badge(2, 0);
+                } else {
+                    app.globalData.set_tab_bar_badge(2, 1, cart_total);
+                }
+
+                // 当前页面
+                var page = app.globalData.current_page().split('?');
+                switch(page[0]) {
+                    // 商品详情页面
+                    case 'pages/goods-detail/goods-detail' :
+                        var res = app.globalData.get_page_object(page[0]);
+                        if(res.length > 0) {
+                            for(var i in res) {
+                                res[i].$vm.goods_cart_count_handle(cart_total);
+                            }
+                        }
+                        break;
+                }
+            },
+
+            // url事件
+            url_event(e) {
+                app.globalData.url_event(e);
+            }
+        }
+    };
+</script>
+<style>
+</style>

+ 355 - 0
components/goods-spec-choice/goods-spec-choice.vue

@@ -0,0 +1,355 @@
+<template>
+    <view>
+        <component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event">
+            <view class="goods-spec-choice-container padding-main bg-white pr">
+                <view class="close fr oh">
+                    <view class="fr" @tap.stop="popup_close_event">
+                        <icon type="clear" size="20"></icon>
+                    </view>
+                </view>
+                <view class="goods-spec-choice-content">
+                    <!-- 商品规格 -->
+                    <view v-if="spec.length > 0" class="goods-spec-choose">
+                        <view v-for="(item, key) in spec" :key="key" class="item padding-top-xxl padding-bottom-xxl">
+                            <view class="text-size-sm">{{item.name}}</view>
+                            <view v-if="item.value.length > 0" class="spec margin-top-sm">
+                                <block v-for="(items, keys) in item.value" :key="keys">
+                                    <button @tap.stop="goods_spec_choice_event" :data-key="key" :data-keys="keys" type="default" size="mini" hover-class="none" :class="'round '+items.is_active + ' ' + items.is_dont + ' ' + items.is_disabled">
+                                        <image v-if="(items.images || null) != null" :src="items.images" mode="scaleToFill" class="va-m dis-inline-block round margin-right-sm"></image>
+                                        <text class="va-m">{{items.name}}</text>
+                                    </button>
+                                </block>
+                            </view>
+                        </view>
+                    </view>
+                </view>
+                <button class="bg-main br-main cr-white text-size-sm round" type="default" @tap.stop="spec_confirm_event" hover-class="none">确定</button>
+            </view>
+        </component-popup>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentPopup from "../../components/popup/popup";
+
+    export default {
+        data() {
+            return {
+                popup_status: false,
+                goods_id: 0,
+                spec: [],
+                buy_min_number: 1,
+                out_value: ''
+            };
+        },
+
+        components: {
+            componentPopup
+        },
+
+        created: function() {},
+
+        methods: {
+            // 获取数据
+            init(goods_id, spec, buy_min_number = 1, out_value = '') {
+                this.setData({
+                    popup_status: true,
+                    goods_id: goods_id,
+                    spec: spec || [],
+                    buy_min_number: buy_min_number || 1,
+                    out_value: out_value,
+                });
+                
+                // 不能选择规格处理
+                this.spec_handle_dont(0, 1);
+            },
+
+            // 购买弹层关闭
+            popup_close_event(e) {
+                this.setData({
+                    popup_status: false
+                });
+            },
+
+            // 规格事件
+            goods_spec_choice_event(e) {
+                var key = e.currentTarget.dataset.key || 0;
+                var keys = e.currentTarget.dataset.keys || 0;
+                this.goods_spec_choice_handle(key, keys);
+            },
+
+            // 规格选择处理
+            goods_spec_choice_handle(key, keys) {
+                var temp_spec = this.spec;
+                // 不能选择和禁止选择跳过
+                if ((temp_spec[key]['value'][keys]['is_dont'] || null) == null && (temp_spec[key]['value'][keys]['is_disabled'] || null) == null) {
+                    // 规格选择
+                    for (var i in temp_spec) {
+                        for (var k in temp_spec[i]['value']) {
+                            if ((temp_spec[i]['value'][k]['is_dont'] || null) == null && (temp_spec[i]['value'][k]['is_disabled'] || null) == null) {
+                                if (key == i) {
+                                    if (keys == k && (temp_spec[i]['value'][k]['is_active'] || null) == null) {
+                                        temp_spec[i]['value'][k]['is_active'] = 'cr-white bg-main br-main';
+                                    } else {
+                                        temp_spec[i]['value'][k]['is_active'] = '';
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    this.setData({
+                        spec: temp_spec
+                    });
+
+                    // 不能选择规格处理
+                    this.spec_handle_dont(key);
+
+                    // 获取下一个规格类型
+                    this.get_spec_type(key);
+
+                    // 获取规格详情
+                    this.get_spec_detail();
+                }
+            },
+            
+            // 获取下一个规格类型
+            get_spec_type(key) {
+                var temp_spec = this.spec;
+                var active_index = parseInt(key) + 1;
+                var sku_count = app.globalData.get_length(temp_spec);
+                if (active_index <= 0 || active_index >= sku_count) {
+                    return false;
+                }
+
+                // 获取规格值
+                var spec = [];
+                for (var i in temp_spec) {
+                    for (var k in temp_spec[i]['value']) {
+                        if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
+                            spec.push({
+                                type: temp_spec[i]['name'],
+                                value: temp_spec[i]['value'][k]['name']
+                            });
+                            break;
+                        }
+                    }
+                }
+                if (spec.length <= 0) {
+                    return false;
+                }
+
+                // 获取数据
+                uni.request({
+                    url: app.globalData.get_request_url('spectype', 'goods'),
+                    method: 'POST',
+                    data: {
+                        id: this.goods_id,
+                        spec: JSON.stringify(spec)
+                    },
+                    dataType: 'json',
+                    success: (res) => {
+                        if (res.data.code == 0) {
+                            var spec_type = res.data.data.spec_type;
+                            var spec_count = spec.length;
+                            var index = spec_count > 0 ? spec_count : 0;
+                            if (index < sku_count) {
+                                for (var i in temp_spec) {
+                                    for (var k in temp_spec[i]['value']) {
+                                        if (index == i) {
+                                            temp_spec[i]['value'][k]['is_dont'] = '';
+                                            var temp_value = temp_spec[i]['value'][k]['name'];
+                                            var temp_status = false;
+                                            for (var t in spec_type) {
+                                                if (spec_type[t] == temp_value) {
+                                                    temp_status = true;
+                                                    break;
+                                                }
+                                            }
+                                            if (temp_status == true) {
+                                                temp_spec[i]['value'][k]['is_disabled'] = '';
+                                            } else {
+                                                temp_spec[i]['value'][k]['is_disabled'] = 'spec-items-disabled';
+                                            }
+                                        }
+                                    }
+                                }
+                                this.setData({
+                                    spec: temp_spec
+                                });
+                            }
+                        } else {
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 获取规格详情
+            get_spec_detail() {
+                // 获取规格值
+                var spec = this.goods_selected_spec();
+
+                // 存在规格的时候是否已完全选择规格
+                var sku_count = this.spec.length;
+                var active_count = spec.length;
+                if (spec.length <= 0 || active_count < sku_count) {
+                    return false;
+                }
+
+                // 获取数据
+                uni.request({
+                    url: app.globalData.get_request_url('specdetail', 'goods'),
+                    method: 'POST',
+                    data: {
+                        id: this.goods_id,
+                        spec: JSON.stringify(spec),
+                        stock: this.buy_min_number
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        if (res.data.code != 0) {
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 已选的商品规格
+            goods_selected_spec() {
+                var spec = [];
+                var temp_spec = this.spec;
+                for (var i in temp_spec) {
+                    for (var k in temp_spec[i]['value']) {
+                        if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
+                            spec.push({
+                                type: temp_spec[i]['name'],
+                                value: temp_spec[i]['value'][k]['name']
+                            });
+                            break;
+                        }
+                    }
+                }
+                return spec;
+            },
+
+            // 不能选择规格处理
+            spec_handle_dont(key, is_init = 0) {
+                var temp_spec = this.spec || [];
+                if (temp_spec.length <= 0) {
+                    return false;
+                }
+
+                // 是否不能选择
+                key = parseInt(key);
+                for (var i in temp_spec) {
+                    for (var k in temp_spec[i]['value']) {
+                        if (i > key) {
+                            temp_spec[i]['value'][k]['is_dont'] = 'spec-dont-choose';
+                            temp_spec[i]['value'][k]['is_disabled'] = '';
+                            temp_spec[i]['value'][k]['is_active'] = '';
+                        } else {
+                            if(is_init == 1) {
+                                temp_spec[i]['value'][k]['is_active'] = '';
+                            }
+                        }
+
+                        // 当只有一个规格的时候
+                        if (key == 0 && temp_spec.length == 1) {
+                            temp_spec[i]['value'][k]['is_disabled'] = (temp_spec[i]['value'][k]['is_only_level_one'] || null) != null && (temp_spec[i]['value'][k]['inventory'] || 0) <= 0 ? 'spec-items-disabled' : '';
+                        }
+                    }
+                }
+
+                this.setData({
+                    spec: temp_spec
+                });
+            },
+
+            // 规格确认事件
+            spec_confirm_event(e) {
+                var temp_spec = this.spec;
+                var sku_count = temp_spec.length;
+                var active_count = 0;
+                var spec = [];
+                if (sku_count > 0) {
+                    for (var i in temp_spec) {
+                        for (var k in temp_spec[i]['value']) {
+                            if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
+                                active_count++;
+                                spec.push({
+                                    type: temp_spec[i]['name'],
+                                    value: temp_spec[i]['value'][k]['name']
+                                });
+                            }
+                        }
+                    }
+                    if (active_count < sku_count) {
+                        app.globalData.showToast('请选择规格');
+                        return false;
+                    }
+                }
+
+                // 关闭弹窗
+                this.setData({
+                    popup_status: false
+                });
+
+                // 调用父级
+                this.$emit('specConfirmEvent', {
+                    goods_id: this.goods_id,
+                    spec: spec,
+                    stock: this.buy_min_number,
+                    out_value: this.out_value,
+                });
+            }
+        }
+    };
+</script>
+<style>
+    .goods-spec-choice-container .close {
+        position: absolute;
+        top: 20rpx;
+        right: 20rpx;
+        z-index: 2;
+    }
+    .goods-spec-choice-content {
+        max-height: 50vh;
+        overflow-y: scroll;
+        overflow-x: hidden;
+        margin-top: 20rpx;
+    }
+    .goods-spec-choice-container .item .spec button {
+        background-color: #f5f5f5;
+        color: #666;
+        border: 1px solid #ccc;
+    }
+    .goods-spec-choice-container .item .spec button:not(:last-child) {
+        margin-right: 25rpx;
+    }
+    .goods-spec-choice-container .item .spec button image {
+        width: 40rpx;
+        height: 40rpx !important;
+    }
+    .goods-spec-choice-container .spec-dont-choose {
+        color: #b4b3b3 !important;
+        background-color: #ffffff !important;
+        border: 1px solid #ebeaea !important;
+    }
+    .goods-spec-choice-container .spec-dont-choose image {
+        opacity: 0.5;
+    }
+    .goods-spec-choice-container .spec-items-disabled {
+        color: #d2cfcf !important;
+        background-color: #ffffff !important;
+        border: 1px dashed #d5d5d5 !important;
+    }
+    .goods-spec-choice-container .spec-items-disabled image {
+        opacity: 0.3;
+    }
+</style>

+ 77 - 0
components/icon-nav/icon-nav.vue

@@ -0,0 +1,77 @@
+<template>
+    <view>
+        <view v-if="propData.length > 0" class="icon-nav-list">
+            <view v-for="(item, index) in propData" :key="index" class="item">
+                <view :class="'item-content '+((item.bg_color || null) == null ? 'item-exposed' : '')" :data-value="item.event_value" :data-type="item.event_type" @tap="navigation_event" :style="((item.bg_color || null) == null ? '' : 'background-color:'+item.bg_color+';')">
+                    <image :src="item.images_url" mode="aspectFit"></image>
+                </view>
+                <view class="title">{{item.name}}</view>
+            </view>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    export default {
+        data() {
+            return {};
+        },
+        components: {},
+        props: {
+            propData: Array
+        },
+        methods: {
+            navigation_event(e) {
+                app.globalData.operation_event(e);
+            }
+        }
+    };
+</script>
+<style>
+    .icon-nav-list {
+        overflow: hidden;
+        margin-bottom: 20rpx;
+    }
+    .icon-nav-list .item {
+        width: calc(20% - 20rpx);
+        float: left;
+        padding: 20rpx 10rpx 0 10rpx;
+        /* #ifdef H5 */
+        cursor: pointer;
+        /* #endif */
+    }
+    .icon-nav-list .item .item-content {
+        border-radius: 50%;
+        padding: 20rpx;
+        text-align: center;
+        margin: 0 auto;
+        -webkit-box-shadow: 0 2px 12px rgb(226 226 226 / 95%);
+        box-shadow: 0 2px 12px rgb(226 226 226 / 95%);
+    }
+	.icon-nav-list .item .item-content,
+    .icon-nav-list .item image {
+        width: 50rpx !important;
+        height: 50rpx !important;
+    }
+	.icon-nav-list .item .item-exposed {
+		padding: 0;
+		-webkit-box-shadow: none;
+		box-shadow: none;
+	}
+	.icon-nav-list .item .item-exposed,
+	.icon-nav-list .item .item-exposed image {
+		width: 90rpx !important;
+		height: 90rpx !important;
+	}
+    .icon-nav-list .item .title {
+        margin-top: 6rpx;
+        font-size: 28rpx;
+        text-align: center;
+        -o-text-overflow: ellipsis;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        white-space: nowrap;
+        max-width: 100%;
+        color: #888;
+    }
+</style>

文件差異過大導致無法顯示
+ 1357 - 0
components/layout/layout.vue


+ 89 - 0
components/no-data/no-data.vue

@@ -0,0 +1,89 @@
+<template>
+    <view>
+        <!-- 1 加载中 -->
+        <view v-if="propStatus == 1" class="no-data-box no-data-loading loading-animation">
+            <text>{{title}}</text>
+        </view>
+
+        <!-- 2 处理错误 -->
+        <view v-else-if="propStatus == 2" class="no-data-box">
+            <image :src="static_dir+'error.png'" mode="widthFix"></image>
+            <view class="no-data-tips">{{propMsg || '处理错误'}}</view>
+        </view>
+
+        <!-- 0 默认没有数据 -->
+        <view v-else-if="propStatus == 0" class="no-data-box">
+            <image :src="static_dir+'empty.png'" mode="widthFix"></image>
+            <view class="no-data-tips">{{propMsg || '没有相关数据'}}</view>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    export default {
+        data() {
+            return {
+                static_dir: '/static/images/common/',
+                title: app.globalData.get_application_title(),
+            };
+        },
+        components: {},
+        props: {
+            propStatus: {
+            	type: [Number,String],
+            	default: 0
+            },
+            propMsg: {
+            	type: String,
+            	default: '没有相关数据'
+            }
+        },
+        methods: {}
+    };
+</script>
+<style>
+    .no-data-box {
+        padding-top: 17%;
+        text-align: center;
+    }
+    .no-data-box image {
+        width: 160rpx;
+        margin-bottom: 30rpx;
+    }
+    .no-data-box .no-data-tips {
+        font-size: 28rpx;
+        color: #a6a6a6;
+    }
+    .no-data-loading text {
+        color: #999;
+    }
+    .loading-animation {
+        background: #e7e7e7 -webkit-linear-gradient(left,#c6c6c6 0%, #c6c6c6 90%) no-repeat 0 0;
+        background-size: 20% 100%; 
+        -webkit-background-clip: text;
+        -webkit-text-fill-color: transparent;
+        font-size: 60rpx;
+        font-weight: bold;
+        padding-top: 20%;
+    }
+    .loading-animation {
+        -webkit-animation: loading-animation 2s linear infinite;
+        animation: loading-animation 2s linear infinite;
+    }
+    @-webkit-keyframes loading-animation {
+        0% {
+            background-position: 0 0;
+        }
+        100% {
+            background-position: 100% 100%;
+        }
+    }
+    @keyframes loading-animation {
+        0% {
+            background-position: 0 0;
+        }
+        100% {
+            background-position: 100% 100%;
+        }
+    }
+</style>

+ 290 - 0
components/online-service/online-service.vue

@@ -0,0 +1,290 @@
+<template>
+    <block v-if="online_service_status == 1">
+        <!-- 是否商品页样式 -->
+        <view v-if="propIsGoods == true" class="goods-chat-container item fl cp">
+            <block v-if="is_chat == 1">
+                <view @tap="chat_event">
+                    <image class="icon" :src="common_static_url+'chat-icon.png'" mode="scaleToFill"></image>
+                    <text class="text dis-block text-size-xs cr-gray">客服</text>
+                </view>
+            </block>
+            <block v-else>
+                <!-- #ifdef MP-WEIXIN || MP-TOUTIAO || MP-BAIDU || MP-KUAISHOU -->
+                <button open-type="contact" :show-message-card="propCard" :send-message-title="propTitle" :send-message-path="propPath" :send-message-img="propImg">
+                    <image class="icon" :src="common_static_url+'chat-icon.png'" mode="scaleToFill"></image>
+                <!-- #endif -->
+                <!-- #ifdef MP-ALIPAY -->
+                <button open-type="contact" class="alipay-contact">
+                    <contact-button :tnt-inst-id="mini_alipay_tnt_inst_id" :scene="mini_alipay_scene" :alipay-card-no="mini_alipay_openid || ''" :icon="common_static_url+'chat-icon.png'" size="40rpx*40rpx" />
+                <!-- #endif -->
+                <!-- #ifdef H5 || APP -->
+                <button type="default" @tap="call_event">
+                    <image class="icon" :src="common_static_url+'chat-icon.png'" mode="scaleToFill"></image>
+                <!-- #endif -->
+                    <text class="text dis-block text-size-xs cr-gray">客服</text>
+                </button>
+            </block>
+        </view>
+        <!-- 默认浮动展示-可拖拽位置 -->
+        <view v-else>
+            <block v-if="is_online_service_fixed == 1">
+                <movable-area class="online-service-movable-container" :style="'height: calc(100% - '+height_dec+'rpx);top:'+top+'rpx;'">
+                    <movable-view direction="all" :x="x" :y="y" :animation="false" class="online-service-event-submit">
+                        <block v-if="is_chat == 1">
+                            <button type="default" :class="common_ent" @tap="chat_event">
+                                <image class="icon dis-block" :src="common_static_url+'online-service-icon.png'"></image>
+                            </button>
+                        </block>
+                        <block v-else>
+                            <!-- #ifdef MP-WEIXIN || MP-TOUTIAO || MP-BAIDU -->
+                            <button open-type="contact" :class="common_ent" :show-message-card="propCard" :send-message-title="propTitle" :send-message-path="propPath" :send-message-img="propImg">
+                                <image class="icon dis-block" :src="common_static_url+'online-service-icon.png'"></image>
+                            </button>
+                            <!-- #endif -->
+                            <!-- #ifdef MP-ALIPAY -->
+                            <button open-type="contact" :class="'alipay-contact '+common_ent">
+                                <contact-button :tnt-inst-id="mini_alipay_tnt_inst_id" :scene="mini_alipay_scene" :alipay-card-no="mini_alipay_openid || ''" :icon="common_static_url+'online-service-icon.png'" size="40rpx*40rpx" />
+                            </button>
+                            <!-- #endif -->
+                            <!-- #ifdef H5 || APP -->
+                            <button type="default" :class="common_ent" @tap="call_event">
+                                <image class="icon dis-block" :src="common_static_url+'online-service-icon.png'"></image>
+                            </button>
+                            <!-- #endif -->
+                        </block>
+                    </movable-view>
+                </movable-area>
+            </block>
+        </view>
+    </block>
+</template>
+<script>
+    const app = getApp();
+    var common_static_url = app.globalData.get_static_url('common');
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                is_chat: 0,
+                chat_url: null,
+                common_app_customer_service_tel: null,
+                online_service_status: 0,
+                is_online_service_fixed: app.globalData.data.is_online_service_fixed,
+                mini_alipay_tnt_inst_id: null,
+                mini_alipay_scene: null,
+                mini_alipay_openid: null,
+                system: null,
+                x: 0,
+                y: 0,
+                top: 0,
+                height_dec: 0,
+                is_first: 1,
+                common_ent: ''
+            };
+        },
+        components: {},
+        props: {
+            propIsGoods: {
+            	type: Boolean,
+            	default: false
+            },
+            propIsBar: {
+            	type: Boolean,
+            	default: false
+            },
+            propIsNav: {
+            	type: Boolean,
+            	default: false
+            },
+            propCard: {
+            	type: Boolean,
+            	default: false
+            },
+            propTitle: {
+            	type: String,
+            	default: ''
+            },
+            propImg: {
+            	type: String,
+            	default: ''
+            },
+            propPath: {
+            	type: String,
+            	default: ''
+            },
+            propIsGrayscale: {
+            	type:Number,
+            	default: 0
+            },
+            propIsChat: {
+            	type:Number,
+            	default: 0
+            },
+            propChatUrl: {
+            	type: String,
+            	default: ''
+            },
+        },
+        // 属性值改变监听
+        watch: {
+            // 是否灰度
+        	propIsGrayscale(value, old_value) {
+                this.common_ent = (value == 1) ? 'grayscale' : '';
+        	}
+        },
+        // 页面被展示
+        created: function(e) {
+            this.init_config();
+
+            // 非首次进入则重新初始化配置接口
+            if (this.is_first == 0) {
+                app.globalData.init_config();
+            }
+
+            // 数据设置
+            var system = app.globalData.get_system_info(null, null, true);
+            var width = app.globalData.window_width_handle(system.windowWidth);
+            var height = app.globalData.window_height_handle(system);
+            
+            // 页面是否定义导航
+            var top_h = this.propIsNav ? 170 : 0;
+            this.setData({
+                is_first: 0,
+                system: system,
+                // 位置坐标
+                x: width - 43,
+                y: height - 380,
+                // 展示位置处理
+                top: top_h,
+                height_dec: top_h,
+                // #ifdef H5 || APP
+                top: 90,
+                height_dec: this.propIsBar ? 190 : 90,
+                // #endif
+                // 是否使用客服系统
+                is_chat: this.propIsChat || this.is_chat,
+                chat_url: this.propChatUrl || this.chat_url,
+            });
+        },
+        methods: {
+            // 初始化配置
+            init_config(status) {
+                if ((status || false) == true) {
+                    // 是否使用客服系统
+                    var is_chat = app.globalData.get_config('plugins_base.chat.data.is_mobile_chat', 0);
+                    var chat_url = app.globalData.get_config('plugins_base.chat.data.chat_url');
+                    if(is_chat == 1 && chat_url != null) {
+                        this.setData({
+                            is_chat: is_chat,
+                            chat_url: chat_url,
+                            common_app_customer_service_tel: app.globalData.get_config('config.common_app_customer_service_tel'),
+                            online_service_status: app.globalData.get_config('config.common_app_is_online_service', 0)
+                        });
+                    } else {
+                        // #ifdef MP-WEIXIN || MP-TOUTIAO || MP-BAIDU || MP-ALIPAY || MP-KUAISHOU || H5 || APP
+                        this.setData({
+                            common_app_customer_service_tel: app.globalData.get_config('config.common_app_customer_service_tel'),
+                            online_service_status: app.globalData.get_config('config.common_app_is_online_service', 0)
+                        });
+                        // #endif
+                        
+                        // #ifdef H5 || APP
+                        if((this.common_app_customer_service_tel || null) == null) {
+                            this.setData({
+                                online_service_status: 0
+                            });
+                        }
+                        // #endif
+                        
+                        // #ifdef MP-ALIPAY
+                        // 在线客服开启,获取用户openid
+                        if(this.online_service_status == 1)
+                        {
+                            this.setData({
+                                mini_alipay_tnt_inst_id: app.globalData.get_config('config.common_app_mini_alipay_tnt_inst_id'),
+                                mini_alipay_scene: app.globalData.get_config('config.common_app_mini_alipay_scene'),
+                                mini_alipay_openid: app.globalData.get_user_cache_info('alipay_openid')
+                            });
+                        }
+                        // #endif
+                    }
+                } else {
+                    app.globalData.is_config(this, 'init_config');
+                }
+            },
+
+            // 客服电话
+            call_event() {
+                if (this.common_app_customer_service_tel == null) {
+                    app.globalData.showToast("客服电话有误");
+                } else {
+                    app.globalData.call_tel(this.common_app_customer_service_tel);
+                }
+            },
+            
+            // 进入客服系统
+            chat_event() {
+                var url = this.propChatUrl || this.chat_url || null;
+                app.globalData.chat_entry_handle(url);
+            }
+        }
+    };
+</script>
+<style>
+    .online-service-movable-container {
+        position: fixed;
+        width: 100%;
+        height: 100%;
+        top: 0;
+        left: 0;
+        background: transparent;
+        pointer-events: none;
+        z-index: 2;
+    }
+    .online-service-event-submit {
+        pointer-events: auto;
+    }
+    .online-service-event-submit,
+    .online-service-event-submit button {
+        width: 31px;
+        height: 31px;
+        border-radius: 50%;
+    }
+    .online-service-event-submit button {
+        border: 0;
+        padding: 5px;
+        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+        background: rgba(0, 0, 0, 0.6);
+    }
+    .online-service-event-submit .icon {
+        width: 21px !important;
+        height: 21px !important;
+    }
+    .goods-chat-container button {
+        padding: 0;
+        border: 0;
+        line-height: initial;
+        font-size: 24rpx;
+        background: transparent;
+    }
+    .goods-chat-container .icon {
+        width: 40rpx;
+        height: 40rpx;
+        margin: 10rpx 0 5rpx 0;
+    }
+    .goods-chat-container .text {
+        margin-top: -10rpx;
+    }
+    /* #ifdef MP-ALIPAY */
+    .goods-chat-container .alipay-contact {
+        margin-top: 10rpx;
+    }
+    .goods-chat-container .alipay-contact .text {
+        margin-top: -5rpx;
+    }
+    .online-service-event-submit contact-button {
+        line-height: initial;
+        display: block;
+    }
+    /* #endif */
+</style>

+ 152 - 0
components/popup/popup.vue

@@ -0,0 +1,152 @@
+<template>
+    <view>
+        <view :class="'popup ' + (propClassname || '') + ' ' + ((propShow || false) ? 'popup-show' : '') + ' ' + ((propAnimation || true) ? 'animation': '' )" :disable-scroll="propDisablescroll">
+            <view class="popup-mask" v-if="propMask || true" @tap="on_mask_tap"></view>
+            <view :class="'popup-content bottom-line-exclude popup-' + (propPosition || 'bottom')+ ' '+(propIsBar ? 'popup-bar' : '')" :style="'left:'+popup_content_left_value+'px'">
+                <slot></slot>
+            </view>
+        </view>
+    </view>
+</template>
+<script>
+    export default {
+        data() {
+            return {
+                popup_content_left_value: 'auto'
+            };
+        },
+        components: {},
+        props: {
+            propClassname: {
+            	type: String,
+            	default: ''
+            },
+            propShow: {
+            	type: Boolean,
+            	default: false
+            },
+            propPosition: {
+            	type: String,
+            	default: 'bottom'
+            },
+            propMask: {
+            	type: Boolean,
+            	default: true
+            },
+            propAnimation: {
+            	type: Boolean,
+            	default: true
+            },
+            propDisablescroll: {
+            	type: Boolean,
+            	default: false
+            },
+            propIsBar: {
+            	type: Boolean,
+            	default: false
+            }
+        },
+        // 属性值改变监听
+        watch: {
+            // 监听状态
+        	propShow(value, old_value) {
+                this.left_handle();
+        	}
+        },
+        // 组建创建
+        created: function() {
+            this.left_handle();
+        },
+        methods: {
+            // 事件处理
+            on_mask_tap: function on_mask_tap() {
+                this.$emit('onclose', {
+                    detail: {}
+                }, {});
+            },
+            // 左边距位置处理
+            left_handle() {
+                // 处理内容左边距、避免父级设置内边距影响
+                var width = uni.getSystemInfoSync().windowWidth;
+                var left = 0;
+                if(width > 800) {
+                    left = (width-800)/2;
+                }
+                this.popup_content_left_value = left;
+            }
+        }
+    };
+</script>
+<style>
+    .popup-content {
+        position: fixed;
+        background: #fff;
+        z-index: 101;
+        overflow: hidden;
+    }
+    .popup-mask {
+        position: fixed;
+        top: 0;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        background-color: rgba(0, 0, 0, 0.6);
+        opacity: 0;
+        pointer-events: none;
+        z-index: 100;
+    }
+    .popup-left {
+        transform: translateX(-100%);
+        left: 0;
+        top: 0;
+        bottom: 0;
+    }
+    .popup-right {
+        transform: translateX(100%);
+        right: 0;
+        top: 0;
+        bottom: 0;
+    }
+    .popup-top {
+        top: 0;
+        width: 100vw;
+        transform: translateY(-100%);
+    }
+    .popup-bottom {
+        bottom: var(--window-bottom);
+        width: 100vw;
+        transform: translateY(100%);
+    }
+    .popup-show .popup-content {
+        transform: none;
+    }
+    .popup-show .popup-mask {
+        opacity: 1;
+        pointer-events: auto;
+    }
+    .popup.animation .popup-mask,
+    .popup.animation .popup-content {
+        transition: all 0.25s linear;
+    }
+    .popup-top {
+        border-bottom-right-radius: 20rpx;
+        border-bottom-left-radius: 20rpx;
+    }
+    .popup-bottom {
+        border-top-right-radius: 20rpx;
+        border-top-left-radius: 20rpx;
+    }
+    .popup-left {
+        border-top-right-radius: 20rpx;
+        border-bottom-right-radius: 20rpx;
+    }
+    .popup-right {
+        border-top-left-radius: 20rpx;
+        border-bottom-left-radius: 20rpx;
+    }
+    .popup-bar {
+        /* #ifdef H5 || APP */
+        bottom: var(--window-bottom) !important;
+        /* #endif */
+    }
+</style>

+ 242 - 0
components/quick-nav/quick-nav.vue

@@ -0,0 +1,242 @@
+<template>
+    <view>
+        <!-- 开启事件 -->
+        <movable-area v-if="quick_status == 1" :class="'quick-movable-container '+ common_ent" :style="'height: calc(100% - '+height_dec+'rpx);top:'+top+'rpx;'">
+            <movable-view direction="all" :x="x" :y="y" :animation="false" class="quick-event-submit bg-main" @tap="quick_open_event">
+                <image :src="common_static_url+'quick-icon.png'" mode="widthFix"></image>
+            </movable-view>
+        </movable-area>
+
+        <!-- 弹窗 -->
+        <component-popup :propShow="popup_status" :propIsBar="propIsBar" propPosition="bottom" @onclose="quick_close_event">
+            <view :class="'nav-popup-container '+common_ent">
+                <view class="close oh">
+                    <view class="icon-right" @tap.stop="quick_close_event">
+                        <icon type="clear" size="20"></icon>
+                    </view>
+                </view>
+                <view class="nav-popup-content">
+                    <view v-if="data_list.length > 0" class="nav-data-list">
+                        <view v-for="(item, index) in data_list" :key="index" class="item cp">
+							<view :class="'item-content '+((item.bg_color || null) == null ? 'item-exposed' : '')" :data-value="item.event_value" :data-type="item.event_type" @tap="navigation_event" :style="((item.bg_color || null) == null ? '' : 'background-color:'+item.bg_color+';')">
+							    <image :src="item.images_url" mode="aspectFit"></image>
+							</view>
+                            <view class="title">{{item.name}}</view>
+                        </view>
+                    </view>
+                    <view v-else>
+                        <!-- 提示信息 -->
+                        <component-no-data :propStatus="0"></component-no-data>
+                    </view>
+                </view>
+            </view>
+        </component-popup>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentPopup from "../popup/popup";
+    import componentNoData from "../no-data/no-data";
+    var common_static_url = app.globalData.get_static_url('common');
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                popup_status: false,
+                quick_status: 0,
+                data_list: [],
+                system: null,
+                x: 0,
+                y: 0,
+                top: 0,
+                height_dec: 0,
+                is_first: 1,
+                common_ent: ''
+            };
+        },
+        components: {
+            componentPopup,
+            componentNoData
+        },
+        props: {
+            propIsBar: {
+            	type: Boolean,
+            	default: false
+            },
+            propIsNav: {
+            	type: Boolean,
+            	default: false
+            },
+            propIsGrayscale: {
+            	type:Number,
+            	default: 0
+            }
+        },
+        // 属性值改变监听
+        watch: {
+            // 是否灰度
+        	propIsGrayscale(value, old_value) {
+                this.common_ent = (value == 1) ? 'grayscale' : '';
+        	}
+        },
+        // 页面被展示
+        created: function() {
+            this.init_config();
+            
+            // 页面是否定义导航
+            var value = this.propIsNav ? 170 : 0;
+            this.top = value
+            this.height_dec = value;
+            // #ifdef H5 || APP
+            this.top = 90;
+            this.height_dec = this.propIsBar ? 190 : 90;
+            // #endif
+
+            // 非首次进入则重新初始化配置接口
+            if (this.is_first == 0) {
+                app.globalData.init_config();
+            }
+
+            // 数据设置
+            var system = app.globalData.get_system_info(null, null, true);
+            var height = app.globalData.window_height_handle(system);
+            this.setData({
+                is_first: 0,
+                system: system,
+                x: 12,
+                y: height - 280
+            });
+        },
+        methods: {
+            // 初始化配置
+            init_config(status) {
+                if ((status || false) == true) {
+                    this.setData({
+                        data_list: app.globalData.get_config('quick_nav') || [],
+                        quick_status: app.globalData.get_config('config.home_navigation_main_quick_status') || 0
+                    });
+                } else {
+                    app.globalData.is_config(this, 'init_config');
+                }
+            },
+
+            // 弹层开启
+            quick_open_event(e) {
+                this.setData({
+                    popup_status: true,
+                    data_list: app.globalData.get_config('quick_nav') || []
+                });
+            },
+
+            // 弹层关闭
+            quick_close_event(e) {
+                this.setData({
+                    popup_status: false
+                });
+            },
+
+            // 操作事件
+            navigation_event(e) {
+                app.globalData.operation_event(e);
+            }
+        }
+    };
+</script>
+<style>
+    /**
+     * 按钮
+     */
+    .quick-movable-container {
+        position: fixed;
+        width: 100%;
+        height: 100%;
+        top: 0;
+        left: 0;
+        background: transparent;
+        pointer-events: none;
+        z-index: 2;
+    }
+    .quick-event-submit {
+        pointer-events: auto;
+        width: 31px;
+        height: 31px;
+        border-radius: 50%;
+        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+        opacity: 0.8;
+    }
+    .quick-event-submit image {
+        width: 17px !important;
+        height: 17px !important;
+        margin: 7px auto 7px auto;
+        display: block;
+    }
+
+    /**
+     * 弹窗
+     */
+    .nav-popup-container {
+        padding: 20rpx 10rpx 0 10rpx;
+        background: #fff;
+    }
+    .nav-popup-container .close {
+        overflow: hidden;
+    }
+    .nav-popup-container .close .icon-right {
+        float: right;
+    }
+    .nav-popup-content {
+        max-height: 80vh;
+        overflow-y: scroll;
+        overflow-x: hidden;
+        padding-bottom: 20rpx;
+    }
+
+    /**
+     * 内容
+     */
+    .nav-data-list {
+        overflow: hidden;
+        background: #fff;
+    }
+    .nav-data-list .item {
+        width: calc(25% - 60rpx);
+        float: left;
+        padding: 30rpx;
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+    }
+    .nav-data-list .item-content {
+        border-radius: 50%;
+        padding: 20rpx;
+        text-align: center;
+        margin: 0 auto;
+        -webkit-box-shadow: 0 2px 12px rgb(226 226 226 / 95%);
+        box-shadow: 0 2px 12px rgb(226 226 226 / 95%);
+    }
+	.nav-data-list .item-content,
+    .nav-data-list .item image {
+        width: 70rpx !important;
+        height: 70rpx !important;
+    }
+	.nav-data-list .item .item-exposed {
+		padding: 0;
+		-webkit-box-shadow: none;
+		box-shadow: none;
+	}
+	.nav-data-list .item .item-exposed,
+	.nav-data-list .item .item-exposed image {
+		width: 110rpx !important;
+		height: 110rpx !important;
+	}
+    .nav-data-list .item .title {
+        margin-top: 10rpx;
+        font-size: 28rpx !important;
+        text-align: center;
+        -o-text-overflow: ellipsis;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        white-space: nowrap;
+        max-width: 100%;
+    }
+</style>

+ 193 - 0
components/realstore-list/realstore-list.vue

@@ -0,0 +1,193 @@
+<template>
+    <view>
+        <view v-if="(data_list || null) != null && data_list.length > 0" class="plugins-realstore-data-list oh">
+            <block v-for="(item, index) in data_list" :key="index">
+                <view class="item bg-white padding-main border-radius-main pr spacing-mb" :data-value="item.url" @tap="url_event">
+                    <view class="base oh">
+                        <!-- 基础内容 -->
+                        <image :src="item.logo" mode="widthFix" class="logo circle fl br"></image>
+                        <view class="base-right fr">
+                            <view :class="'status-icon pa text-size-xs '+((item.status_info.status == 1) ? 'bg-main cr-white' : 'bg-gray cr-gray')">{{item.status_info.msg}}</view>
+                            <view class="title fw-b text-size single-text">
+                                <text v-if="(item.alias || null) != null" class="va-m title-icon round br-main cr-main text-size-xs padding-left-sm padding-right-sm margin-right-xs">{{item.alias}}</text>
+                                <text class="va-m">{{item.name}}</text>
+                            </view>
+                            <view class="margin-top-xs text-size-xs cr-grey">
+                                <view v-if="(item.status_info.time || null) != null">营业时间:{{item.status_info.time}}</view>
+                                <view v-if="(item.distance || null) != null">距离您{{item.distance}}</view>
+                            </view>
+                        </view>
+                    </view>
+                    <!-- 地址 -->
+                    <view class="margin-top-sm oh cp">
+                        <view class="dis-inline-block va-m">
+                            <uni-icons type="location-filled" size="32rpx" color="#8d8d8d"></uni-icons>
+                        </view>
+                        <view class="address-content single-text cr-base margin-left-xs dis-inline-block text-size-xs va-m" :data-value="item.province_name+item.city_name+item.county_name+item.address" @tap.stop="text_copy_event">{{item.province_name}}{{item.city_name}}{{item.county_name}}{{item.address}}</view>
+                    </view>
+                    <!-- 右侧操作 -->
+                    <view class="icon-list pa">
+                        <!-- #ifndef MP-KUAISHOU -->
+                        <view v-if="(item.lat != 0 && item.lng != 0)" class="icon-item bg-green circle dis-inline-block tc cp" :data-index="index" @tap.stop="address_map_event">
+                            <uni-icons type="paperplane-filled" size="32rpx" color="#fff"></uni-icons>
+                        </view>
+                        <!-- #endif -->
+                        <view v-if="(item.service_tel || null) != null" class="icon-item bg-yellow circle dis-inline-block tc cp" :data-value="item.service_tel" @tap.stop="tel_event">
+                            <uni-icons type="phone-filled" size="32rpx" color="#fff"></uni-icons>
+                        </view>
+                        <view v-if="propIsFavor" :class="'icon-item circle dis-inline-block tc cp pr '+((item.is_favor || 0) == 1 ? 'bg-red' : 'bg-gray')" :data-index="index" @tap.stop="favor_event">
+                            <uni-icons type="heart-filled" size="32rpx" color="#fff"></uni-icons>
+                        </view>
+                    </view>
+                </view>
+            </block>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    export default {
+        data() {
+            return {
+                data_list: [],
+                favor_user: []
+            };
+        },
+        components: {},
+        props: {
+            propIsFavor: {
+            	type: Boolean,
+            	default: true
+            },
+            propDataList: {
+            	type: Array,
+            	default: () => []
+            },
+            propFavorUser: {
+            	type: Array,
+            	default: () => []
+            }
+        },
+        // 属性值改变监听
+        watch: {
+            // 数据列表
+        	propDataList(value, old_value) {
+                this.setData({
+                    data_list: value
+                });
+                this.data_list_handle();
+        	}
+        },
+        // 页面被展示
+        created: function(e) {        
+            this.setData({
+                data_list: this.propDataList,
+                favor_user: this.propFavorUser
+            });
+            this.data_list_handle();
+        },
+        methods: {
+            // 数据列表处理
+            data_list_handle() {
+                var temp_data_list = this.data_list;
+                for(var i in temp_data_list) {
+                    temp_data_list[i]['is_favor'] = (this.favor_user.indexOf(temp_data_list[i]['id']) == -1) ? 0 : 1;
+                }
+                this.setData({
+                    data_list: temp_data_list
+                });
+            },
+
+            // 收藏事件
+            favor_event(e) {
+                if(!app.globalData.is_single_page_check()) {
+                    return false;
+                }
+                var user = app.globalData.get_user_info(this, 'favor_event');
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.navigateTo({
+                            url: "/pages/login/login?event_callback=favor_event"
+                        });
+                        return false;
+                    } else {
+                        var index = e.currentTarget.dataset.index;
+                        var info = this.data_list[index];
+                        uni.showLoading({
+                            title: '处理中...'
+                        });
+                        uni.request({
+                            url: app.globalData.get_request_url("reversal", "favor", "realstore"),
+                            method: 'POST',
+                            data: {
+                                "id": info.id
+                            },
+                            dataType: 'json',
+                            success: res => {
+                                uni.hideLoading();
+                                if (res.data.code == 0) {
+                                    var temp_data = this.data_list;
+                                    var temp_favor = this.favor_user;
+                                    temp_data[index]['is_favor'] = res.data.data.status;
+                                    if(res.data.data.status == 1) {
+                                        if(temp_favor.indexOf(info.id) == -1) {
+                                            temp_favor.push(info.id);
+                                        }
+                                    } else {
+                                        if(temp_favor.indexOf(info.id) != -1) {
+                                            temp_favor.splice(index, 1);
+                                        }
+                                    }
+                                    this.setData({
+                                        data_list: temp_data,
+                                        favor_user: temp_favor
+                                    });
+                                    app.globalData.showToast(res.data.msg, "success");
+                                } else {
+                                    if (app.globalData.is_login_check(res.data, this, 'favor_event')) {
+                                        app.globalData.showToast(res.data.msg);
+                                    }
+                                }
+                            },
+                            fail: () => {
+                                uni.hideLoading();
+                                app.globalData.showToast('服务器请求出错');
+                            }
+                        });
+                    }
+                }
+            },
+            
+            // 剪切板
+            text_copy_event(e) {
+                app.globalData.text_copy_event(e);
+            },
+            
+            // 地图查看
+            address_map_event(e) {
+                var info = this.data_list[e.currentTarget.dataset.index];
+                if (info.lat == 0 || info.lng == 0) {
+                    app.globalData.showToast("地址有误");
+                    return false;
+                }
+            
+                // 打开地图
+                var address = (info.province_name || '') + (info.city_name || '') + (info.county_name || '') + (info.address || '');
+                app.globalData.open_location(info.lng, info.lat, info.name, address);
+            },
+            
+            // 电话
+            tel_event(e) {
+                app.globalData.call_tel(e.currentTarget.dataset.value || null);
+            },
+            
+            // url事件
+            url_event(e) {
+                app.globalData.url_event(e);
+            }
+        }
+    };
+</script>
+<style>
+</style>

+ 119 - 0
components/search/search.vue

@@ -0,0 +1,119 @@
+<template>
+    <view>
+        <view class="search-content pr">
+            <view class="search-icon dis-inline-block pa" @tap="search_icon_event">
+                <uni-icons :type="propIcon" size="12" :color="propIconColor"></uni-icons>
+            </view>
+            <input type="text" confirm-type="search" class="round wh-auto dis-block" :placeholder="propPlaceholder" :placeholder-class="propPlaceholderClass" :value="propDefaultValue" @confirm="search_input_event" :style="'color:'+propTextColor+';background:'+propBgColor+';'+((propBrColor || null) != null ? 'border:1px solid '+propBrColor+';' : '')">
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    export default {
+        data() {
+            return {};
+        },
+        components: {},
+        props: {
+            propUrl: {
+            	type: String,
+            	default: '/pages/goods-search/goods-search'
+            },
+            propFormName: {
+            	type: String,
+            	default: 'keywords'
+            },
+            propPlaceholder: {
+            	type: String,
+            	default: '其实搜索很简单 ^_^!'
+            },
+            propDefaultValue: {
+            	type: String,
+            	default: ''
+            },
+            propPlaceholderClass: {
+            	type: String,
+            	default: 'cr-grey'
+            },
+            propTextColor: {
+            	type: String,
+            	default: '#666'
+            },
+            propBgColor: {
+            	type: String,
+            	default: '#f0f0f0'
+            },
+            propBrColor: {
+            	type: String,
+            	default: ''
+            },
+            propIsRequired: {
+            	type: Boolean,
+            	default: true
+            },
+            propIsOnEvent: {
+            	type: Boolean,
+            	default: false
+            },
+            propIcon: {
+            	type: String,
+            	default: 'search'
+            },
+            propIconColor: {
+            	type: String,
+            	default: '#b7b7b7'
+            },
+            propIsIconOnEvent: {
+            	type: Boolean,
+            	default: false
+            },
+        },
+        methods: {
+            // 搜索事件
+            search_input_event(e) {
+                var keywords = e.detail.value || null;
+                
+                // 是否验证必须要传值
+                if (this.propIsRequired && keywords == null) {
+                    app.globalData.showToast("请输入搜索关键字");
+                    return false;
+                }
+                
+                // 是否回调事件
+                if(this.propIsOnEvent) {
+                    this.$emit('onsearch', keywords);
+                } else {
+                    // 进入搜索页面
+                    uni.navigateTo({
+                        url: this.propUrl+'?'+this.propFormName+'=' + keywords
+                    });
+                }
+            },
+            
+            // icon事件
+            search_icon_event(e) {
+                // 是否回调事件
+                if(this.propIsIconOnEvent) {
+                    this.$emit('onicon', {});
+                }
+            }
+        }
+    };
+</script>
+<style>
+    .search-content .search-icon {
+        line-height: 12px;
+        left: 10px;
+        top: calc(50% - 11px);
+        z-index: 1;
+        padding: 5px;
+    }
+    .search-content input {
+        font-size: 12px;
+        padding: 0 15px 0 38px;
+        box-sizing: border-box;
+        height: 30px;
+        line-height: 30px;
+    }
+</style>

+ 185 - 0
components/share-popup/share-popup.vue

@@ -0,0 +1,185 @@
+<template>
+    <view>
+        <component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event">
+            <view class="share-popup bg-white">
+                <view class="close fr oh">
+                    <view class="fr" @tap.stop="popup_close_event">
+                        <icon type="clear" size="20"></icon>
+                    </view>
+                </view>
+                <view class="share-popup-content">
+                    <!-- #ifdef H5 -->
+                    <view class="share-items oh cp" @tap="share_h5_event">
+                        <image :src="common_static_url+'share-user-icon.png'" mode="scaleToFill"></image>
+                        <text class="cr-gray text-size-xs single-text">点击复制地址分享给好友、群聊</text>
+                    </view>
+                    <!-- #endif -->
+                    <!-- #ifdef MP-ALIPAY -->
+                    <view class="share-items oh cp" @tap="share_base_event">
+                        <image :src="common_static_url+'share-user-icon.png'" mode="scaleToFill"></image>
+                        <text class="cr-gray text-size-xs single-text">一键分享给好友、群聊</text>
+                    </view>
+                    <!-- #endif -->
+                    <!-- #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO || MP-KUAISHOU -->
+                    <view class="share-items oh cp">
+                        <button class="dis-block br-0 ht-auto" type="default" size="mini" open-type="share" hover-class="none" @tap="popup_close_event">
+                            <image :src="common_static_url+'share-user-icon.png'" mode="scaleToFill"></image>
+                            <text class="cr-gray text-size-xs single-text">一键分享给好友、群聊</text>
+                        </button>
+                    </view>
+                    <!-- #endif -->
+                    <view v-if="is_goods_poster == 1 && (goods_id || 0) != 0" class="share-items oh cp" @tap="poster_event">
+                        <image :src="common_static_url+'share-friend-icon.png'" mode="scaleToFill"></image>
+                        <text class="cr-gray text-size-xs single-text">生成海报,分享到朋友圈、好友及群聊</text>
+                    </view>
+                </view>
+            </view>
+        </component-popup>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    var common_static_url = app.globalData.get_static_url('common');
+    import componentPopup from "../../components/popup/popup";
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                popup_status: false,
+                is_goods_poster: 0,
+                goods_id: 0
+            };
+        },
+
+        components: {
+            componentPopup
+        },
+
+        created: function() {},
+
+        methods: {
+            // 初始配置
+            init(config = {}) {
+                if(!app.globalData.is_single_page_check()) {
+                    return false;
+                }
+                this.setData({
+                    popup_status: config.status == undefined ? true : config.status,
+                    is_goods_poster: config.is_goods_poster || 0,
+                    goods_id: config.goods_id || 0
+                });
+            },
+
+            // 弹层关闭
+            popup_close_event(e) {
+                this.setData({
+                    popup_status: false
+                });
+            },
+
+            // h5分享
+            share_h5_event() {
+                app.globalData.text_copy_event(app.globalData.get_page_url());
+            },
+
+            // 基础分享事件
+            share_base_event() {
+                this.setData({
+                    popup_status: false
+                });
+                uni.pageScrollTo({
+                    scrollTop: 0,
+                    duration: 300,
+                    complete: res => {
+                        setTimeout(function() {
+                            uni.showShareMenu();
+                        }, 500);
+                    }
+                });
+            },
+
+            // 商品海报分享
+            poster_event() {
+                var user = app.globalData.get_user_info(this, 'poster_event');
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.navigateTo({
+                            url: "/pages/login/login?event_callback=poster_event"
+                        });
+                        return false;
+                    } else {
+                        uni.showLoading({
+                            title: '生成中...'
+                        });
+                        uni.request({
+                            url: app.globalData.get_request_url('goodsposter', 'distribution', 'distribution'),
+                            method: 'POST',
+                            data: {goods_id: this.goods_id},
+                            dataType: 'json',
+                            success: res => {
+                                uni.hideLoading();
+            
+                                if (res.data.code == 0) {
+                                    uni.previewImage({
+                                        current: res.data.data,
+                                        urls: [res.data.data]
+                                    });
+                                } else {
+                                    if (app.globalData.is_login_check(res.data, this, 'poster_event')) {
+                                        app.globalData.showToast(res.data.msg);
+                                    }
+                                }
+                            },
+                            fail: () => {
+                                uni.hideLoading();
+                                app.globalData.showToast('服务器请求出错');
+                            }
+                        });
+                    }
+                }
+            }
+        }
+    };
+</script>
+<style>
+    .share-popup {
+        padding: 20rpx 10rpx 0 10rpx;
+        position: relative;
+    }
+    .share-popup .close {
+        position: absolute;
+        top: 20rpx;
+        right: 20rpx;
+        z-index: 2;
+    }
+    .share-popup-content {
+        padding: 0 20rpx;
+        margin-top: 40rpx;
+        text-align: left;
+    }
+    .share-popup-content .share-items {
+        padding: 30rpx 0;
+        height: 85rpx;
+    }
+    .share-popup-content .share-items:not(:first-child) {
+        border-top: 1px solid #f0f0f0;
+    }
+    .share-popup-content .share-items button {
+        background: transparent;
+        padding: 0;
+        width: 100%;
+        text-align: left;
+        margin: 0;
+    }
+    .share-popup-content .share-items image {
+        width: 80rpx;
+        height: 80rpx;
+        vertical-align: middle;
+        margin-right: 20rpx;
+    }
+    .share-popup-content .share-items .single-text {
+        width: calc(100% - 100rpx);
+        line-height: 85rpx;
+    }
+</style>

+ 78 - 0
components/shop-list/shop-list.vue

@@ -0,0 +1,78 @@
+<template>
+    <view>
+        <view v-if="(data_list || null) != null && data_list.length > 0" class="plugins-shop-data-list oh">
+            <block v-for="(item, index) in data_list" :key="index">
+                <view class="item oh border-radius-main padding-main bg-white arrow-right spacing-mb">
+                    <view :data-value="item.url" @tap="url_event">
+                        <image :src="item.logo" mode="aspectFit" class="logo circle fl br"></image>
+                        <view class="right-content fr">
+                            <view class="title single-text">
+                                <!-- 认证信息 -->
+                                <view v-if="(config.is_enable_auth || 0) == 1 && ((item.auth_type != -1 && (item.auth_type_msg || null) != null) || ((item.bond_status || 0) == 1 && (item.bond_status_msg || null) != null))" class="auth-icon dis-inline-block">
+                                    <!-- 实名认证 -->
+                                    <block v-if="item.auth_type != -1 && (item.auth_type_msg || null) != null">
+                                        <block v-if="item.auth_type == 0">
+                                            <image :src="config.shop_auth_personal_icon" class="icon va-m" mode="aspectFill"></image>
+                                        </block>
+                                        <block v-if="item.auth_type == 1">
+                                            <image :src="config.shop_auth_company_icon" class="icon va-m" mode="aspectFill"></image>
+                                        </block>
+                                    </block>
+                                    <!-- 保证金认证 -->
+                                    <block v-if="(item.bond_status || 0) == 1 && (item.bond_status_msg || null) != null">
+                                        <image :src="config.shop_auth_bond_icon" class="icon va-m" mode="aspectFill"></image>
+                                    </block>
+                                </view>
+                                <!-- 标题 -->
+                                <text class="fw-b text-size va-m">{{item.name}}</text>
+                            </view>
+                            <view class="desc multi-text cr-base text-size-xs margin-top-sm">{{item.describe}}</view>
+                        </view>
+                    </view>
+                </view>
+            </block>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    export default {
+        data() {
+            return {
+                config: {},
+                data_list: []
+            };
+        },
+        components: {},
+        props: {
+            propConfig: {
+            	type: [String,Object],
+            	default: null
+            },
+            propDataList: {
+            	type: Array,
+            	default: () => []
+            }
+        },
+        // 属性值改变监听
+        watch: {
+            
+        },
+        // 页面被展示
+        created: function(e) {  
+            var config = ((this.propConfig || null) == null ? app.globalData.get_config('plugins_base.shop.data') : this.propConfig) || {};
+            this.setData({
+                config: config,
+                data_list: this.propDataList
+            });
+        },
+        methods: {
+            // url事件
+            url_event(e) {
+                app.globalData.url_event(e);
+            }
+        }
+    };
+</script>
+<style>
+</style>

+ 63 - 0
components/slider/slider.vue

@@ -0,0 +1,63 @@
+<template>
+    <view>
+        <swiper :indicator-dots="propData.length > 0" :indicator-color="indicator_color" :indicator-active-color="indicator_active_color" :autoplay="propData.length > 0" :circular="circular" :class="'banner border-radius-main oh bg-white spacing-mb banner-'+(propSize || 'default')" v-if="propData.length > 0">
+            <block v-for="(item, index) in propData" :key="index">
+                <swiper-item>
+                    <image :src="item.images_url" mode="widthFix" :data-value="item.event_value || item.url" :data-type="item.event_type == undefined ? 1 : item.event_type" @tap="banner_event"></image>
+                </swiper-item>
+            </block>
+        </swiper>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    export default {
+        data() {
+            return {
+                indicator_dots: false,
+                indicator_color: 'rgba(0, 0, 0, .2)',
+                indicator_active_color: '#666',
+                autoplay: true,
+                circular: true
+            };
+        },
+
+        components: {},
+        props: {
+            propData: {
+            	type: Array,
+            	default: []
+            },
+            propSize: {
+            	type: String,
+            	default: 'default'
+            }
+        },
+        methods: {
+            banner_event(e) {
+                app.globalData.operation_event(e);
+            }
+
+        }
+    };
+</script>
+<style>
+	.banner {
+		transform: translateY(0);
+	}
+    .banner image {
+        min-width: 100%;
+    }
+    .banner-mini,
+    .banner-mini image {
+        height: 200rpx !important;
+    }
+    .banner-default,
+    .banner-default image {
+        height: 320rpx !important;
+    }
+    .banner-max,
+    .banner-max image {
+        height: 420rpx !important;
+    }
+</style>

+ 25 - 0
components/status-bar-height/status-bar-height.vue

@@ -0,0 +1,25 @@
+<template>
+    <view>
+        <view :style="{ height: statusBarHeight }" class="status-bar-height"></view>
+    </view>
+</template>
+<script>
+    export default {
+        data() {
+            return {
+                statusBarHeight: 20
+            };
+        },
+        components: {},
+        props: {},
+        mounted() {
+        	this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
+        },
+        methods: {}
+    };
+</script>
+<style>
+    .status-bar-height {
+    	height: 20px;
+    }
+</style>

+ 199 - 0
components/switch/switch.vue

@@ -0,0 +1,199 @@
+<template>
+  <view :class="'switch-container switch-container-size-'+propSize" :style="'background:'+propBgColor+';border:1px solid '+propBrColor+';'">
+    <view class="switch_view">
+      <view 
+        :class="'switch-item '+propCheckedClass+' '+(isSwitch ? 'checked_switch' : '')" 
+        :style="isSwitch?`color:${propCheckedColor}`:''"
+        @click.prevent.stop="changeSwitch(true)"
+        :animation="animationData2"
+      >
+        {{propSwitchList[0]}}
+      </view>
+      <view 
+        class="switch-item"
+        :class="{'checked_switch':!isSwitch}"
+        :style="!isSwitch?`color:${propCheckedColor}`:''"
+        @click.prevent.stop="changeSwitch(false)"
+        :animation="animationData3"
+      >
+        {{propSwitchList[1]}}
+      </view>
+    </view>
+    <view class="disabled" v-if="propDisabled"></view>
+    <view 
+      :class="'position_view '+propCheckedBgClass" :animation="animationData1"
+      :style="[{ background: propCheckedBgColor}]"
+    ></view>
+  </view>
+</template>
+<script>
+export default {
+  props: {
+    propSwitchList: {
+      type: Array,
+      default: ['开','关']
+    },
+    propSize:{
+      type:String,
+      default:'sm'
+    },
+    propDefault:{
+      type:Boolean,
+      default:true
+    },
+    propIsShowModal:{
+      type:Boolean,
+      default:false
+    },
+    propDisabled:{
+      type:Boolean,
+      default:false
+    },
+    propBgColor:{
+      type:String,
+      default:'#fff'
+    },
+    propBrColor:{
+      type:String,
+      default:'#ccc'
+    },
+    propCheckedBgColor:{
+      type:String,
+      default:'#4caf50'
+    },
+    propCheckedBgClass:{
+      type:String,
+      default:''
+    },
+    propCheckedColor:{
+      type:String,
+      default:'#fff'
+    },
+    propCheckedClass:{
+      type:String,
+      default:''
+    },
+    propId:{
+      type:null,
+      default:null
+    }
+  },
+  data () {
+    return {
+      isSwitch:true,
+      initAnimation:{},
+      animationData1: {},
+      animationData2: {},
+      animationData3: {}
+    };
+  },
+  created () {
+    this.initAnimation = uni.createAnimation({
+      duration: 500,
+      timingFunction: 'ease'
+    });
+    this.isSwitch = this.propDefault;
+    this.changeAnimation();
+  },
+  methods: {
+    changeSwitch(isSwitch) {
+      if(isSwitch == this.isSwitch || this.propDisabled){
+        return;
+      }
+      if(this.propIsShowModal){
+        let index = isSwitch?0:1;
+        let text =  this.propSwitchList[index];
+        uni.showModal({
+          title: '提示',
+          content: `您确定要将其调整为${text}吗?`,
+          success: (res) => {
+            if(res.confirm){
+              this.isSwitch = isSwitch;
+              this.changeAnimation();
+              this.callParentEvent(isSwitch);
+            }
+          }
+        });
+      }else{
+        this.isSwitch = isSwitch;
+        this.changeAnimation();
+        this.callParentEvent(isSwitch);
+      }
+    },
+    changeAnimation(){
+      if(this.isSwitch){
+        this.animationData1 = this.initAnimation.left(0).width('60%').step().export();
+        this.animationData2 = this.initAnimation.width('60%').step().export();
+        this.animationData3 = this.initAnimation.width('40%').step().export();
+      }else{
+        this.animationData1 = this.initAnimation.left('40%').width('60%').step().export();
+        this.animationData2 = this.initAnimation.width('40%').step().export();
+        this.animationData3 = this.initAnimation.width('60%').step().export();
+      }
+    },
+    callParentEvent(){
+      this.$emit('change',this.isSwitch, this.propId,()=>{
+        // 回调方法应用场景:父级组件请求api接口失败调用
+        this.isSwitch = !this.isSwitch;
+        this.changeAnimation();
+      });
+    }
+  }
+};
+</script>
+<style>
+    .switch-container {
+        display: flex;
+        flex-direction: row;
+        width: 180rpx;
+        height: 60rpx;
+        line-height: 60rpx;
+        border-radius: 1000px;
+        position: relative;
+    }
+    .switch-container .switch_view {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        z-index: 1;
+        display: flex;
+        border-radius: 1000px;
+    }
+    .switch-container .switch_view .switch-item {
+        color: #666;
+        font-size: 24rpx;
+        height: 100%;
+        width: 40%;
+        border-radius: 1000px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+    }
+    .switch-container .position_view {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 60%;
+        height: 100%;
+        border-radius: 1000px;
+        background: #1AAD19;
+    }
+    .switch-container .disabled {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        z-index: 99;
+        background: #fff;
+        opacity: 0.6;
+        border-radius: 1000px;
+    }
+    .switch-container-size-xs {
+        width: 150rpx;
+        height: 45rpx;
+        line-height: 45rpx;
+    }
+</style>

+ 553 - 0
components/time-select/time-select.vue

@@ -0,0 +1,553 @@
+<template>
+    <view>
+        <view class="time-select-content" @click="_dataOpen">
+            <slot></slot>
+        </view>
+        <view :class="'time-select-popup-mask '+(propIsShow ? 'time-select-popup-show' : '')" @click="_maskClose">
+            <view class="time-select-popup-content" @click.stop="_stopFunc">
+                <view class="time-select-close-btn" v-if="propCloseBtn" @click="_closeBtnClose">×</view>
+                <view class="time-select-title">
+                    <view v-if="(propTitle || null) != null">{{ propTitle }}</view>
+                    <view v-if="(propSubhead || null) != null">{{ propSubhead }}</view>
+                </view>
+                <view class="time-select-time-box">
+                    <view class="left_box">
+                        <block v-if="item.timeArr.length > 0" v-for="(item, index) in timeList" :key="item.dateStr">
+                            <view @click="_changeDay(index)" :class="{ active: item.checked }">
+                                {{ item.name }}
+                            </view>
+                        </block>
+                    </view>
+                    <view class="right_box">
+                        <view v-if="day_active_index == 0 && (propPlaceholder || null) != null" @click="_changeTime('')" :class="(time_active_index === '' ? 'active' : '')">{{propPlaceholder}}</view>
+                        <block v-for="(item, index) in activeTimeArr" :key="item.time">
+                            <view @click="_changeTime(index)" :class="{ active: item.checked }">
+                                {{ item.time }}{{ propRangeType ? '-' + item.endtime : '' }}
+                            </view>
+                        </block>
+                    </view>
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+export default {
+    props: {
+        propTitle: {
+            type: String,
+            default: '请选择时间'
+        },
+        propPlaceholder: {
+            type: String,
+            default: ''
+        },
+        propSubhead: {
+            type: String,
+            default: ''
+        },
+        propRangeType: {
+            type: Boolean,
+            default: false
+        },
+        propIsShow: {
+            type: Boolean,
+            default: false
+        },
+        propMaskHide: {
+            type: Boolean,
+            default: true
+        },
+        propCloseBtn: {
+            type: Boolean,
+            default: true
+        },
+        propRangeDay: {
+            type: [Number, String],
+            default: 2
+        },
+        propRangeStartTime: {
+            type: String,
+            default: '00:00:00'
+        },
+        propRangeEndTime: {
+            type: String,
+            default: '00:00:00'
+        },
+        propDefaultTime: {
+            type: String,
+            default: ''
+        },
+        propIsRoundingTime: {
+            type: Boolean,
+            default: true
+        },
+        propIntervalTime: {
+            //间隔时间
+            type: [Number, String],
+            default: 30
+        },
+        propIsNow:{
+            type: Boolean,
+            default: false
+        },
+        propDayStartIntTime: {
+            //每天开始间隔时间
+            type: [Number, String],
+            default: 0
+        },
+        propDisabled: {
+            type: [String, Array],
+            default: () => []
+        }
+    },
+    data() {
+        return {
+            timeList: [],
+            selectDateStr: '',
+            select_dateStr: '',
+            selectTime: '',
+            selectEndime: '',
+            activeTimeArr: [],
+            day_active_index: 0,
+            time_active_index: ''
+        };
+    },
+    beforeMount() {
+        this._initDay();
+    },
+    watch: {
+        propIsShow: function(val, oldVal) {
+            val && this.timeList.length <= 0 && this._initDay();
+        }
+    },
+    methods: {
+        _stopFunc() {},
+
+        _dataOpen() {
+            this._selectEvent('open');
+        },
+        _closeBtnClose() {
+            if(this.propCloseBtn) {
+                this._selectEvent('close');
+            }
+        },
+        _maskClose() {
+            if(this.propMaskHide) {
+                this._selectEvent('close');
+            }
+        },
+        _selectEvent(data = '') {
+            this.$emit('selectEvent', data);
+        },
+        _changeDay(e) {
+            let _ind = e - 0;
+            let { timeList } = this;
+            timeList.forEach(ele => {
+                ele.checked = false;
+            });
+            timeList[_ind].checked = true;
+            this.timeList = timeList;
+            this.selectDateStr = timeList[_ind].dateStr;
+            this.select_dateStr = timeList[_ind]._dateStr;
+            this.activeTimeArr = timeList[_ind].timeArr;
+            this.day_active_index = e;
+        },
+        _changeTime(e) {
+            let { activeTimeArr } = this;
+            let timeArr = JSON.parse(JSON.stringify(activeTimeArr));
+            timeArr.forEach(ele => {
+                ele.checked = false;
+            });
+            let _data = '';
+            if(e !== '') {
+                let _ind = e - 0;
+                timeArr[_ind].checked = true;
+                this.selectTime = timeArr[_ind].time;
+                this.selectEndime = timeArr[_ind].endtime;
+                _data = this._handleData();
+            }
+            this.time_active_index = e;
+            this.activeTimeArr = timeArr;
+            this._selectEvent(_data);
+        },
+        _handleData() {
+            let _data = {};
+            let { selectDateStr, select_dateStr, selectTime, selectEndime } = this;
+            _data.date = selectDateStr + ' ' + selectTime;
+            _data._date = select_dateStr + ' ' + selectTime;
+            _data.dateRange = selectDateStr + ' ' + selectTime + '-' + selectEndime;
+            _data._dateRange = select_dateStr + ' ' + selectTime + '-' + selectEndime;
+            _data.timeStamp = new Date(selectDateStr + ' ' + selectTime).getTime();
+            return _data;
+        },
+        _initDay() {
+            let _timeList = [];
+            for (let index = 0; index < this.propRangeDay; index++) {
+                let _item = {
+                    ...this._getDate(index)
+                };
+                _item.timeArr = this._initTime(index);
+                _timeList.push(_item);
+            }
+
+            if (this.propDefaultTime) {
+                //存在默认时间
+                let _day = this.propDefaultTime.split(' ')[0].replace(/-/g, '/');
+                let _time = this.propDefaultTime.split(' ')[1];
+                let _flag = true;
+                for (let index = 0; index < _timeList.length; index++) {
+                    const element = _timeList[index];
+                    element.checked = false;
+                    if (element.timeArr.length > 0 && element.dateStr === _day) {
+                        element.checked = true;
+                        _flag = false;
+                        element.timeArr.forEach(item => {
+                            if (this._timeRange(item.time + ':00', item.endtime + ':00', _time)) {
+                                item.checked = true;
+                                this.time = item.time;
+                                this.endtime = item.endtime;
+                            }
+                        });
+
+                        this.selectDateStr = element.dateStr;
+                        this.select_dateStr = element._dateStr;
+                        this.activeTimeArr = element.timeArr;
+                    }
+                }
+                if (_flag) {
+                    this._setDefaultTime(_timeList);
+                }
+            } else {
+                this._setDefaultTime(_timeList);
+            }
+
+            this.timeList = _timeList;
+            this.time_active_index = this.propDefaultTime || '';
+        },
+        _setDefaultTime(list) {
+            for (let index = 0; index < list.length; index++) {
+                const element = list[index];
+                if (element.timeArr.length > 0) {
+                    element.checked = true;
+                    //是否默认选择时间
+                    // element.timeArr[0].checked = true;
+                    this.selectDateStr = element.dateStr;
+                    this.select_dateStr = element._dateStr;
+                    this.activeTimeArr = element.timeArr;
+                    break;
+                }
+            }
+        },
+        _initTime(num) {
+            let _item = [];
+            let TempDisabled = this.propDisabled;
+            let tempIntervalTime = this.propIntervalTime;
+            if(tempIntervalTime<=0){
+                tempIntervalTime = 1
+            }
+            let TempRangeStartTime = this._timeHandle(this.propRangeStartTime);
+            let TempRangeEndTime = this._timeHandle(this.propRangeEndTime);
+            if(TempRangeEndTime == '00:00:00') {
+                TempRangeEndTime = '23:59:59';
+            }
+            if (typeof TempDisabled === 'string') {
+                TempDisabled = TempDisabled ? TempDisabled.split(',') : [];
+            } else if (Array.isArray(TempDisabled)) {
+                TempDisabled = TempDisabled.map(ele => {
+                    return ele + '';
+                });
+            }
+            if (num === 0 && !TempDisabled.includes('0')) {
+                //今天
+                let _nowTime = this._roundingTime();
+                if (this._timeRange(TempRangeStartTime, TempRangeEndTime, _nowTime)) {
+                    //当前时间在营业时间内
+                    return this._forTime(_nowTime, TempRangeEndTime, tempIntervalTime, _nowTime);
+                } else if (this._toTimeStr(_nowTime) < this._toTimeStr(TempRangeStartTime)) {
+                    //早于今天开始时间
+                    return this._forTime(TempRangeStartTime, TempRangeEndTime, tempIntervalTime, _nowTime);
+                } else {
+                    return [];
+                }
+            } else {
+                //其他日期
+                if (TempDisabled.includes(num + '')) {
+                    //禁止当前日期了
+                    return [];
+                }
+
+                return this._forTime(TempRangeStartTime, TempRangeEndTime, tempIntervalTime);
+            }
+        },
+        _getDate(num) {
+            let date = new Date();
+            let date1 = new Date(date);
+            let weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
+            date1.setDate(date.getDate() + num);
+            let name = '',
+                dateStr = '';
+            name = date1.getMonth() - 0 + 1 + '月' + date1.getDate() + '日(' + weekday[date1.getDay()] + ')';
+            dateStr = date1.getFullYear() + '/' + (date1.getMonth() - 0 + 1) + '/' + date1.getDate();
+            if (num == 0) {
+                name = '今天(' + weekday[date1.getDay()] + ')';
+            } else if (num == 1) {
+                name = '明天(' + weekday[date1.getDay()] + ')';
+            }
+            return {
+                name: name,
+                dateStr: dateStr,
+                _dateStr: dateStr.replace(/\//g, '-')
+            };
+        },
+        _addZero(num) {
+            num = num + '';
+            if (num.length === 1) {
+                return '0' + num;
+            }
+            return num;
+        },
+        _roundingTime() {
+            let _now = new Date();
+            let _h = _now.getHours() - 0;
+            let _m = _now.getMinutes() - 0;
+            if (_m > 30) {
+                _m = '00';
+                _h += 1;
+            }else if (_m - 0 > 0&&_m - 0<30) {
+                _m = 30;
+            }
+            if (this.propIsRoundingTime&&!this.propIsNow) {
+                return _h + ':' + _m + ':00';
+            }
+            return new Date().getHours() + ':' + new Date().getMinutes() + ':00';
+        },
+        _forTime(st, et, it, dt = 0) {
+            let TempDayStartIntTime = this.propDayStartIntTime * 1000 * 60;
+            let _st = this._toTimeStr(st);
+            let _et = this._toTimeStr(et);
+            let _it = it * 1000 * 60;
+            let _list = [];
+            if (_st < _et) {
+                for (let i = _st + TempDayStartIntTime; i < _et; i += _it) {
+                    _list.push({
+                        time: this._toLocalTime(i),
+                        endtime: this._toLocalTime(i + _it > _et ? _et : i + _it),
+                        checked: false
+                    });
+                }
+            } else {
+                //跨天了
+                for (let i = dt; i < _et; i += _it) {
+                    _list.push({
+                        time: this._toLocalTime(i),
+                        endtime: this._toLocalTime(i + _it > _et ? _et : i + _it),
+                        checked: false
+                    });
+                }
+                for (let i = _st  + TempDayStartIntTime; i < this._toTimeStr('23:59:59'); i += _it) {
+                    _list.push({
+                        time: this._toLocalTime(i),
+                        endtime: this._toLocalTime(i + _it),
+                        checked: false
+                    });
+                }
+            }
+            return _list;
+        },
+        _toTimeStr(time = '') {
+            let newTime = time;
+            let itemStr = 0;
+            let timeArr = newTime.split(':');
+            let h = timeArr[0] * 1000 * 60 * 60;
+            let m = timeArr[1] * 1000 * 60;
+            let s = timeArr[2] * 1000;
+            itemStr = h + m + s;
+            return itemStr;
+        },
+        _toLocalTime(v, type = 0) {
+            let h = parseInt((v / 1000 / 60 / 60) % 24);
+            let m = parseInt((v / 1000 / 60) % 60);
+            let s = parseInt((v / 1000) % 60);
+            v = type === 0 ? `${this._addZero(h)}:${this._addZero(m)}` : `${this._addZero(h)}:${this._addZero(m)}:${this._addZero(s)}`;
+            return v;
+        },
+        _timeRange(beginTime, endTime, nowTime) {
+            let strb = beginTime.split(':');
+            let stre = endTime.split(':');
+            let strn = nowTime.split(':');
+
+            let b = new Date();
+            let e = new Date();
+            let n = new Date();
+
+            b.setHours(strb[0]);
+            b.setMinutes(strb[1]);
+            e.setHours(stre[0]);
+            e.setMinutes(stre[1]);
+            n.setHours(strn[0]);
+            n.setMinutes(strn[1]);
+
+            let _b = b.getTime();
+            let _e = e.getTime();
+            let _n = n.getTime();
+
+            if (_b > _e) {
+                if (_n - _e >= 0 && _n - _b < 0) {
+                    return false;
+                } else {
+                    return true;
+                }
+            } else {
+                if (_n - _b >= 0 && _n - _e < 0) {
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        },
+        _timeHandle(value) {
+            let arr = ((value || null) == null) ? [] : value.split(':');
+            let len = arr.length;
+            if(len < 3) {
+                while(len<3) {
+                    arr.push('00');
+                    len++;
+                }
+            }
+            return arr.join(':');
+        }
+    }
+};
+</script>
+<style>
+.time-select-popup-mask {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    top: 0;
+    background-color: rgba(0, 0, 0, 0.5);
+    opacity: 0;
+    z-index: 100;
+    pointer-events: none;
+}
+.time-select-popup-mask view {
+    box-sizing: border-box;
+}
+.time-select-popup-content {
+    height: 0rpx;
+    background-color: #fff;
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    padding: 40rpx 10rpx 0 10rpx;
+    transition: height 0.5s;
+    border-top-right-radius: 20rpx;
+    border-top-left-radius: 20rpx;
+    height: auto;
+    z-index: 101;
+    transform: translateY(100%);
+}
+.time-select-popup-show {
+    opacity: 1;
+    pointer-events: auto;
+}
+.time-select-popup-show .time-select-popup-content {
+    transform: none;
+}
+.time-select-popup-mask,
+.time-select-popup-content {
+    transition: all 0.25s linear;
+}
+.time-select-title {
+    text-align: center;
+    font-size: 32rpx;
+    color: #222222;
+    font-weight: 600;
+    position: relative;
+}
+.time-select-close-btn {
+    position: absolute;
+    width: 80rpx;
+    line-height: 80rpx;
+    text-align: center;
+    right: 0rpx;
+    padding-right: 15rpx;
+    top: 0;
+    color: #999999;
+    z-index: 99;
+    font-size: 44rpx;
+}
+.time-select-title > view:nth-child(2) {
+    font-size: 22rpx;
+    color: #919191;
+    margin-top: 10rpx;
+}
+.time-select-time-box {
+    border-top: 1px solid #fbf8fb;
+    background-color: #fbf8fb;
+    height: 660rpx;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+}
+.time-select-time-box > view {
+    height: 100%;
+    overflow-y: auto;
+    -webkit-overflow-scrolling: touch;
+    font-size: 28rpx;
+}
+.time-select-time-box .left_box {
+    color: #919191;
+    width: 45%;
+}
+.time-select-time-box .left_box view,
+.time-select-time-box .right_box view {
+    text-align: center;
+    line-height: 90rpx;
+    position: relative;
+    color: #666;
+}
+.time-select-time-box .right_box view::before {
+    content: ' ';
+    width: 80%;
+    position: absolute;
+    left: 10%;
+    bottom: 0;
+    border: 1px dashed #f4f4f4;
+}
+.time-select-time-box .right_box view:last-child::before {
+    border: none;
+}
+.time-select-time-box .right_box {
+    width: 55%;
+    flex: 1;
+    background-color: #fff;
+    text-align: center;
+}
+.time-select-time-box .right_box .active {
+    position: relative;
+    color: #000;
+    font-weight: bold;
+}
+.time-select-time-box .left_box .active {
+    background-color: #fff;
+    color: #000;
+}
+.time-select-time-box .right_box .active::after {
+    content: ' ';
+    position: absolute;
+    top: 50%;
+    margin-top: -16rpx;
+    right: 50rpx;
+    width: 10rpx;
+    height: 20rpx;
+    border-color: #000;
+    border-style: solid;
+    border-width: 0 4rpx 4rpx 0;
+    transform: rotate(45deg);
+}
+</style>

+ 89 - 0
components/trn-nav/trn-nav.vue

@@ -0,0 +1,89 @@
+<template>
+	<view>
+		<view :style="'background:'+(propBackgroundColor || '#fff')+';'+nav_style" :class="'trn-nav-top '+(propEnt || '')">
+            <view v-if="(propTitle || null) != null" class="trn-nav-top-title single-text">{{propTitle}}</view>
+			<slot></slot>
+		</view>
+	</view>
+</template>
+<script>
+    const app = getApp();
+	export default {
+		data() {
+			return {
+				statusbar_height: 0,
+                nav_style: ''
+			}
+		},
+		props: {
+			propTitle: String,
+			propBackgroundColor: String,
+            propEnt: String,
+			propScroll: Number,
+			propHeight: Number,
+		},
+		watch: {
+            // 属性值改变监听
+			propScroll(value, old_value) {
+                // opacity 0 就是完全透明  1是不透明
+                var opacity = 0;
+				if(value >= 70 && value <= 100) {
+					opacity = 0.2;
+				}
+				// 越往下滑动 透明度越低
+				if(value >= 101 && value <= 120) {
+					opacity = 0.3;
+				}
+				if(value >= 120 && value <= 150) {
+					opacity = 0.5;
+				}
+				if(value >= 150 && value <= 170) {
+					opacity = 0.7;
+				}
+				if(value >= 170 && value <= 190) {
+					opacity = 1;
+				}
+				if(value > 190) {
+					opacity = 1;
+				}
+				// 距离小于多少就不显示了
+				if(value <= 70) {
+					opacity = 0;
+				}
+
+                // 设置样式
+                this.nav_style = 'opacity:'+opacity+';';
+                // #ifdef MP
+                this.nav_style += 'height:'+(this.propHeight+this.statusbar_height)+'rpx;';
+                // #endif
+                // #ifdef H5
+                this.nav_style += 'height:44px;';
+                // #endif
+			}
+		},
+		methods: {
+		},
+		mounted() {
+            // 获取系统状态栏高度
+			this.statusbar_height = app.globalData.px_to_rpx(app.globalData.get_system_info('statusBarHeight', 0));
+		}
+	}
+</script>
+<style>
+	.trn-nav-top {
+		padding-top: var(--status-bar-height);
+        opacity: 0;
+		width: 100%;
+		z-index: 10;
+		position: fixed;
+        top: 0;
+        left: 0;
+	}
+    .trn-nav-top .trn-nav-top-title {
+        font-size: 36rpx;
+        text-align: left;
+        padding: 12px 250rpx 0 20rpx;
+        height: 37px;
+        color: #000;
+    }
+</style>

+ 17 - 0
main.js

@@ -0,0 +1,17 @@
+import Vue from 'vue';
+import App from './App';
+
+// 全局mixins
+import base from './common/js/common/base';
+import share from './common/js/common/share';
+Vue.mixin(base);
+Vue.mixin(share);
+
+Vue.config.productionTip = false;
+
+App.mpType = 'app';
+
+const app = new Vue({
+    ...App
+});
+app.$mount();

+ 121 - 0
manifest.json

@@ -0,0 +1,121 @@
+{
+    "name" : "shopxo",
+    "appid" : "__UNI__50E3C11",
+    "description" : "ShopXO开源商城、MIT协议、可商用、可二次开发、满足99%电商运营需求",
+    "versionName" : "1.0.0",
+    "versionCode" : 100,
+    "transformPx" : false,
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        "modules" : {},
+        "distribute" : {
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            "ios" : {},
+            "sdkConfigs" : {}
+        }
+    },
+    "quickapp" : {},
+    "mp-weixin" : {
+        "requiredPrivateInfos" : [ "chooseLocation", "getLocation", "chooseAddress" ],
+        "appid" : "wxda7779770f53e901",
+        "setting" : {
+            "urlCheck" : false,
+            "es6" : true,
+            "minified" : true
+        },
+        "usingComponents" : true,
+        "permission" : {
+            "scope.userLocation" : {
+                "desc" : "你的位置将用于小程序中相应业务位置服务使用"
+            }
+        },
+        "plugins" : {
+            // 直播(需要开通权限 https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/liveplayer/live-player-plugin.html)
+            // "live-player-plugin" : {
+            //     "version" : "1.3.0",
+            //     "provider" : "wx2b03c6e691cd7370"
+            // }
+        }
+    },
+    "mp-alipay" : {
+        "usingComponents" : true,
+        "appid" : "2021001173639600"
+    },
+    "mp-baidu" : {
+        "usingComponents" : true,
+        "appid" : "",
+        "setting" : {
+            "urlCheck" : false
+        }
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true,
+        "appid" : "ttfb628ddf6458b04f",
+        "setting" : {
+            "urlCheck" : false
+        }
+    },
+    "networkTimeout" : {
+        "request" : 10000,
+        "downloadFile" : 10000
+    },
+    "mp-qq" : {
+        "appid" : "1110736292",
+        "setting" : {
+            "urlCheck" : false
+        }
+    },
+    "h5" : {
+        "sdkConfigs" : {
+            "maps" : {
+                "qqmap" : {
+                    "key" : "56SBZ-PCC3G-US2QM-IXYFE-4DE5H-GRBDK"
+                }
+            }
+        },
+        "devServer" : {
+            "https" : false,
+            "port" : 8082
+        },
+        "router" : {
+            "mode" : "history",
+            "base" : "./"
+        },
+        "title" : "ShopXO",
+        "template" : "template.h5.html"
+    },
+    "vueVersion" : "2"
+}

+ 12 - 0
node_modules/.package-lock.json

@@ -0,0 +1,12 @@
+{
+  "name": "shopxo-uniapp",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "node_modules/jweixin-module": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
+      "integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w=="
+    }
+  }
+}

+ 30 - 0
node_modules/jweixin-module/README.md

@@ -0,0 +1,30 @@
+# jweixin-module
+
+微信JS-SDK
+
+## 安装
+
+### NPM
+
+```shell
+npm install jweixin-module --save
+```
+
+### UMD
+
+```http
+https://unpkg.com/jweixin-module/out/index.js
+```
+
+## 使用
+
+```js
+var jweixin = require('jweixin-module')
+jweixin.ready(function(){
+    // TODO
+});
+```
+
+## 完整API
+
+>[微信JS-SDK说明文档](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115)

文件差異過大導致無法顯示
+ 1 - 0
node_modules/jweixin-module/lib/index.js


+ 26 - 0
node_modules/jweixin-module/package.json

@@ -0,0 +1,26 @@
+{
+    "name": "jweixin-module",
+    "version": "1.6.0",
+    "description": "微信JS-SDK",
+    "main": "lib/index.js",
+    "scripts": {},
+    "repository": {
+        "type": "git",
+        "url": "git+https://github.com/zhetengbiji/jweixin-module.git"
+    },
+    "keywords": [
+        "wxjssdk",
+        "weixin",
+        "jweixin",
+        "wechat",
+        "jssdk",
+        "wx"
+    ],
+    "author": "Shengqiang Guo",
+    "license": "ISC",
+    "bugs": {
+        "url": "https://github.com/zhetengbiji/jweixin-module/issues"
+    },
+    "homepage": "https://github.com/zhetengbiji/jweixin-module#readme",
+    "devDependencies": {}
+}

+ 24 - 0
package-lock.json

@@ -0,0 +1,24 @@
+{
+  "name": "shopxo-uniapp",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "jweixin-module": "^1.6.0"
+      }
+    },
+    "node_modules/jweixin-module": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
+      "integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w=="
+    }
+  },
+  "dependencies": {
+    "jweixin-module": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
+      "integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w=="
+    }
+  }
+}

+ 5 - 0
package.json

@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "jweixin-module": "^1.6.0"
+  }
+}

+ 912 - 0
pages.json

@@ -0,0 +1,912 @@
+{
+	"pages": [
+		{
+			"path": "pages/index/index",
+			"style": {
+                // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-KUAISHOU || H5 || APP
+                "navigationStyle": "custom",
+                // #endif
+                // #ifndef MP-ALIPAY
+                "navigationBarTitleText": "ShopXO",
+                // #endif
+                // #ifdef MP-ALIPAY
+                "transparentTitle": "always",
+                "titlePenetrate": "YES",
+                "navigationBarTitleText": "",
+                // #endif
+				"enablePullDownRefresh": true,
+                "navigationBarTextStyle": "white"
+			}
+		},
+		{
+			"path": "pages/goods-category/goods-category",
+			"style": {
+                // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-KUAISHOU || H5 || APP
+                "navigationStyle": "custom",
+                // #endif
+                // #ifndef MP-ALIPAY
+                "navigationBarTitleText": "商品分类",
+                // #endif
+                // #ifdef MP-ALIPAY
+                "transparentTitle": "always",
+                "titlePenetrate": "YES",
+                "navigationBarTitleText": "",
+                // #endif
+				"enablePullDownRefresh": true
+			}
+		},
+		{
+			"path": "pages/cart/cart",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "购物车"
+			}
+		},
+		{
+			"path": "pages/user/user",
+			"style": {
+                // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-KUAISHOU || H5 || APP
+                "navigationStyle": "custom",
+                // #endif
+                // #ifndef MP-ALIPAY
+                "navigationBarTitleText": "用户中心",
+                // #endif
+                // #ifdef MP-ALIPAY
+                "transparentTitle": "always",
+                "titlePenetrate": "YES",
+                "navigationBarTitleText": "",
+                // #endif
+				"enablePullDownRefresh": true
+			}
+		},
+        {
+        	"path": "pages/cart-page/cart-page",
+        	"style": {
+        		"enablePullDownRefresh": true,
+                "navigationBarTitleText": "购物车"
+        	}
+        },
+		{
+			"path": "pages/buy/buy",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "订单确认"
+			}
+		},
+		{
+			"path": "pages/web-view/web-view",
+			"style": {
+				"navigationBarTitleText": "",
+				"enablePullDownRefresh": false
+			}
+		},
+		{
+			"path": "pages/login/login",
+			"style": {
+				"enablePullDownRefresh": false,
+                "navigationBarTitleText": "登录"
+			}
+		},
+		{
+			"path": "pages/paytips/paytips",
+			"style": {
+				"enablePullDownRefresh": false,
+                "navigationBarTitleText": "安全支付"
+			}
+		},
+		{
+			"path": "pages/goods-search/goods-search",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "商品搜索"
+			}
+		},
+		{
+			"path": "pages/goods-detail/goods-detail",
+			"style": {
+                // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-KUAISHOU
+                "navigationStyle": "custom",
+                // #endif
+                "enablePullDownRefresh": true,
+                "navigationBarTitleText": "商品详情"
+            }
+		},
+		{
+			"path": "pages/goods-comment/goods-comment",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "商品评价"
+			}
+		},
+		{
+			"path": "pages/user-address/user-address",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "我的地址"
+			}
+		},
+		{
+			"path": "pages/user-address-save/user-address-save",
+			"style": {
+				"enablePullDownRefresh": false,
+                "navigationBarTitleText": "地址编辑"
+			}
+		},
+		{
+			"path": "pages/user-order/user-order",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "我的订单"
+			}
+		},
+		{
+			"path": "pages/user-order-detail/user-order-detail",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "订单详情"
+			}
+		},
+		{
+			"path": "pages/user-order-comments/user-order-comments",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "订单评价"
+			}
+		},
+		{
+			"path": "pages/user-favor/user-favor",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "商品收藏"
+			}
+		},
+		{
+			"path": "pages/user-answer-list/user-answer-list",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "我的留言"
+			}
+		},
+		{
+			"path": "pages/answer-list/answer-list",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "问答广场"
+			}
+		},
+		{
+			"path": "pages/answer-form/answer-form",
+			"style": {
+				"enablePullDownRefresh": false,
+                "navigationBarTitleText": "留言"
+			}
+		},
+		{
+			"path": "pages/message/message",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "消息"
+			}
+		},
+		{
+			"path": "pages/user-integral/user-integral",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "积分明细"
+			}
+		},
+		{
+			"path": "pages/user-goods-browse/user-goods-browse",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "我的足迹"
+			}
+		},
+		{
+			"path": "pages/user-orderaftersale/user-orderaftersale",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "退款/售后"
+			}
+		},
+		{
+			"path": "pages/user-orderaftersale-detail/user-orderaftersale-detail",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "订单售后"
+                
+			}
+		},
+		{
+			"path": "pages/extraction-address/extraction-address",
+			"style": {
+				"enablePullDownRefresh": true,
+                "navigationBarTitleText": "自提地址"
+			}
+		},
+		{
+			"path": "pages/common/open-setting-location/open-setting-location",
+			"style": {
+                // #ifndef MP-TOUTIAO
+                "navigationStyle": "custom",
+                // #endif
+				"enablePullDownRefresh": false
+			}
+		},
+		{
+			"path": "pages/design/design",
+			"style": {
+				"enablePullDownRefresh": true,
+				"navigationBarTitleText": "页面设计"
+			}
+		},
+        {
+        	"path": "pages/error/error",
+        	"style": {
+        		"enablePullDownRefresh": true,
+        		"navigationBarTitleText": "温馨提示"
+        	}
+        },
+        {
+            "path": "pages/article-category/article-category",
+            "style": {
+            	"enablePullDownRefresh": true,
+            	"navigationBarTitleText": "所有文章"
+            }
+        },
+        {
+            "path": "pages/article-detail/article-detail",
+            "style": {
+            	"enablePullDownRefresh": true,
+            	"navigationBarTitleText": "文章详情"
+            }
+        },
+        {
+            "path": "pages/setup/setup",
+            "style": {
+            	"enablePullDownRefresh": false,
+            	"navigationBarTitleText": "设置"
+            }
+        },
+        {
+            "path": "pages/personal/personal",
+            "style": {
+            	"enablePullDownRefresh": false,
+            	"navigationBarTitleText": "个人资料"
+            }
+        },
+        {
+            "path": "pages/logout/logout",
+            "style": {
+            	"enablePullDownRefresh": false,
+            	"navigationBarTitleText": "账号注销"
+            }
+        }
+	],
+    "subPackages": [{
+        "root": "pages/plugins",
+        "pages": [
+            {
+            	"path": "seckill/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "限时秒杀"
+            	}
+            },
+            {
+            	"path": "coupon/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "领券中心"
+            	}
+            },
+            {
+            	"path": "coupon/shop/shop",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "店铺领券中心"
+            	}
+            },
+            {
+            	"path": "coupon/user/user",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "我的卡券"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "会员VIP"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/buy/buy",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "开通会员"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/user/user",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "我的会员"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/order/order",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "开通订单"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/order-detail/order-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "订单详情"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/profit/profit",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "收益明细"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/profit-detail/profit-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "收益详情"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/statistics/statistics",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "数据统计"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/poster/poster",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "推广返利"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/team/team",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "我的团队"
+            	}
+            },
+            {
+            	"path": "membershiplevelvip/member-code/member-code",
+            	"style": {
+            		"enablePullDownRefresh": false,
+            		"navigationBarTitleText": "会员码"
+            	}
+            },
+            {
+            	"path": "distribution/user/user",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "我的分销"
+            	}
+            },
+            {
+            	"path": "distribution/order/order",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "分销订单"
+            	}
+            },
+            {
+            	"path": "distribution/order-detail/order-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "订单详情"
+            	}
+            },
+            {
+            	"path": "distribution/profit/profit",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "收益明细"
+            	}
+            },
+            {
+            	"path": "distribution/profit-detail/profit-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "收益详情"
+            	}
+            },
+            {
+            	"path": "distribution/statistics/statistics",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "数据统计"
+            	}
+            },
+            {
+            	"path": "distribution/poster/poster",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "推广返利"
+            	}
+            },
+            {
+            	"path": "distribution/team/team",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "我的团队"
+            	}
+            },
+            {
+            	"path": "distribution/extraction/extraction",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "取货点"
+            	}
+            },
+            {
+            	"path": "distribution/extraction-apply/extraction-apply",
+            	"style": {
+            		"enablePullDownRefresh": false,
+            		"navigationBarTitleText": "取货点信息"
+            	}
+            },
+            {
+            	"path": "distribution/extraction-order/extraction-order",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "取货订单"
+            	}
+            },
+            {
+            	"path": "distribution/extraction-switch/extraction-switch",
+            	"style": {
+            		"enablePullDownRefresh": true,
+                    "navigationBarTitleText": "取货点切换"
+            	}
+            },
+            {
+            	"path": "distribution/introduce/introduce",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "等级介绍"
+            	}
+            },
+            {
+            	"path": "wallet/user/user",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "我的钱包"
+            	}
+            },
+            {
+            	"path": "wallet/recharge/recharge",
+            	"style": {
+            		"enablePullDownRefresh": false,
+            		"navigationBarTitleText": "充值"
+            	}
+            },
+            {
+            	"path": "wallet/cash-auth/cash-auth",
+            	"style": {
+            		"enablePullDownRefresh": false,
+            		"navigationBarTitleText": "余额提现"
+            	}
+            },
+            {
+            	"path": "wallet/cash-create/cash-create",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "余额提现"
+            	}
+            },
+            {
+            	"path": "wallet/wallet-log/wallet-log",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "账户明细"
+            	}
+            },
+            {
+            	"path": "wallet/wallet-log-detail/wallet-log-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "明细详情"
+            	}
+            },
+            {
+            	"path": "wallet/user-recharge/user-recharge",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "充值记录"
+            	}
+            },
+            {
+            	"path": "wallet/user-recharge-detail/user-recharge-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "充值详情"
+            	}
+            },
+            {
+            	"path": "wallet/user-cash/user-cash",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "提现记录"
+            	}
+            },
+            {
+            	"path": "wallet/user-cash-detail/user-cash-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "提现详情"
+            	}
+            },
+            {
+            	"path": "wallet/payment-code/payment-code",
+            	"style": {
+            		"enablePullDownRefresh": false,
+            		"navigationBarTitleText": "钱包付款码"
+            	}
+            },
+            {
+            	"path": "excellentbuyreturntocash/profit/profit",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "优购返现明细"
+            	}
+            },
+            {
+            	"path": "excellentbuyreturntocash/profit-detail/profit-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "优购返现详情"
+            	}
+            },
+            {
+            	"path": "weixinliveplayer/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "直播"
+            	}
+            },
+            {
+            	"path": "weixinliveplayer/search/search",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "直播列表"
+            	}
+            },
+            {
+            	"path": "weixinliveplayer/detail/detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "直播详情"
+            	}
+            },
+            {
+            	"path": "exchangerate/currency/currency",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "货币切换"
+            	}
+            },
+            {
+            	"path": "invoice/user/user",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "我的发票"
+            	}
+            },
+            {
+            	"path": "invoice/invoice/invoice",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "开票列表"
+            	}
+            },
+            {
+            	"path": "invoice/invoice-detail/invoice-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "发票详情"
+            	}
+            },
+            {
+            	"path": "invoice/invoice-saveinfo/invoice-saveinfo",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "开票编辑"
+            	}
+            },
+            {
+            	"path": "invoice/order/order",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "订单开票"
+            	}
+            },
+            {
+            	"path": "signin/user/user",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "签到"
+            	}
+            },
+            {
+            	"path": "signin/index-detail/index-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "签到"
+            	}
+            },
+            {
+            	"path": "signin/user-signin/user-signin",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "我的签到"
+            	}
+            },
+            {
+            	"path": "signin/user-qrcode/user-qrcode",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "签到码管理"
+            	}
+            },
+            {
+            	"path": "signin/user-qrcode-detail/user-qrcode-detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "签到码详情"
+            	}
+            },
+            {
+            	"path": "signin/user-qrcode-saveinfo/user-qrcode-saveinfo",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "签到码编辑"
+            	}
+            },
+            {
+            	"path": "signin/user-coming-list/user-coming-list",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "用户签到"
+            	}
+            },
+            {
+            	"path": "points/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "积分商城"
+            	}
+            },
+            {
+            	"path": "brand/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "品牌"
+            	}
+            },
+            {
+            	"path": "shop/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "所有店铺"
+            	}
+            },
+            {
+            	"path": "shop/detail/detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+                    "navigationBarTitleText": "店铺首页"
+            	}
+            },
+            {
+            	"path": "shop/search/search",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "店铺商品搜索"
+            	}
+            },
+            {
+            	"path": "shop/design/design",
+            	"style": {
+            		"enablePullDownRefresh": true
+            	}
+            },
+            {
+            	"path": "shop/favor/favor",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "店铺收藏"
+            	}
+            },
+            {
+            	"path": "activity/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "所有活动"
+            	}
+            },
+            {
+            	"path": "activity/detail/detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "活动详情"
+            	}
+            },
+            {
+            	"path": "label/detail/detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "标签详情"
+            	}
+            },
+            {
+            	"path": "blog/index/index",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "博客"
+            	}
+            },
+            {
+            	"path": "blog/search/search",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "博文搜索"
+            	}
+            },
+            {
+            	"path": "blog/detail/detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "博文详情"
+            	}
+            },
+            {
+            	"path": "blog/comments/comments",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "评论列表"
+            	}
+            },
+            {
+            	"path": "express/detail/detail",
+            	"style": {
+            		"enablePullDownRefresh": true,
+            		"navigationBarTitleText": "物流详情"
+            	}
+            },
+            {
+                "path": "realstore/index/index",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "门店"
+                }
+            },
+            {
+                "path": "realstore/search/search",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "门店搜索"
+                }
+            },
+            {
+            	"path": "realstore/detail/detail",
+            	"style": {
+                    // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-KUAISHOU
+                    "navigationStyle": "custom",
+                    // #endif
+                    "enablePullDownRefresh": true,
+                    "navigationBarTitleText": "门店详情"
+                }
+            },
+            {
+                "path": "realstore/favor/favor",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "门店收藏"
+                }
+            },
+            {
+                "path": "realstore/orderallot-list/orderallot-list",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "子订单列表"
+                }
+            },
+            {
+                "path": "realstore/orderallot-detail/orderallot-detail",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "子订单详情"
+                }
+            },
+            {
+                "path": "realstore/batchorder-list/batchorder-list",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "批次订单"
+                }
+            },
+            {
+                "path": "realstore/frequencycard-list/frequencycard-list",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "次卡"
+                }
+            },
+            {
+                "path": "realstore/frequencycard-used/frequencycard-used",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "次卡使用记录"
+                }
+            },
+            {
+                "path": "binding/index/index",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "组合搭配"
+                }
+            },
+            {
+                "path": "binding/detail/detail",
+                "style": {
+                	"enablePullDownRefresh": true,
+                	"navigationBarTitleText": "组合搭配详情"
+                }
+            }
+        ]
+    }],
+	"globalStyle": {
+		"navigationBarTitleText": "ShopXO",
+        "navigationBarTextStyle": "black",
+		"navigationBarBackgroundColor": "#fff",
+		"backgroundColor": "#f5f5f5",
+		"backgroundColorBottom": "#f5f5f5"
+	},
+    "tabBar": {
+    	"color": "#8a8a8a",
+    	"selectedColor": "#f6c133",
+    	"backgroundColor": "#fff",
+    	"list": [
+    		{
+    			"pagePath": "pages/index/index",
+    			"iconPath": "static/images/common/tabbar/home.png",
+    			"selectedIconPath": "static/images/yellow/tabbar/home.png",
+    			"text": "首页"
+    		},
+    		{
+    			"pagePath": "pages/goods-category/goods-category",
+    			"iconPath": "static/images/common/tabbar/category.png",
+    			"selectedIconPath": "static/images/yellow/tabbar/category.png",
+    			"text": "分类"
+    		},
+    		{
+    			"pagePath": "pages/cart/cart",
+    			"iconPath": "static/images/common/tabbar/cart.png",
+    			"selectedIconPath": "static/images/yellow/tabbar/cart.png",
+    			"text": "购物车"
+    		},
+    		{
+    			"pagePath": "pages/user/user",
+    			"iconPath": "static/images/common/tabbar/user.png",
+    			"selectedIconPath": "static/images/yellow/tabbar/user.png",
+    			"text": "我的"
+    		}
+    	]
+    }
+}

+ 143 - 0
pages/answer-form/answer-form.vue

@@ -0,0 +1,143 @@
+<template>
+    <view>
+        <form v-if="data_list_loding_status == 0" @submit="formSubmit" class="form-container">
+            <view class="padding-main oh">
+                <view class="form-gorup">
+                    <view class="form-gorup-title">联系人<text class="form-group-tips-must">*</text></view>
+                    <input type="text" class="cr-base" name="name" maxlength="30" placeholder="联系人格式 1~30 个字符之间" placeholder-class="cr-grey">
+                </view>
+
+                <view class="form-gorup">
+                    <view class="form-gorup-title">联系电话<text class="form-group-tips-must">*</text></view>
+                    <input type="text" class="cr-base" name="tel" maxlength="30" placeholder-class="cr-grey" placeholder="座机 或 手机">
+                </view>
+
+                <view class="form-gorup">
+                    <view class="form-gorup-title">描述<text class="form-group-tips-must">*</text></view>
+                    <textarea class="cr-base" name="content" maxlength="160" :auto-height="true" placeholder-class="cr-grey" placeholder="请详细描述问题,我们将尽快为您解答!"></textarea>
+                </view>
+
+                <view class="form-gorup form-gorup-submit">
+                    <button class="bg-main br-main cr-white round text-size" type="default" form-type="submit" hover-class="none" :loading="form_submit_loading" :disabled="form_submit_loading">提交</button>
+                </view>
+            </view>
+        </form>
+        <view v-else>
+            <!-- 提示信息 -->
+            <component-no-data :propStatus="data_list_loding_status"></component-no-data>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+
+    export default {
+        data() {
+            return {
+                data_list_loding_status: 1,
+                data_list_loding_msg: '处理错误',
+                form_submit_loading: false
+            };
+        },
+
+        components: {
+            componentNoData
+        },
+        props: {},
+
+        onLoad() {},
+
+        onShow() {
+            this.init();
+            
+            // 分享菜单处理
+            app.globalData.page_share_handle();
+        },
+
+        methods: {
+            // 初始化
+            init() {
+                var user = app.globalData.get_user_info(this, "init");
+
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.redirectTo({
+                            url: "/pages/login/login?event_callback=init"
+                        });
+                        return false;
+                    }
+                    
+                    // 开启表单
+                    this.setData({
+                        data_list_loding_status: 0
+                    });
+                } else {
+                    // 提示错误
+                    this.setData({
+                        data_list_loding_status: 2,
+                        data_list_loding_msg: '用户未登录'
+                    });
+                }
+            },
+
+            /**
+             * 表单提交
+             */
+            formSubmit(e) {
+                // 数据验证
+                var validation = [
+                    {fields: 'name', msg: '请填写联系人'},
+                    {fields: 'tel', msg: '请填写联系电话'},
+                    {fields: 'content', msg: '请填写内容'}
+                ];
+                if (app.globalData.fields_check(e.detail.value, validation)) {
+                    uni.showLoading({
+                        title: '提交中...'
+                    });
+                    this.setData({
+                        form_submit_loading: true
+                    });
+                    
+                    // 网络请求
+                    uni.request({
+                        url: app.globalData.get_request_url('add', 'answer'),
+                        method: 'POST',
+                        data: e.detail.value,
+                        dataType: 'json',
+                        success: res => {
+                            uni.hideLoading();
+                            if (res.data.code == 0) {
+                                app.globalData.showToast(res.data.msg, 'success');
+                                setTimeout(function() {
+                                    uni.redirectTo({
+                                        url: "/pages/user-answer-list/user-answer-list"
+                                    });
+                                }, 2000);
+                            } else {
+                                this.setData({
+                                    form_submit_loading: false
+                                });
+                                if (app.globalData.is_login_check(res.data)) {
+                                    app.globalData.showToast(res.data.msg);
+                                } else {
+                                    app.globalData.showToast('提交失败,请重试!');
+                                }
+                            }
+                        },
+                        fail: () => {
+                            uni.hideLoading();
+                            this.setData({
+                                form_submit_loading: false
+                            });
+                            app.globalData.showToast('服务器请求出错');
+                        }
+                    });
+                }
+            }
+        }
+    };
+</script>
+<style>
+</style>

+ 4 - 0
pages/answer-list/answer-list.css

@@ -0,0 +1,4 @@
+.avatar {
+    width: 35rpx;
+    height: 35rpx;
+}

+ 165 - 0
pages/answer-list/answer-list.vue

@@ -0,0 +1,165 @@
+<template>
+    <view>
+        <scroll-view :scroll-y="true" class="scroll-box" @scrolltolower="scroll_lower" lower-threshold="60">
+            <view v-if="data_list.length > 0" class="padding-horizontal-main padding-top-main">
+                <view v-for="(item, index) in data_list" :key="index" class="padding-main border-radius-main bg-white oh spacing-mb">
+                    <view class="br-b-dashed oh padding-bottom-main">
+                        <image class="avatar fl br bg-white round" :src="item.user.avatar" mode="widthFix" :data-index="index" @error="user_avatar_error"></image>
+                        <text class="fl margin-left-sm cr-base">{{item.user.user_name_view}}</text>
+                        <text class="fr cr-base">{{item.add_time_time}}</text>
+                    </view>
+                    <view class="cr-gray margin-top-lg">{{item.content}}</view>
+                    <view v-if="(item.reply || null) != null" class="br-t margin-top-main padding-top-main">
+                        <text class="bg-main cr-white padding-top-xs padding-bottom-xs padding-left padding-right round margin-right-sm">答</text>
+                        <text class="cr-gray">{{item.reply}}</text>
+                    </view>
+                </view>
+            </view>
+            <view v-else>
+                <!-- 提示信息 -->
+                <component-no-data :propStatus="data_list_loding_status"></component-no-data>
+            </view>
+
+            <!-- 结尾 -->
+            <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+        </scroll-view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+
+    export default {
+        data() {
+            return {
+                data_list: [],
+                data_total: 0,
+                data_page_total: 0,
+                data_page: 1,
+                data_list_loding_status: 1,
+                data_bottom_line_status: false
+            };
+        },
+
+        components: {
+            componentNoData,
+            componentBottomLine
+        },
+        props: {},
+
+        onLoad() {},
+
+        onShow() {
+            this.get_data_list();
+            
+            // 分享菜单处理
+            app.globalData.page_share_handle();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.setData({
+                data_page: 1
+            });
+            this.get_data_list(1);
+        },
+
+        methods: {
+            get_data_list(is_mandatory) {
+                // 分页是否还有数据
+                if ((is_mandatory || 0) == 0) {
+                    if (this.data_bottom_line_status == true) {
+                        uni.stopPullDownRefresh();
+                        return false;
+                    }
+                }
+                
+                // 加载loding
+                this.setData({
+                    data_list_loding_status: 1
+                });
+                
+                // 获取数据
+                uni.request({
+                    url: app.globalData.get_request_url("square", "answer"),
+                    method: 'POST',
+                    data: {
+                        page: this.data_page
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            if (res.data.data.data.length > 0) {
+                                if (this.data_page <= 1) {
+                                    var temp_data_list = res.data.data.data;
+                                } else {
+                                    var temp_data_list = this.data_list || [];
+                                    var temp_data = res.data.data.data;
+                                    for (var i in temp_data) {
+                                        temp_data_list.push(temp_data[i]);
+                                    }
+                                }
+
+                                this.setData({
+                                    data_list: temp_data_list,
+                                    data_total: res.data.data.total,
+                                    data_page_total: res.data.data.page_total,
+                                    data_list_loding_status: 3,
+                                    data_page: this.data_page + 1
+                                });
+                                
+                                // 是否还有数据
+                                this.setData({
+                                    data_bottom_line_status: (this.data_page > 1 && this.data_page > this.data_page_total)
+                                });
+                            } else {
+                                this.setData({
+                                    data_list_loding_status: 0
+                                });
+                            }
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0
+                            });
+                            if (app.globalData.is_login_check(res.data, this, 'get_data_list')) {
+                                app.globalData.showToast(res.data.msg);
+                            }
+                        }
+                    },
+                    fail: () => {
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 滚动加载
+            scroll_lower(e) {
+                this.get_data_list();
+            },
+
+            // 头像加载错误
+            user_avatar_error(e) {
+                var index = e.currentTarget.dataset.index || 0;
+                var temp_data_list = this.data_list;
+                for (var i in temp_data_list) {
+                    if (i == index) {
+                        temp_data_list[i]['user']['avatar'] = app.globalData.data.default_user_head_src;
+                        break;
+                    }
+                }
+                this.setData({
+                    data_list: temp_data_list
+                });
+            }
+        }
+    };
+</script>
+<style>
+    @import './answer-list.css';
+</style>

+ 233 - 0
pages/article-category/article-category.vue

@@ -0,0 +1,233 @@
+<template>
+    <view>
+        <!-- 分类 -->
+        <scroll-view v-if="(category_list || null) != null && category_list.length > 0" class="nav-base scroll-view-horizontal bg-white oh" scroll-x="true">
+            <view :class="'item cr-gray dis-inline-block padding-horizontal-main ' + (nav_active_value == 0 ? 'cr-main' : '')" @tap="nav_event" data-value="0">全部</view>
+            <block v-for="(item, index) in category_list" :key="index">
+                <view :class="'item cr-gray dis-inline-block padding-horizontal-main ' + (nav_active_value == item.id ? 'cr-main' : '')" @tap="nav_event" :data-value="item.id">{{item.name}}</view>
+            </block>
+        </scroll-view>
+
+        <!-- 列表 -->
+        <scroll-view :scroll-y="true" class="scroll-box scroll-box-ece-nav" @scrolltolower="scroll_lower" lower-threshold="60">
+            <view v-if="(data_list || null) != null && data_list.length > 0" class="data-list padding-horizontal-main padding-top-main oh">
+                <block v-for="(item, index) in data_list" :key="index">
+                    <view class="item padding-main border-radius-main bg-white oh spacing-mb">
+                        <navigator :url="item.url" hover-class="none">
+                            <view class="cr-base fw-b" :style="(item.title_color || null) != null ? 'color:'+item.title_color+' !important;' : ''">{{item.title}}</view>
+                            <view class="cr-grey oh margin-top-sm">
+                                <text class="fl">{{item.add_time}}</text>
+                                <text class="fr">浏览量 {{item.access_count}}</text>
+                            </view>
+                        </navigator>
+                    </view>
+                </block>
+            </view>
+            <view v-else>
+                <!-- 提示信息 -->
+                <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+            </view>
+
+            <!-- 结尾 -->
+            <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+        </scroll-view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+
+    export default {
+        data() {
+            return {
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                data_bottom_line_status: false,
+                data_list: [],
+                data_total: 0,
+                data_page_total: 0,
+                data_page: 1,
+                params: null,
+                category_list: [],
+                nav_active_value: 0,
+                // 自定义分享信息
+                share_info: {}
+            };
+        },
+
+        components: {
+            componentNoData,
+            componentBottomLine
+        },
+        props: {},
+
+        onLoad(params) {
+            this.setData({
+                params: params,
+                nav_active_value: params.id || 0
+            });
+            
+            // 数据加载
+            this.get_data();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.setData({
+                data_page: 1
+            });
+            this.get_data_list(1);
+        },
+
+        methods: {
+            // 初始化
+            get_data() {
+                uni.showLoading({
+                    title: '加载中...'
+                });
+                uni.request({
+                    url: app.globalData.get_request_url("index", "article"),
+                    method: 'POST',
+                    data: {},
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            this.setData({
+                                category_list: data.category_list || []
+                            });
+
+                            // 基础自定义分享
+                            this.setData({
+                                share_info: {
+                                    path: '/pages/article-category/article-category',
+                                    query: 'id='+this.nav_active_value
+                                }
+                            });
+
+                            // 获取列表数据
+                            this.get_data_list(1);
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0,
+                                data_list_loding_msg: res.data.msg
+                            });
+                            app.globalData.showToast(res.data.msg);
+                        }
+                        
+                        // 分享菜单处理
+                        app.globalData.page_share_handle(this.share_info);
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 获取数据列表
+            get_data_list(is_mandatory) {
+                // 分页是否还有数据
+                if ((is_mandatory || 0) == 0) {
+                    if (this.data_bottom_line_status == true) {
+                        uni.stopPullDownRefresh();
+                        return false;
+                    }
+                }
+                
+                // 加载loding
+                uni.showLoading({
+                    title: '加载中...'
+                });
+
+                // 获取数据
+                uni.request({
+                    url: app.globalData.get_request_url("datalist", "article"),
+                    method: 'POST',
+                    data: {
+                        page: this.data_page,
+                        id: this.nav_active_value || 0
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            if (data.data.length > 0) {
+                                if (this.data_page <= 1) {
+                                    var temp_data_list = data.data;
+                                } else {
+                                    var temp_data_list = this.data_list || [];
+                                    var temp_data = data.data;
+                                    for (var i in temp_data) {
+                                        temp_data_list.push(temp_data[i]);
+                                    }
+                                }
+                                this.setData({
+                                    data_list: temp_data_list,
+                                    data_total: data.total,
+                                    data_page_total: data.page_total,
+                                    data_list_loding_status: 3,
+                                    data_page: this.data_page + 1
+                                });
+                                
+                                // 是否还有数据
+                                this.setData({
+                                    data_bottom_line_status: (this.data_page > 1 && this.data_page > this.data_page_total)
+                                });
+                            } else {
+                                this.setData({
+                                    data_list_loding_status: 0
+                                });
+                                if (this.data_page <= 1) {
+                                    this.setData({
+                                        data_list: [],
+                                        data_bottom_line_status: false
+                                    });
+                                }
+                            }
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0,
+                                data_list_loding_msg: res.data.msg
+                            });
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 滚动加载
+            scroll_lower(e) {
+                this.get_data_list();
+            },
+
+            // 导航事件
+            nav_event(e) {
+                this.setData({
+                    nav_active_value: e.currentTarget.dataset.value || 0,
+                    data_page: 1
+                });
+                this.get_data_list(1);
+            }
+        }
+    };
+</script>
+<style>
+</style>

+ 3 - 0
pages/article-detail/article-detail.css

@@ -0,0 +1,3 @@
+.last-next-data navigator {
+    width: calc(100% - 120rpx);
+}

+ 142 - 0
pages/article-detail/article-detail.vue

@@ -0,0 +1,142 @@
+<template>
+    <view>        
+        <view v-if="(data || null) != null" class="padding-main">
+            <view class="padding-main border-radius-main bg-white spacing-mb">
+                <view class="fw-b text-size-xl">{{data.title}}</view>
+                <view class="cr-grey margin-top-lg oh br-t padding-top-main">
+                    <view class="fl">
+                        <text>时间:</text>
+                        <text>{{data.add_time}}</text>
+                    </view>
+                    <view class="fr">
+                        <text class="margin-left-xxxl">浏览:</text>
+                        <text>{{data.access_count}}</text>
+                    </view>
+                </view>
+            </view>
+            <view class="padding-main border-radius-main bg-white oh web-html-content spacing-mb">
+                <mp-html :content="data.content" />
+            </view>
+            
+            <!-- 上一篇、下一篇 -->
+            <view v-if="(last_next || null) != null" class="last-next-data spacing-mb">
+                <view v-if="(last_next.last || null) != null">
+                    <text class="cr-gray va-m">上一篇:</text>
+                    <navigator :url="last_next.last.url" open-type="redirect" hover-class="none" class="dis-inline-block va-m cr-blue">{{last_next.last.title}}</navigator>
+                </view>
+                <view v-if="(last_next.next || null) != null" class="margin-top-sm">
+                    <text class="cr-gray va-m">下一篇:</text>
+                    <navigator :url="last_next.next.url" open-type="redirect" hover-class="none" class="dis-inline-block va-m cr-blue">{{last_next.next.title}}</navigator>
+                </view>
+            </view>
+        </view>
+        <view v-else>
+            <!-- 提示信息 -->
+            <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+
+    export default {
+        data() {
+            return {
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                data_bottom_line_status: false,
+                params: null,
+                data: null,
+                last_next: null,
+                // 自定义分享信息
+                share_info: {}
+            };
+        },
+
+        components: {
+            componentNoData,
+            componentBottomLine
+        },
+        props: {},
+
+        onLoad(params) {
+            this.setData({
+                params: params
+            });
+            
+            // 数据加载
+            this.get_data();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.get_data();
+        },
+
+        methods: {
+            // 初始化
+            get_data() {
+                uni.showLoading({
+                    title: '加载中...'
+                });
+                uni.request({
+                    url: app.globalData.get_request_url("detail", "article"),
+                    method: 'POST',
+                    data: {
+                        id: this.params.id || 0,
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        var data = res.data.data;
+                        if (res.data.code == 0 && (data.data || null) != null) {
+                            var article = data.data;
+                            this.setData({
+                                data_bottom_line_status: true,
+                                data_list_loding_status: 3,
+                                data: article,
+                                last_next: data.last_next || null
+                            });
+
+                            // 基础自定义分享
+                            this.setData({
+                                share_info: {
+                                    title: this.data.seo_title || this.data.title,
+                                    desc: this.data.seo_desc,
+                                    path: '/pages/article-detail/article-detail',
+                                    query: 'id='+this.data.id
+                                }
+                            });
+                            
+                            // 标题
+                            uni.setNavigationBarTitle({title: article.title});
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0,
+                                data_list_loding_msg: res.data.msg
+                            });
+                            app.globalData.showToast(res.data.msg);
+                        }
+                        
+                        // 分享菜单处理
+                        app.globalData.page_share_handle(this.share_info);
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            }
+        }
+    };
+</script>
+<style>
+    @import './article-detail.css';
+</style>

+ 238 - 0
pages/buy/buy.css

@@ -0,0 +1,238 @@
+/**
+* 地址
+*/
+.address-base,
+.address-detail {
+    padding-right: 40rpx;;
+}
+.address-detail .icon {
+    width: 30rpx;
+    height: 35rpx !important;
+}
+.address-detail .text {
+    width: calc(100% - 40rpx);
+}
+.address-alias,
+.goods-group-alias,
+.goods-group-map-submit {
+    padding: 0 15rpx;
+    line-height: 40rpx;
+}
+
+/**
+* 商品
+*/
+.goods-group-icon {
+    width: 30rpx;
+    height: 30rpx;
+}
+.goods-group-title {
+    font-weight: bold;
+    vertical-align: middle;
+}
+.goods-group-alias {
+    border: 1px solid #3bb4f2;
+    color: #3bb4f2;
+}
+.goods-image {
+    width: 160rpx;
+    height: 160rpx;
+    margin-right: 20rpx;
+}
+.buy-number {
+    right: 0;
+    bottom: 0;
+}
+.goods-base {
+    min-height: 160rpx;
+    margin-left: 180rpx;
+}
+
+/**
+* 导航
+*/
+.buy-nav {
+    position: fixed;
+    left: 0;
+    bottom: 0;
+}
+.buy-nav,
+.nav-base {
+    height: 100rpx;
+    line-height: 100rpx;
+}
+.nav-submit button {
+    height: 72rpx;
+    line-height: 72rpx;
+}
+.nav-base {
+    width: calc(60% - 20rpx);
+}
+.nav-submit {
+    width: calc(40% - 40rpx);
+}
+
+/**
+* 支付方式
+*/
+.payment-list .item {
+    width: calc(50% - 10rpx);
+}
+.payment-list .item:nth-child(2n) {
+    float: right;
+}
+.payment-list .item:nth-child(2n+1) {
+    float: left;
+}
+.payment-list .item-content {
+    padding: 20rpx 10rpx;
+}
+.payment-list .item-content image {
+    width: 50rpx;
+    height: 50rpx !important;
+}
+
+/**
+* 扩展数据
+*/
+.extension-list {
+    background-color: #ffffeb;
+    border: 1px solid #ffe2cf;
+}
+.extension-list .item:not(:last-child) {
+    border-bottom: 1px dashed #ffe2cf;
+}
+.extension-list .item .text-tips {
+    color: #ff8f44;
+}
+
+/**
+* 留言
+*/
+.content-textarea-container {
+    height: 100rpx;
+}
+.content-textarea-container view,
+.content-textarea-container textarea {
+    height: 100% !important;
+}
+.content-textarea-container textarea {
+    padding: 5rpx 0;
+}
+
+/**
+* 销售+自提 模式选择
+*/
+.buy-header-nav .item {
+    padding: 25rpx 0;
+    width: 50%;
+}
+
+/**
+ * 数据列表项
+ */
+.buy-data-item {
+    padding: 0 40rpx 0 20rpx;
+    line-height: 80rpx;
+}
+.buy-data-item-group {
+    padding: 0 40rpx 0 0;
+}
+.buy-data-item .right-value {
+    width: calc(100% - 300rpx);
+    min-height: 80rpx;
+}
+
+/*
+* 插件样式区域
+*/
+/*
+* 优惠劵
+*/
+.plugins-coupon-popup {
+    padding-top: 20rpx;
+}
+.plugins-coupon-popup .close {
+    margin-right: 20rpx;
+}
+.plugins-coupon-container {
+    max-height: 80vh;
+    overflow-y: scroll;
+    overflow-x: hidden;
+}
+.plugins-coupon-container .item,
+.plugins-coupon-container .v-right,
+.plugins-coupon-container .v-right .circle {
+    height: 230rpx;
+}
+.plugins-coupon-container .not-use-tips {
+    color: #f7b240;
+    font-size: 32rpx;
+}
+
+/*
+* 积分
+*/
+.plugins-points-buy-container {
+    padding: 20rpx;
+}
+.plugins-points-buy-container .select .icon {
+    width: 35rpx;
+    height: 35rpx !important;
+    vertical-align: middle;
+}
+.plugins-points-buy-container .select .sales-price {
+    margin-left: 30rpx;
+    font-size: 28rpx;
+    font-weight: 400;
+}
+.plugins-points-buy-container .desc {
+    color: #F37B1D;
+}
+
+/**
+ * 门店次卡-页面选择
+ */
+.plugins-realstore-container-view .image {
+    width: 40rpx;
+    height: 40rpx !important;
+}
+/*
+ * 门店次卡-弹窗选择
+ */
+.plugins-realstore-container {
+    max-height: 80vh;
+    overflow-y: scroll;
+    overflow-x: hidden;
+}
+.plugins-realstore-container .item {
+    overflow: hidden;
+    height: 220rpx;
+}
+.plugins-realstore-container .v-left {
+    width: calc(100% - 140rpx);
+    padding: 30rpx 0 30rpx 20rpx;
+    box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+}
+.plugins-realstore-container .v-left .base {
+    font-family: arial;
+    color: #D2364C;
+}
+.plugins-realstore-container .v-right {
+    width: 140rpx;
+    height: 220rpx;
+    font-weight: 500;
+}
+.plugins-realstore-container .v-right:before {
+    content: '';
+    display: inline-block;
+    height: 100%;
+    vertical-align: middle;
+}
+.plugins-realstore-container .item-disabled .v-right {
+    background: #dfdfdf !important;
+    color: #c0c0c0 !important;
+    cursor: no-drop !important;
+}

+ 865 - 0
pages/buy/buy.vue

@@ -0,0 +1,865 @@
+<template>
+    <view>
+        <block v-if="common_site_type == 1">
+            <component-no-data propStatus="2" propMsg="展示型不允许提交订单"></component-no-data>
+        </block>
+        <block v-else>
+            <view v-if="goods_list.length > 0" class="page-bottom-fixed">
+                <!-- 销售+自提 模式选择 -->
+                <view v-if="common_site_type == 4" class="buy-header-nav bg-white oh tc">
+                    <block v-for="(item, index) in buy_header_nav" :key="index">
+                        <view :class="'item fl cp ' + (site_model == item.value ? 'cr-main' : 'cr-base')" :data-value="item.value" @tap="buy_header_nav_event">{{item.name}}</view>
+                    </block>
+                </view>
+
+                <view class="padding-horizontal-main padding-top-main bottom-line-exclude">
+                    <!-- 地址 -->
+                    <view v-if="common_site_type == 0 || common_site_type == 2 || common_site_type == 4" class="padding-horizontal-main padding-top-main border-radius-main bg-white spacing-mb">
+                        <view class="address arrow-right cp" @tap="address_event">
+                            <view v-if="address != null" class="padding-bottom-main">
+                                <view class="address-base">
+                                    <text v-if="(address.alias || null) != null" class="address-alias br-main cr-main round margin-right-sm text-size-xs">{{address.alias}}</text>
+                                    <text>{{address.name}}</text>
+                                    <text class="fr">{{address.tel}}</text>
+                                </view>
+                                <view class="address-detail oh margin-top-lg">
+                                    <image class="icon fl" :src="common_static_url+'map-icon.png'" mode="widthFix"></image>
+                                    <view class="text fr">
+                                        {{address.province_name || ''}}{{address.city_name || ''}}{{address.county_name || ''}}{{address.address || ''}}
+                                    </view>
+                                </view>
+                            </view>
+                            <view v-if="address == null" class="padding-top-xl padding-bottom-xxxl cr-gray">
+                                {{(common_site_type == 0 || (common_site_type == 4 && site_model == 0)) ? '请选择收货地址' : '请选择取货地址'}}
+                            </view>
+                        </view>
+                        <view class="address-divider spacing-mb"></view>
+                    </view>
+
+                    <!-- 商品数据 -->
+                    <view v-for="(group, index) in goods_list" :key="index" class="goods-group-list padding-main border-radius-main bg-white spacing-mb">
+                        <!-- 仓库分组 -->
+                        <view class="goods-group-hd oh br-b padding-bottom-main">
+                            <view class="fl cp" @tap="warehouse_group_event" :data-value="group.url || ''">
+                                <image v-if="(group.icon || null) != null" class="goods-group-icon va-m margin-right-xs" :src="group.icon" mode="aspectFit"></image>
+                                <text class="goods-group-title va-m">{{group.name}}</text>
+                                <text v-if="(group.alias || null) != null" class="goods-group-alias va-m round margin-left-sm text-size-xs">{{group.alias}}</text>
+                            </view>
+                            <!-- #ifndef MP-KUAISHOU -->
+                            <view v-if="(group.lng || 0) != 0 && (group.lat || 0) != 0" class="fr">
+                                <view class="goods-group-map-submit br round text-size-xs" :data-index="index" @tap="map_event">查看地图</view>
+                            </view>
+                            <!-- #endif -->
+                        </view>
+                        <!-- 商品 -->
+                        <view class="goods-content margin-bottom-sm">
+                            <view v-for="(item, index2) in group.goods_items" :key="index2" class="goods-item padding-vertical-main oh br-b-dashed">
+                                <image class="goods-image fl radius" :src="item.images" mode="aspectFill"></image>
+                                <view class="goods-base">
+                                    <view class="goods-title multi-text">{{item.title}}</view>
+                                    <view v-if="item.spec != null" class="margin-top-xs cr-gray">
+                                        <block v-for="(spec, si) in item.spec" :key="si">
+                                            <text v-if="si > 0">;</text>
+                                            <text>{{spec.value}}</text>
+                                        </block>
+                                    </view>
+                                    <view class="oh pr margin-top-sm">
+                                        <text class="fw-b">{{currency_symbol}}{{item.price}}</text>
+                                        <text v-if="item.original_price > 0" class="original-price margin-left-sm">{{currency_symbol}}{{item.original_price}}</text>
+                                        <text class="buy-number pa cr-gray">x{{item.stock}}</text>
+                                    </view>
+                                </view>
+                            </view>
+                        </view>
+                        <!-- 优惠劵 -->
+                        <view v-if="(plugins_coupon_data || null) != null && (plugins_coupon_data[index] || null) != null && (plugins_coupon_data[index].coupon_data || null) != null && (plugins_coupon_data[index].coupon_data.coupon_list || null) != null && plugins_coupon_data[index].coupon_data.coupon_list.length > 0" class="buy-data-item buy-data-item-group arrow-right" :data-index="index" @tap="plugins_coupon_open_event">
+                            <text class="cr-base">优惠劵</text>
+                            <text class="cr-grey fr cp">{{((plugins_choice_coupon_value || null) != null && (plugins_choice_coupon_value[group.id] || null) != null) ? plugins_choice_coupon_value[group.id] : '请选择优惠券'}}</text>
+                        </view>
+                        <!-- 门店次卡 -->
+                        <view v-if="(plugins_realstore_data || null) != null && (plugins_realstore_data[group.id] || null) != null" class="plugins-realstore-container-view">
+                            <block v-for="(item, index2) in plugins_realstore_data[group.id]['data']" :key="index2">
+                                <view class="buy-data-item buy-data-item-group arrow-right">
+                                    <text class="cr-base va-m">门店次卡</text>
+                                    <image class="image circle br va-m margin-left-lg" :src="item.images" mode="aspectFill"></image>
+                                    <text class="cr-grey va-m margin-left-xs text-size-xs">x{{item.stock}}</text>
+                                    <view class="right-value single-text dis-inline-block fr tr" :data-index="index2" :data-groupid="group.id" @tap="plugins_realstore_open_event">
+                                        <text class="cr-grey">{{item.tips_msg}}</text>
+                                    </view>
+                                </view>
+                            </block>
+                        </view>
+                        <!-- 扩展数据展示 -->
+                        <view v-if="group.order_base.extension_data.length > 0" class="extension-list radius margin-top-lg">
+                            <view v-for="(item, index2) in group.order_base.extension_data" :key="index2" class="item oh padding-main">
+                                <text class="cr-base fl">{{item.name}}</text>
+                                <text class="text-tips fr">{{item.tips}}</text>
+                            </view>
+                        </view>
+                        <!-- 小计 -->
+                        <view class="oh tr goods-group-footer padding-top-xl">
+                            <text v-if="group.order_base.total_price != group.order_base.actual_price" class="original-price margin-right-sm">{{currency_symbol}}{{group.order_base.total_price}}</text>
+                            <text class="sales-price">{{currency_symbol}}{{group.order_base.actual_price}}</text>
+                        </view>
+                    </view>
+
+                    <!-- 积分 -->
+                    <view v-if="(plugins_points_data || null) != null" class="plugins-points-buy-container padding-main border-radius-main bg-white spacing-mb">
+                        <block v-if="(plugins_points_data.discount_price || 0) > 0">
+                            <view class="select oh">
+                                <text v-if="plugins_points_data.discount_type == 1">使用{{plugins_points_data.use_integral}}个积分兑换商品</text>
+                                <text v-else>使用积分{{plugins_points_data.use_integral}}个</text>
+                                <text class="sales-price">-{{currency_symbol}}{{plugins_points_data.discount_price}}</text>
+                                <view @tap="points_event" class="fr cp">
+                                    <image class="icon" :src="common_static_url+'select' + (plugins_points_status ? '-active' : '') + '-icon.png'" mode="widthFix"></image>
+                                </view>
+                            </view>
+                            <view class="desc">
+                                <text v-if="plugins_points_data.discount_type == 1">你有积分{{plugins_points_data.user_integral}}个</text>
+                                <text v-else>你有积分{{plugins_points_data.user_integral}}个,可用{{plugins_points_data.use_integral}}个</text>
+                            </view>
+                        </block>
+                        <block v-else>
+                            <view v-if="(plugins_points_data.is_support_goods_exchange || 0) == 1" class="desc tr">
+                                <text>你有积分{{plugins_points_data.user_integral}}个,不足以兑换当前商品</text>
+                            </view>
+                        </block>
+                    </view>
+
+                    <!-- 时间选择 -->
+                    <view v-if="(buy_datetime_info || null) != null && (buy_datetime_info.is_select || false) == true" class="buy-data-item bg-white border-radius-main spacing-mb arrow-right">
+                        <text class="cr-base">{{buy_datetime_info.title}}</text>
+                        <view class="right-value single-text dis-inline-block fr tr">
+                            <component-time-select :propTitle="buy_datetime_info.title" :propPlaceholder="buy_datetime_info.placeholder" :propRangeDay="buy_datetime_info.range_day || 2" :propRangeStartTime="buy_datetime_info.time_start" :propRangeEndTime="buy_datetime_info.time_end" :propDisabled="buy_datetime_info.disabled" :propIsShow="buy_datetime_info.status" @selectEvent="buy_datetime_event">
+                                <text v-if="(buy_datetime_info.value || null) == null" class="cr-grey">{{buy_datetime_info.placeholder}}</text>
+                                <text v-else class="cr-base">{{buy_datetime_info.value}}</text>
+                            </component-time-select>
+                        </view>
+                    </view>
+
+                    <!-- 留言 -->
+                    <view class="content-textarea-container padding-main border-radius-main bg-white spacing-mb">
+                        <textarea v-if="user_note_status" @blur="bind_user_note_blur_event" @input="bind_user_note_event" :focus="true" :disable-default-padding="false" :value="user_note_value" maxlength="60" placeholder="留言"></textarea>
+                        <view v-else @tap="bind_user_note_tap_event" :class="(user_note_value || null) == null ? 'cr-gray' : ''">{{user_note_value || '留言'}}</view>
+                    </view>
+
+                    <!-- 支付方式 -->
+                    <view v-if="total_price > 0 && payment_list.length > 0 && common_order_is_booking != 1" class="payment-list padding-horizontal-main padding-top-main border-radius-main bg-white oh">
+                        <view v-for="(item, index) in payment_list" :key="index" class="item tc fl cp margin-bottom-main">
+                            <view :class="'item-content radius br ' + (payment_id == item.id ? 'cr-main br-main' : '')" :data-value="item.id" @tap="payment_event">
+                                <image v-if="(item.logo || null) != null" class="icon margin-right-sm va-m" :src="item.logo" mode="widthFix"></image>
+                                <text>{{item.name}}</text>
+                            </view>
+                        </view>
+                    </view>
+                </view>
+
+                <!-- 导航 -->
+                <view class="buy-nav oh wh-auto bg-white br-t bottom-line-exclude">
+                    <view class="nav-base fl single-text padding-left-main">
+                        <text>合计:</text>
+                        <text class="sales-price">{{currency_symbol}}{{total_price}}</text>
+                    </view>
+                    <view class="fr nav-submit padding-top padding-bottom padding-horizontal-main">
+                        <button class="bg-main cr-white round text-size" type="default" @tap="buy_submit_event" :disabled="buy_submit_disabled_status" hover-class="none">提交订单</button>
+                    </view>
+                </view>
+            </view>
+
+            <view v-if="goods_list.length == 0">
+                <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+            </view>
+
+            <!-- 优惠劵选择 -->
+            <component-popup :propShow="popup_plugins_coupon_status" propPosition="bottom" @onclose="plugins_coupon_close_event">
+                <view class="plugins-coupon-popup bg-base">
+                    <view class="close oh">
+                        <view class="fr" @tap.stop="plugins_coupon_close_event">
+                            <icon type="clear" size="20"></icon>
+                        </view>
+                    </view>
+                    <view v-if="plugins_coupon_list.length > 0" class="plugins-coupon-container padding-horizontal-main padding-bottom-main oh">
+                        <view class="not-use-tips tc">
+                            <text class="cp" @tap="plugins_coupon_not_use_event">不使用优惠劵</text>
+                        </view>
+                        <block v-for="(item, index) in plugins_coupon_list" :key="index">
+                            <view :class="'item spacing-mt bg-white border-radius-main ' + ((item.is_active || 0) == 1 ? 'item-disabled' : '')">
+                                <view class="v-left fl">
+                                    <view class="base single-text" :style="'color:' + item.coupon.bg_color_value + ';'">
+                                        <text v-if="item.coupon.type == 0" class="symbol">{{currency_symbol}}</text>
+                                        <text class="price">{{item.coupon.discount_value}}</text>
+                                        <text class="unit">{{item.coupon.type_unit}}</text>
+                                        <text v-if="(item.coupon.desc || null) != null" class="desc cr-gray">{{item.coupon.desc}}</text>
+                                    </view>
+                                    <view v-if="(item.coupon.use_limit_type_name || null) != null" class="base-tips cr-base single-text">{{item.coupon.use_limit_type_name}}</view>
+                                    <view class="base-time cr-gray single-text">{{item.time_start}} 至 {{item.time_end}}</view>
+                                </view>
+                                <view :class="'v-right fr '+((item.is_active || 0) == 1 ? '' : 'cp')" :style="'background:' + item.coupon.bg_color_value + ';'" :data-index="index" :data-value="item.id" @tap="plugins_coupon_use_event">
+                                    <text class="circle"></text>
+                                    <text>{{(item.is_active || 0) == 1 ? '已选' : '选择'}}</text>
+                                </view>
+                            </view>
+                        </block>
+                    </view>
+                </view>
+            </component-popup>
+            
+            <!-- 次卡选择 -->
+            <component-popup :propShow="popup_plugins_realstore_status" propPosition="bottom" @onclose="plugins_realstore_close_event">
+                <view class="bg-base padding-top-lg">
+                    <view class="close oh margin-right-lg padding-bottom-sm">
+                        <view class="fr" @tap.stop="plugins_realstore_close_event">
+                            <icon type="clear" size="20"></icon>
+                        </view>
+                    </view>
+                    <view class="plugins-realstore-container padding-horizontal-main padding-bottom-main oh">
+                        <view class="not-use-tips tc">
+                            <text class="cp cr-yellow text-size-sm" data-type="0" @tap="plugins_realstore_use_event">不使用次卡</text>
+                        </view>
+                        <view v-if="(plugins_realstore_data || null) != null && (plugins_realstore_data[popup_plugins_realstore_group_id] || null) != null">
+                            <block v-for="(item, index) in plugins_realstore_data[popup_plugins_realstore_group_id]['data'][popup_plugins_realstore_card_index]['user_card']" :key="index">
+                                <view :class="'item spacing-mt bg-white border-radius-main ' + ((item.is_active || 0) == 1 ? 'item-disabled' : '')">
+                                    <view class="v-left fl">
+                                        <view class="base single-text">
+                                            <text class="value fw-b text-size-xxl">{{item.valid_number}}</text>
+                                            <text class="unit margin-left-xs">次</text>
+                                            <text v-if="(item.name || null) != null" class="cr-base margin-left-lg">{{item.name}}</text>
+                                        </view>
+                                        <view v-if="(item.describe || null) != null" class="margin-top-sm cr-grey single-text">{{item.describe}}</view>
+                                        <view class="margin-top-sm cr-gray single-text text-size-xs">{{item.start_time}} 至 {{item.end_time}}</view>
+                                    </view>
+                                    <view v-if="(item.is_active || 0) == 1" class="v-right bg-main fr tc cr-white">
+                                        <text>已选</text>
+                                    </view>
+                                    <view v-else class="v-right bg-main fr tc cr-white cp" :data-index="index" :data-value="item.id" data-type="1" @tap="plugins_realstore_use_event">
+                                        <text>选择</text>
+                                    </view>
+                                </view>
+                            </block>
+                        </view>
+                    </view>
+                </view>
+            </component-popup>
+        </block>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import base64 from '../../common/js/lib/base64.js';
+    import componentPopup from "../../components/popup/popup";
+    import componentNoData from "../../components/no-data/no-data";
+    import componentTimeSelect from "../../components/time-select/time-select";
+
+    var common_static_url = app.globalData.get_static_url('common');
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                data_list_loding_status: 1,
+                buy_submit_disabled_status: false,
+                data_list_loding_msg: '',
+                params: null,
+                payment_list: [],
+                goods_list: [],
+                address: null,
+                address_id: null,
+                total_price: 0,
+                user_note_value: '',
+                user_note_status: false,
+                is_first: 1,
+                extension_data: [],
+                payment_id: 0,
+                common_site_type: 0,
+                extraction_address: [],
+                site_model: 0,
+                buy_header_nav: [
+                    { name: "快递邮寄", value: 0 },
+                    { name: "自提点取货", value: 2 }
+                ],
+                // 基础配置
+                currency_symbol: app.globalData.data.currency_symbol,
+                common_order_is_booking: 0,
+                // 下单时间选择
+                buy_datetime_info: {},
+                // 优惠劵
+                plugins_coupon_data: null,
+                plugins_coupon_list: [],
+                plugins_use_coupon_ids: [],
+                plugins_choice_coupon_value: [],
+                popup_plugins_coupon_status: false,
+                popup_plugins_coupon_index: null,
+                // 积分
+                plugins_points_data: null,
+                plugins_points_status: false,
+                // 门店
+                plugins_realstore_data: [],
+                plugins_choice_realstore_value: {},
+                popup_plugins_realstore_status: false,
+                popup_plugins_realstore_group_id: 0,
+                popup_plugins_realstore_card_index: 0
+            };
+        },
+
+        components: {
+            componentPopup,
+            componentNoData,
+            componentTimeSelect
+        },
+        props: {},
+
+        onLoad(params) {
+            // params.data 参数 urlencode(base64_encode(json字符串))
+            //  buy_type 下单类型(goods 立即购买、cart 购物车)
+            //  goods_data 下单商品urlencode(base64_encode(json字符串[{goods_id,stock,spec}]))
+            //  params['data'] = '{"buy_type":"goods","goods_data":"W3siZ29vZHNfaWQiOiI5Iiwic3RvY2siOjEsInNwZWMiOlt7InR5cGUiOiLpopzoibIiLCJ2YWx1ZSI6IueyieiJsiJ9LHsidHlwZSI6IuWwuueggSIsInZhbHVlIjoiTCJ9XX1"}';
+            //  ids 购物车主键ids
+            if ((params.data || null) != null) {
+                this.setData({
+                    params: JSON.parse(base64.decode(decodeURIComponent(params.data))),
+                    plugins_points_status: app.globalData.get_config('plugins_base.points.data.is_default_use_points', null) == 1
+                });
+
+                // 删除地址缓存
+                uni.removeStorageSync(app.globalData.data.cache_buy_user_address_select_key);
+            }
+        },
+
+        onShow() {
+            // 数据加载
+            this.init();
+            this.setData({
+                is_first: 0
+            });
+
+            // 初始化配置
+            this.init_config();
+            
+            // 分享菜单处理
+            app.globalData.page_share_handle();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.init();
+        },
+
+        methods: {
+            // 初始化配置
+            init_config(status) {
+                if ((status || false) == true) {
+                    this.setData({
+                        currency_symbol: app.globalData.get_config('currency_symbol'),
+                        common_order_is_booking: app.globalData.get_config('config.common_order_is_booking'),
+                        plugins_points_status: app.globalData.get_config('plugins_base.points.data.is_default_use_points', null) == 1
+                    });
+                } else {
+                    app.globalData.is_config(this, 'init_config');
+                }
+            },
+
+            // 获取数据
+            init() {
+                // 订单参数信息是否正确
+                if (this.params == null) {
+                    this.setData({
+                        data_list_loding_status: 2,
+                        data_list_loding_msg: '商品信息有误'
+                    });
+                    uni.stopPullDownRefresh();
+                    return false;
+                }
+
+                // 本地缓存地址
+                if (this.is_first == 0) {
+                    var cache_address = uni.getStorageSync(app.globalData.data.cache_buy_user_address_select_key);
+                    if ((cache_address || null) != null) {
+                        this.setData({
+                            address: cache_address,
+                            address_id: cache_address.id
+                        });
+                    }
+                }
+
+                // 加载loding
+                uni.showLoading({
+                    title: '加载中...'
+                });
+                this.setData({
+                    data_list_loding_status: 1
+                });
+                var data = this.params;
+                data['address_id'] = this.address_id;
+                data['payment_id'] = this.payment_id;
+                data['site_model'] = this.site_model;
+                uni.request({
+                    url: app.globalData.get_request_url("index", "buy"),
+                    method: 'POST',
+                    data: this.request_data_ext_params_merge(data),
+                    dataType: 'json',
+                    success: res => {
+                        uni.stopPullDownRefresh();
+                        uni.hideLoading();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+
+                            // 订单是否已提交、直接进入支付页面
+                            if((data.is_order_submit || 0) == 1) {
+                                this.buy_submit_response_handle(data);
+                                return false;
+                            }
+
+                            // 处理订单初始化数据
+                            if (data.goods_list.length == 0) {
+                                this.setData({
+                                    data_list_loding_status: 0
+                                });
+                            } else {
+                                // 下单选择时间
+                                var data_dt = this.buy_datetime_info || {};
+                                var temp_dt = data.buy_datetime_info || {};
+                                var datetime = {
+                                    // 是否开启时间选择
+                                    is_select: (temp_dt.is_select || 0) == 1,
+                                    // 是否必选
+                                    required: (temp_dt.required || 0) == 1,
+                                    // 状态
+                                    status: data_dt.status || (temp_dt.status || 0) == 1 || false,
+                                    // 默认值
+                                    value: data_dt.value || temp_dt.value || '',
+                                    // 标题
+                                    title: temp_dt.title || '时间',
+                                    // 占位文本及标题
+                                    placeholder: temp_dt.placeholder || '选择时间',
+                                    // 天起始时间
+                                    time_start: temp_dt.time_start || '',
+                                    // 天结束时间
+                                    time_end: temp_dt.time_end || '',
+                                    // 可选最大天数
+                                    range_day: temp_dt.range_day || 2,
+                                    // 禁止选择的时间
+                                    disabled: temp_dt.disabled || '',
+                                    // 未选择错误提示
+                                    error_msg: temp_dt.error_msg || '请选择时间'
+                                };
+
+                                // 设置数据
+                                this.setData({
+                                    goods_list: data.goods_list,
+                                    total_price: data.base.actual_price,
+                                    extension_data: data.extension_data || [],
+                                    data_list_loding_status: 3,
+                                    common_site_type: data.common_site_type || 0,
+                                    extraction_address: data.base.extraction_address || [],
+                                    payment_list: data.payment_list || [],
+                                    payment_id: data.default_payment_id || 0,
+                                    buy_datetime_info: datetime,
+                                    plugins_coupon_data: data.plugins_coupon_data || null,
+                                    plugins_points_data: data.plugins_points_data || null,
+                                    plugins_realstore_data: data.plugins_realstore_data || null,
+                                });
+
+                                // 优惠劵选择处理
+                                if ((data.plugins_coupon_data || null) != null) {
+                                    var plugins_choice_coupon_value = [];
+                                    for (var i in data.plugins_coupon_data) {
+                                        var cupk = data.plugins_coupon_data[i]['warehouse_id'];
+
+                                        if ((data.plugins_coupon_data[i]['coupon_data']['coupon_choice'] || null) != null) {
+                                            plugins_choice_coupon_value[cupk] = data.plugins_coupon_data[i]['coupon_data']['coupon_choice']['coupon']['desc'];
+                                        } else {
+                                            var coupon_count = (data.plugins_coupon_data[i]['coupon_data']['coupon_list'] || null) != null ? data.plugins_coupon_data[i]['coupon_data'].coupon_list.length : 0;
+                                            plugins_choice_coupon_value[cupk] = coupon_count > 0 ? '可选优惠劵' +coupon_count + '张' : '暂无可用优惠劵';
+                                        }
+                                    }
+
+                                    this.setData({
+                                        plugins_choice_coupon_value: plugins_choice_coupon_value
+                                    });
+                                }
+
+                                // 地址
+                                this.setData({
+                                    address: data.base.address || null,
+                                    address_id: (data.base.address || null) != null ? data.base.address.id : null
+                                });
+                                uni.setStorage({
+                                    key: app.globalData.data.cache_buy_user_address_select_key,
+                                    data: data.base.address || null
+                                });
+                            }
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 2,
+                                data_list_loding_msg: res.data.msg
+                            });
+                            if (app.globalData.is_login_check(res.data, this, 'init')) {
+                                app.globalData.showToast(res.data.msg);
+                            }
+                        }
+                    },
+                    fail: () => {
+                        uni.stopPullDownRefresh();
+                        uni.hideLoading();
+                        this.setData({
+                            data_list_loding_status: 2,
+                            data_list_loding_msg: '服务器请求出错'
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 请求参数合并
+            request_data_ext_params_merge(data) {
+                // 优惠券
+                var coupon_ids = this.plugins_use_coupon_ids;
+                if ((coupon_ids || null) != null && coupon_ids.length > 0) {
+                    for (var i in coupon_ids) {
+                        data['coupon_id_' + i] = coupon_ids[i];
+                    }
+                }
+
+                // 门店次卡
+                var key = 'realstore_card_value';
+                var realstore_value = this.plugins_choice_realstore_value;
+                if(Object.keys(realstore_value).length > 0) {
+                    data[key] = realstore_value;
+                } else {
+                    if(data[key] != undefined) {
+                        delete data[key];
+                    }
+                }
+
+                // 积分
+                data['is_points'] = this.plugins_points_status === true ? 1 : 0;
+                return data;
+            },
+
+            // 用户留言输入事件
+            bind_user_note_event(e) {
+                this.setData({
+                    user_note_value: e.detail.value
+                });
+            },
+
+            // 用户留言点击
+            bind_user_note_tap_event(e) {
+                this.setData({
+                    user_note_status: true
+                });
+            },
+
+            // 用户留言失去焦点
+            bind_user_note_blur_event(e) {
+                this.setData({
+                    user_note_status: false
+                });
+            },
+
+            // 提交订单
+            buy_submit_event(e) {
+                // 表单数据
+                var data = this.params;
+                data['address_id'] = this.address_id;
+                data['payment_id'] = this.payment_id;
+                data['user_note'] = this.user_note_value;
+                data['site_model'] = this.site_model;
+
+                // 数据验证
+                var validation = [];
+                if (this.common_site_type == 0 || this.common_site_type == 2 || this.common_site_type == 4) {
+                    validation.push({
+                        fields: 'address_id',
+                        msg: '请选择地址',
+                        is_can_zero: 1
+                    });
+                }
+
+                if (app.globalData.fields_check(data, validation)) {
+                    // 请求参数处理
+                    data = this.request_data_ext_params_merge(data);
+
+                    // 是否需要选择时间
+                    var datetime = this.buy_datetime_info || {};
+                    if((datetime.is_select || false) == true) {
+                        // 是否必选
+                        if((datetime.required || false) == true && (datetime.value || null) == null) {
+                            app.globalData.showToast(datetime.error_msg || '请选择时间');
+                            return false;
+                        }
+                        data['buy_datetime_value'] = datetime.value || '';
+                    }
+
+                    // 是否需要选择支付方式
+                    if (this.total_price > 0 && this.common_order_is_booking != 1) {
+                        if((data.payment_id || null) == null) {
+                            app.globalData.showToast('请选择支付方式');
+                            return false;
+                        }
+                    }
+
+                    // 加载loding
+                    uni.showLoading({
+                        title: '提交中...'
+                    });
+                    this.setData({
+                        buy_submit_disabled_status: true
+                    });
+                    uni.request({
+                        url: app.globalData.get_request_url("add", "buy"),
+                        method: 'POST',
+                        data: data,
+                        dataType: 'json',
+                        success: res => {
+                            uni.hideLoading();
+                            if (res.data.code == 0) {
+                                this.buy_submit_response_handle(res.data.data);
+                            } else {
+                                app.globalData.showToast(res.data.msg);
+                                this.setData({
+                                    buy_submit_disabled_status: false
+                                });
+                            }
+                        },
+                        fail: () => {
+                            uni.hideLoading();
+                            this.setData({
+                                buy_submit_disabled_status: false
+                            });
+                            app.globalData.showToast('服务器请求出错');
+                        }
+                    });
+                }
+            },
+
+            // 订单提交响应处理
+            buy_submit_response_handle(data) {
+                if (data.order_status == 1) {
+                    var pay_data = {
+                        order_ids: data.order_ids.join(','),
+                        payment_id: data.payment_id
+                    };
+                    uni.setStorageSync(app.globalData.data.cache_page_pay_key, pay_data);
+                }
+                uni.redirectTo({
+                    url: '/pages/user-order/user-order'
+                });
+            },
+
+            // 支付方式选择
+            payment_event(e) {
+                this.setData({
+                    payment_id: e.currentTarget.dataset.value
+                });
+                this.init();
+            },
+
+            // 优惠劵弹层开启
+            plugins_coupon_open_event(e) {
+                var index = e.currentTarget.dataset.index;
+                var temp_list = this.plugins_coupon_data[index]['coupon_data']['coupon_list'];
+                // 选中处理
+                if(temp_list.length > 0) {
+                    var temp_ids = this.plugins_use_coupon_ids;
+                    for(var i in temp_list) {
+                        temp_list[i]['is_active'] = (temp_ids.indexOf(temp_list[i]['id']) != -1) ? 1 : 0;
+                    }
+                }
+                this.setData({
+                    plugins_coupon_list: temp_list,
+                    popup_plugins_coupon_status: true,
+                    popup_plugins_coupon_index: index
+                });
+            },
+
+            // 优惠劵弹层关闭
+            plugins_coupon_close_event(e) {
+                this.setData({
+                    popup_plugins_coupon_status: false
+                });
+            },
+
+            // 优惠劵选择
+            plugins_coupon_use_event(e) {
+                var index = e.currentTarget.dataset.index;
+                var value = e.currentTarget.dataset.value;
+                var temp_ids = this.plugins_use_coupon_ids;
+                if(this.popup_plugins_coupon_index !== null && temp_ids.indexOf(value) == -1) {
+                    var temp_data = this.plugins_coupon_data[this.popup_plugins_coupon_index];
+                    var temp_list = this.plugins_coupon_list;
+
+                    // 选中处理
+                    for(var i in temp_list) {
+                        temp_list[i]['is_active'] = (index == i) ? 1 : 0;
+                    }
+                    
+                    // 根据仓库id和优惠券id记录
+                    temp_ids[temp_data['warehouse_id']] = value;
+                    this.setData({
+                        plugins_use_coupon_ids: temp_ids,
+                        plugins_coupon_list: temp_list,
+                        popup_plugins_coupon_status: false
+                    });
+
+                    // 重新获取数据
+                    this.init();
+                }
+            },
+
+            // 不使用优惠劵
+            plugins_coupon_not_use_event(e) {
+                if(this.popup_plugins_coupon_index !== null) {
+                    var temp_data = this.plugins_coupon_data[this.popup_plugins_coupon_index];
+                    var temp_list = this.plugins_coupon_list;
+                    var temp = this.plugins_use_coupon_ids;
+                    for(var i in temp_list) {
+                        temp_list[i]['is_active'] = 0;
+                    }
+                    temp[temp_data['warehouse_id']] = 0;
+                    this.setData({
+                        plugins_coupon_list: temp_list,
+                        plugins_use_coupon_ids: temp,
+                        popup_plugins_coupon_status: false
+                    });
+                    this.init();
+                }
+            },
+
+            // 地址选择事件
+            address_event(e) {
+                // 带上参数
+                var json = this.params || null;
+                if(json != null) {
+                    var params = '&'+Object.keys(json).map(function(key) {
+                            var temp_val = (json[key] === undefined || json[key] === null) ? '' : json[key];
+                            return encodeURIComponent(key) + '=' + encodeURIComponent(temp_val);
+                        }).join('&');
+                } else {
+                    var params = '';
+                }
+
+                // 仅自提和快递需要选择地址
+                if (this.common_site_type == 0 || this.common_site_type == 4 && this.site_model == 0) {
+                    uni.navigateTo({
+                        url: '/pages/user-address/user-address?is_back=1'+params
+                    });
+                } else if (this.common_site_type == 2 || this.common_site_type == 4 && this.site_model == 2) {
+                    uni.navigateTo({
+                        url: '/pages/extraction-address/extraction-address?is_back=1&is_buy=1'+params
+                    });
+                } else {
+                    app.globalData.showToast('当前模式不允许使用地址');
+                }
+            },
+
+            // 销售+自提 模式选择事件
+            buy_header_nav_event(e) {
+                var value = e.currentTarget.dataset.value || 0;
+                if (value != this.site_model) {
+                    // 数据设置
+                    this.setData({
+                        address: null,
+                        address_id: null,
+                        site_model: value
+                    });
+
+                    // 删除地址缓存
+                    uni.removeStorageSync(app.globalData.data.cache_buy_user_address_select_key);
+                    
+                    // 数据初始化
+                    this.init();
+                }
+            },
+
+            // 地图查看
+            map_event(e) {
+                var index = e.currentTarget.dataset.index || 0;
+                var data = this.goods_list[index] || null;
+                if (data == null) {
+                    app.globalData.showToast("地址有误");
+                    return false;
+                }
+
+                // 打开地图
+                var name = data.alias || data.name || '';
+                var address = (data.province_name || '') + (data.city_name || '') + (data.county_name || '') + (data.address || '');
+                app.globalData.open_location(data.lng, data.lat, name, address);
+            },
+
+            // 积分选择事件
+            points_event(e) {
+                this.setData({
+                    plugins_points_status: !this.plugins_points_status
+                });
+                this.init();
+            },
+
+            // 仓库事件
+            warehouse_group_event(e) {
+                app.globalData.url_event(e);
+            },
+
+            // 下单选择时间
+            buy_datetime_event(e) {
+                var temp = this.buy_datetime_info;
+                temp['status'] = !temp.status;
+                if(e != 'open' && e != 'close') {
+                    temp['value'] = (((e || null) != null) ? e._date : '') || '';
+                }
+                this.setData({
+                    buy_datetime_info: temp
+                });
+            },
+
+            // 打开次卡选择
+            plugins_realstore_open_event(e) {
+                this.setData({
+                    popup_plugins_realstore_status: true,
+                    popup_plugins_realstore_group_id: e.currentTarget.dataset.groupid || 0,
+                    popup_plugins_realstore_card_index: e.currentTarget.dataset.index || 0,
+                });
+            },
+
+            // 关闭次卡选择
+            plugins_realstore_close_event(e) {
+                this.setData({
+                    popup_plugins_realstore_status: false
+                });
+            },
+
+            // 次卡选择事件
+            plugins_realstore_use_event(e) {
+                var type = e.currentTarget.dataset.type;
+                var group_id = this.popup_plugins_realstore_group_id;
+                var card_index = this.popup_plugins_realstore_card_index;
+                var id = this.plugins_realstore_data[group_id]['data'][card_index]['id'];
+                var temp = this.plugins_choice_realstore_value;
+                if(type == 1) {
+                    if(temp[group_id] == undefined) {
+                        temp[group_id] = {};
+                    }
+                    temp[group_id][id] = {
+                        group_id: group_id,
+                        data_id: id,
+                        card_id: e.currentTarget.dataset.value
+                    };
+                } else {
+                    if(temp[group_id] != undefined && temp[group_id][id] != undefined) {
+                        delete temp[group_id][id];
+                        if(Object.keys(temp[group_id]).length <= 0) {
+                            delete temp[group_id];
+                        }
+                    }
+                }
+                this.setData({
+                    plugins_choice_realstore_value: temp,
+                    popup_plugins_realstore_status: false
+                });
+                this.init();
+            }
+        }
+    };
+</script>
+<style>
+    @import './buy.css';
+</style>

+ 39 - 0
pages/cart-page/cart-page.vue

@@ -0,0 +1,39 @@
+<template>
+    <view>
+        <!-- 购物车 -->
+        <component-cart ref="cart"></component-cart>
+
+        <!-- 快捷导航 -->
+        <component-quick-nav :propIsBar="true"></component-quick-nav>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentQuickNav from "../../components/quick-nav/quick-nav";
+    import componentCart from "../../components/cart/cart";
+    export default {
+        data() {
+            return {};
+        },
+        components: {
+            componentQuickNav,
+            componentCart
+        },
+
+        onShow() {
+            // 数据加载
+            if((this.$refs.cart || null) != null) {
+                this.$refs.cart.init();
+            }
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.$refs.cart.init();
+        },
+
+        methods: {}
+    };
+</script>
+<style>
+</style>

+ 39 - 0
pages/cart/cart.vue

@@ -0,0 +1,39 @@
+<template>
+    <view>
+        <!-- 购物车 -->
+        <component-cart ref="cart"></component-cart>
+
+        <!-- 快捷导航 -->
+        <component-quick-nav :propIsBar="true"></component-quick-nav>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentQuickNav from "../../components/quick-nav/quick-nav";
+    import componentCart from "../../components/cart/cart";
+    export default {
+        data() {
+            return {};
+        },
+        components: {
+            componentQuickNav,
+            componentCart
+        },
+
+        onShow() {
+            // 数据加载
+            if((this.$refs.cart || null) != null) {
+                this.$refs.cart.init('cart');
+            }
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.$refs.cart.init('cart');
+        },
+
+        methods: {}
+    };
+</script>
+<style>
+</style>

+ 41 - 0
pages/common/open-setting-location/open-setting-location.css

@@ -0,0 +1,41 @@
+page {
+    background: #fbfbfb;
+}
+.open-setting-view {
+    background: hsla(0, 0%, 0%, 0.1);
+    position: fixed;
+    top: 0;
+    /*  #ifdef  H5  */
+    top: calc(88rpx + env(safe-area-inset-top));
+    /*  #endif  */
+    left: 0;
+    width: 100%;
+    height: 100%;
+    text-align: center;
+    z-index: 1000000;
+}
+.open-setting-view .content {
+    margin: 0 auto;
+    width: 360rpx;
+    height: 200rpx;
+    padding: 50rpx;
+    border-radius: 12rpx;
+    margin-top: 70%;
+    position: relative;
+}
+.open-setting-view .content button {
+    margin-top: 15rpx;
+}
+.open-setting-view .content .value {
+    margin-top: 5rpx;
+}
+.open-setting-view .content .value text {
+    font-weight: 500;
+    color: #333;
+}
+.open-setting-loding {
+    padding-top: 35%;
+}
+.open-setting-loding image {
+    margin: 0 auto;
+}

+ 118 - 0
pages/common/open-setting-location/open-setting-location.vue

@@ -0,0 +1,118 @@
+<template>
+    <view>
+        <view v-if="is_show_open_setting" class="open-setting-view">
+            <view class="content bg-white">
+                <view class="msg cr-gray">开启相应的权限服务</view>
+                <view class="value cr-base">获取[ <text>位置信息</text> ]权限</view>
+                <button type="primary" open-type="openSetting" size="mini" @opensetting="setting_callback_event">打开设置页</button>
+                <view class="tc margin-top-sm">
+                    <navigator open-type="navigateBack" class="cp cr-gray dis-inline-block" hover-class="none">返回</navigator>
+                </view>
+            </view>
+        </view>
+        <view v-else class="open-setting-loding">
+            <image :src="common_static_url+'bg-loding.gif'" class="avatar dis-block" mode="widthFix"></image>
+            <view class="tc margin-top-sm">
+                <navigator open-type="navigateBack" class="cp cr-gray dis-inline-block" hover-class="none">返回</navigator>
+            </view>
+        </view>
+        <view v-if="(error_msg || null) != null" class="cr-red margin-top-lg padding-horizontal-main">{{error_msg}}</view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+
+    var common_static_url = app.globalData.get_static_url('common');
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                params: null,
+                is_show_open_setting: false,
+                auth: 'scope.userLocation',
+                cache_key: app.globalData.data.cache_userlocation_key,
+                error_msg: null
+            };
+        },
+
+        components: {},
+        props: {},
+        onLoad: function(params) {
+            this.setData({
+                params: params
+            });
+            this.init();
+        },
+        methods: {
+            // 获取权限
+            init() {
+                // #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
+                var self = this;
+                uni.getSetting({
+                    success(res) {
+                        if (!res.authSetting[self.auth]) {
+                            uni.authorize({
+                                scope: self.auth,
+                                success(res) {
+                                    self.choose_location();
+                                },
+                                fail: res => {
+                                    self.setData({
+                                        is_show_open_setting: true
+                                    });
+                                }
+                            });
+                        } else {
+                            self.choose_location();
+                        }
+                    },
+                    fail: res => {
+                        app.globalData.showToast("请先获取授权");
+                    }
+                });
+                // #endif
+                // #ifdef MP-ALIPAY || H5 || APP
+                this.choose_location();
+                // #endif
+                // #ifdef MP-KUAISHOU
+                app.globalData.showToast('不支持地理位置选择!');
+                uni.navigateBack();
+                // #endif
+            },
+
+            // 位置服务回调方法
+            setting_callback_event(e) {
+                if (e.detail.authSetting[this.auth]) {
+                    this.setData({
+                        is_show_open_setting: false
+                    });
+                    this.choose_location();
+                }
+            },
+
+            // 打开位置服务
+            choose_location() {
+                uni.chooseLocation({
+                    success: res => {
+                        uni.setStorageSync(this.cache_key, res);
+                        setTimeout(function(){
+                            uni.navigateBack();
+                        }, 500);
+                    },
+                    fail: res => {
+                        // 取消则自动返回、则显示错误
+                        if(res.errMsg.indexOf('cancel') != -1) {
+                            uni.navigateBack();
+                        } else {
+                            this.setData({error_msg: res.errMsg});
+                            app.globalData.showToast(res.errMsg);
+                        }
+                    }
+                });
+            }
+        }
+    };
+</script>
+<style>
+    @import './open-setting-location.css';
+</style>

+ 135 - 0
pages/design/design.vue

@@ -0,0 +1,135 @@
+<template>
+    <view>
+        <view v-if="(data || null) != null">
+            <!-- 搜索 -->
+            <block v-if="(data.is_header || 0) == 1">
+                <!-- 搜索框 -->
+                <view class="padding-main bg-white">
+                    <component-search propPlaceholder="输入商品名称搜索"></component-search>
+                </view>
+            </block>
+
+            <!-- 拖拽模式、引入拖拽数据模块 -->
+            <component-layout :propData="layout_data"></component-layout>
+
+            <!-- 结尾 -->
+            <block v-if="(data.is_footer || 0) == 1">
+                <!-- 结尾 -->
+                <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+            </block>
+        </view>
+        <view v-else>
+            <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentLayout from "../../components/layout/layout";
+    import componentSearch from "../../components/search/search";
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+
+    export default {
+        data() {
+            return {
+                data_bottom_line_status: false,
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                params: null,
+                data: null,
+                layout_data: [],
+                // 自定义分享信息
+                share_info: {}
+            };
+        },
+
+        components: {
+            componentLayout,
+            componentSearch,
+            componentNoData,
+            componentBottomLine
+        },
+        props: {},
+
+        onLoad(params) {
+            this.setData({
+                params: params
+            });
+        },
+
+        onShow() {
+            this.get_data();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.get_data();
+        },
+
+        methods: {
+            // 获取数据
+            get_data() {
+                uni.request({
+                    url: app.globalData.get_request_url("index", "design"),
+                    method: 'POST',
+                    data: {
+                        "id": this.params.id || 0
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            this.setData({
+                                data: (data.data || null) != null && data.data.length != 0 ? data.data : null,
+                                layout_data: data.layout_data || [],
+                                data_list_loding_msg: '',
+                                data_list_loding_status: 0,
+                                data_bottom_line_status: true
+                            });
+
+                            if ((this.data || null) != null) {
+                                // 基础自定义分享
+                                this.setData({
+                                    share_info: {
+                                        title: this.data.seo_title || this.data.name,
+                                        desc: this.data.seo_desc,
+                                        path: '/pages/design/design',
+                                        query: 'id='+this.data.id,
+                                        img: this.data.logo
+                                    }
+                                });
+
+                                // 标题名称
+                                uni.setNavigationBarTitle({
+                                    title: this.data.name
+                                });
+                            }
+                            
+                            // 分享菜单处理
+                            app.globalData.page_share_handle(this.share_info);
+                        } else {
+                            this.setData({
+                                data_bottom_line_status: false,
+                                data_list_loding_status: 2,
+                                data_list_loding_msg: res.data.msg
+                            });
+                        }
+                    },
+                    fail: () => {
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_bottom_line_status: false,
+                            data_list_loding_status: 2,
+                            data_list_loding_msg: '服务器请求出错'
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            }
+        }
+    };
+</script>
+<style>
+</style>

+ 67 - 0
pages/error/error.vue

@@ -0,0 +1,67 @@
+<template>
+    <view>
+        <view class="content padding-horizontal-main tc">
+            <view class="margin-top-xxxl">
+                <icon type="warn" size="16" color="#f00" class="va-m" />
+                <view class="cr-red va-m dis-inline-block margin-left-sm">
+                    <block v-if="(params || null) != null && (params.msg || null) != null">{{params.msg}}</block>
+                    <block v-else>异常错误</block>
+                </view>
+            </view>
+            <view class="margin-top-xxl">
+                <button type="default" size="mini" class="bg-main br-main cr-white round text-size-sm padding-left-xxxl padding-right-xxxl padding-top-xs padding-bottom-xs margin-top-xl" @tap="back_event">返回</button>
+            </view>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import base64 from '../../common/js/lib/base64.js';
+
+    export default {
+        data() {
+            return {
+                params: null
+            };
+        },
+        components: {},
+        props: {},
+
+        // 页面加载初始化
+        onLoad(params) {
+            console.log(params);
+            if((params.msg || null) != null) {
+                params['msg'] = base64.decode(decodeURIComponent(params.msg));
+            }console.log(params);
+            this.setData({
+                params: params
+            });
+        },
+
+        // 页面显示
+        onShow() {
+            // 分享菜单处理
+            app.globalData.page_share_handle();
+        },
+
+        // 方法
+        methods: {
+            // 返回
+            back_event(e) {
+                var pages = getCurrentPages();
+                if(pages > 1) {
+                    uni.navigateBack();
+                } else {
+                    uni.switchTab({
+                        url: app.globalData.data.tabbar_pages[0]
+                    });
+                }
+            }
+        }
+    };
+</script>
+<style>
+    .content {
+        padding-top: 30%;
+    }
+</style>

+ 15 - 0
pages/extraction-address/extraction-address.css

@@ -0,0 +1,15 @@
+.address-logo {
+    width: 140rpx;
+    height: 140rpx !important;
+}
+.address .item-icon {
+    width: 30rpx;
+    height: 35rpx !important;
+}
+.address-alias {
+    padding: 0 10rpx;
+}
+.address .text {
+    line-height: 44rpx;
+    width: calc(100% - 40rpx);
+}

+ 268 - 0
pages/extraction-address/extraction-address.vue

@@ -0,0 +1,268 @@
+<template>
+    <view>
+        <view class="page">
+            <view v-if="data_list.length > 0" class="padding-main">
+                <view v-for="(item, index) in data_list" :key="index" class="item bg-white padding-main border-radius-main spacing-mb">
+                    <view @tap="address_conent_event" :data-index="index" class="oh">
+                        <view v-if="(item.logo || null) != null" class="fl oh margin-right-lg">
+                            <image class="dis-block address-logo radius" :src="item.logo" mode="widthFix"></image>
+                        </view>
+                        <view class="oh">
+                            <view class="base oh padding-bottom-main padding-top-xs">
+                                <text v-if="(item.alias || null) != null" class="address-alias br-main cr-main round margin-right-sm">{{item.alias}}</text>
+                                <text>{{item.name}}</text>
+                                <text class="fr">{{item.tel}}</text>
+                            </view>
+                            <view class="address oh padding-top-sm">
+                                <image class="item-icon fl margin-top-xs" :src="common_static_url+'map-icon.png'" mode="widthFix"></image>
+                                <view class="text fr">
+                                    {{item.province_name || ''}}{{item.city_name || ''}}{{item.county_name || ''}}{{item.address || ''}}
+                                </view>
+                            </view>
+                        </view>
+                    </view>
+                    <view v-if="((item.distance_value || null) != null && (item.distance_unit || null) != null) || ((item.lng || 0) != 0 && (item.lat || 0) != 0)" class="item-operation br-t oh padding-top-main margin-top-main">
+                        <view v-if="(item.distance_value || null) != null && (item.distance_unit || null) != null" class="fl margin-top-lg">
+                            <text class="cr-gray">距离</text>
+                            <text class="cr-base">{{item.distance_value}}</text>
+                            <text class="cr-gray">{{item.distance_unit}}</text>
+                        </view>
+                        <button v-if="(item.lng || 0) != 0 && (item.lat || 0) != 0" class="fr round bg-white cr-base br" type="default" size="mini" @tap="address_map_event" :data-index="index" hover-class="none">查看地图</button>
+                    </view>
+                </view>
+            </view>
+            <view v-else>
+                <!-- 提示信息 -->
+                <component-no-data :propStatus="data_list_loding_status"></component-no-data>
+            </view>
+
+            <!-- 结尾 -->
+            <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+        </view>
+    </view>
+</template>
+
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+
+    var common_static_url = app.globalData.get_static_url('common');
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                data_list_loding_status: 1,
+                data_bottom_line_status: false,
+                data_list: [],
+                params: null,
+                is_default: 0,
+                user_location_cache_key: app.globalData.data.cache_userlocation_key,
+                user_location: null,
+                is_first: 1,
+                home_extraction_address_position: 0
+            };
+        },
+
+        components: {
+            componentNoData,
+            componentBottomLine
+        },
+        props: {},
+
+        onLoad(params) {
+            this.setData({
+                params: params,
+                home_extraction_address_position: app.globalData.get_config('config.home_extraction_address_position', 0)
+            });
+        },
+
+        onReady: function() {
+            // 清除位置缓存信息
+            uni.removeStorage({
+                key: this.user_location_cache_key
+            });
+
+            // #ifndef MP-KUAISHOU
+            // 是否获取位置
+            if ((this.params.is_buy || 0) == 1 && this.home_extraction_address_position == 1) {
+                uni.navigateTo({
+                    url: '/pages/common/open-setting-location/open-setting-location'
+                });
+            }
+            // #endif
+        },
+
+        onShow() {
+            // #ifndef MP-KUAISHOU
+            // 是否需要选择地理位置
+            if (this.home_extraction_address_position == 1) {
+                // 首次不请求数据
+                if (this.is_first == 0) {
+                    this.user_location_init();
+                    this.init();
+                }
+            } else {
+                this.init();
+            }
+            // #endif
+            // #ifdef MP-KUAISHOU
+            this.init();
+            // #endif
+
+            this.setData({
+                is_first: 0
+            });
+            
+            // 分享菜单处理
+            app.globalData.page_share_handle();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.get_data_list();
+        },
+
+        methods: {
+            // 初始化
+            init() {
+                var user = app.globalData.get_user_info(this, "init");
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.redirectTo({
+                            url: "/pages/login/login?event_callback=init"
+                        });
+                        return false;
+                    } else {
+                        // 获取数据
+                        this.get_data_list();
+                    }
+                } else {
+                    this.setData({
+                        data_list_loding_status: 0,
+                        data_bottom_line_status: false
+                    });
+                }
+            },
+
+            // 地址信息初始化
+            user_location_init() {
+                var result = uni.getStorageSync(this.user_location_cache_key) || null;
+                var data = null;
+                if (result != null) {
+                    data = {
+                        name: result.name || null,
+                        address: result.address || null,
+                        lat: result.latitude || null,
+                        lng: result.longitude || null
+                    };
+                }
+                this.setData({
+                    user_location: data
+                });
+            },
+
+            // 获取数据列表
+            get_data_list() {
+                // 加载loding
+                uni.showLoading({
+                    title: '加载中...'
+                });
+                this.setData({
+                    data_list_loding_status: 1
+                });
+
+                // 获取数据
+                var data = this.params || {};
+
+                // 是否有坐标
+                if ((this.user_location || null) != null) {
+                    data['lng'] = this.user_location.lng;
+                    data['lat'] = this.user_location.lat;
+                }
+
+                // 请求接口
+                uni.request({
+                    url: app.globalData.get_request_url("extraction", "useraddress"),
+                    method: 'POST',
+                    data: data,
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            if (res.data.data.length > 0) {
+                                // 获取当前默认地址
+                                var is_default = 0;
+                                for (var i in res.data.data) {
+                                    if (res.data.data[i]['is_default'] == 1) {
+                                        is_default = res.data.data[i]['id'];
+                                    }
+                                }
+
+                                // 设置数据
+                                this.setData({
+                                    data_list: res.data.data,
+                                    is_default: is_default,
+                                    data_list_loding_status: 3,
+                                    data_bottom_line_status: true
+                                });
+                            } else {
+                                this.setData({
+                                    data_list_loding_status: 0
+                                });
+                            }
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0
+                            });
+                            if (app.globalData.is_login_check(res.data, this, 'get_data_list')) {
+                                app.globalData.showToast(res.data.msg);
+                            }
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 地图查看
+            address_map_event(e) {
+                var index = e.currentTarget.dataset.index || 0;
+                var data = this.data_list[index] || null;
+                if (data == null) {
+                    app.globalData.showToast("地址有误");
+                    return false;
+                }
+
+                // 打开地图
+                var name = data.alias || data.name || '';
+                var address = (data.province_name || '') + (data.city_name || '') + (data.county_name || '') + (data.address || '');
+                app.globalData.open_location(data.lng, data.lat, name, address);
+            },
+
+            // 地址内容事件
+            address_conent_event(e) {
+                var index = e.currentTarget.dataset.index || 0;
+                var is_back = this.params.is_back || 0;
+                if (is_back == 1) {
+                    uni.setStorage({
+                        key: app.globalData.data.cache_buy_user_address_select_key,
+                        data: this.data_list[index]
+                    });
+                    uni.navigateBack();
+                }
+            }
+        }
+    };
+</script>
+<style>
+    @import './extraction-address.css';
+</style>

+ 206 - 0
pages/goods-category/goods-category.css

@@ -0,0 +1,206 @@
+/**
+ * 导航搜索、内容区域
+ */
+.nav-search {
+    padding-right: 250rpx;
+    /* #ifdef MP-ALIPAY */
+    padding-right: 255rpx;
+    /* #endif */
+    /* #ifdef H5 || MP-TOUTIAO || APP */
+    padding-right: 20rpx;
+    /* #endif */
+    padding-bottom: 10px;
+}
+.category-content {
+    height: calc(100vh - 68px);
+    /* #ifdef H5 || APP */
+    height: calc(100vh - 98px) !important;
+    /* #endif */
+}
+
+/**
+* 左侧导航
+*/
+.left-content-actual {
+    padding-bottom: 120rpx;
+}
+.left-nav {
+    width: 200rpx;
+}
+.left-nav .item {
+    height: 80rpx;
+    line-height: 80rpx;
+    padding: 0 10rpx;
+    border-left: 3px solid #fff;
+    border-right: 3px solid #fff;
+}
+.left-nav .item:not(:last-child) {
+    border-bottom: 1px solid #f1f1f1 !important;
+}
+.nav-active {
+    background: #f5f5f5;
+    border-width: 0 0 0 3px;
+    border-right: 3px solid #f5f5f5 !important;
+    font-weight: bold;
+}
+
+/**
+*  右侧内容
+*/
+.right-container {
+    width: calc(100% - 200rpx);
+    height: 100%;
+    top: 0;
+    right: 0;
+    background: #f5f5f5;
+}
+.content-item {
+    display: -webkit-inline-box;
+    width: calc(33.33% - 20rpx);
+}
+.content-item .content {
+    padding: 15rpx 0;
+}
+.content-item .text {
+    font-size: 28rpx;
+    line-height: 46rpx;
+}
+.content-item .icon {
+    width: 100%;
+    height: 120rpx;
+}
+.model-one .content-item:nth-child(3n) {
+    border-right: 0;
+}
+
+
+/**
+ * 商品列表模式
+ */
+.category-content.goods-model {
+    padding-top: 150rpx;
+}
+.top-nav {
+    height: 150rpx;
+    top: 0;
+    left: 0;
+    z-index: 2;
+}
+.top-nav .icon-content {
+    width: 80rpx;
+    height: 80rpx;
+    padding: 1px;
+}
+.top-nav .item {
+    height: 180rpx;
+    padding: 0 15rpx;
+}
+.right-content-actual {
+    padding-bottom: 105rpx;
+}
+.goods-right-content {
+    width: calc(100% - 200rpx);
+    height: calc(100% - 150rpx);
+    top: 150rpx;
+    right: 0;
+    background: #f5f5f5;
+}
+.goods-right-content .word-list {
+    position: sticky;
+    top: 0;
+    right: 0;
+    background: #f5f5f5;
+    z-index: 1;
+    padding: 0px 1px 20rpx 1px;
+}
+.goods-list .goods-img {
+    width: 190rpx;
+    height: 190rpx !important;
+    border-top-right-radius: 0 !important;
+    border-bottom-right-radius: 0 !important;
+}
+.goods-list .goods-base {
+    width: calc(100% - 220rpx);
+}
+.goods-list .goods-base-content {
+    min-height: 100rpx;
+}
+.goods-list .goods-base .simple-desc {
+    line-height: 30rpx;
+    min-height: 30rpx;
+    max-height: 58rpx;
+}
+.goods-list .goods-base .sales-price {
+    width: calc(100% - 320rpx);
+    left: 210rpx;
+    bottom: 10rpx;
+}
+.goods-list .goods-base .buy-opt {
+    right: 10rpx;
+    bottom: 6rpx;
+}
+.goods-list .goods-base .buy-number {
+    min-width: 32rpx;
+}
+
+/**
+ * 底部导航
+ */
+.botton-nav {
+    width: calc(100% - 40rpx);
+    left: auto;
+    bottom: 20rpx;
+    line-height: 80rpx;
+    z-index: 6;
+    max-width: calc(800px - 40rpx);
+    margin-left: 20rpx;
+}
+.botton-nav .cart .badge-icon {
+    top: -20rpx;
+    right: -2rpx;
+}
+.botton-nav .cart-total-price {
+    width: calc(100% - 260rpx);
+}
+.botton-nav button {
+    top: 0;
+    right: 0;
+    line-height: 88rpx;
+    height: 88rpx;
+    border: 0;
+    /* #ifdef MP-QQ */
+    padding-top: 0;
+    padding-bottom: 0;
+    /* #endif */
+}
+
+/**
+ * 购物车
+ */
+.cart-mask {
+    left: 0;
+    top: 0;
+    background: rgb(0, 0, 0, 0.6);
+    z-index: 5;
+}
+.cart-content {
+    left: auto;
+    bottom: 130rpx;
+    width: calc(100% - 40rpx);
+    z-index: 6;
+    max-width: calc(800px - 40rpx);
+    margin-left: 20rpx;
+}
+.cart-content .cart-list {
+    max-height: 60vh;
+}
+.cart-content .cart-list .goods-img {
+    width: 120rpx;
+    height: 120rpx !important;
+}
+.cart-content .cart-list .goods-base {
+    width: calc(100% - 140rpx);
+}
+.cart-content .cart-list .goods-base-content {
+    min-height: 60rpx;
+}

文件差異過大導致無法顯示
+ 1064 - 0
pages/goods-category/goods-category.vue


+ 53 - 0
pages/goods-comment/goods-comment.css

@@ -0,0 +1,53 @@
+/*
+ * 评分
+ */
+.score-container .score {
+    width: 180rpx;
+    border-right: 1px solid #eee;
+}
+.score-container .score .value {
+    font-weight: bold;
+    font-size: 60rpx;
+    line-height: 60rpx;
+    margin-top: 10rpx;
+}
+.progress {
+    overflow: hidden;
+    height: 40rpx;
+    margin-top: 35rpx;
+    background-color: #eee;
+    width: calc(100% - 200rpx);
+}
+.progress .cr-gray {
+    font-size: 24rpx;
+    line-height: 40rpx;
+}
+.progress-bar {
+    float: left;
+    width: 0;
+    height: 100%;
+    font-size: 24rpx;
+    line-height: 40rpx;
+    color: #fff;
+    text-align: center;
+    background-color: #0e90d2;
+}
+.progress-bar-danger {
+    background-color: #dd514c;
+}
+.progress-bar-warning {
+    background-color: #F37B1D;
+}
+.progress-bar-secondary {
+    background-color: #3bb4f2;
+}
+.progress-bar-success {
+    background-color: #5eb95e;
+}
+
+/*
+ * 列表
+ */
+.scroll-box {
+    height: calc(100vh - 148rpx);
+}

+ 252 - 0
pages/goods-comment/goods-comment.vue

@@ -0,0 +1,252 @@
+<template>
+    <view>
+        <!-- 评分 -->
+        <view v-if="goods_score != null" class="score-container oh padding-main">
+            <view class="score fl tc">
+                <view class="cr-base">综合评分</view>
+                <view class="value cr-main">{{goods_score.avg || '0.0'}}</view>
+            </view>
+            <view class="progress fr tc border-radius-main">
+                <block v-if="goods_score.avg > 0">
+                    <block v-for="(item, index) in goods_score.rating" :key="index">
+                        <view v-if="item.portion > 0" :class="'progress-bar ' + progress_class[index]" :style="'width: ' + item.portion + '%;'">{{item.name}}</view>
+                    </block>
+                </block>
+                <text v-else class="cr-gray">暂无评分</text>
+            </view>
+        </view>
+
+        <!-- 列表 -->
+        <scroll-view :scroll-y="true" class="scroll-box" @scrolltolower="scroll_lower" lower-threshold="60">
+            <view class="padding-horizontal-main goods-comment">
+                <view v-for="(item, index) in data_list" :key="index" class="goods-comment-item padding-main border-radius-main bg-white spacing-mb">
+                    <view class="oh nav br-b padding-bottom-sm">
+                        <image class="avatar dis-block fl" :src="item.user.avatar || static_url+'default-user.png'" mode="aspectFit"></image>
+                        <view class="base-nav fr">
+                            <text class="va-m">{{item.user.user_name_view}}</text>
+                            <view class="dis-inline-block va-m margin-left-sm">
+                                <uni-rate :value="item.rating" :readonly="true" :is-fill="false" :size="14" />
+                            </view>
+                            <view class="fr">
+                                <text class="cr-grey">{{item.add_time_date}}</text>
+                            </view>
+                        </view>
+                    </view>
+                    <view class="base-content oh padding-sm">
+                        <view class="content cr-base text-size-sm">{{item.content}}</view>
+                        <view v-if="(item.images || null) != null && item.images.length > 0" class="images oh margin-top-lg">
+                            <block v-for="(iv, ix) in item.images" :key="ix">
+                                <image class="br radius" @tap="comment_images_show_event" :data-index="index" :data-ix="ix" :src="iv" mode="aspectFit"></image>
+                            </block>
+                        </view>
+                        <view v-if="(item.msg || null) != null" class="spec cr-grey margin-top-lg">{{item.msg}}</view>
+                        <view v-if="item.is_reply == 1 && (item.reply || null) != null" class="reply br-t-dashed margin-top-lg padding-top-lg text-size-sm">
+                            <text class="cr-base">管理员回复:</text>
+                            <text class="reply-desc cr-main-pair">{{item.reply}}</text>
+                        </view>
+                    </view>
+                </view>
+
+                <!-- 提示信息 -->
+                <component-no-data :propStatus="data_list_loding_status"></component-no-data>
+
+                <!-- 结尾 -->
+                <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+            </view>
+        </scroll-view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+
+    var static_url = app.globalData.get_static_url('home');
+    export default {
+        data() {
+            return {
+                static_url: static_url,
+                data_list_loding_status: 1,
+                data_bottom_line_status: false,
+                data_list: [],
+                data_page_total: 0,
+                data_page: 1,
+                goods_score: null,
+                params: null,
+                progress_class: ['progress-bar-danger', 'progress-bar-warning', 'progress-bar-secondary', '', 'progress-bar-success'],
+            };
+        },
+        components: {
+            componentNoData,
+            componentBottomLine
+        },
+        props: {},
+
+        onLoad(params) {
+            //params['goods_id']=9;
+            this.setData({
+                params: params
+            });
+        },
+        
+        onShow() {
+            this.init();
+            
+            // 分享菜单处理
+            app.globalData.page_share_handle();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.setData({
+                data_page: 1
+            });
+            this.get_data_list(1);
+        },
+
+        methods: {
+            // 初始化
+            init() {
+                // 获取数据
+                this.get_goods_score();
+                this.get_data_list();
+            },
+
+            // 获取商品评分
+            get_goods_score() {
+                uni.request({
+                    url: app.globalData.get_request_url("goodsscore", "goods"),
+                    method: 'POST',
+                    data: {
+                        goods_id: this.params.goods_id
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        if (res.data.code == 0) {
+                            this.setData({
+                                goods_score: res.data.data || null
+                            });
+                        } else {
+                            if (res.data.code != -400) {
+                                app.globalData.showToast(res.data.msg);
+                            }
+                        }
+                    },
+                    fail: () => {
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 获取数据列表
+            get_data_list(is_mandatory) {
+                // 参数校验
+                if ((this.params.goods_id || null) == null) {
+                    uni.stopPullDownRefresh();
+                    this.setData({
+                        data_bottom_line_status: false,
+                        data_list_loding_status: 2
+                    });
+                } else {
+                    var self = this;
+                    // 分页是否还有数据
+                    if ((is_mandatory || 0) == 0) {
+                        if (this.data_bottom_line_status == true) {
+                            uni.stopPullDownRefresh();
+                            return false;
+                        }
+                    }
+
+                    uni.showLoading({
+                        title: '加载中...'
+                    });
+                    this.setData({
+                        data_list_loding_status: 1
+                    });
+                    uni.request({
+                        url: app.globalData.get_request_url("comments", "goods"),
+                        method: 'POST',
+                        data: {
+                            goods_id: this.params.goods_id,
+                            page: this.data_page
+                        },
+                        dataType: 'json',
+                        success: res => {
+                            uni.hideLoading();
+                            uni.stopPullDownRefresh();
+
+                            if (res.data.code == 0) {
+                                if (res.data.data.data.length > 0) {
+                                    if (this.data_page <= 1) {
+                                        var temp_data_list = res.data.data.data;
+                                    } else {
+                                        var temp_data_list = this.data_list || [];
+                                        var temp_data = res.data.data.data;
+                                        for (var i in temp_data) {
+                                            temp_data_list.push(temp_data[i]);
+                                        }
+                                    }
+                                    this.setData({
+                                        data_list: temp_data_list,
+                                        data_total: res.data.data.total,
+                                        data_page_total: res.data.data.page_total,
+                                        data_list_loding_status: 3,
+                                        data_page: this.data_page + 1
+                                    });
+                                    
+                                    // 是否还有数据
+                                    this.setData({
+                                        data_bottom_line_status: (this.data_page > 1 && this.data_page > this.data_page_total)
+                                    });
+                                } else {
+                                    this.setData({
+                                        data_list_loding_status: 0
+                                    });
+                                    if (this.data_page <= 1) {
+                                        this.setData({
+                                            data_list: [],
+                                            data_bottom_line_status: false
+                                        });
+                                    }
+                                }
+                            } else {
+                                this.setData({
+                                    data_list_loding_status: 0
+                                });
+                                if (app.globalData.is_login_check(res.data, this, 'get_data_list')) {
+                                    app.globalData.showToast(res.data.msg);
+                                }
+                            }
+                        },
+                        fail: () => {
+                            uni.hideLoading();
+                            uni.stopPullDownRefresh();
+                            this.setData({
+                                data_list_loding_status: 2
+                            });
+                            app.globalData.showToast('服务器请求出错');
+                        }
+                    });
+                }
+            },
+
+            // 滚动加载
+            scroll_lower(e) {
+                this.get_data_list();
+            },
+
+            // 评价图片预览
+            comment_images_show_event(e) {
+                var index = e.currentTarget.dataset.index;
+                var ix = e.currentTarget.dataset.ix;
+                uni.previewImage({
+                    current: this.data_list[index]['images'][ix],
+                    urls: this.data_list[index]['images']
+                });
+            }
+        }
+    };
+</script>
+<style>
+    @import './goods-comment.css';
+</style>

+ 591 - 0
pages/goods-detail/goods-detail.css

@@ -0,0 +1,591 @@
+.page {
+    padding-bottom: 110rpx;
+}
+
+/**
+ * 顶部导航内容
+ */
+.top-nav-left-icon,
+.top-nav-right-icon {
+    top: 28px;
+    z-index: 11;
+}
+.top-nav-left-icon {
+    left: auto;
+    margin-left: 20rpx;
+}
+.top-nav-right-icon {
+    right: 20rpx;
+}
+.top-nav-left-icon .icon,
+.top-nav-right-icon .icon {
+    background: rgb(255 255 255 / 70%);
+    width: 25px;
+    height: 25px;
+    line-height: 25px;
+    display: block;
+    float: left;
+    text-align: center;
+    padding: 3px;
+}
+.top-nav {
+    position: absolute;
+    bottom: 24rpx;
+    width: calc(100% - 40rpx);
+    /* #ifdef H5 || APP */
+    bottom: 6px;
+    padding-bottom: 5px;
+    /* #endif */
+}
+.top-nav-content {
+    margin: 0 auto;
+    width: 310rpx;
+    margin-left: calc(50% - 170rpx);
+}
+.top-nav-content text {
+    font-size: 32rpx;
+    /* #ifdef H5 || APP */
+    font-size: 14px;
+    /* #endif */
+}
+.top-nav-content text:not(:last-child) {
+    margin-right: 30rpx;
+}
+.top-nav-content .nav-active {
+    font-weight: 700;
+    padding-bottom: 5rpx;
+    padding-bottom: 5rpx;
+    border-style: solid;
+    border-width: 0 0 2px 0;
+    font-size: 34rpx;
+    /* #ifdef H5 || APP */
+    font-size: 16px;
+    /* #endif */
+}
+
+/**
+ * 顶部更多导航
+ */
+.nav-more-view {
+    position: fixed;
+    z-index: 20;
+    top: 62px;
+    left: 20rpx;
+}
+.nav-more-view .triangle {
+    width: 0;
+    height: 0;
+    border-width: 0 5px 5px 5px;
+    border-style: solid;
+    border-color: transparent transparent rgb(0 0 0 / 0.7) transparent;
+    top: -5px;
+    left: calc(20rpx + 42px);
+}
+.nav-more-view .content {
+    background: rgb(0 0 0 / 0.7);
+}
+.nav-more-view .content .item {
+    font-size: 12px;
+}
+.nav-more-view .content .item:not(:last-child) {
+    border-bottom: 1px solid #585858;
+}
+
+/**
+ * 相册
+ */
+.goods-photo .swiper,
+.goods-photo .swiper-item {
+    height: 55vh !important;
+    display: block;
+}
+
+/**
+ * 购买操作导航
+ */
+.goods-buy-nav {
+    position: fixed;
+    left: 0;
+    bottom: 0;
+    height: 100rpx;
+    z-index: 2;
+}
+.goods-buy-nav .bus-items {
+    width: 45%;
+}
+.goods-buy-nav .bus-items .item  {
+    position: relative;
+}
+.goods-buy-nav .bus-items-1 .item {
+    width: 100%;
+}
+.goods-buy-nav .bus-items-2 .item {
+    width: 50%;
+}
+.goods-buy-nav .bus-items-3 .item {
+    width: 33.33%;
+}
+.goods-buy-nav .bus-items-4 .item {
+    width: 25%;
+}
+.goods-buy-nav .bus-items-5 .item {
+    width: 20%;
+}
+.goods-buy-nav .btn-items {
+    width: calc(55% - 10rpx);
+    padding: 15rpx 0;
+}
+.goods-buy-nav .bus-items,
+.goods-buy-nav .btn-items {
+    height: 100rpx;
+}
+.goods-buy-nav .btn-items .item {
+    height: 70rpx;
+    line-height: 70rpx;
+    font-size: 24rpx;
+    padding: 0 10rpx;
+    margin-right: 15rpx;
+    position: relative;
+}
+.goods-buy-nav image {
+    width: 40rpx;
+    height: 40rpx;
+    margin: 10rpx 0 5rpx 0;
+}
+.goods-buy-nav .dis-block {
+    margin-top: -10rpx;
+}
+.goods-buy-nav .badge-icon {
+    position: absolute;
+    top: 2rpx;
+    left: calc(50% + 25rpx);
+    z-index: 1;
+}
+.goods-buy-nav-btn-number-0 .item,
+.goods-buy-nav-btn-number-1 .item {
+    width: calc(100% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-2 .item {
+    width: calc(50% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-3 .item {
+    width: calc(33.33% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-4 .item {
+    width: calc(25% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-5 .item {
+    width: calc(20% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-6 .item {
+    width: calc(16.66% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-7 .item {
+    width: calc(14.28% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-8 .item {
+    width: calc(12.5% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-9 .item {
+    width: calc(11.11% - 15rpx) !important;
+}
+.goods-buy-nav-btn-number-10 .item {
+    width: calc(10% - 15rpx) !important;
+}
+
+/**
+ * 商品基础
+ */
+.goods-base-content .goods-title-content {
+    position: relative;
+    min-height: 86rpx;
+}
+.goods-base-content .goods-title {
+    font-size: 36rpx;
+    line-height: 52rpx;
+    font-weight: bold;
+    width: calc(100% - 100rpx);
+}
+.goods-base-content .goods-share {
+    top: calc(50% - 40rpx);
+    right: 20rpx;
+}
+.goods-base-content .goods-share image {
+    width: 50rpx;
+    height: 50rpx;
+}
+.goods-base-content .base-grid view {
+    width: calc(33.33% - 1px);
+}
+
+/**
+* 视频
+*/
+.goods-video {
+    width: 100%;
+    top: 0;
+    left: 0;
+    z-index: 1;
+}
+.goods-video video {
+    width: 100%;
+    height: 55vh !important;
+}
+.goods-video-submit {
+    left: 50rpx;
+    top: auto;
+    bottom: 60rpx;
+    z-index: 2;
+}
+.goods-video-submit image {
+    width: 80rpx;
+    height: 80rpx !important;
+}
+
+/**
+ * 基础价格信息
+ */
+.goods-base-price {
+    height: 145rpx;
+    overflow: hidden;
+}
+.price-content,
+.countdown-content {
+    box-sizing: border-box;
+    position: relative;
+    height: 100%;
+}
+.price-content .price-icon {
+    margin-right: 5rpx;
+    padding: 1px 5px;
+    background: #FF5722;
+    color: #fff;
+}
+.price-content .sales-price {
+    font-size: 42rpx;
+}
+
+/**
+ * app独立内容
+ */
+.goods-detail-app .content-items view {
+    padding: 15rpx 10rpx;
+    line-height: 44rpx;
+    font-size: 32rpx;
+}
+
+/**
+ * 价格信息与秒杀结合
+ */
+.goods-base-price-countdown .price-content {
+    background: #f9534e;
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    width: 60%;
+    float: left;
+}
+.goods-base-price-countdown .price-icon { 
+    margin-right: 0;
+    padding: 0px 10rpx;
+    border: 1px solid #fff;
+    background: transparent;
+    position: absolute;
+    right: 20rpx;
+    bottom: 20rpx;
+    font-size: 24rpx;
+}
+.goods-base-price-countdown .sales-price {
+    color: #fff;
+}
+.goods-base-price-countdown .original-price {
+    color: #ffcece;
+}
+.goods-base-price-countdown .countdown-content {
+    background: #e84742;
+    width: 40%;
+}
+.countdown-content .time-title {
+    font-size: 38rpx;
+    margin-bottom: 10rpx;
+}
+
+/**
+ * 栏目右侧内容
+ */
+.column-right-view {
+    width: calc(100% - 190rpx);
+    margin-right: 50rpx;
+}
+
+/*
+* 商品参数
+*/
+.parameters-base .content-item .item {
+    color: #666;
+}
+.goods-parameters .content-item .item {
+    padding: 8rpx 10rpx;
+    width: calc(50% - 20rpx);
+}
+.goods-parameters .content-item .item .name {
+    margin-right: 10rpx;
+}
+.goods-parameters .content-item .item:nth-child(2n-1) {
+    float: left;
+}
+.goods-parameters .content-item .item:nth-child(2n) {
+    float: right;
+}
+/**
+ * 商品参数弹窗
+ */
+.popup-params-container {
+    max-height: 80vh;
+    overflow-y: scroll;
+    overflow-x: hidden;
+}
+.popup-params-container .item .name {
+	width: 220rpx;
+}
+.popup-params-container .item .value {
+	width: calc(100% - 240rpx);
+}
+
+/*
+* icon
+*/
+.goods-icon-container .item {
+    border: 1px solid #3bb4f2;
+    color: #3bb4f2;
+    padding: 4rpx 16rpx;
+}
+
+/*
+* 面板
+*/
+.goods-panel-container {
+    background: #fffbfc;
+    color: #d2354c;
+}
+.goods-panel-container view {
+    padding: 15rpx 0;
+}
+.goods-panel-container view:not(:first-child) {
+    border-top: 1px dashed #fff1f2;
+}
+
+/**
+* 购买记录 - 插件
+*/
+.plugins-salerecords-tips,
+.plugins-salerecords-tips-top-left,
+.plugins-salerecords-tips-top-right,
+.plugins-salerecords-tips-bottom-left,
+.plugins-salerecords-tips-bottom-right,
+.plugins-salerecords-tips-top-center,
+.plugins-salerecords-tips-bottom-center {
+    position: fixed;
+    left: calc(50% - 170rpx);
+    top: 50%;
+    background: rgb(0 0 0 / 60%);
+    border-radius: 60rpx;
+    padding: 8rpx 20rpx;
+    color: #fff;
+    z-index: 50;
+    -webkit-box-shadow: 0 8px 10px rgb(0 0 0 / 20%);
+    -moz-box-shadow: 0 8px 10px rgba(0, 0, 0, 0.2);
+    box-shadow: 0 8px 10px rgb(0 0 0 / 20%);
+}
+.plugins-salerecords-tips image,
+.plugins-salerecords-tips-top-left image,
+.plugins-salerecords-tips-top-right image,
+.plugins-salerecords-tips-bottom-left image,
+.plugins-salerecords-tips-bottom-right image,
+.plugins-salerecords-tips-top-center image,
+.plugins-salerecords-tips-bottom-center image {
+    width: 50rpx;
+    height: 50rpx;
+    border-radius: 50%;
+}
+.plugins-salerecords-tips-top-left {
+    left: 5%;
+    top: 13%;
+}
+.plugins-salerecords-tips-top-right {
+    right: 5%;
+    top: 13%;
+    left: auto;
+}
+.plugins-salerecords-tips-top-center {
+    top: 13%;
+}
+/* #ifdef MP-ALIPAY  */
+.plugins-salerecords-tips-top-left {
+    top: 5%;
+}
+.plugins-salerecords-tips-top-right {
+    top: 5%;
+}
+.plugins-salerecords-tips-top-center {
+    top: 5%;
+}
+/* #endif  */
+.plugins-salerecords-tips-bottom-left {
+    left: 5%;
+    bottom: 10%;
+    top: auto;
+}
+.plugins-salerecords-tips-bottom-right {
+    right: 5%;
+    bottom: 10%;
+    left: auto;
+    top: auto;
+}
+.plugins-salerecords-tips-bottom-center {
+    bottom: 10%;
+    top: auto;
+}
+
+/*
+* 优惠劵 - 插件
+*/
+.plugins-coupon-container-view .item {
+    padding: 5rpx 15rpx;
+    display: inline-table;
+}
+.plugins-coupon-container-view .item:not(:last-child) {
+    margin-right: 10rpx;
+}
+.plugins-coupon-container {
+    max-height: 50vh;
+    overflow-y: scroll;
+    overflow-x: hidden;
+    margin-top: 20rpx;
+}
+.plugins-coupon-container .v-left {
+    padding: 20rpx 10rpx 20rpx 20rpx;
+}
+.plugins-coupon-container .item:not(:last-child) {
+    margin-bottom: 20rpx;
+}
+.plugins-coupon-container .item,
+.plugins-coupon-container .v-right,
+.plugins-coupon-container .v-right .circle {
+    height: 175rpx;
+}
+.plugins-coupon-container .v-left .base .price {
+    font-size: 46rpx;
+}
+
+/**
+ * 批发 - 插件
+ */
+.plugins-wholesale-container-view .item {
+    padding: 5rpx 15rpx;
+    color: #ff6633;
+    border: 1px dashed #ff9e7e;
+    display: inline-table;
+}
+.plugins-wholesale-container-view .item:not(:last-child) {
+    margin-right: 10rpx;
+}
+.plugins-wholesale-container {
+    max-height: 50vh;
+    overflow-y: scroll;
+    overflow-x: hidden;
+    margin-top: 20rpx;
+}
+.plugins-wholesale-container .item {
+    width: calc(50% - 50rpx);
+    margin-bottom: 20rpx;
+}
+.plugins-wholesale-container .item:nth-child(2n) {
+    margin-left: 10rpx;
+}
+.plugins-wholesale-container .item:nth-child(2n+1) {
+    margin-right: 10rpx;
+}
+.plugins-wholesale-container .spec-tips {
+    color: #ffbf00;
+    border: 1px solid #333;
+    background: #333;
+    padding: 2rpx 10rpx;
+    top: 22rpx;
+    left: 20rpx;
+}
+
+/**
+ * 标签 - 插件
+ */
+.plugins-label navigator:not(:last-child) {
+    margin-right: 20rpx;
+}
+.plugins-label navigator {
+    margin-bottom: 20rpx;
+}
+.plugins-label-top-left,
+.plugins-label-top-center,
+.plugins-label-top-right {
+    top: calc(var(--status-bar-height) + 130rpx);
+}
+.plugins-label-text {
+    padding: 20rpx 20rpx 0 20rpx;
+}
+.plugins-label-bottom-left,
+.plugins-label-bottom-center,
+.plugins-label-bottom-right {
+    bottom: 0;
+}
+
+/**
+ * 智能工具 - 插件
+ */
+.plugins-intellectstools-base-bottom-container .notice-content {
+    padding: 10rpx 20rpx;
+    background: #fff1f0;
+    border-color: #ffe2e0;
+    color: #dd514c;
+}
+.plugins-intellectstools-content-top-container {
+    background: #daeeff;
+    color: #2b6e8f;
+    border: 1px solid #c9e9ff;
+}
+.plugins-intellectstools-content-top-container .panel-content .item:first-child {
+    padding-top: 0 !important;
+}
+.plugins-intellectstools-content-top-container .panel-title,
+.plugins-intellectstools-content-top-container .panel-content .item:not(:last-child) {
+    border-bottom: 1px solid #c8e4fb !important;
+}
+
+/**
+ * 门店 - 插件
+ */
+.plugins-realstore-popup {
+    max-height: 80vh;
+    overflow-y: scroll;
+    overflow-x: hidden;
+    margin-top: 20rpx;
+}
+
+/**
+ * 商品服务 - 插件
+ */
+.plugins-goodsservice-view-container .content {
+    width: calc(100% - 30rpx);
+}
+.plugins-goodsservice-view-container .item image {
+    width: 32rpx;
+    height: 32rpx !important;
+}
+.plugins-goodsservice-container .item image {
+    width: 70rpx;
+    height: 70rpx !important;
+}
+.plugins-goodsservice-container .item .left {
+    width: 80rpx;
+}
+.plugins-goodsservice-container .item .right {
+    width: calc(100% - 90rpx);
+}

文件差異過大導致無法顯示
+ 1407 - 0
pages/goods-detail/goods-detail.vue


+ 137 - 0
pages/goods-search/goods-search.css

@@ -0,0 +1,137 @@
+/**
+* 排序导航
+*/
+.nav-sort-content .item {
+    height: 80rpx;
+    line-height: 80rpx;
+    width: calc(20% - 33.33rpx);
+}
+.nav-sort-content .item .icon {
+    width: 30rpx;
+    height: 30rpx !important;
+}
+.screening-submit {
+    width: 50rpx;
+    height: 50rpx !important;
+    top: 15rpx;
+    right: 80rpx;
+}
+.show-type-submit {
+    width: 50rpx;
+    height: 50rpx !important;
+    top: 15rpx;
+    right: 16rpx;
+}
+
+/**
+* 商品列表
+*/
+.data-list .item {
+    width: calc(50% - 10rpx);
+}
+.data-list .item:nth-child(2n) {
+    float: right;
+}
+.data-list .item:nth-child(2n+1) {
+    float: left;
+}
+.data-list .item .goods-img {
+    width: 100%;
+    height: 380rpx !important;
+}
+
+/**
+* 条件
+*/
+.search-map {
+    height: calc(100vh - 160rpx);
+    overflow-y: scroll;
+    overflow-x: hidden;
+}
+.search-map,
+.search-map .search-submit {
+    width: 660rpx;
+}
+.map-keywords {
+    padding: 0 20rpx;
+    line-height: 66rpx;
+    height: 66rpx;
+    font-size: 26rpx;
+    box-sizing: border-box;
+}
+.map-nav text:first-child {
+    font-weight: bold;
+}
+.map-nav .arrow-bottom {
+    top: 0;
+    right: 10rpx;
+    padding-right: 46rpx;
+}
+.map-item {
+    line-height: 66rpx;
+}
+.map-content {
+    line-height: 60rpx;
+}
+.map-content .item {
+    margin-bottom: 20rpx;
+}
+.map-content .item:not(:last-child) {
+    margin-right: 20rpx;
+}
+.map-text-item .item,
+.map-images-text-item .item {
+    padding: 0 15rpx;
+    border: 1px solid transparent;
+}
+.map-images-text-item .item {
+    vertical-align: middle;
+    border: 1px solid #eee;
+    width: 150rpx;
+    height: 72rpx;
+    line-height: 72rpx;
+}
+.map-images-text-item .item image {
+    width: 150rpx;
+    height: calc(100% - 8rpx);
+    display: block;
+    margin: 0 auto;
+    margin-top: 4rpx;
+}
+.search-map .search-submit {
+    left: 0;
+    bottom: 0;
+}
+.search-map .search-submit button {
+    height: 80rpx;
+    line-height: 80rpx;
+}
+
+/**
+* 品牌基础信息
+*/
+.brand-info {
+    height: 160rpx;
+}
+.brand-info image,
+.brand-info .info-logo-empty {
+    width: 300rpx;
+    height: 130rpx;
+    border: 1px solid #eee;
+}
+.brand-info .info-logo-empty {
+    line-height: 130rpx;
+    font-weight: bold;
+}
+.brand-info .info-right {
+    width: calc(100% - 330rpx);
+}
+.brand-info .info-name {
+    line-height: 56rpx;
+    font-weight: bold;
+}
+.brand-info .info-desc {
+    font-size: 28rpx;
+    line-height: 40rpx;
+    min-height: 80rpx;
+}

+ 568 - 0
pages/goods-search/goods-search.vue

@@ -0,0 +1,568 @@
+<template>
+    <view>
+        <!-- 排序 -->
+        <view class="nav-sort bg-white oh pr">
+            <view class="nav-sort-content">
+                <block v-for="(item, index) in search_nav_sort_list" :key="index">
+                    <view class="item tc fl cp" :data-index="index" @tap="nav_sort_event">
+                        <text class="cr-base va-m">{{item.name}}</text>
+                        <image v-if="(item.icon || null) != null" class="icon va-m" :src="common_static_url + 'sort-' + item.icon + '-icon.png'" mode="aspectFill"></image>
+                    </view>
+                </block>
+            </view>
+            <image class="screening-submit pa cp" :src="common_static_url+'search-submit-icon.png'" mode="aspectFill" @tap="popup_form_event_show"></image>
+			<image class="show-type-submit pa cp" :src="common_static_url+'show-'+(data_show_type_value == 0 ? 'grid' : 'list')+'-icon.png'" mode="aspectFill" @tap="data_show_type_event"></image>
+        </view>
+
+        <!-- 列表 -->
+        <scroll-view :scroll-y="true" class="scroll-box scroll-box-ece-nav" @scrolltolower="scroll_lower" lower-threshold="60">
+            <view v-if="data_list.length > 0" class="padding-horizontal-main padding-top-main oh">
+				<component-goods-list :propData="{style_type: data_show_type_value, goods_list: data_list}" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol"></component-goods-list>
+            </view>
+            <view v-else>
+                <!-- 提示信息 -->
+                <component-no-data :propStatus="data_list_loding_status"></component-no-data>
+            </view>
+
+            <!-- 结尾 -->
+            <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+        </scroll-view>
+
+        <!-- 筛选条件 popup -->
+        <component-popup :propShow="is_show_popup_form" propPosition="left" @onclose="popup_form_event_close">
+            <form @submit="form_submit_event" class="popup-form oh">
+                <view class="search-map padding-main bg-base">
+                    <view class="padding-main border-radius-main bg-white">
+                        <view class="map-item map-base br-b">
+                            <text>筛选出</text>
+                            <text class="cr-main"> {{data_total}} </text>
+                            <text>条数据</text>
+                            <text class="fr cr-red cp" @tap="map_remove_event">清除</text>
+                        </view>
+                        <!-- 搜索关键字 -->
+                        <input type="text" confirm-type="search" placeholder="其实搜索很简单^_^ !" name="wd" :value="(post_data.wd || '')" class="map-keywords wh-auto round bg-base margin-top-lg" placeholder-class="cr-grey">
+                    </view>
+
+                    <!-- 品牌 -->
+                    <view v-if="((search_map_list.brand_list || null) != null && search_map_list.brand_list.length > 0) || ((search_map_info.brand || null) != null)" class="map-item padding-horizontal-main padding-top-main border-radius-main bg-white spacing-mt">
+                        <view class="map-nav br-b pr">
+                            <text>品牌</text>
+                            <text class="arrow-bottom pa cr-grey cp" v-if="search_map_list.brand_list.length > 3" @tap="more_event" data-value="brand_list">更多</text>
+                        </view>
+                        <view v-if="(search_map_info.brand || null) != null && (params.brand || null) != null" class="map-content brand-info oh margin-top-lg">
+                            <image v-if="(search_map_info.brand.logo || null) != null" :src="search_map_info.brand.logo" mode="aspectFit" class="fl"></image>
+                            <view v-else class="info-logo-empty tc fl">{{search_map_info.brand.name}}</view>
+                            <view class="info-right fr">
+                                <view v-if="(search_map_info.brand.logo || null) != null" class="info-name">{{search_map_info.brand.name}}</view>
+                                <view v-if="(search_map_info.brand.describe || null) != null" class="info-desc multi-text cr-grey">{{search_map_info.brand.describe}}</view>
+                            </view>
+                        </view>
+                        <view v-else class="map-content map-images-text-item map-brand-container oh margin-top-lg" :style="'height:' + map_fields_list.brand_list.height + ';'">
+                            <block v-for="(item, index) in search_map_list.brand_list" :key="index">
+                                <view :class="'item fl cr-base radius cp single-text tc ' + (item.active == 1 ? 'cr-main br-main' : '')" @tap="map_item_event" :data-index="index" data-field="brand_list">
+                                    <image v-if="(item.logo || null) != null" :src="item.logo" mode="aspectFit"></image>
+                                    <text v-else>{{item.name}}</text>
+                                </view>
+                            </block>
+                        </view>
+                    </view>
+
+                    <!-- 分类 -->
+                    <view v-if="(search_map_list.category_list || null) != null && search_map_list.category_list.length > 0" class="map-item padding-horizontal-main padding-top-main border-radius-main bg-white spacing-mt">
+                        <view class="map-nav pr br-b">
+                            <text>分类</text>
+                            <text class="arrow-bottom pa cr-grey cp" v-if="search_map_list.category_list.length > 3" @tap="more_event" data-value="category_list">更多</text>
+                        </view>
+                        <view class="map-content map-text-item map-category-container oh margin-top-lg" :style="'height:' + map_fields_list.category_list.height + ';'">
+                            <block v-for="(item, index) in search_map_list.category_list" :key="index">
+                                <view :class="'item fl cr-base radius cp ' + (item.active == 1 ? 'cr-main br-main' : '')" @tap="map_item_event" :data-index="index" data-field="category_list">{{item.name}}</view>
+                            </block>
+                        </view>
+                    </view>
+
+                    <!-- 价格 -->
+                    <view v-if="(search_map_list.screening_price_list || null) != null && search_map_list.screening_price_list.length > 0" class="map-item padding-horizontal-main padding-top-main border-radius-main bg-white spacing-mt">
+                        <view class="map-nav br-b pr">
+                            <text>价格</text>
+                            <text class="arrow-bottom pa cr-grey cp" v-if="search_map_list.screening_price_list.length > 3" @tap="more_event" data-value="screening_price_list">更多</text>
+                        </view>
+                        <view class="map-content map-text-item screening-price-container oh margin-top-lg" :style="'height:' + map_fields_list.screening_price_list.height + ';'">
+                            <block v-for="(item, index) in search_map_list.screening_price_list" :key="index">
+                                <view :class="'item fl cr-base radius cp ' + (item.active == 1 ? 'cr-main br-main' : '')" @tap="map_item_event" :data-index="index" data-field="screening_price_list">{{item.name}}</view>
+                            </block>
+                        </view>
+                    </view>
+
+                    <!-- 属性 -->
+                    <view v-if="(search_map_list.goods_params_list || null) != null && search_map_list.goods_params_list.length > 0" class="map-item padding-horizontal-main padding-top-main border-radius-main bg-white spacing-mt">
+                        <view class="map-nav br-b pr">
+                            <text>属性</text>
+                            <text class="arrow-bottom pa cr-grey cp" v-if="search_map_list.goods_params_list.length > 3" @tap="more_event" data-value="goods_params_list">更多</text>
+                        </view>
+                        <view class="map-content map-text-item goods-params-container oh margin-top-lg" :style="'height:' + map_fields_list.goods_params_list.height + ';'">
+                            <block v-for="(item, index) in search_map_list.goods_params_list" :key="index">
+                                <view :class="'item fl cr-base radius cp ' + (item.active == 1 ? 'cr-main br-main' : '')" @tap="map_item_event" :data-index="index" data-field="goods_params_list">{{item.value}}</view>
+                            </block>
+                        </view>
+                    </view>
+
+                    <!-- 规格 -->
+                    <view v-if="(search_map_list.goods_spec_list || null) != null && search_map_list.goods_spec_list.length > 0" class="map-item padding-horizontal-main padding-top-main border-radius-main bg-white spacing-mt">
+                        <view class="map-nav br-b pr">
+                            <text>规格</text>
+                            <text class="arrow-bottom pa cr-grey cp" v-if="search_map_list.goods_spec_list.length > 3" @tap="more_event" data-value="goods_spec_list">更多</text>
+                        </view>
+                        <view class="map-content map-text-item goods-spec-container oh margin-top-lg" :style="'height:' + map_fields_list.goods_spec_list.height + ';'">
+                            <block v-for="(item, index) in search_map_list.goods_spec_list" :key="index">
+                                <view :class="'item fl cr-base radius cp ' + (item.active == 1 ? 'cr-main br-main' : '')" @tap="map_item_event" :data-index="index" data-field="goods_spec_list">{{item.value}}</view>
+                            </block>
+                        </view>
+                    </view>
+
+                    <view class="search-submit padding-main pa">
+                        <button form-type="submit" class="bg-main cr-white text-size wh-auto round" :disabled="popup_form_loading_status" hover-class="none">确认</button>
+                    </view>
+                </view>
+            </form>
+        </component-popup>
+
+        <!-- 快捷导航 -->
+        <component-quick-nav></component-quick-nav>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentQuickNav from "../../components/quick-nav/quick-nav";
+    import componentPopup from "../../components/popup/popup";
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+	import componentGoodsList from "../../components/goods-list/goods-list";
+
+    var common_static_url = app.globalData.get_static_url('common');
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                data_list_loding_status: 1,
+                data_bottom_line_status: false,
+                data_list: [],
+                data_total: 0,
+                data_page_total: 0,
+                data_page: 1,
+                params: null,
+                post_data: {},
+                is_show_popup_form: false,
+                popup_form_loading_status: false,
+                // 自定义分享信息
+                share_info: {},
+                // 排序导航
+                search_nav_sort_index: 0,
+                search_nav_sort_list: [
+                    { name: "综合", field: "default", sort: "asc", "icon": null },
+                    { name: "销量", field: "sales_count", sort: "asc", "icon": "default" },
+                    { name: "热度", field: "access_count", sort: "asc", "icon": "default" },
+                    { name: "价格", field: "min_price", sort: "asc", "icon": "default" },
+                    { name: "最新", field: "id", sort: "asc", "icon": "default" }
+                ],
+                // 数据展示样式(0图文、1九方格)
+                data_show_type_value: 1,
+                // 基础配置
+                currency_symbol: app.globalData.data.currency_symbol,
+                // 搜素条件
+                search_map_list: {
+                    brand_list: [],
+                    category_list: [],
+                    screening_price_list: [],
+                    goods_params_list: [],
+                    goods_spec_list: []
+                },
+                search_map_info: [],
+                map_fields_list: {
+                    brand_list: {height: "100rpx", default: "100rpx", form_key: "brand_ids"},
+                    category_list: {height: "82rpx", default: "82rpx", form_key: "category_ids"},
+                    screening_price_list: {height: "82rpx", default: "82rpx", form_key: "screening_price_values"},
+                    goods_params_list: {height: "82rpx", default: "82rpx", form_key: "goods_params_values"},
+                    goods_spec_list: {height: "82rpx", default: "82rpx", form_key: "goods_spec_values"}
+                },
+                // 标签插件
+                plugins_label_data: null
+            };
+        },
+
+        components: {
+            componentQuickNav,
+            componentPopup,
+            componentNoData,
+            componentBottomLine,
+			componentGoodsList
+        },
+        props: {},
+
+        onLoad(params) {
+            this.setData({
+                params: params,
+                post_data: {
+                    wd: params.keywords || ''
+                }
+            });
+
+            // 数据加载
+            this.init();
+        },
+
+        onShow() {            
+            // 初始化配置
+            this.init_config();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.setData({
+                data_page: 1
+            });
+            this.get_data_list(1);
+        },
+
+        methods: {
+            // 初始化配置
+            init_config(status) {
+                if ((status || false) == true) {
+                    this.setData({
+                        currency_symbol: app.globalData.get_config('currency_symbol')
+                    });
+                } else {
+                    app.globalData.is_config(this, 'init_config');
+                }
+            },
+
+            // 获取数据
+            init() {
+                // 获取数据
+                this.get_data();
+            },
+
+            // 搜索
+            search_event() {
+                this.setData({
+                    data_list: [],
+                    data_page: 1
+                });
+                this.get_data_list(1);
+            },
+            
+            // 初始化数据
+            get_data() {
+                uni.showLoading({
+                    title: '加载中...',
+                    mask: true
+                });
+                var post_data = this.request_map_handle();
+                uni.request({
+                    url: app.globalData.get_request_url("index", "search"),
+                    method: 'POST',
+                    data: post_data,
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            this.setData({
+                                search_map_info: data.search_map_info || [],
+                                search_map_list: {
+                                    brand_list: data.brand_list || [],
+                                    category_list: data.category_list || [],
+                                    screening_price_list: data.screening_price_list || [],
+                                    goods_params_list: data.goods_params_list || [],
+                                    goods_spec_list: data.goods_spec_list || []
+                                },
+                                plugins_label_data: (data.plugins_label_data || null) == null || (data.plugins_label_data.base || null) == null || (data.plugins_label_data.data || null) == null || data.plugins_label_data.data.length <= 0 ? null : data.plugins_label_data
+                            });
+                            
+                            // 获取数据列表
+                            this.get_data_list(1);
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0
+                            });
+                            app.globalData.showToast(res.data.msg);
+                        }
+
+                        // 基础自定义分享
+                        var category_id = this.params.category_id || 0;
+                        var brand = this.params.brand || 0;
+                        var keywords = this.params.keywords || '';
+                        this.setData({
+                            share_info: {
+                                path: '/pages/goods-search/goods-search',
+                                query: 'category_id=' + category_id + '&brand=' + brand + '&keywords=' + keywords
+                            }
+                        });
+
+                        // 分享菜单处理
+                        app.globalData.page_share_handle(this.share_info);
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 获取数据列表
+            get_data_list(is_mandatory) {
+                // 分页是否还有数据
+                if ((is_mandatory || 0) == 0) {
+                    if (this.data_bottom_line_status == true) {
+                        uni.stopPullDownRefresh();
+                        return false;
+                    }
+                }
+                
+                // 获取数据
+                uni.showLoading({
+                    title: '加载中...',
+                    mask: true
+                });
+                var post_data = this.request_map_handle();
+                uni.request({
+                    url: app.globalData.get_request_url("datalist", "search"),
+                    method: 'POST',
+                    data: post_data,
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;                            
+                            if (data.data.length > 0) {
+                                if (this.data_page <= 1) {
+                                    var temp_data_list = data.data;
+                                } else {
+                                    var temp_data_list = this.data_list || [];
+                                    var temp_data = data.data;
+                                    for (var i in temp_data) {
+                                        temp_data_list.push(temp_data[i]);
+                                    }
+                                }
+                                this.setData({
+                                    data_list: temp_data_list,
+                                    data_total: data.total,
+                                    data_page_total: data.page_total,
+                                    data_list_loding_status: 3,
+                                    data_page: this.data_page + 1
+                                });
+
+                                // 是否还有数据
+                                this.setData({
+                                    data_bottom_line_status: (this.data_page > 1 && this.data_page > this.data_page_total)
+                                });
+                            } else {
+                                this.setData({
+                                    data_list_loding_status: 0,
+                                    data_total: 0
+                                });
+                                if (this.data_page <= 1) {
+                                    this.setData({
+                                        data_list: [],
+                                        data_bottom_line_status: false
+                                    });
+                                }
+                            }
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0
+                            });
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 搜索条件处理
+            request_map_handle() {
+                var params = this.params;
+                var post_data = this.post_data;
+                post_data['page'] = this.data_page;
+
+                // 指定分类、品牌
+                post_data['category_id'] = params['category_id'] || 0;
+                post_data['brand'] = params['brand'] || 0;
+
+                // 搜索条件
+                var temp_field = this.map_fields_list;
+                var temp_list = this.search_map_list;
+                for (var i in temp_field) {
+                    if (temp_list[i] != null != null && temp_list[i].length > 0) {
+                        var temp = {};
+                        var index = 0;
+                        for (var k in temp_list[i]) {
+                            if ((temp_list[i][k]['active'] || 0) == 1) {
+                                switch (i) {
+                                    // 价格
+                                    case 'screening_price_list':
+                                        temp[index] = temp_list[i][k]['min_price'] + '-' + temp_list[i][k]['max_price'];
+                                        break;
+                                    // 属性、规格
+                                    case 'goods_params_list':
+                                    case 'goods_spec_list':
+                                        temp[index] = temp_list[i][k]['value'];
+                                        break;
+                                    // 默认取值id
+                                    default:
+                                        temp[index] = temp_list[i][k]['id'];
+                                }
+                                index++;
+                            }
+                        }
+                        post_data[temp_field[i]['form_key']] = app.globalData.get_length(temp) > 0 ? JSON.stringify(temp) : '';
+                    }
+                }
+
+                // 排序
+                var temp_index = this.search_nav_sort_index;
+                var temp_search_nav_sort = this.search_nav_sort_list;
+                post_data['order_by_type'] = temp_search_nav_sort[temp_index]['sort'] == 'desc' ? 'asc' : 'desc';
+                post_data['order_by_field'] = temp_search_nav_sort[temp_index]['field'];
+
+                return post_data;
+            },
+
+            // 滚动加载
+            scroll_lower(e) {
+                this.get_data_list();
+            },
+
+            // 搜索条件
+            form_submit_event(e) {
+                this.setData({
+                    post_data: e.detail.value,
+                    data_page: 1
+                });
+                this.popup_form_event_close();
+                this.get_data_list(1);
+            },
+
+            // 筛选条件关闭
+            popup_form_event_close(e) {
+                this.setData({
+                    is_show_popup_form: false
+                });
+            },
+
+            // 筛选条件开启
+            popup_form_event_show(e) {
+                this.setData({
+                    is_show_popup_form: true
+                });
+            },
+
+            // 排序事件
+            nav_sort_event(e) {
+                var index = e.currentTarget.dataset.index || 0;
+                var temp_search_nav_sort = this.search_nav_sort_list;
+                var temp_sort = temp_search_nav_sort[index]['sort'] == 'desc' ? 'asc' : 'desc';
+                for (var i in temp_search_nav_sort) {
+                    if (i != index) {
+                        if (temp_search_nav_sort[i]['icon'] != null) {
+                            temp_search_nav_sort[i]['icon'] = 'default';
+                        }
+                        temp_search_nav_sort[i]['sort'] = 'desc';
+                    }
+                }
+                temp_search_nav_sort[index]['sort'] = temp_sort;
+                if (temp_search_nav_sort[index]['icon'] != null) {
+                    temp_search_nav_sort[index]['icon'] = temp_sort;
+                }
+
+                this.setData({
+                    search_nav_sort_index: index,
+                    search_nav_sort_list: temp_search_nav_sort,
+                    data_page: 1
+                });
+                this.get_data_list(1);
+            },
+
+            // 条件-更多数据展示事件
+            more_event(e) {
+                var value = e.currentTarget.dataset.value || null;
+                var temp_more = this.map_fields_list;
+                if (value != null && (temp_more[value] || null) != null) {
+                    temp_more[value]['height'] = temp_more[value]['height'] == 'auto' ? temp_more[value]['default'] : 'auto';
+                    this.setData({
+                        map_fields_list: temp_more
+                    });
+                }
+            },
+
+            // 条件-选择事件
+            map_item_event(e) {
+                var index = e.currentTarget.dataset.index;
+                var field = e.currentTarget.dataset.field;
+                var temp_list = this.search_map_list;                
+                if ((temp_list[field] || null) != null && (temp_list[field][index] || null) != null) {
+                    temp_list[field][index]['active'] = (temp_list[field][index]['active'] || 0) == 0 ? 1 : 0;
+                    this.setData({
+                        search_map_list: temp_list
+                    });
+                }
+            },
+
+            // 条件-清空
+            map_remove_event(e) {
+                var temp_list = this.search_map_list;
+                var temp_post = this.post_data;
+
+                // 关键字
+                temp_post['wd'] = '';
+
+                // 品牌、分类、价格、属性、规格
+                for (var i in temp_list) {
+                    if((temp_list[i] || null) != null && temp_list[i].length > 0) {
+                        for(var k in temp_list[i]) {
+                            temp_list[i][k]['active'] = 0;
+                        }
+                    }
+                }
+
+                // 排序导航
+                var temp_search_nav_sort = this.search_nav_sort_list;
+                for (var i in temp_search_nav_sort) {
+                    temp_search_nav_sort[i]['sort'] = 'asc';
+                    temp_search_nav_sort[i]['icon'] = (temp_search_nav_sort[i]['field'] == 'default') ? null : 'default';
+                }
+
+                // 关闭弹窗、分页恢复1页、重新获取数据
+                this.setData({
+                    search_map_list: temp_list,
+                    post_data: temp_post,
+                    is_show_popup_form: false,
+                    search_nav_sort_list: temp_search_nav_sort,
+                    search_nav_sort_index: 0,
+                    data_page: 1
+                });
+                this.get_data_list(1);
+            },
+
+            // 数据展示类型
+            data_show_type_event(e) {
+                this.setData({data_show_type_value: this.data_show_type_value == 0 ? 1 : 0});
+            }
+        }
+    };
+</script>
+<style>
+    @import './goods-search.css';
+</style>

+ 186 - 0
pages/index/index.css

@@ -0,0 +1,186 @@
+/**
+ * 顶部内容
+ */
+.home-top-nav-content {
+    background-repeat: no-repeat;
+    background-size: 100% auto;
+    min-height: calc(var(--status-bar-height) + 130rpx);
+    /* #ifdef H5 */
+    min-height: calc(var(--status-bar-height) + 160rpx);
+    /* #endif */
+    padding-top: calc(var(--status-bar-height) + 8px);
+}
+.home-top-nav-logo {
+    text-align: left;
+    padding: 2px 250rpx 0 20rpx;
+    height: 37px;
+    /* #ifdef H5 || MP-TOUTIAO || APP */
+    padding-top: 0;
+    /* #endif */
+}
+.home-top-nav-logo-image {
+    width: 240rpx;
+    height: 70rpx !important;
+}
+.home-top-nav-logo-title {
+    font-weight: bold;
+    font-size: 42rpx;
+    /* #ifdef H5 || MP-TOUTIAO || APP */
+    font-size: 24px;
+    /* #endif */
+}
+
+/**
+ * 右侧图标导航
+ */
+/* #ifdef H5 || MP-TOUTIAO || APP */
+.nav-top-right-icon {
+    top: -34px;
+    right: 28rpx;
+    z-index: 12;
+    line-height: 28px;
+    /* #ifdef MP-TOUTIAO */
+    top: 2px;
+    /* #endif */
+}
+.nav-top-right-icon .item:not(:last-child) {
+    margin-right: 20rpx;
+}
+.nav-top-right-icon .badge-icon {
+    top: -10px;
+    right: 2px;
+}
+/* #endif */
+
+/**
+ * 搜索
+ */
+.search-fixed-seat {
+    padding-top: 70rpx;
+	/* #ifdef MP-TOUTIAO */
+	padding-top: 60rpx;
+	/* #endif */
+}
+.search-content-fixed {
+    position: fixed !important;
+    top: 0;
+    z-index: 11;
+    padding-bottom: 20rpx;
+    width: 100%;
+    background-repeat: no-repeat;
+    background-size: 100% auto;
+    padding-top: 25px;
+    /* #ifdef H5 || APP */
+    padding-top: 15rpx !important;
+    padding-bottom: 15rpx !important;
+    /* #endif */
+}
+/* #ifdef H5 || MP-TOUTIAO || APP */
+.search-content-fixed .nav-top-right-icon {
+    top: 9px !important;
+}
+/* #endif */
+
+/**
+ * 轮播
+ */
+.banner-content {
+    margin-top: 26rpx;
+}
+
+/**
+ * 推荐文章
+ */
+.article-list .new-icon {
+    width: 130rpx !important;
+    height: 42rpx !important;
+}
+.article-list .right-content {
+    width: calc(100% - 150rpx);
+}
+.article-list .right-content swiper {
+    height: 40rpx;
+}
+
+/*
+ * 限时秒杀 - 插件
+ */
+.seckill .goods-list swiper {
+    height: 435rpx !important;
+}
+.seckill .goods-list .item .goods-img {
+    width: 100%;
+    height: 240rpx;
+}
+.seckill .goods-list .goods-base .icon {
+    right: 20rpx;
+    bottom: 13rpx;
+}
+
+/**
+ * 购买记录 - 插件
+ */
+.plugins-salerecords swiper {
+    height: 506rpx;
+}
+.plugins-salerecords swiper-item {
+    border-bottom: 1px solid #f7f7f7;
+}
+.plugins-salerecords image {
+    width: 40rpx !important;
+    height: 40rpx !important;
+    border-radius: 50%;
+}
+.plugins-salerecords .item-content {
+    width: 24%;
+}
+.plugins-salerecords .item-content:nth-child(1) {
+    width: 36%;
+}
+.plugins-salerecords .item-content:nth-child(2) {
+    width: 40%;
+}
+
+/**
+ * 标签 - 秒杀单独修改样式
+ */
+.seckill .plugins-label-bottom-left,
+.seckill .plugins-label-bottom-center,
+.seckill .plugins-label-bottom-right {
+    bottom: calc(100% - 240rpx);
+}
+
+/**
+ * 首页中间广告- 插件
+ */
+.plugins-homemiddleadv .item {
+    width: calc(50% - 10rpx);
+}
+.plugins-homemiddleadv .item:nth-of-type(2n + 1) {
+    float: left;
+}
+.plugins-homemiddleadv .item:nth-of-type(2n) {
+    float: right;
+}
+
+/**
+ * 弹屏广告 - 插件
+ */
+.plugins-popupscreen {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 20;
+    background-color: rgb(0 0 0 / 0.7);
+}
+.plugins-popupscreen .close {
+    right: 10%;
+    top: 0;
+    z-index: 1;
+}
+.plugins-popupscreen .content {
+    margin-top: calc(50vh - 200rpx) !important;
+}
+.plugins-popupscreen .content image {
+    width: 600rpx;
+}

+ 557 - 0
pages/index/index.vue

@@ -0,0 +1,557 @@
+<template>
+    <view>
+        <view :class="((plugins_mourning_data || 0) == 1 ? ' grayscale' : '')+(is_single_page == 1 ? ' single-page-top' : '')">
+            <!-- 顶部内容 -->
+            <view v-if="load_status == 1" class="home-top-nav-content" :style="top_content_style">
+                <!-- logo/标题 -->
+                <!-- #ifndef MP-TOUTIAO -->
+                <view class="home-top-nav-logo">
+                    <block v-if="is_logo_use_text == 0 && (application_logo || null) != null">
+                        <image :src="application_logo" mode="aspectFit" class="home-top-nav-logo-image"></image>
+                    </block>
+                    <block v-else>
+                        <view class="home-top-nav-logo-title cr-white single-text">{{application_title}}</view>
+                    </block>
+                </view>
+                <!-- #endif -->
+
+                <!-- 搜索 -->
+                <view v-if="search_is_fixed == 1" class="search-fixed-seat"></view>
+                <view v-if="load_status == 1" :class="'pr '+(search_is_fixed == 1 ? 'search-content-fixed bg-main' : '')" :style="search_is_fixed == 1 ? top_content_style : ''">
+                    <view v-if="common_app_is_enable_search == 1" :style="search_style">
+                        <view class="margin-horizontal-main">
+                            <component-search propPlaceholder="输入商品名称搜索" propBgColor="#fff"></component-search>
+                        </view>
+                    </view>
+
+                    <!-- #ifdef H5 || MP-TOUTIAO || APP -->
+                    <!-- 右上角icon列表 -->
+                    <view v-if="(right_icon_list || null) != null && right_icon_list.length > 0" class="nav-top-right-icon pa">
+                        <block v-for="(item,index) in right_icon_list">
+                            <view class="item dis-inline-block cp" :data-value="item.url || ''" @tap="url_event">
+                                <uni-icons :type="item.icon" size="32rpx" color="#f1f1f1"></uni-icons>
+                                <view v-if="(item.badge || null) != null" class="badge-icon pa">
+                                    <component-badge :propNumber="item.badge"></component-badge>
+                                </view>
+                            </view>
+                        </block>
+                    </view>
+                    <!-- #endif -->
+                </view>
+
+                <!-- 轮播 -->
+                <view class="banner-content padding-horizontal-main" v-if="banner_list.length > 0">
+                    <component-banner :propData="banner_list"></component-banner>
+                </view>
+            </view>
+
+            <!-- 内容 -->
+            <view class="content padding-horizontal-main">
+                <!-- 导航 -->
+                <view v-if="navigation.length > 0">
+                    <component-icon-nav :propData="navigation"></component-icon-nav>
+                </view>
+
+                <!-- 商城公告 -->
+                <view class="notice-content spacing-mb" v-if="load_status == 1 && (common_shop_notice || null) != null">{{common_shop_notice}}</view>
+
+                <!-- 推荐文章 -->
+                <view v-if="article_list.length > 0" class="article-list padding-main border-radius-main oh bg-white spacing-mb">
+                    <image :src="static_url+'new-icon.png'" mode="aspectFit" class="new-icon va-m fl cp" data-value="/pages/article-category/article-category" @tap="url_event"></image>
+                    <view class="right-content fr va-m">
+                        <swiper :vertical="true" :autoplay="true" :circular="true" display-multiple-items="1" interval="3000">
+                            <block v-for="(item, index) in article_list" :key="index">
+                                <swiper-item class="single-text">
+                                    <text class="cr-base text-size-sm cp" :data-value="item.category_url" @tap="url_event">[{{item.article_category_name}}]</text>
+                                    <text class="cr-base text-size-sm margin-left-xs cp" :style="(item.title_color || null) != null ? 'color:'+item.title_color+' !important;' : ''" :data-value="item.url" @tap="url_event">{{item.title}}</text>
+                                </swiper-item>
+                            </block>
+                        </swiper>
+                    </view>
+                </view>
+
+                <!-- 按照插件顺序渲染插件数据 -->
+                <block v-if="plugins_sort_list.length > 0">
+                    <block v-for="(pv, pi) in plugins_sort_list" :key="pi">
+                        <!-- 首页中间广告 - 插件 -->
+                        <view v-if="pv.plugins == 'homemiddleadv' && (plugins_homemiddleadv_data || null) != null && plugins_homemiddleadv_data.length > 0" class="plugins-homemiddleadv oh">
+                            <view v-for="(item, index) in plugins_homemiddleadv_data" :key="index" class="item border-radius-main oh cp spacing-mb" :data-value="item.url || ''" @tap="url_event">
+                                <image class="dis-block wh-auto border-radius-main" :src="item.images" mode="widthFix"></image>
+                            </view>
+                        </view>
+
+                        <!-- 限时秒杀 - 插件 -->
+                        <view v-if="pv.plugins == 'seckill' && plugins_seckill_is_valid == 1 && plugins_seckill_data.goods.length > 0" class="seckill border-radius-main padding-horizontal-main spacing-mb" :style="plugins_seckill_bg">
+                            <view class="spacing-nav-title">
+                                <text class="text-wrapper va-m">限时秒杀</text>
+                                <view class="dis-inline-block va-m margin-left-sm">
+                                    <component-countdown :propHour="plugins_seckill_data.time.hours" :propMinute="plugins_seckill_data.time.minutes" :propSecond="plugins_seckill_data.time.seconds"></component-countdown>
+                                </view>
+                                <navigator url="/pages/plugins/seckill/index/index" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr">更多</navigator>
+                            </view>
+                            <component-goods-list :propData="{style_type: 2, goods_list: plugins_seckill_data.goods}" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol" :propIsCartParaCurve="true"></component-goods-list>
+                        </view>
+
+                        <!-- 活动配置-楼层顶部 - 插件 -->
+                        <block v-if="pv.plugins == 'activity' && (plugins_activity_data || null) != null">
+                            <component-activity-list :propConfig="plugins_activity_data.base" :propData="plugins_activity_data.data" propLocation="0" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol" :propIsCartParaCurve="true"></component-activity-list>
+                        </block>
+
+                        <!-- 门店 - 插件 -->
+                        <block v-if="pv.plugins == 'realstore' && (plugins_realstore_data || null) != null">
+                            <view class="spacing-nav-title">
+                                <text class="text-wrapper">{{plugins_realstore_data.base.home_data_list_title || '最新门店'}}</text>
+                                <navigator url="/pages/plugins/realstore/search/search" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr">更多</navigator>
+                            </view>
+                            <component-realstore-list :propDataList="plugins_realstore_data.data" :propFavorUser="plugins_realstore_data.favor_user"></component-realstore-list>
+                        </block>
+
+                        <!-- 多商户 - 插件 -->
+                        <block v-if="pv.plugins == 'shop' && (plugins_shop_data || null) != null">
+                            <view class="spacing-nav-title">
+                                <text class="text-wrapper">{{plugins_shop_data.base.home_data_list_title || '最新商家'}}</text>
+                                <navigator url="/pages/plugins/shop/index/index" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr">更多</navigator>
+                            </view>
+                            <component-shop-list :propConfig="plugins_shop_data.base" :propDataList="plugins_shop_data.data"></component-shop-list>
+                        </block>
+
+                        <!-- 博客-楼层顶部 - 插件 -->
+                        <block v-if="pv.plugins == 'blog' && (plugins_blog_data || null) != null">
+                            <component-blog-list :propConfig="plugins_blog_data.base" :propData="plugins_blog_data.data" propLocation="0"></component-blog-list>
+                        </block>
+                    </block>
+                </block>
+
+                <!-- 楼层数据 -->
+                <block v-if="(data_list || null) != null && data_list.length > 0">
+                    <!-- 数据模式0,1自动+手动、2拖拽 -->
+                    <block v-if="home_index_floor_data_type == 2">
+                        <!-- 引入拖拽数据模块 -->
+                        <component-layout :propData="data_list"></component-layout>
+                    </block>
+                    <block v-else>
+                        <!-- 自动+手动 -->
+                        <view v-for="(floor, index) in data_list" :key="index" class="floor">
+                            <view class="spacing-nav-title">
+                                <text class="text-wrapper" :style="'color:'+(floor.bg_color || '#333')+';'">{{floor.name}}</text>
+                                <text v-if="(floor.describe || null) != null" class="vice-name margin-left-lg cr-gray">{{floor.describe}}</text>
+                                <navigator :url="'/pages/goods-search/goods-search?category_id=' + floor.id" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr">更多</navigator>
+                            </view>
+                            <view class="floor-list wh-auto oh pr">
+                                <view v-if="floor.items.length > 0" class="word-list scroll-view-horizontal margin-bottom-lg">
+                                    <scroll-view :scroll-x="true">
+                                        <block v-for="(icv, icx) in floor.items" :key="icx">
+                                            <navigator :url="'/pages/goods-search/goods-search?category_id=' + icv.id" hover-class="none" class="word-icon dis-inline-block bg-main-light text-size-xs cr-main round padding-top-xs padding-bottom-xs padding-left padding-right">{{icv.name}}</navigator>
+                                        </block>
+                                    </scroll-view>
+                                </view>
+                                <block v-if="floor.goods.length > 0">
+									<component-goods-list :propData="{style_type: 1, goods_list: floor.goods}" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol" :propIsCartParaCurve="true"></component-goods-list>
+                                </block>
+                            </view>
+                        </view>
+                    </block>
+                </block>
+
+                <!-- 按照插件顺序渲染插件数据 -->
+                <block v-if="plugins_sort_list.length > 0">
+                    <block v-for="(pv, pi) in plugins_sort_list" :key="pi">
+                        <!-- 活动配置-楼层底部 - 插件 -->
+                        <block v-if="pv.plugins == 'activity' && (plugins_activity_data || null) != null">
+                            <component-activity-list :propConfig="plugins_activity_data.base" :propData="plugins_activity_data.data" propLocation="1" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol"></component-activity-list>
+                        </block>
+
+                        <!-- 博客-楼层底部 - 插件 -->
+                        <block v-if="pv.plugins == 'blog' && (plugins_blog_data || null) != null">
+                            <component-blog-list :propConfig="plugins_blog_data.base" :propData="plugins_blog_data.data" propLocation="1"></component-blog-list>
+                        </block>
+
+                        <!--- 底部购买记录 - 插件 -->
+                        <view v-if="pv.plugins == 'salerecords' && (plugins_salerecords_data || null) != null && (plugins_salerecords_data.data || null) != null && plugins_salerecords_data.data.length > 0" class="spacing-mb plugins-salerecords">
+                            <view class="spacing-nav-title">
+                                <text class="text-wrapper">{{plugins_salerecords_data.base.home_bottom_title || '最新购买'}}</text>
+                                <text v-if="(plugins_salerecords_data.base || null) != null && (plugins_salerecords_data.base.home_bottom_desc || null) != null" class="vice-name margin-left-lg cr-gray">{{plugins_salerecords_data.base.home_bottom_desc}}</text>
+                            </view>
+                            <view class="bg-white padding-horizontal-main border-radius-main oh">
+                                <swiper :vertical="true" :autoplay="true" :circular="true" :display-multiple-items="plugins_salerecords_data.data.length < 6 ? plugins_salerecords_data.data.length : 6" interval="3000" :style="plugins_salerecords_data.data.length < 6 ? 'height:'+(plugins_salerecords_data.data.length*84.33)+'rpx;' : ''">
+                                    <block v-for="(item, index) in plugins_salerecords_data.data" :key="index">
+                                        <swiper-item>
+                                            <view class="item oh padding-vertical-main">
+                                                <view class="item-content single-text fl">
+                                                    <image mode="widthFix" :src="item.user.avatar" class="va-m br"></image>
+                                                    <text class="margin-left-sm">{{item.user.user_name_view}}</text>
+                                                    <text v-if="(item.user.province || null) != null"><text class="padding-left-xs padding-right-xs">-</text>{{item.user.province}}</text>
+                                                </view>
+                                                <view class="item-content fl">
+                                                    <navigator :url="item.goods_url" hover-class="none" class="single-text">
+                                                        <image mode="widthFix" :src="item.images" class="va-m br"></image>
+                                                        <text class="margin-left-sm single-text">{{item.title}}</text>
+                                                    </navigator>
+                                                </view>
+                                                <view class="item-content single-text fr tr cr-gray padding-top-xs">{{item.add_time}}</view>
+                                            </view>
+                                        </swiper-item>
+                                    </block>
+                                </swiper>
+                            </view>
+                        </view>
+                    </block>
+                </block>
+
+                <!-- 弹屏广告 - 插件 -->
+                <view v-if="(plugins_popupscreen_data || null) != null && plugins_popupscreen_status == 1" class="plugins-popupscreen wh-auto ht-auto">
+                    <view class="content pr">
+                        <icon type="clear" size="20" class="close pa cp" @tap.stop="plugins_popupscreen_close_event"></icon>
+                        <image class="dis-block auto" :src="plugins_popupscreen_data.images" mode="widthFix" :data-value="plugins_popupscreen_data.images_url || ''" @tap="url_event"></image>
+                    </view>
+                </view>
+
+                <!-- 留言 -->
+                <view v-if="load_status == 1 && common_app_is_enable_answer == 1" class="bg-white border-radius-main oh spacing-mt">
+                    <navigator url="/pages/answer-form/answer-form" hover-class="none">
+                        <image mode="widthFix" :src="static_url+'answer-form.jpg'" class="wh-auto border-radius-main"></image>
+                    </navigator>
+                </view>
+            </view>
+            
+            <!-- 提示信息 -->
+            <block v-if="load_status == 0">
+                <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+            </block>
+            
+            <!-- 结尾 -->
+            <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+            
+            <!-- 版权信息 -->
+            <view v-if="load_status == 1">
+                <component-copyright></component-copyright>
+            </view>
+        </view>
+
+        <!-- 在线客服 -->
+        <component-online-service :propIsNav="true" :propIsBar="true" :propIsGrayscale="plugins_mourning_data || 0"></component-online-service>
+        
+        <!-- 快捷导航 -->
+        <component-quick-nav :propIsNav="true" :propIsBar="true" :propIsGrayscale="plugins_mourning_data || 0"></component-quick-nav>
+    </view>
+</template>
+
+<script>
+    const app = getApp();
+    import componentSearch from "../../components/search/search";
+    import componentQuickNav from "../../components/quick-nav/quick-nav";
+    import componentIconNav from "../../components/icon-nav/icon-nav";
+    import componentBanner from "../../components/slider/slider";
+    import componentCountdown from "../../components/countdown/countdown";
+    import componentLayout from "../../components/layout/layout";
+    import componentBadge from "../../components/badge/badge";
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+    import componentCopyright from "../../components/copyright/copyright";
+    import componentOnlineService from "../../components/online-service/online-service";
+    import componentActivityList from "../../components/activity-list/activity-list";
+    import componentBlogList from "../../components/blog-list/blog-list";
+    import componentRealstoreList from "../../components/realstore-list/realstore-list";
+    import componentShopList from "../../components/shop-list/shop-list";
+	import componentGoodsList from "../../components/goods-list/goods-list";
+
+    var common_static_url = app.globalData.get_static_url('common');
+    var static_url = app.globalData.get_static_url('home');
+    var seckill_static_url = app.globalData.get_static_url('seckill', true);
+    // 状态栏高度
+    var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0, true));
+    // #ifdef MP-TOUTIAO
+    bar_height = 0;
+    // #endif
+
+    export default {
+        data() {
+            return {
+                common_static_url: common_static_url,
+                static_url: static_url,
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                data_bottom_line_status: false,
+                load_status: 0,
+                currency_symbol: app.globalData.data.currency_symbol,
+                data_list: [],
+                banner_list: [],
+                navigation: [],
+                article_list: [],
+                cart_total: 0,
+                message_total: 0,
+                right_icon_list: [],
+                // 基础配置
+                common_shop_notice: null,
+                home_index_floor_data_type: 0,
+                common_app_is_enable_search: 0,
+                common_app_is_enable_answer: 0,
+                common_app_is_header_nav_fixed: 0,
+                common_app_is_online_service: 0,
+                // 名称
+                application_title: app.globalData.data.application_title,
+                application_logo: app.globalData.data.application_logo,
+                is_logo_use_text: app.globalData.data.is_logo_use_text || 0,
+                // 顶部+搜索样式配置
+                top_content_style: 'background-image: url("'+static_url+'nav-top.png");'+'padding-top:'+(bar_height+8)+'px;',
+                search_style: '',
+                search_is_fixed: 0,
+                // 是否单页预览
+                is_single_page: app.globalData.is_current_single_page() || 0,
+                // 插件顺序列表
+                plugins_sort_list: [],
+                // 限时秒杀插件
+                plugins_seckill_bg: 'background: url('+seckill_static_url+'home-bg.png) top/100% no-repeat;',
+                plugins_seckill_is_valid: 0,
+                plugins_seckill_data: null,
+                // 购买记录插件
+                plugins_salerecords_data: null,
+                // 活动配置插件
+                plugins_activity_data: null,
+                // 标签插件
+                plugins_label_data: null,
+                // 首页中间广告插件
+                plugins_homemiddleadv_data: null,
+                // 弹屏广告、这里设置一天后可以再次显示
+                plugins_popupscreen_data: null,
+                plugins_popupscreen_status: 0,
+                plugins_popupscreen_cache_key: 'plugins_popupscreen_cache_key',
+                plugins_popupscreen_timer: null,
+                // 哀悼灰度插件
+                plugins_mourning_data: 0,
+                // 标签插件
+                plugins_blog_data: null,
+                // 门店插件
+                plugins_realstore_data: null,
+                // 多商户插件
+                plugins_shop_data: null
+            };
+        },
+
+        components: {
+            componentSearch,
+            componentQuickNav,
+            componentIconNav,
+            componentBanner,
+            componentCountdown,
+            componentLayout,
+            componentBadge,
+            componentNoData,
+            componentBottomLine,
+            componentCopyright,
+            componentOnlineService,
+            componentActivityList,
+            componentBlogList,
+            componentRealstoreList,
+            componentShopList,
+			componentGoodsList
+        },
+        props: {},
+
+        onShow() {
+            // 数据加载
+            this.init();
+
+            // 初始化配置
+            this.init_config();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.init();
+        },
+
+        methods: {
+            // 初始化配置
+            init_config(status) {
+                if ((status || false) == true) {
+                    this.setData({
+                        currency_symbol: app.globalData.get_config('currency_symbol'),
+                        common_shop_notice: app.globalData.get_config('config.common_shop_notice'),
+                        home_index_floor_data_type: app.globalData.get_config('config.home_index_floor_data_type'),
+                        common_app_is_enable_search: app.globalData.get_config('config.common_app_is_enable_search'),
+                        common_app_is_enable_answer: app.globalData.get_config('config.common_app_is_enable_answer'),
+                        common_app_is_header_nav_fixed: app.globalData.get_config('config.common_app_is_header_nav_fixed'),
+                        common_app_is_online_service: app.globalData.get_config('config.common_app_is_online_service'),
+                        application_title: app.globalData.get_application_title(),
+                        application_logo: app.globalData.get_application_logo()
+                    });
+                } else {
+                    app.globalData.is_config(this, 'init_config');
+                }
+            },
+
+            // 获取数据
+            init() {
+                this.setData({
+                    data_list_loding_status: 1
+                });
+                uni.request({
+                    url: app.globalData.get_request_url("index", "index"),
+                    method: 'POST',
+                    data: {},
+                    dataType: 'json',
+                    success: res => {
+                        uni.stopPullDownRefresh();
+                        // 获取最新缓存
+                        if (this.load_status == 0) {
+                            this.init_config(true);
+                        }
+
+                        // 设置首次加载状态
+                        this.setData({
+                            load_status: 1
+                        });
+
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            this.setData({
+                                data_bottom_line_status: true,
+                                banner_list: data.banner_list || [],
+                                navigation: data.navigation || [],
+                                article_list: data.article_list || [],
+                                data_list: data.data_list,
+                                cart_total: data.cart_total.buy_number || 0,
+                                message_total: parseInt(data.message_total || 0),
+                                right_icon_list: data.right_icon_list || [],
+                                data_list_loding_status: data.data_list.length == 0 ? 0 : 3,
+                                plugins_sort_list: data.plugins_sort_list || [],
+                                plugins_seckill_data: data.plugins_seckill_data || null,
+                                plugins_seckill_is_valid: (data.plugins_seckill_data || null) != null && (data.plugins_seckill_data.is_valid || 0) == 1 ? 1 : 0,
+                                plugins_salerecords_data: (data.plugins_salerecords_data || null) == null || data.plugins_salerecords_data.length <= 0 ? null : data.plugins_salerecords_data,
+                                plugins_activity_data: (data.plugins_activity_data || null) == null || data.plugins_activity_data.length <= 0 ? null : data.plugins_activity_data,
+                                plugins_label_data: (data.plugins_label_data || null) == null || (data.plugins_label_data.base || null) == null || (data.plugins_label_data.data || null) == null || data.plugins_label_data.data.length <= 0 ? null : data.plugins_label_data,
+                                plugins_homemiddleadv_data: (data.plugins_homemiddleadv_data || null) == null || data.plugins_homemiddleadv_data.length <= 0 ? null : data.plugins_homemiddleadv_data,
+                                plugins_popupscreen_data: data.plugins_popupscreen_data || null,
+                                plugins_mourning_data: data.plugins_mourning_data || 0,
+                                plugins_blog_data: data.plugins_blog_data || null,
+                                plugins_realstore_data: data.plugins_realstore_data || null,
+                                plugins_shop_data: data.plugins_shop_data || null
+                            });
+
+                            // 弹屏广告插件处理
+                            this.plugins_popupscreen_handle();
+
+                            // 导航购物车处理
+                            if (this.cart_total <= 0) {
+                                app.globalData.set_tab_bar_badge(2, 0);
+                            } else {
+                                app.globalData.set_tab_bar_badge(2, 1, this.cart_total);
+                            }
+
+                            // 搜索框宽度处理
+                            // #ifdef MP-TOUTIAO
+                                var len = (this.right_icon_list || []).length;
+                                var val = (len <= 0) ? 0 : 66*len;
+                                this.setData({
+                                    search_style: 'width: calc(100% - '+val+'rpx);',
+                                });
+                            // #endif
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0,
+                                data_list_loding_msg: res.data.msg,
+                                data_bottom_line_status: true
+                            });
+                            app.globalData.showToast(res.data.msg);
+                        }
+
+                        // 分享菜单处理、延时执行,确保基础数据已加载完成
+                        setTimeout(function() {
+                            app.globalData.page_share_handle();
+                        }, 3000);
+                    },
+                    fail: () => {
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2,
+                            data_list_loding_msg: '服务器请求出错',
+                            data_bottom_line_status: true,
+                            load_status: 1
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+            
+            // 页面滚动监听
+            onPageScroll(e) {
+                if(this.common_app_is_header_nav_fixed == 1 && this.common_app_is_enable_search == 1) {
+                    var top = e.scrollTop > 35 ? 35 : e.scrollTop;
+                    var num = top*7;
+                    var base = 230;
+                    // #ifdef MP-ALIPAY
+                        base = 235
+                    // #endif
+                    // #ifdef H5 || MP-TOUTIAO || APP
+                        var len = (this.right_icon_list || []).length;
+                        base = (len <= 0) ? 0 : 66*len;
+                    // #endif
+                    // 开启哀悼插件的时候不需要浮动导航并且搜索框也不需要缩短、开启站点灰度会导致浮动失效
+                    if((this.plugins_mourning_data || 0) != 1) {
+                        var top_val = 35;
+                        var val = (num > base) ? base : num;
+                        // #ifdef MP-TOUTIAO
+                            top_val = 0;
+                            val = base
+                        // #endif
+                        this.setData({
+                            search_style: 'width: calc(100% - '+(val < 0 ? 0 : val)+'rpx);',
+                            search_is_fixed: (top >= top_val) ? 1 : 0,
+                        });
+                    }
+                }
+            },
+            
+            // url事件
+            url_event(e) {
+                app.globalData.url_event(e);
+            },
+            
+            // 弹屏广告插件处理
+            plugins_popupscreen_handle() {
+                if(this.plugins_popupscreen_data != null) {
+                    // 不存在关闭缓存或者超过间隔时间则显示
+                    var cv = parseInt(uni.getStorageSync(this.plugins_popupscreen_cache_key)) || 0;
+                    var pv = parseInt(this.plugins_popupscreen_data.interval_time) || 86400;
+                    if(cv == 0 || cv+pv < app.globalData.get_timestamp()) {
+                        // 是否开启自动关闭
+                        var timer = null;
+                        var ct = parseInt(this.plugins_popupscreen_data.close_time) || 0;
+                        if(ct > 0) {
+                            var self = this;
+                            timer = setTimeout(function() {
+                                self.setData({
+                                    plugins_popupscreen_status: 0
+                                });
+                                uni.setStorage({
+                                    key: self.plugins_popupscreen_cache_key,
+                                    data: app.globalData.get_timestamp()
+                                });
+                            }, ct*1000);
+                        }
+                        this.setData({
+                            plugins_popupscreen_status: 1,
+                            plugins_popupscreen_timer: timer
+                        });
+                    }
+                }
+            },
+            
+            // 弹屏广告 - 插件 关闭事件
+            plugins_popupscreen_close_event(e) {
+                this.setData({
+                    plugins_popupscreen_status: 0,
+                });
+                uni.setStorage({
+                    key: this.plugins_popupscreen_cache_key,
+                    data: app.globalData.get_timestamp()
+                });
+                clearInterval(this.plugins_popupscreen_timer);
+            }
+        }
+    };
+</script>
+<style>
+    @import './index.css';
+</style>

+ 79 - 0
pages/login/login.css

@@ -0,0 +1,79 @@
+page {
+    background: #fff;
+    
+}
+/**
+ * 基础
+ */
+.content {
+    padding-top: 8%;
+}
+.content .icon {
+    width: 150rpx;
+    height: 150rpx !important;
+}
+
+/**
+ * 表单内容
+ */
+.form-content {
+    padding: 2% 40rpx 0 40rpx;
+}
+.form-content .form-item,
+.form-content .code,
+.form-content .verify {
+    border-bottom: solid 1px #f7f7f7;
+}
+.form-content .form-item,
+.form-content .code input,
+.form-content .verify input {
+    font-size: 28rpx;
+    color: #4e4e4e;
+    height: 40px;
+    line-height: 40px;
+    border-radius: 0;
+}
+.form-content .code input,
+.form-content .verify input {
+    width: 63%;
+}
+.form-content .code .verify-submit {
+    width: 35%;
+    height: 35px;
+    line-height: 35px;
+    top: 0;
+    right: 0;
+}
+.form-content .verify .verify-image {
+    width: 35%;
+    height: 35px;
+    line-height: 35px;
+    top: 0;
+    right: 0;
+}
+.opt-type-list text:not(:last-child) {
+    margin-right: 50rpx;
+}
+
+/**
+ * 第三方登录 - 插件
+ */
+.plugins-thirdpartylogin .item {
+    width: 35rpx;
+    height: 35rpx;
+    padding: 5rpx;
+}
+.plugins-thirdpartylogin .item:not(:last-child) {
+    margin-right: 10rpx;
+}
+.plugins-thirdpartylogin .item image {
+    width: 25rpx !important;
+    height: 25rpx !important;
+}
+.plugins-thirdpartylogin-bind image {
+    width: 40rpx !important;
+    height: 40rpx !important;
+}
+.plugins-thirdpartylogin-bind button {
+    line-height: 40rpx;
+}

文件差異過大導致無法顯示
+ 1346 - 0
pages/login/login.vue


+ 3 - 0
pages/logout/logout.css

@@ -0,0 +1,3 @@
+.bottom-fixed button {
+    width: calc(50% - 10rpx);
+}

+ 155 - 0
pages/logout/logout.vue

@@ -0,0 +1,155 @@
+<template>
+    <view class="scroll-box bg-white">
+        <view class="page-bottom-fixed">
+            <block v-if="data_list_loding_status == 3">
+                <view class="padding-main">
+                    <view class="">
+                        <mp-html :content="agreement_data.value" />
+                    </view>
+                    <view class="bottom-fixed padding-main oh bg-white">
+                        <button class="bg-gray br-gray cr-base round text-size fl" type="default" size="mini" hover-class="none" @tap="logout_submit_event">确认注销</button>
+                        <button class="bg-main br-main cr-white round text-size fr" type="default" size="mini" hover-class="none" @tap="logout_cancel_event">取消</button>
+                    </view>
+                </view>
+            </block>
+
+            <!-- 错误提示 -->
+            <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+
+    export default {
+        data() {
+            return {
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                agreement_data: {}
+            }
+        },
+
+        components: {
+            componentNoData
+        },
+
+        onShow() {
+            // 数据加载
+            this.init();
+        },
+
+        methods: {
+            // 获取数据
+            init() {
+                var user = app.globalData.get_user_info(this, 'init');
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.redirectTo({
+                            url: "/pages/login/login?event_callback=init"
+                        });
+                        this.setData({
+                            data_list_loding_status: 0,
+                            data_list_loding_msg: '请先绑定手机'
+                        });
+                        return false;
+                    } else {
+                        this.get_data();
+                    }
+                } else {
+                    this.setData({
+                        data_list_loding_status: 0,
+                        data_list_loding_msg: '请先登录'
+                    });
+                }
+            },
+
+            // 获取数据
+            get_data() {
+                uni.request({
+                    url: app.globalData.get_request_url("index", "agreement"),
+                    method: 'POST',
+                    data: {document: 'userlogout'},
+                    dataType: 'json',
+                    success: res => {
+                        if(res.data.code == 0) {
+                            this.setData({
+                                data_list_loding_status: 3,
+                                agreement_data: res.data.data || {}
+                            });
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0,
+                                data_list_loding_msg: res.data.msg
+                            });
+                        }
+                    },
+                    fail: () => {
+                        this.setData({
+                            data_list_loding_status: 2,
+                            data_list_loding_msg: '服务器请求出错'
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 注销提交
+            logout_submit_event(e) {
+                // 是否再次确认
+                if(e != 0 && e != 1) {
+                    app.globalData.alert({
+                        msg: '账号注销后不可恢复、确定继续吗?',
+                        is_show_cancel: 1,
+                        object: this,
+                        method: 'logout_submit_event'
+                    });
+                    return false;
+                }
+
+                // 注销提交
+                if(e == 1) {
+                    uni.showLoading({
+                        title: '处理中...'
+                    });
+                    uni.request({
+                        url: app.globalData.get_request_url('logout', 'safety'),
+                        method: 'POST',
+                        data: {},
+                        dataType: 'json',
+                        success: res => {
+                            uni.hideLoading();
+                            if(res.data.code == 0) {
+                                app.globalData.remove_user_cache_event();
+                                app.globalData.showToast(res.data.msg, 'success');
+                                setTimeout(function() {
+                                    uni.switchTab({url: app.globalData.data.tabbar_pages[0]});
+                                }, 1500);
+                            } else {
+                                if (app.globalData.is_login_check(res.data)) {
+                                    app.globalData.showToast(res.data.msg);
+                                } else {
+                                    app.globalData.showToast('提交失败,请重试!');
+                                }
+                            }
+                        },
+                        fail: () => {
+                            uni.hideLoading();
+                            app.globalData.showToast('服务器请求出错');
+                        }
+                    });
+                }
+            },
+
+            // 取消返回
+            logout_cancel_event() {
+                app.globalData.page_back_prev_event();
+            }
+        }
+    }
+</script>
+<style>
+    @import './logout.css';
+</style>

+ 168 - 0
pages/message/message.vue

@@ -0,0 +1,168 @@
+<template>
+    <view>
+        <scroll-view :scroll-y="true" class="scroll-box" @scrolltolower="scroll_lower" lower-threshold="60">
+            <view v-if="data_list.length > 0" class="padding-horizontal-main padding-top-main">
+                <view v-for="(item, index) in data_list" :key="index" class="padding-main border-radius-main bg-white oh spacing-mb">
+                    <view class="oh">
+                        <text class="fw-b">{{item.title}}</text>
+                        <text class="fr cr-base">{{item.add_time_time}}</text>
+                    </view>
+                    <view class="cr-grey margin-top-lg">{{item.detail}}</view>
+                </view>
+            </view>
+            <view v-else>
+                <!-- 提示信息 -->
+                <component-no-data :propStatus="data_list_loding_status"></component-no-data>
+            </view>
+
+            <!-- 结尾 -->
+            <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+        </scroll-view>
+    </view>
+</template>
+
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+    import componentBottomLine from "../../components/bottom-line/bottom-line";
+
+    export default {
+        data() {
+            return {
+                data_list: [],
+                data_total: 0,
+                data_page_total: 0,
+                data_page: 1,
+                data_list_loding_status: 1,
+                data_bottom_line_status: false
+            };
+        },
+
+        components: {
+            componentNoData,
+            componentBottomLine
+        },
+        props: {},
+
+        onShow() {
+            this.init();
+            
+            // 分享菜单处理
+            app.globalData.page_share_handle();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.setData({
+                data_page: 1
+            });
+            this.get_data_list(1);
+        },
+
+        methods: {
+            init() {
+                var user = app.globalData.get_user_info(this, "init");
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.redirectTo({
+                            url: "/pages/login/login?event_callback=init"
+                        });
+                        return false;
+                    } else {
+                        // 获取数据
+                        this.get_data_list();
+                    }
+                } else {
+                    this.setData({
+                        data_list_loding_status: 0,
+                        data_bottom_line_status: false
+                    });
+                }
+            },
+
+            get_data_list(is_mandatory) {
+                // 分页是否还有数据
+                if ((is_mandatory || 0) == 0) {
+                    if (this.data_bottom_line_status == true) {
+                        uni.stopPullDownRefresh();
+                        return false;
+                    }
+                }
+                
+                // 加载loding
+                uni.showLoading({
+                    title: '加载中...'
+                });
+                this.setData({
+                    data_list_loding_status: 1
+                });
+                
+                // 获取数据
+                uni.request({
+                    url: app.globalData.get_request_url("index", "message"),
+                    method: 'POST',
+                    data: {
+                        page: this.data_page
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            if (res.data.data.data.length > 0) {
+                                if (this.data_page <= 1) {
+                                    var temp_data_list = res.data.data.data;
+                                } else {
+                                    var temp_data_list = this.data_list || [];
+                                    var temp_data = res.data.data.data;
+                                    for (var i in temp_data) {
+                                        temp_data_list.push(temp_data[i]);
+                                    }
+                                }
+                                this.setData({
+                                    data_list: temp_data_list,
+                                    data_total: res.data.data.total,
+                                    data_page_total: res.data.data.page_total,
+                                    data_list_loding_status: 3,
+                                    data_page: this.data_page + 1
+                                });
+                                
+                                // 是否还有数据
+                                this.setData({
+                                    data_bottom_line_status: (this.data_page > 1 && this.data_page > this.data_page_total)
+                                });
+                            } else {
+                                this.setData({
+                                    data_list_loding_status: 0
+                                });
+                            }
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0
+                            });
+                            if (app.globalData.is_login_check(res.data, this, 'get_data_list')) {
+                                app.globalData.showToast(res.data.msg);
+                            }
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 滚动加载
+            scroll_lower(e) {
+                this.get_data_list();
+            }
+        }
+    };
+</script>
+<style>
+</style>

+ 21 - 0
pages/paytips/paytips.css

@@ -0,0 +1,21 @@
+page {
+    background: #fff;
+}
+.content {
+    padding-top: 15%;
+}
+.content .pay-icon {
+    width: 200rpx;
+    height: 200rpx !important;
+    margin: 60rpx auto;
+}
+.btn-box {
+    margin-top: 150rpx;
+}
+.btn-box button {
+    height: 80rpx;
+    line-height: 80rpx;
+    padding-top: 0;
+    padding-bottom: 0;
+    width: 300rpx;
+}

+ 94 - 0
pages/paytips/paytips.vue

@@ -0,0 +1,94 @@
+<template>
+    <view>
+        <view class="content tc">
+            <image class="pay-icon dis-block" v-if="params.code == '9000'" mode="widthFix" :src="default_round_success_icon"></image>
+            <image class="pay-icon dis-block" v-else mode="widthFix" :src="default_round_error_icon"></image>
+            <view class="text-size-lg cr-base">{{params.msg}}</view>
+        </view>
+        <view class="btn-box tc">
+            <view>
+                <button class="bg-main br-main cr-white round" type="default" hover-class="none" size="mini" @tap="back_event">返回</button>
+            </view>
+            <view v-if="(params.page || null) != null && (params.title || null) != null" class="margin-top-lg">
+                <navigator class="dis-inline-block" :url="'/pages/' + params.page + '/' + params.page" open-type="redirect">
+                    <button class="bg-main-pair br-main-pair cr-white round" type="default" hover-class="none" size="mini">{{params.title}}</button>
+                </navigator>
+            </view>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+
+    export default {
+        data() {
+            return {
+                params: {},
+                default_round_success_icon: app.globalData.data.default_round_success_icon,
+                default_round_error_icon: app.globalData.data.default_round_error_icon
+            };
+        },
+
+        components: {},
+        props: {},
+
+        /**
+         * 页面加载初始化
+         */
+        onLoad(options) {
+            var msg = null;
+            switch (options.code) {
+                // 支付成功
+                case '9000':
+                    msg = '支付成功';
+                    break;
+                // 正在处理中
+                case '8000':
+                    msg = '正在处理中';
+                    break;
+                // 支付失败
+                case '4000':
+                    msg = '支付失败';
+                    break;
+                // 用户中途取消
+                case '6001':
+                    msg = '已取消支付';
+                    break;
+                // 网络连接出错
+                case '6002':
+                    msg = '网络连接出错';
+                    break;
+                // 支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
+                case '6004':
+                    msg = '支付结果未知';
+                    break;
+                // 用户点击忘记密码导致快捷界面退出(only iOS)
+                case '99':
+                    msg = '用户取消支付';
+                    break;
+                // 默认错误
+                default:
+                    msg = '其它异常错误';
+            }
+            options['msg'] = msg;
+            this.setData({
+                params: options
+            });
+        },
+        
+        onShow() {            
+            // 分享菜单处理
+            app.globalData.page_share_handle();
+        },
+
+        methods: {
+            // 返回
+            back_event(e) {
+                uni.navigateBack();
+            }
+        }
+    };
+</script>
+<style>
+    @import './paytips.css';
+</style>

+ 4 - 0
pages/personal/personal.css

@@ -0,0 +1,4 @@
+.user-avatar {
+    width: 80rpx;
+    height: 80rpx !important;
+}

+ 268 - 0
pages/personal/personal.vue

@@ -0,0 +1,268 @@
+<template>
+    <view>
+        <view class="page-bottom-fixed">
+            <!-- 主体内容 -->
+            <block v-if="data_list_loding_status == 3">
+                <form @submit="form_submit" class="form-container">
+                    <view class="padding-main oh">
+                        <view class="form-gorup oh">
+                            <view class="fw-b fl margin-top-lg">头像</view>
+                            <button class="fr bg-white br-0 lh-0" hover-class="none" open-type="chooseAvatar" @chooseavatar="choose_avatar_event" @tap="choose_avatar_event">
+                                <image :src="(user_data.avatar || default_avatar)" mode="widthFix" class="circle br user-avatar"></image>
+                            </button>
+                        </view>
+
+                        <view class="form-gorup oh">
+                            <view class="form-gorup-item-left">
+                                <view class="form-gorup-title">昵称<text class="form-group-tips-must">*</text></view>
+                                <input :type="(application_client_type == 'weixin') ? 'nickname' : 'text'" name="nickname" :value="user_data.nickname || ''" maxlength="16" placeholder-class="cr-grey" class="cr-base" placeholder="昵称2~16个字符">
+                            </view>
+                            <view class="form-gorup-item-right">
+                                <view class="form-gorup-title">生日</view>
+                                <picker name="birthday" mode="date" :value="user_data.birthday || ''" data-field="birthday" @change="select_change_event">
+                                    <view :class="'picker '+((user_data.birthday || null) == null ? 'cr-grey' : '')">{{user_data.birthday || '请选择生日'}}</view>
+                                </picker>
+                            </view>
+                        </view>
+
+                        <view class="form-gorup">
+                            <view class="oh">
+                                <view class="form-gorup-item-left">
+                                    <view class="form-gorup-title">所在省</view>
+                                    <input type="text" name="province" :value="user_data.province || ''" maxlength="30" placeholder-class="cr-grey" class="cr-base" placeholder="所在省最多30个字符">
+                                </view>
+                                <view class="form-gorup-item-right">
+                                    <view class="form-gorup-title">所在市</view>
+                                    <input type="text" name="city" :value="user_data.city || ''" maxlength="30" placeholder-class="cr-grey" class="cr-base" placeholder="所在市最多30个字符">
+                                </view>
+                            </view>
+                            <view class="oh br-t">
+                                <view class="form-gorup-item-left padding-top-lg">
+                                    <view class="form-gorup-title">所在区/县</view>
+                                    <input type="text" name="county" :value="user_data.county || ''" maxlength="30" placeholder-class="cr-grey" class="cr-base" placeholder="所在区/县最多30个字符">
+                                </view>
+                                <view class="form-gorup-item-right padding-top-lg">
+                                    <view class="form-gorup-title">详细地址</view>
+                                    <input type="text" name="address" :value="user_data.address || ''" maxlength="30" placeholder-class="cr-grey" class="cr-base" placeholder="详细地址最多30个字符">
+                                </view>
+                            </view>
+                        </view>
+
+                        <view class="form-gorup oh">
+                            <view class="form-gorup-title">性别</view>
+                            <view class="radio-gorup">
+                                <radio-group data-field="gender" @change="select_change_event">
+                                    <block v-for="(item,index) in gender_list" :key="index">
+                                        <label class="radio">
+                                            <radio :value="item.id.toString()" :checked="(parseInt(user_data.gender || 0) == item.id)" />
+                                            <text class="va-m">{{item.name}}</text>
+                                        </label>
+                                    </block>
+                                </radio-group>
+                            </view>
+                        </view>
+
+                        <view class="bottom-fixed padding-main">
+                            <button class="bg-main br-main cr-white round text-size" type="default" form-type="submit" hover-class="none" :disabled="form_submit_disabled_status">保存</button>
+                        </view>
+                    </view>
+                </form>
+            </block>
+
+            <!-- 错误提示 -->
+            <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentNoData from "../../components/no-data/no-data";
+
+    export default {
+        data() {
+            return {
+                application_client_type: app.globalData.application_client_type(),
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                form_submit_disabled_status: false,
+                default_avatar: app.globalData.data.default_user_head_src,
+                user_data: {},
+                gender_list: []
+            }
+        },
+
+        components: {
+            componentNoData
+        },
+
+        onShow() {
+            // 数据加载
+            this.init();
+        },
+
+        methods: {
+            // 获取数据
+            init() {
+                var user = app.globalData.get_user_info(this, 'init');
+                if (user != false) {
+                    // 用户未绑定用户则转到登录页面
+                    if (app.globalData.user_is_need_login(user)) {
+                        uni.redirectTo({
+                            url: "/pages/login/login?event_callback=init"
+                        });
+                        this.setData({
+                            data_list_loding_status: 0,
+                            data_list_loding_msg: '请先绑定手机'
+                        });
+                        return false;
+                    } else {
+                        this.get_data();
+                    }
+                } else {
+                    this.setData({
+                        data_list_loding_status: 0,
+                        data_list_loding_msg: '请先登录'
+                    });
+                }
+            },
+
+            // 获取数据
+            get_data() {
+                uni.request({
+                    url: app.globalData.get_request_url("index", "personal"),
+                    method: 'POST',
+                    data: {},
+                    dataType: 'json',
+                    success: res => {
+                        if(res.data.code == 0) {
+                            this.setData({
+                                data_list_loding_status: 3,
+                                user_data: res.data.data.data || {},
+                                gender_list: res.data.data.gender_list || []
+                            });
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0,
+                                data_list_loding_msg: res.data.msg
+                            });
+                        }
+                    },
+                    fail: () => {
+                        this.setData({
+                            data_list_loding_status: 2,
+                            data_list_loding_msg: '服务器请求出错'
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // url事件
+            url_event(e) {
+                app.globalData.url_event(e);
+            },
+
+            // 生日、性别选择事件
+            select_change_event(e) {
+                var temp = this.user_data;
+                temp[e.currentTarget.dataset.field] = e.detail.value;
+                this.setData({user_data: temp});
+            },
+
+            // 头像事件
+            choose_avatar_event(e) {
+                var self = this;
+                if(this.application_client_type == 'weixin') {
+                    self.upload_handle(e.detail.avatarUrl);
+                } else {
+                    uni.chooseImage({
+                        count: 1,
+                        success(res) {
+                            if(res.tempFilePaths.length > 0) {
+                                self.upload_handle(res.tempFilePaths[0]);
+                            }
+                        }
+                    });
+                }
+            },
+
+            // 上传处理
+            upload_handle(image) {
+                var self = this;
+                uni.uploadFile({
+                    url: app.globalData.get_request_url('useravatarupload', 'personal'),
+                    filePath: image,
+                    name: 'file',
+                    formData: {},
+                    success: function(res) {
+                        if(res.statusCode == 200) {
+                            var data = typeof res.data == 'object' ? res.data : JSON.parse(res.data);
+                            if(data.code == 0) {
+                                var temp = self.user_data;
+                                temp['avatar'] = data.data;
+                                self.setData({user_data: temp});
+                            } else {
+                                app.globalData.showToast(data.msg);
+                            }
+                        }
+                    }
+                });
+            },
+
+            // 数据提交
+            form_submit(e) {
+                // 表单数据
+                var form_data = e.detail.value;
+                // 头像
+                form_data['avatar'] = this.user_data.avatar || '';
+                // 生日
+                form_data['birthday'] = this.user_data.birthday || '';
+                // 性别
+                form_data['gender'] = this.user_data.gender || 0;
+
+                // 数据保存
+                this.setData({
+                    form_submit_disabled_status: true
+                });
+                uni.showLoading({
+                    title: '处理中...'
+                });
+                uni.request({
+                    url: app.globalData.get_request_url('save', 'personal'),
+                    method: 'POST',
+                    data: form_data,
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        this.setData({
+                            form_submit_disabled_status: false
+                        });
+                        if(res.data.code == 0) {
+                            uni.setStorageSync(app.globalData.data.cache_user_info_key, res.data.data);
+                            app.globalData.showToast(res.data.msg, 'success');
+                            setTimeout(function() {
+                                uni.navigateBack();
+                            }, 1000);
+                        } else {
+                            if (app.globalData.is_login_check(res.data)) {
+                                app.globalData.showToast(res.data.msg);
+                            } else {
+                                app.globalData.showToast('提交失败,请重试!');
+                            }
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        this.setData({
+                            form_submit_disabled_status: false
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            }
+        }
+    }
+</script>
+<style>
+    @import './personal.css';
+</style>

+ 16 - 0
pages/plugins/activity/detail/detail.css

@@ -0,0 +1,16 @@
+/**
+* 基础
+*/
+.base-container {
+    height: 280rpx;
+    background-size: cover;
+}
+.base-container .text {
+    top: 0;
+    left: 0;
+    background: rgb(0 0 0 / 35%);
+    padding: 100rpx 20rpx 20rpx 20rpx;
+}
+.word-content .word-icon:not(:last-child) {
+    margin-right: 20rpx;
+}

+ 171 - 0
pages/plugins/activity/detail/detail.vue

@@ -0,0 +1,171 @@
+<template>
+    <view>
+        <view v-if="(data || null) != null">
+            <view class="padding-horizontal-main padding-top-main">
+                <!-- 基础信息 -->
+                <view class="base-container tc pr padding-main border-radius-main bg-main oh spacing-mb" :style="'background-color:'+data.color+' !important;background-image:url('+data.cover+')'">
+                    <view class="text cr-white pa bs-bb text-size wh-auto ht-auto">{{data.describe}}</view>
+                </view>
+
+                <!-- 关键字 -->
+                <view v-if="data.keywords_arr.length > 0" class="word-content scroll-view-horizontal margin-bottom-sm">
+                    <scroll-view scroll-x>
+                        <block v-for="(kv, ki) in data.keywords_arr" :key="ki">
+                            <navigator :url="'/pages/goods-search/goods-search?keywords=' + kv" hover-class="none" class="word-icon dis-inline-block bg-main-light text-size-xs cr-main round padding-top-xs padding-bottom-xs padding-left padding-right">{{kv}}</navigator>
+                        </block>
+                    </scroll-view>
+                </view>
+
+                <!-- 推荐商品 -->
+                <view v-if="(data.goods_list || null) != null && data.goods_list.length > 0">
+                    <view class="spacing-nav-title">
+                        <text class="text-wrapper">活动商品</text>
+                        <text class="cr-grey text-size-xs margin-left-lg">{{data.vice_title}}</text>
+                        <navigator url="/pages/plugins/activity/index/index" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr">更多活动</navigator>
+                    </view>
+                    <component-goods-list :propData="{style_type: 1, goods_list: data.goods_list}" :propCurrencySymbol="currency_symbol"></component-goods-list>
+                </view>
+                <view v-else>
+                    <!-- 提示信息 -->
+                    <component-no-data propStatus="0" propMsg="没有相关商品"></component-no-data>
+                </view>
+            </view>
+
+            <!-- 结尾 -->
+            <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+        </view>
+        <view v-else>
+            <!-- 提示信息 -->
+            <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentNoData from "../../../../components/no-data/no-data";
+    import componentBottomLine from "../../../../components/bottom-line/bottom-line";
+    import componentGoodsList from "../../../../components/goods-list/goods-list";
+
+    export default {
+        data() {
+            return {
+                data_bottom_line_status: false,
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                currency_symbol: app.globalData.data.currency_symbol,
+                params: null,
+                user: null,
+                data_base: null,
+                data: null,
+                // 自定义分享信息
+                share_info: {}
+            };
+        },
+
+        components: {
+            componentNoData,
+            componentBottomLine,
+            componentGoodsList
+        },
+        props: {},
+
+        onLoad(params) {
+            //params['id'] = 1;
+            this.setData({
+                params: params
+            });
+        },
+
+        onShow() {
+            // 初始化配置
+            this.init_config();
+
+            // 获取数据
+            this.get_data();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.get_data();
+        },
+
+        methods: {
+            // 初始化配置
+            init_config(status) {
+                if ((status || false) == true) {
+                    this.setData({
+                        currency_symbol: app.globalData.get_config('currency_symbol'),
+                    });
+                } else {
+                    app.globalData.is_config(this, 'init_config');
+                }
+            },
+
+            // 获取数据
+            get_data() {
+                uni.request({
+                    url: app.globalData.get_request_url("detail", "index", "activity"),
+                    method: 'POST',
+                    data: {
+                        id: this.params.id || 0
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            this.setData({
+                                data_base: data.base || null,
+                                data: data.data || null,
+                                data_list_loding_msg: '',
+                                data_list_loding_status: 0,
+                                data_bottom_line_status: ((data.data || null) != null && (data.data.goods_list || null) != null && data.data.goods_list.length > 0)
+                            });
+                            
+                            if ((this.data || null) != null) {
+                                // 基础自定义分享
+                                this.setData({
+                                    share_info: {
+                                        title: this.data.seo_title || this.data.title,
+                                        desc: this.data.seo_desc || this.data.describe,
+                                        path: '/pages/plugins/activity/detail/detail',
+                                        query: 'id='+this.data.id,
+                                        img: this.data.cover
+                                    }
+                                });
+
+                                // 标题
+                                if((this.data.title || null) != null) {
+                                    uni.setNavigationBarTitle({
+                                        title: this.data.title
+                                    });
+                                }
+                            }
+                        } else {
+                            this.setData({
+                                data_bottom_line_status: false,
+                                data_list_loding_status: 2,
+                                data_list_loding_msg: res.data.msg
+                            });
+                        }
+
+                        // 分享菜单处理
+                        app.globalData.page_share_handle(this.share_info);
+                    },
+                    fail: () => {
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_bottom_line_status: false,
+                            data_list_loding_status: 2,
+                            data_list_loding_msg: '服务器请求出错'
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            }
+        }
+    };
+</script>
+<style>
+    @import './detail.css';
+</style>

+ 17 - 0
pages/plugins/activity/index/index.css

@@ -0,0 +1,17 @@
+/**
+* 数据列表
+*/
+.data-list .item {
+    width: calc(50% - 10rpx);
+    margin-bottom: 20rpx;
+}
+.data-list .item:nth-child(2n) {
+    float: right;
+}
+.data-list .item:nth-child(2n+1) {
+    float: left;
+}
+.data-list .item image {
+    width: 100%;
+    height: 160rpx !important;
+}

+ 256 - 0
pages/plugins/activity/index/index.vue

@@ -0,0 +1,256 @@
+<template>
+    <view>
+        <view v-if="(data_base || null) != null">
+            <!-- 轮播 -->
+            <view v-if="slider_list.length > 0" class="padding-horizontal-main padding-top-main">
+                <component-banner :propData="slider_list" propSize="mini"></component-banner>
+            </view>
+
+            <!-- 分类 -->
+            <scroll-view v-if="(activity_category || null) != null && activity_category.length > 0" class="nav-base scroll-view-horizontal bg-white oh" scroll-x="true">
+                <view :class="'item cr-gray dis-inline-block padding-horizontal-main ' + (nav_active_value == 0 ? 'cr-main' : '')" @tap="nav_event" data-value="0">全部</view>
+                <block v-for="(item, index) in activity_category" :key="index">
+                    <view :class="'item cr-gray dis-inline-block padding-horizontal-main ' + (nav_active_value == item.id ? 'cr-main' : '')" @tap="nav_event" :data-value="item.id">{{item.name}}</view>
+                </block>
+            </scroll-view>
+
+            <!-- 列表 -->
+            <scroll-view :scroll-y="true" class="scroll-box scroll-box-ece-nav" @scrolltolower="scroll_lower" lower-threshold="30" :style="slider_list.length > 0 ? 'height:calc(100vh - 320rpx);' : ''">
+                <view v-if="(data_list || null) != null && data_list.length > 0" class="data-list padding-horizontal-main padding-top-main oh">
+                    <block v-for="(item, index) in data_list" :key="index">
+                        <view class="item border-radius-main bg-white oh spacing-mb">
+                            <navigator :url="'/pages/plugins/activity/detail/detail?id=' + item.id" hover-class="none">
+                                <image :src="item.cover" mode="aspectFit"></image>
+                                <view class="padding-main tc">
+                                    <view class="single-text fw-b cr-base">{{item.title}}</view>
+                                    <view class="multi-text cr-grey margin-top-sm">{{item.describe}}</view>
+                                </view>
+                            </navigator>
+                        </view>
+                    </block>
+                </view>
+                <view v-else>
+                    <!-- 提示信息 -->
+                    <component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
+                </view>
+
+                <!-- 结尾 -->
+                <component-bottom-line :propStatus="data_bottom_line_status"></component-bottom-line>
+            </scroll-view>
+        </view>
+    </view>
+</template>
+<script>
+    const app = getApp();
+    import componentBanner from "../../../../components/slider/slider";
+    import componentNoData from "../../../../components/no-data/no-data";
+    import componentBottomLine from "../../../../components/bottom-line/bottom-line";
+
+    export default {
+        data() {
+            return {
+                data_list_loding_status: 1,
+                data_list_loding_msg: '',
+                data_bottom_line_status: false,
+                data_list: [],
+                data_total: 0,
+                data_page_total: 0,
+                data_page: 1,
+                params: null,
+                data_base: null,
+                slider_list: [],
+                activity_category: [],
+                nav_active_value: 0,
+                // 自定义分享信息
+                share_info: {}
+            };
+        },
+
+        components: {
+            componentBanner,
+            componentNoData,
+            componentBottomLine
+        },
+        props: {},
+
+        onLoad(params) {
+            this.setData({
+                params: params
+            });
+            
+            // 数据加载
+            this.get_data();
+        },
+
+        // 下拉刷新
+        onPullDownRefresh() {
+            this.setData({
+                data_page: 1
+            });
+            this.get_data_list(1);
+        },
+
+        methods: {
+            // 初始化
+            get_data() {
+                uni.showLoading({
+                    title: '加载中...'
+                });
+                uni.request({
+                    url: app.globalData.get_request_url("index", "index", "activity"),
+                    method: 'POST',
+                    data: {},
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            this.setData({
+                                data_base: data.base || null,
+                                slider_list: data.slider_list || [],
+                                activity_category: data.activity_category || []
+                            });
+
+                            if ((this.data_base || null) != null) {
+                                // 基础自定义分享
+                                this.setData({
+                                    share_info: {
+                                        title: this.data_base.seo_title || this.data_base.application_name,
+                                        desc: this.data_base.seo_desc,
+                                        path: '/pages/plugins/activity/index/index'
+                                    }
+                                });
+
+                                // 标题
+                                if((this.data_base.application_name || null) != null) {
+                                    uni.setNavigationBarTitle({
+                                        title: this.data_base.application_name
+                                    });
+                                }
+                            }
+                            
+                            // 获取列表数据
+                            this.get_data_list(1);
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0,
+                                data_list_loding_msg: res.data.msg
+                            });
+                            app.globalData.showToast(res.data.msg);
+                        }
+                        
+                        // 分享菜单处理
+                        app.globalData.page_share_handle(this.share_info);
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 获取数据列表
+            get_data_list(is_mandatory) {
+                // 分页是否还有数据
+                if ((is_mandatory || 0) == 0) {
+                    if (this.data_bottom_line_status == true) {
+                        uni.stopPullDownRefresh();
+                        return false;
+                    }
+                }
+                
+                // 加载loding
+                uni.showLoading({
+                    title: '加载中...'
+                });
+
+                // 获取数据
+                uni.request({
+                    url: app.globalData.get_request_url("datalist", "index", "activity"),
+                    method: 'POST',
+                    data: {
+                        page: this.data_page,
+                        category_id: this.nav_active_value || 0
+                    },
+                    dataType: 'json',
+                    success: res => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        if (res.data.code == 0) {
+                            var data = res.data.data;
+                            if (data.data.length > 0) {
+                                if (this.data_page <= 1) {
+                                    var temp_data_list = data.data;
+                                } else {
+                                    var temp_data_list = this.data_list || [];
+                                    var temp_data = data.data || [];
+                                    for (var i in temp_data) {
+                                        temp_data_list.push(temp_data[i]);
+                                    }
+                                }
+                                this.setData({
+                                    data_list: temp_data_list,
+                                    data_total: data.total,
+                                    data_page_total: data.page_total,
+                                    data_list_loding_status: 3,
+                                    data_page: this.data_page + 1
+                                });
+                                
+                                // 是否还有数据
+                                this.setData({
+                                    data_bottom_line_status: (this.data_page > 1 && this.data_page > this.data_page_total)
+                                });
+                            } else {
+                                this.setData({
+                                    data_list_loding_status: 0
+                                });
+                                if (this.data_page <= 1) {
+                                    this.setData({
+                                        data_list: [],
+                                        data_bottom_line_status: false
+                                    });
+                                }
+                            }
+                        } else {
+                            this.setData({
+                                data_list_loding_status: 0,
+                                data_list_loding_msg: res.data.msg
+                            });
+                            app.globalData.showToast(res.data.msg);
+                        }
+                    },
+                    fail: () => {
+                        uni.hideLoading();
+                        uni.stopPullDownRefresh();
+                        this.setData({
+                            data_list_loding_status: 2
+                        });
+                        app.globalData.showToast('服务器请求出错');
+                    }
+                });
+            },
+
+            // 滚动加载
+            scroll_lower(e) {
+                this.get_data_list();
+            },
+
+            // 导航事件
+            nav_event(e) {
+                this.setData({
+                    nav_active_value: e.currentTarget.dataset.value || 0,
+                    data_page: 1
+                });
+                this.get_data_list(1);
+            }
+        }
+    };
+</script>
+<style>
+    @import './index.css';
+</style>

+ 69 - 0
pages/plugins/binding/detail/detail.css

@@ -0,0 +1,69 @@
+/**
+* 基础
+*/
+.base-container {
+    height: 280rpx;
+    background-size: cover;
+}
+.base-container .text {
+    top: 0;
+    left: 0;
+    background: rgb(0 0 0 / 35%);
+    padding: 100rpx 20rpx 20rpx 20rpx;
+}
+
+/**
+* 商品列表
+*/
+.data-list .item .goods-img {
+    width:170rpx;
+    height: 170rpx !important;
+}
+.data-list .item .right-base {
+    width: calc(100% - 190rpx);
+}
+.data-list .item .spec-choice {
+    max-width: calc(100% - 220rpx);
+}
+.data-list .item .cart-badge-icon {
+    top: -16rpx;
+    right: 0;
+}
+
+/**
+ * 导航
+ */
+.nav-button {
+    background: #eee;
+    box-shadow: 0 -2px 3px #e2e2e2;
+}
+.nav-button .left-price {
+    width: calc(100% - 270rpx);
+}
+.nav-button .right-button {
+    width: 250rpx;
+}
+.nav-button .left-price .estimate-discount-price {
+    top: 6rpx;
+    left: 20rpx;
+    width: calc(100% - 270rpx);
+}
+.nav-button .left-price .discount-icon {
+    border-top-right-radius: 30rpx;
+    border-bottom-left-radius: 30rpx;
+    background-image: linear-gradient(45deg,#a3f9a3,#248828,#8bc34a,#d2374c,#9c27b0);
+    background-size: 400%;
+    animation: gradient 5s ease infinite;
+    padding: 0 16rpx;
+}
+@keyframes gradient {
+    0% {
+        background-position: 0% 50%;
+    }
+    50% {
+        background-position: 100% 50%;
+    }
+    100% {
+        background-position: 0% 50%;
+    }
+}

+ 0 - 0
pages/plugins/binding/detail/detail.vue


部分文件因文件數量過多而無法顯示