18016688350 4 vuotta sitten
säilyke
809ca5458d
100 muutettua tiedostoa jossa 9299 lisäystä ja 0 poistoa
  1. 1 0
      README.md
  2. 43 0
      app.js
  3. 95 0
      app.json
  4. 103 0
      app.wxss
  5. 184 0
      colorui/animation.wxss
  6. 54 0
      colorui/components/cu-custom.js
  7. 4 0
      colorui/components/cu-custom.json
  8. 16 0
      colorui/components/cu-custom.wxml
  9. 1 0
      colorui/components/cu-custom.wxss
  10. 36 0
      colorui/icon.wxss
  11. 3941 0
      colorui/main.wxss
  12. 109 0
      components/button/button.js
  13. 3 0
      components/button/button.json
  14. 31 0
      components/button/button.wxml
  15. 227 0
      components/button/button.wxss
  16. 31 0
      components/drawer/drawer.js
  17. 3 0
      components/drawer/drawer.json
  18. 7 0
      components/drawer/drawer.wxml
  19. 64 0
      components/drawer/drawer.wxss
  20. 30 0
      components/drawer/index.js
  21. 4 0
      components/drawer/index.json
  22. 7 0
      components/drawer/index.wxml
  23. 64 0
      components/drawer/index.wxss
  24. 43 0
      components/extend/alert/alert.js
  25. 3 0
      components/extend/alert/alert.json
  26. 7 0
      components/extend/alert/alert.wxml
  27. 73 0
      components/extend/alert/alert.wxss
  28. 57 0
      components/extend/button/button.js
  29. 3 0
      components/extend/button/button.json
  30. 39 0
      components/extend/button/button.wxml
  31. 248 0
      components/extend/button/button.wxss
  32. 42 0
      components/extend/tips/tips.js
  33. 3 0
      components/extend/tips/tips.json
  34. 7 0
      components/extend/tips/tips.wxml
  35. 49 0
      components/extend/tips/tips.wxss
  36. 74 0
      components/extend/toast/toast.js
  37. 4 0
      components/extend/toast/toast.json
  38. 17 0
      components/extend/toast/toast.wxml
  39. 58 0
      components/extend/toast/toast.wxss
  40. 25 0
      components/icon/icon.js
  41. 3 0
      components/icon/icon.json
  42. 1 0
      components/icon/icon.wxml
  43. 2 0
      components/icon/icon.wxss
  44. 49 0
      components/list-cell/list-cell.js
  45. 4 0
      components/list-cell/list-cell.json
  46. 4 0
      components/list-cell/list-cell.wxml
  47. 49 0
      components/list-cell/list-cell.wxss
  48. 15 0
      components/list-view/list-view.js
  49. 4 0
      components/list-view/list-view.json
  50. 6 0
      components/list-view/list-view.wxml
  51. 46 0
      components/list-view/list-view.wxss
  52. 17 0
      components/loading/loading.js
  53. 4 0
      components/loading/loading.json
  54. 4 0
      components/loading/loading.wxml
  55. 56 0
      components/loading/loading.wxss
  56. 27 0
      components/loadmore/loadmore.js
  57. 4 0
      components/loadmore/loadmore.json
  58. 4 0
      components/loadmore/loadmore.wxml
  59. 128 0
      components/loadmore/loadmore.wxss
  60. 92 0
      components/modal/modal.js
  61. 4 0
      components/modal/modal.json
  62. 18 0
      components/modal/modal.wxml
  63. 248 0
      components/modal/modal.wxss
  64. 30 0
      components/nomore/nomore.js
  65. 4 0
      components/nomore/nomore.json
  66. 5 0
      components/nomore/nomore.wxml
  67. 69 0
      components/nomore/nomore.wxss
  68. 154 0
      components/numberbox/numberbox.js
  69. 4 0
      components/numberbox/numberbox.json
  70. 5 0
      components/numberbox/numberbox.wxml
  71. 38 0
      components/numberbox/numberbox.wxss
  72. 38 0
      components/tag/tag.js
  73. 4 0
      components/tag/tag.json
  74. 24 0
      components/tag/tag.wxml
  75. 266 0
      components/tag/tag.wxss
  76. 565 0
      components/timePicker/timePicker.js
  77. 4 0
      components/timePicker/timePicker.json
  78. 68 0
      components/timePicker/timePicker.wxml
  79. 96 0
      components/timePicker/timePicker.wxss
  80. 47 0
      components/top-dropdown/top-dropdown.js
  81. 3 0
      components/top-dropdown/top-dropdown.json
  82. 4 0
      components/top-dropdown/top-dropdown.wxml
  83. 35 0
      components/top-dropdown/top-dropdown.wxss
  84. 83 0
      components/tui-tabbar/tui-tabbar.js
  85. 4 0
      components/tui-tabbar/tui-tabbar.json
  86. 12 0
      components/tui-tabbar/tui-tabbar.wxml
  87. 142 0
      components/tui-tabbar/tui-tabbar.wxss
  88. 139 0
      components/tui-tabs/tui-tabs.js
  89. 4 0
      components/tui-tabs/tui-tabs.json
  90. 6 0
      components/tui-tabs/tui-tabs.wxml
  91. 62 0
      components/tui-tabs/tui-tabs.wxss
  92. 270 0
      components/tui-upload/tui-upload.js
  93. 3 0
      components/tui-upload/tui-upload.json
  94. 16 0
      components/tui-upload/tui-upload.wxml
  95. 137 0
      components/tui-upload/tui-upload.wxss
  96. 38 0
      custom-tab-bar/index.js
  97. 6 0
      custom-tab-bar/index.json
  98. 1 0
      custom-tab-bar/index.wxml
  99. 64 0
      custom-tab-bar/index.wxss
  100. 250 0
      ec-canvas/ec-canvas.js

+ 1 - 0
README.md

@@ -0,0 +1 @@
+# mg-vending-machine-applets-manage

+ 43 - 0
app.js

@@ -0,0 +1,43 @@
+//app.js
+App({
+  onLaunch: function () {
+    // 展示本地存储能力
+    var logs = wx.getStorageSync('logs') || []
+    logs.unshift(Date.now())
+    wx.setStorageSync('logs', logs)
+
+    // 登录
+    wx.login({
+      success: res => {
+        // 发送 res.code 到后台换取 openId, sessionKey, unionId
+      }
+    })
+    // 获取用户信息
+    wx.getSetting({
+      success: res => {
+        if (res.authSetting['scope.userInfo']) {
+          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
+          wx.getUserInfo({
+            success: res => {
+              // 可以将 res 发送给后台解码出 unionId
+              this.globalData.userInfo = res.userInfo
+
+              // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
+              // 所以此处加入 callback 以防止这种情况
+              if (this.userInfoReadyCallback) {
+                this.userInfoReadyCallback(res)
+              }
+            }
+          })
+        }
+      }
+    })
+  },
+  onShow:function(){
+  },
+  globalData: {
+    userInfo: null,
+    isLogin: false,
+    token:'',
+  }
+})

+ 95 - 0
app.json

@@ -0,0 +1,95 @@
+{
+  "pages": [
+    "pages/index/index",
+    "pages/logs/logs",
+    "pages/total/index",
+    "pages/mine/index",
+    "pages/operation/index",
+    "pages/operation/deviceTest",
+    "pages/divide/index",
+    "pages/order/index",
+    "pages/billing/index",
+    "pages/accountBind/index",
+    "pages/contractTime/index",
+    "pages/pwdSet/index",
+    "pages/role/index",
+    "pages/hotel/index",
+    "pages/hotel/add",
+    "pages/hotel/edit",
+    "pages/device/index",
+    "pages/device/list",
+    "pages/device/detail",
+    "pages/vendingMachine/index",
+    "pages/vendingMachine/settledHotel",
+    "pages/product/index",
+    "pages/product/edit",
+    "pages/scheme/index",
+    "pages/scheme/form",
+    "pages/stock/index",
+    "pages/pssRecord/index",
+    "pages/scheme/sync",
+    "pages/orderGoods/index",
+    "pages/orderGoods/submitBuy",
+    "pages/operation/deviceUnbind",
+    "pages/stock/stockout",
+    "pages/repairs/index",
+    "pages/repairs/add",
+    "pages/stock/replenish",
+    "pages/stock/replenishDetail",
+    "pages/orderGoods/buy",
+    "pages/orderGoods/order",
+    "pages/total/salesTotalList",
+    "pages/total/salesTotalDetail",
+    "pages/login/index",
+    "pages/product/select",
+    "pages/scheme/select",
+    "pages/repairs/detail",
+    "pages/stock/stockDeviceDetail",
+    "pages/role/operationList",
+    "pages/role/addOperation",
+    "pages/role/editOperation",
+    "pages/role/introducerList",
+    "pages/role/addIntroducer",
+    "pages/role/editIntroducer",
+    "pages/accountRecord/index"
+  ],
+
+  "tabBar": {
+    "custom": true,
+    "color": "#666666",
+    "selectedColor": "#5677fc",
+    "backgroundColor": "#FFFFFF",
+    "list": [
+      {
+        "pagePath": "pages/index/index",
+        "text": "首页",
+        "iconPath": "static/images/tabbar/btn_ico_home_nomal@2x.png",
+        "selectedIconPath": "static/images/tabbar/btn_ico_home_pressed@2x.png"
+      },
+      {
+        "pagePath": "pages/total/index",
+        "text": "统计",
+        "iconPath": "static/images/tabbar/btn_ico_statistics_nomal@2x.png",
+        "selectedIconPath": "static/images/tabbar/btn_ico_statistics_pressed@2x.png"
+      },
+      {
+        "pagePath": "pages/mine/index",
+        "text": "我的",
+        "iconPath": "static/images/tabbar/btn_ico_my_nomal@2x.png",
+        "selectedIconPath": "static/images/tabbar/btn_ico_my_pressed@2x.png"
+      }
+    ]
+  },
+  "networkTimeout": {
+    "request": 10000,
+    "connectSocket": 10000,
+    "uploadFile": 10000,
+    "downloadFile": 10000
+  },
+  "sitemapLocation": "sitemap.json",
+  "permission": {
+    "scope.userLocation": {
+      "desc": "你的位置信息将用于小程序位置接口的效果展示"
+    }
+  }
+}

+ 103 - 0
app.wxss

@@ -0,0 +1,103 @@
+@import "colorui/main.wxss";
+@import "colorui/icon.wxss";
+@import "static/style/thorui.wxss";
+
+/**app.wxss**/
+
+page {
+  background: #fafafa;
+  font-size: 28rpx;
+  /* font-family:PingFang-SC-Medium; */ 
+}
+
+.container {
+  display: flex;
+  flex-direction: column;
+  box-sizing: border-box;
+}
+
+.phcolor {
+  color: #ccc;
+  font-size: 32rpx;
+}
+
+button::after {
+  border: none;
+}
+
+.opcity {
+  opacity: 0.5;
+}
+
+.hover {
+  background: #f7f7f9 !important;
+}
+
+.ellipsis {
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
+/*列表统一样式 */
+
+.list-item {
+  position: relative;
+}
+
+.list-item::after {
+  content: '';
+  position: absolute;
+  border-bottom: 1rpx solid #eaeef1;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  bottom: 0;
+  right: 0;
+  left: 30rpx;
+}
+
+.last::after {
+  border-bottom: 0 !important;
+}
+
+/*按钮样式*/
+
+.btn-primary {
+  width: 100%;
+  height: 90rpx;
+  line-height: 90rpx;
+  background: linear-gradient(-90deg, #5677fc, #5c8dff);
+  border-radius: 45rpx;
+  color: #fff;
+  font-size: 36rpx;
+}
+
+.btn-hover {
+  color: #d5d4d9;
+  background: linear-gradient(-90deg, #4a67d6, #4e77d9);
+}
+
+.btn-gray {
+  background: #ededed;
+  color: #999 !important;
+}
+
+.btn-gray-hover {
+  background: #d5d5d5 !important;
+  color: #898989;
+}
+
+.btn-white {
+  background: #fff;
+  color: #333 !important;
+}
+
+.tui-white-hover {
+  background: #e5e5e5 !important;
+  color: #2e2e2e !important;
+}
+
+.btn-disabled {
+  color: #fafbfc !important;
+  background: linear-gradient(-90deg, #cad8fb, #c9d3fb);
+}

+ 184 - 0
colorui/animation.wxss

@@ -0,0 +1,184 @@
+/* 
+  Animation 微动画  
+  基于ColorUI组建库的动画模块 by 文晓港 2019年3月26日19:52:28
+ */
+
+/* css 滤镜 控制黑白底色gif的 */
+.gif-black{  
+  mix-blend-mode: screen;  
+}
+.gif-white{  
+  mix-blend-mode: multiply; 
+}
+
+
+/* Animation css */
+[class*=animation-] {
+    animation-duration: .5s;
+    animation-timing-function: ease-out;
+    animation-fill-mode: both
+}
+
+.animation-fade {
+    animation-name: fade;
+    animation-duration: .8s;
+    animation-timing-function: linear
+}
+
+.animation-scale-up {
+    animation-name: scale-up
+}
+
+.animation-scale-down {
+    animation-name: scale-down
+}
+
+.animation-slide-top {
+    animation-name: slide-top
+}
+
+.animation-slide-bottom {
+    animation-name: slide-bottom
+}
+
+.animation-slide-left {
+    animation-name: slide-left
+}
+
+.animation-slide-right {
+    animation-name: slide-right
+}
+
+.animation-shake {
+    animation-name: shake
+}
+
+.animation-reverse {
+    animation-direction: reverse
+}
+
+@keyframes fade {
+    0% {
+        opacity: 0
+    }
+
+    100% {
+        opacity: 1
+    }
+}
+
+@keyframes scale-up {
+    0% {
+        opacity: 0;
+        transform: scale(.2)
+    }
+
+    100% {
+        opacity: 1;
+        transform: scale(1)
+    }
+}
+
+@keyframes scale-down {
+    0% {
+        opacity: 0;
+        transform: scale(1.8)
+    }
+
+    100% {
+        opacity: 1;
+        transform: scale(1)
+    }
+}
+
+@keyframes slide-top {
+    0% {
+        opacity: 0;
+        transform: translateY(-100%)
+    }
+
+    100% {
+        opacity: 1;
+        transform: translateY(0)
+    }
+}
+
+@keyframes slide-bottom {
+    0% {
+        opacity: 0;
+        transform: translateY(100%)
+    }
+
+    100% {
+        opacity: 1;
+        transform: translateY(0)
+    }
+}
+
+@keyframes shake {
+
+    0%,
+    100% {
+        transform: translateX(0)
+    }
+
+    10% {
+        transform: translateX(-9px)
+    }
+
+    20% {
+        transform: translateX(8px)
+    }
+
+    30% {
+        transform: translateX(-7px)
+    }
+
+    40% {
+        transform: translateX(6px)
+    }
+
+    50% {
+        transform: translateX(-5px)
+    }
+
+    60% {
+        transform: translateX(4px)
+    }
+
+    70% {
+        transform: translateX(-3px)
+    }
+
+    80% {
+        transform: translateX(2px)
+    }
+
+    90% {
+        transform: translateX(-1px)
+    }
+}
+
+@keyframes slide-left {
+    0% {
+        opacity: 0;
+        transform: translateX(-100%)
+    }
+
+    100% {
+        opacity: 1;
+        transform: translateX(0)
+    }
+}
+
+@keyframes slide-right {
+    0% {
+        opacity: 0;
+        transform: translateX(100%)
+    }
+
+    100% {
+        opacity: 1;
+        transform: translateX(0)
+    }
+}

+ 54 - 0
colorui/components/cu-custom.js

@@ -0,0 +1,54 @@
+const app = getApp();
+Component({
+  /**
+   * 组件的一些选项
+   */
+  options: {
+    addGlobalClass: true,
+    multipleSlots: true
+  },
+  /**
+   * 组件的对外属性
+   */
+  properties: {
+    bgColor: {
+      type: String,
+      default: ''
+    }, 
+    isCustom: {
+      type: [Boolean, String],
+      default: false
+    },
+    isBack: {
+      type: [Boolean, String],
+      default: false
+    },
+    bgImage: {
+      type: String,
+      default: ''
+    },
+  },
+  /**
+   * 组件的初始数据
+   */
+  data: {
+    StatusBar: app.globalData.StatusBar,
+    CustomBar: app.globalData.CustomBar,
+    Custom: app.globalData.Custom
+  },
+  /**
+   * 组件的方法列表
+   */
+  methods: {
+    BackPage() {
+      wx.navigateBack({
+        delta: 1
+      });
+    },
+    toHome(){
+      wx.reLaunch({
+        url: '/pages/index/index',
+      })
+    }
+  }
+})

+ 4 - 0
colorui/components/cu-custom.json

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

+ 16 - 0
colorui/components/cu-custom.wxml

@@ -0,0 +1,16 @@
+<view class="cu-custom" style="height:{{CustomBar}}px">
+  <view class="cu-bar fixed {{bgImage!=''?'none-bg text-white bg-img':''}} {{bgColor}}" style="height:{{CustomBar}}px;padding-top:{{StatusBar}}px;{{bgImage?'background-image:url(' + bgImage+')':''}}">
+    <view class="action" bindtap="BackPage" wx:if="{{isBack}}">
+      <text class="cuIcon-back"></text>
+      <slot name="backText"></slot>
+    </view>
+    <view class="action border-custom"  wx:if="{{isCustom}}" style="width:{{Custom.width}}px;height:{{Custom.height}}px;margin-left:calc(750rpx - {{Custom.right}}px)">
+      <text class="cuIcon-back" bindtap="BackPage"></text>
+      <text class="cuIcon-homefill" bindtap="toHome"></text>
+    </view>
+    <view class="content" style="top:{{StatusBar}}px">
+      <slot name="content"></slot>
+    </view>
+    <slot name="right"></slot>
+  </view>
+</view>

+ 1 - 0
colorui/components/cu-custom.wxss

@@ -0,0 +1 @@
+/* colorui/components/cu-custom.wxss */

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 36 - 0
colorui/icon.wxss


+ 3941 - 0
colorui/main.wxss

@@ -0,0 +1,3941 @@
+/*
+  ColorUi for MP-weixin  v2.1.4 | by 文晓港 2019年4月25日19:15:42
+  仅供学习交流,如作它用所承受的法律责任一概与作者无关
+  使用ColorUi开发扩展与插件时,请注明基于ColorUi开发
+  
+  (QQ交流群:240787041)
+*/
+
+/* ==================
+        初始化
+ ==================== */
+page {
+	/* Color 可以自定义相关配色 */
+	/* var属性兼容性 --> https://www.caniuse.com/#feat=css-variables */
+	/* 标准色 */
+	--red: #e54d42;
+	--orange: #f37b1d;
+	--yellow: #fbbd08;
+	--olive: #8dc63f;
+	--green: #39b54a;
+	--cyan: #1cbbb4;
+	--blue: #0081ff;
+	--purple: #6739b6;
+	--mauve: #9c26b0;
+	--pink: #e03997;
+	--brown: #a5673f;
+	--grey: #8799a3;
+	--black: #333333;
+	--darkGray: #666666;
+	--gray: #aaaaaa;
+	--ghostWhite: #f1f1f1;
+	--white: #ffffff;
+	/* 浅色 */
+	--redLight: #fadbd9;
+	--orangeLight: #fde6d2;
+	--yellowLight: #fef2ce;
+	--oliveLight: #e8f4d9;
+	--greenLight: #d7f0db;
+	--cyanLight: #d2f1f0;
+	--blueLight: #cce6ff;
+	--purpleLight: #e1d7f0;
+	--mauveLight: #ebd4ef;
+	--pinkLight: #f9d7ea;
+	--brownLight: #ede1d9;
+	--greyLight: #e7ebed;
+	/* 渐变色 */
+	--gradualRed: linear-gradient(45deg, #f43f3b, #ec008c);
+	--gradualOrange: linear-gradient(45deg, #ff9700, #ed1c24);
+	--gradualGreen: linear-gradient(45deg, #39b54a, #8dc63f);
+	--gradualPurple: linear-gradient(45deg, #9000ff, #5e00ff);
+	--gradualPink: linear-gradient(45deg, #ec008c, #6739b6);
+	--gradualBlue: linear-gradient(45deg, #0081ff, #1cbbb4);
+	/* 阴影透明色 */
+	--ShadowSize: 6rpx 6rpx 8rpx;
+	--redShadow: rgba(204, 69, 59, 0.2);
+	--orangeShadow: rgba(217, 109, 26, 0.2);
+	--yellowShadow: rgba(224, 170, 7, 0.2);
+	--oliveShadow: rgba(124, 173, 55, 0.2);
+	--greenShadow: rgba(48, 156, 63, 0.2);
+	--cyanShadow: rgba(28, 187, 180, 0.2);
+	--blueShadow: rgba(0, 102, 204, 0.2);
+	--purpleShadow: rgba(88, 48, 156, 0.2);
+	--mauveShadow: rgba(133, 33, 150, 0.2);
+	--pinkShadow: rgba(199, 50, 134, 0.2);
+	--brownShadow: rgba(140, 88, 53, 0.2);
+	--greyShadow: rgba(114, 130, 138, 0.2);
+	--grayShadow: rgba(114, 130, 138, 0.2);
+	--blackShadow: rgba(26, 26, 26, 0.2);
+
+	background-color: var(--ghostWhite);
+	font-size: 28rpx;
+	color: var(--black);
+	font-family: Helvetica Neue, Helvetica, sans-serif;
+}
+
+view,
+scroll-view,
+swiper,
+button,
+input,
+textarea,
+label,
+navigator,
+image {
+	box-sizing: border-box;
+}
+
+.round {
+	border-radius: 5000rpx;
+}
+
+.radius {
+	border-radius: 6rpx;
+}
+
+/* ==================
+          图片
+ ==================== */
+
+image {
+	max-width: 100%;
+	display: inline-block;
+	position: relative;
+	z-index: 0;
+}
+
+image.loading::before {
+	content: "";
+	background-color: #f5f5f5;
+	display: block;
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	z-index: -2;
+}
+
+image.loading::after {
+	content: "\e7f1";
+	font-family: "cuIcon";
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 32rpx;
+	height: 32rpx;
+	line-height: 32rpx;
+	right: 0;
+	bottom: 0;
+	z-index: -1;
+	font-size: 32rpx;
+	margin: auto;
+	color: #ccc;
+	-webkit-animation: cuIcon-spin 2s infinite linear;
+	animation: cuIcon-spin 2s infinite linear;
+	display: block;
+}
+
+.response {
+	width: 100%;
+}
+
+/* ==================
+         开关
+ ==================== */
+
+switch,
+checkbox,
+radio {
+	position: relative;
+}
+
+switch::after,
+switch::before {
+	font-family: "cuIcon";
+	content: "\e645";
+	position: absolute;
+	color: var(--white) !important;
+	top: 0%;
+	left: 0rpx;
+	font-size: 26rpx;
+	line-height: 26px;
+	width: 50%;
+	text-align: center;
+	pointer-events: none;
+	transform: scale(0, 0);
+	transition: all 0.3s ease-in-out 0s;
+	z-index: 9;
+	bottom: 0;
+	height: 26px;
+	margin: auto;
+}
+
+switch::before {
+	content: "\e646";
+	right: 0;
+	transform: scale(1, 1);
+	left: auto;
+}
+
+switch[checked]::after,
+switch.checked::after {
+	transform: scale(1, 1);
+}
+
+switch[checked]::before,
+switch.checked::before {
+	transform: scale(0, 0);
+}
+
+switch[checked]::before {
+	transform: scale(0, 0);
+}
+
+radio::before,
+checkbox::before {
+	font-family: "cuIcon";
+	content: "\e645";
+	position: absolute;
+	color: var(--white) !important;
+	top: 50%;
+	margin-top: -8px;
+	right: 5px;
+	font-size: 32rpx;
+	line-height: 16px;
+	pointer-events: none;
+	transform: scale(1, 1);
+	transition: all 0.3s ease-in-out 0s;
+	z-index: 9;
+}
+
+radio .wx-radio-input,
+checkbox .wx-checkbox-input {
+	margin: 0;
+	width: 24px;
+	height: 24px;
+}
+
+checkbox.round .wx-checkbox-input {
+	border-radius: 100rpx;
+}
+
+switch .wx-switch-input {
+	border: none;
+	padding: 0 24px;
+	width: 48px;
+	height: 26px;
+	margin: 0;
+	border-radius: 100rpx;
+}
+
+switch .wx-switch-input:not([class*="bg-"]) {
+	background: var(--grey) !important;
+}
+
+switch .wx-switch-input::after {
+	margin: auto;
+	width: 26px;
+	height: 26px;
+	border-radius: 100rpx;
+	left: 0rpx;
+	top: 0rpx;
+	bottom: 0rpx;
+	position: absolute;
+	transform: scale(0.9, 0.9);
+	transition: all 0.1s ease-in-out 0s;
+}
+
+switch .wx-switch-input.wx-switch-input-checked::after {
+	margin: auto;
+	left: 22px;
+	box-shadow: none;
+	transform: scale(0.9, 0.9);
+}
+
+radio-group {
+	display: inline-block;
+}
+
+
+
+switch.radius .wx-switch-input::after,
+switch.radius .wx-switch-input,
+switch.radius .wx-switch-input::before {
+	border-radius: 10rpx;
+}
+
+switch .wx-switch-input::before,
+radio.radio::before,
+checkbox .wx-checkbox-input::before,
+radio .wx-radio-input::before,
+radio.radio::before {
+	display: none;
+}
+
+radio.radio[checked]::after {
+	content: "";
+	background-color: transparent;
+	display: block;
+	position: absolute;
+	width: 8px;
+	height: 8px;
+	z-index: 999;
+	top: 0rpx;
+	left: 0rpx;
+	right: 0;
+	bottom: 0;
+	margin: auto;
+	border-radius: 200rpx;
+	border: 8px solid var(--white) !important;
+}
+
+.switch-sex::after {
+	content: "\e71c";
+}
+
+.switch-sex::before {
+	content: "\e71a";
+}
+
+.switch-sex .wx-switch-input {
+	background: var(--red) !important;
+	border-color: var(--red) !important;
+}
+
+.switch-sex[checked] .wx-switch-input {
+	background: var(--blue) !important;
+	border-color: var(--blue) !important;
+}
+
+switch.red[checked] .wx-switch-input,
+checkbox.red[checked] .wx-checkbox-input,
+radio.red[checked] .wx-radio-input {
+	border-color: var(--red) !important;
+}
+
+switch.orange[checked] .wx-switch-input,
+checkbox.orange[checked] .wx-checkbox-input,
+radio.orange[checked] .wx-radio-input {
+	border-color: var(--orange) !important;
+}
+
+switch.yellow[checked] .wx-switch-input,
+checkbox.yellow[checked] .wx-checkbox-input,
+radio.yellow[checked] .wx-radio-input {
+	border-color: var(--yellow) !important;
+}
+
+switch.olive[checked] .wx-switch-input,
+checkbox.olive[checked] .wx-checkbox-input,
+radio.olive[checked] .wx-radio-input {
+	border-color: var(--olive) !important;
+}
+
+switch.green[checked] .wx-switch-input,
+checkbox.green[checked] .wx-checkbox-input,
+checkbox[checked] .wx-checkbox-input,
+radio.green[checked] .wx-radio-input {
+	border-color: var(--green) !important;
+}
+
+switch.cyan[checked] .wx-switch-input,
+checkbox.cyan[checked] .wx-checkbox-input,
+radio.cyan[checked] .wx-radio-input {
+	border-color: var(--cyan) !important;
+}
+
+switch.blue[checked] .wx-switch-input,
+checkbox.blue[checked] .wx-checkbox-input,
+radio.blue[checked] .wx-radio-input {
+	border-color: var(--blue) !important;
+}
+
+switch.purple[checked] .wx-switch-input,
+checkbox.purple[checked] .wx-checkbox-input,
+radio.purple[checked] .wx-radio-input {
+	border-color: var(--purple) !important;
+}
+
+switch.mauve[checked] .wx-switch-input,
+checkbox.mauve[checked] .wx-checkbox-input,
+radio.mauve[checked] .wx-radio-input {
+	border-color: var(--mauve) !important;
+}
+
+switch.pink[checked] .wx-switch-input,
+checkbox.pink[checked] .wx-checkbox-input,
+radio.pink[checked] .wx-radio-input {
+	border-color: var(--pink) !important;
+}
+
+switch.brown[checked] .wx-switch-input,
+checkbox.brown[checked] .wx-checkbox-input,
+radio.brown[checked] .wx-radio-input {
+	border-color: var(--brown) !important;
+}
+
+switch.grey[checked] .wx-switch-input,
+checkbox.grey[checked] .wx-checkbox-input,
+radio.grey[checked] .wx-radio-input {
+	border-color: var(--grey) !important;
+}
+
+switch.gray[checked] .wx-switch-input,
+checkbox.gray[checked] .wx-checkbox-input,
+radio.gray[checked] .wx-radio-input {
+	border-color: var(--grey) !important;
+}
+
+switch.black[checked] .wx-switch-input,
+checkbox.black[checked] .wx-checkbox-input,
+radio.black[checked] .wx-radio-input {
+	border-color: var(--black) !important;
+}
+
+switch.white[checked] .wx-switch-input,
+checkbox.white[checked] .wx-checkbox-input,
+radio.white[checked] .wx-radio-input {
+	border-color: var(--white) !important;
+}
+
+switch.red[checked] .wx-switch-input.wx-switch-input-checked,
+checkbox.red[checked] .wx-checkbox-input,
+radio.red[checked] .wx-radio-input {
+	background-color: var(--red) !important;
+	color: var(--white) !important;
+}
+
+switch.orange[checked] .wx-switch-input,
+checkbox.orange[checked] .wx-checkbox-input,
+radio.orange[checked] .wx-radio-input {
+	background-color: var(--orange) !important;
+	color: var(--white) !important;
+}
+
+switch.yellow[checked] .wx-switch-input,
+checkbox.yellow[checked] .wx-checkbox-input,
+radio.yellow[checked] .wx-radio-input {
+	background-color: var(--yellow) !important;
+	color: var(--black) !important;
+}
+
+switch.olive[checked] .wx-switch-input,
+checkbox.olive[checked] .wx-checkbox-input,
+radio.olive[checked] .wx-radio-input {
+	background-color: var(--olive) !important;
+	color: var(--white) !important;
+}
+
+switch.green[checked] .wx-switch-input,
+switch[checked] .wx-switch-input,
+checkbox.green[checked] .wx-checkbox-input,
+checkbox[checked] .wx-checkbox-input,
+radio.green[checked] .wx-radio-input,
+radio[checked] .wx-radio-input {
+	background-color: var(--green) !important;
+	color: var(--white) !important;
+}
+
+switch.cyan[checked] .wx-switch-input,
+checkbox.cyan[checked] .wx-checkbox-input,
+radio.cyan[checked] .wx-radio-input {
+	background-color: var(--cyan) !important;
+	color: var(--white) !important;
+}
+
+switch.blue[checked] .wx-switch-input,
+checkbox.blue[checked] .wx-checkbox-input,
+radio.blue[checked] .wx-radio-input {
+	background-color: var(--blue) !important;
+	color: var(--white) !important;
+}
+
+switch.purple[checked] .wx-switch-input,
+checkbox.purple[checked] .wx-checkbox-input,
+radio.purple[checked] .wx-radio-input {
+	background-color: var(--purple) !important;
+	color: var(--white) !important;
+}
+
+switch.mauve[checked] .wx-switch-input,
+checkbox.mauve[checked] .wx-checkbox-input,
+radio.mauve[checked] .wx-radio-input {
+	background-color: var(--mauve) !important;
+	color: var(--white) !important;
+}
+
+switch.pink[checked] .wx-switch-input,
+checkbox.pink[checked] .wx-checkbox-input,
+radio.pink[checked] .wx-radio-input {
+	background-color: var(--pink) !important;
+	color: var(--white) !important;
+}
+
+switch.brown[checked] .wx-switch-input,
+checkbox.brown[checked] .wx-checkbox-input,
+radio.brown[checked] .wx-radio-input {
+	background-color: var(--brown) !important;
+	color: var(--white) !important;
+}
+
+switch.grey[checked] .wx-switch-input,
+checkbox.grey[checked] .wx-checkbox-input,
+radio.grey[checked] .wx-radio-input {
+	background-color: var(--grey) !important;
+	color: var(--white) !important;
+}
+
+switch.gray[checked] .wx-switch-input,
+checkbox.gray[checked] .wx-checkbox-input,
+radio.gray[checked] .wx-radio-input {
+	background-color: #f0f0f0 !important;
+	color: var(--black) !important;
+}
+
+switch.black[checked] .wx-switch-input,
+checkbox.black[checked] .wx-checkbox-input,
+radio.black[checked] .wx-radio-input {
+	background-color: var(--black) !important;
+	color: var(--white) !important;
+}
+
+switch.white[checked] .wx-switch-input,
+checkbox.white[checked] .wx-checkbox-input,
+radio.white[checked] .wx-radio-input {
+	background-color: var(--white) !important;
+	color: var(--black) !important;
+}
+
+/* ==================
+          边框
+ ==================== */
+
+/* -- 实线 -- */
+
+.solid,
+.solid-top,
+.solid-right,
+.solid-bottom,
+.solid-left,
+.solids,
+.solids-top,
+.solids-right,
+.solids-bottom,
+.solids-left,
+.dashed,
+.dashed-top,
+.dashed-right,
+.dashed-bottom,
+.dashed-left {
+	position: relative;
+}
+
+.solid::after,
+.solid-top::after,
+.solid-right::after,
+.solid-bottom::after,
+.solid-left::after,
+.solids::after,
+.solids-top::after,
+.solids-right::after,
+.solids-bottom::after,
+.solids-left::after,
+.dashed::after,
+.dashed-top::after,
+.dashed-right::after,
+.dashed-bottom::after,
+.dashed-left::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border-radius: inherit;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+}
+
+.solid::after {
+	border: 1rpx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-top::after {
+	border-top: 1rpx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-right::after {
+	border-right: 1rpx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-bottom::after {
+	border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-left::after {
+	border-left: 1rpx solid rgba(0, 0, 0, 0.1);
+}
+
+.solids::after {
+	border: 8rpx solid #eee;
+}
+
+.solids-top::after {
+	border-top: 8rpx solid #eee;
+}
+
+.solids-right::after {
+	border-right: 8rpx solid #eee;
+}
+
+.solids-bottom::after {
+	border-bottom: 8rpx solid #eee;
+}
+
+.solids-left::after {
+	border-left: 8rpx solid #eee;
+}
+
+/* -- 虚线 -- */
+
+.dashed::after {
+	border: 1rpx dashed #ddd;
+}
+
+.dashed-top::after {
+	border-top: 1rpx dashed #ddd;
+}
+
+.dashed-right::after {
+	border-right: 1rpx dashed #ddd;
+}
+
+.dashed-bottom::after {
+	border-bottom: 1rpx dashed #ddd;
+}
+
+.dashed-left::after {
+	border-left: 1rpx dashed #ddd;
+}
+
+/* -- 阴影 -- */
+
+.shadow[class*='white'] {
+	--ShadowSize: 0 1rpx 6rpx;
+}
+
+.shadow-lg {
+	--ShadowSize: 0rpx 40rpx 100rpx 0rpx;
+}
+
+.shadow-warp {
+	position: relative;
+	box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
+}
+
+.shadow-warp:before,
+.shadow-warp:after {
+	position: absolute;
+	content: "";
+	top: 20rpx;
+	bottom: 30rpx;
+	left: 20rpx;
+	width: 50%;
+	box-shadow: 0 30rpx 20rpx rgba(0, 0, 0, 0.2);
+	transform: rotate(-3deg);
+	z-index: -1;
+}
+
+.shadow-warp:after {
+	right: 20rpx;
+	left: auto;
+	transform: rotate(3deg);
+}
+
+.shadow-blur {
+	position: relative;
+}
+
+.shadow-blur::before {
+	content: "";
+	display: block;
+	background: inherit;
+	filter: blur(10rpx);
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	top: 10rpx;
+	left: 10rpx;
+	z-index: -1;
+	opacity: 0.4;
+	transform-origin: 0 0;
+	border-radius: inherit;
+	transform: scale(1, 1);
+}
+
+/* ==================
+          按钮
+ ==================== */
+
+.cu-btn {
+	position: relative;
+	border: 0rpx;
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	box-sizing: border-box;
+	padding: 0 30rpx;
+	font-size: 28rpx;
+	height: 64rpx;
+	line-height: 1;
+	text-align: center;
+	text-decoration: none;
+	overflow: visible;
+	margin-left: initial;
+	transform: translate(0rpx, 0rpx);
+	margin-right: initial;
+}
+
+.cu-btn::after {
+	display: none;
+}
+
+.cu-btn:not([class*="bg-"]) {
+	background-color: #f0f0f0;
+}
+
+.cu-btn[class*="line"] {
+	background-color: transparent;
+}
+
+.cu-btn[class*="line"]::after {
+	content: " ";
+	display: block;
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border: 1rpx solid currentColor;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	box-sizing: border-box;
+	border-radius: 12rpx;
+	z-index: 1;
+	pointer-events: none;
+}
+
+.cu-btn.round[class*="line"]::after {
+	border-radius: 1000rpx;
+}
+
+.cu-btn[class*="lines"]::after {
+	border: 6rpx solid currentColor;
+}
+
+.cu-btn[class*="bg-"]::after {
+	display: none;
+}
+
+.cu-btn.sm {
+	padding: 0 20rpx;
+	font-size: 20rpx;
+	height: 48rpx;
+}
+
+.cu-btn.lg {
+	padding: 0 40rpx;
+	font-size: 32rpx;
+	height: 80rpx;
+}
+
+.cu-btn.icon.sm {
+	width: 48rpx;
+	height: 48rpx;
+}
+
+.cu-btn.icon {
+	width: 64rpx;
+	height: 64rpx;
+	border-radius: 500rpx;
+	padding: 0;
+}
+
+button.icon.lg {
+	width: 80rpx;
+	height: 80rpx;
+}
+
+.cu-btn.shadow-blur::before {
+	top: 4rpx;
+	left: 4rpx;
+	filter: blur(6rpx);
+	opacity: 0.6;
+}
+
+.cu-btn.button-hover {
+	transform: translate(1rpx, 1rpx);
+}
+
+.block {
+	display: block;
+}
+
+.cu-btn.block {
+	display: flex;
+}
+
+.cu-btn[disabled] {
+	opacity: 0.6;
+	color: var(--white);
+}
+
+/* ==================
+          徽章
+ ==================== */
+
+.cu-tag {
+	font-size: 24rpx;
+	vertical-align: middle;
+	position: relative;
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	box-sizing: border-box;
+	padding: 0rpx 16rpx;
+	height: 48rpx;
+	font-family: Helvetica Neue, Helvetica, sans-serif;
+	white-space: nowrap;
+}
+
+.cu-tag:not([class*="bg"]):not([class*="line"]) {
+	background-color: var(--ghostWhite);
+}
+
+.cu-tag[class*="line-"]::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border: 1rpx solid currentColor;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	box-sizing: border-box;
+	border-radius: inherit;
+	z-index: 1;
+	pointer-events: none;
+}
+
+.cu-tag.radius[class*="line"]::after {
+	border-radius: 12rpx;
+}
+
+.cu-tag.round[class*="line"]::after {
+	border-radius: 1000rpx;
+}
+
+.cu-tag[class*="line-"]::after {
+	border-radius: 0;
+}
+
+.cu-tag+.cu-tag {
+	margin-left: 10rpx;
+}
+
+.cu-tag.sm {
+	font-size: 20rpx;
+	padding: 0rpx 12rpx;
+	height: 32rpx;
+}
+
+.cu-capsule {
+	display: inline-flex;
+	vertical-align: middle;
+}
+
+.cu-capsule+.cu-capsule {
+	margin-left: 10rpx;
+}
+
+.cu-capsule .cu-tag {
+	margin: 0;
+}
+
+.cu-capsule .cu-tag[class*="line-"]:last-child::after {
+	border-left: 0rpx solid transparent;
+}
+
+.cu-capsule .cu-tag[class*="line-"]:first-child::after {
+	border-right: 0rpx solid transparent;
+}
+
+.cu-capsule.radius .cu-tag:first-child {
+	border-top-left-radius: 6rpx;
+	border-bottom-left-radius: 6rpx;
+}
+
+.cu-capsule.radius .cu-tag:last-child::after,
+.cu-capsule.radius .cu-tag[class*="line-"] {
+	border-top-right-radius: 12rpx;
+	border-bottom-right-radius: 12rpx;
+}
+
+.cu-capsule.round .cu-tag:first-child {
+	border-top-left-radius: 200rpx;
+	border-bottom-left-radius: 200rpx;
+	text-indent: 4rpx;
+}
+
+.cu-capsule.round .cu-tag:last-child::after,
+.cu-capsule.round .cu-tag:last-child {
+	border-top-right-radius: 200rpx;
+	border-bottom-right-radius: 200rpx;
+	text-indent: -4rpx;
+}
+
+.cu-tag.badge {
+	border-radius: 200rpx;
+	position: absolute;
+	top: -10rpx;
+	right: -10rpx;
+	font-size: 20rpx;
+	padding: 0rpx 10rpx;
+	height: 28rpx;
+	color: var(--white);
+}
+
+.cu-tag.badge:not([class*="bg-"]) {
+	background-color: #dd514c;
+}
+
+.cu-tag:empty:not([class*="cuIcon-"]) {
+	padding: 0rpx;
+	width: 16rpx;
+	height: 16rpx;
+	top: -4rpx;
+	right: -4rpx;
+}
+
+.cu-tag[class*="cuIcon-"] {
+	width: 32rpx;
+	height: 32rpx;
+	top: -4rpx;
+	right: -4rpx;
+}
+
+/* ==================
+          头像
+ ==================== */
+
+.cu-avatar {
+	font-variant: small-caps;
+	margin: 0;
+	padding: 0;
+	display: inline-flex;
+	text-align: center;
+	justify-content: center;
+	align-items: center;
+	background-color: #ccc;
+	color: var(--white);
+	white-space: nowrap;
+	position: relative;
+	width: 64rpx;
+	height: 64rpx;
+	background-size: cover;
+	background-position: center;
+	vertical-align: middle;
+	font-size: 1.5em;
+}
+
+.cu-avatar.sm {
+	width: 48rpx;
+	height: 48rpx;
+	font-size: 1em;
+}
+
+.cu-avatar.lg {
+	width: 96rpx;
+	height: 96rpx;
+	font-size: 2em;
+}
+
+.cu-avatar.xl {
+	width: 128rpx;
+	height: 128rpx;
+	font-size: 2.5em;
+}
+
+.cu-avatar .avatar-text {
+	font-size: 0.4em;
+}
+
+.cu-avatar-group {
+	direction: rtl;
+	unicode-bidi: bidi-override;
+	padding: 0 10rpx 0 40rpx;
+	display: inline-block;
+}
+
+.cu-avatar-group .cu-avatar {
+	margin-left: -30rpx;
+	border: 4rpx solid var(--ghostWhite);
+	vertical-align: middle;
+}
+
+.cu-avatar-group .cu-avatar.sm {
+	margin-left: -20rpx;
+	border: 1rpx solid var(--ghostWhite);
+}
+
+/* ==================
+         进度条
+ ==================== */
+
+.cu-progress {
+	overflow: hidden;
+	height: 28rpx;
+	background-color: #ebeef5;
+	display: inline-flex;
+	align-items: center;
+	width: 100%;
+}
+
+.cu-progress+view,
+.cu-progress+text {
+	line-height: 1;
+}
+
+.cu-progress.xs {
+	height: 10rpx;
+}
+
+.cu-progress.sm {
+	height: 20rpx;
+}
+
+.cu-progress view {
+	width: 0;
+	height: 100%;
+	align-items: center;
+	display: flex;
+	justify-items: flex-end;
+	justify-content: space-around;
+	font-size: 20rpx;
+	color: var(--white);
+	transition: width 0.6s ease;
+}
+
+.cu-progress text {
+	align-items: center;
+	display: flex;
+	font-size: 20rpx;
+	color: var(--black);
+	text-indent: 10rpx;
+}
+
+.cu-progress.text-progress {
+	padding-right: 60rpx;
+}
+
+.cu-progress.striped view {
+	background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+	background-size: 72rpx 72rpx;
+}
+
+.cu-progress.active view {
+	animation: progress-stripes 2s linear infinite;
+}
+
+@keyframes progress-stripes {
+	from {
+		background-position: 72rpx 0;
+	}
+
+	to {
+		background-position: 0 0;
+	}
+}
+
+/* ==================
+          加载
+ ==================== */
+
+.cu-load {
+	display: block;
+	line-height: 3em;
+	text-align: center;
+}
+
+.cu-load::before {
+	font-family: "cuIcon";
+	display: inline-block;
+	margin-right: 6rpx;
+}
+
+.cu-load.loading::before {
+	content: "\e67a";
+	animation: cuIcon-spin 2s infinite linear;
+}
+
+.cu-load.loading::after {
+	content: "加载中...";
+}
+
+.cu-load.over::before {
+	content: "\e64a";
+}
+
+.cu-load.over::after {
+	content: "没有更多了";
+}
+
+.cu-load.erro::before {
+	content: "\e658";
+}
+
+.cu-load.erro::after {
+	content: "加载失败";
+}
+
+.cu-load.load-icon::before {
+	font-size: 32rpx;
+}
+
+.cu-load.load-icon::after {
+	display: none;
+}
+
+.cu-load.load-icon.over {
+	display: none;
+}
+
+.cu-load.load-modal {
+	position: fixed;
+	top: 0;
+	right: 0;
+	bottom: 140rpx;
+	left: 0;
+	margin: auto;
+	width: 260rpx;
+	height: 260rpx;
+	background-color: var(--white);
+	border-radius: 10rpx;
+	box-shadow: 0 0 0rpx 2000rpx rgba(0, 0, 0, 0.5);
+	display: flex;
+	align-items: center;
+	flex-direction: column;
+	justify-content: center;
+	font-size: 28rpx;
+	z-index: 9999;
+	line-height: 2.4em;
+}
+
+.cu-load.load-modal [class*="cuIcon-"] {
+	font-size: 60rpx;
+}
+
+.cu-load.load-modal image {
+	width: 70rpx;
+	height: 70rpx;
+}
+
+.cu-load.load-modal::after {
+	content: "";
+	position: absolute;
+	background-color: var(--white);
+	border-radius: 50%;
+	width: 200rpx;
+	height: 200rpx;
+	font-size: 10px;
+	border-top: 6rpx solid rgba(0, 0, 0, 0.05);
+	border-right: 6rpx solid rgba(0, 0, 0, 0.05);
+	border-bottom: 6rpx solid rgba(0, 0, 0, 0.05);
+	border-left: 6rpx solid var(--orange);
+	animation: cuIcon-spin 1s infinite linear;
+	z-index: -1;
+}
+
+.load-progress {
+	pointer-events: none;
+	top: 0;
+	position: fixed;
+	width: 100%;
+	left: 0;
+	z-index: 2000;
+}
+
+.load-progress.hide {
+	display: none;
+}
+
+.load-progress .load-progress-bar {
+	position: relative;
+	width: 100%;
+	height: 4rpx;
+	overflow: hidden;
+	transition: all 200ms ease 0s;
+}
+
+.load-progress .load-progress-spinner {
+	position: absolute;
+	top: 10rpx;
+	right: 10rpx;
+	z-index: 2000;
+	display: block;
+}
+
+.load-progress .load-progress-spinner::after {
+	content: "";
+	display: block;
+	width: 24rpx;
+	height: 24rpx;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+	border: solid 4rpx transparent;
+	border-top-color: inherit;
+	border-left-color: inherit;
+	border-radius: 50%;
+	-webkit-animation: load-progress-spinner 0.4s linear infinite;
+	animation: load-progress-spinner 0.4s linear infinite;
+}
+
+@-webkit-keyframes load-progress-spinner {
+	0% {
+		-webkit-transform: rotate(0);
+		transform: rotate(0);
+	}
+
+	100% {
+		-webkit-transform: rotate(360deg);
+		transform: rotate(360deg);
+	}
+}
+
+@keyframes load-progress-spinner {
+	0% {
+		-webkit-transform: rotate(0);
+		transform: rotate(0);
+	}
+
+	100% {
+		-webkit-transform: rotate(360deg);
+		transform: rotate(360deg);
+	}
+}
+
+/* ==================
+          列表
+ ==================== */
+.grayscale {
+	filter: grayscale(1);
+}
+
+.cu-list+.cu-list {
+	margin-top: 30rpx
+}
+
+.cu-list>.cu-item {
+	transition: all .6s ease-in-out 0s;
+	transform: translateX(0rpx)
+}
+
+.cu-list>.cu-item.move-cur {
+	transform: translateX(-260rpx)
+}
+
+.cu-list>.cu-item .move {
+	position: absolute;
+	right: 0;
+	display: flex;
+	width: 260rpx;
+	height: 100%;
+	transform: translateX(100%)
+}
+
+.cu-list>.cu-item .move view {
+	display: flex;
+	flex: 1;
+	justify-content: center;
+	align-items: center
+}
+
+.cu-list.menu-avatar {
+	overflow: hidden;
+}
+
+.cu-list.menu-avatar>.cu-item {
+	position: relative;
+	display: flex;
+	padding-right: 10rpx;
+	height: 140rpx;
+	background-color: var(--white);
+	justify-content: flex-end;
+	align-items: center
+}
+
+.cu-list.menu-avatar>.cu-item>.cu-avatar {
+	position: absolute;
+	left: 30rpx
+}
+
+.cu-list.menu-avatar>.cu-item .flex .text-cut {
+	max-width: 510rpx
+}
+
+.cu-list.menu-avatar>.cu-item .content {
+	position: absolute;
+	left: 146rpx;
+	width: calc(100% - 96rpx - 60rpx - 120rpx - 20rpx);
+	line-height: 1.6em;
+}
+
+.cu-list.menu-avatar>.cu-item .content.flex-sub {
+	width: calc(100% - 96rpx - 60rpx - 20rpx);
+}
+
+.cu-list.menu-avatar>.cu-item .content>view:first-child {
+	font-size: 30rpx;
+	display: flex;
+	align-items: center
+}
+
+.cu-list.menu-avatar>.cu-item .content .cu-tag.sm {
+	display: inline-block;
+	margin-left: 10rpx;
+	height: 28rpx;
+	font-size: 16rpx;
+	line-height: 32rpx
+}
+
+.cu-list.menu-avatar>.cu-item .action {
+	width: 100rpx;
+	text-align: center
+}
+
+.cu-list.menu-avatar>.cu-item .action view+view {
+	margin-top: 10rpx
+}
+
+.cu-list.menu-avatar.comment>.cu-item .content {
+	position: relative;
+	left: 0;
+	width: auto;
+	flex: 1;
+}
+
+.cu-list.menu-avatar.comment>.cu-item {
+	padding: 30rpx 30rpx 30rpx 120rpx;
+	height: auto
+}
+
+.cu-list.menu-avatar.comment .cu-avatar {
+	align-self: flex-start
+}
+
+.cu-list.menu>.cu-item {
+	position: relative;
+	display: flex;
+	padding: 0 30rpx;
+	min-height: 100rpx;
+	background-color: var(--white);
+	justify-content: space-between;
+	align-items: center
+}
+
+.cu-list.menu>.cu-item:last-child:after {
+	border: none
+}
+
+.cu-list.menu>.cu-item:after {
+	position: absolute;
+	top: 0;
+	left: 0;
+	box-sizing: border-box;
+	width: 200%;
+	height: 200%;
+	border-bottom: 1rpx solid #ddd;
+	border-radius: inherit;
+	content: " ";
+	transform: scale(.5);
+	transform-origin: 0 0;
+	pointer-events: none
+}
+
+.cu-list.menu>.cu-item.grayscale {
+	background-color: #f5f5f5
+}
+
+.cu-list.menu>.cu-item.cur {
+	background-color: #fcf7e9
+}
+
+.cu-list.menu>.cu-item.arrow {
+	padding-right: 90rpx
+}
+
+.cu-list.menu>.cu-item.arrow:before {
+	position: absolute;
+	top: 0;
+	right: 30rpx;
+	bottom: 0;
+	display: block;
+	margin: auto;
+	width: 30rpx;
+	height: 30rpx;
+	color: var(--grey);
+	content: "\e6a3";
+	text-align: center;
+	font-size: 34rpx;
+	font-family: "cuIcon";
+	line-height: 30rpx
+}
+
+.cu-list.menu>.cu-item button.content {
+	padding: 0;
+	background-color: transparent;
+	justify-content: flex-start
+}
+
+.cu-list.menu>.cu-item button.content:after {
+	display: none
+}
+
+.cu-list.menu>.cu-item .cu-avatar-group .cu-avatar {
+	border-color: var(--white)
+}
+
+.cu-list.menu>.cu-item .content>view:first-child {
+	display: flex;
+	align-items: center
+}
+
+.cu-list.menu>.cu-item .content>text[class*=cuIcon] {
+	display: inline-block;
+	margin-right: 10rpx;
+	width: 1.6em;
+	text-align: center
+}
+
+.cu-list.menu>.cu-item .content>image {
+	display: inline-block;
+	margin-right: 10rpx;
+	width: 1.6em;
+	height: 1.6em;
+	vertical-align: middle
+}
+
+.cu-list.menu>.cu-item .content {
+	font-size: 30rpx;
+	line-height: 1.6em;
+	flex: 1
+}
+
+.cu-list.menu>.cu-item .content .cu-tag.sm {
+	display: inline-block;
+	margin-left: 10rpx;
+	height: 28rpx;
+	font-size: 16rpx;
+	line-height: 32rpx
+}
+
+.cu-list.menu>.cu-item .action .cu-tag:empty {
+	right: 10rpx
+}
+
+.cu-list.menu {
+	display: block;
+	overflow: hidden
+}
+
+.cu-list.menu.sm-border>.cu-item:after {
+	left: 30rpx;
+	width: calc(200% - 120rpx)
+}
+
+.cu-list.grid>.cu-item {
+	position: relative;
+	display: flex;
+	padding: 20rpx 0 30rpx;
+	transition-duration: 0s;
+	flex-direction: column
+}
+
+.cu-list.grid>.cu-item:after {
+	position: absolute;
+	top: 0;
+	left: 0;
+	box-sizing: border-box;
+	width: 200%;
+	height: 200%;
+	border-right: 1px solid rgba(0, 0, 0, .1);
+	border-bottom: 1px solid rgba(0, 0, 0, .1);
+	border-radius: inherit;
+	content: " ";
+	transform: scale(.5);
+	transform-origin: 0 0;
+	pointer-events: none
+}
+
+.cu-list.grid>.cu-item text {
+	display: block;
+	margin-top: 10rpx;
+	color: #888;
+	font-size: 26rpx;
+	line-height: 40rpx
+}
+
+.cu-list.grid>.cu-item [class*=cuIcon] {
+	position: relative;
+	display: block;
+	margin-top: 20rpx;
+	width: 100%;
+	font-size: 48rpx
+}
+
+.cu-list.grid>.cu-item .cu-tag {
+	right: auto;
+	left: 50%;
+	margin-left: 20rpx
+}
+
+.cu-list.grid {
+	background-color: var(--white);
+	text-align: center
+}
+
+.cu-list.grid.no-border>.cu-item {
+	padding-top: 10rpx;
+	padding-bottom: 20rpx
+}
+
+.cu-list.grid.no-border>.cu-item:after {
+	border: none
+}
+
+.cu-list.grid.no-border {
+	padding: 20rpx 10rpx
+}
+
+.cu-list.grid.col-3>.cu-item:nth-child(3n):after,
+.cu-list.grid.col-4>.cu-item:nth-child(4n):after,
+.cu-list.grid.col-5>.cu-item:nth-child(5n):after {
+	border-right-width: 0
+}
+
+.cu-list.card-menu {
+	overflow: hidden;
+	margin-right: 30rpx;
+	margin-left: 30rpx;
+	border-radius: 20rpx
+}
+
+
+/* ==================
+          操作条
+ ==================== */
+
+.cu-bar {
+	display: flex;
+	position: relative;
+	align-items: center;
+	min-height: 100rpx;
+	justify-content: space-between;
+}
+
+.cu-bar .action {
+	display: flex;
+	align-items: center;
+	height: 100%;
+	justify-content: center;
+	max-width: 100%;
+}
+
+.cu-bar .action.border-title {
+	position: relative;
+	top: -10rpx;
+}
+
+.cu-bar .action.border-title text[class*="bg-"]:last-child {
+	position: absolute;
+	bottom: -0.5rem;
+	min-width: 2rem;
+	height: 6rpx;
+	left: 0;
+}
+
+.cu-bar .action.sub-title {
+	position: relative;
+	top: -0.2rem;
+}
+
+.cu-bar .action.sub-title text {
+	position: relative;
+	z-index: 1;
+}
+
+.cu-bar .action.sub-title text[class*="bg-"]:last-child {
+	position: absolute;
+	display: inline-block;
+	bottom: -0.2rem;
+	border-radius: 6rpx;
+	width: 100%;
+	height: 0.6rem;
+	left: 0.6rem;
+	opacity: 0.3;
+	z-index: 0;
+}
+
+.cu-bar .action.sub-title text[class*="text-"]:last-child {
+	position: absolute;
+	display: inline-block;
+	bottom: -0.7rem;
+	left: 0.5rem;
+	opacity: 0.2;
+	z-index: 0;
+	text-align: right;
+	font-weight: 900;
+	font-size: 36rpx;
+}
+
+.cu-bar.justify-center .action.border-title text:last-child,
+.cu-bar.justify-center .action.sub-title text:last-child {
+	left: 0;
+	right: 0;
+	margin: auto;
+	text-align: center;
+}
+
+.cu-bar .action:first-child {
+	margin-left: 30rpx;
+	font-size: 30rpx;
+}
+
+.cu-bar .action text.text-cut {
+	text-align: left;
+	width: 100%;
+}
+
+.cu-bar .cu-avatar:first-child {
+	margin-left: 20rpx;
+}
+
+.cu-bar .action:first-child>text[class*="cuIcon-"] {
+	margin-left: -0.3em;
+	margin-right: 0.3em;
+}
+
+.cu-bar .action:last-child {
+	margin-right: 30rpx;
+}
+
+.cu-bar .action>text[class*="cuIcon-"],
+.cu-bar .action>view[class*="cuIcon-"] {
+	font-size: 36rpx;
+}
+
+.cu-bar .action>text[class*="cuIcon-"]+text[class*="cuIcon-"] {
+	margin-left: 0.5em;
+}
+
+.cu-bar .content {
+	position: absolute;
+	text-align: center;
+	width: calc(100% - 340rpx);
+	left: 0;
+	right: 0;
+	bottom: 0;
+	top: 0;
+	margin: auto;
+	height: 60rpx;
+	font-size: 32rpx;
+	line-height: 60rpx;
+	cursor: none;
+	pointer-events: none;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+}
+
+.cu-bar.ios .content {
+	bottom: 7px;
+	height: 30px;
+	font-size: 32rpx;
+	line-height: 30px;
+}
+
+.cu-bar.btn-group {
+	justify-content: space-around;
+}
+
+.cu-bar.btn-group button {
+	padding: 20rpx 32rpx;
+}
+
+.cu-bar.btn-group button {
+	flex: 1;
+	margin: 0 20rpx;
+	max-width: 50%;
+}
+
+.cu-bar .search-form {
+	background-color: #f5f5f5;
+	line-height: 64rpx;
+	height: 64rpx;
+	font-size: 24rpx;
+	color: var(--black);
+	flex: 1;
+	display: flex;
+	align-items: center;
+	margin: 0 30rpx;
+}
+
+.cu-bar .search-form+.action {
+	margin-right: 30rpx;
+}
+
+.cu-bar .search-form input {
+	flex: 1;
+	padding-right: 30rpx;
+	height: 64rpx;
+	line-height: 64rpx;
+	font-size: 26rpx;
+	background-color: transparent;
+}
+
+.cu-bar .search-form [class*="cuIcon-"] {
+	margin: 0 0.5em 0 0.8em;
+}
+
+.cu-bar .search-form [class*="cuIcon-"]::before {
+	top: 0rpx;
+}
+
+.cu-bar.fixed,
+.nav.fixed {
+	position: fixed;
+	width: 100%;
+	top: 0;
+	z-index: 1024;
+	box-shadow: 0 1rpx 6rpx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.foot {
+	position: fixed;
+	width: 100%;
+	bottom: 0;
+	z-index: 1024;
+	box-shadow: 0 -1rpx 6rpx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.tabbar {
+	padding: 0;
+	height: calc(100rpx + env(safe-area-inset-bottom) / 2);
+	padding-bottom: calc(env(safe-area-inset-bottom) / 2);
+}
+
+.cu-tabbar-height {
+	min-height: 100rpx;
+	height: calc(100rpx + env(safe-area-inset-bottom) / 2);
+}
+
+.cu-bar.tabbar.shadow {
+	box-shadow: 0 -1rpx 6rpx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.tabbar .action {
+	font-size: 22rpx;
+	position: relative;
+	flex: 1;
+	text-align: center;
+	padding: 0;
+	display: block;
+	height: auto;
+	line-height: 1;
+	margin: 0;
+	overflow: initial;
+}
+
+.cu-bar.tabbar.shop .action {
+	width: 140rpx;
+	flex: initial;
+}
+
+.cu-bar.tabbar .action.add-action {
+	position: relative;
+	z-index: 2;
+	padding-top: 50rpx;
+	background-color: inherit;
+}
+
+.cu-bar.tabbar .action.add-action [class*="cuIcon-"] {
+	position: absolute;
+	width: 70rpx;
+	z-index: 2;
+	height: 70rpx;
+	border-radius: 50%;
+	line-height: 70rpx;
+	font-size: 50rpx;
+	top: -35rpx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	padding: 0;
+}
+
+.cu-bar.tabbar .action.add-action::after {
+	content: "";
+	position: absolute;
+	width: 100rpx;
+	height: 100rpx;
+	top: -50rpx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	box-shadow: 0 -3rpx 8rpx rgba(0, 0, 0, 0.08);
+	border-radius: 50rpx;
+	background-color: inherit;
+	z-index: 0;
+}
+
+.cu-bar.tabbar .action.add-action::before {
+	content: "";
+	position: absolute;
+	width: 100rpx;
+	height: 30rpx;
+	bottom: 30rpx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	background-color: inherit;
+	z-index: 1;
+}
+
+.cu-bar.tabbar .btn-group {
+	flex: 1;
+	display: flex;
+	justify-content: space-around;
+	align-items: center;
+	padding: 0 10rpx;
+}
+
+.cu-bar.tabbar button.action::after {
+	border: 0;
+}
+
+.cu-bar.tabbar .action [class*="cuIcon-"] {
+	width: 100rpx;
+	position: relative;
+	display: block;
+	height: auto;
+	margin: 0 auto 10rpx;
+	text-align: center;
+	font-size: 40rpx;
+}
+
+.cu-bar.tabbar .action .cuIcon-cu-image {
+	margin: 0 auto;
+}
+
+.cu-bar.tabbar .action .cuIcon-cu-image image {
+	width: 50rpx;
+	height: 50rpx;
+	display: inline-block;
+}
+
+.cu-bar.tabbar .submit {
+	align-items: center;
+	display: flex;
+	justify-content: center;
+	text-align: center;
+	position: relative;
+	flex: 2;
+	align-self: stretch;
+}
+
+.cu-bar.tabbar .submit:last-child {
+	flex: 2.6;
+}
+
+.cu-bar.tabbar .submit+.submit {
+	flex: 2;
+}
+
+.cu-bar.tabbar.border .action::before {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	border-right: 1rpx solid rgba(0, 0, 0, 0.1);
+	z-index: 3;
+}
+
+.cu-bar.tabbar.border .action:last-child:before {
+	display: none;
+}
+
+.cu-bar.input {
+	padding-right: 20rpx;
+	background-color: var(--white);
+}
+
+.cu-bar.input input {
+	overflow: initial;
+	line-height: 64rpx;
+	height: 64rpx;
+	min-height: 64rpx;
+	flex: 1;
+	font-size: 30rpx;
+	margin: 0 20rpx;
+}
+
+.cu-bar.input .action {
+	margin-left: 20rpx;
+}
+
+.cu-bar.input .action [class*="cuIcon-"] {
+	font-size: 48rpx;
+}
+
+.cu-bar.input input+.action {
+	margin-right: 20rpx;
+	margin-left: 0rpx;
+}
+
+.cu-bar.input .action:first-child [class*="cuIcon-"] {
+	margin-left: 0rpx;
+}
+
+.cu-custom {
+	display: block;
+	position: relative;
+}
+
+.cu-custom .cu-bar .content {
+	width: calc(100% - 440rpx);
+}
+
+
+.cu-custom .cu-bar .content image {
+	height: 60rpx;
+	width: 240rpx;
+}
+
+.cu-custom .cu-bar {
+	min-height: 0px;
+	padding-right: 220rpx;
+	box-shadow: 0rpx 0rpx 0rpx;
+	z-index: 9999;
+}
+
+.cu-custom .cu-bar .border-custom {
+	position: relative;
+	background: rgba(0, 0, 0, 0.15);
+	border-radius: 1000rpx;
+	height: 30px;
+}
+
+.cu-custom .cu-bar .border-custom::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border-radius: inherit;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+	border: 1rpx solid var(--white);
+	opacity: 0.5;
+}
+
+.cu-custom .cu-bar .border-custom::before {
+	content: " ";
+	width: 1rpx;
+	height: 110%;
+	position: absolute;
+	top: 22.5%;
+	left: 0;
+	right: 0;
+	margin: auto;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+	opacity: 0.6;
+	background-color: var(--white);
+}
+
+.cu-custom .cu-bar .border-custom text {
+	display: block;
+	flex: 1;
+	margin: auto !important;
+	text-align: center;
+	font-size: 34rpx;
+}
+
+/* ==================
+         导航栏
+ ==================== */
+
+.nav {
+	white-space: nowrap;
+}
+
+::-webkit-scrollbar {
+	display: none;
+}
+
+.nav .cu-item {
+	height: 90rpx;
+	display: inline-block;
+	line-height: 90rpx;
+	margin: 0 10rpx;
+	padding: 0 20rpx;
+}
+
+.nav .cu-item.cur {
+	border-bottom: 4rpx solid;
+}
+
+/* ==================
+         时间轴
+ ==================== */
+
+.cu-timeline {
+	display: block;
+	background-color: var(--white);
+}
+
+.cu-timeline .cu-time {
+	width: 120rpx;
+	text-align: center;
+	padding: 20rpx 0;
+	font-size: 26rpx;
+	color: #888;
+	display: block;
+}
+
+.cu-timeline>.cu-item {
+	padding: 30rpx 30rpx 30rpx 120rpx;
+	position: relative;
+	display: block;
+	z-index: 0;
+}
+
+.cu-timeline>.cu-item:not([class*="text-"]) {
+	color: #ccc;
+}
+
+.cu-timeline>.cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	width: 1rpx;
+	background-color: #ddd;
+	left: 60rpx;
+	height: 100%;
+	top: 0;
+	z-index: 8;
+}
+
+.cu-timeline>.cu-item::before {
+	font-family: "cuIcon";
+	display: block;
+	position: absolute;
+	top: 36rpx;
+	z-index: 9;
+	background-color: var(--white);
+	width: 50rpx;
+	height: 50rpx;
+	text-align: center;
+	border: none;
+	line-height: 50rpx;
+	left: 36rpx;
+}
+
+.cu-timeline>.cu-item:not([class*="cuIcon-"])::before {
+	content: "\e763";
+}
+
+.cu-timeline>.cu-item[class*="cuIcon-"]::before {
+	background-color: var(--white);
+	width: 50rpx;
+	height: 50rpx;
+	text-align: center;
+	border: none;
+	line-height: 50rpx;
+	left: 36rpx;
+}
+
+.cu-timeline>.cu-item>.content {
+	padding: 30rpx;
+	border-radius: 6rpx;
+	display: block;
+	line-height: 1.6;
+}
+
+.cu-timeline>.cu-item>.content:not([class*="bg-"]) {
+	background-color: var(--ghostWhite);
+	color: var(--black);
+}
+
+.cu-timeline>.cu-item>.content+.content {
+	margin-top: 20rpx;
+}
+
+/* ==================
+         聊天
+ ==================== */
+
+.cu-chat {
+	display: flex;
+	flex-direction: column;
+}
+
+.cu-chat .cu-item {
+	display: flex;
+	padding: 30rpx 30rpx 70rpx;
+	position: relative;
+}
+
+.cu-chat .cu-item>.cu-avatar {
+	width: 80rpx;
+	height: 80rpx;
+}
+
+.cu-chat .cu-item>.main {
+	max-width: calc(100% - 260rpx);
+	margin: 0 40rpx;
+	display: flex;
+	align-items: center;
+}
+
+.cu-chat .cu-item>image {
+	height: 320rpx;
+}
+
+.cu-chat .cu-item>.main .content {
+	padding: 20rpx;
+	border-radius: 6rpx;
+	display: inline-flex;
+	max-width: 100%;
+	align-items: center;
+	font-size: 30rpx;
+	position: relative;
+	min-height: 80rpx;
+	line-height: 40rpx;
+	text-align: left;
+}
+
+.cu-chat .cu-item>.main .content:not([class*="bg-"]) {
+	background-color: var(--white);
+	color: var(--black);
+}
+
+.cu-chat .cu-item .date {
+	position: absolute;
+	font-size: 24rpx;
+	color: var(--grey);
+	width: calc(100% - 320rpx);
+	bottom: 20rpx;
+	left: 160rpx;
+}
+
+.cu-chat .cu-item .action {
+	padding: 0 30rpx;
+	display: flex;
+	align-items: center;
+}
+
+.cu-chat .cu-item>.main .content::after {
+	content: "";
+	top: 27rpx;
+	transform: rotate(45deg);
+	position: absolute;
+	z-index: 100;
+	display: inline-block;
+	overflow: hidden;
+	width: 24rpx;
+	height: 24rpx;
+	left: -12rpx;
+	right: initial;
+	background-color: inherit;
+}
+
+.cu-chat .cu-item.self>.main .content::after {
+	left: auto;
+	right: -12rpx;
+}
+
+.cu-chat .cu-item>.main .content::before {
+	content: "";
+	top: 30rpx;
+	transform: rotate(45deg);
+	position: absolute;
+	z-index: -1;
+	display: inline-block;
+	overflow: hidden;
+	width: 24rpx;
+	height: 24rpx;
+	left: -12rpx;
+	right: initial;
+	background-color: inherit;
+	filter: blur(5rpx);
+	opacity: 0.3;
+}
+
+.cu-chat .cu-item>.main .content:not([class*="bg-"])::before {
+	background-color: var(--black);
+	opacity: 0.1;
+}
+
+.cu-chat .cu-item.self>.main .content::before {
+	left: auto;
+	right: -12rpx;
+}
+
+.cu-chat .cu-item.self {
+	justify-content: flex-end;
+	text-align: right;
+}
+
+.cu-chat .cu-info {
+	display: inline-block;
+	margin: 20rpx auto;
+	font-size: 24rpx;
+	padding: 8rpx 12rpx;
+	background-color: rgba(0, 0, 0, 0.2);
+	border-radius: 6rpx;
+	color: var(--white);
+	max-width: 400rpx;
+	line-height: 1.4;
+}
+
+/* ==================
+         卡片
+ ==================== */
+
+.cu-card {
+	display: block;
+	overflow: hidden;
+}
+
+.cu-card>.cu-item {
+	display: block;
+	background-color: var(--white);
+	overflow: hidden;
+	border-radius: 10rpx;
+	margin: 30rpx;
+}
+
+.cu-card>.cu-item.shadow-blur {
+	overflow: initial;
+}
+
+.cu-card.no-card>.cu-item {
+	margin: 0rpx;
+	border-radius: 0rpx;
+}
+
+.cu-card .grid.grid-square {
+	margin-bottom: -20rpx;
+}
+
+.cu-card.case .image {
+	position: relative;
+}
+
+.cu-card.case .image image {
+	width: 100%;
+}
+
+.cu-card.case .image .cu-tag {
+	position: absolute;
+	right: 0;
+	top: 0;
+}
+
+.cu-card.case .image .cu-bar {
+	position: absolute;
+	bottom: 0;
+	width: 100%;
+	background-color: transparent;
+	padding: 0rpx 30rpx;
+}
+
+.cu-card.case.no-card .image {
+	margin: 30rpx 30rpx 0;
+	overflow: hidden;
+	border-radius: 10rpx;
+}
+
+.cu-card.dynamic {
+	display: block;
+}
+
+.cu-card.dynamic>.cu-item {
+	display: block;
+	background-color: var(--white);
+	overflow: hidden;
+}
+
+.cu-card.dynamic>.cu-item>.text-content {
+	padding: 0 30rpx 0;
+	max-height: 6.4em;
+	overflow: hidden;
+	font-size: 30rpx;
+	margin-bottom: 20rpx;
+}
+
+.cu-card.dynamic>.cu-item .square-img {
+	width: 100%;
+	height: 200rpx;
+	border-radius: 6rpx;
+}
+
+.cu-card.dynamic>.cu-item .only-img {
+	width: 100%;
+	height: 320rpx;
+	border-radius: 6rpx;
+}
+
+.cu-card.article {
+	display: block;
+}
+
+.cu-card.article>.cu-item {
+	padding-bottom: 30rpx;
+}
+
+.cu-card.article>.cu-item .title {
+	font-size: 30rpx;
+	font-weight: 900;
+	color: var(--black);
+	line-height: 100rpx;
+	padding: 0 30rpx;
+}
+
+.cu-card.article>.cu-item .content {
+	display: flex;
+	padding: 0 30rpx;
+}
+
+.cu-card.article>.cu-item .content>image {
+	width: 240rpx;
+	height: 6.4em;
+	margin-right: 20rpx;
+	border-radius: 6rpx;
+}
+
+.cu-card.article>.cu-item .content .desc {
+	flex: 1;
+	display: flex;
+	flex-direction: column;
+	justify-content: space-between;
+}
+
+.cu-card.article>.cu-item .content .text-content {
+	font-size: 28rpx;
+	color: #888;
+	height: 4.8em;
+	overflow: hidden;
+}
+
+/* ==================
+         表单
+ ==================== */
+
+.cu-form-group {
+	background-color: var(--white);
+	padding: 1rpx 30rpx;
+	display: flex;
+	align-items: center;
+	min-height: 100rpx;
+	justify-content: space-between;
+}
+
+.cu-form-group+.cu-form-group {
+	border-top: 1rpx solid #eee;
+}
+
+.cu-form-group .title {
+	text-align: justify;
+	padding-right: 30rpx;
+	font-size: 30rpx;
+	position: relative;
+	height: 60rpx;
+	line-height: 60rpx;
+}
+
+.cu-form-group input {
+	flex: 1;
+	font-size: 30rpx;
+	color: #555;
+	padding-right: 20rpx;
+}
+
+.cu-form-group>text[class*="cuIcon-"] {
+	font-size: 36rpx;
+	padding: 0;
+	box-sizing: border-box;
+}
+
+.cu-form-group textarea {
+	margin: 32rpx 0 30rpx;
+	height: 4.6em;
+	width: 100%;
+	line-height: 1.2em;
+	flex: 1;
+	font-size: 28rpx;
+	padding: 0;
+}
+
+.cu-form-group.align-start .title {
+	height: 1em;
+	margin-top: 32rpx;
+	line-height: 1em;
+}
+
+.cu-form-group picker {
+	flex: 1;
+	padding-right: 40rpx;
+	overflow: hidden;
+	position: relative;
+}
+
+.cu-form-group picker .picker {
+	line-height: 100rpx;
+	font-size: 28rpx;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+	width: 100%;
+	text-align: right;
+}
+
+.cu-form-group picker::after {
+	font-family: "cuIcon";
+	display: block;
+	content: "\e6a3";
+	position: absolute;
+	font-size: 34rpx;
+	color: var(--grey);
+	line-height: 100rpx;
+	width: 60rpx;
+	text-align: center;
+	top: 0;
+	bottom: 0;
+	right: -20rpx;
+	margin: auto;
+}
+
+.cu-form-group textarea[disabled],
+.cu-form-group textarea[disabled] .placeholder {
+	color: transparent;
+}
+
+/* ==================
+         模态窗口
+ ==================== */
+
+.cu-modal {
+	position: fixed;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	left: 0;
+	z-index: 1110;
+	opacity: 0;
+	outline: 0;
+	text-align: center;
+	-ms-transform: scale(1.185);
+	transform: scale(1.185);
+	backface-visibility: hidden;
+	perspective: 2000rpx;
+	background: rgba(0, 0, 0, 0.6);
+	transition: all 0.3s ease-in-out 0s;
+	pointer-events: none;
+}
+
+.cu-modal::before {
+	content: "\200B";
+	display: inline-block;
+	height: 100%;
+	vertical-align: middle;
+}
+
+.cu-modal.show {
+	opacity: 1;
+	transition-duration: 0.3s;
+	-ms-transform: scale(1);
+	transform: scale(1);
+	overflow-x: hidden;
+	overflow-y: auto;
+	pointer-events: auto;
+}
+
+.cu-dialog {
+	position: relative;
+	display: inline-block;
+	vertical-align: middle;
+	margin-left: auto;
+	margin-right: auto;
+	width: 680rpx;
+	max-width: 100%;
+	background-color: #f8f8f8;
+	border-radius: 10rpx;
+	overflow: hidden;
+}
+
+.cu-modal.bottom-modal::before {
+	vertical-align: bottom;
+}
+
+.cu-modal.bottom-modal .cu-dialog {
+	width: 100%;
+	border-radius: 0;
+}
+
+.cu-modal.bottom-modal {
+	margin-bottom: -1000rpx;
+}
+
+.cu-modal.bottom-modal.show {
+	margin-bottom: 0;
+}
+
+.cu-modal.drawer-modal {
+	transform: scale(1);
+	display: flex;
+}
+
+.cu-modal.drawer-modal .cu-dialog {
+	height: 100%;
+	min-width: 200rpx;
+	border-radius: 0;
+	margin: initial;
+	transition-duration: 0.3s;
+}
+
+.cu-modal.drawer-modal.justify-start .cu-dialog {
+	transform: translateX(-100%);
+}
+
+.cu-modal.drawer-modal.justify-end .cu-dialog {
+	transform: translateX(100%);
+}
+
+.cu-modal.drawer-modal.show .cu-dialog {
+	transform: translateX(0%);
+}
+.cu-modal .cu-dialog>.cu-bar:first-child .action{
+  min-width: 100rpx;
+  margin-right: 0;
+  min-height: 100rpx;
+}
+/* ==================
+         轮播
+ ==================== */
+swiper .a-swiper-dot {
+	display: inline-block;
+	width: 16rpx;
+	height: 16rpx;
+	background: rgba(0, 0, 0, .3);
+	border-radius: 50%;
+	vertical-align: middle;
+}
+
+swiper[class*="-dot"] .wx-swiper-dots {
+	display: flex;
+	align-items: center;
+	width: 100%;
+	justify-content: center;
+}
+
+swiper.square-dot .wx-swiper-dot {
+	background-color: var(--white);
+	opacity: 0.4;
+	width: 10rpx;
+	height: 10rpx;
+	border-radius: 20rpx;
+	margin: 0 8rpx !important;
+}
+
+swiper.square-dot .wx-swiper-dot.wx-swiper-dot-active {
+	opacity: 1;
+	width: 30rpx;
+}
+
+swiper.round-dot .wx-swiper-dot {
+	width: 10rpx;
+	height: 10rpx;
+	position: relative;
+	margin: 4rpx 8rpx !important;
+}
+
+swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active::after {
+	content: "";
+	position: absolute;
+	width: 10rpx;
+	height: 10rpx;
+	top: 0rpx;
+	left: 0rpx;
+	right: 0;
+	bottom: 0;
+	margin: auto;
+	background-color: var(--white);
+	border-radius: 20rpx;
+}
+
+swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active {
+	width: 18rpx;
+	height: 18rpx;
+}
+
+.screen-swiper {
+	min-height: 375rpx;
+}
+
+.screen-swiper image,
+.screen-swiper video,
+.swiper-item image,
+.swiper-item video {
+	width: 100%;
+	display: block;
+	height: 100%;
+	margin: 0;
+	pointer-events: none;
+}
+
+.card-swiper {
+	height: 420rpx !important;
+}
+
+.card-swiper swiper-item {
+	width: 610rpx !important;
+	left: 70rpx;
+	box-sizing: border-box;
+	padding: 40rpx 0rpx 70rpx;
+	overflow: initial;
+}
+
+.card-swiper swiper-item .swiper-item {
+	width: 100%;
+	display: block;
+	height: 100%;
+	border-radius: 10rpx;
+	transform: scale(0.9);
+	transition: all 0.2s ease-in 0s;
+	overflow: hidden;
+}
+
+.card-swiper swiper-item.cur .swiper-item {
+	transform: none;
+	transition: all 0.2s ease-in 0s;
+}
+
+
+.tower-swiper {
+	height: 420rpx;
+	position: relative;
+	max-width: 750rpx;
+	overflow: hidden;
+}
+
+.tower-swiper .tower-item {
+	position: absolute;
+	width: 300rpx;
+	height: 380rpx;
+	top: 0;
+	bottom: 0;
+	left: 50%;
+	margin: auto;
+	transition: all 0.2s ease-in 0s;
+	opacity: 1;
+}
+
+.tower-swiper .tower-item.none {
+	opacity: 0;
+}
+
+.tower-swiper .tower-item .swiper-item {
+	width: 100%;
+	height: 100%;
+	border-radius: 6rpx;
+	overflow: hidden;
+}
+
+/* ==================
+          步骤条
+ ==================== */
+
+.cu-steps {
+	display: flex;
+}
+
+scroll-view.cu-steps {
+	display: block;
+	white-space: nowrap;
+}
+
+scroll-view.cu-steps .cu-item {
+	display: inline-block;
+}
+
+.cu-steps .cu-item {
+	flex: 1;
+	text-align: center;
+	position: relative;
+	min-width: 100rpx;
+}
+
+.cu-steps .cu-item:not([class*="text-"]) {
+	color: var(--grey);
+}
+
+.cu-steps .cu-item [class*="cuIcon-"],
+.cu-steps .cu-item .num {
+	display: block;
+	font-size: 40rpx;
+	line-height: 80rpx;
+}
+
+.cu-steps .cu-item::before,
+.cu-steps .cu-item::after,
+.cu-steps.steps-arrow .cu-item::before,
+.cu-steps.steps-arrow .cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	height: 0px;
+	width: calc(100% - 80rpx);
+	border-bottom: 1px solid #ccc;
+	left: calc(0px - (100% - 80rpx) / 2);
+	top: 40rpx;
+	z-index: 0;
+}
+
+.cu-steps.steps-arrow .cu-item::before,
+.cu-steps.steps-arrow .cu-item::after {
+	content: "\e6a3";
+	font-family: "cuIcon";
+	height: 30rpx;
+	border-bottom-width: 0px;
+	line-height: 30rpx;
+	top: 0;
+	bottom: 0;
+	margin: auto;
+	color: #ccc;
+}
+
+.cu-steps.steps-bottom .cu-item::before,
+.cu-steps.steps-bottom .cu-item::after {
+	bottom: 40rpx;
+	top: initial;
+}
+
+.cu-steps .cu-item::after {
+	border-bottom: 1px solid currentColor;
+	width: 0px;
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.cu-steps .cu-item[class*="text-"]::after {
+	width: calc(100% - 80rpx);
+	color: currentColor;
+}
+
+.cu-steps .cu-item:first-child::before,
+.cu-steps .cu-item:first-child::after {
+	display: none;
+}
+
+.cu-steps .cu-item .num {
+	width: 40rpx;
+	height: 40rpx;
+	border-radius: 50%;
+	line-height: 40rpx;
+	margin: 20rpx auto;
+	font-size: 24rpx;
+	border: 1px solid currentColor;
+	position: relative;
+	overflow: hidden;
+}
+
+.cu-steps .cu-item[class*="text-"] .num {
+	background-color: currentColor;
+}
+
+.cu-steps .cu-item .num::before,
+.cu-steps .cu-item .num::after {
+	content: attr(data-index);
+	position: absolute;
+	left: 0;
+	right: 0;
+	top: 0;
+	bottom: 0;
+	margin: auto;
+	transition: all 0.3s ease-in-out 0s;
+	transform: translateY(0rpx);
+}
+
+.cu-steps .cu-item[class*="text-"] .num::before {
+	transform: translateY(-40rpx);
+	color: var(--white);
+}
+
+.cu-steps .cu-item .num::after {
+	transform: translateY(40rpx);
+	color: var(--white);
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.cu-steps .cu-item[class*="text-"] .num::after {
+	content: "\e645";
+	font-family: "cuIcon";
+	color: var(--white);
+	transform: translateY(0rpx);
+}
+
+.cu-steps .cu-item[class*="text-"] .num.err::after {
+	content: "\e646";
+}
+
+/* ==================
+          布局
+ ==================== */
+
+/*  -- flex弹性布局 -- */
+
+.flex {
+	display: flex;
+}
+
+.basis-xs {
+	flex-basis: 20%;
+}
+
+.basis-sm {
+	flex-basis: 40%;
+}
+
+.basis-df {
+	flex-basis: 50%;
+}
+
+.basis-lg {
+	flex-basis: 60%;
+}
+
+.basis-xl {
+	flex-basis: 80%;
+}
+
+.flex-sub {
+	flex: 1;
+}
+
+.flex-twice {
+	flex: 2;
+}
+
+.flex-treble {
+	flex: 3;
+}
+
+.flex-direction {
+	flex-direction: column;
+}
+
+.flex-wrap {
+	flex-wrap: wrap;
+}
+
+.align-start {
+	align-items: flex-start;
+}
+
+.align-end {
+	align-items: flex-end;
+}
+
+.align-center {
+	align-items: center;
+}
+
+.align-stretch {
+	align-items: stretch;
+}
+
+.self-start {
+	align-self: flex-start;
+}
+
+.self-center {
+	align-self: flex-center;
+}
+
+.self-end {
+	align-self: flex-end;
+}
+
+.self-stretch {
+	align-self: stretch;
+}
+
+.align-stretch {
+	align-items: stretch;
+}
+
+.justify-start {
+	justify-content: flex-start;
+}
+
+.justify-end {
+	justify-content: flex-end;
+}
+
+.justify-center {
+	justify-content: center;
+}
+
+.justify-between {
+	justify-content: space-between;
+}
+
+.justify-around {
+	justify-content: space-around;
+}
+
+/* grid布局 */
+
+.grid {
+	display: flex;
+	flex-wrap: wrap;
+}
+
+.grid.grid-square {
+	overflow: hidden;
+}
+
+.grid.grid-square .cu-tag {
+	position: absolute;
+	right: 0;
+	top: 0;
+	border-bottom-left-radius: 6rpx;
+	padding: 6rpx 12rpx;
+	height: auto;
+	background-color: rgba(0, 0, 0, 0.5);
+}
+
+.grid.grid-square>view>text[class*="cuIcon-"] {
+	font-size: 52rpx;
+	position: absolute;
+	color: var(--grey);
+	margin: auto;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	flex-direction: column;
+}
+
+.grid.grid-square>view {
+	margin-right: 20rpx;
+	margin-bottom: 20rpx;
+	border-radius: 6rpx;
+	position: relative;
+	overflow: hidden;
+}
+
+.grid.grid-square>view.bg-img image {
+	width: 100%;
+	height: 100%;
+	position: absolute;
+}
+
+.grid.col-1.grid-square>view {
+	padding-bottom: 100%;
+	height: 0;
+	margin-right: 0;
+}
+
+.grid.col-2.grid-square>view {
+	padding-bottom: calc((100% - 20rpx)/2);
+	height: 0;
+	width: calc((100% - 20rpx)/2);
+}
+
+.grid.col-3.grid-square>view {
+	padding-bottom: calc((100% - 40rpx)/3);
+	height: 0;
+	width: calc((100% - 40rpx)/3);
+}
+
+.grid.col-4.grid-square>view {
+	padding-bottom: calc((100% - 60rpx)/4);
+	height: 0;
+	width: calc((100% - 60rpx)/4);
+}
+
+.grid.col-5.grid-square>view {
+	padding-bottom: calc((100% - 80rpx)/5);
+	height: 0;
+	width: calc((100% - 80rpx)/5);
+}
+
+.grid.col-2.grid-square>view:nth-child(2n),
+.grid.col-3.grid-square>view:nth-child(3n),
+.grid.col-4.grid-square>view:nth-child(4n),
+.grid.col-5.grid-square>view:nth-child(5n){
+	margin-right: 0;
+}
+
+.grid.col-1>view {
+	width: 100%;
+}
+
+.grid.col-2>view {
+	width: 50%;
+}
+
+.grid.col-3>view {
+	width: 33.33%;
+}
+
+.grid.col-4>view {
+	width: 25%;
+}
+
+.grid.col-5>view {
+	width: 20%;
+}
+
+/*  -- 内外边距 -- */
+
+.margin-0 {
+	margin: 0;
+}
+
+.margin-xs {
+	margin: 10rpx;
+}
+
+.margin-sm {
+	margin: 20rpx;
+}
+
+.margin {
+	margin: 30rpx;
+}
+
+.margin-lg {
+	margin: 40rpx;
+}
+
+.margin-xl {
+	margin: 50rpx;
+}
+
+.margin-top-xs {
+	margin-top: 10rpx;
+}
+
+.margin-top-sm {
+	margin-top: 20rpx;
+}
+
+.margin-top {
+	margin-top: 30rpx;
+}
+
+.margin-top-lg {
+	margin-top: 40rpx;
+}
+
+.margin-top-xl {
+	margin-top: 50rpx;
+}
+
+.margin-right-xs {
+	margin-right: 10rpx;
+}
+
+.margin-right-sm {
+	margin-right: 20rpx;
+}
+
+.margin-right {
+	margin-right: 30rpx;
+}
+
+.margin-right-lg {
+	margin-right: 40rpx;
+}
+
+.margin-right-xl {
+	margin-right: 50rpx;
+}
+
+.margin-bottom-xs {
+	margin-bottom: 10rpx;
+}
+
+.margin-bottom-sm {
+	margin-bottom: 20rpx;
+}
+
+.margin-bottom {
+	margin-bottom: 30rpx;
+}
+
+.margin-bottom-lg {
+	margin-bottom: 40rpx;
+}
+
+.margin-bottom-xl {
+	margin-bottom: 50rpx;
+}
+
+.margin-left-xs {
+	margin-left: 10rpx;
+}
+
+.margin-left-sm {
+	margin-left: 20rpx;
+}
+
+.margin-left {
+	margin-left: 30rpx;
+}
+
+.margin-left-lg {
+	margin-left: 40rpx;
+}
+
+.margin-left-xl {
+	margin-left: 50rpx;
+}
+
+.margin-lr-xs {
+	margin-left: 10rpx;
+	margin-right: 10rpx;
+}
+
+.margin-lr-sm {
+	margin-left: 20rpx;
+	margin-right: 20rpx;
+}
+
+.margin-lr {
+	margin-left: 30rpx;
+	margin-right: 30rpx;
+}
+
+.margin-lr-lg {
+	margin-left: 40rpx;
+	margin-right: 40rpx;
+}
+
+.margin-lr-xl {
+	margin-left: 50rpx;
+	margin-right: 50rpx;
+}
+
+.margin-tb-xs {
+	margin-top: 10rpx;
+	margin-bottom: 10rpx;
+}
+
+.margin-tb-sm {
+	margin-top: 20rpx;
+	margin-bottom: 20rpx;
+}
+
+.margin-tb {
+	margin-top: 30rpx;
+	margin-bottom: 30rpx;
+}
+
+.margin-tb-lg {
+	margin-top: 40rpx;
+	margin-bottom: 40rpx;
+}
+
+.margin-tb-xl {
+	margin-top: 50rpx;
+	margin-bottom: 50rpx;
+}
+
+.padding-0 {
+	padding: 0;
+}
+
+.padding-xs {
+	padding: 10rpx;
+}
+
+.padding-sm {
+	padding: 20rpx;
+}
+
+.padding {
+	padding: 30rpx;
+}
+
+.padding-lg {
+	padding: 40rpx;
+}
+
+.padding-xl {
+	padding: 50rpx;
+}
+
+.padding-top-xs {
+	padding-top: 10rpx;
+}
+
+.padding-top-sm {
+	padding-top: 20rpx;
+}
+
+.padding-top {
+	padding-top: 30rpx;
+}
+
+.padding-top-lg {
+	padding-top: 40rpx;
+}
+
+.padding-top-xl {
+	padding-top: 50rpx;
+}
+
+.padding-right-xs {
+	padding-right: 10rpx;
+}
+
+.padding-right-sm {
+	padding-right: 20rpx;
+}
+
+.padding-right {
+	padding-right: 30rpx;
+}
+
+.padding-right-lg {
+	padding-right: 40rpx;
+}
+
+.padding-right-xl {
+	padding-right: 50rpx;
+}
+
+.padding-bottom-xs {
+	padding-bottom: 10rpx;
+}
+
+.padding-bottom-sm {
+	padding-bottom: 20rpx;
+}
+
+.padding-bottom {
+	padding-bottom: 30rpx;
+}
+
+.padding-bottom-lg {
+	padding-bottom: 40rpx;
+}
+
+.padding-bottom-xl {
+	padding-bottom: 50rpx;
+}
+
+.padding-left-xs {
+	padding-left: 10rpx;
+}
+
+.padding-left-sm {
+	padding-left: 20rpx;
+}
+
+.padding-left {
+	padding-left: 30rpx;
+}
+
+.padding-left-lg {
+	padding-left: 40rpx;
+}
+
+.padding-left-xl {
+	padding-left: 50rpx;
+}
+
+.padding-lr-xs {
+	padding-left: 10rpx;
+	padding-right: 10rpx;
+}
+
+.padding-lr-sm {
+	padding-left: 20rpx;
+	padding-right: 20rpx;
+}
+
+.padding-lr {
+	padding-left: 30rpx;
+	padding-right: 30rpx;
+}
+
+.padding-lr-lg {
+	padding-left: 40rpx;
+	padding-right: 40rpx;
+}
+
+.padding-lr-xl {
+	padding-left: 50rpx;
+	padding-right: 50rpx;
+}
+
+.padding-tb-xs {
+	padding-top: 10rpx;
+	padding-bottom: 10rpx;
+}
+
+.padding-tb-sm {
+	padding-top: 20rpx;
+	padding-bottom: 20rpx;
+}
+
+.padding-tb {
+	padding-top: 30rpx;
+	padding-bottom: 30rpx;
+}
+
+.padding-tb-lg {
+	padding-top: 40rpx;
+	padding-bottom: 40rpx;
+}
+
+.padding-tb-xl {
+	padding-top: 50rpx;
+	padding-bottom: 50rpx;
+}
+
+/* -- 浮动 --  */
+
+.cf::after,
+.cf::before {
+	content: " ";
+	display: table;
+}
+
+.cf::after {
+	clear: both;
+}
+
+.fl {
+	float: left;
+}
+
+.fr {
+	float: right;
+}
+
+/* ==================
+          背景
+ ==================== */
+
+.line-red::after,
+.lines-red::after {
+	border-color: var(--red);
+}
+
+.line-orange::after,
+.lines-orange::after {
+	border-color: var(--orange);
+}
+
+.line-yellow::after,
+.lines-yellow::after {
+	border-color: var(--yellow);
+}
+
+.line-olive::after,
+.lines-olive::after {
+	border-color: var(--olive);
+}
+
+.line-green::after,
+.lines-green::after {
+	border-color: var(--green);
+}
+
+.line-cyan::after,
+.lines-cyan::after {
+	border-color: var(--cyan);
+}
+
+.line-blue::after,
+.lines-blue::after {
+	border-color: var(--blue);
+}
+
+.line-purple::after,
+.lines-purple::after {
+	border-color: var(--purple);
+}
+
+.line-mauve::after,
+.lines-mauve::after {
+	border-color: var(--mauve);
+}
+
+.line-pink::after,
+.lines-pink::after {
+	border-color: var(--pink);
+}
+
+.line-brown::after,
+.lines-brown::after {
+	border-color: var(--brown);
+}
+
+.line-grey::after,
+.lines-grey::after {
+	border-color: var(--grey);
+}
+
+.line-gray::after,
+.lines-gray::after {
+	border-color: var(--gray);
+}
+
+.line-black::after,
+.lines-black::after {
+	border-color: var(--black);
+}
+
+.line-white::after,
+.lines-white::after {
+	border-color: var(--white);
+}
+
+.bg-red {
+	background-color: var(--red);
+	color: var(--white);
+}
+
+.bg-orange {
+	background-color: var(--orange);
+	color: var(--white);
+}
+
+.bg-yellow {
+	background-color: var(--yellow);
+	color: var(--black);
+}
+
+.bg-olive {
+	background-color: var(--olive);
+	color: var(--white);
+}
+
+.bg-green {
+	background-color: var(--green);
+	color: var(--white);
+}
+
+.bg-cyan {
+	background-color: var(--cyan);
+	color: var(--white);
+}
+
+.bg-blue {
+	background-color: var(--blue);
+	color: var(--white);
+}
+
+.bg-purple {
+	background-color: var(--purple);
+	color: var(--white);
+}
+
+.bg-mauve {
+	background-color: var(--mauve);
+	color: var(--white);
+}
+
+.bg-pink {
+	background-color: var(--pink);
+	color: var(--white);
+}
+
+.bg-brown {
+	background-color: var(--brown);
+	color: var(--white);
+}
+
+.bg-grey {
+	background-color: var(--grey);
+	color: var(--white);
+}
+
+.bg-gray {
+	background-color: #f0f0f0;
+	color: var(--black);
+}
+
+.bg-black {
+	background-color: var(--black);
+	color: var(--white);
+}
+
+.bg-white {
+	background-color: var(--white);
+	color: var(--darkGray);
+}
+
+.bg-shadeTop {
+	background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.01));
+	color: var(--white);
+}
+
+.bg-shadeBottom {
+	background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 1));
+	color: var(--white);
+}
+
+.bg-red.light {
+	color: var(--red);
+	background-color: var(--redLight);
+}
+
+.bg-orange.light {
+	color: var(--orange);
+	background-color: var(--orangeLight);
+}
+
+.bg-yellow.light {
+	color: var(--yellow);
+	background-color: var(--yellowLight);
+}
+
+.bg-olive.light {
+	color: var(--olive);
+	background-color: var(--oliveLight);
+}
+
+.bg-green.light {
+	color: var(--green);
+	background-color: var(--greenLight);
+}
+
+.bg-cyan.light {
+	color: var(--cyan);
+	background-color: var(--cyanLight);
+}
+
+.bg-blue.light {
+	color: var(--blue);
+	background-color: var(--blueLight);
+}
+
+.bg-purple.light {
+	color: var(--purple);
+	background-color: var(--purpleLight);
+}
+
+.bg-mauve.light {
+	color: var(--mauve);
+	background-color: var(--mauveLight);
+}
+
+.bg-pink.light {
+	color: var(--pink);
+	background-color: var(--pinkLight);
+}
+
+.bg-brown.light {
+	color: var(--brown);
+	background-color: var(--brownLight);
+}
+
+.bg-grey.light {
+	color: var(--grey);
+	background-color: var(--greyLight);
+}
+
+.bg-gradual-red {
+	background-image: var(--gradualRed);
+	color: var(--white);
+}
+
+.bg-gradual-orange {
+	background-image: var(--gradualOrange);
+	color: var(--white);
+}
+
+.bg-gradual-green {
+	background-image: var(--gradualGreen);
+	color: var(--white);
+}
+
+.bg-gradual-purple {
+	background-image: var(--gradualPurple);
+	color: var(--white);
+}
+
+.bg-gradual-pink {
+	background-image: var(--gradualPink);
+	color: var(--white);
+}
+
+.bg-gradual-blue {
+	background-image: var(--gradualBlue);
+	color: var(--white);
+}
+
+.shadow[class*="-red"] {
+	box-shadow: var(--ShadowSize) var(--redShadow);
+}
+
+.shadow[class*="-orange"] {
+	box-shadow: var(--ShadowSize) var(--orangeShadow);
+}
+
+.shadow[class*="-yellow"] {
+	box-shadow: var(--ShadowSize) var(--yellowShadow);
+}
+
+.shadow[class*="-olive"] {
+	box-shadow: var(--ShadowSize) var(--oliveShadow);
+}
+
+.shadow[class*="-green"] {
+	box-shadow: var(--ShadowSize) var(--greenShadow);
+}
+
+.shadow[class*="-cyan"] {
+	box-shadow: var(--ShadowSize) var(--cyanShadow);
+}
+
+.shadow[class*="-blue"] {
+	box-shadow: var(--ShadowSize) var(--blueShadow);
+}
+
+.shadow[class*="-purple"] {
+	box-shadow: var(--ShadowSize) var(--purpleShadow);
+}
+
+.shadow[class*="-mauve"] {
+	box-shadow: var(--ShadowSize) var(--mauveShadow);
+}
+
+.shadow[class*="-pink"] {
+	box-shadow: var(--ShadowSize) var(--pinkShadow);
+}
+
+.shadow[class*="-brown"] {
+	box-shadow: var(--ShadowSize) var(--brownShadow);
+}
+
+.shadow[class*="-grey"] {
+	box-shadow: var(--ShadowSize) var(--greyShadow);
+}
+
+.shadow[class*="-gray"] {
+	box-shadow: var(--ShadowSize) var(--grayShadow);
+}
+
+.shadow[class*="-black"] {
+	box-shadow: var(--ShadowSize) var(--blackShadow);
+}
+
+.shadow[class*="-white"] {
+	box-shadow: var(--ShadowSize) var(--blackShadow);
+}
+
+.text-shadow[class*="-red"] {
+	text-shadow: var(--ShadowSize) var(--redShadow);
+}
+
+.text-shadow[class*="-orange"] {
+	text-shadow: var(--ShadowSize) var(--orangeShadow);
+}
+
+.text-shadow[class*="-yellow"] {
+	text-shadow: var(--ShadowSize) var(--yellowShadow);
+}
+
+.text-shadow[class*="-olive"] {
+	text-shadow: var(--ShadowSize) var(--oliveShadow);
+}
+
+.text-shadow[class*="-green"] {
+	text-shadow: var(--ShadowSize) var(--greenShadow);
+}
+
+.text-shadow[class*="-cyan"] {
+	text-shadow: var(--ShadowSize) var(--cyanShadow);
+}
+
+.text-shadow[class*="-blue"] {
+	text-shadow: var(--ShadowSize) var(--blueShadow);
+}
+
+.text-shadow[class*="-purple"] {
+	text-shadow: var(--ShadowSize) var(--purpleShadow);
+}
+
+.text-shadow[class*="-mauve"] {
+	text-shadow: var(--ShadowSize) var(--mauveShadow);
+}
+
+.text-shadow[class*="-pink"] {
+	text-shadow: var(--ShadowSize) var(--pinkShadow);
+}
+
+.text-shadow[class*="-brown"] {
+	text-shadow: var(--ShadowSize) var(--brownShadow);
+}
+
+.text-shadow[class*="-grey"] {
+	text-shadow: var(--ShadowSize) var(--greyShadow);
+}
+
+.text-shadow[class*="-gray"] {
+	text-shadow: var(--ShadowSize) var(--grayShadow);
+}
+
+.text-shadow[class*="-black"] {
+	text-shadow: var(--ShadowSize) var(--blackShadow);
+}
+
+.bg-img {
+	background-size: cover;
+	background-position: center;
+	background-repeat: no-repeat;
+}
+
+.bg-mask {
+	background-color: var(--black);
+	position: relative;
+}
+
+.bg-mask::after {
+	content: "";
+	border-radius: inherit;
+	width: 100%;
+	height: 100%;
+	display: block;
+	background-color: rgba(0, 0, 0, 0.4);
+	position: absolute;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	top: 0;
+}
+
+.bg-mask view,
+.bg-mask cover-view {
+	z-index: 5;
+	position: relative;
+}
+
+.bg-video {
+	position: relative;
+}
+
+.bg-video video {
+	display: block;
+	height: 100%;
+	width: 100%;
+	-o-object-fit: cover;
+	object-fit: cover;
+	position: absolute;
+	top: 0;
+	z-index: 0;
+	pointer-events: none;
+}
+
+/* ==================
+          文本
+ ==================== */
+
+.text-xs {
+	font-size: 20rpx;
+}
+
+.text-sm {
+	font-size: 24rpx;
+}
+
+.text-df {
+	font-size: 28rpx;
+}
+
+.text-lg {
+	font-size: 32rpx;
+}
+
+.text-xl {
+	font-size: 36rpx;
+}
+
+.text-xxl {
+	font-size: 44rpx;
+}
+
+.text-sl {
+	font-size: 80rpx;
+}
+
+.text-xsl {
+	font-size: 120rpx;
+}
+
+.text-Abc {
+	text-transform: Capitalize;
+}
+
+.text-ABC {
+	text-transform: Uppercase;
+}
+
+.text-abc {
+	text-transform: Lowercase;
+}
+
+.text-price::before {
+	content: "¥";
+	font-size: 80%;
+	margin-right: 4rpx;
+}
+
+.text-cut {
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+}
+
+.text-bold {
+	font-weight: bold;
+}
+
+.text-center {
+	text-align: center;
+}
+
+.text-content {
+	line-height: 1.6;
+}
+
+.text-left {
+	text-align: left;
+}
+
+.text-right {
+	text-align: right;
+}
+
+.text-red,
+.line-red,
+.lines-red {
+	color: var(--red);
+}
+
+.text-orange,
+.line-orange,
+.lines-orange {
+	color: var(--orange);
+}
+
+.text-yellow,
+.line-yellow,
+.lines-yellow {
+	color: var(--yellow);
+}
+
+.text-olive,
+.line-olive,
+.lines-olive {
+	color: var(--olive);
+}
+
+.text-green,
+.line-green,
+.lines-green {
+	color: var(--green);
+}
+
+.text-cyan,
+.line-cyan,
+.lines-cyan {
+	color: var(--cyan);
+}
+
+.text-blue,
+.line-blue,
+.lines-blue {
+	color: var(--blue);
+}
+
+.text-purple,
+.line-purple,
+.lines-purple {
+	color: var(--purple);
+}
+
+.text-mauve,
+.line-mauve,
+.lines-mauve {
+	color: var(--mauve);
+}
+
+.text-pink,
+.line-pink,
+.lines-pink {
+	color: var(--pink);
+}
+
+.text-brown,
+.line-brown,
+.lines-brown {
+	color: var(--brown);
+}
+
+.text-grey,
+.line-grey,
+.lines-grey {
+	color: var(--grey);
+}
+
+.text-gray,
+.line-gray,
+.lines-gray {
+	color: var(--gray);
+}
+
+.text-black,
+.line-black,
+.lines-black {
+	color: var(--black);
+}
+
+.text-white,
+.line-white,
+.lines-white {
+	color: var(--white);
+}

+ 109 - 0
components/button/button.js

@@ -0,0 +1,109 @@
+//注意:自定义组件无法触发form的bindsubmit,bindreset事件. 
+// 在基础库2.10.3 以上 添加 behaviors: ['wx://form-field-button'] 属性 form 可以触发bindsubmit事件。
+//可以在组件外层嵌套个button按钮,背景设为none,form-type写在外层按钮上(参考登录页面)
+Component({
+  behaviors: ['wx://form-field-button'], // 用于触发bindsubmit事件
+  externalClasses: ['tui-button-class'], //自定义样式
+  properties: {
+    // primary, white, danger, warning, green, gray,gradual
+    type: {
+      type: String,
+      value: 'gradual',
+    },
+    // block, mini, small
+    size: {
+      type: String,
+      value: 'block',
+    },
+    // circle, square
+    shape: {
+      type: String,
+      value: 'square'
+    },
+    plain: {
+      type: Boolean,
+      value: false
+    },
+    disabled: {
+      type: Boolean,
+      value: false,
+    },
+    loading: {
+      type: Boolean,
+      value: false,
+    },
+    openType: {
+      type: String,
+      value: ''
+    },
+    formType: {
+      type: String,
+      value: ''
+    },
+    hoverStopPropagation: {
+      type: Boolean,
+      value: false
+    },
+    lang: {
+      type: String,
+      value: 'en'
+    },
+    appParameter: {
+      type: String,
+      value: ''
+    },
+    sessionFrom: {
+      type: String,
+      value: ''
+    },
+    showMessageCard: {
+      type: Boolean,
+      value: false
+    },
+    sendMessageImg: {
+      type: String,
+      value: ''
+    },
+    sendMessagePath: {
+      type: String,
+      value: ''
+    },
+    sendMessageTitle: {
+      type: String,
+      value: ''
+    },
+    hidden: {
+      type: Boolean,
+      value: false
+    }
+  },
+  data: {
+
+  },
+  methods: {
+    handleClick() {
+      if (this.data.disabled) return false;
+      this.triggerEvent('click', {});
+    },
+    bindgetuserinfo({
+      detail = {}
+    } = {}) {
+      this.triggerEvent('getuserinfo', detail);
+    },
+    bindcontact({
+      detail = {}
+    } = {}) {
+      this.triggerEvent('contact', detail);
+    },
+    bindgetphonenumber({
+      detail = {}
+    } = {}) {
+      this.triggerEvent('getphonenumber', detail);
+    },
+    binderror({
+      detail = {}
+    } = {}) {
+      this.triggerEvent('error', detail);
+    }
+  }
+})

+ 3 - 0
components/button/button.json

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

+ 31 - 0
components/button/button.wxml

@@ -0,0 +1,31 @@
+
+<button class="tui-button-class tui-btn {{'tui-btn-'+size}} {{plain?'tui-'+type+'-outline':'tui-'+(type || 'gradual')}} {{parse.getDisabledClass(disabled,type)}} {{parse.getShapeClass(shape,plain)}}" hover-class="{{parse.getHoverClass(disabled,type,plain)}}" loading="{{loading}}"
+  disabled="{{disabled}}" open-type="{{ openType }}" app-parameter="{{ appParameter }}" hover-stop-propagation="{{ hoverStopPropagation }}" bindtap="handleClick" session-from="{{ sessionFrom }}" send-message-title="{{ sendMessageTitle }}" send-message-path="{{ sendMessagePath }}"
+  send-message-img="{{ sendMessageImg }}" show-message-card="{{ showMessageCard }}" bindcontact="bindcontact" bindgetuserinfo="bindgetuserinfo" bindgetphonenumber="bindgetphonenumber" binderror="binderror" form-type="{{formType}}" hidden="{{hidden}}">
+  <slot></slot>
+</button>
+<wxs module="parse">
+  module.exports = {
+    getDisabledClass: function(disabled, type) {
+      var className = '';
+      if (disabled && type != 'white' && type != 'gray') {
+        className = type == 'gradual' ? 'btn-gradual-disabled' : 'tui-dark-disabled';
+      }
+      return className;
+    },
+    getShapeClass: function(shape, plain) {
+      var className = '';
+      if (shape == 'circle') {
+        className = plain ? 'tui-outline-fillet' : 'tui-fillet';
+      }
+      return className;
+    },
+    getHoverClass: function(disabled, type, plain) {
+      var className = '';
+      if (!disabled) {
+        className = plain ? 'tui-outline-hover' : ('tui-' + (type || 'gradual') + '-hover');
+      }
+      return className;
+    }
+  }
+</wxs>

+ 227 - 0
components/button/button.wxss

@@ -0,0 +1,227 @@
+/* color start*/
+
+.tui-primary {
+  background: #5677fc !important;
+  color: #fff;
+}
+
+.tui-danger {
+  background: #EB0909 !important; 
+  color: #fff;
+}
+
+.tui-red {
+  background: #e41f19 !important;
+  color: #fff;
+}
+
+.tui-warning {
+  background: #ff7900 !important;
+  color: #fff;
+}
+
+.tui-green {
+  background: #19be6b !important;
+  color: #fff;
+}
+
+.tui-white {
+  background: #fff !important;
+  color: #333 !important;
+}
+
+.tui-gray {
+  background: #ededed !important;
+  color: #999 !important;
+}
+
+.tui-hover-gray {
+  background: #f7f7f9 !important;
+}
+
+/* color end*/
+
+/* button start*/
+
+.tui-btn {
+  width: 100%;
+  position: relative;
+  border: 0 !important;
+  border-radius: 10rpx;
+  display: inline-block;
+}
+
+.tui-btn::after {
+  content: "";
+  position: absolute;
+  width: 200%;
+  height: 200%;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scale(0.5, 0.5);
+  transform: scale(0.5, 0.5);
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+  left: 0;
+  top: 0;
+  border-radius: 20rpx;
+}
+
+.tui-btn-block {
+  font-size: 36rpx;
+  height: 90rpx;
+  line-height: 90rpx;
+}
+
+.tui-white::after {
+  border: 1px solid #eaeef1;
+}
+
+.tui-white-hover {
+  background: #e5e5e5 !important;
+  color: #2e2e2e !important;
+}
+
+.tui-dark-disabled {
+  opacity: 0.6;
+  color: #fafbfc !important;
+}
+
+.tui-outline-hover {
+  opacity: 0.5;
+}
+
+.tui-primary-hover {
+  background: #4a67d6 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-primary-outline::after {
+  border: 1px solid #5677fc !important;
+}
+
+.tui-primary-outline {
+  color: #5677fc !important;
+  background: none;
+}
+
+.tui-danger-hover {
+  background: #c80808 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-danger-outline {
+  color: #EB0909 !important;
+  background: none;
+}
+
+.tui-danger-outline::after {
+  border: 1px solid #EB0909 !important;
+}
+
+.tui-red-hover {
+  background: #c51a15 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-red-outline {
+  color: #e41f19 !important;
+  background: none;
+}
+
+.tui-red-outline::after {
+  border: 1px solid #e41f19 !important;
+}
+
+.tui-warning-hover {
+  background: #e56d00 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-warning-outline {
+  color: #ff7900 !important;
+  background: none;
+}
+
+.tui-warning-outline::after {
+  border: 1px solid #ff7900 !important;
+}
+
+.tui-green-hover {
+  background: #16ab60 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-green-outline {
+  color: #44cf85 !important;
+  background: none;
+}
+
+.tui-green-outline::after {
+  border: 1px solid #44cf85 !important;
+}
+
+.tui-gray-hover {
+  background: #d5d5d5 !important;
+  color: #898989;
+}
+
+.tui-gray-outline, .tui-white-outline {
+  color: #999 !important;
+  background: none !important;
+}
+
+.tui-gray-outline::after, .tui-white-outline::after {
+  border: 1px solid #ccc !important;
+}
+
+/*圆角 */
+
+.tui-fillet {
+  border-radius: 45rpx;
+}
+
+.tui-white.tui-fillet::after {
+  border-radius: 90rpx;
+}
+
+.tui-outline-fillet::after {
+  border-radius: 90rpx;
+}
+
+/*渐变 */
+
+.tui-gradual {
+  background: linear-gradient(-90deg, #5677fc, #5c8dff);
+  border-radius: 45rpx;
+  color: #fff;
+}
+
+.tui-gradual-hover {
+  color: #d5d4d9 !important;
+  background: linear-gradient(-90deg, #4a67d6, #4e77d9);
+}
+
+.btn-gradual-disabled {
+  color: #fafbfc !important;
+  border-radius: 45rpx;
+  background: linear-gradient(-90deg, #cad8fb, #c9d3fb);
+}
+
+/*不同尺寸 */
+
+.tui-btn-mini {
+  width: auto;
+  font-size: 30rpx;
+  height: 70rpx;
+  line-height: 70rpx;
+}
+
+.tui-btn-small {
+  width: auto;
+  font-size: 30rpx;
+  height: 60rpx;
+  line-height: 60rpx;
+}
+
+/* button end*/

+ 31 - 0
components/drawer/drawer.js

@@ -0,0 +1,31 @@
+//抽屉组件
+Component({
+  externalClasses: ['tui-drawer-class'], //自定义样式
+  properties: {
+    visible: {
+      type: Boolean,
+      value: false
+    },
+    mask: {
+      type: Boolean,
+      value: true
+    },
+    maskClosable: {
+      type: Boolean,
+      value: true
+    },
+    mode: {
+      type: String,
+      value: 'left' // left right
+    }
+  },
+  data: {},
+  methods: {
+    handleMaskClick() {
+      if (!this.data.maskClosable) {
+        return;
+      }
+      this.triggerEvent('close', {});
+    }
+  }
+});

+ 3 - 0
components/drawer/drawer.json

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

+ 7 - 0
components/drawer/drawer.wxml

@@ -0,0 +1,7 @@
+<view class="tui-drawer-class tui-drawer {{ visible ? 'tui-drawer-show' : '' }} {{ 'tui-drawer-' + mode }}">
+    <view wx:if="{{ mask }}" class="tui-drawer-mask" bindtap="handleMaskClick"></view>
+    <view class="tui-drawer-container">
+        <slot></slot>
+    </view>
+</view>
+

+ 64 - 0
components/drawer/drawer.wxss

@@ -0,0 +1,64 @@
+.tui-drawer {
+  visibility: hidden;
+}
+
+.tui-drawer-show {
+  visibility: visible;
+}
+
+.tui-drawer-show .tui-drawer-mask {
+  display: block;
+  opacity: 1;
+}
+
+.tui-drawer-show .tui-drawer-container {
+  opacity: 1;
+}
+
+.tui-drawer-show.tui-drawer-left .tui-drawer-container,
+.tui-drawer-show.tui-drawer-right .tui-drawer-container {
+  transform: translate3d(0, -50%, 0);
+}
+
+.tui-drawer-mask {
+  opacity: 0;
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 8888;
+  background: rgba(0, 0, 0, 0.6);
+  transition: all 0.3s ease-in-out;
+}
+
+.tui-drawer-container {
+  position: fixed;
+  left: 50%;
+  height: 100%;
+  top: 0;
+  transform: translate3d(-50%, -50%, 0);
+  transform-origin: center;
+  transition: all 0.3s ease-in-out;
+  z-index: 99999;
+  opacity: 0;
+  overflow-y: scroll;
+  background: #fff;
+  -webkit-overflow-scrolling: touch;
+  -ms-touch-action: pan-y cross-slide-y;
+  -ms-scroll-chaining: none;
+  -ms-scroll-limit: 0 50 0 50;
+}
+
+.tui-drawer-left .tui-drawer-container {
+  left: 0;
+  top: 50%;
+  transform: translate3d(-100%, -50%, 0);
+}
+
+.tui-drawer-right .tui-drawer-container {
+  right: 0;
+  top: 50%;
+  left: auto;
+  transform: translate3d(100%, -50%, 0);
+}

+ 30 - 0
components/drawer/index.js

@@ -0,0 +1,30 @@
+//抽屉组件
+Component({
+  properties: {
+    visible: {
+      type: Boolean,
+      value: false
+    },
+    mask: {
+      type: Boolean,
+      value: true
+    },
+    maskClosable: {
+      type: Boolean,
+      value: true
+    },
+    mode: {
+      type: String,
+      value: 'left' // left right
+    }
+  },
+  data: {},
+  methods: {
+    handleMaskClick() {
+      if (!this.data.maskClosable) {
+        return;
+      }
+      this.triggerEvent('close', {});
+    }
+  }
+});

+ 4 - 0
components/drawer/index.json

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

+ 7 - 0
components/drawer/index.wxml

@@ -0,0 +1,7 @@
+<view class="i-class i-drawer {{ visible ? 'i-drawer-show' : '' }} {{ 'i-drawer-' + mode }}">
+    <view wx:if="{{ mask }}" class="i-drawer-mask" bindtap="handleMaskClick"></view>
+    <view class="i-drawer-container">
+        <slot></slot>
+    </view>
+</view>
+

+ 64 - 0
components/drawer/index.wxss

@@ -0,0 +1,64 @@
+.i-drawer {
+  visibility: hidden;
+}
+
+.i-drawer-show {
+  visibility: visible;
+}
+
+.i-drawer-show .i-drawer-mask {
+  display: block;
+  opacity: 1;
+}
+
+.i-drawer-show .i-drawer-container {
+  opacity: 1;
+}
+
+.i-drawer-show.i-drawer-left .i-drawer-container,
+.i-drawer-show.i-drawer-right .i-drawer-container {
+  transform: translate3d(0, -50%, 0);
+}
+
+.i-drawer-mask {
+  opacity: 0;
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 6;
+  background: rgba(0, 0, 0, 0.6);
+  transition: all 0.3s ease-in-out;
+}
+
+.i-drawer-container {
+  position: fixed;
+  left: 50%;
+  height: 100%;
+  top: 0;
+  transform: translate3d(-50%, -50%, 0);
+  transform-origin: center;
+  transition: all 0.3s ease-in-out;
+  z-index: 7;
+  opacity: 0;
+  overflow-y: scroll;
+  background: #fff;
+  -webkit-overflow-scrolling: touch;
+  -ms-touch-action: pan-y cross-slide-y;
+  -ms-scroll-chaining: none;
+  -ms-scroll-limit: 0 50 0 50;
+}
+
+.i-drawer-left .i-drawer-container {
+  left: 0;
+  top: 50%;
+  transform: translate3d(-100%, -50%, 0);
+}
+
+.i-drawer-right .i-drawer-container {
+  right: 0;
+  top: 50%;
+  left: auto;
+  transform: translate3d(100%, -50%, 0);
+}

+ 43 - 0
components/extend/alert/alert.js

@@ -0,0 +1,43 @@
+Component({
+  properties: {
+    //控制显示
+    show: {
+      type: Boolean,
+      value: false
+    },
+    //提示信息字体大小
+    size: {
+      type: Number,
+      value: 30
+    },
+    //提示信息字体颜色
+    color: {
+      type: String,
+      value: "#333"
+    },
+    //按钮字体颜色
+    btnColor: {
+      type: String,
+      value: "#EB0909"
+    },
+    btnText: {
+      type: String,
+      value: "确定"
+    },
+    //点击遮罩 是否可关闭
+    maskClosable: {
+      type: Boolean,
+      value: false
+    }
+  },
+  methods: {
+    handleClick(e) {
+      if (!this.data.show) return;
+      this.triggerEvent('click', {});
+    },
+    handleClickCancel() {
+      if (!this.data.maskClosable) return;
+      this.triggerEvent('cancel');
+    }
+  }
+})

+ 3 - 0
components/extend/alert/alert.json

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

+ 7 - 0
components/extend/alert/alert.wxml

@@ -0,0 +1,7 @@
+<view class="tui-alert-box {{show?'tui-alert-show':''}}">
+  <view class="tui-alert-content" style="font-size:{{size}}rpx;color:{{color}}">
+    <slot></slot>
+  </view>
+  <view class="tui-alert-btn" style="color:{{btnColor}}" hover-class="tui-alert-btn-hover" hover-stay-time="150" catchtap="handleClick">{{btnText}}</view>
+</view>
+<view class="tui-alert-mask {{show?'tui-alert-mask-show':''}}" catchtap="handleClickCancel"></view>

+ 73 - 0
components/extend/alert/alert.wxss

@@ -0,0 +1,73 @@
+.tui-alert-box {
+		position: fixed;
+		width: 560rpx;
+		left: 50%;
+		top: 50%;
+		background: #fff;
+		transition: all 0.3s ease-in-out;
+		transform: translate(-50%, -50%) scale(0);
+		opacity: 0;
+		border-radius: 6rpx;
+		overflow: hidden;
+		z-index: 99998;
+	}
+
+	.tui-alert-show {
+		transform: translate(-50%, -50%) scale(1);
+		opacity: 1;
+	}
+
+	.tui-alert-mask {
+    width: 100%;
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		background: rgba(0, 0, 0, 0.5);
+		z-index: 99996;
+		transition: all 0.3s ease-in-out;
+		opacity: 0;
+		visibility: hidden;
+	}
+
+	.tui-alert-mask-show {
+		visibility: visible;
+		opacity: 1;
+	}
+
+	.tui-alert-content {
+		text-align: center;
+		color: #333333;
+		padding: 98rpx 48rpx 92rpx 48rpx;
+		box-sizing: border-box;
+		word-break: break-all;
+	}
+
+	.tui-alert-btn {
+		width: 100%;
+		height: 90rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		background: #fff;
+		box-sizing: border-box;
+		position: relative;
+		font-size: 32rpx;
+		line-height: 32rpx;
+	}
+
+	.tui-alert-btn-hover {
+		background: #f7f7f7;
+	}
+
+	.tui-alert-btn::before {
+		width: 100%;
+		content: "";
+		position: absolute;
+		border-top: 1rpx solid #E0E0E0;
+		-webkit-transform: scaleY(0.5);
+		transform: scaleY(0.5);
+		left: 0;
+		top: 0;
+	}

+ 57 - 0
components/extend/button/button.js

@@ -0,0 +1,57 @@
+Component({
+  properties: {
+    //样式类型 primary, white, danger, warning, green,blue, gray,black
+    type: {
+      type: String,
+      value: 'primary'
+    },
+    //是否加阴影 type =primary和 danger有效
+    shadow: {
+      type: Boolean,
+      value: false
+    },
+    // 宽度 rpx或 %
+    width: {
+      type: String,
+      value: '100%'
+    },
+    //高度 rpx
+    height: {
+      type: String,
+      value: '94rpx'
+    },
+    //字体大小 rpx
+    size: {
+      type: Number,
+      value: 32
+    },
+    //形状 circle(圆角), square(默认方形),rightAngle(平角)
+    shape: {
+      type: String,
+      value: 'square'
+    },
+    plain: {
+      type: Boolean,
+      value: false
+    },
+    disabled: {
+      type: Boolean,
+      value: false
+    },
+    loading: {
+      type: Boolean,
+      value: false
+    }
+  },
+  data: {
+
+  },
+  methods: {
+    handleClick() {
+      if (this.data.disabled) {
+        return false;
+      }
+      this.triggerEvent('click', {})
+    }
+  }
+})

+ 3 - 0
components/extend/button/button.json

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

+ 39 - 0
components/extend/button/button.wxml

@@ -0,0 +1,39 @@
+<button class="tui-btn-class tui-btn {{plain?'tui-'+type+'-outline':'tui-btn-'+(type || 'primary')}} {{wxs.getDisabledClass(disabled,type)}} {{wxs.getShapeClass(shape,plain)}} {{wxs.getShadowClass(type,shadow,plain)}}" hover-class="{{wxs.getHoverClass(disabled,type,plain)}}"
+  style="width:{{width}};height:{{height}};line-height:{{height}};font-size:{{size}}rpx" loading="{{loading}}" disabled="{{disabled}}" bindtap="handleClick">
+  <slot></slot>
+</button>
+
+<wxs module="wxs">
+  module.exports = {
+    getShadowClass: function(type, shadow, plain) {
+      var className = '';
+      if (shadow && type != 'white' && !plain) {
+        className = 'tui-shadow-' + type;
+      }
+      return className;
+    },
+    getDisabledClass: function(disabled, type) {
+      var className = '';
+      if (disabled && type != 'white' && type != 'gray') {
+        className = 'tui-dark-disabled';
+      }
+      return className;
+    },
+    getShapeClass: function(shape, plain) {
+      var className = '';
+      if (shape == 'circle') {
+        className = plain ? 'tui-outline-fillet' : 'tui-fillet';
+      } else if (shape == "rightAngle") {
+        className = plain ? 'tui-outline-rightAngle' : 'tui-rightAngle';
+      }
+      return className;
+    },
+    getHoverClass: function(disabled, type, plain) {
+      var className = '';
+      if (!disabled) {
+        className = plain ? 'tui-outline-hover' : ('tui-' + (type || 'primary') + '-hover');
+      }
+      return className;
+    }
+  }
+</wxs>

+ 248 - 0
components/extend/button/button.wxss

@@ -0,0 +1,248 @@
+.tui-btn-primary {
+  background: #1582ad !important;
+  color: #fff;
+}
+
+.tui-shadow-primary {
+  box-shadow: 0 10rpx 14rpx 0 rgba(15, 96, 128, 0.14);
+}
+
+.tui-btn-danger {
+  background: #eb0909 !important;
+  color: #fff;
+}
+
+.tui-shadow-danger {
+  box-shadow: 0 10rpx 14rpx 0 rgba(235, 9, 9, 0.2);
+}
+
+.tui-btn-warning {
+  background: #fc872d !important;
+  color: #fff;
+}
+
+.tui-shadow-warning {
+  box-shadow: 0 10rpx 14rpx 0 rgba(252, 135, 45, 0.2);
+}
+
+.tui-btn-green {
+  background: #35b06a !important;
+  color: #fff;
+}
+
+.tui-shadow-green {
+  box-shadow: 0 10rpx 14rpx 0 rgba(53, 176, 106, 0.2);
+}
+
+.tui-btn-blue {
+  background: #5677fc !important;
+  color: #fff;
+}
+
+.tui-shadow-blue {
+  box-shadow: 0 10rpx 14rpx 0 rgba(86, 119, 252, 0.2);
+}
+
+.tui-btn-white {
+  background: #fff !important;
+  color: #333 !important;
+}
+
+.tui-btn-gray {
+  background: #bfbfbf !important;
+  color: #fff !important;
+}
+
+.tui-btn-black {
+  background: #333 !important;
+  color: #fff !important;
+}
+
+.tui-shadow-gray {
+  box-shadow: 0 10rpx 14rpx 0 rgba(191, 191, 191, 0.2);
+}
+
+.tui-hover-gray {
+  background: #f7f7f9 !important;
+}
+
+/* button start*/
+
+.tui-btn {
+  width: 100%;
+  position: relative;
+  border: 0 !important;
+  border-radius: 6rpx;
+  padding-left: 0;
+  padding-right: 0;
+  overflow: visible;
+}
+
+.tui-btn::after {
+  content: "";
+  position: absolute;
+  width: 200%;
+  height: 200%;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scale(0.5, 0.5);
+  transform: scale(0.5, 0.5);
+  box-sizing: border-box;
+  left: 0;
+  top: 0;
+  border-radius: 12rpx;
+  border: 0;
+}
+
+.tui-btn-white::after {
+  border: 1rpx solid #bfbfbf;
+}
+
+.tui-white-hover {
+  background: #e5e5e5 !important;
+  color: #2e2e2e !important;
+}
+
+.tui-dark-disabled {
+  opacity: 0.6 !important;
+  color: #fafbfc !important;
+}
+
+.tui-dark-disabled.tui-btn-danger {
+  opacity: 1 !important;
+  background: #fc8888 !important;
+}
+
+.tui-outline-hover {
+  opacity: 0.5;
+}
+
+.tui-primary-hover {
+  background: #126f93 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-primary-outline::after {
+  border: 1rpx solid #1582ad !important;
+}
+
+.tui-primary-outline {
+  color: #1582ad !important;
+  background: none;
+}
+
+.tui-danger-hover {
+  background: #c80808 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-danger-outline {
+  color: #eb0909 !important;
+  background: none;
+}
+
+.tui-danger-outline::after {
+  border: 1rpx solid #eb0909 !important;
+}
+
+.tui-warning-hover {
+  background: #d67326 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-warning-outline {
+  color: #fc872d !important;
+  background: none;
+}
+
+.tui-warning-outline::after {
+  border: 1px solid #fc872d !important;
+}
+
+.tui-green-hover {
+  background: #2d965a !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-green-outline {
+  color: #35b06a !important;
+  background: none;
+}
+
+.tui-green-outline::after {
+  border: 1rpx solid #35b06a !important;
+}
+
+.tui-blue-hover {
+  background: #4a67d6 !important;
+  color: #e5e5e5 !important;
+}
+
+.tui-blue-outline {
+  color: #5677fc !important;
+  background: none;
+}
+
+.tui-blue-outline::after {
+  border: 1rpx solid #5677fc !important;
+}
+
+.tui-gray-hover {
+  background: #a3a3a3 !important;
+  color: #898989;
+}
+
+.tui-gray-outline {
+  color: #999 !important;
+  background: none !important;
+}
+
+.tui-white-outline {
+  color: #fff !important;
+  background: none !important;
+}
+
+.tui-black-outline {
+  background: none !important;
+  color: #333 !important;
+}
+
+.tui-gray-outline::after {
+  border: 1rpx solid #ccc !important;
+}
+
+.tui-white-outline::after {
+  border: 1px solid #fff !important;
+}
+
+.tui-black-outline::after {
+  border: 1px solid #333 !important;
+}
+
+/*圆角 */
+
+.tui-fillet {
+  border-radius: 50rpx;
+}
+
+.tui-btn-white.tui-fillet::after {
+  border-radius: 98rpx;
+}
+
+.tui-outline-fillet::after {
+  border-radius: 98rpx;
+}
+
+/*平角*/
+
+.tui-rightAngle {
+  border-radius: 0;
+}
+
+.tui-btn-white.tui-rightAngle::after {
+  border-radius: 0;
+}
+
+.tui-outline-rightAngle::after {
+  border-radius: 0;
+}

+ 42 - 0
components/extend/tips/tips.js

@@ -0,0 +1,42 @@
+Component({
+  properties: {
+    //是否垂直居中
+    fixed: {
+      type: Boolean,
+      value: true
+    },
+    //图片地址,没有则不显示
+    imgUrl: {
+      type: String,
+      value: ""
+    },
+    //图片宽度
+    imgWidth: {
+      type: Number,
+      value: 200
+    },
+    //图片高度
+    imgHeight: {
+      type: Number,
+      value: 200
+    },
+    //按钮宽度
+    btnWidth: {
+      type: Number,
+      value: 200
+    },
+    //按钮文字,没有则不显示
+    btnText: {
+      type: String,
+      value: ""
+    }
+  },
+  data: {
+
+  },
+  methods: {
+    handleClick() {
+      this.triggerEvent('click', {})
+    }
+  }
+})

+ 3 - 0
components/extend/tips/tips.json

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

+ 7 - 0
components/extend/tips/tips.wxml

@@ -0,0 +1,7 @@
+<view class="tui-tips-box {{fixed?'tui-tips-fixed':''}}">
+  <image src="{{imgUrl}}" class="tui-tips-icon" style="width:{{imgWidth}}rpx;height:{{imgHeight}}rpx"></image>
+  <view class="tui-tips-content">
+    <slot></slot>
+  </view>
+  <button class="tui-tips-btn" hover-class="tui-tips-btn-hover" style="width:{{btnWidth}}rpx" wx:if="{{btnText}}" bindtap="handleClick">{{btnText}}</button>
+</view>

+ 49 - 0
components/extend/tips/tips.wxss

@@ -0,0 +1,49 @@
+	.tui-tips-box {
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+    text-align: center
+	}
+
+	.tui-tips-fixed {
+		width: 90%;
+		position: fixed;
+		left: 50%;
+		top: 50%;
+		-webkit-transform: translate(-50%, -50%);
+		transform: translate(-50%, -50%);
+	}
+
+	.tui-tips-icon {
+		display: block;
+		flex-shrink: 0;
+		width: 280rpx;
+		height: 280rpx;
+		margin-bottom: 40rpx;
+	}
+
+	.tui-tips-content {
+		text-align: center;
+		color: #666666;
+		font-size: 28rpx;
+		padding: 0 50rpx 24rpx 50rpx;
+		box-sizing: border-box;
+		word-break: break-all;
+		word-wrap: break-word;
+	}
+
+	.tui-tips-btn {
+		height: 60rpx;
+		line-height: 60rpx;
+		font-size: 28rpx;
+		background: #EB0909;
+		color: #fff;
+		border-radius: 6rpx;
+		margin: 0;
+	}
+
+	.tui-tips-btn-hover {
+		background: #c80808;
+		color: #e5e5e5;
+	}

+ 74 - 0
components/extend/toast/toast.js

@@ -0,0 +1,74 @@
+let timer;
+Page({
+  properties: {},
+  data: {
+    //是否显示
+    visible: false,
+    //显示标题
+    title: "操作成功",
+    //显示内容
+    content: "",
+    //是否有icon
+    icon: false,
+    imgUrl: ""
+  },
+  lifetimes: {
+    detached: function () {
+      clearTimeout(timer);
+      timer = null;
+    }
+  },
+  methods: {
+    // show: function (options) {
+    //   let {
+    //     duration = 2000,
+    //     icon = false
+    //   } = options;
+    //   clearTimeout(timer);
+    //   if (icon && options.imgUrl) {
+    //     this.setData({
+    //       imgUrl: options.imgUrl
+    //     })
+    //   }
+    //   this.setData({
+    //     visible: true,
+    //     title: options.title || "",
+    //     content: options.content || "",
+    //     icon: icon
+    //   })
+    //   timer = setTimeout(() => {
+    //     this.setData({
+    //       visible: false
+    //     }, () => {
+    //       timer = null;
+    //     })
+    //   }, duration)
+    // }
+  },
+  show: function (options) {
+    let {
+      duration = 2000,
+      icon = false
+    } = options;
+    clearTimeout(timer);
+    if (icon && options.imgUrl) {
+      this.setData({
+        imgUrl: options.imgUrl
+      })
+    }
+    this.setData({
+      visible: true,
+      title: options.title || "",
+      content: options.content || "",
+      icon: icon
+    })
+    timer = setTimeout(() => {
+      this.setData({
+        visible: false
+      }, () => {
+        timer = null;
+      })
+    }, duration)
+  }
+
+})

+ 4 - 0
components/extend/toast/toast.json

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

+ 17 - 0
components/extend/toast/toast.wxml

@@ -0,0 +1,17 @@
+<view class="tui-toast {{visible?'tui-toast-show':''}} {{content?'tui-toast-padding':''}} {{icon?'':'tui-unicon-padding'}}" style="width:{{wxs.getWidth(icon,content)}}">
+  <image src="{{imgUrl}}" class="tui-toast-img" wx:if="{{icon}}"></image>
+  <view class="tui-toast-text {{icon?'':'tui-unicon'}}">{{title}}</view>
+  <view class="tui-toast-text tui-content-ptop" wx:if="{{content && icon}}">{{content}}</view>
+</view>
+
+<wxs module="wxs">
+  module.exports = {
+    getWidth: function(icon, content) {
+      var width = "auto";
+      if (icon) {
+        width = content ? '420rpx' : '360rpx';
+      }
+      return width
+    }
+  }
+</wxs>

+ 58 - 0
components/extend/toast/toast.wxss

@@ -0,0 +1,58 @@
+.tui-toast {
+		background: rgba(0, 0, 0, 0.75);
+		border-radius: 10rpx;
+		position: fixed;
+		visibility: hidden;
+		opacity: 0;
+		left: 50%;
+		top: 48%;
+		-webkit-transform: translate(-50%, -50%);
+		transform: translate(-50%, -50%);
+		transition:  0.3s ease-in-out;
+		transition-property:opacity,visibility;
+		z-index: 9999;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		flex-direction: column;
+		padding: 60rpx 20rpx 54rpx 20rpx;
+		box-sizing: border-box;
+	}
+
+	.tui-toast-padding {
+		padding-top: 50rpx !important;
+		padding-bottom: 50rpx !important;
+	}
+	.tui-unicon-padding {
+		padding: 24rpx 40rpx !important;
+		word-break: break-all;
+	}
+
+	.tui-toast-show {
+		visibility: visible;
+		opacity: 1;
+	}
+
+
+	.tui-toast-img {
+		width: 120rpx;
+		height: 120rpx;
+		display: block;
+		margin-bottom: 28rpx;
+	}
+
+	.tui-toast-text {
+		font-size: 30rpx;
+		line-height: 30rpx;
+		font-weight: 400;
+		color: #fff;
+		text-align: center;
+	}
+	.tui-unicon{
+		line-height: 40rpx !important;
+		font-size: 32rpx !important;
+	}
+	.tui-content-ptop {
+		padding-top: 10rpx;
+		font-size: 26rpx !important;
+	}

+ 25 - 0
components/icon/icon.js

@@ -0,0 +1,25 @@
+Component({
+  externalClasses: ['tui-icon-class'],
+  properties: {
+    name: {
+      type: String,
+      value: ''
+    },
+    size: {
+      type: Number,
+      value: 32
+    },
+    color: {
+      type: String,
+      value: ''
+    },
+    bold:{
+      type:Boolean,
+      value:false
+    },
+    visible:{
+      type: Boolean,
+      value: true
+    }
+  }
+});

+ 3 - 0
components/icon/icon.json

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

+ 1 - 0
components/icon/icon.wxml

@@ -0,0 +1 @@
+<view class="tui-icon-class tui-icon tui-icon-{{name}}" style="font-size: {{ size }}px; {{ color ? 'color:' + color : '' }};{{bold?'font-weight: bold': ''}}" wx:if="{{visible}}"></view>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 0
components/icon/icon.wxss


+ 49 - 0
components/list-cell/list-cell.js

@@ -0,0 +1,49 @@
+Component({
+  externalClasses: ['tui-cell-class'], //自定义样式
+  properties: {
+    arrow: {
+      type: Boolean,
+      value: false //是否有箭头
+    },
+    hover: {
+      type: Boolean,
+      value: true //是否有点击效果
+    },
+    last: {
+      type: Boolean,
+      value: false //最后一条数据隐藏线条
+    },
+    lineLeft: {
+      type: Boolean,
+      value: true
+    },
+    lineRight: {
+      type: Boolean,
+      value: false
+    },
+    padding: {
+      type: String,
+      value: "26rpx 30rpx"
+    },
+    bgcolor:{
+      type: String,
+      value: "#fff" //背景颜色
+    },
+    size:{
+      type: Number,
+      value: 32//字体大小
+    },
+    color: {
+      type: String,
+      value: "#333" //字体颜色
+    }
+  },
+  data: {
+
+  },
+  methods: {
+    handleClick() {
+      this.triggerEvent('click', {});
+    }
+  }
+})

+ 4 - 0
components/list-cell/list-cell.json

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

+ 4 - 0
components/list-cell/list-cell.wxml

@@ -0,0 +1,4 @@
+<view class="tui-cell-class tui-list-cell {{arrow?'tui-cell-arrow':''}} {{last?'tui-cell-last':''}} {{lineLeft?'tui-line-left':''}} {{lineRight?'tui-line-right':''}}" hover-class="{{hover?'tui-cell-hover':''}}" style="background: {{bgcolor}};font-size: {{ size }}rpx; {{ color ? 'color:' + color : '' }};padding:{{padding}}"
+  hover-stay-time="150" bindtap="handleClick">
+  <slot></slot>
+</view>

+ 49 - 0
components/list-cell/list-cell.wxss

@@ -0,0 +1,49 @@
+.tui-list-cell {
+  position: relative;
+  width: 100%;
+  box-sizing: border-box;
+  overflow: hidden;
+  display: flex;
+  align-items: center;
+}
+
+.tui-cell-hover {
+  background: #f7f7f9 !important;
+}
+
+.tui-list-cell::after {
+  content: '';
+  position: absolute;
+  border-bottom: 1rpx solid #eaeef1;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  bottom: 0;
+  right: 0;
+  left: 0;
+}
+.tui-line-left::after{
+		left: 30rpx !important;
+	}
+	
+	.tui-line-right::after{
+		right: 30rpx !important;
+	}
+
+.tui-cell-last::after {
+  border-bottom: 0 !important;
+}
+
+.tui-list-cell.tui-cell-arrow:before {
+  content: " ";
+  height: 11px;
+  width: 11px;
+  border-width: 2px 2px 0 0;
+  border-color: #b2b2b2;
+  border-style: solid;
+  -webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
+  transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
+  position: absolute;
+  top: 50%;
+  margin-top: -7px;
+  right: 30rpx;
+}

+ 15 - 0
components/list-view/list-view.js

@@ -0,0 +1,15 @@
+Component({
+  externalClasses: ['tui-view-class'], //自定义样式
+  properties: {
+    title: {
+      type: String,
+      value: ''
+    },
+    unlined: {
+      type: String,
+      value: '' //top,bottom,all
+    }
+  },
+  data: {},
+  methods: {}
+})

+ 4 - 0
components/list-view/list-view.json

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

+ 6 - 0
components/list-view/list-view.wxml

@@ -0,0 +1,6 @@
+<view class="tui-list-view tui-view-class">
+  <view class="tui-list-title" wx:if="{{title}}">{{title}}</view>
+  <view class="tui-list-content {{unlined?'tui-border-'+unlined:''}}">
+    <slot></slot>
+  </view>
+</view>

+ 46 - 0
components/list-view/list-view.wxss

@@ -0,0 +1,46 @@
+.tui-list-title{
+  width: 100%;
+  padding: 30rpx;
+  box-sizing: border-box;
+  font-size: 30rpx;
+  line-height: 30rpx;
+  color: #666;
+}
+.tui-list-content{
+  width: 100%;
+  position: relative;
+}
+.tui-list-content::before {
+  content: " ";
+  position: absolute;
+  top: -1rpx;
+  right: 0;
+  left: 0;
+  border-top: 1rpx solid #eaeef1;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+
+}
+.tui-list-content::after {
+  content: '';
+  position: absolute;
+  border-bottom: 1rpx solid #eaeef1;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  bottom: 0;
+  right: 0;
+  left: 0;
+}
+
+.tui-border-top::before {
+  border-top: 0;
+}
+.tui-border-bottom::after {
+  border-bottom:0;
+}
+.tui-border-all::after {
+  border-bottom:0;
+}
+.tui-border-all::before {
+  border-top:0;
+}

+ 17 - 0
components/loading/loading.js

@@ -0,0 +1,17 @@
+Component({
+  externalClasses: ['tui-loading-class'],
+  properties: {
+    text:{
+      type: String,
+      value: "正在加载..."
+    },
+    visible: {
+      type: Boolean,
+      value: false
+    }
+  },
+  data: {
+  },
+  methods: {
+  }
+})

+ 4 - 0
components/loading/loading.json

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

+ 4 - 0
components/loading/loading.wxml

@@ -0,0 +1,4 @@
+ <view class="tui-loading-class tui-loading-init" wx:if="{{visible}}">
+    <view class="tui-loading-center"></view>
+    <view class="tui-loadmore-tips">{{text}}</view>
+  </view>

+ 56 - 0
components/loading/loading.wxss

@@ -0,0 +1,56 @@
+.tui-loading-init {
+  min-width: 200rpx;
+  min-height: 200rpx;
+  max-width: 500rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+  z-index: 9999;
+  font-size: 26rpx;
+  color: #fff;
+  background:rgba(0, 0, 0, .7);
+  border-radius: 10rpx;
+}
+
+.tui-loading-center {
+  width: 50rpx;
+  height: 50rpx;
+  border: 3px solid #fff;
+  border-radius: 50%;
+  margin: 0 6px;
+  display: inline-block;
+  vertical-align: middle;
+  clip-path: polygon(0% 0%, 100% 0%, 100% 40%, 0% 40%);
+  animation: rotate 1s linear infinite;
+  margin-bottom: 36rpx;
+}
+.tui-loadmore-tips{
+  text-align: center;
+  padding: 0 20rpx;
+  box-sizing: border-box;
+}
+
+@-webkit-keyframes rotate {
+  from {
+    transform: rotatez(0deg);
+  }
+
+  to {
+    transform: rotatez(360deg);
+  }
+}
+
+@keyframes rotate {
+  from {
+    transform: rotatez(0deg);
+  }
+
+  to {
+    transform: rotatez(360deg);
+  }
+}

+ 27 - 0
components/loadmore/loadmore.js

@@ -0,0 +1,27 @@
+Component({
+  externalClasses: ['tui-loadmore-class'],
+  properties: {
+    //显示文本
+    text: {
+      type: String,
+      value: "正在加载..."
+    },
+    //是否可见
+    visible: {
+      type: Boolean,
+      value: false
+    },
+    //loading 样式 :1,2,3
+    index:{
+      type: Number,
+      value: 1
+    },
+    //颜色设置,只有index=3时生效:primary,red,orange,green
+    type:{
+      type: String,
+      value: ""
+    }
+  },
+  data: {},
+  methods: {}
+})

+ 4 - 0
components/loadmore/loadmore.json

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

+ 4 - 0
components/loadmore/loadmore.wxml

@@ -0,0 +1,4 @@
+<view class="tui-loadmore-class tui-loadmore" wx:if="{{visible}}">
+  <view class="{{'tui-loading-'+index}} {{(index==3 && type)?'tui-loading-'+type:''}}"></view>
+  <view class="tui-loadmore-tips">{{text}}</view>
+</view>

+ 128 - 0
components/loadmore/loadmore.wxss

@@ -0,0 +1,128 @@
+.tui-loadmore {
+  width: 48%;
+  margin: 1.5em auto;
+  line-height: 1.5em;
+  font-size: 24rpx;
+  text-align: center;
+}
+
+.tui-loading-1 {
+  margin: 0 5px;
+  width: 20px;
+  height: 20px;
+  display: inline-block;
+  vertical-align: middle;
+  -webkit-animation: a 1s steps(12) infinite;
+  animation: a 1s steps(12) infinite;
+  background: transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=) no-repeat;
+  background-size: 100%;
+}
+
+@-webkit-keyframes a {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  to {
+    -webkit-transform: rotate(1turn);
+    transform: rotate(1turn);
+  }
+}
+
+@keyframes a {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  to {
+    -webkit-transform: rotate(1turn);
+    transform: rotate(1turn);
+  }
+}
+
+.tui-loadmore-tips {
+  display: inline-block;
+  vertical-align: middle;
+}
+
+.tui-loading-2 {
+  width: 28rpx;
+  height: 28rpx;
+  border: 1px solid #8f8d8e;
+  border-radius: 50%;
+  margin: 0 6px;
+  display: inline-block;
+  vertical-align: middle;
+  clip-path: polygon(0% 0%, 100% 0%, 100% 30%, 0% 30%);
+  animation: rotate 1s linear infinite;
+}
+
+@-webkit-keyframes rotate {
+  from {
+    transform: rotatez(0deg);
+  }
+
+  to {
+    transform: rotatez(360deg);
+  }
+}
+
+@keyframes rotate {
+  from {
+    transform: rotatez(0deg);
+  }
+
+  to {
+    transform: rotatez(360deg);
+  }
+}
+
+.tui-loading-3 {
+  display: inline-block;
+  margin: 0 6px;
+  vertical-align: middle;
+  width: 28rpx;
+  height: 28rpx;
+  background: 0 0;
+  border-radius: 50%;
+  border: 2px solid;
+  border-color: #e5e5e5 #e5e5e5 #e5e5e5 #8f8d8e;
+  animation: tui-rotate 0.7s linear infinite;
+}
+.tui-loading-3.tui-loading-primary {
+  border-color: #e5e5e5 #e5e5e5 #e5e5e5 #5677fc;
+}
+
+.tui-loading-3.tui-loading-green {
+  border-color: #e5e5e5 #e5e5e5 #e5e5e5 #19be6b;
+}
+
+.tui-loading-3.tui-loading-orange {
+  border-color: #e5e5e5 #e5e5e5 #e5e5e5 #ff7900;
+}
+
+.tui-loading-3.tui-loading-red {
+  border-color: #ededed #ededed #ededed #ed3f14;
+}
+
+@-webkit-keyframes tui-rotate {
+  0% {
+    transform: rotate(0);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+@keyframes tui-rotate {
+  0% {
+    transform: rotate(0);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}

+ 92 - 0
components/modal/modal.js

@@ -0,0 +1,92 @@
+Component({
+  externalClasses: ['tui-modal-class'],
+  properties: {
+    //是否显示
+    show:{
+      type:Boolean,
+      value:false
+    },
+    width: {
+      type: String,
+      value: "84%"
+    },
+    padding: {
+      type: String,
+      value: "40rpx 64rpx"
+    },
+    radius: {
+      type: String,
+      value: "24rpx"
+    },
+    //标题
+    title: {
+      type: String,
+      value: ""
+    },
+    //内容
+    content: {
+      type: String,
+      value: ""
+    },
+    //内容字体颜色
+    color: {
+      type: String,
+      value: "#999"
+    },
+    //内容字体大小
+    size: {
+      type: Number,
+      value: 28
+    },
+    //形状 circle, square
+    shape: {
+      type: String,
+      value: 'square'
+    },
+    button: {
+      type: Array,
+      value: [{
+        text: "取消",
+        type: "red",
+        plain: true //是否空心
+      }, {
+        text: "确定",
+        type: "red",
+        plain: false
+      }]
+    },
+    //点击遮罩 是否可关闭
+    maskClosable: {
+      type: Boolean,
+      value: true
+    },
+    //自定义弹窗内容
+    custom:{
+      type:Boolean,
+      value:false
+    },
+    //淡入效果,自定义弹框插入input输入框时传true
+    fadein: {
+      type: Boolean,
+      value: false
+    }
+
+  },
+  data: {
+
+  },
+  methods: {
+    handleClick(e) {
+      if (!this.data.show) return;
+      const dataset = e.currentTarget.dataset;
+      this.triggerEvent('click', {
+        index: Number(dataset.index)
+      });
+    },
+    handleClickCancel() {
+      if(!this.data.maskClosable) return;
+      this.triggerEvent('cancel');
+    },
+    forbid(){}
+  }
+})

+ 4 - 0
components/modal/modal.json

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

+ 18 - 0
components/modal/modal.wxml

@@ -0,0 +1,18 @@
+<view catchtouchmove="forbid">
+  <view class="tui-modal-class tui-modal-box {{show?'tui-modal-show':''}} {{(fadein || show)?'tui-modal-normal':'tui-modal-scale'}}" style="width:{{width}};padding:{{padding}};border-radius:{{radius}}">
+    <view wx:if="{{!custom}}">
+      <view class="tui-modal-title" v-if="title">{{title}}</view>
+      <view class="tui-modal-content {{title?'':'tui-mtop'}}" style="color:{{color}};font-size:{{size}}rpx">{{content}}</view>
+      <view class="tui-modalBtn-box {{button.length>2?'tui-flex-column':''}}">
+        <block wx:for="{{button}}" wx:key="{{index}}">
+          <button class="tui-modal-btn {{'tui-'+(item.type || 'primary')+(item.plain?'-outline':'')}} {{button.length!=2?'tui-btn-width':''}} {{button.length>2?'tui-mbtm':''}} {{shape=='circle'?'tui-circle-btn':''}}" hover-class="{{'tui-'+(item.plain?'outline':(item.type || 'primary'))+'-hover'}}"
+            data-index="{{index}}" bindtap="handleClick">{{item.text || "确定"}}</button>
+        </block>
+      </view>
+    </view>
+    <view wx:else>
+      <slot></slot>
+    </view>
+  </view>
+  <view class="tui-modal-mask {{show?'tui-mask-show':''}}" bindtap="handleClickCancel"></view>
+</view>

+ 248 - 0
components/modal/modal.wxss

@@ -0,0 +1,248 @@
+.tui-modal-box {
+  position: fixed;
+  left: 50%;
+  top: 50%;
+  margin: auto;
+  background: #fff;
+  z-index: 9999998;
+  transition: all 0.3s ease-in-out;
+  opacity: 0;
+  visibility: hidden;
+  box-sizing: border-box;
+}
+
+.tui-modal-scale {
+		transform: translate(-50%, -50%) scale(0);
+	}
+
+	.tui-modal-normal {
+		transform: translate(-50%, -50%) scale(1);
+	}
+
+	.tui-modal-show {
+		opacity: 1;
+		visibility: visible;
+	}
+.tui-modal-mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.6);
+  z-index: 9999996;
+  transition: all 0.3s ease-in-out;
+  opacity: 0;
+  visibility: hidden;
+}
+
+.tui-mask-show {
+  visibility: visible;
+  opacity: 1;
+}
+
+.tui-modal-title {
+  text-align: center;
+  font-size: 34rpx;
+  color: #333;
+  padding-top: 20rpx;
+  font-weight: bold;
+}
+
+.tui-modal-content {
+  text-align: center;
+  color: #999;
+  font-size: 28rpx;
+  padding-top: 20rpx;
+  padding-bottom: 60rpx;
+}
+
+.tui-mtop {
+  margin-top: 30rpx;
+}
+.tui-mbtm {
+  margin-bottom: 30rpx;
+}
+
+.tui-modalBtn-box {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.tui-flex-column {
+  flex-direction: column;
+}
+
+.tui-modal-btn {
+  width: 44%;
+  height: 68rpx;
+  line-height: 68rpx;
+  position: relative;
+  border-radius: 10rpx;
+  font-size: 24rpx;
+  overflow: visible;
+}
+
+.tui-modal-btn::after {
+  content: "";
+  position: absolute;
+  width: 200%;
+  height: 200%;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scale(0.5, 0.5);
+  transform: scale(0.5, 0.5);
+  left: 0;
+  top: 0;
+  border-radius: 20rpx;
+}
+
+.tui-btn-width {
+  width: 80% !important;
+}
+
+.tui-primary {
+  background: #5677fc;
+  color: #fff;
+}
+
+.tui-primary-hover {
+  background: #4a67d6;
+  color: #e5e5e5;
+}
+
+.tui-primary-outline {
+  color: #5677fc;
+  background: none;
+}
+
+.tui-primary-outline::after {
+  border: 1px solid #5677fc;
+}
+
+.tui-danger {
+  background: #ed3f14;
+  color: #fff;
+}
+
+.tui-danger-hover {
+  background: #d53912;
+  color: #e5e5e5;
+}
+
+.tui-danger-outline {
+  color: #ed3f14;
+  background: none;
+}
+
+.tui-danger-outline::after {
+  border: 1px solid #ed3f14;
+}
+
+.tui-red {
+  background: #e41f19;
+  color: #fff;
+}
+
+.tui-red-hover {
+  background: #c51a15;
+  color: #e5e5e5;
+}
+
+.tui-red-outline {
+  color: #e41f19;
+  background: none;
+}
+
+.tui-red-outline::after {
+  border: 1px solid #e41f19;
+}
+
+.tui-warning {
+  background: #ff7900;
+  color: #fff;
+}
+
+.tui-warning-hover {
+  background: #e56d00;
+  color: #e5e5e5;
+}
+
+.tui-warning-outline {
+  color: #ff7900;
+  background: none;
+}
+
+.tui-warning-outline::after {
+  border: 1px solid #ff7900;
+}
+
+.tui-green {
+  background: #19be6b;
+  color: #fff;
+}
+
+.tui-green-hover {
+  background: #16ab60;
+  color: #e5e5e5;
+}
+
+.tui-green-outline {
+  color: #19be6b;
+  background: none;
+}
+
+.tui-green-outline::after {
+  border: 1px solid #19be6b;
+}
+
+.tui-white {
+  background: #fff;
+  color: #333;
+}
+
+.tui-white-hover {
+  background: #f7f7f9;
+  color: #666;
+}
+
+.tui-white-outline {
+  color: #333;
+  background: none;
+}
+
+.tui-white-outline::after {
+  border: 1px solid #333;
+}
+
+.tui-gray {
+  background: #ededed;
+  color: #999;
+}
+
+.tui-gray-hover {
+  background: #d5d5d5;
+  color: #898989;
+}
+
+.tui-gray-outline {
+  color: #999;
+  background: none;
+}
+
+.tui-gray-outline::after {
+  border: 1px solid #999;
+}
+
+.tui-outline-hover {
+  opacity: 0.6;
+}
+
+.tui-circle-btn {
+  border-radius: 40rpx !important;
+}
+
+.tui-circle-btn::after {
+  border-radius: 80rpx !important;
+}

+ 30 - 0
components/nomore/nomore.js

@@ -0,0 +1,30 @@
+//为了可重用性强,这里做了修改,和thorui.css里的略有不同
+Component({
+  externalClasses: ['tui-nomore-class'],
+  properties: {
+    //是否可见
+    visible: {
+      type: Boolean,
+      value: false
+    },
+    //当前页面背景颜色
+    bgcolor: {
+      type: String,
+      value: "#fafafa"
+    },
+    //是否以圆点代替 "没有更多了"
+    isDot: {
+      type: Boolean,
+      value: false
+    },
+    //isDot为false时生效
+    text:{
+      type:String,
+      value:"没有更多了"
+    }
+  },
+  data: {  
+    dotText:"●"
+  },
+  methods: {}
+})

+ 4 - 0
components/nomore/nomore.json

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

+ 5 - 0
components/nomore/nomore.wxml

@@ -0,0 +1,5 @@
+<view class="tui-nomore-class tui-loadmore" wx:if="{{visible}}">
+  <view class="{{isDot?'tui-nomore-dot':'tui-nomore'}}">
+    <view style="background:{{bgcolor}}" class="{{isDot?'tui-dot-text':'tui-text'}}">{{isDot?dotText:text}}</view>
+  </view>
+</view>

+ 69 - 0
components/nomore/nomore.wxss

@@ -0,0 +1,69 @@
+.tui-loadmore {
+  width: 48%;
+  margin: 1.5em auto;
+  line-height: 1.5em;
+  font-size: 24rpx;
+  text-align: center;
+}
+
+.tui-nomore {
+  position: relative;
+  text-align: center;
+  display: flex;
+  justify-content: center;
+  margin-top: 10rpx;
+  padding-bottom: 44rpx;
+}
+
+.tui-nomore::before {
+  content: '';
+  position: absolute;
+  border-bottom: 1rpx solid #e5e5e5;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  width: 360rpx;
+  top: 18rpx;
+}
+
+.tui-text {
+  position: absolute;
+  color: #999;
+  font-size: 24rpx;
+  text-align: center;
+  padding: 0 18rpx;
+  height: 36rpx;
+  line-height: 36rpx;
+  z-index: 1;
+}
+
+.tui-nomore-dot {
+  position: relative;
+  text-align: center;
+  display: flex;
+  justify-content: center;
+  margin-top: 10rpx;
+  padding-bottom: 40rpx;
+}
+
+.tui-nomore-dot::before {
+  content: '';
+  position: absolute;
+  border-bottom: 1rpx solid #e5e5e5;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  width: 360rpx;
+  top: 18rpx;
+}
+
+.tui-dot-text {
+  position: absolute;
+  color: #e5e5e5;
+  font-size: 10px;
+  text-align: center;
+  width: 50rpx;
+  height: 36rpx;
+  line-height: 36rpx;
+  transform: scale(0.8);
+  transform-origin: center center;
+  z-index: 1;
+}

+ 154 - 0
components/numberbox/numberbox.js

@@ -0,0 +1,154 @@
+Component({
+  externalClasses: ['tui-numberbox-class'],
+  properties: {
+    value: {
+      type: Number,
+      value: 1,
+      observer(val) {
+        this.setValue()
+      }
+    },
+    //最小值
+    min: {
+      type: Number,
+      value: 0
+    },
+    //最大值
+    max: {
+      type: Number,
+      value: 100
+    },
+    //迈步大小 1 1.1 10...
+    step: {
+      type: Number,
+      value: 1
+    },
+    //是否禁用操作
+    disabled: {
+      type: Boolean,
+      value: false
+    },
+    //加减图标大小 rpx
+    iconsize: {
+      type: Number,
+      value: 24
+    },
+    iconcolor: {
+      type: String,
+      value: "#333"
+    },
+    //input 高度
+    height: {
+      type: Number,
+      value: 50
+    },
+    //input 宽度
+    width: {
+      type: Number,
+      value: 90
+    },
+    //input 背景颜色
+    bgcolor: {
+      type: String,
+      value: "#f2f2f2"
+    },
+    //input 字体颜色
+    color: {
+      type: String,
+      value: "#333"
+    },
+    //索引值,列表中使用
+    index: {
+      type: Number,
+      value: 0
+    },
+    //自定义参数
+    custom: {
+      type: Number,
+      value: 0
+    }
+  },
+  data: {
+    inputValue: 0
+  },
+  lifetimes: {
+    attached: function() {
+      this.setValue()
+    }
+  },
+  methods: {
+    setValue() {
+      this.setData({
+        inputValue: +this.data.value
+      })
+    },
+    getScale() {
+      let scale = 1;
+      //浮点型
+      if (this.data.step != parseInt(this.data.step)) {
+        scale = Math.pow(10, (this.data.step + '').split('.')[1].length)
+      }
+      return scale;
+    },
+    calcNum: function(type) {
+      if (this.data.disabled) {
+        return
+      }
+      const scale = this.getScale()
+      let num = this.data.value * scale
+      let step = this.data.step * scale
+      if (type === 'reduce') {
+        num -= step
+      } else if (type === 'plus') {
+        num += step
+      }
+      let value = num / scale
+      if (type === "plus" && value < this.data.min) {
+        value = this.data.min
+      } else if (type === "reduce" && value > this.data.max) {
+        value = this.data.max
+      }
+      if (value < this.data.min || value > this.data.max) {
+        return
+      }
+
+      this.handleChange(value, type)
+    },
+    plus: function() {
+      this.calcNum("plus")
+    },
+    reduce: function() {
+      this.calcNum("reduce")
+    },
+    blur: function(e) {
+      let value = e.detail.value
+      if (value) {
+        value = +value
+        if (value > this.data.max) {
+          value = this.data.max
+        } else if (value < this.data.min) {
+          value = this.data.min
+        }
+      } else {
+        value = this.data.min
+      }
+      if (value == this.data.value && value != this.data.inputValue) {
+        this.setData({
+          inputValue: value
+        })
+      }
+      this.handleChange(value, "blur")
+    },
+    handleChange(value, type) {
+      if (this.data.disabled) {
+        return
+      }
+      this.triggerEvent('change', {
+        value: value,
+        type: type,
+        index: this.data.index,
+        custom: this.data.custom
+      })
+    }
+  }
+})

+ 4 - 0
components/numberbox/numberbox.json

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

+ 5 - 0
components/numberbox/numberbox.wxml

@@ -0,0 +1,5 @@
+<view class="tui-numberbox-class tui-numberbox">
+  <view class="tui-numbox-icon tui-icon-reduce {{disabled || min>=value?'tui-disabled':''}}" bindtap="reduce" style="color:{{iconcolor}};font-size:{{iconsize}}rpx"></view>
+  <input type="number" value="{{inputValue}}" disabled="{{disabled}}" bindblur="blur" class="tui-num-input" style="color:{{color}};font-size:{{iconsize}}rpx;background:{{bgcolor}};height:{{height}}rpx;width:{{width}}rpx" />
+  <view class="tui-numbox-icon tui-icon-plus  {{disabled || value>=max?'tui-disabled':''}}" bindtap="plus" style="color:{{iconcolor}};font-size:{{iconsize}}rpx"></view>
+</view>

+ 38 - 0
components/numberbox/numberbox.wxss

@@ -0,0 +1,38 @@
+@font-face {
+  font-family: 'numberbox';
+  src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAASQAA0AAAAABtwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEdAAAABoAAAAciBpnRUdERUYAAARUAAAAHgAAAB4AKQALT1MvMgAAAZwAAABDAAAAVjxzSINjbWFwAAAB9AAAAEYAAAFK5zLpOGdhc3AAAARMAAAACAAAAAj//wADZ2x5ZgAAAkgAAACHAAAAnIfIEjxoZWFkAAABMAAAAC8AAAA2FZWEOWhoZWEAAAFgAAAAHAAAACQH3gOFaG10eAAAAeAAAAARAAAAEgwAAAFsb2NhAAACPAAAAAwAAAAMADAATm1heHAAAAF8AAAAHwAAACABEAAobmFtZQAAAtAAAAFJAAACiCnmEVVwb3N0AAAEHAAAAC0AAABV/+8iFXjaY2BkYGAA4gVmC5Tj+W2+MnCzMIDATWsFOQT9v5GFgbkeyOVgYAKJAgDrogf+AHjaY2BkYGBu+N/AEMPCAAJAkpEBFbAAAEcKAm142mNgZGBgYGWQYQDRDAxMQMwFhAwM/8F8BgALpAE5AHjaY2BkYWCcwMDKwMDUyXSGgYGhH0IzvmYwYuQAijKwMjNgBQFprikMDs9Yn01kbvjfwBDD3MDQABRmBMkBAOXpDHEAeNpjYYAAFghmZGAAAACdAA4AAAB42mNgYGBmgGAZBkYGEHAB8hjBfBYGDSDNBqQZGZiesT6b+P8/AwOElvwnWQxVDwSMbAxwDiMTkGBiQAWMDMMeAABRZwszAAAAAAAAAAAAAAAwAE542iWKQQrCMBBF5xNpd0pQ7EIoTEnahSCTUNqdWz2A9TrieXKeXCc1qcPn/zfzh0BYv2pVH7oQgbvqdG5Yt/DTrNlPYz+wHvuuqhFSME4sFshTgKUsKfhH5lg8BSul3i5bS3mQdd0RIh2IjnvUrkXDd8zuhuFt86tY9fonIsSYgsXpB+cCGosAeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAOWMGiTIxMjMwiWZmJQJRXVQoigTgjMd9QGIsgAFDsEBsAAAAAAAAB//8AAgABAAAADAAAABYAAAACAAEAAwAEAAEABAAAAAIAAAAAeNpjYGBgZACCq0vUOUD0TWsFORgNADPBBE4AAA==) format('woff');
+  font-weight: normal;
+  font-style: normal;
+}
+
+.tui-numbox-icon {
+  font-family: "numberbox" !important;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+   padding: 10rpx;
+}
+
+.tui-icon-reduce:before {
+  content: "\e691";
+}
+
+.tui-icon-plus:before {
+  content: "\e605";
+}
+
+.tui-numberbox {
+  display: -webkit-inline-flex;
+  display: inline-flex;
+  align-items: center;
+}
+
+.tui-num-input {
+  text-align: center;
+  margin: 0 10rpx;
+  font-weight: bold;
+}
+
+.tui-disabled{
+  color: #ededed !important;
+}

+ 38 - 0
components/tag/tag.js

@@ -0,0 +1,38 @@
+Component({
+  externalClasses: ['tui-tag-class'], //自定义样式
+  properties: {
+    // primary, white, danger, warning, green, gray,light-blue,light-brownish,light-orange,light-green
+    type: {
+      type: String,
+      value: 'primary',
+    },
+    // '', small
+    size: {
+      type: String,
+      value: '',
+    },
+    // circle, square,circleLeft,circleRight
+    shape: {
+      type: String,
+      value: 'square'
+    },
+    //是否空心
+    plain: {
+      type: Boolean,
+      value: false
+    },
+    //是否可见
+    visible: {
+      type: Boolean,
+      value: true
+    }
+  },
+  data: {
+
+  },
+  methods: {
+    handleClick() {
+      this.triggerEvent('click', {});
+    }
+  }
+})

+ 4 - 0
components/tag/tag.json

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

+ 24 - 0
components/tag/tag.wxml

@@ -0,0 +1,24 @@
+<view class="tui-tag-class {{size?'tui-tag-'+size:'tui-tag'}} {{parse.getClassName(shape,plain)}} {{parse.getTypeClass(type,plain)}}" bindtap="handleClick" wx:if="{{visible}}">
+  <slot></slot>
+</view>
+<wxs module="parse">
+  module.exports = {
+    getTypeClass: function(type, plain) {
+      return plain ? 'tui-' + type + '-outline' : 'tui-' + type
+    },
+    getClassName: function(shape, plain) {
+      //circle, square,circleLeft,circleRight
+      var className = plain ? 'tui-tag-outline ' : '';
+      if (shape != 'square') {
+        if (shape == "circle") {
+          className = className + (plain ? 'tui-tag-outline-fillet' : 'tui-tag-fillet');
+        } else if (shape == "circleLeft") {
+          className = className + 'tui-tag-fillet-left';
+        } else if (shape == "circleRight") {
+          className = className + 'tui-tag-fillet-right';
+        }
+      }
+      return className;
+    }
+  }
+</wxs>

+ 266 - 0
components/tag/tag.wxss

@@ -0,0 +1,266 @@
+/* color start*/
+
+.tui-primary {
+  background: #5677fc !important;
+  color: #fff;
+}
+
+.tui-light-primary {
+  background: #5c8dff !important;
+  color: #fff;
+}
+
+.tui-dark-primary {
+  background: #4a67d6 !important;
+  color: #fff;
+}
+
+.tui-dLight-primary {
+  background: #4e77d9 !important;
+  color: #fff;
+}
+
+.tui-danger {
+  background: #ed3f14 !important;
+  color: #fff;
+}
+
+.tui-red {
+  background: #ff201f !important;
+  color: #fff;
+}
+
+.tui-warning {
+  background: #ff7900 !important;
+  color: #fff;
+}
+
+.tui-green {
+  background: #19be6b !important;
+  color: #fff;
+}
+
+.tui-high-green {
+  background: #52dcae !important;
+  color: #52dcae;
+}
+
+.tui-black {
+  background: #000 !important;
+  color: #fff;
+}
+
+.tui-white {
+  background: #fff !important;
+  color: #333 !important;
+}
+
+.tui-translucent {
+  background: rgba(0, 0, 0, 0.7);
+}
+
+.tui-light-black {
+  background: #333 !important;
+}
+
+.tui-gray {
+  background: #ededed !important;
+}
+
+.tui-phcolor-gray {
+  background: #ccc !important;
+}
+
+.tui-divider-gray {
+  background: #eaeef1 !important;
+}
+
+.tui-btn-gray {
+  background: #ededed !important;
+  color: #999 !important;
+}
+
+.tui-hover-gray {
+  background: #f7f7f9 !important;
+}
+
+.tui-bg-gray {
+  background: #fafafa !important;
+}
+
+.tui-light-blue {
+  background: #ecf6fd;
+  color: #4dabeb !important;
+}
+
+.tui-light-brownish {
+  background: #fcebef;
+  color: #8a5966 !important;
+}
+
+.tui-light-orange {
+  background: #fef5eb;
+  color: #faa851 !important;
+}
+
+.tui-light-green {
+  background: #e8f6e8;
+  color: #44cf85 !important;
+}
+
+.tui-primary-outline::after {
+  border: 1px solid #5677fc !important;
+}
+
+.tui-primary-outline {
+  color: #5677fc !important;
+  background: none;
+}
+
+.tui-danger-outline {
+  color: #ed3f14 !important;
+  background: none;
+}
+
+.tui-danger-outline::after {
+  border: 1px solid #ed3f14 !important;
+}
+
+.tui-red-outline {
+  color: #ff201f !important;
+  background: none;
+}
+
+.tui-red-outline::after {
+  border: 1px solid #ff201f !important;
+}
+
+.tui-warning-outline {
+  color: #ff7900 !important;
+  background: none;
+}
+
+.tui-warning-outline::after {
+  border: 1px solid #ff7900 !important;
+}
+
+.tui-green-outline {
+  color: #44cf85 !important;
+  background: none;
+}
+
+.tui-green-outline::after {
+  border: 1px solid #44cf85 !important;
+}
+
+.tui-high-green-outline {
+  color: #52dcae !important;
+  background: none;
+}
+
+.tui-high-green-outline::after {
+  border: 1px solid #52dcae !important;
+}
+
+.tui-gray-outline {
+  color: #999 !important;
+  background: none;
+}
+
+.tui-gray-outline::after {
+  border: 1px solid #ccc !important;
+}
+
+
+.tui-black-outline {
+  color: #333 !important;
+  background: none;
+}
+
+.tui-black-outline::after {
+  border: 1px solid #333 !important;
+}
+
+.tui-white-outline {
+  color: #fff !important;
+  background: none;
+}
+
+.tui-white-outline::after {
+  border: 1px solid #fff !important;
+}
+
+/* color end*/
+
+/* tag start*/
+
+.tui-tag {
+  padding: 16rpx 26rpx;
+  font-size: 28rpx;
+  border-radius: 6rpx;
+  /* display: inline-block;
+  vertical-align: middle; */
+  line-height: 28rpx;
+}
+
+.tui-tag-small {
+  padding: 10rpx 16rpx;
+  font-size: 24rpx;
+  border-radius: 6rpx;
+  /* display: inline-block;
+  vertical-align: middle; */
+  line-height: 24rpx;
+}
+
+.tui-tag-outline {
+  position: relative;
+  background: none;
+  color: #5677fc;
+}
+
+.tui-tag-outline::after {
+  content: "";
+  position: absolute;
+  width: 200%;
+  height: 200%;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scale(0.5, 0.5);
+  transform: scale(0.5, 0.5);
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+  left: 0;
+  top: 0;
+  border-radius: 80rpx;
+  border: 1px solid #5677fc;
+}
+
+.tui-tag-fillet {
+  border-radius: 50rpx;
+}
+
+.tui-white.tui-tag-fillet::after {
+  border-radius: 80rpx;
+}
+
+.tui-tag-outline-fillet::after {
+  border-radius: 80rpx;
+}
+
+.tui-tag-fillet-left {
+  border-radius: 50rpx 0 0 50rpx;
+}
+
+.tui-tag-fillet-right {
+  border-radius: 0 50rpx 50rpx 0;
+}
+
+.tui-tag-fillet-left.tui-tag-outline::after {
+  border-radius: 100rpx 0 0 100rpx;
+}
+
+.tui-tag-fillet-right.tui-tag-outline::after {
+  border-radius: 0 100rpx 100rpx 0;
+}
+
+/* tag end*/

+ 565 - 0
components/timePicker/timePicker.js

@@ -0,0 +1,565 @@
+Component({
+  /**
+   * 组件的属性列表
+   */
+  properties: {
+    pickerShow: {
+      type: Boolean,
+      observer:function(val){   //弹出动画
+        // console.log(this.data);
+        if(val){
+          let animation = wx.createAnimation({
+            duration: 500,
+            timingFunction: "ease"
+          });
+          let animationOpacity = wx.createAnimation({
+            duration: 500,
+            timingFunction: "ease"
+          });
+          setTimeout(() => {
+            animation.bottom(0).step();
+            animationOpacity.opacity(0.7).step();
+            this.setData({
+              animationOpacity: animationOpacity.export(),
+              animationData: animation.export()
+            })
+          }, 0);
+        }else{
+          let animation = wx.createAnimation({
+            duration: 100,
+            timingFunction: "ease"
+          });
+          let animationOpacity = wx.createAnimation({
+            duration: 500,
+            timingFunction: "ease"
+          });
+          animation.bottom(-320).step();
+          animationOpacity.opacity(0).step();
+          this.setData({
+            animationOpacity: animationOpacity.export(),
+            animationData: animation.export()
+          });
+        }
+
+        // 在picker滚动未停止前点确定,会使startValue数组各项归零,发生错误,这里判断并重新初始化
+        // 微信新增了picker滚动的回调函数,已进行兼容
+        if(this.data.startValue&&this.data.endValue){
+          let s = 0, e = 0;
+          let conf = this.data.config;
+          
+          this.data.startValue.map(val => {
+            if (val == 0) {
+              s++
+            }
+          })
+          this.data.endValue.map(val => {
+            if (val == 0) {
+              e++;
+            }
+          });
+          let tmp={
+            hour:4,
+            minute:5,
+            second:6
+          }
+          let n = tmp[conf.column];
+          if (s>=n || e>=n) {
+            this.initPick(this.data.config);
+            this.setData({
+              startValue: this.data.startValue,
+              endValue: this.data.endValue,
+            });
+          }
+        }
+        
+
+      }
+    },
+    config: Object
+  },
+
+  /**
+   * 组件的初始数据
+   */
+  data: {
+    // pickerShow:true
+    // limitStartTime: new Date().getTime()-1000*60*60*24*30,
+    // limitEndTime: new Date().getTime(),
+    // yearStart:2000,
+    // yearEnd:2100
+  },
+  detached: function() {
+    console.log("dele");
+  },
+  attached: function() {},
+  ready: function() {
+    this.readConfig();
+    this.initPick(this.data.config || null);
+    this.setData({
+      startValue: this.data.startValue,
+      endValue: this.data.endValue,
+    });
+
+
+    
+    
+  },
+  /**
+   * 组件的方法列表
+   */
+  methods: {
+    //阻止滑动事件
+    onCatchTouchMove(e) {
+
+    },
+    //读取配置项
+    readConfig() {
+      let limitEndTime = new Date().getTime();
+      let limitStartTime = new Date().getTime() - 1000 * 60 * 60 * 24 * 30;
+      if (this.data.config) {
+        let conf = this.data.config;
+        
+        if (typeof conf.dateLimit == "number") {
+          limitStartTime =
+            new Date().getTime() - 1000 * 60 * 60 * 24 * conf.dateLimit;
+        }
+        if(conf.limitStartTime){
+          
+          limitStartTime = new Date(conf.limitStartTime.replace(/-/g,'/')).getTime();
+        }
+        
+        if (conf.limitEndTime) {
+          limitEndTime = new Date(conf.limitEndTime.replace(/-/g, '/')).getTime();
+        }
+        
+        this.setData({
+          yearStart: conf.yearStart || 2000,
+          yearEnd: conf.yearEnd || 2100,
+          endDate: conf.endDate || false,
+          dateLimit: conf.dateLimit || false,
+          hourColumn:
+            conf.column == "hour" ||
+            conf.column == "minute" ||
+            conf.column == "second",
+          minColumn: conf.column == "minute" || conf.column == "second",
+          secColumn: conf.column == "second"
+        });
+      }
+
+      let limitStartTimeArr = formatTime(limitStartTime);
+      let limitEndTimeArr = formatTime(limitEndTime);
+      
+      this.setData({
+        limitStartTime,
+        limitStartTimeArr,
+        limitEndTime,
+        limitEndTimeArr
+      });
+    },
+    //滚动开始
+    handlePickStart:function(e){
+      this.setData({
+        isPicking:true
+      })
+    },
+    //滚动结束
+    handlePickEnd:function(e){
+      this.setData({
+        isPicking:false
+      })
+    },
+    onConfirm: function() {
+      //滚动未结束时不能确认
+      if(this.data.isPicking){return}
+      let startTime = new Date(this.data.startPickTime.replace(/-/g, "/"));
+      let endTime = new Date(this.data.endPickTime.replace(/-/g, "/"));
+      if (startTime <= endTime || !this.data.endDate) {
+        this.setData({
+          startTime,
+          endTime
+        });
+        let startArr = formatTime(startTime).arr;
+        let endArr = formatTime(endTime).arr;
+        let format0 = function(num){
+          return num<10?'0'+num:num
+        }
+        
+        let startTimeBack =
+          startArr[0] +
+          "-" +
+          format0(startArr[1]) +
+          "-" +
+          format0(startArr[2]) +
+          " " +
+          (this.data.hourColumn ? format0(startArr[3]) : "00") +
+          ":" +
+          (this.data.minColumn ? format0(startArr[4]) : "00") +
+          ":" +
+          (this.data.secColumn ? format0(startArr[5]) : "00");
+
+        let endTimeBack =
+          endArr[0] +
+          "-" +
+          format0(endArr[1]) +
+          "-" +
+          format0(endArr[2]) +
+          " " +
+          (this.data.hourColumn ? format0(endArr[3]) : "00") +
+          ":" +
+          (this.data.minColumn ? format0(endArr[4]) : "00") +
+          ":" +
+          (this.data.secColumn ? format0(endArr[5]) : "00");
+
+        let time = {
+          startTime: startTimeBack,
+          endTime: endTimeBack
+        };
+
+        //触发自定义事件
+        this.triggerEvent("setPickerTime", time);
+        this.triggerEvent("hidePicker", {});
+      } else {
+        wx.showToast({
+          icon: "none",
+          title: "时间不合理"
+        });
+      }
+    },
+    hideModal: function() {
+      
+      this.triggerEvent("hidePicker", {});
+    },
+    changeStartDateTime: function(e) {
+      let val = e.detail.value;
+      
+      this.compareTime(val, "start");
+    },
+
+    changeEndDateTime: function(e) {
+      let val = e.detail.value;
+      this.compareTime(val, "end");
+    },
+    //比较时间是否在范围内
+    compareTime(val, type) {
+      let h = val[3] ? this.data.HourList[val[3]] : "00";
+      let m = val[4] ? this.data.MinuteList[val[4]] : "00";
+      let s = val[5] ? this.data.SecondList[val[5]] : "00";
+      let time =
+        this.data.YearList[val[0]] +
+        "-" +
+        this.data.MonthList[val[1]] +
+        "-" +
+        this.data.DayList[val[2]] +
+        " " +
+        h +
+        ":" +
+        m +
+        ":" +
+        s;
+
+      let start = this.data.limitStartTime;
+      let end = this.data.limitEndTime;
+      let timeNum = new Date(time.replace(/-/g, '/')).getTime();
+      let year, month, day, hour, min, sec, limitDate;
+      let tempArr = []
+
+      if (!this.data.dateLimit){
+        limitDate = [
+          this.data.YearList[val[0]],
+          this.data.MonthList[val[1]],
+          this.data.DayList[val[2]],
+          this.data.HourList[val[3]],
+          this.data.MinuteList[val[4]],
+          this.data.SecondList[val[5]]]
+      } else if (type == "start" && timeNum > new Date(this.data.endPickTime.replace(/-/g, '/')) && this.data.config.endDate) {
+        limitDate = formatTime(this.data.endPickTime).arr;
+        
+      } else if (type == "end" && timeNum < new Date(this.data.startPickTime.replace(/-/g, '/'))) {
+        limitDate = formatTime(this.data.startPickTime).arr;
+        
+      } else if (timeNum < start) {
+        limitDate = this.data.limitStartTimeArr.arr;
+
+      } else if (timeNum > end) {
+        limitDate = this.data.limitEndTimeArr.arr;
+        
+      } else {
+        limitDate = [
+          this.data.YearList[val[0]],
+        this.data.MonthList[val[1]],
+        this.data.DayList[val[2]],
+        this.data.HourList[val[3]],
+        this.data.MinuteList[val[4]],
+       this.data.SecondList[val[5]]
+        ]
+        
+      }
+
+      year = limitDate[0];
+      month = limitDate[1];
+      day = limitDate[2];
+      hour = limitDate[3];
+      min = limitDate[4];
+      sec = limitDate[5];
+
+      if (type == "start") {
+        this.setStartDate(year, month, day, hour, min, sec);
+      } else if (type == "end") {
+        this.setEndDate(year, month, day, hour, min, sec);
+      }
+    },
+    getDays: function(year, month) {
+      let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+      if (month === 2) {
+        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
+          ? 29
+          : 28;
+      } else {
+        return daysInMonth[month - 1];
+      }
+    },
+    initPick: function(initData) {
+      const date = initData.initStartTime ? new Date(initData.initStartTime.replace(/-/g, '/')): new Date();
+      const endDate = initData.initEndTime ? new Date(initData.initEndTime.replace(/-/g, '/')) : new Date();
+      // const startDate = new Date(date.getTime() - 1000 * 60 * 60 * 24);
+      const startDate = date;
+      const startYear = date.getFullYear();
+      const startMonth = date.getMonth() + 1;
+      const startDay = date.getDate();
+      const startHour = date.getHours();
+      const startMinute = date.getMinutes();
+      const startSecond = date.getSeconds();
+
+      const endYear = endDate.getFullYear();
+      const endMonth = endDate.getMonth() + 1;
+      const endDay = endDate.getDate();
+      const endHour = endDate.getHours();
+      const endMinute = endDate.getMinutes();
+      const endSecond = endDate.getSeconds();
+
+      let YearList = [];
+      let MonthList = [];
+      let DayList = [];
+      let HourList = [];
+      let MinuteList = [];
+      let SecondList = [];
+
+      //设置年份列表
+      for (let i = this.data.yearStart; i <= this.data.yearEnd; i++) {
+        YearList.push(i);
+      }
+
+      // 设置月份列表
+      for (let i = 1; i <= 12; i++) {
+        MonthList.push(i);
+      }
+      // 设置日期列表
+      for (let i = 1; i <= 31; i++) {
+        DayList.push(i);
+      }
+      // 设置时列表
+      for (let i = 0; i <= 23; i++) {
+        if (0 <= i && i < 10) {
+          i = "0" + i;
+        }
+        HourList.push(i);
+      }
+      // 分|秒
+      for (let i = 0; i <= 59; i++) {
+        if (0 <= i && i < 10) {
+          i = "0" + i;
+        }
+        MinuteList.push(i);
+        SecondList.push(i);
+      }
+
+      this.setData({
+        YearList,
+        MonthList,
+        DayList,
+        HourList,
+        MinuteList,
+        SecondList
+      });
+
+      this.setStartDate(startYear, startMonth, startDay, startHour, startMinute, startSecond);
+      this.setEndDate(endYear, endMonth, endDay, endHour, endMinute, endSecond);
+
+      //!!!
+      // setTimeout(() => {
+      //   this.setStartDate(nowYear, nowMonth, nowDay, nowHour, nowMinute)
+      //   this.setEndDate(nowYear, nowMonth, nowDay, nowHour, nowMinute)
+      // }, 0);
+    },
+    setPickerDateArr(type, year, month, day, hour, minute, second) {
+      let yearIdx = 0;
+      let monthIdx = 0;
+      let dayIdx = 0;
+      let hourIdx = 0;
+      let minuteIdx = 0;
+      let secondIdx = 0;
+
+      this.data.YearList.map((v, idx) => {
+        if (parseInt(v) === year) {
+          yearIdx = idx;
+        }
+      });
+
+      this.data.MonthList.map((v, idx) => {
+        if (parseInt(v) === month) {
+          monthIdx = idx;
+        }
+      });
+
+      // 重新设置日期列表
+      let DayList = [];
+      for (let i = 1; i <= this.getDays(year, month); i++) {
+        DayList.push(i);
+      }
+
+      DayList.map((v, idx) => {
+        if (parseInt(v) === day) {
+          dayIdx = idx;
+        }
+      });
+      if (type == "start") {
+        this.setData({ startDayList: DayList });
+      } else if (type == "end") {
+        this.setData({ endDayList: DayList });
+      }
+
+      this.data.HourList.map((v, idx) => {
+        if (parseInt(v) === parseInt(hour)) {
+          hourIdx = idx;
+        }
+      });
+
+      this.data.MinuteList.map((v, idx) => {
+        if (parseInt(v) === parseInt(minute)) {
+          minuteIdx = idx;
+        }
+      });
+      this.data.SecondList.map((v, idx) => {
+        if (parseInt(v) === parseInt(second)) {
+          secondIdx = idx;
+        }
+      });
+
+      return {
+        yearIdx,
+        monthIdx,
+        dayIdx,
+        hourIdx,
+        minuteIdx,
+        secondIdx
+      };
+    },
+    setStartDate: function(year, month, day, hour, minute, second) {
+      let pickerDateArr = this.setPickerDateArr(
+        "start",
+        year,
+        month,
+        day,
+        hour,
+        minute,
+        second
+      );
+      this.setData({
+        startYearList: this.data.YearList,
+        startMonthList: this.data.MonthList,
+        // startDayList: this.data.DayList,
+        startHourList: this.data.HourList,
+        startMinuteList: this.data.MinuteList,
+        startSecondList: this.data.SecondList,
+        startValue: [
+          pickerDateArr.yearIdx,
+          pickerDateArr.monthIdx,
+          pickerDateArr.dayIdx,
+          pickerDateArr.hourIdx,
+          pickerDateArr.minuteIdx,
+          pickerDateArr.secondIdx
+        ],
+        startPickTime:
+          this.data.YearList[pickerDateArr.yearIdx] +
+          "-" +
+          this.data.MonthList[pickerDateArr.monthIdx] +
+          "-" +
+          this.data.DayList[pickerDateArr.dayIdx] +
+          " " +
+          this.data.HourList[pickerDateArr.hourIdx] +
+          ":" +
+          this.data.MinuteList[pickerDateArr.minuteIdx] +
+          ":" +
+          this.data.SecondList[pickerDateArr.secondIdx]
+      });
+    },
+    setEndDate: function(year, month, day, hour, minute, second) {
+      let pickerDateArr = this.setPickerDateArr(
+        "end",
+        year,
+        month,
+        day,
+        hour,
+        minute,
+        second
+      );
+
+      this.setData({
+        endYearList: this.data.YearList,
+        endMonthList: this.data.MonthList,
+        // endDayList: this.data.DayList,
+        endHourList: this.data.HourList,
+        endMinuteList: this.data.MinuteList,
+        endSecondList: this.data.SecondList,
+        endValue: [
+          pickerDateArr.yearIdx,
+          pickerDateArr.monthIdx,
+          pickerDateArr.dayIdx,
+          pickerDateArr.hourIdx,
+          pickerDateArr.minuteIdx,
+          pickerDateArr.secondIdx
+        ],
+        endPickTime:
+          this.data.YearList[pickerDateArr.yearIdx] +
+          "-" +
+          this.data.MonthList[pickerDateArr.monthIdx] +
+          "-" +
+          this.data.DayList[pickerDateArr.dayIdx] +
+          " " +
+          this.data.HourList[pickerDateArr.hourIdx] +
+          ":" +
+          this.data.MinuteList[pickerDateArr.minuteIdx] +
+          ":" +
+          this.data.SecondList[pickerDateArr.secondIdx]
+      });
+    },
+  }
+});
+
+
+function formatTime(date) {
+  
+  if (typeof date == 'string' || 'number') {
+    try {
+      date = date.replace(/-/g, '/')//兼容ios
+    } catch (error) {
+    }
+    date = new Date(date)
+  }
+
+  const year = date.getFullYear()
+  const month = date.getMonth() + 1
+  const day = date.getDate()
+  const hour = date.getHours()
+  const minute = date.getMinutes()
+  const second = date.getSeconds()
+  
+  return {
+    str: [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':'),
+    arr: [year, month, day, hour, minute, second]
+  }
+}
+function formatNumber(n) {
+  n = n.toString()
+  return n[1] ? n : '0' + n
+}

+ 4 - 0
components/timePicker/timePicker.json

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

+ 68 - 0
components/timePicker/timePicker.wxml

@@ -0,0 +1,68 @@
+<!--components/timePicker/timePicker.wxml-->
+<!-- 自定义时间筛选器 -->
+<view hidden="{{!pickerShow}}">
+  <view class="picker-container {{pickerShow?'show_picker':'hide_picker'}}" animation="{{animationData}}">
+
+    <view class="btn-box" catchtouchmove="onCatchTouchMove">
+      <view class="pick_btn" bindtap="hideModal">取消</view>
+      <view class='pick_btn' style="color: #19f" bindtap="onConfirm">确定</view>
+    </view>
+
+    <view>
+      <picker-view class='sensorTypePicker' indicator-style='height: 35px;' bindchange="changeStartDateTime"
+        value="{{startValue}}" style="height: {{endDate?'120px':'250px'}};" bindpickstart="handlePickStart" bindpickend="handlePickEnd">
+        <picker-view-column style="min-width: 70px;flex-shrink: 0">
+          <view class='picker-item' wx:for="{{startYearList}}" wx:key='*this'>{{item}}年</view>
+        </picker-view-column>
+        <picker-view-column>
+          <view class='picker-item' wx:for="{{startMonthList}}" wx:key='*this'>{{item}}月</view>
+        </picker-view-column>
+        <picker-view-column>
+          <view class='picker-item' wx:for="{{startDayList}}" wx:key='*this'>{{item}}日</view>
+        </picker-view-column>
+        <picker-view-column hidden="{{!hourColumn}}">
+          <view class='picker-item' wx:for="{{startHourList}}" wx:key='*this'>{{item}}时</view>
+        </picker-view-column>
+        <picker-view-column hidden="{{!minColumn}}">
+          <view class='picker-item' wx:for="{{startMinuteList}}" wx:key='*this'>{{item}}分</view>
+        </picker-view-column>
+        <picker-view-column hidden="{{!secColumn}}">
+          <view class='picker-item' wx:for="{{startSecondList}}" wx:key='*this'>{{item}}秒</view>
+        </picker-view-column>
+      </picker-view>
+    </view>
+
+    <view wx:if="{{endDate}}">
+      <view class='to' style='margin-top: 4px;margin-bottom: 4px;'>至</view>
+        <picker-view class='sensorTypePicker' indicator-style='height: 35px;' bindchange="changeEndDateTime" bindpickstart="handlePickStart" bindpickend="handlePickEnd" 
+          value="{{endValue}}">
+          <picker-view-column style="min-width: 70px;flex-shrink: 0">
+            <view class='picker-item' wx:for="{{endYearList}}" wx:key='*this' style="min-width: 70px;">{{item}}年</view>
+          </picker-view-column>
+          <picker-view-column>
+            <view class='picker-item' wx:for="{{endMonthList}}" wx:key='*this'>{{item}}月</view>
+          </picker-view-column>
+          <picker-view-column>
+            <view class='picker-item' wx:for="{{endDayList}}" wx:key='*this'>{{item}}日</view>
+          </picker-view-column>
+          <picker-view-column hidden="{{!hourColumn}}" >
+            <view class='picker-item' wx:for="{{endHourList}}" wx:key='*this'>{{item}}时</view>
+          </picker-view-column>
+          <picker-view-column hidden="{{!minColumn}}">
+            <view class='picker-item' wx:for="{{endMinuteList}}" wx:key='*this'>{{item}}分</view>
+          </picker-view-column>
+          <picker-view-column hidden="{{!secColumn}}">
+            <view class='picker-item' wx:for="{{startSecondList}}" wx:key='*this'>{{item}}秒</view>
+          </picker-view-column>
+      
+      
+        </picker-view>
+    </view>
+    
+
+    <!-- <view class='sure' bindtap="onConfirm">确定</view> -->
+
+  </view>
+  <!-- 遮罩 -->
+  <view class="sensorType-screen" bindtap="hideModal" catchtouchmove="onCatchTouchMove" animation="{{animationOpacity}}"/>
+</view>

+ 96 - 0
components/timePicker/timePicker.wxss

@@ -0,0 +1,96 @@
+/* components/timePicker/timePicker.wxss */
+
+.picker-item{
+  line-height: 100rpx;  
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+/* 自定义时间 */
+.picker-container {
+  display: flex;
+  flex-direction: column;
+  /* justify-content: center; */
+  align-items: center;
+
+  width: 100%;
+  overflow: hidden;
+  position: fixed;
+  bottom: -640rpx;
+  left: 0;
+  /* height: 0; */
+  transition: height 0.5s;
+  z-index: 2000;
+  background: white;
+  border-top: 1px solid #EFEFF4;
+}
+.sensorType-screen{
+  width: 100vw;
+  /* height:400rpx; */
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  background: #000;
+  opacity: 0;
+  overflow: hidden;
+  z-index: 1999;
+  color: #fff;
+}
+.sensorTypePicker{
+  width: 690rpx;
+  height: 240rpx;
+  /* padding: 45px 0; */
+}
+.picker-item{
+  line-height: 100rpx;  
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  font-size: 32rpx;
+  /* overflow: hidden; */
+}
+.box{
+   padding: 0 20rpx; 
+}
+
+/* 至 */
+.to{
+  width:100%;
+  display: flex;
+  justify-content: center;align-items: center;
+  color:rgb(138,138,138);
+  /* font-size:30rpx; */
+}
+
+/* 确定 */
+.sure{
+  width:100%;
+  height:90rpx;
+  border-top: 2rpx solid #EFEFF4;
+  display: flex;justify-content: center;align-items: center;
+  color: rgb(36,123,255);
+  font-size:16px;
+}
+
+.btn-box{
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 2rpx solid #eee;
+}
+.pick_btn{
+  padding: 14rpx 30rpx;
+  color: #ccc;
+  /* background-color: #159; */
+}
+
+.show_picker{
+  /* height: 320px; */
+}
+.hide_picker{
+  /* height: 0; */
+}

+ 47 - 0
components/top-dropdown/top-dropdown.js

@@ -0,0 +1,47 @@
+// 顶部下拉列表
+Component({
+  externalClasses: ['tui-top-dropdown'],
+  properties: {
+    //是否需要mask
+    mask: {
+      type: Boolean,
+      value: true
+    },
+    //控制显示
+    show: {
+      type: Boolean,
+      value: false
+    },
+    //背景颜色
+    bgcolor: {
+      type: String,
+      value: "#f2f2f2"
+    },
+    //padding-bottom  rpx
+    paddingbtm: {
+      type: Number,
+      value: 0
+    },
+    //高度 rpx
+    height: {
+      type: Number,
+      value: 580
+    },
+    //移动距离 需要计算
+    translatey: {
+      type: Number,
+      value: 0
+    }
+  },
+  data: {
+
+  },
+  methods: {
+    handleClose() {
+      if (!this.data.show) {
+        return;
+      }
+      this.triggerEvent('close', {});
+    }
+  }
+})

+ 3 - 0
components/top-dropdown/top-dropdown.json

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

+ 4 - 0
components/top-dropdown/top-dropdown.wxml

@@ -0,0 +1,4 @@
+<view class="tui-top-dropdown tui-dropdown-box {{show?'tui-dropdown-show':''}}" style="height:{{height?height+'rpx':'auto'}}; background: {{bgcolor}};padding-bottom: {{paddingbtm}}rpx;transform: translateZ(0) translateY({{show?translatey+'rpx':'-100%'}});">
+  <slot></slot>
+</view>
+<view class="tui-dropdown-mask {{mask && show ?'tui-mask-show':''}}" bindtap="handleClose"></view>

+ 35 - 0
components/top-dropdown/top-dropdown.wxss

@@ -0,0 +1,35 @@
+.tui-dropdown-box {
+  width: 100%;
+  position: fixed;
+  box-sizing: border-box;
+  border-bottom-right-radius: 24rpx;
+  border-bottom-left-radius: 24rpx;
+  transform: translateZ(0);
+  overflow: hidden;
+  visibility: hidden;
+  transition: all 0.3s ease-in-out;
+  z-index: 998;
+  top:0;
+}
+
+.tui-dropdown-show {
+  visibility: visible;
+}
+
+.tui-dropdown-mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.6);
+  z-index: 996;
+  transition: all 0.3s ease-in-out;
+  opacity: 0;
+  visibility: hidden;
+}
+
+.tui-mask-show {
+  opacity: 1;
+  visibility: visible;
+}

+ 83 - 0
components/tui-tabbar/tui-tabbar.js

@@ -0,0 +1,83 @@
+Component({
+  properties: {
+    //当前索引
+    current: {
+      type: Number,
+      value: 0
+    },
+    //字体颜色
+    color: {
+      type: String,
+      value: "#666"
+    },
+    //字体选中颜色
+    selectedColor: {
+      type: String,
+      value: "#5677FC"
+    },
+    //背景颜色
+    backgroundColor: {
+      type: String,
+      value: "#FFFFFF"
+    },
+    //是否需要中间凸起按钮
+    hump: {
+      type: Boolean,
+      value: false
+    },
+    //固定在底部
+    isFixed: {
+      type: Boolean,
+      value: true
+    },
+    //tabbar
+    // "pagePath": "/pages/my/my", 页面路径
+    // "text": "thor", 标题
+    // "iconPath": "thor_gray.png", 图标地址
+    // "selectedIconPath": "thor_active.png", 选中图标地址
+    // "hump": true, 是否为凸起图标
+    // "num": 2,   角标数量
+    // "isDot": true,  角标是否为圆点
+    // "verify": true  是否验证  (如登录)
+    tabBar: {
+      type: Array,
+      value: []
+    },
+    //角标字体颜色
+    badgeColor: {
+      type: String,
+      value: "#fff"
+    },
+    //角标背景颜色
+    badgeBgColor: {
+      type: String,
+      value: "#F74D54"
+    },
+    unlined: {
+      type: Boolean,
+      value: false
+    }
+  },
+  data: {
+
+  },
+  methods: {
+    tabbarSwitch(e) {
+      let index = Number(e.currentTarget.dataset.index);
+      let hump = false;
+      let pagePath = "";
+      let verify = false
+      if (this.data.tabBar.length > 0) {
+        hump = this.data.tabBar[index].hump;
+        pagePath = this.data.tabBar[index].pagePath;
+        verify = this.data.tabBar[index].verify;
+      }
+      this.triggerEvent("click", {
+        index: index,
+        hump: hump,
+        pagePath: pagePath,
+        verify: verify
+      })
+    }
+  }
+})

+ 4 - 0
components/tui-tabbar/tui-tabbar.json

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

+ 12 - 0
components/tui-tabbar/tui-tabbar.wxml

@@ -0,0 +1,12 @@
+<view class="tui-tabbar {{isFixed?'tui-tabbar-fixed':''}} {{unlined?'tui-unlined':''}}" style="background:{{backgroundColor}}">
+  <block wx:for="{{tabBar}}" wx:key="{{index}}">
+    <view class="tui-tabbar-item {{item.hump?'tui-item-hump':''}}" style="background:{{item.hump?backgroundColor:'none'}}" bindtap="tabbarSwitch" data-index="{{index}}">
+      <view class="tui-icon-box {{item.hump?'tui-tabbar-hump':''}}">
+        <image src="{{current==index?item.selectedIconPath:item.iconPath}}" class="{{item.hump?'':'tui-tabbar-icon'}}"></image>
+        <view class="{{item.isDot?'tui-badge-dot':'tui-badge'}}" style="color:{{badgeColor}};background:{{badgeBgColor}}" wx:if="{{item.num>0}}">{{item.isDot?"":item.num}}</view>
+      </view>
+      <view class="tui-text-scale {{item.hump?'tui-text-hump':''}}" style="color:{{current==index?selectedColor:color}}">{{item.text}}</view>
+    </view>
+  </block>
+  <view class="{{hump?'tui-hump-box':''}}" wx:if="{{hump && !unlined}}"></view>
+</view>

+ 142 - 0
components/tui-tabbar/tui-tabbar.wxss

@@ -0,0 +1,142 @@
+.tui-tabbar {
+		width: 100%;
+		height: 100rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		position: relative;
+	}
+
+	.tui-tabbar-fixed {
+		position: fixed;
+		z-index: 99999;
+		left: 0;
+		bottom: 0;
+		padding-bottom: env(safe-area-inset-bottom);
+	}
+
+	.tui-tabbar::before {
+		content: '';
+		width: 100%;
+		border-top: 1rpx solid #B2B2B2;
+		position: absolute;
+		top: 0;
+		left: 0;
+		transform: scaleY(0.5);
+		transform-origin: 0 100%;
+	}
+
+	.tui-tabbar-item {
+		height: 100%;
+		flex: 1;
+		display: flex;
+		text-align: center;
+		align-items: center;
+		flex-direction: column;
+		justify-content: space-between;
+		position: relative;
+		padding: 10rpx 0;
+		box-sizing: border-box;
+
+	}
+
+	.tui-icon-box {
+		position: relative;
+	}
+
+	.tui-item-hump {
+		height: 98rpx;
+		z-index: 2;
+	}
+
+	.tui-tabbar-icon {
+		width: 52rpx;
+		height: 52rpx;
+		display: block;
+	}
+
+	.tui-hump-box {
+		width: 120rpx;
+		height: 120rpx;
+		background: #FFFFFF;
+		position: absolute;
+		left: 50%;
+		transform: translateX(-50%);
+		top: -50rpx;
+		border-radius: 50%;
+		z-index: 1;
+	}
+
+	.tui-hump-box::before {
+		content: '';
+		height: 200%;
+		width: 200%;
+		border: 1rpx solid #B2B2B2;
+		position: absolute;
+		top: 0;
+		left: 0;
+		transform: scale(0.5) translateZ(0);
+		transform-origin: 0 0;
+		border-radius: 100%;
+	}
+
+	.tui-unlined::before {
+		border: 0 !important
+	}
+
+	.tui-tabbar-hump {
+		width: 100rpx;
+		height: 100rpx;
+		position: absolute;
+		left: 50%;
+		transform: translateX(-50%) rotate(0deg);
+		top: -40rpx;
+		transition: all 0.2s linear;
+	}
+
+	.tui-tabbar-hump image {
+		width: 100rpx;
+		height: 100rpx;
+		display: block;
+	}
+
+	.tui-hump-active {
+		transform: translateX(-50%) rotate(135deg);
+	}
+
+	.tui-text-hump {
+		position: absolute;
+		bottom: 10rpx;
+	}
+
+	.tui-text-scale {
+		font-weight: bold;
+		transform: scale(0.8);
+		font-size: 25rpx;
+		line-height: 28rpx;
+		transform-origin: center 100%;
+	}
+
+	.tui-badge {
+		position: absolute;
+		font-size: 24rpx;
+		height: 32rpx;
+		min-width: 20rpx;
+		padding: 0 6rpx;
+		border-radius: 40rpx;
+		right: 0;
+		top: -5rpx;
+		transform: translateX(70%);
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.tui-badge-dot {
+		position: absolute;
+		height: 16rpx;
+		width: 16rpx;
+		border-radius: 50%;
+		right: -4rpx;
+		top: -4rpx;
+	}

+ 139 - 0
components/tui-tabs/tui-tabs.js

@@ -0,0 +1,139 @@
+Component({
+  properties: {
+    //标签页
+    tabs: {
+      type: Array,
+      value: []
+    },
+    //rpx
+    height: {
+      type: Number,
+      value: 80
+    },
+    //rpx 只对左右padding起作用,上下为0
+    padding: {
+      type: Number,
+      value: 30
+    },
+    //背景色
+    bgColor: {
+      type: String,
+      value: "#FFFFFF"
+    },
+    //是否固定
+    isFixed: {
+      type: Boolean,
+      value: false
+    },
+    //px
+    top: {
+      type: Number,
+      value: 0
+    },
+    //是否去掉底部线条
+    unlined: {
+      type: Boolean,
+      value: false
+    },
+    //当前选项卡
+    currentTab: {
+      type: Number,
+      value: 0,
+      observer(val) {
+        this.checkCor();
+      }
+    },
+    //滑块宽度
+    sliderWidth: {
+      type: Number,
+      value: 68
+    },
+    //滑块高度
+    sliderHeight: {
+      type: Number,
+      value: 6
+    },
+    //滑块背景颜色
+    sliderBgColor: {
+      type: String,
+      value: "#5677fc"
+    },
+    //滑块bottom
+    bottom: {
+      type: String,
+      value: "0"
+    },
+    //标签页宽度
+    itemWidth: {
+      type: String,
+      value: "25%"
+    },
+    //字体颜色
+    color: {
+      type: String,
+      value: "#666"
+    },
+    //选中后字体颜色
+    selectedColor: {
+      type: String,
+      value: "#5677fc"
+    },
+    //字体大小
+    size: {
+      type: Number,
+      value: 28
+    },
+    //选中后 是否加粗 ,未选中则无效
+    bold: {
+      type: Boolean,
+      value: false
+    }
+  },
+  lifetimes: {
+    ready: function() {
+      setTimeout(() => {
+        wx.getSystemInfo({
+          success: (res) => {
+            this.setData({
+              winWidth: res.windowWidth
+            }, () => {
+              this.checkCor()
+            })
+          }
+        });
+      }, 20);
+    }
+  },
+  data: {
+    winWidth: 0,
+    scrollLeft: 0
+  },
+  methods: {
+    checkCor: function() {
+      let tabsNum = this.data.tabs.length
+      let padding = this.data.winWidth / 750 * this.data.padding
+      let width = this.data.winWidth - padding * 2
+      let left = (width / tabsNum - (this.data.winWidth / 750 * this.data.sliderWidth)) / 2 + padding
+      let scrollLeft = left
+      if (this.data.currentTab > 0) {
+        scrollLeft = scrollLeft + (width / tabsNum) * this.data.currentTab
+      }
+      this.setData({
+        scrollLeft: scrollLeft
+      })
+    },
+    // 点击标题切换当前页时改变样式
+    swichTabs: function(e) {
+      let index = Number(e.currentTarget.dataset.index)
+      let item = this.data.tabs[index]
+      if (item && item.disabled) return;
+      if (this.data.currentTab == index) {
+        return false;
+      } else {
+        this.triggerEvent("change", {
+          index: Number(index)
+        })
+      }
+    }
+  }
+})

+ 4 - 0
components/tui-tabs/tui-tabs.json

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

+ 6 - 0
components/tui-tabs/tui-tabs.wxml

@@ -0,0 +1,6 @@
+<view class="tui-tabs-view {{isFixed?'tui-tabs-fixed':'tui-tabs-relative'}} {{unlined?'tui-unlined':''}}" style="height:{{height}}rpx;padding:0 {{padding}}rpx;background:{{bgColor}};top:{{isFixed?top+'px':'auto'}}">
+  <view wx:for="{{tabs}}" wx:key="{{index}}" class="tui-tabs-item" style="width:{{itemWidth}}" catchtap="swichTabs" data-index="{{index}}">
+    <view class="tui-tabs-title {{currentTab==index?'tui-tabs-active':''}} {{item.disabled?'tui-tabs-disabled':''}}" style="color:{{currentTab==index?selectedColor:color}};font-size:{{size}}rpx;line-height:{{size}}rpx;font-weight:{{(bold && currentTab==index)?'bold':'normal'}};">{{item.name}}</view>
+  </view>
+  <view class="tui-tabs-slider" style="transform:translateX({{scrollLeft}}px);width:{{sliderWidth}}rpx;height:{{sliderHeight}}rpx;bottom:{{bottom}};background:{{sliderBgColor}};margin-bottom:{{bottom=='50%'?('-'+sliderHeight/2+'rpx'):0}}"></view>
+</view>

+ 62 - 0
components/tui-tabs/tui-tabs.wxss

@@ -0,0 +1,62 @@
+.tui-tabs-view {
+		width: 100%;
+		box-sizing: border-box;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		z-index: 9999;
+	}
+
+	.tui-tabs-relative {
+		position: relative;
+	}
+
+	.tui-tabs-fixed {
+		position: fixed;
+		left: 0;
+	}
+
+	.tui-tabs-fixed::before,
+	.tui-tabs-relative::before {
+		content: '';
+		position: absolute;
+		-webkit-transform: scaleY(0.5);
+		transform: scaleY(0.5);
+		bottom: 0;
+		right: 0;
+		left: 0;
+	}
+
+	.tui-unlined::before {
+		border-bottom: 0 !important
+	}
+
+	.tui-tabs-item {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.tui-tabs-disabled {
+		opacity: .6;
+	}
+
+	.tui-tabs-title {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		position: relative;
+		z-index: 2;
+	}
+
+	.tui-tabs-active {
+		transition: all 0.15s ease-in-out;
+	}
+
+	.tui-tabs-slider {
+		border-radius: 40rpx;
+		position: absolute;
+		left: 0;
+		transition: all 0.15s ease-in-out;
+		z-index: 0;
+	}

+ 270 - 0
components/tui-upload/tui-upload.js

@@ -0,0 +1,270 @@
+Component({
+  properties: {
+    //初始化图片路径
+    value: {
+      type: Array,
+      value: [],
+      observer(val) {
+        this.initImages()
+      }
+    },
+    //禁用删除
+    forbidDel: {
+      type: Boolean,
+      value: false
+    },
+    //禁用添加
+    forbidAdd: {
+      type: Boolean,
+      value: false
+    },
+    //服务器地址
+    serverUrl: {
+      type: String,
+      value: ""
+    },
+    //限制数
+    limit: {
+      type: Number,
+      value: 9
+    },
+    //original 原图,compressed 压缩图,默认二者都有
+    sizeType: {
+      type: Array,
+      value:['original', 'compressed']
+    },
+    //album 从相册选图,camera 使用相机,默认二者都有。如需直接开相机或直接选相册,请只使用一个选项
+    sourceType: {
+      type: Array,
+      value:['album', 'camera']
+    },
+    //可上传图片类型,默认为空,不限制  Array<String> [jpg,png,gif]
+    imageFormat: {
+      type: Array,
+      value:[]
+    },
+    //单张图片大小限制 MB 
+    size: {
+      type: Number,
+      value: 4
+    },
+    //项目名,默认为 file
+    fileKeyName: {
+      type: String,
+      value: "file"
+    },
+    //HTTP 请求 Header, header 中不能设置 Referer。
+    header: {
+      type: Object,
+      value: {}
+    },
+    //HTTP 请求中其他额外的 form data
+    formData: {
+      type: Object,
+      value: {}
+    }
+  },
+  lifetimes: {
+    ready: function () {
+      this.initImages()
+    }
+  },
+  data: {
+    //图片地址
+    imageList: [],
+    //上传状态:1-上传成功 2-上传中 3-上传失败
+    statusArr: []
+  },
+
+  /**
+   * 组件的方法列表
+   */
+  methods: {
+    initImages() {
+      let imgArr = [...this.data.value]
+      let status = []
+      for (let item of imgArr) {
+        status.push("1")
+      }
+      this.setData({
+        imageList: [...imgArr],
+        statusArr: status
+      })
+    },
+    // 重新上传
+    reUpLoad(e) {
+      let index = Number(e.currentTarget.dataset.index)
+      let value = `statusArr[${index}]`
+      this.setData({
+        [value]: "2"
+      })
+      this.change()
+      this.uploadImage(index, this.data.imageList[index]).then(() => {
+        this.change()
+      }).catch(() => {
+        this.change()
+      })
+    },
+    change() {
+      let status = ~this.data.statusArr.indexOf("2") ? 2 : 1
+      if (status != 2 && ~this.data.statusArr.indexOf("3")) {
+        // 上传失败
+        status = 3
+      }
+      this.triggerEvent('complete', {
+        status: status,
+        imgArr: this.data.imageList
+      })
+    },
+    toast(text) {
+      text && wx.showToast({
+        title: text,
+        icon: "none"
+      });
+    },
+    chooseImage: function () {
+      let _this = this;
+      wx.chooseImage({
+        count: _this.data.limit - _this.data.imageList.length,
+        sizeType: _this.data.sizeType,
+				sourceType: _this.data.sourceType,
+        success: function (e) {
+          let imageArr = [];
+          let status = []
+          for (let i = 0; i < e.tempFiles.length; i++) {
+            let len = _this.data.imageList.length;
+            if (len >= _this.data.limit) {
+              _this.toast(`最多可上传${_this.data.limit}张图片`);
+              break;
+            }
+
+            //过滤图片类型
+							let path = e.tempFiles[i].path;
+
+							if (_this.data.imageFormat.length > 0) {
+								let format = path.split(".")[(path.split(".")).length - 1];
+								if (_this.data.imageFormat.indexOf(format) == -1) {
+									let text = `只能上传 ${_this.data.imageFormat.join(',')} 格式图片!`
+									_this.toast(text);
+									continue;
+								}
+							}
+
+							//过滤超出大小限制图片
+							let size = e.tempFiles[i].size;
+
+							if (_this.data.size * 1024 * 1024 < size){
+								let err=`单张图片大小不能超过:${_this.data.size}MB`
+								_this.toast(err);
+								continue;
+							}
+
+            imageArr.push(path)
+            status.push("2")
+          }
+          _this.setData({
+            imageList: _this.data.imageList.concat(imageArr),
+            statusArr: _this.data.statusArr.concat(status)
+          })
+          _this.change()
+
+          let start = _this.data.imageList.length - imageArr.length
+          for (let j = 0; j < imageArr.length; j++) {
+            let index = start + j
+            //服务器地址
+            if (_this.data.serverUrl) {
+              _this.uploadImage(index, imageArr[j]).then(() => {
+                _this.change()
+              }).catch(() => {
+                _this.change()
+              })
+            } else {
+              //无服务器地址则直接返回成功
+              let value = `statusArr[${index}]`
+              _this.setData({
+                [value]: "1"
+              })
+              _this.change()
+            }
+          }
+        }
+      })
+    },
+    uploadImage: function (index, url) {
+      let _this = this;
+      let status = `statusArr[${index}]`;
+      return new Promise((resolve, reject) => {
+        wx.uploadFile({
+          url: this.data.serverUrl,
+          name: this.data.fileKeyName,
+          header: this.data.header,
+          formData: this.data.formData,
+          filePath: url,
+          success: function (res) {
+            console.log(res)
+            if (res.statusCode == 200) {
+              //返回结果 此处需要按接口实际返回进行修改
+              let d = JSON.parse(res.data.replace(/\ufeff/g, "") || "{}")
+              //判断code,以实际接口规范判断
+              if (d.code % 100 === 0) {
+                // 上传成功 d.url 为上传后图片地址,以实际接口返回为准
+                if (d.url) {
+                  let value = `imageList[${index}]`
+                  _this.setData({
+                    [value]: d.url
+                  })
+                }
+                _this.setData({
+                  [status]: d.url ? "1" : "3"
+                })
+              } else {
+                // 上传失败
+                _this.setData({
+                  [status]: "3"
+                })
+              }
+              resolve(index)
+            } else {
+              _this.setData({
+                [status]: "3"
+              })
+              reject(index)
+            }
+          },
+          fail: function (res) {
+            _this.setData({
+              [status]: "3"
+            })
+            reject(index)
+          }
+        })
+      })
+
+    },
+    delImage: function (e) {
+      let index = Number(e.currentTarget.dataset.index)
+
+      let imgList = [...this.data.imageList]
+      let status = [...this.data.statusArr]
+      imgList.splice(index, 1)
+      status.splice(index, 1)
+      this.setData({
+        imageList: imgList,
+        statusArr: status
+      })
+      this.triggerEvent("remove", {
+        index: index
+      })
+      this.change()
+    },
+    previewImage: function (e) {
+      let index = Number(e.currentTarget.dataset.index)
+      if (!this.data.imageList.length) return;
+      wx.previewImage({
+        current: this.data.imageList[index],
+        loop: true,
+        urls: this.data.imageList
+      })
+    }
+  }
+})

+ 3 - 0
components/tui-upload/tui-upload.json

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

+ 16 - 0
components/tui-upload/tui-upload.wxml

@@ -0,0 +1,16 @@
+<view class="tui-container">
+  <view class="tui-upload-box">
+    <view class="tui-image-item" wx:for="{{imageList}}" wx:key="{{index}}">
+      <image src="{{item}}" class="tui-item-img" catchtap="previewImage" data-index="{{index}}" mode="aspectFill"></image>
+      <view wx:if="{{!forbidDel}}" class="tui-img-del" catchtap="delImage" data-index="{{index}}"></view>
+      <view wx:if="{{statusArr[index]!=1}}" class="tui-upload-mask">
+        <view class="tui-upload-loading" wx:if="{{statusArr[index]==2}}"></view>
+        <text class="tui-tips">{{statusArr[index]==2?'上传中...':'上传失败'}}</text>
+        <view class="tui-mask-btn" wx:if="{{statusArr[index]==3}}" catchtap="reUpLoad" data-index="{{index}}" hover-class="tui-hover" hover-stay-time="150">重新上传</view>
+      </view>
+    </view>
+    <view wx:if="{{!forbidAdd && imageList.length < limit}}" class="tui-upload-add" bindtap="chooseImage">
+      <view class="tui-upload-icon tui-icon-plus"></view>
+    </view>
+  </view>
+</view>

+ 137 - 0
components/tui-upload/tui-upload.wxss

@@ -0,0 +1,137 @@
+@font-face {
+  font-family: 'tuiUpload';
+  src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAATcAA0AAAAAByQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEwAAAABoAAAAciR52BUdERUYAAASgAAAAHgAAAB4AKQALT1MvMgAAAaAAAABCAAAAVjxvR/tjbWFwAAAB+AAAAEUAAAFK5ibpuGdhc3AAAASYAAAACAAAAAj//wADZ2x5ZgAAAkwAAADXAAABAAmNjcZoZWFkAAABMAAAAC8AAAA2FpiS+WhoZWEAAAFgAAAAHQAAACQH3QOFaG10eAAAAeQAAAARAAAAEgwAACBsb2NhAAACQAAAAAwAAAAMAEoAgG1heHAAAAGAAAAAHwAAACABEgA2bmFtZQAAAyQAAAFJAAACiCnmEVVwb3N0AAAEcAAAACgAAAA6OMUs4HjaY2BkYGAAYo3boY/i+W2+MnCzMIDAzb3qdQj6fwPzf+YGIJeDgQkkCgA/KAtvAHjaY2BkYGBu+N/AEMPCAALM/xkYGVABCwBZ4wNrAAAAeNpjYGRgYGBl0GJgZgABJiDmAkIGhv9gPgMADTABSQB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ9xMjf8b2CIYW5gaAAKM4LkANt9C+UAAHjaY2GAABYIVmBgAAAA+gAtAAAAeNpjYGBgZoBgGQZGBhBwAfIYwXwWBg0gzQakGRmYnjE+4/z/n4EBQksxSf6GqgcCRjYGOIeRCUgwMaACRoZhDwCiLwmoAAAAAAAAAAAAAAAASgCAeNpdjkFKw0AARf/vkIR0BkPayWRKQZtYY90ohJju2kOIbtz0KD1HVm50UfEmWXoAr9ADOHFARHHzeY//Fx8Ci+FJfIgdJFa4AhgiMshbrCuIsLxhFJZVs+Vl1bT1GddtbXTC3OhohN4dg4BJ3zMJAnccyfm468ZzHXddrH9ZKbHzdf9n/vkY/xv9sPQXgGEvBrHHwst5kTbXLE+YpYVPkxepPmW94W16UbdNJd6f3SAzo5W7m1jaKd+8ZZIvk5nlKw9SK6Wle7BLS3f/bTzQLmfAF2T1NsQAeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAOWMGiTIxMjMxsKak5qSWpbFmZiRmJ+QAmgAUIAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMABAABAAQAAAACAAAAAHjaY2BgYGQAgqtL1DlA9M296nUwGgA+8QYgAAA=) format('woff');
+  font-weight: normal;
+  font-style: normal;
+}
+
+.tui-upload-icon {
+  font-family: "tuiUpload" !important;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  padding: 10rpx;
+}
+
+.tui-icon-delete:before {
+  content: "\e601";
+}
+
+.tui-icon-plus:before {
+  content: "\e609";
+}
+
+.tui-upload-box {
+  width: 100%;
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.tui-upload-add {
+  width: 220rpx;
+  height: 220rpx;
+  font-size: 68rpx;
+  font-weight: 100;
+  color: #888;
+  background-color: #F7F7F7;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0;
+}
+
+.tui-image-item {
+  width: 220rpx;
+  height: 220rpx;
+  position: relative;
+  margin-right: 20rpx;
+  margin-bottom: 20rpx;
+}
+
+.tui-image-item:nth-of-type(3n) {
+  margin-right: 0;
+}
+
+.tui-item-img {
+  width: 220rpx;
+  height: 220rpx;
+  display: block;
+}
+
+.tui-img-del {
+  width: 36rpx;
+  height: 36rpx;
+  position: absolute;
+  right: -12rpx;
+  top: -12rpx;
+  background-color: #EB0909;
+  border-radius: 50%;
+  color: white;
+  font-size: 34rpx;
+  z-index: 999;
+}
+
+.tui-img-del::before {
+  content: '';
+  width: 16rpx;
+  height: 1px;
+  position: absolute;
+  left: 10rpx;
+  top: 18rpx;
+  background-color: #fff;
+}
+
+.tui-upload-mask {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  left: 0;
+  top: 0;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-around;
+  padding: 40rpx 0;
+  box-sizing: border-box;
+  background-color: rgba(0, 0, 0, 0.6);
+}
+
+.tui-upload-loading {
+  width: 28rpx;
+  height: 28rpx;
+  border-radius: 50%;
+  border: 2px solid;
+  border-color: #B2B2B2 #B2B2B2 #B2B2B2 #fff;
+  animation: tui-rotate 0.7s linear infinite;
+}
+
+@keyframes tui-rotate {
+  0% {
+    transform: rotate(0);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+.tui-tips {
+  font-size: 26rpx;
+  color: #fff;
+}
+
+.tui-mask-btn {
+  padding: 4rpx 16rpx;
+  border-radius: 40rpx;
+  text-align: center;
+  font-size: 24rpx;
+  color: #fff;
+  border: 1rpx solid #fff;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.tui-btn-hover {
+  opacity: 0.8;
+}

+ 38 - 0
custom-tab-bar/index.js

@@ -0,0 +1,38 @@
+Component({
+  data: {
+    current: 0,
+    list: [{
+        "pagePath": "/pages/index/index",
+        "text": "首页",
+        "iconPath": "/static/images/tabbar/btn_ico_home_nomal@2x.png",
+        "selectedIconPath": "/static/images/tabbar/btn_ico_home_pressed@2x.png"
+      },
+      {
+        "pagePath": "/pages/total/index",
+        "text": "统计",
+        "iconPath": "/static/images/tabbar/btn_ico_statistics_nomal@2x.png",
+        "selectedIconPath": "/static/images/tabbar/btn_ico_statistics_pressed@2x.png"
+      },
+      {
+        "pagePath": "/pages/mine/index",
+        "text": "我的",
+        "iconPath": "/static/images/tabbar/btn_ico_my_nomal@2x.png",
+        "selectedIconPath": "/static/images/tabbar/btn_ico_my_pressed@2x.png"
+      }
+    ]
+  },
+  attached() {},
+  methods: {
+    tabbarChange(e) {
+      console.log(e)
+      const idx = e.detail.index
+      const path = e.detail.pagePath
+      wx.switchTab({
+        url: path,
+      })
+      this.setData({
+        current: idx
+      })
+    }
+  }
+})

+ 6 - 0
custom-tab-bar/index.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "tui-tabbar": "../../components/tui-tabbar/tui-tabbar"
+  }
+}

+ 1 - 0
custom-tab-bar/index.wxml

@@ -0,0 +1 @@
+<tui-tabbar tabBar="{{list}}" isFixed="{{false}}" current="{{current}}" bind:click="tabbarChange"></tui-tabbar>

+ 64 - 0
custom-tab-bar/index.wxss

@@ -0,0 +1,64 @@
+.tab-bar {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  height: 150rpx;
+  background: white;
+  display: flex;
+  padding-bottom: env(safe-area-inset-bottom);
+  border-radius: 30rpx 30rpx 0 0;
+  border-top: 1px solid #eaeaea;
+  z-index: -1;
+}
+ 
+.tab-bar-item {
+  flex: 1;
+  text-align: center;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+}
+ 
+.tab-bar-item cover-image {
+  width: 27px;
+  height: 27px;
+}
+ 
+.tab-bar-item cover-view {
+  font-size: 10px;
+}
+.txt{
+  font-size: 40rpx;
+  color: #aaaaaa;
+}
+.fontWeight{
+  font-weight: bold;
+}
+.bg_rec{
+  background: #ffd324;
+  width: 80rpx;
+  min-height: auto;
+  height: 20rpx;
+  margin-top: -28rpx;
+  vertical-align: text-bottom;
+  border-radius: 0;
+  z-index: -10;
+}
+.center_img{
+  width: 120rpx;
+  height: 120rpx;
+  position: fixed;
+  transform: translate(-50%);
+  left: 50%;
+  bottom:0;
+}
+.center-has-noimg{
+  bottom: 26px;
+  z-index: 10;
+}
+.center-has-image{
+  bottom: 20px;
+  z-index: 11;
+}

+ 250 - 0
ec-canvas/ec-canvas.js

@@ -0,0 +1,250 @@
+import WxCanvas from './wx-canvas';
+import * as echarts from './echarts';
+
+let ctx;
+
+function compareVersion(v1, v2) {
+  v1 = v1.split('.')
+  v2 = v2.split('.')
+  const len = Math.max(v1.length, v2.length)
+
+  while (v1.length < len) {
+    v1.push('0')
+  }
+  while (v2.length < len) {
+    v2.push('0')
+  }
+
+  for (let i = 0; i < len; i++) {
+    const num1 = parseInt(v1[i])
+    const num2 = parseInt(v2[i])
+
+    if (num1 > num2) {
+      return 1
+    } else if (num1 < num2) {
+      return -1
+    }
+  }
+  return 0
+}
+
+Component({
+  properties: {
+    canvasId: {
+      type: String,
+      value: 'ec-canvas'
+    },
+
+    ec: {
+      type: Object
+    },
+
+    forceUseOldCanvas: {
+      type: Boolean,
+      value: false
+    }
+  },
+
+  data: {
+    isUseNewCanvas: false
+  },
+
+  ready: function () {
+    // Disable prograssive because drawImage doesn't support DOM as parameter
+    // See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
+    echarts.registerPreprocessor(option => {
+      if (option && option.series) {
+        if (option.series.length > 0) {
+          option.series.forEach(series => {
+            series.progressive = 0;
+          });
+        }
+        else if (typeof option.series === 'object') {
+          option.series.progressive = 0;
+        }
+      }
+    });
+
+    if (!this.data.ec) {
+      console.warn('组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" '
+        + 'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>');
+      return;
+    }
+
+    if (!this.data.ec.lazyLoad) {
+      this.init();
+    }
+  },
+
+  methods: {
+    init: function (callback) {
+      const version = wx.getSystemInfoSync().SDKVersion
+
+      const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0;
+      const forceUseOldCanvas = this.data.forceUseOldCanvas;
+      const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
+      this.setData({ isUseNewCanvas });
+
+      if (forceUseOldCanvas && canUseNewCanvas) {
+        console.warn('开发者强制使用旧canvas,建议关闭');
+      }
+
+      if (isUseNewCanvas) {
+        // console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
+        // 2.9.0 可以使用 <canvas type="2d"></canvas>
+        this.initByNewWay(callback);
+      } else {
+        const isValid = compareVersion(version, '1.9.91') >= 0
+        if (!isValid) {
+          console.error('微信基础库版本过低,需大于等于 1.9.91。'
+            + '参见:https://github.com/ecomfe/echarts-for-weixin'
+            + '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');
+          return;
+        } else {
+          console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能');
+          this.initByOldWay(callback);
+        }
+      }
+    },
+
+    initByOldWay(callback) {
+      // 1.9.91 <= version < 2.9.0:原来的方式初始化
+      ctx = wx.createCanvasContext(this.data.canvasId, this);
+      const canvas = new WxCanvas(ctx, this.data.canvasId, false);
+
+      echarts.setCanvasCreator(() => {
+        return canvas;
+      });
+      // const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
+      const canvasDpr = 1
+      var query = wx.createSelectorQuery().in(this);
+      query.select('.ec-canvas').boundingClientRect(res => {
+        if (typeof callback === 'function') {
+          this.chart = callback(canvas, res.width, res.height, canvasDpr);
+        }
+        else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
+          this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr);
+        }
+        else {
+          this.triggerEvent('init', {
+            canvas: canvas,
+            width: res.width,
+            height: res.height,
+            canvasDpr: canvasDpr // 增加了dpr,可方便外面echarts.init
+          });
+        }
+      }).exec();
+    },
+
+    initByNewWay(callback) {
+      // version >= 2.9.0:使用新的方式初始化
+      const query = wx.createSelectorQuery().in(this)
+      query
+        .select('.ec-canvas')
+        .fields({ node: true, size: true })
+        .exec(res => {
+          const canvasNode = res[0].node
+          this.canvasNode = canvasNode
+
+          const canvasDpr = wx.getSystemInfoSync().pixelRatio
+          const canvasWidth = res[0].width
+          const canvasHeight = res[0].height
+
+          const ctx = canvasNode.getContext('2d')
+
+          const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
+          echarts.setCanvasCreator(() => {
+            return canvas
+          })
+
+          if (typeof callback === 'function') {
+            this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)
+          } else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
+            this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr)
+          } else {
+            this.triggerEvent('init', {
+              canvas: canvas,
+              width: canvasWidth,
+              height: canvasHeight,
+              dpr: canvasDpr
+            })
+          }
+        })
+    },
+    canvasToTempFilePath(opt) {
+      if (this.data.isUseNewCanvas) {
+        // 新版
+        const query = wx.createSelectorQuery().in(this)
+        query
+          .select('.ec-canvas')
+          .fields({ node: true, size: true })
+          .exec(res => {
+            const canvasNode = res[0].node
+            opt.canvas = canvasNode
+            wx.canvasToTempFilePath(opt)
+          })
+      } else {
+        // 旧的
+        if (!opt.canvasId) {
+          opt.canvasId = this.data.canvasId;
+        }
+        ctx.draw(true, () => {
+          wx.canvasToTempFilePath(opt, this);
+        });
+      }
+    },
+
+    touchStart(e) {
+      if (this.chart && e.touches.length > 0) {
+        var touch = e.touches[0];
+        var handler = this.chart.getZr().handler;
+        handler.dispatch('mousedown', {
+          zrX: touch.x,
+          zrY: touch.y
+        });
+        handler.dispatch('mousemove', {
+          zrX: touch.x,
+          zrY: touch.y
+        });
+        handler.processGesture(wrapTouch(e), 'start');
+      }
+    },
+
+    touchMove(e) {
+      if (this.chart && e.touches.length > 0) {
+        var touch = e.touches[0];
+        var handler = this.chart.getZr().handler;
+        handler.dispatch('mousemove', {
+          zrX: touch.x,
+          zrY: touch.y
+        });
+        handler.processGesture(wrapTouch(e), 'change');
+      }
+    },
+
+    touchEnd(e) {
+      if (this.chart) {
+        const touch = e.changedTouches ? e.changedTouches[0] : {};
+        var handler = this.chart.getZr().handler;
+        handler.dispatch('mouseup', {
+          zrX: touch.x,
+          zrY: touch.y
+        });
+        handler.dispatch('click', {
+          zrX: touch.x,
+          zrY: touch.y
+        });
+        handler.processGesture(wrapTouch(e), 'end');
+      }
+    }
+  }
+});
+
+function wrapTouch(event) {
+  for (let i = 0; i < event.touches.length; ++i) {
+    const touch = event.touches[i];
+    touch.offsetX = touch.x;
+    touch.offsetY = touch.y;
+  }
+  return event;
+}

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä