scorpio 2 年之前
父節點
當前提交
34aa950203
共有 100 個文件被更改,包括 3738 次插入8 次删除
  1. 2 1
      package.json
  2. 3 2
      src/App.vue
  3. 80 0
      src/api/fetch.js
  4. 52 0
      src/api/index.js
  5. 12 1
      src/main.js
  6. 65 4
      src/pages.json
  7. 18 0
      src/pages/home/index.vue
  8. 10 0
      src/pages/index/index.vue
  9. 13 0
      src/pages/login/index.vue
  10. 13 0
      src/pages/register/index.vue
  11. 24 0
      src/pages/user/index.vue
  12. 二進制
      src/static/image/tab/tab1.png
  13. 二進制
      src/static/image/tab/tab1_on.png
  14. 二進制
      src/static/image/tab/tab2.png
  15. 二進制
      src/static/image/tab/tab2_on.png
  16. 二進制
      src/static/image/tab/tab3.png
  17. 二進制
      src/static/image/tab/tab3_on.png
  18. 二進制
      src/static/image/tab/tab4.png
  19. 二進制
      src/static/image/tab/tab4_on.png
  20. 二進制
      src/static/image/tab/tab5.png
  21. 二進制
      src/static/image/tab/tab5_on.png
  22. 449 0
      src/static/style/main.scss
  23. 11 0
      src/static/style/var.scss
  24. 362 0
      src/store/common.js
  25. 17 0
      src/store/getters.js
  26. 15 0
      src/store/index.js
  27. 13 0
      src/tenant/config.js
  28. 28 0
      src/utils/date.js
  29. 2 0
      src/utils/eventBus.js
  30. 27 0
      src/utils/regExp.js
  31. 360 0
      src/utils/uniApi.js
  32. 175 0
      src/utils/validate.js
  33. 13 0
      src/view/news-detail/index.vue
  34. 1 0
      src/wxcomponents/vant/action-sheet/index.d.ts
  35. 70 0
      src/wxcomponents/vant/action-sheet/index.js
  36. 8 0
      src/wxcomponents/vant/action-sheet/index.json
  37. 69 0
      src/wxcomponents/vant/action-sheet/index.wxml
  38. 1 0
      src/wxcomponents/vant/action-sheet/index.wxss
  39. 1 0
      src/wxcomponents/vant/area/index.d.ts
  40. 217 0
      src/wxcomponents/vant/area/index.js
  41. 6 0
      src/wxcomponents/vant/area/index.json
  42. 20 0
      src/wxcomponents/vant/area/index.wxml
  43. 8 0
      src/wxcomponents/vant/area/index.wxs
  44. 1 0
      src/wxcomponents/vant/area/index.wxss
  45. 1 0
      src/wxcomponents/vant/button/index.d.ts
  46. 64 0
      src/wxcomponents/vant/button/index.js
  47. 7 0
      src/wxcomponents/vant/button/index.json
  48. 53 0
      src/wxcomponents/vant/button/index.wxml
  49. 39 0
      src/wxcomponents/vant/button/index.wxs
  50. 0 0
      src/wxcomponents/vant/button/index.wxss
  51. 68 0
      src/wxcomponents/vant/calendar/calendar.wxml
  52. 1 0
      src/wxcomponents/vant/calendar/components/header/index.d.ts
  53. 37 0
      src/wxcomponents/vant/calendar/components/header/index.js
  54. 3 0
      src/wxcomponents/vant/calendar/components/header/index.json
  55. 16 0
      src/wxcomponents/vant/calendar/components/header/index.wxml
  56. 1 0
      src/wxcomponents/vant/calendar/components/header/index.wxss
  57. 6 0
      src/wxcomponents/vant/calendar/components/month/index.d.ts
  58. 154 0
      src/wxcomponents/vant/calendar/components/month/index.js
  59. 3 0
      src/wxcomponents/vant/calendar/components/month/index.json
  60. 39 0
      src/wxcomponents/vant/calendar/components/month/index.wxml
  61. 71 0
      src/wxcomponents/vant/calendar/components/month/index.wxs
  62. 0 0
      src/wxcomponents/vant/calendar/components/month/index.wxss
  63. 1 0
      src/wxcomponents/vant/calendar/index.d.ts
  64. 337 0
      src/wxcomponents/vant/calendar/index.js
  65. 10 0
      src/wxcomponents/vant/calendar/index.json
  66. 25 0
      src/wxcomponents/vant/calendar/index.wxml
  67. 37 0
      src/wxcomponents/vant/calendar/index.wxs
  68. 1 0
      src/wxcomponents/vant/calendar/index.wxss
  69. 12 0
      src/wxcomponents/vant/calendar/utils.d.ts
  70. 83 0
      src/wxcomponents/vant/calendar/utils.js
  71. 25 0
      src/wxcomponents/vant/calendar/utils.wxs
  72. 1 0
      src/wxcomponents/vant/card/index.d.ts
  73. 49 0
      src/wxcomponents/vant/card/index.js
  74. 6 0
      src/wxcomponents/vant/card/index.json
  75. 56 0
      src/wxcomponents/vant/card/index.wxml
  76. 1 0
      src/wxcomponents/vant/card/index.wxss
  77. 1 0
      src/wxcomponents/vant/cell-group/index.d.ts
  78. 11 0
      src/wxcomponents/vant/cell-group/index.js
  79. 3 0
      src/wxcomponents/vant/cell-group/index.json
  80. 11 0
      src/wxcomponents/vant/cell-group/index.wxml
  81. 1 0
      src/wxcomponents/vant/cell-group/index.wxss
  82. 1 0
      src/wxcomponents/vant/cell/index.d.ts
  83. 38 0
      src/wxcomponents/vant/cell/index.js
  84. 6 0
      src/wxcomponents/vant/cell/index.json
  85. 47 0
      src/wxcomponents/vant/cell/index.wxml
  86. 17 0
      src/wxcomponents/vant/cell/index.wxs
  87. 0 0
      src/wxcomponents/vant/cell/index.wxss
  88. 1 0
      src/wxcomponents/vant/checkbox-group/index.d.ts
  89. 36 0
      src/wxcomponents/vant/checkbox-group/index.js
  90. 3 0
      src/wxcomponents/vant/checkbox-group/index.json
  91. 5 0
      src/wxcomponents/vant/checkbox-group/index.wxml
  92. 1 0
      src/wxcomponents/vant/checkbox-group/index.wxss
  93. 1 0
      src/wxcomponents/vant/checkbox/index.d.ts
  94. 77 0
      src/wxcomponents/vant/checkbox/index.js
  95. 6 0
      src/wxcomponents/vant/checkbox/index.json
  96. 31 0
      src/wxcomponents/vant/checkbox/index.wxml
  97. 20 0
      src/wxcomponents/vant/checkbox/index.wxs
  98. 1 0
      src/wxcomponents/vant/checkbox/index.wxss
  99. 4 0
      src/wxcomponents/vant/circle/canvas.d.ts
  100. 43 0
      src/wxcomponents/vant/circle/canvas.js

+ 2 - 1
package.json

@@ -94,7 +94,8 @@
     "mini-types": "*",
     "miniprogram-api-typings": "*",
     "postcss-comment": "^2.0.0",
-    "vue-template-compiler": "^2.6.11"
+    "vue-template-compiler": "^2.6.11",
+    "node-sass": "^4.0.0"
   },
   "browserslist": [
     "Android >= 4.4",

+ 3 - 2
src/App.vue

@@ -12,6 +12,7 @@
 	}
 </script>
 
-<style>
+<style lang='scss'>
 	/*每个页面公共css */
-</style>
+  @import "./static/style/main.scss";
+</style>

+ 80 - 0
src/api/fetch.js

@@ -0,0 +1,80 @@
+import { toast, navigator, indicator, storage, modal } from '@/utils/uniApi'
+import tenant from '../tenant/config'
+import store from '../store'
+
+/* 本地模拟数据,上线要注释 */
+/* import mock from './mock'
+const debug = false */
+/* eslint-disable no-undef */
+const baseUrl = tenant.host
+const fetch = (url, data = {}, method = 'GET', type = 'form') => {
+  /* if (debug) {
+    let res = mock(url)
+    return new Promise((resolve, reject) => {
+      resolve(res)
+    })
+  } */
+	let {common} = store.state
+  method = method.toUpperCase()
+  const headers = {
+    Authorization: 'Basic c2FiZXI6c2FiZXJfc2VjcmV0',
+    Platform: common.platform + '/mp',
+    Device: common.device,
+    tag: 'ent',
+    tenantId: tenant.id,
+		'Blade-Auth': 'bearer ' + storage.get('token') || '',
+    'Content-Type': 'application/x-www-form-urlencoded'
+  }
+  if (type === 'json') {
+    headers['Content-Type'] = 'application/json'
+  }
+  return new Promise((resolve, reject) => {
+    uni.request({
+      url: baseUrl + url,
+      method,
+      data,
+      header: headers,
+      success: async (response) => {
+        if (response.statusCode >= 200 && response.statusCode < 400) {
+          if (response.data.code === 401) { // 未授权
+            // toast('请先登录')
+            modal({
+              content: '登录已过期,请重新登录',
+              confirmText: '去登录',
+              cancelText: '暂不登录',
+              success: (res) => {
+                if (res.confirm) {
+                  navigator.push('/pages/login/index')
+                }
+              }
+            })
+            indicator.close()
+            storage.clear()
+          } else {
+            resolve(response.data)
+          }
+          setTimeout(() => {
+            indicator.close()
+          }, 5000)
+        } else if (response.statusCode === 503) {
+          toast('操作太快,太频繁')
+        } else {
+          if (response.statusCode === 401) {
+            navigator.push('/pages/login/index')
+            storage.clear()
+          }else {
+            toast(response.data && response.data.msg ? response.data.msg : response.statusCode + '-' + '系统或网络错误')
+          }
+        }
+      },
+      fail: err => {
+        if (err.errMsg.indexOf('timeout') !== -1) {
+          toast('请求超时,请稍后重试')
+          return
+        }
+        reject(err)
+      }
+    })
+  })
+}
+export default fetch

+ 52 - 0
src/api/index.js

@@ -0,0 +1,52 @@
+import fetch from './fetch'
+import tenant from '../tenant/config.js'
+
+export default {
+	uploadPath: tenant.host + '/sys/attachment/upload', // 上传
+	commonApi: {
+		getBaseInfo() { // 获取用户基本信息
+			return fetch('/blade-user/info')
+		},
+		getOpenId(code) { // code换openid
+			return fetch('/api/blade-auth/oauth/info', {
+				code
+			})
+		},
+		wxLogin(params, grant_type = 'password') {
+			let data = {
+				scope: 'all',
+				tenantId: '000000',
+				grant_type: grant_type,
+				type: 'account',
+				...params
+			}
+			return fetch('/blade-auth/token', data, 'post', 'form')
+		}
+	},
+	// 公共参数接口
+	paramsApi: {
+		//
+		getServiceCentre (params) {
+			return fetch('/demobilized/siteinfo/list',params)
+		},
+		getOfficeCentre (params) {
+			return fetch('/demobilized/officeinfo/list',params)
+		},
+		//获取站点详细信息
+		getDetail(id){
+			return fetch('/demobilized/siteinfo/info/'+id)
+		},
+		//获取站点详细信息
+		officeDetail(id){
+			return fetch('/demobilized/officeinfo/info/'+id)
+		},
+		//获取地区列表
+		getRegion(id){
+			return fetch('/area/listbyPid/'+id)
+		},
+		posterDetail (id) {
+			return fetch('/demobilized/poster/info/' + id)
+		},
+
+	}
+}

+ 12 - 1
src/main.js

@@ -1,11 +1,22 @@
 import Vue from 'vue'
 import App from './App'
+import api from "@/api";
+import eventBus from "@/utils/eventBus";
+import {toast, indicator, modal, storage, navigator} from '@/utils/uniApi'
 
 Vue.config.productionTip = false
 
+Vue.prototype.$api= api
+Vue.prototype.$indicator = indicator
+Vue.prototype.$toast = toast
+Vue.prototype.$modal = modal
+Vue.prototype.$storage = storage
+Vue.prototype.$navigator = navigator
+Vue.prototype.$bus = eventBus
+
 App.mpType = 'app'
 
 const app = new Vue({
   ...App
 })
-app.$mount()
+app.$mount()

+ 65 - 4
src/pages.json

@@ -1,16 +1,77 @@
 {
-	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+	"pages": [
+		{
+			"path": "pages/home/index",
+			"style": {
+				"navigationBarTitleText": "首页"
+			}
+		},
 		{
 			"path": "pages/index/index",
 			"style": {
-				"navigationBarTitleText": "uni-app"
+				"navigationBarTitleText": "主页"
+			}
+		},
+		{
+			"path": "pages/user/index",
+			"style": {
+				"navigationBarTitleText": "个人中心"
 			}
 		}
 	],
+	"tabBar": {
+		"color": "#999",
+		"selectedColor": "#31d5a2",
+		"borderStyle": "black",
+		"backgroundColor": "#ffffff",
+		"list": [
+			{
+				"pagePath": "pages/home/index",
+				"text": "首页",
+				"iconPath": "/static/image/tab/tab1.png",
+				"selectedIconPath": "/static/image/tab/tab1_on.png"
+			},
+			{
+				"pagePath": "pages/user/index",
+				"text": "阳光公开",
+				"iconPath": "/static/image/tab/tab4.png",
+				"selectedIconPath": "/static/image/tab/tab4_on.png"
+			},
+			{
+				"pagePath": "pages/index/index",
+				"text": "党建",
+				"iconPath": "/static/image/tab/tab3.png",
+				"selectedIconPath": "/static/image/tab/tab3_on.png"
+			}
+		]
+	},
+	"subPackages": [
+		{
+			"root": "view",
+			"view": "view",
+			"pages": [
+				{
+					"path": "news-detail/index",
+					"style": {
+						"navigationBarTitleText": "详情"
+					}
+				}
+			]
+		}
+	],
 	"globalStyle": {
 		"navigationBarTextStyle": "black",
 		"navigationBarTitleText": "uni-app",
 		"navigationBarBackgroundColor": "#F8F8F8",
-		"backgroundColor": "#F8F8F8"
+		"backgroundColor": "#F8F8F8",
+		"usingComponents": {
+			"van-button": "/wxcomponents/vant/button/index",
+			"van-card": "/wxcomponents/vant/card/index",
+			"van-sidebar": "/wxcomponents/vant/sidebar/index",
+			"van-sidebar-item": "/wxcomponents/vant/sidebar-item/index",
+			"van-popup": "/wxcomponents/vant/popup/index",
+			"van-cell": "/wxcomponents/vant/cell/index",
+			"van-cell-group": "/wxcomponents/vant/cell-group/index"
+		}
 	}
-}
+}

+ 18 - 0
src/pages/home/index.vue

@@ -0,0 +1,18 @@
+<template>
+  <view>
+    <van-cell-group>
+      <van-cell title="单元格" value="内容" />
+      <van-cell title="单元格" value="内容" label="描述信息" />
+    </van-cell-group>
+  </view>
+</template>
+
+<script>
+export default {
+  name: "index.vue"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 10 - 0
src/pages/index/index.vue

@@ -3,6 +3,7 @@
 		<image class="logo" src="/static/logo.png"></image>
 		<view>
 			<text class="title">{{title}}</text>
+      <van-button type="info" @click='test'>默认按钮</van-button>
 		</view>
 	</view>
 </template>
@@ -18,7 +19,16 @@
 
 		},
 		methods: {
+      test(){
+        this.$toast('需要同意授权')
+        this.$api.commonApi.getBaseInfo().then(res => {
+          if (res.code === 200) {
+            console.log(res)
+          } else {
 
+          }
+        })
+      }
 		}
 	}
 </script>

+ 13 - 0
src/pages/login/index.vue

@@ -0,0 +1,13 @@
+<template>
+
+</template>
+
+<script>
+export default {
+  name: "index.vue"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 13 - 0
src/pages/register/index.vue

@@ -0,0 +1,13 @@
+<template>
+
+</template>
+
+<script>
+export default {
+  name: "index.vue"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 24 - 0
src/pages/user/index.vue

@@ -0,0 +1,24 @@
+<template>
+  <view>
+    <van-button type="default" @click='goDetail'>默认按钮</van-button>
+    <van-button type="primary">主要按钮</van-button>
+    <van-button type="info">信息按钮</van-button>
+    <van-button type="warning">警告按钮</van-button>
+    <van-button type="danger">危险按钮</van-button>
+  </view>
+</template>
+
+<script>
+export default {
+  name: "index.vue",
+  methods: {
+    goDetail() {
+      this.$navigator.push('/view/news-detail/index')
+    }
+  },
+}
+</script>
+
+<style scoped>
+
+</style>

二進制
src/static/image/tab/tab1.png


二進制
src/static/image/tab/tab1_on.png


二進制
src/static/image/tab/tab2.png


二進制
src/static/image/tab/tab2_on.png


二進制
src/static/image/tab/tab3.png


二進制
src/static/image/tab/tab3_on.png


二進制
src/static/image/tab/tab4.png


二進制
src/static/image/tab/tab4_on.png


二進制
src/static/image/tab/tab5.png


二進制
src/static/image/tab/tab5_on.png


+ 449 - 0
src/static/style/main.scss

@@ -0,0 +1,449 @@
+@import './var';
+page{font-size:14px;color: #333;}
+.main-color, a.main-color { color: $mainColor; } /*主色*/
+.main-bgcolor { background-color: $mainColor; }
+.assist-color, a.assist-color{color:$assistColor;} /*辅助色*/
+.assist-bgcolor { background-color: $assistColor; }
+.black, a.black { color: #333; }
+.black-bg { background-color: #333; }
+.grey, a.grey { color: #505050; }
+.grey-bg { background-color: #505050; }
+.grey-6, a.grey-6 { color: #6b6b6b; }
+.grey-6-bg { background-color: #6b6b6b; }
+.grey-9, a.grey-9 { color: $gray; }
+.grey-9-bg { background-color: $gray; }
+.grey-d, a.grey-d { color: #dfdfdf; }
+.grey-d-bg { background-color: #dfdfdf; }
+.grey-e, a.grey-e { color: #efefef; }
+.grey-e-bg { background-color: #efefef; }
+.grey-f, a.grey-f { color: #f5f5f5; }
+.grey-f-bg { background-color: #f5f5f5; }
+.white, a.white { color: #fff; }
+.white-bg { background-color: #fff; }
+.red, a.red { color: #f21c1c; }
+.red-bg { background-color: #f21c1c; }
+.light-red, a.light-red { color: #ff5050; }
+.light-red-bg { background-color: #ff5050; }
+.orange-red, a.orange-red { color: #ff4e00; }
+.orange-red-bg { background-color: #ff4e00; }
+.orange, a.orange { color: #ff6700; }
+.orange-bg { background-color: #ff6700; }
+.orange-yellow, a.orange-yellow { color: #fd9712; }
+.orange-yellow-bg { background-color: #fd9712; }
+.yellow, a.yellow { color: #fbcb30; }
+.yellow-bg { background-color: #fbcb30; }
+.green, a.green { color: $green; }
+.green-bg { background-color: $green; }
+.light-green, a.light-green { color: #8fd14c; }
+.light-green-bg { background-color: #8fd14c; }
+.blue, a.blue { color: $blue; }
+.blue-bg { background-color: $blue; }
+.light-blue, a.light-blue { color: #78b; }
+.light-blue-bg { background-color: #78b; }
+.purple, a.purple { color: #a776d9; }
+.purple-bg { background-color: #a776d9; }
+.light-purple, a.light-purple { color: #b394f3; }
+.light-purple-bg { background-color: #b394f3; }
+.pink, a.pink { color: #fb5c9b; }
+.pink-bg { background-color: #fb5c9b; }
+
+/****************flexbox**************/
+.flex {display:flex;}
+.inline-flex {display:inline-flex;}
+.flex-center{justify-content: center;align-items: center;}
+.flex-center-between{justify-content: space-between;align-items: center;}
+/*横向或纵向*/
+.flex-row {flex-direction:row;}
+.flex-col {flex-direction:column;}
+.flex-row-reverse {flex-direction:row-reverse;}
+.flex-col-reverse {flex-direction:column-reverse;}
+.flex-wrap {flex-wrap:wrap;}
+/*主轴对齐方式*/
+.flex-justify-start {justify-content:flex-start;}
+.flex-justify-end {justify-content:flex-end;}
+.flex-justify-center {justify-content:center;}
+.flex-justify-between {justify-content:space-between;}
+.flex-justify-around {justify-content:space-around;}
+/*侧轴对齐方式*/
+.flex-align-start {align-items:flex-start;}
+.flex-align-end {align-items:flex-end;}
+.flex-align-center {align-items:center;}
+.flex-align-baseline {align-items:baseline;}
+.flex-align-stretch {align-items:stretch;}
+/*主轴换行时行在侧轴的对齐方式,必须定义flex-wrap为换行*/
+.flex-content-start {align-content:flex-start;}
+.flex-content-end {align-content:flex-end;}
+.flex-content-center {align-content:center;}
+.flex-content-between {align-content:space-between;}
+.flex-content-around {align-content:space-around;}
+.flex-content-stretch {align-content:stretch;}
+/*允许子元素收缩*/
+.flex-child-grow {flex-grow: 1;}/*允许拉伸*/
+.flex-child-shrink {flex-shrink: 1;}/*允许收缩*/
+.flex-child-noshrink {flex-shrink: 0;}/*不允许收缩*/
+.flex-child-average {flex:1;}/*平均分布,兼容旧版必须给宽度*/
+.flex-child-first {order: 1;}/*排第一个*/
+/*子元素在侧轴的对齐方式*/
+.flex-child-align-start {align-self:flex-start;}
+.flex-child-align-end {align-self:flex-end;}
+.flex-child-align-center {align-self:center;}
+.flex-child-align-baseline {align-self:baseline;}
+.flex-child-align-stretch {align-self:stretch;}
+
+.border{border:solid 1rpx $borderColor;}
+.border-top{border-top:solid 1rpx $borderColor;}
+.border-right{border-right:solid 1rpx $borderColor;}
+.border-bottom{border-bottom:solid 1rpx $borderColor;}
+.border-left{border-left:solid 1rpx $borderColor;}
+
+.full-screen{width:100%;height:100%;}
+.full-width{width:100%;}
+.full-height{height:100%;}
+
+.block { display: block; }
+.inline-block { display: inline-block; }
+.inline { display: inline; }
+.hide { display: none; }
+.left { float: left; }
+.right { float: right; }
+.relative { position: relative; }
+.absolute { position: absolute; }
+.fixed { position: fixed; }
+.clear { clear: both; }
+.circle{border-radius: 100%;}
+
+.overflow-hide { overflow: hidden; }
+.italic { font-style: italic; }
+.normal { font-weight: normal; }
+.bold { font-weight: bold; }
+.font-36 { font-size: 72rpx; }
+.font-30 { font-size: 60rpx; }
+.font-26 { font-size: 52rpx; }
+.font-24 { font-size: 48rpx; }
+.font-20 { font-size: 40rpx; }
+.font-18 { font-size: 36rpx; }
+.font-17 { font-size: 34rpx; }
+.font-16 { font-size: 32rpx; }
+.font-15 { font-size: 30rpx; }
+.font-14 { font-size: 28rpx; }
+.font-13 { font-size: 26rpx; }
+.font-12 { font-size: 24rpx; }
+.font-10 { font-size: 20rpx; }
+
+.text-shadow{text-shadow: 4rpx 4rpx 10rpx rgba(0,0,0,.7);}
+.box-shadow{box-shadow: 0 0 20rpx rgba($mainColor,.1);}
+.text-center { text-align: center; }
+.text-right { text-align: right; }
+.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.nowrap { word-wrap: normal; white-space: nowrap; }
+.vertical-middle{vertical-align: middle;}
+.lines-height-2{line-height: 2;}
+.lines-height-15{line-height: 1.5;}
+.lines-1{text-overflow:ellipsis;-webkit-line-clamp:1;display: -webkit-box;overflow:hidden;-webkit-box-orient: vertical;line-height: 1.5;word-break: break-all;height:1.5em}
+.lines-2{text-overflow:ellipsis;-webkit-line-clamp:2;display: -webkit-box;overflow:hidden;-webkit-box-orient: vertical;line-height: 1.5;word-break: break-all;height:3em}
+.lines-3{text-overflow:ellipsis;-webkit-line-clamp:3;display: -webkit-box;overflow:hidden;-webkit-box-orient: vertical;line-height: 1.5;word-break: break-all;height:4.5em}
+
+.border-box{box-sizing:border-box;}
+.radius { border-radius: 10rpx;}
+.margin { margin: 20rpx; }
+.margin-top { margin-top: 20rpx; }
+.margin-right { margin-right: 20rpx; }
+.margin-bottom { margin-bottom: 20rpx; }
+.margin-left { margin-left: 20rpx; }
+.padding { padding: 20rpx; }
+.padding-14 { padding: 28rpx; }
+.padding-12 { padding: 24rpx; }
+.padding-top { padding-top: 20rpx; }
+.padding-right { padding-right: 20rpx; }
+.padding-bottom { padding-bottom: 20rpx; }
+.padding-left { padding-left: 20rpx; }
+.mt-5{margin-top: 10rpx;}
+.mr-5{margin-right: 10rpx;}
+.mb-5{margin-bottom: 10rpx;}
+.ml-5{margin-left: 10rpx;}
+.pt-5{padding-top: 10rpx;}
+.pr-5{padding-right: 10rpx;}
+.pb-5{padding-bottom: 10rpx;}
+.pl-5{padding-left: 10rpx;}
+.mt-15{margin-top: 30rpx;}
+.mr-15{margin-right: 30rpx;}
+.mb-15{margin-bottom: 30rpx;}
+.ml-15{margin-left: 30rpx;}
+.mt-20{margin-top: 40rpx;}
+.mr-20{margin-right: 40rpx;}
+.mb-20{margin-bottom: 40rpx;}
+.ml-20{margin-left: 40rpx;}
+.arrow-right { display: block; width: 30rpx; height: 40rpx;}
+.arrow-down{transform:rotate(90deg)}
+.cell{height:44px;}
+.grey-space{height: 20rpx; background: #f5f5f5;}
+.card-item{border-radius: 16rpx; box-shadow: 0 4rpx 20rpx 0 rgba(0, 0, 0, 0.08); background-color: #fff; margin: 0 28rpx 28rpx; overflow:hidden; }
+.interval {height: 20rpx;background: #f1f1f1;}
+
+/* button样式修改 */
+button {
+	line-height: 3;
+	border-radius: 10rpx;
+	font-size: 28rpx;
+	&::after {
+		border: none;
+	}
+}
+.main-button {
+	color: #fff;
+	background-color: $mainColor;
+}
+.assist-button {
+	color: #fff;
+	background-color: $assistColor;
+}
+.main-assist-button {
+	color: #fff;
+	background-color: $assistColor;
+}
+.main-button-plain {
+	color: $mainColor;
+	background: none;
+	border: 1rpx solid $mainColor;
+}
+.mini-button {
+	font-size: 24rpx;
+	line-height: 2.2;
+}
+.grey-button {
+	color: #666;
+}
+.grey-button-plain {
+	background: none;
+	border: 1rpx solid $gray;
+	color: #666;
+}
+
+/* 会员标签 */
+.vip-tag {
+	position: absolute;
+	right: -40rpx;
+	top: -4rpx;
+	z-index: 5;
+	padding: 10rpx 40rpx 6rpx;
+	transform: rotate(45deg);
+	color: #fff;
+	font-size: 20rpx;
+	background: rgba(238,195,127,.8);
+}
+
+/* 新消息角标 */
+.tag-tips {
+	position: absolute;
+	font-size: 18rpx;
+	padding: 1px 3px;
+	background: #f21c1c;
+	color: #fff;
+	border-radius: 3px;
+	right: 30rpx;
+	top: -16rpx;
+	opacity: .9;
+}
+
+/* 列表页角标 */
+.tag {
+	top: 0;
+	left: 0;
+	padding: 4rpx 20rpx;
+	border-bottom-right-radius: 10rpx;
+}
+
+/* 图标大小 */
+.icon {
+	width: 50rpx;
+	height: 50rpx;
+}
+
+/* 重写checkbox样式 */
+checkbox .wx-checkbox-input {
+	border-radius: 50%;
+	transform: scale(0.5) translate(50%, 0) !important;
+	flex-shrink: 0;
+}
+checkbox .wx-checkbox-input.wx-checkbox-input-checked {
+	border: 1px solid $mainColor;
+	transform: scale(0.5) translate(50%, 0) !important;
+	border-radius: 50%;
+	background: none !important;
+}
+checkbox.hide-checkbox .wx-checkbox-input {
+	display: none;
+}
+
+/* 导航搜索 样式 */
+.nav-search {
+	height: 72rpx;
+	background: rgba(#f1f1f1, 0.8);
+	border-radius: 72rpx;
+	padding-left: 30rpx;
+}
+
+/* 表单 */
+.form-item {
+	padding: 26rpx;
+	background: #fff;
+	.title {
+		flex-shrink: 0;
+		min-width: 140rpx;
+		i{
+			display: inline-block;
+			margin-left: 6rpx;
+			color: $red;
+		}
+	}
+	input, textarea {
+		flex-grow: 1;
+		margin-left: 20rpx;
+		text-align: right;
+	}
+}
+
+.list-card {
+	margin: 20rpx;
+	background: #fff;
+	border-radius: 10rpx;
+	box-shadow: 0 0 10rpx #e1e1e1;
+}
+
+/*标题样式*/
+.before-line {
+	position: relative;
+	margin-left: 10px;
+}
+.before-line:before {
+	content: '';
+	position: absolute;
+	left: -20rpx;
+	top: 50%;
+	transform: translateY(-50%);
+	border: 4rpx solid $mainColor;
+	border-radius: 6rpx;
+	height: 60%;
+}
+
+/*图片展示*/
+.img-list {
+	image {
+		$img: 218rpx;
+		width: $img;
+		height: $img;
+		box-sizing: border-box;
+		border-radius: 10rpx;
+		margin: 0 20rpx 20rpx 0;
+		background: #f5f5f5;
+		&:nth-child(3n) {
+			margin-right: 0;
+		}
+	}
+}
+
+.searchBtn {
+	.addBtn {
+		padding: 14rpx 0 14rpx 20rpx;
+		line-height: 40rpx;
+		display: block;
+	}
+}
+
+.pb-bottomBtn{padding-bottom: 120rpx;}
+
+.bottomBtn{
+	position:fixed;
+	bottom:0;
+	left:0;
+	right:0;
+	z-index: 2;
+
+	.save{
+		color: #fff;
+		border-radius:0;
+		background-color: $mainColor;
+		line-height: 100rpx;
+		height: 100rpx;
+	}
+}
+/* 顶部的暂无备案 */
+.top-noRecord-box{
+	color: #67C23A;
+	background-color: #F0F9EB;
+
+	.no-record-button{
+		font-size: 24rpx;
+		line-height: 2.2;
+		color:  #67C23A;
+		background: none;
+		border: 1rpx solid  #67C23A;
+	}
+}
+
+.status_bar {
+	height: var(--status-bar-height);
+	width: 100%;
+}
+/*表格*/
+.table-item {
+	font-size: 26rpx;
+	width: 100%;
+	border-bottom: 1rpx solid #eee;
+	._tr {
+		display: flex;
+	}
+	._th {
+		font-size: 28rpx;
+		font-weight: bold;
+		background: #f9f9f9;
+	}
+	._td, ._th {
+		width: 100%;
+		// display: flex;
+		// align-items: center;
+		// justify-content: center;
+		// min-height: 90rpx;
+		line-height: 1.5;
+		text-align: center;
+		border-top: 1rpx solid #eee;
+		border-right: 1rpx solid #eee;
+		padding: 10rpx;
+		box-sizing: border-box;
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+	}
+}
+
+.body {
+	min-height: 100vh;
+	//background: #f5f5f5 url('/static/image/bg.png') no-repeat top center;
+	background: #f5f5f5;
+	background-size: contain;
+	padding-bottom: 1rpx;
+	box-sizing: border-box;
+}
+
+.topBar {
+	@extend .body;
+	background-position: 0 -260rpx;
+}
+
+.ad {
+	width: 100%;
+	max-height: 320rpx;
+}
+
+
+
+.btn-list {
+	.btn {
+		padding: 10upx 20upx;
+		border: 1upx solid $mainColor;
+		color: $mainColor;
+		margin-right: 16upx;
+		border-radius: 6upx;
+		font-size: 24upx;
+	}
+}

+ 11 - 0
src/static/style/var.scss

@@ -0,0 +1,11 @@
+//$mainColor:#DC4E4C;
+$mainColor:#0054AF;
+$assistColor:#faca72;
+$borderColor:#eee;
+$red: #f21c1c;
+$blue: #3caaff;
+$gray: #808080;
+$green: #07c160;
+$success: #67c23a;
+$warning: #e6a23c;
+$danger: #f56c6c;

+ 362 - 0
src/store/common.js

@@ -0,0 +1,362 @@
+import api from '../api'
+import {
+	storage,
+	navigator,
+	indicator,
+	modal
+} from '../utils/uniApi.js'
+import bus from '../utils/eventBus.js'
+import tenant from '../tenant/config'
+
+const device = uni.getSystemInfoSync()
+const brand = device.brand && device.brand.toLowerCase()
+if (brand === 'iphone') {
+	var reg = new RegExp('[^\\<\\>]+(?=\\>)', 'g')
+	device.model = device.model.match(reg)[0]
+}
+
+// #ifdef MP-WEIXIN
+const appTopButton = uni.getMenuButtonBoundingClientRect() // 小程序顶部胶囊按钮
+// #endif
+
+const common = {
+	state: {
+		token: storage.get('token') || '',
+		permission: storage.get('permission') || {},
+		enterPriseType: '',
+		UUID: '',
+		userInfo: storage.get('userInfo') || {},
+		city: {},
+		systemInfo: {},
+		gps: '',
+		platform: device.platform === 'android' ? 'android' : 'ios',
+		device: (brand === 'iphone' || brand === 'devtools') ? device.model : brand ? brand + ' ' + device.model :
+			device.model,
+		// #ifdef MP-WEIXIN
+		wrapHeight: (appTopButton.top + 32 + 10) + 'px',
+		appTopButton,
+		// #endif
+		authInfo: {
+			openId: '',
+			unionId: '',
+			sessionKey: '',
+			isBind: false
+		},
+		approve: false, // 是否审核完成
+		tenant
+	},
+	mutations: {
+		setToken(state, token) {
+			if (token) {
+				state.token = token
+				storage.set('token', token)
+			} else {
+				let storageToken = storage.get('token') || ''
+				state.token = storageToken
+			}
+			bus.$emit('setToken')
+		},
+		setPermission(state, permission) {
+			if (permission) {
+				state.permission = permission
+				storage.set('permission', permission)
+			} else {
+				let storagePermission = storage.get('permission') || ''
+				state.permission = storagePermission
+			}
+		},
+		setEnterpriseType(state, enterPriseType) {
+			// console.log(enterPriseType)
+			if (enterPriseType) {
+				state.enterPriseType = enterPriseType
+				storage.set('enterPriseType', enterPriseType)
+			} else {
+				state.enterPriseType = storage.get('enterPriseType') || ''
+			}
+		},
+		deleteToken(state) {
+			state.token = ''
+			storage.remove('token')
+		},
+		setGps(state, gps) {
+			state.gps = gps
+		},
+		setUUID(state) {
+			let UUID = storage.get('uuid')
+			if (!UUID) {
+				UUID = uuid()
+				storage.set('uuid', UUID)
+			}
+			state.UUID = UUID
+		},
+		setUserInfo(state, userInfo) {
+			storage.set('userInfo', userInfo)
+			state.userInfo = userInfo
+		},
+		setCity(state, city) {
+			storage.set('selectCity', city)
+			state.city = city
+		},
+		setSystemInfo(state, device) {
+			state.device = device
+		},
+		setApprove(state, value) {
+			state.approve = value
+		},
+		setAuthInfo(state, authInfo) {
+			state.authInfo = authInfo
+		}
+	},
+	actions: {
+		async init({
+			commit,
+			dispatch
+		}) {
+			// if (storage.get('token')) return
+			// 登录
+			// storage.set('hideLogin', true)
+			let l = await new Promise((resolve, reject) => {
+				uni.login({
+					success: r => resolve(r),
+					fail: e => reject(e)
+				})
+			})
+			// 获取code
+			api.commonApi.wxLogin({
+				code: l.code
+			}).then(data => {
+				commit('setAuthInfo', {
+					openId: data.openId,
+					sessionKey: data.sessionKey
+				})
+				storage.set('authInfo', {
+					openId: data.openId,
+					sessionKey: data.sessionKey
+				})
+				if (data.access_token) {
+					commit('setToken', data.access_token)
+					commit('setEnterpriseType', data.enterprise_type)
+					dispatch('getUserInfo')
+					let url = storage.get('urlParams') ? JSON.parse(storage.get('urlParams')) : ''
+					// console.log(url.path)
+					if (url && url.path === 'pages/login/index') {
+						navigator.switchTab('/pages/home/index')
+					}
+				} else {
+					storage.clear()
+					navigator.login()
+				}
+				bus.$emit('hideLoading') // 关闭loading
+				// storage.set('hideLogin', false) // 显示登录页面
+			})
+		},
+		approve({commit}) { // 小程序审核参数
+			api.paramsApi.getParams('mpapprove').then(res => {
+				if (res.success) {
+					commit('setApprove', res.data.paramValue > 0) // 0 审核中,1 审核完成
+				}
+			})
+		},
+		checkUser({
+			commit,
+			dispatch
+		}) { // 判断用户是否注册
+			api.commonApi.checkUser().then(res => {
+				if (res.success) {
+					dispatch('getUserInfo')
+				} else {
+					uni.showModal({
+						// 弹窗提示
+						title: '登录',
+						content: '您还未登录,无法获取您的用户信息,请先登录',
+						confirmText: '去登录',
+						cancelText: '暂不登录',
+						success(res) {
+							if (res.confirm) {
+								navigator.replace('/mine/register/index')
+							}
+						}
+					})
+				}
+			}).finally(() => {
+				indicator.close()
+			})
+		},
+		getUserInfo({
+			commit
+		}) { // 获取用户信息
+			let storageToken = storage.get('token') || ''
+			if (!storageToken) return // 不强制登录,需要强制登录就删除此行
+			return new Promise((resolve, reject) => {
+				api.commonApi.getBaseInfo().then(res => {
+					if (res.success) {
+						commit('setUserInfo', res.data)
+						commit('setToken', storageToken)
+						// 设置角标文本--【我的】
+						// if (res.data.myNew) {
+						//   uni.showTabBarRedDot({
+						//     index: 1
+						//   })
+						// } else {
+						//   // 取消角标
+						//   uni.hideTabBarRedDot({
+						//     index: 1
+						//   })
+						// }
+					}
+					resolve(res.success)
+				})
+			})
+		},
+		getGps({
+			commit,
+			dispatch
+		}, type = 0) {
+			// type = 0 只获取gps,type = 1 获取社区信息,
+			return new Promise((resolve, reject) => {
+				uni.getLocation({
+					type: 'gcj02',
+					isHighAccuracy: true,
+					success(gps) {
+						// console.log(gps)
+						commit('setGps', gps)
+						if (type === 0) {
+							dispatch('getCommunity')
+						}
+						resolve(gps)
+					},
+					fail() { // 授权失败
+						uni.getSetting({
+							// 获取用户的当前设置,返回值中只会出现小程序已经向用户请求过的权限
+							success(res) {
+								// 成功调用授权窗口
+								let statu = res.authSetting
+								if (!statu['scope.userLocation']) {
+									// 如果设置中没有位置权限
+									uni.showModal({
+										// 弹窗提示
+										title: '是否授权当前位置',
+										content: '需要获取您的地理位置,请确认授权,否则社区功能将无法使用',
+										success(tip) {
+											if (tip.confirm) {
+												uni.openSetting({
+													// 点击确定则调其用户设置
+													success(data) {
+														if (data
+															.authSetting[
+																'scope.userLocation'
+															] === true
+														) {
+															// 如果设置成功
+															uni.showToast({
+																// 弹窗提示
+																title: '授权成功',
+																icon: 'success',
+																duration: 1000
+															})
+															uni.getLocation({
+																// 通过getLocation方法获取数据
+																type: 'gcj02',
+																isHighAccuracy: true,
+																success(
+																	gps
+																) {
+																	// 成功的执行方法
+																	commit
+																		('setGps',
+																			gps
+																		)
+																	if (type ===
+																		0
+																	) {
+																		dispatch
+																			(
+																				'getCommunity'
+																				)
+																	}
+																	resolve
+																		(
+																			gps
+																			)
+																}
+															})
+														}
+													}
+												})
+											} else {
+												if (type === 0) {
+													uni.showModal({
+														title: '温馨提示',
+														content: '未获取到您当前位置的社区信息',
+														confirmText: '选择社区',
+														success: (res) => {
+															if (res
+																.confirm
+															) {
+																uni.navigateTo({
+																	url: '/pages/select-community/main'
+																})
+															} else {}
+														}
+													})
+												} else {
+													resolve('')
+												}
+											}
+										}
+									})
+								}
+							}
+						})
+					}
+				})
+			})
+		},
+		getCommunity({
+			state,
+			commit,
+			dispatch
+		}) { // 获取城市信息
+			const {
+				latitude,
+				longitude
+			} = state.gps
+			if (latitude && longitude) {
+				const location = latitude + ',' + longitude
+				api.commonApi.getCityInfo(location).then(res => {
+					let selectCity = res.data.find(item => item.isSelected)
+					// console.log(selectCity)
+					commit('setCity', selectCity)
+					storage.set('cityList', res.data)
+					bus.$emit('getCity', res.data)
+				})
+			}
+		},
+		getButtons({commit}) {
+			api.commonApi.getButtons().then(res => {
+				let result = []
+				function getCode(list) {
+					list.forEach(ele => {
+						if (typeof(ele) === 'object') {
+							const chiildren = ele.children
+							const code = ele.code
+							if (chiildren) {
+								getCode(chiildren)
+							} else {
+								result.push(code)
+							}
+						}
+					})
+				}
+				getCode(res.data)
+				let obj = {}
+				result.forEach(ele => {
+					obj[ele] = true
+				})
+				commit('setPermission', obj)
+			})
+		}
+	}
+}
+
+export default common

+ 17 - 0
src/store/getters.js

@@ -0,0 +1,17 @@
+const getters = {
+	isLogin: state => state.common.token,
+	userInfo: state => state.common.userInfo,
+	device: state => state.common.systemInfo ? state.common.systemInfo.device : '',
+	platform: state => state.common.platform,
+	openId: state => state.common.authInfo.openId,
+	authInfo: state => state.common.authInfo,
+	city: state => state.common.city,
+	appTopButton: state => state.common.appTopButton,
+	tenantId: state => state.common.tenant.id,
+	imagePath: state => state.common.tenant.imagePath,
+	appName: state => state.common.tenant.name,
+	permission: state => state.common.permission,
+	approve: state => state.common.approve,
+}
+
+export default getters

+ 15 - 0
src/store/index.js

@@ -0,0 +1,15 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import common from './common.js'
+
+import getters from './getters'
+
+Vue.use(Vuex)
+const store = new Vuex.Store({
+  modules: {
+    common
+  },
+  getters
+})
+
+export default store

+ 13 - 0
src/tenant/config.js

@@ -0,0 +1,13 @@
+// 测试环境
+// const path = 'http://47.111.227.213:9091/api'
+
+// 线上环境
+ const path = 'https://wutong.kmxxg.cn/api'
+module.exports = {
+	id: '000000',
+	name: '云南省退役军人政务公开服务',
+	appId: 'wx88a0bf63ba2c7300',
+	host: path,
+	imagePath: 'https://img.yousuyoushu.cn/ent/',
+	// h5Url: 'https://h5.yousuyoushu.cn', // 线上环境,H5页面域名前缀,上线前必须修改此项
+}

+ 28 - 0
src/utils/date.js

@@ -0,0 +1,28 @@
+
+/**
+ * 日期格式化
+ */
+export function dateFormat(date, format) {
+    format = format || 'yyyy-MM-dd hh:mm:ss'
+    if (date !== 'Invalid Date') {
+        let o = {
+            'M+': date.getMonth() + 1, //month
+            'd+': date.getDate(), //day
+            'h+': date.getHours(), //hour
+            'm+': date.getMinutes(), //minute
+            's+': date.getSeconds(), //second
+            'q+': Math.floor((date.getMonth() + 3) / 3), //quarter
+            'S': date.getMilliseconds() //millisecond
+        }
+        if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
+            (date.getFullYear() + '').substr(4 - RegExp.$1.length))
+        for (let k in o)
+            if (new RegExp('(' + k + ')').test(format))
+                format = format.replace(RegExp.$1,
+                    RegExp.$1.length === 1 ? o[k] :
+                        ('00' + o[k]).substr(('' + o[k]).length))
+        return format
+    }
+    return ''
+
+}

+ 2 - 0
src/utils/eventBus.js

@@ -0,0 +1,2 @@
+import Vue from 'vue'
+export default new Vue()

+ 27 - 0
src/utils/regExp.js

@@ -0,0 +1,27 @@
+// 手机号
+export const regExp_mobile = /^1(3|4|5|6|7|8|9)\d{9}$/
+
+// 国内座机电话,如: 0341-86091234
+export const regExp_phone = /\d{3}-\d{8}|\d{4}-\d{7}/
+
+// 是否电话格式(手机和座机)
+export const regExp_isPhoneNum = /^((0\d{2,3}-\d{7,8})|(1[3456789]\d{9}))$/
+
+// 是否8位纯数字 /^[0-9]{8}$/
+// 短信验证码
+export const regExp_messageVftCode = /^[0-9]{4,6}$/
+
+// email地址
+export const regExp_email = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
+
+// 身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X
+export const regExp_IdCard = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
+
+// 车牌号
+export const regExp_isCarNum = /^([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1})$/
+
+// 只包含中文
+export const regExp_onlyChinese = /^[\u4E00-\u9FA5]/
+
+// 16进制颜色
+export const regExp_isColor = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/

+ 360 - 0
src/utils/uniApi.js

@@ -0,0 +1,360 @@
+// 对uni-API进行简单封装
+const toast = (title = '提示', icon = 'none', duration = 2000, mask = false) => {
+	return new Promise((resolve, reject) => {
+		uni.showToast({
+			title,
+			icon,
+			duration,
+			mask,
+			success: res => {
+				setTimeout(function() {
+					resolve(res)
+				}, duration)
+			},
+			fail: err => reject(err)
+		})
+	})
+}
+
+const indicator = {
+	open(title = '加载中', mask = true) {
+		return new Promise((resolve, reject) => {
+			uni.showLoading({
+				title,
+				mask,
+				success: res => resolve(res),
+				fail: err => reject(err)
+			})
+		})
+	},
+	close() {
+		uni.hideLoading()
+	}
+}
+
+const modal = (options) => {
+	uni.showModal(options)
+}
+
+const storage = {
+	get(key) {
+		return uni.getStorageSync(key)
+	},
+	set(key, value) {
+		uni.setStorageSync(key, value)
+	},
+	remove(key) {
+		uni.removeStorageSync(key)
+	},
+	clear() {
+		uni.clearStorage()
+	}
+}
+
+const navigator = {
+	urlCache: [],
+	clearUrlCache() {
+		this.urlCache = []
+	},
+	push(url) {
+		if (this.urlCache[0] === url && (url === '/pages/login/index' || url === '/pages/register/index')) {
+			return
+		}
+		return new Promise((resolve, reject) => {
+			this.urlCache.shift()
+			this.urlCache.push(url)
+			uni.navigateTo({
+				url,
+				success: res => resolve(res),
+				fail: err => reject(err)
+			})
+		})
+	},
+	replace(url) {
+		return new Promise((resolve, reject) => {
+			uni.redirectTo({
+				url,
+				success: res => resolve(res),
+				fail: err => reject(err)
+			})
+		})
+	},
+	back(delta) {
+		return new Promise((resolve, reject) => {
+			uni.navigateBack({
+				delta
+			})
+		})
+	},
+	relaunch(url) {
+		return new Promise((resolve, reject) => {
+			uni.reLaunch({
+				url,
+				success: res => resolve(res),
+				fail: err => reject(err)
+			})
+		})
+	},
+	switchTab(url) {
+		return new Promise((resolve, reject) => {
+			uni.switchTab({
+				url,
+				success: res => resolve(res),
+				fail: err => reject(err)
+			})
+		})
+	},
+	login() {
+		return this.relaunch('/pages/login/index')
+	},
+	// securityLogin () {
+	//   return this.push('/pages/splitpackage/pages/security/main')
+	// }
+}
+const getCurrentPosition = (type = 'wgs84') => {
+	return new Promise((resolve, reject) => {
+		uni.getLocation({
+			type,
+			success: res => resolve(res),
+			fail: async err => {
+				await locationErrHandler(err)
+				reject(err)
+			}
+		})
+	})
+}
+const chooseLocation = () => {
+	return new Promise((resolve, reject) => {
+		uni.chooseLocation({
+			success: res => resolve(res),
+			fail: async err => {
+				await locationErrHandler(err)
+				reject(err)
+			}
+		})
+	})
+}
+const locationErrHandler = async (res) => {
+	if (res.errMsg.indexOf('cancel') + 1) {
+		return
+	}
+	if (res.errMsg.indexOf('system') + 1 || res.errMsg.indexOf('fail 1') + 1) {
+		return toast('请确保开启微信定位服务')
+	}
+	// ios 拒绝定位 "getLocation:fail auth deny"
+	modal({
+		title: '提示',
+		content: '需要开启【地理位置】',
+		success: (res) => {
+			if (res.confirm) {
+				navigator.push('/pages/splitpackage/pages/member/config/main')
+			} else {
+				toast('取消定位')
+			}
+		}
+	})
+}
+const makePhone = (phone = '') => { // 拨打电话
+	return new Promise((resolve, reject) => {
+		uni.makePhoneCall({
+			phoneNumber: phone
+		})
+	})
+}
+
+const scrollTo = (location = 0, time = 700) => { // 滚动条滚动到指定位置
+	return new Promise((resolve, reject) => {
+		uni.pageScrollTo({
+			scrollTop: location,
+			duration: time
+		})
+		setTimeout(() => {
+			resolve()
+		}, time)
+	})
+}
+const actionSheet = (actions) => {
+	return new Promise((resolve, reject) => {
+		uni.showActionSheet({
+			itemList: actions,
+			success: function(res) {
+				resolve(res.tapIndex)
+			},
+			fail: function() {
+				reject()
+			}
+		})
+	})
+}
+
+
+/**
+ * html 解码
+ * @param str
+ * @returns {string}
+ */
+function htmlDecode(str) {
+	let s = ''
+	if (!str.length) return ''
+	s = str.replace(/&amp;/g, '&')
+	s = s.replace(/&lt;/g, '<')
+	s = s.replace(/&gt;/g, '>')
+	s = s.replace(/&nbsp;/g, ' ')
+	s = s.replace(/&#39;/g, '\'')
+	s = s.replace(/&quot;/g, '"')
+
+	const keyword1 = '<img'
+	const keyword2 = '<p'
+	let type = s.indexOf(keyword1) > -1 || s.indexOf(keyword2) > -1
+	if (type) {
+		s = s.replace(new RegExp(keyword1, 'gi'), `${keyword1} class="rich-img"`)
+		s = s.replace(new RegExp(keyword2, 'gi'), `${keyword2} class="p"`)
+	}
+	return s
+}
+
+function arrayUnique(array) {
+	let temp
+	let arrVal
+	let arrClone = array.concat() // 克隆数组
+	let typeArr = { // 数组原型
+		'obj': '[object Object]',
+		'fun': '[object Function]',
+		'arr': '[object Array]',
+		'num': '[object Number]'
+	}
+	let ent = /(\u3000|\s|\t)*(\n)+(\u3000|\s|\t)*/gi // 空白字符正则
+
+	// 把数组中的object和function转换为字符串形式
+	for (let i = arrClone.length; i--;) {
+		arrVal = arrClone[i]
+		temp = Object.prototype.toString.call(arrVal)
+
+		if (temp === typeArr['num'] && arrVal.toString() === 'NaN') {
+			arrClone[i] = arrVal.toString()
+		}
+
+		if (temp === typeArr['obj']) {
+			arrClone[i] = JSON.stringify(arrVal)
+		}
+
+		if (temp === typeArr['fun']) {
+			arrClone[i] = arrVal.toString().replace(ent, '')
+		}
+	}
+
+	// 去重关键步骤
+	for (let i = arrClone.length; i--;) {
+		arrVal = arrClone[i]
+		temp = Object.prototype.toString.call(arrVal)
+
+		if (temp === typeArr['arr']) this.arrayUnique(arrVal) // 如果数组中有数组,则递归
+		if (arrClone.indexOf(arrVal) !== arrClone.lastIndexOf(arrVal)) { // 如果有重复的,则去重
+			array.splice(i, 1)
+			arrClone.splice(i, 1)
+		} else {
+			if (Object.prototype.toString.call(array[i]) !== temp) {
+				// 检查现在数组和原始数组的值类型是否相同,如果不同则用原数组中的替换,原因是原数组经过了字符串变换
+				arrClone[i] = array[i]
+			}
+		}
+	}
+	return arrClone
+}
+
+/**
+ * 处理日期格式
+ * @param str
+ * @returns {string}
+ */
+function dateFormat(date, format) {
+	format = format || 'yyyy-MM-dd hh:mm:ss'
+	if (date !== 'Invalid Date') {
+		let o = {
+			'M+': date.getMonth() + 1, //month
+			'd+': date.getDate(), //day
+			'h+': date.getHours(), //hour
+			'm+': date.getMinutes(), //minute
+			's+': date.getSeconds(), //second
+			'q+': Math.floor((date.getMonth() + 3) / 3), //quarter
+			'S': date.getMilliseconds() //millisecond
+		}
+		if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
+			(date.getFullYear() + '').substr(4 - RegExp.$1.length))
+		for (let k in o)
+			if (new RegExp('(' + k + ')').test(format))
+				format = format.replace(RegExp.$1,
+					RegExp.$1.length === 1 ? o[k] :
+					('00' + o[k]).substr(('' + o[k]).length))
+		return format
+	}
+	return ''
+
+}
+
+/**
+ * 当前时间增加分钟数
+ *
+ */
+function dateAdd(num) {
+	var dt = new Date(); //得到时间对象
+	var tmNow = dt.getMinutes(); //得到当前分钟,此处只是举个例子
+	var tmNowNext = tmNow + num //
+	dt.setMinutes(tmNowNext, 0, 0)
+	return dt
+}
+
+/**
+ * 获取数组某个元素的下标
+ * arrays  : 传入的数组
+ * obj     : 需要获取下标的元素
+ */
+
+function contains(arrays, obj) {
+	let i = arrays.length;
+	while (i--) {
+		if (arrays[i] === obj) {
+			return i;
+		}
+	}
+	return false;
+}
+
+
+/***
+ * 连续输入节流阀
+ * func 输入完成的回调函数
+ * delay 延迟时间
+ */
+function debounce(func, delay) {
+	let timer
+	return (...args) => {
+		if (timer) {
+			clearTimeout(timer)
+		}
+		timer = setTimeout(() => {
+			func.apply(this, args)
+		}, delay)
+	}
+}
+
+
+
+export {
+	actionSheet,
+	toast,
+	indicator,
+	modal,
+	storage,
+	navigator,
+	makePhone,
+	scrollTo,
+	getCurrentPosition,
+	chooseLocation,
+	htmlDecode,
+	arrayUnique,
+	dateFormat,
+	contains,
+	dateAdd,
+	debounce
+}

+ 175 - 0
src/utils/validate.js

@@ -0,0 +1,175 @@
+/**
+ * Created by jiachenpan on 16/11/18.
+ */
+
+export function isvalidUsername(str) {
+  const valid_map = ['admin', 'editor']
+  return valid_map.indexOf(str.trim()) >= 0
+}
+
+/* 合法uri*/
+export function validateURL(textval) {
+  const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
+  return urlregex.test(textval)
+}
+/**
+ * 邮箱
+ * @param {*} s
+ */
+export function isEmail(s) {
+  return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
+}
+
+/**
+ * 手机号码
+ * @param {*} s
+ */
+export function isMobile(s) {
+  return /^1[0-9]{10}$/.test(s)
+}
+
+/**
+ * 电话号码
+ * @param {*} s
+ */
+export function isPhone(s) {
+  return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
+}
+
+/**
+ * URL地址
+ * @param {*} s
+ */
+export function isURL(s) {
+  return /^http[s]?:\/\/.*/.test(s)
+}
+
+/* 小写字母*/
+export function validateLowerCase(str) {
+  const reg = /^[a-z]+$/
+  return reg.test(str)
+}
+
+/* 大写字母*/
+export function validateUpperCase(str) {
+  const reg = /^[A-Z]+$/
+  return reg.test(str)
+}
+
+/* 大小写字母*/
+export function validatAlphabets(str) {
+  const reg = /^[A-Za-z]+$/
+  return reg.test(str)
+}
+/*验证pad还是pc*/
+export const vaildatePc = function() {
+  const userAgentInfo = navigator.userAgent
+  const Agents = ['Android', 'iPhone',
+    'SymbianOS', 'Windows Phone',
+    'iPad', 'iPod'
+  ]
+  let flag = true
+  for (var v = 0; v < Agents.length; v++) {
+    if (userAgentInfo.indexOf(Agents[v]) > 0) {
+      flag = false
+      break
+    }
+  }
+  return flag
+}
+/**
+     * validate email
+     * @param email
+     * @returns {boolean}
+     */
+export function validateEmail(email) {
+  const re = /^(([^<>()\\[\]\\.,;:\s@"]+(\.[^<>()\\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+  return re.test(email)
+}
+
+/**
+ * 判断身份证号码
+ */
+export function cardId (val) {
+  return /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/.test(val)
+}
+/**
+ * 判断手机号码是否正确
+ */
+export function isvalidatemobile(phone) {
+  let list = []
+  let result = true
+  let msg = ''
+  var isPhone = /^0\d{2,3}-?\d{7,8}$/
+  //增加134 减少|1349[0-9]{7},增加181,增加145,增加17[678]
+  if (!validatenull(phone)) {
+    if (phone.length == 11) {
+      if (isPhone.test(phone)) {
+        msg = '手机号码格式不正确'
+      } else {
+        result = false
+      }
+    } else {
+      msg = '手机号码长度不为11位'
+    }
+  } else {
+    msg = '手机号码不能为空'
+  }
+  list.push(result)
+  list.push(msg)
+  return list
+}
+/**
+ * 判断姓名是否正确
+ */
+export function validatename(name) {
+  var regName = /^[\u4e00-\u9fa5]{2,4}$/
+  if (!regName.test(name)) return false
+  return true
+}
+/**
+ * 判断是否为整数
+ */
+export function validatenum(num, type) {
+  let regName = /[^\d.]/g
+  if (type == 1) {
+    if (!regName.test(num)) return false
+  } else if (type == 2) {
+    regName = /[^\d]/g
+    if (!regName.test(num)) return false
+  }
+  return true
+}
+/**
+ * 判断是否为小数
+ */
+export function validatenumord(num, type) {
+  let regName = /[^\d.]/g
+  if (type == 1) {
+    if (!regName.test(num)) return false
+  } else if (type == 2) {
+    regName = /[^\d.]/g
+    if (!regName.test(num)) return false
+  }
+  return true
+}
+/**
+ * 判断是否为空
+ */
+export function validatenull(val) {
+  if (typeof val == 'boolean') {
+    return false
+  }
+  if (typeof val == 'number') {
+    return false
+  }
+  if (val instanceof Array) {
+    if (val.length == 0) return true
+  } else if (val instanceof Object) {
+    if (JSON.stringify(val) === '{}') return true
+  } else {
+    if (val == 'null' || val == null || val == 'undefined' || val == undefined || val == '') return true
+    return false
+  }
+  return false
+}

+ 13 - 0
src/view/news-detail/index.vue

@@ -0,0 +1,13 @@
+<template>
+  <van-button>新闻详情</van-button>
+</template>
+
+<script>
+export default {
+  name: "index.vue"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 1 - 0
src/wxcomponents/vant/action-sheet/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 70 - 0
src/wxcomponents/vant/action-sheet/index.js

@@ -0,0 +1,70 @@
+import { VantComponent } from '../common/component';
+import { button } from '../mixins/button';
+VantComponent({
+    mixins: [button],
+    props: {
+        show: Boolean,
+        title: String,
+        cancelText: String,
+        description: String,
+        round: {
+            type: Boolean,
+            value: true,
+        },
+        zIndex: {
+            type: Number,
+            value: 100,
+        },
+        actions: {
+            type: Array,
+            value: [],
+        },
+        overlay: {
+            type: Boolean,
+            value: true,
+        },
+        closeOnClickOverlay: {
+            type: Boolean,
+            value: true,
+        },
+        closeOnClickAction: {
+            type: Boolean,
+            value: true,
+        },
+        safeAreaInsetBottom: {
+            type: Boolean,
+            value: true,
+        },
+    },
+    methods: {
+        onSelect(event) {
+            const { index } = event.currentTarget.dataset;
+            const { actions, closeOnClickAction, canIUseGetUserProfile } = this.data;
+            const item = actions[index];
+            if (item) {
+                this.$emit('select', item);
+                if (closeOnClickAction) {
+                    this.onClose();
+                }
+                if (item.openType === 'getUserInfo' && canIUseGetUserProfile) {
+                    wx.getUserProfile({
+                        desc: item.getUserProfileDesc || '  ',
+                        complete: (userProfile) => {
+                            this.$emit('getuserinfo', userProfile);
+                        },
+                    });
+                }
+            }
+        },
+        onCancel() {
+            this.$emit('cancel');
+        },
+        onClose() {
+            this.$emit('close');
+        },
+        onClickOverlay() {
+            this.$emit('click-overlay');
+            this.onClose();
+        },
+    },
+});

+ 8 - 0
src/wxcomponents/vant/action-sheet/index.json

@@ -0,0 +1,8 @@
+{
+  "component": true,
+  "usingComponents": {
+    "van-icon": "../icon/index",
+    "van-popup": "../popup/index",
+    "van-loading": "../loading/index"
+  }
+}

+ 69 - 0
src/wxcomponents/vant/action-sheet/index.wxml

@@ -0,0 +1,69 @@
+<wxs src="../wxs/utils.wxs" module="utils" />
+
+<van-popup
+  show="{{ show }}"
+  position="bottom"
+  round="{{ round }}"
+  z-index="{{ zIndex }}"
+  overlay="{{ overlay }}"
+  custom-class="van-action-sheet"
+  safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
+  close-on-click-overlay="{{ closeOnClickOverlay }}"
+  bind:close="onClickOverlay"
+>
+  <view wx:if="{{ title }}" class="van-action-sheet__header">
+    {{ title }}
+    <van-icon
+      name="cross"
+      custom-class="van-action-sheet__close"
+      bind:click="onClose"
+    />
+  </view>
+  <view wx:if="{{ description }}" class="van-action-sheet__description van-hairline--bottom">
+    {{ description }}
+  </view>
+  <view wx:if="{{ actions && actions.length }}">
+    <!-- button外包一层view,防止actions动态变化,导致渲染时button被打散 -->
+    <button
+      wx:for="{{ actions }}"
+      wx:key="index"
+      open-type="{{ item.disabled || item.loading || (canIUseGetUserProfile && item.openType === 'getUserInfo') ? '' : item.openType }}"
+      style="{{ item.color ? 'color: ' + item.color : '' }}"
+      class="{{ utils.bem('action-sheet__item', { disabled: item.disabled || item.loading }) }} {{ item.className || '' }}"
+      hover-class="van-action-sheet__item--hover"
+      data-index="{{ index }}"
+      bindtap="{{ item.disabled || item.loading ? '' : 'onSelect' }}"
+      bindgetuserinfo="onGetUserInfo"
+      bindcontact="onContact"
+      bindgetphonenumber="onGetPhoneNumber"
+      binderror="onError"
+      bindlaunchapp="onLaunchApp"
+      bindopensetting="onOpenSetting"
+      lang="{{ lang }}"
+      session-from="{{ sessionFrom }}"
+      send-message-title="{{ sendMessageTitle }}"
+      send-message-path="{{ sendMessagePath }}"
+      send-message-img="{{ sendMessageImg }}"
+      show-message-card="{{ showMessageCard }}"
+      app-parameter="{{ appParameter }}"
+    >
+      <block wx:if="{{ !item.loading }}">
+        {{ item.name }}
+        <view wx:if="{{ item.subname }}" class="van-action-sheet__subname" >{{ item.subname }}</view>
+      </block>
+      <van-loading wx:else custom-class="van-action-sheet__loading" size="22px" />
+    </button>
+  </view>
+  <slot />
+  <block wx:if="{{ cancelText }}">
+    <view class="van-action-sheet__gap" />
+    <view
+      class="van-action-sheet__cancel"
+      hover-class="van-action-sheet__cancel--hover"
+      hover-stay-time="70"
+      bind:tap="onCancel"
+    >
+      {{ cancelText }}
+    </view>
+  </block>
+</van-popup>

+ 1 - 0
src/wxcomponents/vant/action-sheet/index.wxss

@@ -0,0 +1 @@
+@import '../common/index.wxss';.van-action-sheet{color:var(--action-sheet-item-text-color,#323233);max-height:var(--action-sheet-max-height,90%)!important}.van-action-sheet__cancel,.van-action-sheet__item{background-color:var(--action-sheet-item-background,#fff);font-size:var(--action-sheet-item-font-size,16px);line-height:var(--action-sheet-item-line-height,22px);padding:14px 16px;text-align:center}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5}.van-action-sheet__cancel:after,.van-action-sheet__item:after{border-width:0}.van-action-sheet__cancel{color:var(--action-sheet-cancel-text-color,#646566)}.van-action-sheet__gap{background-color:var(--action-sheet-cancel-padding-color,#f7f8fa);display:block;height:var(--action-sheet-cancel-padding-top,8px)}.van-action-sheet__item--disabled{color:var(--action-sheet-item-disabled-text-color,#c8c9cc)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__subname{color:var(--action-sheet-subname-color,#969799);font-size:var(--action-sheet-subname-font-size,12px);line-height:var(--action-sheet-subname-line-height,20px);margin-top:var(--padding-xs,8px)}.van-action-sheet__header{font-size:var(--action-sheet-header-font-size,16px);font-weight:var(--font-weight-bold,500);line-height:var(--action-sheet-header-height,48px);text-align:center}.van-action-sheet__description{color:var(--action-sheet-description-color,#969799);font-size:var(--action-sheet-description-font-size,14px);line-height:var(--action-sheet-description-line-height,20px);padding:20px var(--padding-md,16px);text-align:center}.van-action-sheet__close{color:var(--action-sheet-close-icon-color,#c8c9cc);font-size:var(--action-sheet-close-icon-size,22px)!important;line-height:inherit!important;padding:var(--action-sheet-close-icon-padding,0 16px);position:absolute!important;right:0;top:0}.van-action-sheet__loading{display:flex!important}

+ 1 - 0
src/wxcomponents/vant/area/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 217 - 0
src/wxcomponents/vant/area/index.js

@@ -0,0 +1,217 @@
+import { VantComponent } from '../common/component';
+import { pickerProps } from '../picker/shared';
+import { requestAnimationFrame } from '../common/utils';
+const EMPTY_CODE = '000000';
+VantComponent({
+    classes: ['active-class', 'toolbar-class', 'column-class'],
+    props: Object.assign(Object.assign({}, pickerProps), { value: {
+            type: String,
+            observer(value) {
+                this.code = value;
+                this.setValues();
+            },
+        }, areaList: {
+            type: Object,
+            value: {},
+            observer: 'setValues',
+        }, columnsNum: {
+            type: null,
+            value: 3,
+        }, columnsPlaceholder: {
+            type: Array,
+            observer(val) {
+                this.setData({
+                    typeToColumnsPlaceholder: {
+                        province: val[0] || '',
+                        city: val[1] || '',
+                        county: val[2] || '',
+                    },
+                });
+            },
+        } }),
+    data: {
+        columns: [{ values: [] }, { values: [] }, { values: [] }],
+        typeToColumnsPlaceholder: {},
+    },
+    mounted() {
+        requestAnimationFrame(() => {
+            this.setValues();
+        });
+    },
+    methods: {
+        getPicker() {
+            if (this.picker == null) {
+                this.picker = this.selectComponent('.van-area__picker');
+            }
+            return this.picker;
+        },
+        onCancel(event) {
+            this.emit('cancel', event.detail);
+        },
+        onConfirm(event) {
+            const { index } = event.detail;
+            let { value } = event.detail;
+            value = this.parseValues(value);
+            this.emit('confirm', { value, index });
+        },
+        emit(type, detail) {
+            detail.values = detail.value;
+            delete detail.value;
+            this.$emit(type, detail);
+        },
+        parseValues(values) {
+            const { columnsPlaceholder } = this.data;
+            return values.map((value, index) => {
+                if (value &&
+                    (!value.code || value.name === columnsPlaceholder[index])) {
+                    return Object.assign(Object.assign({}, value), { code: '', name: '' });
+                }
+                return value;
+            });
+        },
+        onChange(event) {
+            var _a;
+            const { index, picker, value } = event.detail;
+            this.code = value[index].code;
+            (_a = this.setValues()) === null || _a === void 0 ? void 0 : _a.then(() => {
+                this.$emit('change', {
+                    picker,
+                    values: this.parseValues(picker.getValues()),
+                    index,
+                });
+            });
+        },
+        getConfig(type) {
+            const { areaList } = this.data;
+            return (areaList && areaList[`${type}_list`]) || {};
+        },
+        getList(type, code) {
+            if (type !== 'province' && !code) {
+                return [];
+            }
+            const { typeToColumnsPlaceholder } = this.data;
+            const list = this.getConfig(type);
+            let result = Object.keys(list).map((code) => ({
+                code,
+                name: list[code],
+            }));
+            if (code != null) {
+                // oversea code
+                if (code[0] === '9' && type === 'city') {
+                    code = '9';
+                }
+                result = result.filter((item) => item.code.indexOf(code) === 0);
+            }
+            if (typeToColumnsPlaceholder[type] && result.length) {
+                // set columns placeholder
+                const codeFill = type === 'province'
+                    ? ''
+                    : type === 'city'
+                        ? EMPTY_CODE.slice(2, 4)
+                        : EMPTY_CODE.slice(4, 6);
+                result.unshift({
+                    code: `${code}${codeFill}`,
+                    name: typeToColumnsPlaceholder[type],
+                });
+            }
+            return result;
+        },
+        getIndex(type, code) {
+            let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
+            const list = this.getList(type, code.slice(0, compareNum - 2));
+            // oversea code
+            if (code[0] === '9' && type === 'province') {
+                compareNum = 1;
+            }
+            code = code.slice(0, compareNum);
+            for (let i = 0; i < list.length; i++) {
+                if (list[i].code.slice(0, compareNum) === code) {
+                    return i;
+                }
+            }
+            return 0;
+        },
+        setValues() {
+            const picker = this.getPicker();
+            if (!picker) {
+                return;
+            }
+            let code = this.code || this.getDefaultCode();
+            const provinceList = this.getList('province');
+            const cityList = this.getList('city', code.slice(0, 2));
+            const stack = [];
+            const indexes = [];
+            const { columnsNum } = this.data;
+            if (columnsNum >= 1) {
+                stack.push(picker.setColumnValues(0, provinceList, false));
+                indexes.push(this.getIndex('province', code));
+            }
+            if (columnsNum >= 2) {
+                stack.push(picker.setColumnValues(1, cityList, false));
+                indexes.push(this.getIndex('city', code));
+                if (cityList.length && code.slice(2, 4) === '00') {
+                    [{ code }] = cityList;
+                }
+            }
+            if (columnsNum === 3) {
+                stack.push(picker.setColumnValues(2, this.getList('county', code.slice(0, 4)), false));
+                indexes.push(this.getIndex('county', code));
+            }
+            return Promise.all(stack)
+                .catch(() => { })
+                .then(() => picker.setIndexes(indexes))
+                .catch(() => { });
+        },
+        getDefaultCode() {
+            const { columnsPlaceholder } = this.data;
+            if (columnsPlaceholder.length) {
+                return EMPTY_CODE;
+            }
+            const countyCodes = Object.keys(this.getConfig('county'));
+            if (countyCodes[0]) {
+                return countyCodes[0];
+            }
+            const cityCodes = Object.keys(this.getConfig('city'));
+            if (cityCodes[0]) {
+                return cityCodes[0];
+            }
+            return '';
+        },
+        getValues() {
+            const picker = this.getPicker();
+            if (!picker) {
+                return [];
+            }
+            return this.parseValues(picker.getValues().filter((value) => !!value));
+        },
+        getDetail() {
+            const values = this.getValues();
+            const area = {
+                code: '',
+                country: '',
+                province: '',
+                city: '',
+                county: '',
+            };
+            if (!values.length) {
+                return area;
+            }
+            const names = values.map((item) => item.name);
+            area.code = values[values.length - 1].code;
+            if (area.code[0] === '9') {
+                area.country = names[1] || '';
+                area.province = names[2] || '';
+            }
+            else {
+                area.province = names[0] || '';
+                area.city = names[1] || '';
+                area.county = names[2] || '';
+            }
+            return area;
+        },
+        reset(code) {
+            this.code = code || '';
+            return this.setValues();
+        },
+    },
+});

+ 6 - 0
src/wxcomponents/vant/area/index.json

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

+ 20 - 0
src/wxcomponents/vant/area/index.wxml

@@ -0,0 +1,20 @@
+<wxs src="./index.wxs" module="computed" />
+
+<van-picker
+  class="van-area__picker"
+  active-class="active-class"
+  toolbar-class="toolbar-class"
+  column-class="column-class"
+  show-toolbar
+  value-key="name"
+  title="{{ title }}"
+  loading="{{ loading }}"
+  columns="{{ computed.displayColumns(columns, columnsNum) }}"
+  item-height="{{ itemHeight }}"
+  visible-item-count="{{ visibleItemCount }}"
+  cancel-button-text="{{ cancelButtonText }}"
+  confirm-button-text="{{ confirmButtonText }}"
+  bind:change="onChange"
+  bind:confirm="onConfirm"
+  bind:cancel="onCancel"
+/>

+ 8 - 0
src/wxcomponents/vant/area/index.wxs

@@ -0,0 +1,8 @@
+/* eslint-disable */
+function displayColumns(columns, columnsNum) {
+  return columns.slice(0, +columnsNum);
+}
+
+module.exports = {
+  displayColumns: displayColumns,
+};

+ 1 - 0
src/wxcomponents/vant/area/index.wxss

@@ -0,0 +1 @@
+@import '../common/index.wxss';

+ 1 - 0
src/wxcomponents/vant/button/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 64 - 0
src/wxcomponents/vant/button/index.js

@@ -0,0 +1,64 @@
+import { VantComponent } from '../common/component';
+import { button } from '../mixins/button';
+import { canIUseFormFieldButton } from '../common/version';
+const mixins = [button];
+if (canIUseFormFieldButton()) {
+    mixins.push('wx://form-field-button');
+}
+VantComponent({
+    mixins,
+    classes: ['hover-class', 'loading-class'],
+    data: {
+        baseStyle: '',
+    },
+    props: {
+        formType: String,
+        icon: String,
+        classPrefix: {
+            type: String,
+            value: 'van-icon',
+        },
+        plain: Boolean,
+        block: Boolean,
+        round: Boolean,
+        square: Boolean,
+        loading: Boolean,
+        hairline: Boolean,
+        disabled: Boolean,
+        loadingText: String,
+        customStyle: String,
+        loadingType: {
+            type: String,
+            value: 'circular',
+        },
+        type: {
+            type: String,
+            value: 'default',
+        },
+        dataset: null,
+        size: {
+            type: String,
+            value: 'normal',
+        },
+        loadingSize: {
+            type: String,
+            value: '20px',
+        },
+        color: String,
+    },
+    methods: {
+        onClick(event) {
+            this.$emit('click', event);
+            const { canIUseGetUserProfile, openType, getUserProfileDesc, lang, } = this.data;
+            if (openType === 'getUserInfo' && canIUseGetUserProfile) {
+                wx.getUserProfile({
+                    desc: getUserProfileDesc || '  ',
+                    lang: lang || 'en',
+                    complete: (userProfile) => {
+                        this.$emit('getuserinfo', userProfile);
+                    },
+                });
+            }
+        },
+    },
+});

+ 7 - 0
src/wxcomponents/vant/button/index.json

@@ -0,0 +1,7 @@
+{
+  "component": true,
+  "usingComponents": {
+    "van-icon": "../icon/index",
+    "van-loading": "../loading/index"
+  }
+}

+ 53 - 0
src/wxcomponents/vant/button/index.wxml

@@ -0,0 +1,53 @@
+<wxs src="../wxs/utils.wxs" module="utils" />
+<wxs src="./index.wxs" module="computed" />
+
+<button
+  id="{{ id }}"
+  data-detail="{{ dataset }}"
+  class="custom-class {{ utils.bem('button', [type, size, { block, round, plain, square, loading, disabled, hairline, unclickable: disabled || loading }]) }} {{ hairline ? 'van-hairline--surround' : '' }}"
+  hover-class="van-button--active hover-class"
+  lang="{{ lang }}"
+  form-type="{{ formType }}"
+  style="{{ computed.rootStyle({ plain, color, customStyle }) }}"
+  open-type="{{ disabled || loading || (canIUseGetUserProfile && openType === 'getUserInfo') ? '' : openType }}"
+  business-id="{{ businessId }}"
+  session-from="{{ sessionFrom }}"
+  send-message-title="{{ sendMessageTitle }}"
+  send-message-path="{{ sendMessagePath }}"
+  send-message-img="{{ sendMessageImg }}"
+  show-message-card="{{ showMessageCard }}"
+  app-parameter="{{ appParameter }}"
+  aria-label="{{ ariaLabel }}"
+  bindtap="{{ disabled || loading ? '' : 'onClick' }}"
+  bindgetuserinfo="onGetUserInfo"
+  bindcontact="onContact"
+  bindgetphonenumber="onGetPhoneNumber"
+  binderror="onError"
+  bindlaunchapp="onLaunchApp"
+  bindopensetting="onOpenSetting"
+>
+  <block wx:if="{{ loading }}">
+    <van-loading
+      custom-class="loading-class"
+      size="{{ loadingSize }}"
+      type="{{ loadingType }}"
+      color="{{ computed.loadingColor({ type, color, plain }) }}"
+    />
+    <view wx:if="{{ loadingText }}" class="van-button__loading-text">
+      {{ loadingText }}
+    </view>
+  </block>
+  <block wx:else>
+    <van-icon
+      wx:if="{{ icon }}"
+      size="1.2em"
+      name="{{ icon }}"
+      class-prefix="{{ classPrefix }}"
+      class="van-button__icon"
+      custom-style="line-height: inherit;"
+    />
+    <view class="van-button__text">
+      <slot />
+    </view>
+  </block>
+</button>

+ 39 - 0
src/wxcomponents/vant/button/index.wxs

@@ -0,0 +1,39 @@
+/* eslint-disable */
+var style = require('../wxs/style.wxs');
+
+function rootStyle(data) {
+  if (!data.color) {
+    return data.customStyle;
+  }
+
+  var properties = {
+    color: data.plain ? data.color : '#fff',
+    background: data.plain ? null : data.color,
+  };
+
+  // hide border when color is linear-gradient
+  if (data.color.indexOf('gradient') !== -1) {
+    properties.border = 0;
+  } else {
+    properties['border-color'] = data.color;
+  }
+
+  return style([properties, data.customStyle]);
+}
+
+function loadingColor(data) {
+  if (data.plain) {
+    return data.color ? data.color : '#c9c9c9';
+  }
+
+  if (data.type === 'default') {
+    return '#c9c9c9';
+  }
+
+  return '#fff';
+}
+
+module.exports = {
+  rootStyle: rootStyle,
+  loadingColor: loadingColor,
+};

文件差異過大導致無法顯示
+ 0 - 0
src/wxcomponents/vant/button/index.wxss


+ 68 - 0
src/wxcomponents/vant/calendar/calendar.wxml

@@ -0,0 +1,68 @@
+<view class="van-calendar">
+  <header
+    title="{{ title }}"
+    showTitle="{{ showTitle }}"
+    subtitle="{{ subtitle }}"
+    showSubtitle="{{ showSubtitle }}"
+    firstDayOfWeek="{{ firstDayOfWeek }}"
+    bind:click-subtitle="onClickSubtitle"
+  >
+    <slot name="title" slot="title"></slot>
+  </header>
+
+  <scroll-view
+    class="van-calendar__body"
+    scroll-y
+    scroll-into-view="{{ scrollIntoView }}"
+  >
+    <month
+      wx:for="{{ computed.getMonths(minDate, maxDate) }}"
+      wx:key="index"
+      id="month{{ index }}"
+      class="month"
+      data-date="{{ item }}"
+      date="{{ item }}"
+      type="{{ type }}"
+      color="{{ color }}"
+      minDate="{{ minDate }}"
+      maxDate="{{ maxDate }}"
+      showMark="{{ showMark }}"
+      formatter="{{ formatter }}"
+      rowHeight="{{ rowHeight }}"
+      currentDate="{{ currentDate }}"
+      showSubtitle="{{ showSubtitle }}"
+      allowSameDay="{{ allowSameDay }}"
+      showMonthTitle="{{ index !== 0 || !showSubtitle }}"
+      firstDayOfWeek="{{ firstDayOfWeek }}"
+      bind:click="onClickDay"
+    />
+  </scroll-view>
+
+  <view
+    class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}"
+  >
+    <slot name="footer"></slot>
+  </view>
+
+  <view
+    class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}"
+  >
+    <van-button
+      wx:if="{{ showConfirm }}"
+      round
+      block
+      type="danger"
+      color="{{ color }}"
+      custom-class="van-calendar__confirm"
+      disabled="{{ computed.getButtonDisabled(type, currentDate) }}"
+      nativeType="text"
+      bind:click="onConfirm"
+    >
+      {{
+        computed.getButtonDisabled(type, currentDate)
+          ? confirmDisabledText
+          : confirmText
+      }}
+    </van-button>
+  </view>
+</view>

+ 1 - 0
src/wxcomponents/vant/calendar/components/header/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 37 - 0
src/wxcomponents/vant/calendar/components/header/index.js

@@ -0,0 +1,37 @@
+import { VantComponent } from '../../../common/component';
+VantComponent({
+    props: {
+        title: {
+            type: String,
+            value: '日期选择',
+        },
+        subtitle: String,
+        showTitle: Boolean,
+        showSubtitle: Boolean,
+        firstDayOfWeek: {
+            type: Number,
+            observer: 'initWeekDay',
+        },
+    },
+    data: {
+        weekdays: [],
+    },
+    created() {
+        this.initWeekDay();
+    },
+    methods: {
+        initWeekDay() {
+            const defaultWeeks = ['日', '一', '二', '三', '四', '五', '六'];
+            const firstDayOfWeek = this.data.firstDayOfWeek || 0;
+            this.setData({
+                weekdays: [
+                    ...defaultWeeks.slice(firstDayOfWeek, 7),
+                    ...defaultWeeks.slice(0, firstDayOfWeek),
+                ],
+            });
+        },
+        onClickSubtitle(event) {
+            this.$emit('click-subtitle', event);
+        },
+    },
+});

+ 3 - 0
src/wxcomponents/vant/calendar/components/header/index.json

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

+ 16 - 0
src/wxcomponents/vant/calendar/components/header/index.wxml

@@ -0,0 +1,16 @@
+<view class="van-calendar__header">
+  <block wx:if="{{ showTitle }}">
+    <view class="van-calendar__header-title"><slot name="title"></slot></view>
+    <view class="van-calendar__header-title">{{ title }}</view>
+  </block>
+
+  <view wx:if="{{ showSubtitle }}" class="van-calendar__header-subtitle" bind:tap="onClickSubtitle">
+    {{ subtitle }}
+  </view>
+
+  <view class="van-calendar__weekdays">
+    <view wx:for="{{ weekdays }}" wx:key="index" class="van-calendar__weekday">
+      {{ item }}
+    </view>
+  </view>
+</view>

+ 1 - 0
src/wxcomponents/vant/calendar/components/header/index.wxss

@@ -0,0 +1 @@
+@import '../../../common/index.wxss';.van-calendar__header{box-shadow:var(--calendar-header-box-shadow,0 2px 10px hsla(220,1%,50%,.16));flex-shrink:0}.van-calendar__header-subtitle,.van-calendar__header-title{font-weight:var(--font-weight-bold,500);height:var(--calendar-header-title-height,44px);line-height:var(--calendar-header-title-height,44px);text-align:center}.van-calendar__header-title+.van-calendar__header-title,.van-calendar__header-title:empty{display:none}.van-calendar__header-title:empty+.van-calendar__header-title{display:block!important}.van-calendar__weekdays{display:flex}.van-calendar__weekday{flex:1;font-size:var(--calendar-weekdays-font-size,12px);line-height:var(--calendar-weekdays-height,30px);text-align:center}

+ 6 - 0
src/wxcomponents/vant/calendar/components/month/index.d.ts

@@ -0,0 +1,6 @@
+export interface Day {
+    date: Date;
+    type: string;
+    text: number;
+    bottomInfo?: string;
+}

+ 154 - 0
src/wxcomponents/vant/calendar/components/month/index.js

@@ -0,0 +1,154 @@
+import { VantComponent } from '../../../common/component';
+import { getMonthEndDay, compareDay, getPrevDay, getNextDay, } from '../../utils';
+VantComponent({
+    props: {
+        date: {
+            type: null,
+            observer: 'setDays',
+        },
+        type: {
+            type: String,
+            observer: 'setDays',
+        },
+        color: String,
+        minDate: {
+            type: null,
+            observer: 'setDays',
+        },
+        maxDate: {
+            type: null,
+            observer: 'setDays',
+        },
+        showMark: Boolean,
+        rowHeight: null,
+        formatter: {
+            type: null,
+            observer: 'setDays',
+        },
+        currentDate: {
+            type: null,
+            observer: 'setDays',
+        },
+        firstDayOfWeek: {
+            type: Number,
+            observer: 'setDays',
+        },
+        allowSameDay: Boolean,
+        showSubtitle: Boolean,
+        showMonthTitle: Boolean,
+    },
+    data: {
+        visible: true,
+        days: [],
+    },
+    methods: {
+        onClick(event) {
+            const { index } = event.currentTarget.dataset;
+            const item = this.data.days[index];
+            if (item.type !== 'disabled') {
+                this.$emit('click', item);
+            }
+        },
+        setDays() {
+            const days = [];
+            const startDate = new Date(this.data.date);
+            const year = startDate.getFullYear();
+            const month = startDate.getMonth();
+            const totalDay = getMonthEndDay(startDate.getFullYear(), startDate.getMonth() + 1);
+            for (let day = 1; day <= totalDay; day++) {
+                const date = new Date(year, month, day);
+                const type = this.getDayType(date);
+                let config = {
+                    date,
+                    type,
+                    text: day,
+                    bottomInfo: this.getBottomInfo(type),
+                };
+                if (this.data.formatter) {
+                    config = this.data.formatter(config);
+                }
+                days.push(config);
+            }
+            this.setData({ days });
+        },
+        getMultipleDayType(day) {
+            const { currentDate } = this.data;
+            if (!Array.isArray(currentDate)) {
+                return '';
+            }
+            const isSelected = (date) => currentDate.some((item) => compareDay(item, date) === 0);
+            if (isSelected(day)) {
+                const prevDay = getPrevDay(day);
+                const nextDay = getNextDay(day);
+                const prevSelected = isSelected(prevDay);
+                const nextSelected = isSelected(nextDay);
+                if (prevSelected && nextSelected) {
+                    return 'multiple-middle';
+                }
+                if (prevSelected) {
+                    return 'end';
+                }
+                return nextSelected ? 'start' : 'multiple-selected';
+            }
+            return '';
+        },
+        getRangeDayType(day) {
+            const { currentDate, allowSameDay } = this.data;
+            if (!Array.isArray(currentDate)) {
+                return '';
+            }
+            const [startDay, endDay] = currentDate;
+            if (!startDay) {
+                return '';
+            }
+            const compareToStart = compareDay(day, startDay);
+            if (!endDay) {
+                return compareToStart === 0 ? 'start' : '';
+            }
+            const compareToEnd = compareDay(day, endDay);
+            if (compareToStart === 0 && compareToEnd === 0 && allowSameDay) {
+                return 'start-end';
+            }
+            if (compareToStart === 0) {
+                return 'start';
+            }
+            if (compareToEnd === 0) {
+                return 'end';
+            }
+            if (compareToStart > 0 && compareToEnd < 0) {
+                return 'middle';
+            }
+            return '';
+        },
+        getDayType(day) {
+            const { type, minDate, maxDate, currentDate } = this.data;
+            if (compareDay(day, minDate) < 0 || compareDay(day, maxDate) > 0) {
+                return 'disabled';
+            }
+            if (type === 'single') {
+                return compareDay(day, currentDate) === 0 ? 'selected' : '';
+            }
+            if (type === 'multiple') {
+                return this.getMultipleDayType(day);
+            }
+            /* istanbul ignore else */
+            if (type === 'range') {
+                return this.getRangeDayType(day);
+            }
+            return '';
+        },
+        getBottomInfo(type) {
+            if (this.data.type === 'range') {
+                if (type === 'start') {
+                    return '开始';
+                }
+                if (type === 'end') {
+                    return '结束';
+                }
+                if (type === 'start-end') {
+                    return '开始/结束';
+                }
+            }
+        },
+    },
+});

+ 3 - 0
src/wxcomponents/vant/calendar/components/month/index.json

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

+ 39 - 0
src/wxcomponents/vant/calendar/components/month/index.wxml

@@ -0,0 +1,39 @@
+<wxs src="./index.wxs" module="computed"></wxs>
+<wxs src="../../../wxs/utils.wxs" module="utils" />
+
+<view class="van-calendar__month" style="{{ computed.getMonthStyle(visible, date, rowHeight) }}">
+  <view wx:if="{{ showMonthTitle }}" class="van-calendar__month-title">
+    {{ computed.formatMonthTitle(date) }}
+  </view>
+
+  <view wx:if="{{ visible }}" class="van-calendar__days">
+    <view wx:if="{{ showMark }}" class="van-calendar__month-mark">
+      {{ computed.getMark(date) }}
+    </view>
+
+    <view
+      wx:for="{{ days }}"
+      wx:key="index"
+      style="{{ computed.getDayStyle(item.type, index, date, rowHeight, color, firstDayOfWeek) }}"
+      class="{{ utils.bem('calendar__day', [item.type]) }} {{ item.className }}"
+      data-index="{{ index }}"
+      bindtap="onClick"
+    >
+      <view wx:if="{{ item.type === 'selected' }}" class="van-calendar__selected-day" style="background: {{ color }}">
+        <view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view>
+        {{ item.text }}
+        <view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info">
+          {{ item.bottomInfo }}
+        </view>
+      </view>
+
+      <view wx:else>
+        <view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view>
+        {{ item.text }}
+        <view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info">
+          {{ item.bottomInfo }}
+        </view>
+      </view>
+    </view>
+  </view>
+</view>

+ 71 - 0
src/wxcomponents/vant/calendar/components/month/index.wxs

@@ -0,0 +1,71 @@
+/* eslint-disable */
+var utils = require('../../utils.wxs');
+
+function getMark(date) {
+  return getDate(date).getMonth() + 1;
+}
+
+var ROW_HEIGHT = 64;
+
+function getDayStyle(type, index, date, rowHeight, color, firstDayOfWeek) {
+  var style = [];
+  var current = getDate(date).getDay() || 7;
+  var offset = current < firstDayOfWeek ? (7 - firstDayOfWeek + current) :
+               current === 7 && firstDayOfWeek === 0 ? 0 :
+               (current - firstDayOfWeek);
+
+  if (index === 0) {
+    style.push(['margin-left', (100 * offset) / 7 + '%']);
+  }
+
+  if (rowHeight !== ROW_HEIGHT) {
+    style.push(['height', rowHeight + 'px']);
+  }
+
+  if (color) {
+    if (
+      type === 'start' ||
+      type === 'end' ||
+      type === 'start-end' ||
+      type === 'multiple-selected' ||
+      type === 'multiple-middle'
+    ) {
+      style.push(['background', color]);
+    } else if (type === 'middle') {
+      style.push(['color', color]);
+    }
+  }
+
+  return style
+    .map(function(item) {
+      return item.join(':');
+    })
+    .join(';');
+}
+
+function formatMonthTitle(date) {
+  date = getDate(date);
+  return date.getFullYear() + '年' + (date.getMonth() + 1) + '月';
+}
+
+function getMonthStyle(visible, date, rowHeight) {
+  if (!visible) {
+    date = getDate(date);
+
+    var totalDay = utils.getMonthEndDay(
+      date.getFullYear(),
+      date.getMonth() + 1
+    );
+    var offset = getDate(date).getDay();
+    var padding = Math.ceil((totalDay + offset) / 7) * rowHeight;
+
+    return 'padding-bottom:' + padding + 'px';
+  }
+}
+
+module.exports = {
+  getMark: getMark,
+  getDayStyle: getDayStyle,
+  formatMonthTitle: formatMonthTitle,
+  getMonthStyle: getMonthStyle
+};

文件差異過大導致無法顯示
+ 0 - 0
src/wxcomponents/vant/calendar/components/month/index.wxss


+ 1 - 0
src/wxcomponents/vant/calendar/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 337 - 0
src/wxcomponents/vant/calendar/index.js

@@ -0,0 +1,337 @@
+import { VantComponent } from '../common/component';
+import { ROW_HEIGHT, getPrevDay, getNextDay, getToday, compareDay, copyDates, calcDateNum, formatMonthTitle, compareMonth, getMonths, getDayByOffset, } from './utils';
+import Toast from '../toast/toast';
+import { requestAnimationFrame } from '../common/utils';
+const initialMinDate = getToday().getTime();
+const initialMaxDate = (() => {
+    const now = getToday();
+    return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate()).getTime();
+})();
+const getTime = (date) => date instanceof Date ? date.getTime() : date;
+VantComponent({
+    props: {
+        title: {
+            type: String,
+            value: '日期选择',
+        },
+        color: String,
+        show: {
+            type: Boolean,
+            observer(val) {
+                if (val) {
+                    this.initRect();
+                    this.scrollIntoView();
+                }
+            },
+        },
+        formatter: null,
+        confirmText: {
+            type: String,
+            value: '确定',
+        },
+        confirmDisabledText: {
+            type: String,
+            value: '确定',
+        },
+        rangePrompt: String,
+        showRangePrompt: {
+            type: Boolean,
+            value: true,
+        },
+        defaultDate: {
+            type: null,
+            observer(val) {
+                this.setData({ currentDate: val });
+                this.scrollIntoView();
+            },
+        },
+        allowSameDay: Boolean,
+        type: {
+            type: String,
+            value: 'single',
+            observer: 'reset',
+        },
+        minDate: {
+            type: Number,
+            value: initialMinDate,
+        },
+        maxDate: {
+            type: Number,
+            value: initialMaxDate,
+        },
+        position: {
+            type: String,
+            value: 'bottom',
+        },
+        rowHeight: {
+            type: null,
+            value: ROW_HEIGHT,
+        },
+        round: {
+            type: Boolean,
+            value: true,
+        },
+        poppable: {
+            type: Boolean,
+            value: true,
+        },
+        showMark: {
+            type: Boolean,
+            value: true,
+        },
+        showTitle: {
+            type: Boolean,
+            value: true,
+        },
+        showConfirm: {
+            type: Boolean,
+            value: true,
+        },
+        showSubtitle: {
+            type: Boolean,
+            value: true,
+        },
+        safeAreaInsetBottom: {
+            type: Boolean,
+            value: true,
+        },
+        closeOnClickOverlay: {
+            type: Boolean,
+            value: true,
+        },
+        maxRange: {
+            type: null,
+            value: null,
+        },
+        firstDayOfWeek: {
+            type: Number,
+            value: 0,
+        },
+        readonly: Boolean,
+    },
+    data: {
+        subtitle: '',
+        currentDate: null,
+        scrollIntoView: '',
+    },
+    created() {
+        this.setData({
+            currentDate: this.getInitialDate(this.data.defaultDate),
+        });
+    },
+    mounted() {
+        if (this.data.show || !this.data.poppable) {
+            this.initRect();
+            this.scrollIntoView();
+        }
+    },
+    methods: {
+        reset() {
+            this.setData({ currentDate: this.getInitialDate() });
+            this.scrollIntoView();
+        },
+        initRect() {
+            if (this.contentObserver != null) {
+                this.contentObserver.disconnect();
+            }
+            const contentObserver = this.createIntersectionObserver({
+                thresholds: [0, 0.1, 0.9, 1],
+                observeAll: true,
+            });
+            this.contentObserver = contentObserver;
+            contentObserver.relativeTo('.van-calendar__body');
+            contentObserver.observe('.month', (res) => {
+                if (res.boundingClientRect.top <= res.relativeRect.top) {
+                    // @ts-ignore
+                    this.setData({ subtitle: formatMonthTitle(res.dataset.date) });
+                }
+            });
+        },
+        limitDateRange(date, minDate = null, maxDate = null) {
+            minDate = minDate || this.data.minDate;
+            maxDate = maxDate || this.data.maxDate;
+            if (compareDay(date, minDate) === -1) {
+                return minDate;
+            }
+            if (compareDay(date, maxDate) === 1) {
+                return maxDate;
+            }
+            return date;
+        },
+        getInitialDate(defaultDate = null) {
+            const { type, minDate, maxDate } = this.data;
+            const now = getToday().getTime();
+            if (type === 'range') {
+                if (!Array.isArray(defaultDate)) {
+                    defaultDate = [];
+                }
+                const [startDay, endDay] = defaultDate || [];
+                const start = this.limitDateRange(startDay || now, minDate, getPrevDay(new Date(maxDate)).getTime());
+                const end = this.limitDateRange(endDay || now, getNextDay(new Date(minDate)).getTime());
+                return [start, end];
+            }
+            if (type === 'multiple') {
+                if (Array.isArray(defaultDate)) {
+                    return defaultDate.map((date) => this.limitDateRange(date));
+                }
+                return [this.limitDateRange(now)];
+            }
+            if (!defaultDate || Array.isArray(defaultDate)) {
+                defaultDate = now;
+            }
+            return this.limitDateRange(defaultDate);
+        },
+        scrollIntoView() {
+            requestAnimationFrame(() => {
+                const { currentDate, type, show, poppable, minDate, maxDate } = this.data;
+                // @ts-ignore
+                const targetDate = type === 'single' ? currentDate : currentDate[0];
+                const displayed = show || !poppable;
+                if (!targetDate || !displayed) {
+                    return;
+                }
+                const months = getMonths(minDate, maxDate);
+                months.some((month, index) => {
+                    if (compareMonth(month, targetDate) === 0) {
+                        this.setData({ scrollIntoView: `month${index}` });
+                        return true;
+                    }
+                    return false;
+                });
+            });
+        },
+        onOpen() {
+            this.$emit('open');
+        },
+        onOpened() {
+            this.$emit('opened');
+        },
+        onClose() {
+            this.$emit('close');
+        },
+        onClosed() {
+            this.$emit('closed');
+        },
+        onClickDay(event) {
+            if (this.data.readonly) {
+                return;
+            }
+            let { date } = event.detail;
+            const { type, currentDate, allowSameDay } = this.data;
+            if (type === 'range') {
+                // @ts-ignore
+                const [startDay, endDay] = currentDate;
+                if (startDay && !endDay) {
+                    const compareToStart = compareDay(date, startDay);
+                    if (compareToStart === 1) {
+                        const { days } = this.selectComponent('.month').data;
+                        days.some((day, index) => {
+                            const isDisabled = day.type === 'disabled' &&
+                                getTime(startDay) < getTime(day.date) &&
+                                getTime(day.date) < getTime(date);
+                            if (isDisabled) {
+                                ({ date } = days[index - 1]);
+                            }
+                            return isDisabled;
+                        });
+                        this.select([startDay, date], true);
+                    }
+                    else if (compareToStart === -1) {
+                        this.select([date, null]);
+                    }
+                    else if (allowSameDay) {
+                        this.select([date, date]);
+                    }
+                }
+                else {
+                    this.select([date, null]);
+                }
+            }
+            else if (type === 'multiple') {
+                let selectedIndex;
+                // @ts-ignore
+                const selected = currentDate.some((dateItem, index) => {
+                    const equal = compareDay(dateItem, date) === 0;
+                    if (equal) {
+                        selectedIndex = index;
+                    }
+                    return equal;
+                });
+                if (selected) {
+                    // @ts-ignore
+                    const cancelDate = currentDate.splice(selectedIndex, 1);
+                    this.setData({ currentDate });
+                    this.unselect(cancelDate);
+                }
+                else {
+                    // @ts-ignore
+                    this.select([...currentDate, date]);
+                }
+            }
+            else {
+                this.select(date, true);
+            }
+        },
+        unselect(dateArray) {
+            const date = dateArray[0];
+            if (date) {
+                this.$emit('unselect', copyDates(date));
+            }
+        },
+        select(date, complete) {
+            if (complete && this.data.type === 'range') {
+                const valid = this.checkRange(date);
+                if (!valid) {
+                    // auto selected to max range if showConfirm
+                    if (this.data.showConfirm) {
+                        this.emit([
+                            date[0],
+                            getDayByOffset(date[0], this.data.maxRange - 1),
+                        ]);
+                    }
+                    else {
+                        this.emit(date);
+                    }
+                    return;
+                }
+            }
+            this.emit(date);
+            if (complete && !this.data.showConfirm) {
+                this.onConfirm();
+            }
+        },
+        emit(date) {
+            this.setData({
+                currentDate: Array.isArray(date) ? date.map(getTime) : getTime(date),
+            });
+            this.$emit('select', copyDates(date));
+        },
+        checkRange(date) {
+            const { maxRange, rangePrompt, showRangePrompt } = this.data;
+            if (maxRange && calcDateNum(date) > maxRange) {
+                if (showRangePrompt) {
+                    Toast({
+                        context: this,
+                        message: rangePrompt || `选择天数不能超过 ${maxRange} 天`,
+                    });
+                }
+                this.$emit('over-range');
+                return false;
+            }
+            return true;
+        },
+        onConfirm() {
+            if (this.data.type === 'range' &&
+                !this.checkRange(this.data.currentDate)) {
+                return;
+            }
+            wx.nextTick(() => {
+                // @ts-ignore
+                this.$emit('confirm', copyDates(this.data.currentDate));
+            });
+        },
+        onClickSubtitle(event) {
+            this.$emit('click-subtitle', event);
+        },
+    },
+});

+ 10 - 0
src/wxcomponents/vant/calendar/index.json

@@ -0,0 +1,10 @@
+{
+  "component": true,
+  "usingComponents": {
+    "header": "./components/header/index",
+    "month": "./components/month/index",
+    "van-button": "../button/index",
+    "van-popup": "../popup/index",
+    "van-toast": "../toast/index"
+  }
+}

+ 25 - 0
src/wxcomponents/vant/calendar/index.wxml

@@ -0,0 +1,25 @@
+<wxs src="./index.wxs" module="computed" />
+<wxs src="../wxs/utils.wxs" module="utils" />
+
+<import src="./calendar.wxml" />
+
+<van-popup
+  wx:if="{{ poppable }}"
+  custom-class="van-calendar__popup--{{ position }}"
+  close-icon-class="van-calendar__close-icon"
+  show="{{ show }}"
+  round="{{ round }}"
+  position="{{ position }}"
+  closeable="{{ showTitle || showSubtitle }}"
+  close-on-click-overlay="{{ closeOnClickOverlay }}"
+  bind:enter="onOpen"
+  bind:close="onClose"
+  bind:after-enter="onOpened"
+  bind:after-leave="onClosed"
+>
+  <include src="./calendar.wxml" />
+</van-popup>
+
+<include wx:else src="./calendar.wxml" />
+
+<van-toast id="van-toast" />

+ 37 - 0
src/wxcomponents/vant/calendar/index.wxs

@@ -0,0 +1,37 @@
+/* eslint-disable */
+var utils = require('./utils.wxs');
+
+function getMonths(minDate, maxDate) {
+  var months = [];
+  var cursor = getDate(minDate);
+
+  cursor.setDate(1);
+
+  do {
+    months.push(cursor.getTime());
+    cursor.setMonth(cursor.getMonth() + 1);
+  } while (utils.compareMonth(cursor, getDate(maxDate)) !== 1);
+
+  return months;
+}
+
+function getButtonDisabled(type, currentDate) {
+  if (currentDate == null) {
+    return true;
+  }
+
+  if (type === 'range') {
+    return !currentDate[0] || !currentDate[1];
+  }
+
+  if (type === 'multiple') {
+    return !currentDate.length;
+  }
+
+  return !currentDate;
+}
+
+module.exports = {
+  getMonths: getMonths,
+  getButtonDisabled: getButtonDisabled
+};

+ 1 - 0
src/wxcomponents/vant/calendar/index.wxss

@@ -0,0 +1 @@
+@import '../common/index.wxss';.van-calendar{background-color:var(--calendar-background-color,#fff);display:flex;flex-direction:column;height:var(--calendar-height,100%)}.van-calendar__close-icon{top:11px}.van-calendar__popup--bottom,.van-calendar__popup--top{height:var(--calendar-popup-height,80%)}.van-calendar__popup--left,.van-calendar__popup--right{height:100%}.van-calendar__body{-webkit-overflow-scrolling:touch;flex:1;overflow:auto}.van-calendar__footer{flex-shrink:0;padding:0 var(--padding-md,16px)}.van-calendar__footer--safe-area-inset-bottom{padding-bottom:env(safe-area-inset-bottom)}.van-calendar__footer+.van-calendar__footer,.van-calendar__footer:empty{display:none}.van-calendar__footer:empty+.van-calendar__footer{display:block!important}.van-calendar__confirm{height:var(--calendar-confirm-button-height,36px)!important;line-height:var(--calendar-confirm-button-line-height,34px)!important;margin:var(--calendar-confirm-button-margin,7px 0)!important}

+ 12 - 0
src/wxcomponents/vant/calendar/utils.d.ts

@@ -0,0 +1,12 @@
+export declare const ROW_HEIGHT = 64;
+export declare function formatMonthTitle(date: Date): string;
+export declare function compareMonth(date1: Date | number, date2: Date | number): 1 | -1 | 0;
+export declare function compareDay(day1: Date | number, day2: Date | number): 1 | -1 | 0;
+export declare function getDayByOffset(date: Date, offset: number): Date;
+export declare function getPrevDay(date: Date): Date;
+export declare function getNextDay(date: Date): Date;
+export declare function getToday(): Date;
+export declare function calcDateNum(date: [Date, Date]): number;
+export declare function copyDates(dates: Date | Date[]): Date | Date[];
+export declare function getMonthEndDay(year: number, month: number): number;
+export declare function getMonths(minDate: number, maxDate: number): number[];

+ 83 - 0
src/wxcomponents/vant/calendar/utils.js

@@ -0,0 +1,83 @@
+export const ROW_HEIGHT = 64;
+export function formatMonthTitle(date) {
+    if (!(date instanceof Date)) {
+        date = new Date(date);
+    }
+    return `${date.getFullYear()}年${date.getMonth() + 1}月`;
+}
+export function compareMonth(date1, date2) {
+    if (!(date1 instanceof Date)) {
+        date1 = new Date(date1);
+    }
+    if (!(date2 instanceof Date)) {
+        date2 = new Date(date2);
+    }
+    const year1 = date1.getFullYear();
+    const year2 = date2.getFullYear();
+    const month1 = date1.getMonth();
+    const month2 = date2.getMonth();
+    if (year1 === year2) {
+        return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
+    }
+    return year1 > year2 ? 1 : -1;
+}
+export function compareDay(day1, day2) {
+    if (!(day1 instanceof Date)) {
+        day1 = new Date(day1);
+    }
+    if (!(day2 instanceof Date)) {
+        day2 = new Date(day2);
+    }
+    const compareMonthResult = compareMonth(day1, day2);
+    if (compareMonthResult === 0) {
+        const date1 = day1.getDate();
+        const date2 = day2.getDate();
+        return date1 === date2 ? 0 : date1 > date2 ? 1 : -1;
+    }
+    return compareMonthResult;
+}
+export function getDayByOffset(date, offset) {
+    date = new Date(date);
+    date.setDate(date.getDate() + offset);
+    return date;
+}
+export function getPrevDay(date) {
+    return getDayByOffset(date, -1);
+}
+export function getNextDay(date) {
+    return getDayByOffset(date, 1);
+}
+export function getToday() {
+    const today = new Date();
+    today.setHours(0, 0, 0, 0);
+    return today;
+}
+export function calcDateNum(date) {
+    const day1 = new Date(date[0]).getTime();
+    const day2 = new Date(date[1]).getTime();
+    return (day2 - day1) / (1000 * 60 * 60 * 24) + 1;
+}
+export function copyDates(dates) {
+    if (Array.isArray(dates)) {
+        return dates.map((date) => {
+            if (date === null) {
+                return date;
+            }
+            return new Date(date);
+        });
+    }
+    return new Date(dates);
+}
+export function getMonthEndDay(year, month) {
+    return 32 - new Date(year, month - 1, 32).getDate();
+}
+export function getMonths(minDate, maxDate) {
+    const months = [];
+    const cursor = new Date(minDate);
+    cursor.setDate(1);
+    do {
+        months.push(cursor.getTime());
+        cursor.setMonth(cursor.getMonth() + 1);
+    } while (compareMonth(cursor, maxDate) !== 1);
+    return months;
+}

+ 25 - 0
src/wxcomponents/vant/calendar/utils.wxs

@@ -0,0 +1,25 @@
+/* eslint-disable */
+function getMonthEndDay(year, month) {
+  return 32 -  getDate(year, month - 1, 32).getDate();
+}
+
+function compareMonth(date1, date2) {
+  date1 = getDate(date1);
+  date2 = getDate(date2);
+
+  var year1 = date1.getFullYear();
+  var year2 = date2.getFullYear();
+  var month1 = date1.getMonth();
+  var month2 = date2.getMonth();
+
+  if (year1 === year2) {
+    return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
+  }
+
+  return year1 > year2 ? 1 : -1;
+}
+
+module.exports = {
+  getMonthEndDay: getMonthEndDay,
+  compareMonth: compareMonth
+};

+ 1 - 0
src/wxcomponents/vant/card/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 49 - 0
src/wxcomponents/vant/card/index.js

@@ -0,0 +1,49 @@
+import { link } from '../mixins/link';
+import { VantComponent } from '../common/component';
+VantComponent({
+    classes: [
+        'num-class',
+        'desc-class',
+        'thumb-class',
+        'title-class',
+        'price-class',
+        'origin-price-class',
+    ],
+    mixins: [link],
+    props: {
+        tag: String,
+        num: String,
+        desc: String,
+        thumb: String,
+        title: String,
+        price: {
+            type: String,
+            observer: 'updatePrice',
+        },
+        centered: Boolean,
+        lazyLoad: Boolean,
+        thumbLink: String,
+        originPrice: String,
+        thumbMode: {
+            type: String,
+            value: 'aspectFit',
+        },
+        currency: {
+            type: String,
+            value: '¥',
+        },
+    },
+    methods: {
+        updatePrice() {
+            const { price } = this.data;
+            const priceArr = price.toString().split('.');
+            this.setData({
+                integerStr: priceArr[0],
+                decimalStr: priceArr[1] ? `.${priceArr[1]}` : '',
+            });
+        },
+        onClickThumb() {
+            this.jumpLink('thumbLink');
+        },
+    },
+});

+ 6 - 0
src/wxcomponents/vant/card/index.json

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

+ 56 - 0
src/wxcomponents/vant/card/index.wxml

@@ -0,0 +1,56 @@
+<wxs src="../wxs/utils.wxs" module="utils" />
+
+<view class="custom-class van-card">
+  <view class="{{ utils.bem('card__header', { center: centered }) }}">
+    <view class="van-card__thumb" bind:tap="onClickThumb">
+      <image
+        wx:if="{{ thumb }}"
+        src="{{ thumb }}"
+        mode="{{ thumbMode }}"
+        lazy-load="{{ lazyLoad }}"
+        class="van-card__img thumb-class"
+      />
+      <slot wx:else name="thumb" />
+      <van-tag
+        wx:if="{{ tag }}"
+        mark
+        type="danger"
+        custom-class="van-card__tag"
+      >
+        {{ tag }}
+      </van-tag>
+      <slot wx:else name="tag" />
+    </view>
+
+    <view class="van-card__content {{ utils.bem('card__content', { center: centered }) }}">
+      <view>
+        <view wx:if="{{ title }}" class="van-card__title title-class">{{ title }}</view>
+        <slot wx:else name="title" />
+
+        <view wx:if="{{ desc }}" class="van-card__desc desc-class">{{ desc }}</view>
+        <slot wx:else name="desc" />
+
+        <slot name="tags" />
+      </view>
+
+      <view class="van-card__bottom">
+        <slot name="price-top" />
+        <view wx:if="{{ price || price === 0 }}" class="van-card__price price-class">
+          <text>{{ currency }}</text>
+          <text class="van-card__price-integer">{{ integerStr }}</text>
+          <text class="van-card__price-decimal">{{ decimalStr }}</text>
+        </view>
+        <slot wx:else name="price" />
+        <view wx:if="{{ originPrice || originPrice === 0 }}" class="van-card__origin-price origin-price-class">{{ currency }} {{ originPrice }}</view>
+        <slot wx:else name="origin-price" />
+        <view wx:if="{{ num }}" class="van-card__num num-class">x {{ num }}</view>
+        <slot wx:else  name="num" />
+        <slot name="bottom" />
+      </view>
+    </view>
+  </view>
+
+  <view class="van-card__footer">
+    <slot name="footer" />
+  </view>
+</view>

+ 1 - 0
src/wxcomponents/vant/card/index.wxss

@@ -0,0 +1 @@
+@import '../common/index.wxss';.van-card{background-color:var(--card-background-color,#fafafa);box-sizing:border-box;color:var(--card-text-color,#323233);font-size:var(--card-font-size,12px);padding:var(--card-padding,8px 16px);position:relative}.van-card__header{display:flex}.van-card__header--center{align-items:center;justify-content:center}.van-card__thumb{flex:none;height:var(--card-thumb-size,88px);margin-right:var(--padding-xs,8px);position:relative;width:var(--card-thumb-size,88px)}.van-card__thumb:empty{display:none}.van-card__img{border-radius:8px;height:100%;width:100%}.van-card__content{display:flex;flex:1;flex-direction:column;justify-content:space-between;min-height:var(--card-thumb-size,88px);min-width:0;position:relative}.van-card__content--center{justify-content:center}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:var(--card-title-line-height,16px)}.van-card__desc{color:var(--card-desc-color,#646566);line-height:var(--card-desc-line-height,20px)}.van-card__bottom{line-height:20px}.van-card__price{color:var(--card-price-color,#ee0a24);display:inline-block;font-size:var(--card-price-font-size,12px);font-weight:700}.van-card__price-integer{font-size:var(--card-price-integer-font-size,16px)}.van-card__price-decimal,.van-card__price-integer{font-family:var(--card-price-font-family,Avenir-Heavy,PingFang SC,Helvetica Neue,Arial,sans-serif)}.van-card__origin-price{color:var(--card-origin-price-color,#646566);display:inline-block;font-size:var(--card-origin-price-font-size,10px);margin-left:5px;text-decoration:line-through}.van-card__num{float:right}.van-card__tag{left:0;position:absolute!important;top:2px}.van-card__footer{flex:none;text-align:right;width:100%}

+ 1 - 0
src/wxcomponents/vant/cell-group/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 11 - 0
src/wxcomponents/vant/cell-group/index.js

@@ -0,0 +1,11 @@
+import { VantComponent } from '../common/component';
+VantComponent({
+    props: {
+        title: String,
+        border: {
+            type: Boolean,
+            value: true,
+        },
+        inset: Boolean,
+    },
+});

+ 3 - 0
src/wxcomponents/vant/cell-group/index.json

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

+ 11 - 0
src/wxcomponents/vant/cell-group/index.wxml

@@ -0,0 +1,11 @@
+<wxs src="../wxs/utils.wxs" module="utils" />
+
+<view
+  wx:if="{{ title }}"
+  class="{{ utils.bem('cell-group__title', { inset }) }}"
+>
+  {{ title }}
+</view>
+<view class="custom-class {{ utils.bem('cell-group', { inset }) }} {{ border ? 'van-hairline--top-bottom' : '' }}">
+  <slot />
+</view>

+ 1 - 0
src/wxcomponents/vant/cell-group/index.wxss

@@ -0,0 +1 @@
+@import '../common/index.wxss';.van-cell-group--inset{border-radius:var(--cell-group-inset-border-radius,8px);margin:var(--cell-group-inset-padding,0 16px);overflow:hidden}.van-cell-group__title{color:var(--cell-group-title-color,#969799);font-size:var(--cell-group-title-font-size,14px);line-height:var(--cell-group-title-line-height,16px);padding:var(--cell-group-title-padding,16px 16px 8px)}.van-cell-group__title--inset{padding:var(--cell-group-inset-title-padding,16px 16px 8px 32px)}

+ 1 - 0
src/wxcomponents/vant/cell/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 38 - 0
src/wxcomponents/vant/cell/index.js

@@ -0,0 +1,38 @@
+import { link } from '../mixins/link';
+import { VantComponent } from '../common/component';
+VantComponent({
+    classes: [
+        'title-class',
+        'label-class',
+        'value-class',
+        'right-icon-class',
+        'hover-class',
+    ],
+    mixins: [link],
+    props: {
+        title: null,
+        value: null,
+        icon: String,
+        size: String,
+        label: String,
+        center: Boolean,
+        isLink: Boolean,
+        required: Boolean,
+        clickable: Boolean,
+        titleWidth: String,
+        customStyle: String,
+        arrowDirection: String,
+        useLabelSlot: Boolean,
+        border: {
+            type: Boolean,
+            value: true,
+        },
+        titleStyle: String,
+    },
+    methods: {
+        onClick(event) {
+            this.$emit('click', event.detail);
+            this.jumpLink();
+        },
+    },
+});

+ 6 - 0
src/wxcomponents/vant/cell/index.json

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

+ 47 - 0
src/wxcomponents/vant/cell/index.wxml

@@ -0,0 +1,47 @@
+<wxs src="../wxs/utils.wxs" module="utils" />
+<wxs src="./index.wxs" module="computed" />
+
+<view
+  class="custom-class {{ utils.bem('cell', [size, { center, required, borderless: !border, clickable: isLink || clickable }]) }}"
+  hover-class="van-cell--hover hover-class"
+  hover-stay-time="70"
+  style="{{ customStyle }}"
+  bind:tap="onClick"
+>
+  <van-icon
+    wx:if="{{ icon }}"
+    name="{{ icon }}"
+    class="van-cell__left-icon-wrap"
+    custom-class="van-cell__left-icon"
+  />
+  <slot wx:else name="icon" />
+
+  <view
+    style="{{ computed.titleStyle({ titleWidth, titleStyle }) }}"
+    class="van-cell__title title-class"
+  >
+
+    <block wx:if="{{ title }}">{{ title }}</block>
+    <slot wx:else name="title" />
+
+    <view wx:if="{{ label || useLabelSlot }}" class="van-cell__label label-class">
+      <slot wx:if="{{ useLabelSlot }}" name="label" />
+      <block wx:elif="{{ label }}">{{ label }}</block>
+    </view>
+  </view>
+
+  <view class="van-cell__value value-class">
+    <block wx:if="{{ value || value === 0 }}">{{ value }}</block>
+    <slot wx:else />
+  </view>
+
+  <van-icon
+    wx:if="{{ isLink }}"
+    name="{{ arrowDirection ? 'arrow' + '-' + arrowDirection : 'arrow' }}"
+    class="van-cell__right-icon-wrap right-icon-class"
+    custom-class="van-cell__right-icon"
+  />
+  <slot wx:else name="right-icon" />
+
+  <slot name="extra" />
+</view>

+ 17 - 0
src/wxcomponents/vant/cell/index.wxs

@@ -0,0 +1,17 @@
+/* eslint-disable */
+var style = require('../wxs/style.wxs');
+var addUnit = require('../wxs/add-unit.wxs');
+
+function titleStyle(data) {
+  return style([
+    {
+      'max-width': addUnit(data.titleWidth),
+      'min-width': addUnit(data.titleWidth),
+    },
+    data.titleStyle,
+  ]);
+}
+
+module.exports = {
+  titleStyle: titleStyle,
+};

文件差異過大導致無法顯示
+ 0 - 0
src/wxcomponents/vant/cell/index.wxss


+ 1 - 0
src/wxcomponents/vant/checkbox-group/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 36 - 0
src/wxcomponents/vant/checkbox-group/index.js

@@ -0,0 +1,36 @@
+import { useChildren } from '../common/relation';
+import { VantComponent } from '../common/component';
+VantComponent({
+    field: true,
+    relation: useChildren('checkbox', function (target) {
+        this.updateChild(target);
+    }),
+    props: {
+        max: Number,
+        value: {
+            type: Array,
+            observer: 'updateChildren',
+        },
+        disabled: {
+            type: Boolean,
+            observer: 'updateChildren',
+        },
+        direction: {
+            type: String,
+            value: 'vertical',
+        },
+    },
+    methods: {
+        updateChildren() {
+            this.children.forEach((child) => this.updateChild(child));
+        },
+        updateChild(child) {
+            const { value, disabled, direction } = this.data;
+            child.setData({
+                value: value.indexOf(child.data.name) !== -1,
+                parentDisabled: disabled,
+                direction,
+            });
+        },
+    },
+});

+ 3 - 0
src/wxcomponents/vant/checkbox-group/index.json

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

+ 5 - 0
src/wxcomponents/vant/checkbox-group/index.wxml

@@ -0,0 +1,5 @@
+<wxs src="../wxs/utils.wxs" module="utils" />
+
+<view class="{{ utils.bem('checkbox-group', [{ horizontal: direction === 'horizontal' }]) }}">
+  <slot />
+</view>

+ 1 - 0
src/wxcomponents/vant/checkbox-group/index.wxss

@@ -0,0 +1 @@
+@import '../common/index.wxss';.van-checkbox-group--horizontal{display:flex;flex-wrap:wrap}

+ 1 - 0
src/wxcomponents/vant/checkbox/index.d.ts

@@ -0,0 +1 @@
+export {};

+ 77 - 0
src/wxcomponents/vant/checkbox/index.js

@@ -0,0 +1,77 @@
+import { useParent } from '../common/relation';
+import { VantComponent } from '../common/component';
+function emit(target, value) {
+    target.$emit('input', value);
+    target.$emit('change', value);
+}
+VantComponent({
+    field: true,
+    relation: useParent('checkbox-group'),
+    classes: ['icon-class', 'label-class'],
+    props: {
+        value: Boolean,
+        disabled: Boolean,
+        useIconSlot: Boolean,
+        checkedColor: String,
+        labelPosition: {
+            type: String,
+            value: 'right',
+        },
+        labelDisabled: Boolean,
+        shape: {
+            type: String,
+            value: 'round',
+        },
+        iconSize: {
+            type: null,
+            value: 20,
+        },
+    },
+    data: {
+        parentDisabled: false,
+        direction: 'vertical',
+    },
+    methods: {
+        emitChange(value) {
+            if (this.parent) {
+                this.setParentValue(this.parent, value);
+            }
+            else {
+                emit(this, value);
+            }
+        },
+        toggle() {
+            const { parentDisabled, disabled, value } = this.data;
+            if (!disabled && !parentDisabled) {
+                this.emitChange(!value);
+            }
+        },
+        onClickLabel() {
+            const { labelDisabled, parentDisabled, disabled, value } = this.data;
+            if (!disabled && !labelDisabled && !parentDisabled) {
+                this.emitChange(!value);
+            }
+        },
+        setParentValue(parent, value) {
+            const parentValue = parent.data.value.slice();
+            const { name } = this.data;
+            const { max } = parent.data;
+            if (value) {
+                if (max && parentValue.length >= max) {
+                    return;
+                }
+                if (parentValue.indexOf(name) === -1) {
+                    parentValue.push(name);
+                    emit(parent, parentValue);
+                }
+            }
+            else {
+                const index = parentValue.indexOf(name);
+                if (index !== -1) {
+                    parentValue.splice(index, 1);
+                    emit(parent, parentValue);
+                }
+            }
+        },
+    },
+});

+ 6 - 0
src/wxcomponents/vant/checkbox/index.json

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

+ 31 - 0
src/wxcomponents/vant/checkbox/index.wxml

@@ -0,0 +1,31 @@
+<wxs src="../wxs/utils.wxs" module="utils" />
+<wxs src="./index.wxs" module="computed" />
+
+<view class="{{ utils.bem('checkbox', [{ horizontal: direction === 'horizontal' }]) }} custom-class">
+  <view
+    wx:if="{{ labelPosition === 'left' }}"
+    class="label-class {{ utils.bem('checkbox__label', [labelPosition, { disabled: disabled || parentDisabled }]) }}"
+    bindtap="onClickLabel"
+  >
+    <slot />
+  </view>
+  <view class="van-checkbox__icon-wrap" bindtap="toggle">
+    <slot wx:if="{{ useIconSlot }}" name="icon" />
+    <van-icon
+      wx:else
+      name="success"
+      size="0.8em"
+      class="{{ utils.bem('checkbox__icon', [shape, { disabled: disabled || parentDisabled, checked: value }]) }}"
+      style="{{ computed.iconStyle(checkedColor, value, disabled, parentDisabled, iconSize) }}"
+      custom-class="icon-class"
+      custom-style="line-height: 1.25em;"
+    />
+  </view>
+  <view
+    wx:if="{{ labelPosition === 'right' }}"
+    class="label-class {{ utils.bem('checkbox__label', [labelPosition, { disabled: disabled || parentDisabled }]) }}"
+    bindtap="onClickLabel"
+  >
+    <slot />
+  </view>
+</view>

+ 20 - 0
src/wxcomponents/vant/checkbox/index.wxs

@@ -0,0 +1,20 @@
+/* eslint-disable */
+var style = require('../wxs/style.wxs');
+var addUnit = require('../wxs/add-unit.wxs');
+
+function iconStyle(checkedColor, value, disabled, parentDisabled, iconSize) {
+  var styles = {
+    'font-size': addUnit(iconSize),
+  };
+
+  if (checkedColor && value && !disabled && !parentDisabled) {
+    styles['border-color'] = checkedColor;
+    styles['background-color'] = checkedColor;
+  }
+
+  return style(styles);
+}
+
+module.exports = {
+  iconStyle: iconStyle,
+};

+ 1 - 0
src/wxcomponents/vant/checkbox/index.wxss

@@ -0,0 +1 @@
+@import '../common/index.wxss';.van-checkbox{align-items:center;display:flex;overflow:hidden;-webkit-user-select:none;user-select:none}.van-checkbox--horizontal{margin-right:12px}.van-checkbox__icon-wrap,.van-checkbox__label{line-height:var(--checkbox-size,20px)}.van-checkbox__icon-wrap{flex:none}.van-checkbox__icon{align-items:center;border:1px solid var(--checkbox-border-color,#c8c9cc);box-sizing:border-box;color:transparent;display:flex;font-size:var(--checkbox-size,20px);height:1em;justify-content:center;text-align:center;transition-duration:var(--checkbox-transition-duration,.2s);transition-property:color,border-color,background-color;width:1em}.van-checkbox__icon--round{border-radius:100%}.van-checkbox__icon--checked{background-color:var(--checkbox-checked-icon-color,#1989fa);border-color:var(--checkbox-checked-icon-color,#1989fa);color:#fff}.van-checkbox__icon--disabled{background-color:var(--checkbox-disabled-background-color,#ebedf0);border-color:var(--checkbox-disabled-icon-color,#c8c9cc)}.van-checkbox__icon--disabled.van-checkbox__icon--checked{color:var(--checkbox-disabled-icon-color,#c8c9cc)}.van-checkbox__label{word-wrap:break-word;color:var(--checkbox-label-color,#323233);padding-left:var(--checkbox-label-margin,10px)}.van-checkbox__label--left{float:left;margin:0 var(--checkbox-label-margin,10px) 0 0}.van-checkbox__label--disabled{color:var(--checkbox-disabled-label-color,#c8c9cc)}.van-checkbox__label:empty{margin:0}

+ 4 - 0
src/wxcomponents/vant/circle/canvas.d.ts

@@ -0,0 +1,4 @@
+/// <reference types="miniprogram-api-typings" />
+declare type CanvasContext = WechatMiniprogram.CanvasContext;
+export declare function adaptor(ctx: CanvasContext & Record<string, unknown>): CanvasContext;
+export {};

+ 43 - 0
src/wxcomponents/vant/circle/canvas.js

@@ -0,0 +1,43 @@
+export function adaptor(ctx) {
+    // @ts-ignore
+    return Object.assign(ctx, {
+        setStrokeStyle(val) {
+            ctx.strokeStyle = val;
+        },
+        setLineWidth(val) {
+            ctx.lineWidth = val;
+        },
+        setLineCap(val) {
+            ctx.lineCap = val;
+        },
+        setFillStyle(val) {
+            ctx.fillStyle = val;
+        },
+        setFontSize(val) {
+            ctx.font = String(val);
+        },
+        setGlobalAlpha(val) {
+            ctx.globalAlpha = val;
+        },
+        setLineJoin(val) {
+            ctx.lineJoin = val;
+        },
+        setTextAlign(val) {
+            ctx.textAlign = val;
+        },
+        setMiterLimit(val) {
+            ctx.miterLimit = val;
+        },
+        setShadow(offsetX, offsetY, blur, color) {
+            ctx.shadowOffsetX = offsetX;
+            ctx.shadowOffsetY = offsetY;
+            ctx.shadowBlur = blur;
+            ctx.shadowColor = color;
+        },
+        setTextBaseline(val) {
+            ctx.textBaseline = val;
+        },
+        createCircularGradient() { },
+        draw() { },
+    });
+}

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