Ver código fonte

1.1.46原始版本

tangbin 3 anos atrás
commit
2e2404042d
100 arquivos alterados com 3600 adições e 0 exclusões
  1. 6 0
      .gitignore
  2. 464 0
      app.js
  3. 109 0
      app.json
  4. 295 0
      app.wxss
  5. 42 0
      components/actionsheet/index.js
  6. 6 0
      components/actionsheet/index.json
  7. 39 0
      components/actionsheet/index.wxml
  8. 86 0
      components/actionsheet/index.wxss
  9. 61 0
      components/btn/index.js
  10. 3 0
      components/btn/index.json
  11. 24 0
      components/btn/index.wxml
  12. 0 0
      components/btn/index.wxss
  13. 74 0
      components/btn/native-button-behaviors.js
  14. 3 0
      components/common/color.js
  15. 48 0
      components/common/component.js
  16. 1 0
      components/common/index.wxss
  17. 1 0
      components/common/style/clearfix.wxss
  18. 1 0
      components/common/style/ellipsis.wxss
  19. 1 0
      components/common/style/hairline.wxss
  20. 0 0
      components/common/style/mixins/clearfix.wxss
  21. 0 0
      components/common/style/mixins/ellipsis.wxss
  22. 0 0
      components/common/style/mixins/hairline.wxss
  23. 0 0
      components/common/style/var.wxss
  24. 14 0
      components/common/utils.js
  25. 130 0
      components/countdown/index.js
  26. 3 0
      components/countdown/index.json
  27. 15 0
      components/countdown/index.wxml
  28. 33 0
      components/countdown/index.wxss
  29. 26 0
      components/dialog/data.js
  30. 104 0
      components/dialog/dialog.js
  31. 148 0
      components/dialog/index.js
  32. 7 0
      components/dialog/index.json
  33. 18 0
      components/dialog/index.wxml
  34. 79 0
      components/dialog/index.wxss
  35. 35 0
      components/diy/article/article.js
  36. 3 0
      components/diy/article/article.json
  37. 31 0
      components/diy/article/article.wxml
  38. 46 0
      components/diy/article/article.wxss
  39. 77 0
      components/diy/banner/banner.js
  40. 3 0
      components/diy/banner/banner.json
  41. 11 0
      components/diy/banner/banner.wxml
  42. 45 0
      components/diy/banner/banner.wxss
  43. 36 0
      components/diy/bargainGoods/index.js
  44. 3 0
      components/diy/bargainGoods/index.json
  45. 47 0
      components/diy/bargainGoods/index.wxml
  46. 100 0
      components/diy/bargainGoods/index.wxss
  47. 16 0
      components/diy/blank/blank.js
  48. 3 0
      components/diy/blank/blank.json
  49. 3 0
      components/diy/blank/blank.wxml
  50. 1 0
      components/diy/blank/blank.wxss
  51. 45 0
      components/diy/coupon/coupon.js
  52. 3 0
      components/diy/coupon/coupon.json
  53. 33 0
      components/diy/coupon/coupon.wxml
  54. 85 0
      components/diy/coupon/coupon.wxss
  55. 36 0
      components/diy/goods/goods.js
  56. 3 0
      components/diy/goods/goods.json
  57. 61 0
      components/diy/goods/goods.wxml
  58. 158 0
      components/diy/goods/goods.wxss
  59. 16 0
      components/diy/guide/guide.js
  60. 3 0
      components/diy/guide/guide.json
  61. 5 0
      components/diy/guide/guide.wxml
  62. 5 0
      components/diy/guide/guide.wxss
  63. 34 0
      components/diy/imageSingle/imageSingle.js
  64. 3 0
      components/diy/imageSingle/imageSingle.json
  65. 8 0
      components/diy/imageSingle/imageSingle.wxml
  66. 6 0
      components/diy/imageSingle/imageSingle.wxss
  67. 15 0
      components/diy/index.js
  68. 25 0
      components/diy/index.json
  69. 103 0
      components/diy/index.wxml
  70. 0 0
      components/diy/index.wxss
  71. 34 0
      components/diy/navBar/navBar.js
  72. 3 0
      components/diy/navBar/navBar.json
  73. 13 0
      components/diy/navBar/navBar.wxml
  74. 41 0
      components/diy/navBar/navBar.wxss
  75. 17 0
      components/diy/notice/notice.js
  76. 6 0
      components/diy/notice/notice.json
  77. 4 0
      components/diy/notice/notice.wxml
  78. 16 0
      components/diy/notice/notice.wxss
  79. 17 0
      components/diy/officialAccount/index.js
  80. 3 0
      components/diy/officialAccount/index.json
  81. 4 0
      components/diy/officialAccount/index.wxml
  82. 0 0
      components/diy/officialAccount/index.wxss
  83. 29 0
      components/diy/richText/richText.js
  84. 6 0
      components/diy/richText/richText.json
  85. 5 0
      components/diy/richText/richText.wxml
  86. 8 0
      components/diy/richText/richText.wxss
  87. 31 0
      components/diy/search/search.js
  88. 3 0
      components/diy/search/search.json
  89. 13 0
      components/diy/search/search.wxml
  90. 33 0
      components/diy/search/search.wxss
  91. 37 0
      components/diy/service/service.js
  92. 3 0
      components/diy/service/service.json
  93. 21 0
      components/diy/service/service.wxml
  94. 19 0
      components/diy/service/service.wxss
  95. 36 0
      components/diy/sharingGoods/sharingGoods.js
  96. 3 0
      components/diy/sharingGoods/sharingGoods.json
  97. 37 0
      components/diy/sharingGoods/sharingGoods.wxml
  98. 110 0
      components/diy/sharingGoods/sharingGoods.wxss
  99. 94 0
      components/diy/sharpGoods/index.js
  100. 6 0
      components/diy/sharpGoods/index.json

+ 6 - 0
.gitignore

@@ -0,0 +1,6 @@
+.idea
+.git
+project.config.json
+
+*.wxss.map
+.sass-cache

+ 464 - 0
app.js

@@ -0,0 +1,464 @@
+/**
+ * tabBar页面路径列表 (用于链接跳转时判断)
+ * tabBarLinks为常量, 无需修改
+ */
+const tabBarLinks = [
+  'pages/index/index',
+  'pages/category/index',
+  'pages/flow/index',
+  'pages/user/index'
+];
+
+// 站点配置文件
+import siteinfo from './siteinfo.js';
+
+// 工具类
+import util from './utils/util.js';
+
+App({
+
+  /**
+   * 全局变量
+   */
+  globalData: {
+    user_id: null,
+  },
+
+  // api地址
+  api_root: siteinfo.siteroot + 'index.php?s=/api/',
+
+  /**
+   * 生命周期函数--监听小程序初始化
+   */
+  onLaunch(e) {
+    let _this = this;
+    // 小程序主动更新
+    _this.updateManager();
+    // 小程序启动场景
+    _this.onStartupScene(e.query);
+  },
+
+  /**
+   * 小程序启动场景
+   */
+  onStartupScene(query) {
+    // 获取场景值
+    let scene = this.getSceneData(query);
+    // 记录推荐人id
+    let refereeId = query.referee_id ? query.referee_id : scene.uid;
+    refereeId > 0 && (this.saveRefereeId(refereeId));
+  },
+
+  /**
+   * 获取商城ID
+   */
+  getWxappId() {
+    return siteinfo.uniacid || 10001;
+  },
+
+  /**
+   * 记录推荐人id
+   */
+  saveRefereeId(refereeId) {
+    let App = this;
+    refereeId = parseInt(refereeId);
+    if (refereeId <= 0 || refereeId == App.getUserId()) {
+      return false;
+    }
+    if (wx.getStorageSync('referee_id')) {
+      return false;
+    }
+    wx.setStorageSync('referee_id', refereeId);
+    return true;
+  },
+
+  /**
+   * 获取场景值(scene)
+   */
+  getSceneData(query) {
+    return query.scene ? util.scene_decode(query.scene) : {};
+  },
+
+  /**
+   * 当小程序启动,或从后台进入前台显示,会触发 onShow
+   */
+  onShow(options) {
+    let App = this;
+    try {
+      const livePlayer = requirePlugin('live-player-plugin');
+      if (options.scene == 1007 || options.scene == 1008 || options.scene == 1044) {
+        livePlayer.getShareParams()
+          .then(res => {
+            // 直播页面的自定义参数
+            let customParams = res.custom_params;
+            console.log('get custom params', customParams);
+            // 记录推荐人ID
+            if (customParams.hasOwnProperty('referee_id')) {
+              App.saveRefereeId(customParams['referee_id']);
+            }
+          }).catch(err => {
+            console.log('get share params', err)
+          });
+      }
+    } catch (error) {
+
+    }
+  },
+
+  /**
+   * 执行用户登录
+   */
+  doLogin(delta) {
+    // 保存当前页面
+    let pages = getCurrentPages();
+    if (pages.length) {
+      let currentPage = pages[pages.length - 1];
+      "pages/login/login" != currentPage.route &&
+        wx.setStorageSync("currentPage", currentPage);
+    }
+    // 跳转授权页面
+    wx.navigateTo({
+      url: "/pages/login/login?delta=" + (delta || 1)
+    });
+  },
+
+  /**
+   * 当前用户id
+   */
+  getUserId() {
+    return wx.getStorageSync('user_id');
+  },
+
+  /**
+   * 显示成功提示框
+   */
+  showSuccess(msg, callback) {
+    wx.showToast({
+      title: msg,
+      icon: 'success',
+      mask: true,
+      duration: 1500,
+      success() {
+        callback && (setTimeout(() => {
+          callback();
+        }, 1500));
+      }
+    });
+  },
+
+  /**
+   * 显示失败提示框
+   */
+  showError(msg, callback) {
+    wx.showModal({
+      title: '友情提示',
+      content: msg,
+      showCancel: false,
+      success(res) {
+        // callback && (setTimeout(() => {
+        //   callback();
+        // }, 1500));
+        callback && callback();
+      }
+    });
+  },
+
+  /**
+   * get请求
+   */
+  _get(url, data, success, fail, complete, check_login) {
+    wx.showNavigationBarLoading();
+    let _this = this;
+    // 构造请求参数
+    data = data || {};
+    data.wxapp_id = _this.getWxappId();
+
+    // if (typeof check_login === 'undefined')
+    //   check_login = true;
+
+    // 构造get请求
+    let request = () => {
+      data.token = wx.getStorageSync('token');
+      wx.request({
+        url: _this.api_root + url,
+        header: {
+          'content-type': 'application/json'
+        },
+        data: data,
+        success(res) {
+          if (res.statusCode !== 200 || typeof res.data !== 'object') {
+            console.log(res);
+            _this.showError('网络请求出错');
+            return false;
+          }
+          if (res.data.code === -1) {
+            // 登录态失效, 重新登录
+            wx.hideNavigationBarLoading();
+            _this.doLogin(2);
+          } else if (res.data.code === 0) {
+            _this.showError(res.data.msg, () => {
+              fail && fail(res);
+            });
+            return false;
+          } else {
+            success && success(res.data);
+          }
+        },
+        fail(res) {
+          _this.showError(res.errMsg, () => {
+            fail && fail(res);
+          });
+        },
+        complete(res) {
+          wx.hideNavigationBarLoading();
+          complete && complete(res);
+        },
+      });
+    };
+    // 判断是否需要验证登录
+    check_login ? _this.doLogin(request) : request();
+  },
+
+  /**
+   * post提交
+   */
+  _post_form(url, data, success, fail, complete, isShowNavBarLoading) {
+    let _this = this;
+
+    isShowNavBarLoading || true;
+    data.wxapp_id = _this.getWxappId();
+    data.token = wx.getStorageSync('token');
+
+    // 在当前页面显示导航条加载动画
+    if (isShowNavBarLoading == true) {
+      wx.showNavigationBarLoading();
+    }
+    wx.request({
+      url: _this.api_root + url,
+      header: {
+        'content-type': 'application/x-www-form-urlencoded',
+      },
+      method: 'POST',
+      data: data,
+      success(res) {
+        if (res.statusCode !== 200 || typeof res.data !== 'object') {
+          _this.showError('网络请求出错');
+          return false;
+        }
+        if (res.data.code === -1) {
+          // 登录态失效, 重新登录
+          wx.hideNavigationBarLoading();
+          _this.doLogin(1);
+          return false;
+        } else if (res.data.code === 0) {
+          _this.showError(res.data.msg, () => {
+            fail && fail(res);
+          });
+          return false;
+        }
+        success && success(res.data);
+      },
+      fail(res) {
+        // console.log(res);
+        _this.showError(res.errMsg, () => {
+          fail && fail(res);
+        });
+      },
+      complete(res) {
+        wx.hideNavigationBarLoading();
+        // wx.hideLoading();
+        complete && complete(res);
+      }
+    });
+  },
+
+  /**
+   * 验证是否存在user_info
+   */
+  validateUserInfo() {
+    let user_info = wx.getStorageSync('user_info');
+    return !!wx.getStorageSync('user_info');
+  },
+
+  /**
+   * 小程序主动更新
+   */
+  updateManager() {
+    if (!wx.canIUse('getUpdateManager')) {
+      return false;
+    }
+    const updateManager = wx.getUpdateManager();
+    updateManager.onCheckForUpdate(res => {
+      // 请求完新版本信息的回调
+      // console.log(res.hasUpdate)
+    });
+    updateManager.onUpdateReady(() => {
+      wx.showModal({
+        title: '更新提示',
+        content: '新版本已经准备好,即将重启应用',
+        showCancel: false,
+        success(res) {
+          if (res.confirm) {
+            // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
+            updateManager.applyUpdate()
+          }
+        }
+      });
+    });
+    updateManager.onUpdateFailed(() => {
+      // 新的版本下载失败
+      wx.showModal({
+        title: '更新提示',
+        content: '新版本下载失败',
+        showCancel: false
+      })
+    });
+  },
+
+  /**
+   * 获取tabBar页面路径列表
+   */
+  getTabBarLinks() {
+    return tabBarLinks;
+  },
+
+  /**
+   * 跳转到指定页面
+   * 支持tabBar页面
+   */
+  navigationTo(url) {
+    if (!url || url.length == 0) {
+      return false;
+    }
+    let tabBarLinks = this.getTabBarLinks();
+    // tabBar页面
+    if (tabBarLinks.indexOf(url) > -1) {
+      wx.switchTab({
+        url: '/' + url
+      });
+    } else {
+      // 普通页面
+      wx.navigateTo({
+        url: '/' + url
+      });
+    }
+  },
+
+  /**
+   * 记录formId
+   * (因微信模板消息已下线,所以formId取消不再收集)
+   */
+  saveFormId(formId) {
+    return true;
+    // let _this = this;
+    // console.log('saveFormId');
+    // if (formId === 'the formId is a mock one') {
+    //   return false;
+    // }
+    // _this._post_form('wxapp.formId/save', {
+    //   formId: formId
+    // }, null, null, null, false);
+  },
+
+  /**
+   * 生成转发的url参数
+   */
+  getShareUrlParams(params) {
+    let _this = this;
+    return util.urlEncode(Object.assign({
+      referee_id: _this.getUserId()
+    }, params));
+  },
+
+  /**
+   * 发起微信支付
+   */
+  wxPayment(option) {
+    let options = Object.assign({
+      payment: {},
+      success: () => {},
+      fail: () => {},
+      complete: () => {},
+    }, option);
+    wx.requestPayment({
+      timeStamp: options.payment.timeStamp,
+      nonceStr: options.payment.nonceStr,
+      package: 'prepay_id=' + options.payment.prepay_id,
+      signType: 'MD5',
+      paySign: options.payment.paySign,
+      success(res) {
+        options.success(res);
+      },
+      fail(res) {
+        options.fail(res);
+      },
+      complete(res) {
+        options.complete(res);
+      }
+    });
+  },
+
+  /**
+   * 验证登录
+   */
+  checkIsLogin() {
+    return wx.getStorageSync('token') != '' && wx.getStorageSync('user_id') != '';
+  },
+
+  /**
+   * 授权登录
+   */
+  getUserInfo(userInfo, callback) {
+    let App = this;
+    wx.showLoading({
+      title: "正在登录",
+      mask: true
+    });
+    // 执行微信登录
+    wx.login({
+      success(res) {
+        // 发送用户信息
+        App._post_form('user/login', {
+          code: res.code,
+          user_info: JSON.stringify(userInfo),
+          referee_id: wx.getStorageSync('referee_id')
+        }, result => {
+          // 记录token user_id
+          wx.setStorageSync('token', result.data.token);
+          wx.setStorageSync('user_id', result.data.user_id);
+          // 执行回调函数
+          callback && callback();
+        }, false, () => {
+          wx.hideLoading();
+        });
+      }
+    });
+  },
+
+  /**
+   * 记录购物车商品总数量
+   * @param {*} value 
+   */
+  setCartTotalNum(value) {
+    wx.setStorageSync('cartTotalNum', Number(value))
+  },
+
+  /**
+   * 设置购物车tabbar的角标
+   */
+  setCartTabBadge() {
+    const number = wx.getStorageSync('cartTotalNum')
+    if (number > 0) {
+      wx.setTabBarBadge({
+        index: 2,
+        text: `${number}`
+      })
+    } else {
+      wx.removeTabBarBadge({
+        index: 2
+      })
+    }
+    return
+  }
+
+});

+ 109 - 0
app.json

@@ -0,0 +1,109 @@
+{
+  "pages": [
+    "pages/index/index",
+    "pages/custom/index",
+    "pages/category/index",
+    "pages/category/list",
+    "pages/goods/index",
+    "pages/goods/comment/comment",
+    "pages/search/index",
+    "pages/flow/index",
+    "pages/flow/checkout",
+    "pages/coupon/coupon",
+    "pages/user/index",
+    "pages/user/wallet/index",
+    "pages/user/wallet/balance/log",
+    "pages/user/recharge/index",
+    "pages/user/recharge/order/index",
+    "pages/user/coupon/coupon",
+    "pages/user/help/index",
+    "pages/order/index",
+    "pages/order/detail",
+    "pages/order/express/express",
+    "pages/order/comment/comment",
+    "pages/order/refund/index",
+    "pages/order/refund/apply/apply",
+    "pages/order/refund/detail/detail",
+    "pages/address/index",
+    "pages/address/create",
+    "pages/address/detail",
+    "pages/login/login",
+    "pages/dealer/index/index",
+    "pages/dealer/apply/apply",
+    "pages/dealer/order/order",
+    "pages/dealer/team/team",
+    "pages/dealer/withdraw/apply/apply",
+    "pages/dealer/withdraw/list/list",
+    "pages/dealer/qrcode/qrcode",
+    "pages/sharing/index/index",
+    "pages/sharing/goods/index",
+    "pages/sharing/goods/comment/comment",
+    "pages/sharing/active/index",
+    "pages/sharing/checkout/index",
+    "pages/sharing/order/index",
+    "pages/sharing/order/detail/detail",
+    "pages/sharing/order/express/express",
+    "pages/sharing/order/comment/comment",
+    "pages/sharing/order/refund/index",
+    "pages/sharing/order/refund/apply/apply",
+    "pages/sharing/order/refund/detail/detail",
+    "pages/article/index",
+    "pages/article/detail/index",
+    "pages/_select/extract_point/index",
+    "pages/shop/detail/index",
+    "pages/store/check/order",
+    "pages/bargain/index/index",
+    "pages/bargain/task/index",
+    "pages/bargain/goods/index",
+    "pages/points/log/index",
+    "pages/sharp/index/index",
+    "pages/sharp/goods/index",
+    "pages/live/index"
+  ],
+  "window": {
+    "navigationBarBackgroundColor": "#ffffff",
+    "navigationBarTitleText": "",
+    "navigationBarTextStyle": "black",
+    "backgroundTextStyle": "dark"
+  },
+  "tabBar": {
+    "color": "#6e6d6b",
+    "selectedColor": "#fd4a5f",
+    "borderStyle": "black",
+    "backgroundColor": "#ffffff",
+    "list": [
+      {
+        "pagePath": "pages/index/index",
+        "text": "首页",
+        "iconPath": "images/home.png",
+        "selectedIconPath": "images/home-active.png"
+      },
+      {
+        "pagePath": "pages/category/index",
+        "text": "分类",
+        "iconPath": "images/cate.png",
+        "selectedIconPath": "images/cate-active.png"
+      },
+      {
+        "pagePath": "pages/flow/index",
+        "text": "购物车",
+        "iconPath": "images/flow.png",
+        "selectedIconPath": "images/flow-active.png"
+      },
+      {
+        "pagePath": "pages/user/index",
+        "text": "我的",
+        "iconPath": "images/user.png",
+        "selectedIconPath": "images/user-active.png"
+      }
+    ],
+    "position": "bottom"
+  },
+  "debug": false,
+  "permission": {
+    "scope.userLocation": {
+      "desc": "你的位置信息将用于为您提供更合适您的服务"
+    }
+  },
+  "sitemapLocation": "sitemap.json"
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 295 - 0
app.wxss


+ 42 - 0
components/actionsheet/index.js

@@ -0,0 +1,42 @@
+'use strict';
+
+Component({
+  externalClasses: ['mask-class', 'container-class'],
+  properties: {
+    actions: {
+      type: Array,
+      value: []
+    },
+    show: {
+      type: Boolean,
+      value: false
+    },
+    cancelWithMask: {
+      type: Boolean,
+      value: true
+    },
+    cancelText: {
+      type: String,
+      value: ''
+    }
+  },
+  methods: {
+    onMaskClick: function onMaskClick() {
+      if (this.data.cancelWithMask) {
+        this.cancelClick();
+      }
+    },
+    cancelClick: function cancelClick() {
+      this.triggerEvent('cancel');
+    },
+    handleBtnClick: function handleBtnClick(_ref) {
+      var _ref$currentTarget = _ref.currentTarget,
+          currentTarget = _ref$currentTarget === undefined ? {} : _ref$currentTarget;
+
+      var dataset = currentTarget.dataset || {};
+      var index = dataset.index;
+
+      this.triggerEvent('actionclick', { index: index });
+    }
+  }
+});

+ 6 - 0
components/actionsheet/index.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "zan-btn": "../btn/index"
+  }
+}

+ 39 - 0
components/actionsheet/index.wxml

@@ -0,0 +1,39 @@
+<view class="zan-actionsheet {{ show ? 'zan-actionsheet--show' : '' }}">
+  <view
+    class="mask-class zan-actionsheet__mask"
+    bindtap="onMaskClick"
+  ></view>
+  <view class="container-class zan-actionsheet__container">
+    <!-- 选项按钮 -->
+    <zan-btn
+      wx:for="{{ actions }}"
+      wx:key="this"
+      bind:btnclick="handleBtnClick"
+      data-index="{{ index }}"
+      open-type="{{ item.openType }}"
+      custom-class="zan-actionsheet__btn"
+      loading="{{ item.loading }}"
+    >
+      <!-- 自定义组件控制 slot 样式有问题,故在 slot 容器上传入 loading 信息 -->
+      <view class="zan-actionsheet__btn-content {{ item.loading ? 'zan-actionsheet__btn--loading' : '' }}">
+        <view class="zan-actionsheet__name">{{ item.name }}</view>
+        <view
+          wx:if="{{ item.subname }}"
+          class="zan-actionsheet__subname">
+          {{ item.subname }}
+        </view>
+      </view>
+    </zan-btn>
+
+    <!-- 关闭按钮 -->
+    <view
+      wx:if="{{ cancelText }}"
+      class="zan-actionsheet__footer"
+    >
+      <zan-btn
+        custom-class="zan-actionsheet__btn"
+        catchtap="cancelClick"
+      >{{ cancelText }}</zan-btn>
+    </view>
+  </view>
+</view>

+ 86 - 0
components/actionsheet/index.wxss

@@ -0,0 +1,86 @@
+.zan-actionsheet {
+  background-color: #f8f8f8;
+}
+
+.zan-actionsheet__mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 10;
+  background: rgba(0, 0, 0, 0.7);
+  display: none;
+}
+
+.zan-actionsheet__container {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: #f8f8f8;
+  -webkit-transform: translate3d(0, 50%, 0);
+  transform: translate3d(0, 50%, 0);
+  -webkit-transform-origin: center;
+  transform-origin: center;
+  -webkit-transition: all 0.2s ease;
+  transition: all 0.2s ease;
+  z-index: 11;
+  opacity: 0;
+  visibility: hidden;
+}
+
+.zan-actionsheet__btn {
+  margin-bottom: 0 !important;
+}
+
+.zan-actionsheet__footer .zan-actionsheet__btn {
+  background: #fff;
+}
+
+.zan-actionsheet__btn-content {
+  display: -webkit-box;
+  display: flex;
+  -webkit-box-orient: horizontal;
+  -webkit-box-direction: normal;
+  flex-direction: row;
+  -webkit-box-pack: center;
+  justify-content: center;
+}
+
+.zan-actionsheet__subname {
+  color: #999;
+}
+
+.zan-actionsheet__name, .zan-actionsheet__subname {
+  height: 45px;
+  line-height: 45px;
+}
+
+.zan-actionsheet__btn.zan-btn:last-child::after {
+  border-bottom-width: 0;
+}
+
+.zan-actionsheet__subname {
+  margin-left: 2px;
+  font-size: 12px;
+}
+
+.zan-actionsheet__footer {
+  margin-top: 10px;
+}
+
+.zan-actionsheet__btn--loading .zan-actionsheet__subname {
+  color: transparent;
+}
+
+.zan-actionsheet--show .zan-actionsheet__container {
+  opacity: 1;
+  -webkit-transform: translate3d(0, 0, 0);
+  transform: translate3d(0, 0, 0);
+  visibility: visible;
+}
+
+.zan-actionsheet--show .zan-actionsheet__mask {
+  display: block;
+}

+ 61 - 0
components/btn/index.js

@@ -0,0 +1,61 @@
+'use strict';
+
+var nativeButtonBehavior = require('./native-button-behaviors');
+
+Component({
+  externalClasses: ['custom-class', 'theme-class'],
+  behaviors: [nativeButtonBehavior],
+  relations: {
+    '../btn-group/index': {
+      type: 'parent',
+      linked: function linked() {
+        this.setData({ inGroup: true });
+      },
+      unlinked: function unlinked() {
+        this.setData({ inGroup: false });
+      }
+    }
+  },
+  properties: {
+    type: {
+      type: String,
+      value: ''
+    },
+    size: {
+      type: String,
+      value: ''
+    },
+    plain: {
+      type: Boolean,
+      value: false
+    },
+    disabled: {
+      type: Boolean,
+      value: false
+    },
+    loading: {
+      type: Boolean,
+      value: false
+    }
+  },
+
+  data: {
+    inGroup: false,
+    isLast: false
+  },
+
+  methods: {
+    handleTap: function handleTap() {
+      if (this.data.disabled) {
+        this.triggerEvent('disabledclick');
+        return;
+      }
+      this.triggerEvent('btnclick');
+    },
+    switchLastButtonStatus: function switchLastButtonStatus() {
+      var isLast = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+
+      this.setData({ isLast: isLast });
+    }
+  }
+});

+ 3 - 0
components/btn/index.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 24 - 0
components/btn/index.wxml

@@ -0,0 +1,24 @@
+<button
+  class="custom-class theme-class zan-btn {{ inGroup ? 'zan-btn--group' : '' }} {{ isLast ? 'zan-btn--last' : '' }} {{size ? 'zan-btn--'+size : ''}} {{size === 'mini' ? 'zan-btn--plain' : ''}} {{plain ? 'zan-btn--plain' : ''}} {{type ? 'zan-btn--'+type : ''}} {{loading ? 'zan-btn--loading' : ''}} {{disabled ? 'zan-btn--disabled' : ''}}"
+  disabled="{{ disabled }}"
+  hover-class="button-hover"
+  open-type="{{ openType }}"
+  app-parameter="{{ appParameter }}"
+  hover-stop-propagation="{{ hoverStopPropagation }}"
+  hover-start-time="{{ hoverStartTime }}"
+  hover-stay-time="{{ hoverStayTime }}"
+  lang="{{ lang }}"
+  session-from="{{ sessionFrom }}"
+  send-message-title="{{ sendMessageTitle }}"
+  send-message-path="{{ sendMessagePath }}"
+  send-message-img="{{ sendMessageImg }}"
+  show-message-card="{{ showMessageCard }}"
+  bindtap="handleTap"
+  bindcontact="bindcontact"
+  bindgetuserinfo="bindgetuserinfo"
+  bindgetphonenumber="bindgetphonenumber"
+  binderror="binderror"
+  bindopensetting="bindopensetting"
+>
+  <slot></slot>
+</button>

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
components/btn/index.wxss


+ 74 - 0
components/btn/native-button-behaviors.js

@@ -0,0 +1,74 @@
+'use strict';
+
+module.exports = Behavior({
+  properties: {
+    loading: Boolean,
+    // 在自定义组件中,无法与外界的 form 组件联动,暂时不开放
+    // formType: String,
+    openType: String,
+    appParameter: String,
+    // 暂时不开放,直接传入无法设置样式
+    // hoverClass: {
+    //   type: String,
+    //   value: 'button-hover'
+    // },
+    hoverStopPropagation: Boolean,
+    hoverStartTime: {
+      type: Number,
+      value: 20
+    },
+    hoverStayTime: {
+      type: Number,
+      value: 70
+    },
+    lang: {
+      type: String,
+      value: 'en'
+    },
+    sessionFrom: {
+      type: String,
+      value: ''
+    },
+    sendMessageTitle: String,
+    sendMessagePath: String,
+    sendMessageImg: String,
+    showMessageCard: String
+  },
+  methods: {
+    bindgetuserinfo: function bindgetuserinfo() {
+      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
+          _ref$detail = _ref.detail,
+          detail = _ref$detail === undefined ? {} : _ref$detail;
+
+      this.triggerEvent('getuserinfo', detail);
+    },
+    bindcontact: function bindcontact() {
+      var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
+          _ref2$detail = _ref2.detail,
+          detail = _ref2$detail === undefined ? {} : _ref2$detail;
+
+      this.triggerEvent('contact', detail);
+    },
+    bindgetphonenumber: function bindgetphonenumber() {
+      var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
+          _ref3$detail = _ref3.detail,
+          detail = _ref3$detail === undefined ? {} : _ref3$detail;
+
+      this.triggerEvent('getphonenumber', detail);
+    },
+    bindopensetting: function bindopensetting() {
+      var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
+          _ref4$detail = _ref4.detail,
+          detail = _ref4$detail === undefined ? {} : _ref4$detail;
+
+      this.triggerEvent('opensetting', detail);
+    },
+    binderror: function binderror() {
+      var _ref5 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
+          _ref5$detail = _ref5.detail,
+          detail = _ref5$detail === undefined ? {} : _ref5$detail;
+
+      this.triggerEvent('error', detail);
+    }
+  }
+});

+ 3 - 0
components/common/color.js

@@ -0,0 +1,3 @@
+export const RED = '#f44';
+export const BLUE = '#1989fa';
+export const GREEN = '#07c160';

+ 48 - 0
components/common/component.js

@@ -0,0 +1,48 @@
+import { basic } from '../mixins/basic';
+import { observe } from '../mixins/observer/index';
+function mapKeys(source, target, map) {
+    Object.keys(map).forEach(key => {
+        if (source[key]) {
+            target[map[key]] = source[key];
+        }
+    });
+}
+function VantComponent(vantOptions = {}) {
+    const options = {};
+    mapKeys(vantOptions, options, {
+        data: 'data',
+        props: 'properties',
+        mixins: 'behaviors',
+        methods: 'methods',
+        beforeCreate: 'created',
+        created: 'attached',
+        mounted: 'ready',
+        relations: 'relations',
+        destroyed: 'detached',
+        classes: 'externalClasses'
+    });
+    const { relation } = vantOptions;
+    if (relation) {
+        options.relations = Object.assign(options.relations || {}, {
+            [`../${relation.name}/index`]: relation
+        });
+    }
+    // add default externalClasses
+    options.externalClasses = options.externalClasses || [];
+    options.externalClasses.push('custom-class');
+    // add default behaviors
+    options.behaviors = options.behaviors || [];
+    options.behaviors.push(basic);
+    // map field to form-field behavior
+    if (vantOptions.field) {
+        options.behaviors.push('wx://form-field');
+    }
+    // add default options
+    options.options = {
+        multipleSlots: true,
+        addGlobalClass: true
+    };
+    observe(vantOptions, options);
+    Component(options);
+}
+export { VantComponent };

+ 1 - 0
components/common/index.wxss

@@ -0,0 +1 @@
+.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical}.van-clearfix::after{content:'';display:table;clear:both}.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom::after,.van-hairline--left::after,.van-hairline--right::after,.van-hairline--surround::after,.van-hairline--top-bottom::after,.van-hairline--top::after,.van-hairline::after{content:' ';position:absolute;pointer-events:none;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;top:-50%;left:-50%;right:-50%;bottom:-50%;-webkit-transform:scale(.5);transform:scale(.5);border:0 solid #eee}.van-hairline--top::after{border-top-width:1px}.van-hairline--left::after{border-left-width:1px}.van-hairline--right::after{border-right-width:1px}.van-hairline--bottom::after{border-bottom-width:1px}.van-hairline--top-bottom::after{border-width:1px 0}.van-hairline--surround::after{border-width:1px}

+ 1 - 0
components/common/style/clearfix.wxss

@@ -0,0 +1 @@
+.van-clearfix::after{content:'';display:table;clear:both}

+ 1 - 0
components/common/style/ellipsis.wxss

@@ -0,0 +1 @@
+.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical}

+ 1 - 0
components/common/style/hairline.wxss

@@ -0,0 +1 @@
+.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom::after,.van-hairline--left::after,.van-hairline--right::after,.van-hairline--surround::after,.van-hairline--top-bottom::after,.van-hairline--top::after,.van-hairline::after{content:' ';position:absolute;pointer-events:none;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;top:-50%;left:-50%;right:-50%;bottom:-50%;-webkit-transform:scale(.5);transform:scale(.5);border:0 solid #eee}.van-hairline--top::after{border-top-width:1px}.van-hairline--left::after{border-left-width:1px}.van-hairline--right::after{border-right-width:1px}.van-hairline--bottom::after{border-bottom-width:1px}.van-hairline--top-bottom::after{border-width:1px 0}.van-hairline--surround::after{border-width:1px}

+ 0 - 0
components/common/style/mixins/clearfix.wxss


+ 0 - 0
components/common/style/mixins/ellipsis.wxss


+ 0 - 0
components/common/style/mixins/hairline.wxss


+ 0 - 0
components/common/style/var.wxss


+ 14 - 0
components/common/utils.js

@@ -0,0 +1,14 @@
+function isDef(value) {
+    return value !== undefined && value !== null;
+}
+function isObj(x) {
+    const type = typeof x;
+    return x !== null && (type === 'object' || type === 'function');
+}
+function isNumber(value) {
+    return /^\d+$/.test(value);
+}
+function range(num, min, max) {
+    return Math.min(Math.max(num, min), max);
+}
+export { isObj, isDef, isNumber, range };

+ 130 - 0
components/countdown/index.js

@@ -0,0 +1,130 @@
+import util from '../../utils/util'
+
+Component({
+  properties: {
+    // useSlot: Boolean,
+    // 截止的时间
+    date: String,
+    // 分隔符, colon为英文冒号,zh为中文
+    separator: {
+      type: String,
+      value: 'zh'
+    },
+    // 组件样式, text为纯文本,custom为带背景色
+    style: {
+      type: String,
+      value: 'text'
+    },
+  },
+
+  data: {
+    // 倒计时数据
+    dynamic: {
+      day: '00',
+      hou: '00',
+      min: '00',
+      sec: '00'
+    },
+    // 分隔符文案
+    separatorText: {
+      day: '天',
+      hou: '时',
+      min: '分',
+      sec: '秒'
+    }
+  },
+
+  attached() {
+    // 分隔符文案
+    this.separatorText()
+    // 开始倒计时
+    this.onTime()
+  },
+
+  detached() {
+
+  },
+
+
+  methods: {
+
+    // 分隔符文案
+    separatorText() {
+      const separatorText = this.data.separatorText
+      if (this.data.separator === 'colon') {
+        separatorText.day = ':'
+        separatorText.hou = ':'
+        separatorText.min = ':'
+        separatorText.sec = ''
+      }
+      this.setData({
+        separatorText
+      })
+    },
+
+    // 开始倒计时
+    onTime(deep = 0) {
+      const app = this
+      const dynamic = {}
+
+      // 获取当前时间,同时得到活动结束时间数组
+      const newTime = new Date().getTime()
+      // 对结束时间进行处理渲染到页面
+      const endTime = new Date(util.format_date(app.data.date)).getTime();
+
+      // 如果活动未结束,对时间进行处理
+      if ((endTime - newTime) <= 0) {
+        return false
+      }
+
+      const diffTime = (endTime - newTime) / 1000;
+      // 获取时、分、秒
+      const day = parseInt(diffTime / 86400),
+        hou = parseInt(diffTime % 86400 / 3600),
+        min = parseInt(diffTime % 86400 % 3600 / 60),
+        sec = parseInt(diffTime % 86400 % 3600 % 60);
+      dynamic.day = app.timeFormat(day)
+      dynamic.hou = app.timeFormat(hou)
+      dynamic.min = app.timeFormat(min)
+      dynamic.sec = app.timeFormat(sec)
+
+      // 渲染,然后每隔一秒执行一次倒计时函数
+      app.setData({
+        dynamic
+      })
+      // 判断倒计时是否结束
+      const isEnd = app.isEnd()
+      // 结束后执行回调函数
+      if (isEnd) {
+        deep > 0 && app.triggerEvent('finish')
+      }
+      // 重复执行
+      if (!isEnd) {
+        setTimeout(() => {
+          app.onTime(++deep)
+        }, 1000)
+      }
+    },
+
+    // 判断倒计时是否结束
+    isEnd() {
+      const {
+        dynamic
+      } = this.data
+      if (dynamic.day == '00' && dynamic.hou == '00' && dynamic.min == '00' && dynamic.sec == '00') {
+        return true
+      }
+      return false
+    },
+
+    /**
+     * 小于10的格式化函数
+     */
+    timeFormat(value) {
+      return value < 10 ? '0' + value : value
+    }
+
+
+
+  }
+})

+ 3 - 0
components/countdown/index.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 15 - 0
components/countdown/index.wxml

@@ -0,0 +1,15 @@
+<view wx:if="{{ date }}" class="count-down">
+  <!-- <slot wx:if="{{ useSlot }}" /> -->
+  <view class="{{ style }}-style separator-{{ separator }}">
+    <block wx:if="{{ dynamic.day != '00' }}">
+      <text class="dynamic-value">{{ dynamic.day }}</text>
+      <text class="separator">{{ separatorText.day }}</text>
+    </block>
+    <text class="dynamic-value">{{ dynamic.hou }}</text>
+    <text class="separator">{{ separatorText.hou }}</text>
+    <text class="dynamic-value">{{ dynamic.min }}</text>
+    <text class="separator">{{ separatorText.min }}</text>
+    <text class="dynamic-value">{{ dynamic.sec }}</text>
+    <text class="separator">{{ separatorText.sec }}</text>
+  </view>
+</view>

+ 33 - 0
components/countdown/index.wxss

@@ -0,0 +1,33 @@
+.item {
+  display: inline-block;
+  width: 22px;
+  margin-right: 5px;
+  color: #fff;
+  font-size: 12px;
+  text-align: center;
+  background-color: #1989fa;
+  border-radius: 2px;
+}
+
+.separator {
+  padding: 0 2rpx;
+}
+
+/* 冒号分隔符 */
+.text-style.separator-colon .separator {
+  padding: 0 5rpx;
+}
+
+
+/* 带背景的样式 */
+.custom-style .dynamic-value {
+  background: #252525;
+  color: #fff;
+  padding: 0 8rpx;
+  line-height: 40rpx;
+  border-radius: 8rpx;
+}
+
+.custom-style .separator {
+  padding: 0 7rpx;
+}

+ 26 - 0
components/dialog/data.js

@@ -0,0 +1,26 @@
+'use strict';
+
+module.exports = {
+  // 标题
+  title: '',
+  // 内容
+  message: ' ',
+  // 选择节点
+  selector: '#zan-dialog',
+  // 按钮是否展示为纵向
+  buttonsShowVertical: false,
+  // 是否展示确定
+  showConfirmButton: true,
+  // 确认按钮文案
+  confirmButtonText: '确定',
+  // 确认按钮颜色
+  confirmButtonColor: '#3CC51F',
+  // 是否展示取消
+  showCancelButton: false,
+  // 取消按钮文案
+  cancelButtonText: '取消',
+  // 取消按钮颜色
+  cancelButtonColor: '#333',
+  // 点击按钮自动关闭 dialog
+  autoClose: true
+};

+ 104 - 0
components/dialog/dialog.js

@@ -0,0 +1,104 @@
+'use strict';
+
+var defaultData = require('./data');
+
+function getDialogCtx(_ref) {
+  var selector = _ref.selector,
+      pageCtx = _ref.pageCtx;
+
+  var ctx = pageCtx;
+  if (!ctx) {
+    var pages = getCurrentPages();
+    ctx = pages[pages.length - 1];
+  }
+  return ctx.selectComponent(selector);
+}
+
+function getParsedOptions() {
+  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+  return Object.assign({
+    // 自定义 btn 列表
+    // { type: 按钮类型,回调时以此作为区分依据,text: 按钮文案, color: 按钮文字颜色 }
+    buttons: []
+  }, defaultData, options);
+}
+
+// options 使用参数
+// pageCtx 页面 page 上下文
+function Dialog(options, pageCtx) {
+  var parsedOptions = getParsedOptions(options);
+
+  var dialogCtx = getDialogCtx({
+    selector: parsedOptions.selector,
+    pageCtx: pageCtx
+  });
+
+  if (!dialogCtx) {
+    console.error('无法找到对应的dialog组件,请于页面中注册并在 wxml 中声明 dialog 自定义组件');
+    return Promise.reject({ type: 'component error' });
+  }
+
+  // 处理默认按钮的展示
+  // 纵向排布确认按钮在上方
+  var _parsedOptions$button = parsedOptions.buttons,
+      buttons = _parsedOptions$button === undefined ? [] : _parsedOptions$button;
+
+  var showCustomBtns = false;
+  if (buttons.length === 0) {
+    if (parsedOptions.showConfirmButton) {
+      buttons.push({
+        type: 'confirm',
+        text: parsedOptions.confirmButtonText,
+        color: parsedOptions.confirmButtonColor
+      });
+    }
+
+    if (parsedOptions.showCancelButton) {
+      var cancelButton = {
+        type: 'cancel',
+        text: parsedOptions.cancelButtonText,
+        color: parsedOptions.cancelButtonColor
+      };
+      if (parsedOptions.buttonsShowVertical) {
+        buttons.push(cancelButton);
+      } else {
+        buttons.unshift(cancelButton);
+      }
+    }
+  } else {
+    showCustomBtns = true;
+  }
+
+  return new Promise(function (resolve, reject) {
+    dialogCtx.setData(Object.assign({}, parsedOptions, {
+      buttons: buttons,
+      showCustomBtns: showCustomBtns,
+      key: '' + new Date().getTime(),
+      show: true,
+      promiseFunc: { resolve: resolve, reject: reject },
+      openTypePromiseFunc: null
+    }));
+  });
+}
+
+Dialog.close = function (options, pageCtx) {
+  var parsedOptions = getParsedOptions(options);
+
+  var dialogCtx = getDialogCtx({
+    selector: parsedOptions.selector,
+    pageCtx: pageCtx
+  });
+
+  if (!dialogCtx) {
+    return;
+  }
+
+  dialogCtx.setData({
+    show: false,
+    promiseFunc: null,
+    openTypePromiseFunc: null
+  });
+};
+
+module.exports = Dialog;

+ 148 - 0
components/dialog/index.js

@@ -0,0 +1,148 @@
+'use strict';
+
+var _f = function _f() {};
+var needResponseOpenTypes = ['getUserInfo', 'getPhoneNumber', 'openSetting'];
+
+Component({
+  properties: {},
+
+  data: {
+    // 标题
+    title: '',
+    // 自定义 btn 列表
+    // { type: 按钮类型,回调时以此作为区分依据,text: 按钮文案, color: 按钮文字颜色, openType: 微信开放能力 }
+    buttons: [],
+    // 内容
+    message: ' ',
+    // 选择节点
+    selector: '#zan-dialog',
+    // 是否允许滚动
+    isScroll: false,
+    // 按钮是否展示为纵向
+    buttonsShowVertical: false,
+    // 是否展示确定
+    showConfirmButton: true,
+    // 确认按钮文案
+    confirmButtonText: '确定',
+    // 确认按钮颜色
+    confirmButtonColor: '#3CC51F',
+    // 是否展示取消
+    showCancelButton: false,
+    // 取消按钮文案
+    cancelButtonText: '取消',
+    // 取消按钮颜色
+    cancelButtonColor: '#333',
+    key: '',
+    autoClose: true,
+    show: false,
+    showCustomBtns: false,
+    promiseFunc: {},
+    openTypePromiseFunc: {}
+  },
+
+  methods: {
+    handleButtonClick: function handleButtonClick(e) {
+      var _this = this;
+
+      var _e$currentTarget = e.currentTarget,
+        currentTarget = _e$currentTarget === undefined ? {} : _e$currentTarget;
+      var _currentTarget$datase = currentTarget.dataset,
+        dataset = _currentTarget$datase === undefined ? {} : _currentTarget$datase;
+
+      // 获取当次弹出框的信息
+
+      var _ref = this.data.promiseFunc || {},
+        _ref$resolve = _ref.resolve,
+        resolve = _ref$resolve === undefined ? _f : _ref$resolve,
+        _ref$reject = _ref.reject,
+        reject = _ref$reject === undefined ? _f : _ref$reject;
+
+      // 重置展示
+
+
+      if (this.data.autoClose) {
+        this.setData({
+          show: false
+        });
+      }
+
+      // 自定义按钮,全部 resolve 形式返回,根据 type 区分点击按钮
+      if (this.data.showCustomBtns) {
+        var isNeedOpenDataButton = needResponseOpenTypes.indexOf(dataset.openType) > -1;
+        var resolveData = {
+          type: dataset.type
+        };
+        // 如果需要 openData,就额外返回一个 promise,用于后续 open 数据返回
+        if (isNeedOpenDataButton) {
+          resolveData.openDataPromise = new Promise(function(resolve, reject) {
+            _this.setData({
+              openTypePromiseFunc: {
+                resolve: resolve,
+                reject: reject
+              }
+            });
+          });
+          resolveData.hasOpenDataPromise = true;
+        }
+        resolve(resolveData);
+        return;
+      }
+
+      // 默认按钮,确认为 resolve,取消为 reject
+      if (dataset.type === 'confirm') {
+        resolve({
+          type: 'confirm'
+        });
+      } else {
+        reject({
+          type: 'cancel'
+        });
+      }
+
+      this.setData({
+        promiseFunc: {}
+      });
+    },
+
+
+    // 以下为处理微信按钮开放能力的逻辑
+    handleUserInfoResponse: function handleUserInfoResponse(_ref2) {
+      var detail = _ref2.detail;
+
+      this.__handleOpenDataResponse({
+        type: detail.errMsg === 'getUserInfo:ok' ? 'resolve' : 'reject',
+        data: detail
+      });
+    },
+    handlePhoneResponse: function handlePhoneResponse(_ref3) {
+      var detail = _ref3.detail;
+
+      this.__handleOpenDataResponse({
+        type: detail.errMsg === 'getPhoneNumber:ok' ? 'resolve' : 'reject',
+        data: detail
+      });
+    },
+    handleOpenSettingResponse: function handleOpenSettingResponse(_ref4) {
+      var detail = _ref4.detail;
+
+      this.__handleOpenDataResponse({
+        type: detail.errMsg === 'openSetting:ok' ? 'resolve' : 'reject',
+        data: detail
+      });
+    },
+    __handleOpenDataResponse: function __handleOpenDataResponse(_ref5) {
+      var _ref5$type = _ref5.type,
+        type = _ref5$type === undefined ? 'resolve' : _ref5$type,
+        _ref5$data = _ref5.data,
+        data = _ref5$data === undefined ? {} : _ref5$data;
+
+      var promiseFuncs = this.data.openTypePromiseFunc || {};
+      var responseFunc = promiseFuncs[type] || _f;
+
+      responseFunc(data);
+      this.setData({
+        openTypePromiseFunc: null
+      });
+    }
+  }
+});

+ 7 - 0
components/dialog/index.json

@@ -0,0 +1,7 @@
+{
+  "component": true,
+  "usingComponents": {
+    "pop-manager": "../pop-manager/index",
+    "zan-button": "../btn/index"
+  } 
+}

+ 18 - 0
components/dialog/index.wxml

@@ -0,0 +1,18 @@
+<pop-manager show="{{ show }}" type="center">
+  <view class="zan-dialog--container">
+    <view wx:if="{{ title }}" class="zan-dialog__header">{{ title }}</view>
+    <view class="zan-dialog__content {{ title ? 'zan-dialog__content--title' : '' }}">
+      <scroll-view class="zan-dialog__content--scroll" scroll-y="{{ isScroll }}">
+        <text>{{ message }}</text>
+      </scroll-view>
+    </view>
+    <view class="zan-dialog__footer {{ buttonsShowVertical ? 'zan-dialog__footer--vertical' : 'zan-dialog__footer--horizon' }}">
+      <block wx:for="{{ buttons }}" wx:key="this">
+        <zan-button class="zan-dialog__button" custom-class="{{ index === 0 ? 'zan-dialog__button-inside--first' : 'zan-dialog__button-inside' }}" data-type="{{ item.type }}" data-open-type="{{ item.openType }}" open-type="{{ item.openType }}" bind:btnclick="handleButtonClick"
+          bind:getuserinfo="handleUserInfoResponse" bind:getphonenumber="handlePhoneResponse" bind:opensetting="handleOpenSettingResponse">
+          <view style="color: {{ item.color || '#333' }}">{{ item.text }}</view>
+        </zan-button>
+      </block>
+    </view>
+  </view>
+</pop-manager>

+ 79 - 0
components/dialog/index.wxss

@@ -0,0 +1,79 @@
+.zan-dialog--container {
+  width: 80vw;
+  font-size: 16px;
+  overflow: hidden;
+  border-radius: 4px;
+  background-color: #fff;
+  color: #333;
+}
+
+.zan-dialog__header {
+  padding: 15px 0 0;
+  text-align: center;
+}
+
+.zan-dialog__content {
+  position: relative;
+  padding: 15px 20px;
+  line-height: 1.5;
+  min-height: 40px;
+}
+
+.zan-dialog__content::after {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 200%;
+  height: 200%;
+  -webkit-transform: scale(0.5);
+  transform: scale(0.5);
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  pointer-events: none;
+  box-sizing: border-box;
+  border: 0 solid #e5e5e5;
+  border-bottom-width: 1px;
+}
+
+.zan-dialog__content--title {
+  color: #999;
+  font-size: 14px;
+}
+
+.zan-dialog__content--scroll {
+  max-height: 70vh;
+}
+
+.zan-dialog__footer {
+  overflow: hidden;
+}
+
+.zan-dialog__button {
+  -webkit-box-flex: 1;
+  flex: 1;
+}
+
+.zan-dialog__button-inside, .zan-dialog__button-inside--first {
+  margin-bottom: 0;
+  line-height: 50px;
+  height: 50px;
+}
+
+.zan-dialog__button-inside--first::after, .zan-dialog__button-inside::after {
+  border-width: 0;
+  border-radius: 0;
+}
+
+.zan-dialog__footer--horizon {
+  display: -webkit-box;
+  display: flex;
+}
+
+.zan-dialog__footer--horizon .zan-dialog__button-inside::after {
+  border-left-width: 1px;
+}
+
+.zan-dialog__footer--vertical .zan-dialog__button-inside::after {
+  border-top-width: 1px;
+}

+ 35 - 0
components/diy/article/article.js

@@ -0,0 +1,35 @@
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    // itemStyle: Object,
+    params: Object,
+    dataList: Object
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 跳转文章详情页
+     */
+    onTargetDetail(e) {
+      wx.navigateTo({
+        url: '/pages/article/detail/index?article_id=' + e.currentTarget.dataset.id
+      });
+    },
+
+  }
+
+})

+ 3 - 0
components/diy/article/article.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 31 - 0
components/diy/article/article.wxml

@@ -0,0 +1,31 @@
+<!-- 文章组 -->
+<view class="diy-article">
+  <view class="article-item show-type__{{ item.show_type }}" wx:for="{{ dataList }}" wx:key="this" catchtap="onTargetDetail" data-id="{{ item.article_id }}">
+    <!-- 小图模式 -->
+    <block wx:if="{{ item.show_type == 10 }}">
+      <view class="article-item__left flex-box">
+        <view class="article-item__title twolist-hidden">
+          <text class="f-30 col-3">{{ item.article_title }}</text>
+        </view>
+        <view class="article-item__footer m-top10">
+          <text class="article-views f-24 col-8">{{ item.show_views }}次浏览</text>
+        </view>
+      </view>
+      <view class="article-item__image">
+        <image class="image" mode="widthFix" src="{{ item.image.file_path }}"></image>
+      </view>
+    </block>
+    <!-- 大图模式 -->
+    <block wx:if="{{ item.show_type == 20 }}">
+      <view class="article-item__title">
+        <text class="f-30 col-3">{{ item.article_title }}</text>
+      </view>
+      <view class="article-item__image m-top20">
+        <image class="image" mode="widthFix" src="{{ item.image.file_path }}"></image>
+      </view>
+      <view class="article-item__footer m-top10">
+        <text class="article-views f-24 col-8">{{ item.show_views }}次浏览</text>
+      </view>
+    </block>
+  </view>
+</view>

+ 46 - 0
components/diy/article/article.wxss

@@ -0,0 +1,46 @@
+/* common.wxss */
+/* @import "/utils/common.wxss"; */
+
+/* 文章组 */
+
+.diy-article {
+  background: #f7f7f7;
+}
+
+.diy-article .article-item {
+  margin-bottom: 20rpx;
+  padding: 30rpx;
+  background: #fff;
+}
+
+.diy-article .article-item:last-child {
+  margin-bottom: 0;
+}
+
+.diy-article .article-item .article-item__image .image {
+  display: block;
+}
+
+/* 小图模式 */
+
+.show-type__10 {
+  display: flex;
+}
+
+.show-type__10 .article-item__left {
+  padding-right: 20rpx;
+}
+
+.show-type__10 .article-item__title {
+  min-height: 72rpx;
+}
+
+.show-type__10 .article-item__image .image {
+  width: 240rpx;
+}
+
+/* 大图模式 */
+
+.show-type__20 .article-item__image .image {
+  width: 100%;
+}

+ 77 - 0
components/diy/banner/banner.js

@@ -0,0 +1,77 @@
+const App = getApp();
+
+Component({
+
+  options: {
+
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    dataList: Object,
+    params: Object
+  },
+
+  /**
+   * 私有数据,组件的初始数据
+   * 可用于模版渲染
+   */
+  data: {
+    // banner轮播组件属性
+    indicatorDots: true, // 是否显示面板指示点	
+    autoplay: true, // 是否自动切换
+    duration: 800, // 滑动动画时长
+
+    imgHeights: [], // 图片的高度
+    imgCurrent: 0, // 当前banne所在滑块指针
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 计算图片高度
+     */
+    _imagesHeight: function(e) {
+      // 获取图片真实宽度
+      let imgwidth = e.detail.width,
+        imgheight = e.detail.height,
+        // 宽高比
+        ratio = imgwidth / imgheight;
+      // 计算的高度值
+      let viewHeight = 750 / ratio,
+        imgHeights = this.data.imgHeights;
+      // 把每一张图片的高度记录到数组里
+      imgHeights.push(viewHeight);
+      this.setData({
+        imgHeights,
+      });
+    },
+
+    /**
+     * 记录当前指针
+     */
+    _bindChange: function(e) {
+      this.setData({
+        imgCurrent: e.detail.current
+      });
+    },
+
+    /**
+     * 跳转到指定页面
+     */
+    navigationTo: function(e) {
+      App.navigationTo(e.currentTarget.dataset.url);
+    },
+
+  }
+
+})

+ 3 - 0
components/diy/banner/banner.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 11 - 0
components/diy/banner/banner.wxml

@@ -0,0 +1,11 @@
+<!-- banner轮播 -->
+<view class="diy-banner">
+  <swiper autoplay="{{ autoplay }}" class="banner-box swiper-box dot-{{ itemStyle.btnShape }}" duration="{{ duration }}" circular="{{ true }}" indicator-dots="{{ indicatorDots }}" interval="{{ params.interval }}" indicator-color="{{ itemStyle.btnColor }}" indicator-active-color="#000"
+    bindchange="_bindChange" data-item-key="{{ itemIndex }}" style="height: {{ imgHeights[imgCurrent] }}rpx">
+    <swiper-item wx:for-item="banner" wx:for="{{dataList}}" wx:key="this">
+      <image mode="widthFix" catchtap="navigationTo" data-url="{{ banner.linkUrl }}" class="slide-image" bindload="_imagesHeight" src="{{banner.imgUrl}}" data-id="{{index}}" data-item-key="{{ itemIndex }}"></image>
+    </swiper-item>
+  </swiper>
+  <!-- 顶部置灰 -->
+  <!-- <view class="linear"></view>  -->
+</view>

+ 45 - 0
components/diy/banner/banner.wxss

@@ -0,0 +1,45 @@
+/* banner轮播 */
+
+.diy-banner {
+  position: relative;
+}
+
+.diy-banner .slide-image {
+  width: 100%;
+  height: 100%;
+  margin: 0 auto;
+  display: block;
+}
+
+/* 顶部置灰 */
+
+.diy-banner .linear {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 3.4rem;
+  background: linear-gradient(#111, transparent);
+  opacity: 0.6;
+  z-index: 9;
+}
+
+.swiper-box .wx-swiper-dots.wx-swiper-dots-horizontal {
+  margin-bottom: 2rpx;
+}
+
+/* banner组件按钮 */
+
+.swiper-box .wx-swiper-dot {
+  height: 20rpx;
+  width: 20rpx;
+}
+
+.swiper-box.dot-rectangle .wx-swiper-dot {
+  width: 30rpx;
+  border-radius: unset;
+}
+
+.swiper-box.dot-square .wx-swiper-dot {
+  border-radius: unset;
+}

+ 36 - 0
components/diy/bargainGoods/index.js

@@ -0,0 +1,36 @@
+const App = getApp();
+
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object,
+    dataList: Object
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 跳转商品详情页
+     */
+    _onTargetGoods(e) {
+      wx.navigateTo({
+        url: `/pages/bargain/goods/index?active_id=${e.detail.target.dataset.id}`,
+      });
+    },
+  }
+
+})

+ 3 - 0
components/diy/bargainGoods/index.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 47 - 0
components/diy/bargainGoods/index.wxml

@@ -0,0 +1,47 @@
+<!-- 商品组 -->
+<view class="diy-bargainGoods" style="background: {{ itemStyle.background }};">
+  <view class="goods-item dis-flex" wx:for="{{ dataList }}" wx:key="this" wx:for-item="dataItem">
+    <form bindsubmit="_onTargetGoods" report-submit="true">
+      <button formType="submit" class="btn-normal dis-flex" data-id="{{ dataItem.active_id }}">
+        <view class="goods-item--container dis-flex">
+          <!-- 商品图片 -->
+          <view class="goods-image">
+            <image class="image" src="{{ dataItem.goods_image }}"></image>
+          </view>
+          <view class="goods-info">
+            <!-- 商品名称 -->
+            <view class="goods-name">
+              <text class="twolist-hidden">{{ dataItem.goods_name }}</text>
+            </view>
+            <!-- 参与的用户头像 -->
+            <view wx:if="{{ dataItem.helps_count > 0 }}" class="peoples dis-flex">
+              <view class="user-list dis-flex">
+                <view wx:for="{{ dataItem.helps }}" wx:for-item="help" wx:key="this" class="user-item-avatar">
+                  <image class="image" src="{{ help.user.avatarUrl }}"></image>
+                </view>
+              </view>
+              <view class="people__text">
+                <text>{{ dataItem.helps_count }}人正在砍价</text>
+              </view>
+            </view>
+            <!-- 商品原价 -->
+            <view class="goods-price">
+              <text>¥{{ dataItem.original_price }}</text>
+            </view>
+            <!-- 砍价低价 -->
+            <view class="floor-price">
+              <text class="small">最低¥</text>
+              <text class="big">{{ dataItem.floor_price }}</text>
+            </view>
+            <!-- 操作按钮 -->
+            <view class="opt-touch">
+              <view class="touch-btn">
+                <text>立即参加</text>
+              </view>
+            </view>
+          </view>
+        </view>
+      </button>
+    </form>
+  </view>
+</view>

+ 100 - 0
components/diy/bargainGoods/index.wxss

@@ -0,0 +1,100 @@
+/* common.wxss */
+
+/* 砍价商品 */
+
+.goods-item {
+  margin-bottom: 20rpx;
+  background: #fff;
+  padding: 20rpx 16rpx;
+}
+
+.goods-item:last-child {
+  margin-bottom: 0;
+}
+
+.goods-item .goods-image .image {
+  display: block;
+  width: 220rpx;
+  height: 220rpx;
+}
+
+.goods-item .goods-info {
+  width: 498rpx;
+  padding-top: 8rpx;
+  margin-left: 15rpx;
+  position: relative;
+}
+
+.goods-item .goods-info .goods-name {
+  font-size: 28rpx;
+  min-height: 60rpx;
+}
+
+/* 正在参与的用户 */
+
+.goods-item .goods-info .peoples {
+  margin-top: 15rpx;
+}
+
+.goods-item .goods-info .peoples .user-list {
+  margin-right: 10rpx;
+}
+
+.goods-item .goods-info .peoples .user-list .user-item-avatar {
+  margin-left: -8rpx;
+}
+
+.goods-item .goods-info .peoples .user-list .user-item-avatar:first-child {
+  margin-left: 0;
+}
+
+.goods-item .goods-info .peoples .user-list .user-item-avatar .image {
+  display: block;
+  width: 36rpx;
+  height: 36rpx;
+  border-radius: 50%;
+}
+
+.goods-item .goods-info .peoples .people__text {
+  font-size: 24rpx;
+  color: #818181;
+}
+
+/* 商品原价 */
+
+.goods-item .goods-info .goods-price {
+  margin-top: 15rpx;
+  color: #818181;
+  font-size: 25rpx;
+  text-decoration: line-through;
+}
+
+/* 砍价底价 */
+
+.goods-item .goods-info .floor-price {
+  color: #fc1e56;
+}
+
+.goods-item .goods-info .floor-price .small {
+  font-size: 24rpx;
+}
+
+.goods-item .goods-info .floor-price .big {
+  font-size: 32rpx;
+}
+
+/* 立即参加按钮 */
+
+.opt-touch {
+  position: absolute;
+  bottom: 0;
+  right: 10rpx;
+}
+
+.touch-btn {
+  color: #fff;
+  font-size: 28rpx;
+  background: #d3a975;
+  border-radius: 30rpx;
+  padding: 10rpx 28rpx;
+}

+ 16 - 0
components/diy/blank/blank.js

@@ -0,0 +1,16 @@
+Component({
+
+  options: {
+
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object
+  },
+
+})

+ 3 - 0
components/diy/blank/blank.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 3 - 0
components/diy/blank/blank.wxml

@@ -0,0 +1,3 @@
+<!-- 辅助空白 -->
+<view class="diy-blank" style="height: {{ itemStyle.height }}px; background: {{ itemStyle.background }};">
+</view>

+ 1 - 0
components/diy/blank/blank.wxss

@@ -0,0 +1 @@
+/* 辅助空白 */

+ 45 - 0
components/diy/coupon/coupon.js

@@ -0,0 +1,45 @@
+const App = getApp();
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object,
+    dataList: Object
+  },
+
+  methods: {
+
+    /**
+     * 领取优惠券
+     */
+    receiveTap: function(e) {
+      let _this = this,
+        dataset = e.currentTarget.dataset;
+      if (!dataset.state) {
+        return false;
+      }
+      App._post_form('user.coupon/receive', {
+        coupon_id: dataset.couponId
+      }, function(result) {
+        App.showSuccess(result.msg);
+        _this.setData({
+          ['dataList[' + dataset.index + '].state']: {
+            value: 0,
+            text: '已领取'
+          }
+        });
+      });
+    }
+
+  }
+
+})

+ 3 - 0
components/diy/coupon/coupon.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 33 - 0
components/diy/coupon/coupon.wxml

@@ -0,0 +1,33 @@
+<!-- 优惠券组 -->
+<view class="diy-coupon" wx:if="{{ dataList.length }}" style="background: {{ itemStyle.background }}; padding: {{ itemStyle.paddingTop }}px 0;">
+
+  <scroll-view scroll-x="{{ true }}">
+    <view class="coupon-wrapper" wx:for="{{ dataList }}" wx:key="this" wx:for-item="dataItem">
+      <view class="coupon-item color__{{ dataItem.state.value ? dataItem.color.text : 'gray' }}">
+        <i class="before" style="background: {{ itemStyle.background }};"></i>
+        <view class="left-content dis-flex flex-dir-column flex-x-center flex-y-center">
+          <view class="content-top">
+            <block wx:if="{{ dataItem.coupon_type.value == 10 }}">
+              <text class="f-30">¥</text>
+              <text class="price">{{ dataItem.reduce_price }}</text>
+            </block>
+            <text class="price" wx:if="{{ dataItem.coupon_type.value == 20 }}">{{ dataItem.discount }}折</text>
+          </view>
+          <view class="content-bottom">
+            <text class="f-22">满{{ dataItem.min_price }}元可用</text>
+          </view>
+        </view>
+        <view class="right-receive dis-flex flex-x-center flex-y-center" catchtap="receiveTap" data-index="{{ index }}" data-state="{{ dataItem.state.value }}" data-coupon-id="{{ dataItem.coupon_id }}">
+          <view wx:if="{{ dataItem.state.value }}" class="dis-flex flex-dir-column">
+            <text>立即</text>
+            <text>领取</text>
+          </view>
+          <view wx:else class="state">
+            <text>{{ dataItem.state.text }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+  </scroll-view>
+
+</view>

+ 85 - 0
components/diy/coupon/coupon.wxss

@@ -0,0 +1,85 @@
+/* common.wxss */
+
+/* @import "/utils/common.wxss"; */
+
+.diy-coupon {
+  white-space: nowrap;
+  font-size: 0;
+}
+
+.diy-coupon .coupon-item {
+  width: 350rpx;
+  height: 130rpx;
+  position: relative;
+  color: #fff;
+  overflow: hidden;
+  box-sizing: border-box;
+}
+
+.diy-coupon .coupon-item .before {
+  content: "";
+  position: absolute;
+  z-index: 1;
+  width: 40rpx;
+  height: 40rpx;
+  top: 50%;
+  left: -.8rem;
+  -webkit-transform: translateY(-50%);
+  transform: translateY(-50%);
+  -webkit-border-radius: 80%;
+  border-radius: 80%;
+  background-color: #fff;
+}
+
+.diy-coupon .coupon-wrapper {
+  display: inline-block;
+  padding: 0 12rpx;
+}
+
+.diy-coupon .coupon-item .left-content {
+  position: relative;
+  width: 70%;
+  height: 100%;
+  background-color: #e5004f;
+  float: left;
+}
+
+.diy-coupon .coupon-item .left-content .content-top .price {
+  font-size: 44rpx;
+}
+
+.diy-coupon .coupon-item.color__blue .left-content {
+  background: linear-gradient(-125deg, #57bdbf, #2f9de2);
+}
+
+.diy-coupon .coupon-item.color__red .left-content {
+  background: linear-gradient(-128deg, #ff6d6d, #ff3636);
+}
+
+.diy-coupon .coupon-item.color__violet .left-content {
+  background: linear-gradient(-113deg, #ef86ff, #b66ff5);
+}
+
+.diy-coupon .coupon-item.color__yellow .left-content {
+  background: linear-gradient(-141deg, #f7d059, #fdb054);
+}
+
+.diy-coupon .coupon-item.color__gray .left-content {
+  background: linear-gradient(-113deg, #bdbdbd, #a2a1a2);
+}
+
+.diy-coupon .coupon-item.color__gray .right-receive {
+  background-color: #949494;
+}
+
+.diy-coupon .coupon-item .right-receive {
+  width: 30%;
+  height: 100%;
+  background-color: #4e4e4e;
+  text-align: center;
+  float: right;
+}
+
+.diy-coupon .coupon-item .right-receive {
+  font-size: 26rpx;
+}

+ 36 - 0
components/diy/goods/goods.js

@@ -0,0 +1,36 @@
+const App = getApp();
+
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object,
+    dataList: Object
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 跳转商品详情页
+     */
+    _onTargetGoods(e) {
+      wx.navigateTo({
+        url: '/pages/goods/index?goods_id=' + e.detail.target.dataset.id,
+      });
+    },
+  }
+
+})

+ 3 - 0
components/diy/goods/goods.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 61 - 0
components/diy/goods/goods.wxml

@@ -0,0 +1,61 @@
+<!-- 商品组 -->
+<view class="diy-goods" style="background: {{ itemStyle.background }};">
+  <view class="goods-list display__{{ itemStyle.display }} column__{{ itemStyle.column }}">
+    <scroll-view scroll-x="{{ itemStyle.display === 'slide' }}">
+      <view class="goods-item" wx:for="{{ dataList }}" wx:key="this" wx:for-item="dataItem">
+        <form bindsubmit="_onTargetGoods" report-submit="true">
+          <button formType="submit" class="btn-normal" data-id="{{ dataItem.goods_id }}">
+            <!-- 单列商品 -->
+            <block wx:if="{{ itemStyle.column == 1 }}">
+              <view class="dis-flex">
+                <!-- 商品图片 -->
+                <view class="goods-item_left">
+                  <image class="image" src="{{ dataItem.image }}"></image>
+                </view>
+                <view class="goods-item_right">
+                  <!-- 商品名称 -->
+                  <view wx:if="{{ itemStyle.show.goodsName }}" class="goods-item_title twolist-hidden">
+                    <text>{{ dataItem.goods_name }}</text>
+                  </view>
+                  <view class="goods-item_desc">
+                    <!-- 商品卖点 -->
+                    <view wx:if="{{ itemStyle.show.sellingPoint }}" class="desc-selling_point dis-flex">
+                      <text class="onelist-hidden">{{ dataItem.selling_point }}</text>
+                    </view>
+                    <!-- 商品销量 -->
+                    <view wx:if="{{ itemStyle.show.goodsSales }}" class="desc-goods_sales dis-flex">
+                      <text>已售{{ dataItem.goods_sales }}件</text>
+                    </view>
+                    <!-- 商品价格 -->
+                    <view class="desc_footer">
+                      <text wx:if="{{ itemStyle.show.goodsPrice }}" class="price_x">¥{{ dataItem.goods_price }}</text>
+                      <text class="price_y col-9" wx:if="{{ itemStyle.show.linePrice && dataItem.line_price > 0 }}">¥{{ dataItem.line_price }}</text>
+                    </view>
+                  </view>
+                </view>
+              </view>
+            </block>
+            <!-- 多列商品 -->
+            <block wx:else>
+              <!-- 商品图片 -->
+              <view class="goods-image">
+                <image class="image" mode="aspectFill" src="{{ dataItem.image }}"></image>
+              </view>
+              <view class="detail">
+                <!-- 商品标题 -->
+                <view wx:if="{{ itemStyle.show.goodsName }}" class="goods-name f-28 twolist-hidden">
+                  {{ dataItem.goods_name }}
+                </view>
+                <!-- 商品价格 -->
+                <view class="detail-price onelist-hidden">
+                  <text wx:if="{{ itemStyle.show.goodsPrice }}" class="goods-price f-30 col-m">¥{{ dataItem.goods_price }}</text>
+                  <text wx:if="{{ itemStyle.show.linePrice && dataItem.line_price > 0 }}" class="line-price col-9 f-24">¥{{ dataItem.line_price }}</text>
+                </view>
+              </view>
+            </block>
+          </button>
+        </form>
+      </view>
+    </scroll-view>
+  </view>
+</view>

+ 158 - 0
components/diy/goods/goods.wxss

@@ -0,0 +1,158 @@
+/* common.wxss */
+
+/* @import "/utils/common.wxss"; */
+
+/* 商品组 */
+
+.diy-goods .goods-list {
+  padding: 4rpx;
+  box-sizing: border-box;
+}
+
+.diy-goods .goods-list .goods-item {
+  box-sizing: border-box;
+  padding: 6rpx;
+}
+
+.diy-goods .goods-list.display__slide {
+  white-space: nowrap;
+  font-size: 0;
+}
+
+.diy-goods .goods-list.display__slide .goods-item {
+  display: inline-block;
+}
+
+.diy-goods .goods-list.display__list .goods-item {
+  float: left;
+}
+
+.diy-goods .goods-list.column__2 .goods-item {
+  width: 50%;
+}
+
+.diy-goods .goods-list.column__3 .goods-item {
+  width: 33.33333%;
+}
+
+.diy-goods .goods-list .goods-item .goods-image {
+  position: relative;
+  width: 100%;
+  height: 0;
+  padding-bottom: 100%;
+  overflow: hidden;
+  background: #fff;
+}
+
+.diy-goods .goods-list .goods-item .goods-image:after {
+  content: '';
+  display: block;
+  margin-top: 100%; /* margin 百分比相对父元素宽度计算 */
+}
+
+.diy-goods .goods-list .goods-item .goods-image .image {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  -o-object-fit: cover;
+  object-fit: cover;
+}
+
+.diy-goods .goods-list .goods-item .detail {
+  padding: 8rpx;
+  background: #fff;
+}
+
+.diy-goods .goods-list .goods-item .detail .goods-name {
+  height: 72rpx;
+  line-height: 1.3;
+  white-space: normal;
+}
+
+.diy-goods .goods-list .goods-item .detail .detail-price .goods-price {
+  margin-right: 8rpx;
+}
+
+.diy-goods .goods-list .goods-item .detail .detail-price .line-price {
+  text-decoration: line-through;
+}
+
+/* 单列商品 */
+
+.diy-goods .goods-list.column__1 .goods-item {
+  width: 100%;
+  height: 280rpx;
+  margin-bottom: 12rpx;
+  padding: 20rpx;
+  box-sizing: border-box;
+  background: #fff;
+}
+
+.diy-goods .goods-list.column__1 .goods-item {
+  line-height: 1.6;
+}
+
+.diy-goods .goods-list.column__1 .goods-item:last-child {
+  margin-bottom: 0;
+}
+
+.diy-goods .goods-list.column__1 .goods-item_left {
+  display: flex;
+  width: 40%;
+  background: #fff;
+  align-items: center;
+}
+
+.diy-goods .goods-list.column__1 .goods-item_left .image {
+  display: block;
+  width: 240rpx;
+  height: 240rpx;
+}
+
+.diy-goods .goods-list.column__1 .goods-item_right {
+  position: relative;
+  width: 60%;
+}
+
+.diy-goods .goods-list.column__1 .goods-item_right .goods-item_title {
+  height: 72rpx;
+  margin-top: 20rpx;
+  font-size: 28rpx;
+  color: #333;
+}
+
+.diy-goods .goods-list.column__1 .goods-item_right .goods-item_title {
+  line-height: 1.3;
+}
+
+.diy-goods .goods-list.column__1 .goods-item_desc {
+  margin-top: 8rpx;
+}
+
+.diy-goods .goods-list.column__1 .desc-selling_point {
+  width: 400rpx;
+  /* height: 40rpx; */
+  font-size: 24rpx;
+  color: #ff495e;
+}
+
+.diy-goods .goods-list.column__1 .desc-goods_sales {
+  color: #999;
+  font-size: 24rpx;
+}
+
+.diy-goods .goods-list.column__1 .desc_footer {
+  font-size: 24rpx;
+}
+
+.diy-goods .goods-list.column__1 .desc_footer .price_x {
+  margin-right: 16rpx;
+  color: #f03c3c;
+  font-size: 30rpx;
+}
+
+.diy-goods .goods-list.column__1 .desc_footer .price_y {
+  text-decoration: line-through;
+}

+ 16 - 0
components/diy/guide/guide.js

@@ -0,0 +1,16 @@
+Component({
+
+  options: {
+
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object
+  },
+
+})

+ 3 - 0
components/diy/guide/guide.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 5 - 0
components/diy/guide/guide.wxml

@@ -0,0 +1,5 @@
+<!-- 辅助线 -->
+<view class="diy-guide" style="padding: {{ itemStyle.paddingTop }}px 0; background: {{ itemStyle.background }};">
+  <view class="line" style="border-top: {{ itemStyle.lineHeight }}px {{ itemStyle.lineStyle }} {{ itemStyle.lineColor }};">
+  </view>
+</view>

+ 5 - 0
components/diy/guide/guide.wxss

@@ -0,0 +1,5 @@
+/* 辅助线 */
+
+.diy-guide .line {
+  width: 100%;
+}

+ 34 - 0
components/diy/imageSingle/imageSingle.js

@@ -0,0 +1,34 @@
+const App = getApp();
+
+Component({
+
+  options: {
+
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object,
+    dataList: Object
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 跳转到指定页面
+     */
+    navigationTo: function(e) {
+      App.navigationTo(e.currentTarget.dataset.url);
+    },
+
+  }
+})

+ 3 - 0
components/diy/imageSingle/imageSingle.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 8 - 0
components/diy/imageSingle/imageSingle.wxml

@@ -0,0 +1,8 @@
+<!-- 单图组 -->
+<view class="diy-imageSingle" style="padding-bottom: {{ itemStyle.paddingTop }}px; background: {{ itemStyle.background }};">
+  <view class="item-image" wx:for="{{ dataList }}" wx:key="this" wx:for-item="dataItem" style="padding: {{ itemStyle.paddingTop }}px {{ itemStyle.paddingLeft }}px 0;">
+    <view class="nav-to" catchtap="navigationTo" data-url="{{ dataItem.linkUrl }}">
+      <image class="image" src="{{ dataItem.imgUrl }}" mode="widthFix"></image>
+    </view>
+  </view>
+</view>

+ 6 - 0
components/diy/imageSingle/imageSingle.wxss

@@ -0,0 +1,6 @@
+/* 单图组 */
+
+.diy-imageSingle .item-image .image {
+  display: block;
+  width: 100%;
+}

+ 15 - 0
components/diy/index.js

@@ -0,0 +1,15 @@
+Component({
+
+  options: {
+
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    diyItems: Object
+  },
+
+})

+ 25 - 0
components/diy/index.json

@@ -0,0 +1,25 @@
+{
+  "component": true,
+  "usingComponents": {
+    "diy-banner": "./banner/banner",
+    "diy-search": "./search/search",
+    "diy-imageSingle": "./imageSingle/imageSingle",
+    "diy-video": "./video/video",
+    "diy-article": "./article/article",
+    "diy-special": "./special/index",
+    "diy-blank": "./blank/blank",
+    "diy-guide": "./guide/guide",
+    "diy-navBar": "./navBar/navBar",
+    "diy-window": "./window/window",
+    "diy-goods": "./goods/goods",
+    "diy-coupon": "./coupon/coupon",
+    "diy-notice": "./notice/notice",
+    "diy-service": "./service/service",
+    "diy-richText": "./richText/richText",
+    "diy-sharingGoods": "./sharingGoods/sharingGoods",
+    "diy-bargainGoods": "./bargainGoods/index",
+    "diy-sharpGoods": "./sharpGoods/index",
+    "diy-shop": "./shop/index",
+    "diy-officialAccount": "./officialAccount/index"
+  }
+}

+ 103 - 0
components/diy/index.wxml

@@ -0,0 +1,103 @@
+<block wx:for="{{diyItems}}" wx:for-item="item" wx:for-index="itemIndex" wx:key="this">
+
+  <!-- 搜索框 -->
+  <block wx:if="{{item.type === 'search'}}">
+    <diy-search itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" params="{{ item.params }}"></diy-search>
+  </block>
+
+  <!-- banner轮播 -->
+  <block wx:if="{{item.type === 'banner'}}">
+    <diy-banner itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" params="{{ item.params }}" dataList="{{ item.data }}"></diy-banner>
+  </block>
+
+  <!-- 单图组 -->
+  <block wx:if="{{item.type === 'imageSingle'}}">
+    <diy-imageSingle itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-imageSingle>
+  </block>
+
+  <!-- 视频组 -->
+  <block wx:if="{{item.type === 'video'}}">
+    <diy-video itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" params="{{ item.params }}"></diy-video>
+  </block>
+
+  <!-- 文章组 -->
+  <block wx:if="{{item.type === 'article'}}">
+    <diy-article itemIndex="{{ itemIndex }}" params="{{ item.params }}" dataList="{{ item.data }}"></diy-article>
+  </block>
+
+  <!-- 头条快报 -->
+  <block wx:if="{{item.type === 'special'}}">
+    <diy-special itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" params="{{ item.params }}" dataList="{{ item.data }}"></diy-special>
+  </block>
+
+  <!-- 公告组 -->
+  <block wx:if="{{item.type === 'notice'}}">
+    <diy-notice itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" params="{{ item.params }}"></diy-notice>
+  </block>
+
+  <!-- 空白组 -->
+  <block wx:if="{{item.type === 'blank'}}">
+    <diy-blank itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}"></diy-blank>
+  </block>
+
+  <!-- 辅助线 -->
+  <block wx:if="{{item.type === 'guide'}}">
+    <diy-guide itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}"></diy-guide>
+  </block>
+
+  <!-- 在线客服 -->
+  <block wx:if="{{item.type === 'service'}}">
+    <diy-service itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" params="{{ item.params }}"></diy-service>
+  </block>
+
+  <!-- 富文本 -->
+  <block wx:if="{{item.type === 'richText'}}">
+    <diy-richText itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" params="{{ item.params }}"></diy-richText>
+  </block>
+
+  <!-- 导航组 -->
+  <block wx:if="{{item.type === 'navBar'}}">
+    <diy-navBar itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-navBar>
+  </block>
+
+  <!-- 图片橱窗 -->
+  <block wx:if="{{item.type === 'window'}}">
+    <diy-window itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-window>
+  </block>
+
+  <!-- 商品组 -->
+  <block wx:if="{{item.type === 'goods'}}">
+    <diy-goods itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-goods>
+  </block>
+
+  <!-- 优惠券组 -->
+  <block wx:if="{{item.type === 'coupon'}}">
+    <diy-coupon itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-coupon>
+  </block>
+
+  <!-- 拼团商品 -->
+  <block wx:if="{{item.type === 'sharingGoods'}}">
+    <diy-sharingGoods itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-sharingGoods>
+  </block>
+
+  <!-- 砍价商品 -->
+  <block wx:if="{{item.type === 'bargainGoods'}}">
+    <diy-bargainGoods itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-bargainGoods>
+  </block>
+
+  <!-- 秒杀商品 -->
+  <block wx:if="{{item.type === 'sharpGoods'}}">
+    <diy-sharpGoods itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" data="{{ item.data }}"></diy-sharpGoods>
+  </block>
+
+  <!-- 线下门店 -->
+  <block wx:if="{{item.type === 'shop'}}">
+    <diy-shop itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-shop>
+  </block>
+
+  <!-- 关注公众号 -->
+  <block wx:if="{{ item.type === 'officialAccount' }}">
+    <diy-officialAccount itemIndex="{{ itemIndex }}" itemStyle="{{ item.style }}" dataList="{{ item.data }}"></diy-officialAccount>
+  </block>
+
+</block>

+ 0 - 0
components/diy/index.wxss


+ 34 - 0
components/diy/navBar/navBar.js

@@ -0,0 +1,34 @@
+const App = getApp();
+
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object,
+    dataList: Object
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 跳转到指定页面
+     */
+    navigationTo: function(e) {
+      App.navigationTo(e.currentTarget.dataset.url);
+    },
+
+  }
+})

+ 3 - 0
components/diy/navBar/navBar.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 13 - 0
components/diy/navBar/navBar.wxml

@@ -0,0 +1,13 @@
+<!-- 导航组 -->
+<view class="diy-navBar" style="background: {{ itemStyle.background }};">
+  <view class="data-list avg-sm-{{ itemStyle.rowsNum }}">
+    <view class="item-nav" wx:for="{{ dataList }}" wx:key="this" wx:for-item="dataItem">
+      <view class="nav-to" catchtap="navigationTo" data-url="{{ dataItem.linkUrl }}">
+        <view class="item-image">
+          <image class="image" mode="widthFix" src="{{ dataItem.imgUrl }}"></image>
+        </view>
+        <view class="item-text f-28 onelist-hidden" style="color: {{ dataItem.color }};">{{ dataItem.text }}</view>
+      </view>
+    </view>
+  </view>
+</view>

+ 41 - 0
components/diy/navBar/navBar.wxss

@@ -0,0 +1,41 @@
+/* common.wxss */
+
+/* @import "/utils/common.wxss"; */
+
+/* 导航组 */
+
+.diy-navBar .data-list::after {
+  clear: both;
+  content: " ";
+  display: table;
+}
+
+.diy-navBar .item-nav {
+  float: left;
+  margin: 10px 0;
+  text-align: center;
+}
+
+.diy-navBar .item-nav .item-image {
+  margin-bottom: 4px;
+  font-size: 0;
+}
+
+.diy-navBar .item-nav .item-image .image {
+  width: 88rpx;
+  height: 88rpx;
+}
+
+/* 分列布局 */
+
+.diy-navBar .avg-sm-3 > .item-nav {
+  width: 33.33333333%;
+}
+
+.diy-navBar .avg-sm-4 > .item-nav {
+  width: 25%;
+}
+
+.diy-navBar .avg-sm-5 > .item-nav {
+  width: 20%;
+}

+ 17 - 0
components/diy/notice/notice.js

@@ -0,0 +1,17 @@
+Component({
+
+  options: {
+
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object
+  },
+
+})

+ 6 - 0
components/diy/notice/notice.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "zan-noticebar": "../../noticebar/index"
+  }
+}

+ 4 - 0
components/diy/notice/notice.wxml

@@ -0,0 +1,4 @@
+<!-- 公告组 -->
+<view class="diy-notice">
+  <zan-noticebar leftIcon="{{ params.icon }}" text="{{ params.text }}" color="{{ itemStyle.textColor }}" background-color="{{ itemStyle.background }}" paddingTop="{{ itemStyle.paddingTop }}" scrollable="{{ true }}" />
+</view>

+ 16 - 0
components/diy/notice/notice.wxss

@@ -0,0 +1,16 @@
+/* 公告组 */
+
+/* .notice__icon {
+  font-size: 0;
+} */
+
+/* .notice__icon img {
+  width: 28rpx;
+  height: 28rpx;
+} */
+
+/* .notice__text {
+  width: 298rpx;
+  height: 30rpx;
+  padding-left: 5rpx; 
+}*/

+ 17 - 0
components/diy/officialAccount/index.js

@@ -0,0 +1,17 @@
+Component({
+
+  options: {
+
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object
+  },
+
+})

+ 3 - 0
components/diy/officialAccount/index.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 4 - 0
components/diy/officialAccount/index.wxml

@@ -0,0 +1,4 @@
+<!-- 关注公众号 -->
+<view class="diy-officialAccount">
+  <official-account></official-account>
+</view>

+ 0 - 0
components/diy/officialAccount/index.wxss


+ 29 - 0
components/diy/richText/richText.js

@@ -0,0 +1,29 @@
+// 富文本插件
+import wxParse from '../../../wxParse/wxParse.js';
+
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object
+  },
+
+  ready: function() {
+    let content = this.data.params.content;
+    // 富文本转码
+    if (content.length > 0) {
+      wxParse.wxParse('content', 'html', content, this, 0);
+    }
+  },
+
+
+})

+ 6 - 0
components/diy/richText/richText.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "zan-noticebar": "../../noticebar/index"
+  }
+}

+ 5 - 0
components/diy/richText/richText.wxml

@@ -0,0 +1,5 @@
+<!-- 富文本 -->
+<import src="../../../wxParse/wxParse.wxml"></import>
+<view class="diy-richText" style="padding: {{ itemStyle.paddingTop }}px {{ itemStyle.paddingLeft }}px; background: {{ itemStyle.background }};">
+  <template is="wxParse" data="{{ wxParseData:content.nodes }}"></template>
+</view>

+ 8 - 0
components/diy/richText/richText.wxss

@@ -0,0 +1,8 @@
+/* wxParse.wxss */
+@import "/wxParse/wxParse.wxss";
+
+/* 富文本 */
+
+.diy-richText {
+  font-size: 28rpx;
+}

+ 31 - 0
components/diy/search/search.js

@@ -0,0 +1,31 @@
+const App = getApp();
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+    /**
+     * 跳转到搜索页面
+     */
+    onTargetSearch(e) {
+      App.navigationTo('pages/search/index');
+    },
+  }
+
+})

+ 3 - 0
components/diy/search/search.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 13 - 0
components/diy/search/search.wxml

@@ -0,0 +1,13 @@
+<!-- 搜索框 -->
+<view class="diy-search">
+  <form bindsubmit="onTargetSearch" report-submit="true">
+    <button formType="submit" class="btn-normal">
+      <view class="inner {{ itemStyle.searchStyle }}">
+        <view class="search-input" style="text-align: {{ itemStyle.textAlign }}">
+          <text class="search-icon iconfont icon-sousuo"></text>
+          <text> {{ params.placeholder }}</text>
+        </view>
+      </view>
+    </button>
+  </form>
+</view>

+ 33 - 0
components/diy/search/search.wxss

@@ -0,0 +1,33 @@
+/* common.wxss */
+
+/* @import "/utils/common.wxss"; */
+
+/* 搜索框 */
+
+.diy-search {
+  background: #f1f1f2;
+  padding: 20rpx 20rpx;
+  font-size: 26rpx;
+}
+
+.diy-search .inner {
+  height: 60rpx;
+  background: #fff;
+  overflow: hidden;
+}
+
+.diy-search .inner.radius {
+  border-radius: 10rpx;
+}
+
+.diy-search .inner.round {
+  border-radius: 60rpx;
+}
+
+.diy-search .inner .search-input {
+  height: 60rpx;
+  /* width: 100%; */
+  line-height: 60rpx;
+  color: #999;
+  padding: 0 20rpx;
+}

+ 37 - 0
components/diy/service/service.js

@@ -0,0 +1,37 @@
+const App = getApp();
+
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 点击拨打电话
+     */
+    _onServiceEvent(e) {
+      // 拨打电话
+      wx.makePhoneCall({
+        phoneNumber: this.data.params.phone_num
+      })
+    },
+
+  }
+
+})

+ 3 - 0
components/diy/service/service.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 21 - 0
components/diy/service/service.wxml

@@ -0,0 +1,21 @@
+<!-- 在线客服 -->
+<view class="diy-service" style="right: {{ itemStyle.right }}%; bottom: {{ itemStyle.bottom }}%;">
+  <!-- 拨打电话 -->
+  <block wx:if="{{ params.type == 'phone' }}">
+    <form bindsubmit="_onServiceEvent" report-submit="true">
+      <button formType="submit" class="btn-normal">
+        <view class="service-icon">
+          <image class="image" src="{{ params.image }}"></image>
+        </view>
+      </button>
+    </form>
+  </block>
+  <!-- 在线聊天 -->
+  <block wx:elif="{{ params.type == 'chat' }}">
+    <button open-type="contact" class="btn-normal">
+      <view class="service-icon">
+        <image class="image" src="{{ params.image }}"></image>
+      </view>
+    </button>
+  </block>
+</view>

+ 19 - 0
components/diy/service/service.wxss

@@ -0,0 +1,19 @@
+/* common.wxss */
+/* @import "/utils/common.wxss"; */
+
+/* 在线客服 */
+
+.diy-service {
+  position: fixed;
+  z-index: 999;
+}
+
+.diy-service .service-icon {
+  padding: 10rpx;
+}
+
+.diy-service .service-icon .image {
+  display: block;
+  width: 90rpx;
+  height: 90rpx;
+}

+ 36 - 0
components/diy/sharingGoods/sharingGoods.js

@@ -0,0 +1,36 @@
+const App = getApp();
+
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object,
+    dataList: Object
+  },
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 跳转商品详情页
+     */
+    _onTargetGoods(e) {
+      wx.navigateTo({
+        url: '/pages/sharing/goods/index?goods_id=' + e.detail.target.dataset.id,
+      });
+    },
+  }
+
+})

+ 3 - 0
components/diy/sharingGoods/sharingGoods.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 37 - 0
components/diy/sharingGoods/sharingGoods.wxml

@@ -0,0 +1,37 @@
+<!-- 商品组 -->
+<view class="diy-sharingGoods" style="background: {{ itemStyle.background }};">
+  <view class="goods-item" wx:for="{{ dataList }}" wx:key="this" wx:for-item="dataItem">
+    <form bindsubmit="_onTargetGoods" report-submit="true">
+      <button formType="submit" class="btn-normal dis-flex" data-id="{{ dataItem.goods_id }}">
+        <!-- 商品图片 -->
+        <view class="goods-item_left">
+          <image class="image" mode="aspectFill" src="{{ dataItem.image }}"></image>
+        </view>
+        <view class="goods-item_right">
+          <!-- 商品名称 -->
+          <view wx:if="{{ itemStyle.show.goodsName }}" class="goods-item_title twolist-hidden">
+            <text>{{ dataItem.goods_name }}</text>
+          </view>
+          <view class="goods-item_desc">
+            <!-- 商品卖点 -->
+            <view wx:if="{{ itemStyle.show.sellingPoint }}" class="desc-selling_point onelist-hidden">
+              <text>{{ dataItem.selling_point }}</text>
+            </view>
+            <!-- 拼团信息 -->
+            <view class="desc-situation">
+              <text class="iconfont icon-pintuan_huaban"></text>
+              <text class="people">{{ dataItem.people }}人团</text>
+              <text class="col-9">已有{{ dataItem.goods_sales }}人进行拼团</text>
+            </view>
+            <!-- 商品价格 -->
+            <view class="desc_footer">
+              <text class="price_x" wx:if="{{ itemStyle.show.sharingPrice }}">¥{{ dataItem.sharing_price }}</text>
+              <text class="price_y col-9" wx:if="{{ itemStyle.show.linePrice && dataItem.line_price > 0 }}">¥{{ dataItem.line_price }}</text>
+            </view>
+          </view>
+          <view class="btn-settlement">去拼团</view>
+        </view>
+      </button>
+    </form>
+  </view>
+</view>

+ 110 - 0
components/diy/sharingGoods/sharingGoods.wxss

@@ -0,0 +1,110 @@
+/* common.wxss */
+/* @import "/utils/common.wxss"; */
+
+/* 商品组 */
+
+.diy-sharingGoods {
+  padding: 20rpx;
+}
+
+.goods-item {
+  height: 320rpx;
+  margin-bottom: 20rpx;
+  padding: 20rpx;
+  box-sizing: border-box;
+  background: #fff;
+}
+
+.goods-item:last-child {
+  margin-bottom: 0;
+}
+
+/* 商品图片 */
+
+.goods-item_left {
+  display: flex;
+  width: 40%;
+  background: #fff;
+  align-items: center;
+}
+
+.goods-item_left .image {
+  display: block;
+  width: 240rpx;
+  height: 240rpx;
+}
+
+.goods-item_right {
+  position: relative;
+  width: 60%;
+}
+
+/* 商品名称 */
+
+.goods-item_right .goods-item_title {
+  height: 72rpx;
+  margin-top: 20rpx;
+  font-size: 28rpx;
+  line-height: 1.3;
+  color: #333;
+}
+
+.goods-item_desc {
+  margin-top: 16rpx;
+}
+
+/* 商品卖点 */
+
+.desc-selling_point {
+  width: 400rpx;
+  /* height: 40rpx; */
+  font-size: 24rpx;
+  line-height: 1.4;
+  color: #ff495e;
+}
+
+/* 拼团信息 */
+
+.desc-situation {
+  margin-top: 12rpx;
+  font-size: 24rpx;
+  line-height: 1.3;
+  color: rgb(240, 60, 60);
+}
+
+.desc-situation .people {
+  margin: 0 12rpx;
+}
+
+/* 商品价格 */
+
+.desc_footer {
+  margin-top: 12rpx;
+  font-size: 24rpx;
+}
+
+.desc_footer .price_x {
+  margin-right: 16rpx;
+  color: rgb(240, 60, 60);
+  font-size: 28rpx;
+}
+
+.desc_footer .price_y {
+  text-decoration: line-through;
+}
+
+/* 去拼团按钮 */
+
+.goods-item .btn-settlement {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  padding: 0 28rpx;
+  border-radius: 40rpx;
+  background: linear-gradient(to right, rgb(235, 53, 107) 0%, rgb(240, 60, 60) 100%);
+  box-shadow: 0 4rpx 20rpx -4rpx rgb(235, 53, 107);
+  font-size: 28rpx;
+  line-height: 54rpx;
+  text-align: center;
+  color: #fff;
+}

+ 94 - 0
components/diy/sharpGoods/index.js

@@ -0,0 +1,94 @@
+import util from '../../../utils/util.js';
+import ActiveStatusEnum from '../../../utils/enum/sharp/GoodsStatus.js';
+
+const App = getApp()
+
+Component({
+
+  options: {
+    addGlobalClass: true,
+  },
+
+  /**
+   * 组件的属性列表
+   * 用于组件自定义设置
+   */
+  properties: {
+    itemIndex: String,
+    itemStyle: Object,
+    params: Object,
+    data: Object,
+  },
+
+  /**
+   * 组件私有属性
+   */
+  data: {
+    ActiveStatusEnum, // 秒杀活动商品状态
+    countDownTime: false, // 倒计时日期
+  },
+
+  /**
+   * 组件生命周期声明对象
+   */
+  lifetimes: {
+
+    /**
+     * 在组件实例进入页面节点树时执行
+     */
+    attached() {
+      let _this = this;
+      _this._initCountDownData();
+    }
+
+  },
+
+
+
+  /**
+   * 组件的方法列表
+   * 更新属性和数据的方法与更新页面数据的方法类似
+   */
+  methods: {
+
+    /**
+     * 跳转商品详情页
+     */
+    _onTargetGoods(e) {
+      // 生成query参数
+      let _this = this,
+        query = util.urlEncode({
+          active_time_id: _this.data.data.active.active_time_id,
+          sharp_goods_id: e.detail.target.dataset.id,
+        });
+      // 跳转到商品详情页
+      wx.navigateTo({
+        url: `/pages/sharp/goods/index?${query}`,
+      });
+    },
+
+    /**
+     * 更多秒杀
+     */
+    _onTargetSharpIndex(e) {
+      // 跳转到秒杀会场首页
+      wx.navigateTo({
+        url: `/pages/sharp/index/index`,
+      });
+    },
+
+    /**
+     * 初始化倒计时组件
+     */
+    _initCountDownData() {
+      const app = this
+      const active = app.data.data.active
+      if (!active) return false;
+      // 记录倒计时的时间
+      app.setData({
+        countDownTime: active.count_down_time
+      })
+    }
+  }
+
+})

+ 6 - 0
components/diy/sharpGoods/index.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "countdown": "/components/countdown/index"
+  }
+}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff