zhangdaiscott 4 лет назад
Родитель
Сommit
4c4877996a
100 измененных файлов с 16873 добавлено и 0 удалено
  1. 2 0
      .gitignore
  2. 278 0
      App.vue
  3. 39 0
      api/api.js
  4. 438 0
      common/luch-request/core/Request.js
  5. 20 0
      common/luch-request/core/buildFullPath.js
  6. 69 0
      common/luch-request/helpers/buildURL.js
  7. 14 0
      common/luch-request/helpers/combineURLs.js
  8. 14 0
      common/luch-request/helpers/isAbsoluteURL.js
  9. 2 0
      common/luch-request/index.js
  10. 95 0
      common/luch-request/utils.js
  11. 31 0
      common/router/index.js
  12. 10 0
      common/router/modules/index.js
  13. 69 0
      common/router/modules/routes.js
  14. 16 0
      common/service/config.service.js
  15. 110 0
      common/service/service.js
  16. 101 0
      common/util/MinCache.js
  17. 73 0
      common/util/appUpdate.js
  18. 14 0
      common/util/constants.js
  19. 130 0
      common/util/tip.js
  20. 118 0
      common/util/work.js
  21. 106 0
      components/my-componets/my-image-upload.vue
  22. 46 0
      components/my-componets/my-page.vue
  23. 80 0
      components/my-componets/my-select.vue
  24. 29 0
      components/uni-popup/message.js
  25. 25 0
      components/uni-popup/popup.js
  26. 243 0
      components/uni-popup/uni-popup-dialog.vue
  27. 116 0
      components/uni-popup/uni-popup-message.vue
  28. 165 0
      components/uni-popup/uni-popup-share.vue
  29. 294 0
      components/uni-popup/uni-popup.vue
  30. 279 0
      components/uni-transition/uni-transition.vue
  31. 84 0
      main.js
  32. 81 0
      manifest.json
  33. BIN
      myhjdc.keystore
  34. 44 0
      package-lock.json
  35. 151 0
      pages.json
  36. 108 0
      pages/basics/avatar.vue
  37. 141 0
      pages/basics/background.vue
  38. 123 0
      pages/basics/button.vue
  39. 130 0
      pages/basics/design.vue
  40. 97 0
      pages/basics/home.vue
  41. 939 0
      pages/basics/icon.vue
  42. 207 0
      pages/basics/layout.vue
  43. 101 0
      pages/basics/loading.vue
  44. 153 0
      pages/basics/progress.vue
  45. 54 0
      pages/basics/shadow.vue
  46. 130 0
      pages/basics/tag.vue
  47. 169 0
      pages/basics/text.vue
  48. 51 0
      pages/common/exit.vue
  49. 48 0
      pages/common/success.vue
  50. 448 0
      pages/component/bar.vue
  51. 167 0
      pages/component/card.vue
  52. 113 0
      pages/component/chat.vue
  53. 415 0
      pages/component/form.vue
  54. 92 0
      pages/component/home.vue
  55. 425 0
      pages/component/list.vue
  56. 279 0
      pages/component/modal.vue
  57. 90 0
      pages/component/nav.vue
  58. 114 0
      pages/component/steps.vue
  59. 162 0
      pages/component/swiper.vue
  60. 101 0
      pages/component/timeline.vue
  61. 208 0
      pages/home/home.vue
  62. 47 0
      pages/index/index.vue
  63. 169 0
      pages/login/login.vue
  64. 145 0
      pages/plugin/animation.vue
  65. 170 0
      pages/plugin/drawer.vue
  66. 103 0
      pages/plugin/home.vue
  67. 197 0
      pages/plugin/indexes.vue
  68. 226 0
      pages/plugin/verticalnav.vue
  69. 167 0
      pages/user/people.vue
  70. 39 0
      pages/user/user.vue
  71. 258 0
      pages/user/userdetail.vue
  72. 229 0
      pages/user/useredit.vue
  73. 39 0
      pages/user/userexit.vue
  74. 184 0
      plugin/colorui/animation.css
  75. 67 0
      plugin/colorui/components/cu-custom.vue
  76. 36 0
      plugin/colorui/icon.css
  77. 3912 0
      plugin/colorui/main.css
  78. 41 0
      plugin/uni-simple-router/README.md
  79. 361 0
      plugin/uni-simple-router/appRouter/hooks.js
  80. 108 0
      plugin/uni-simple-router/appRouter/init.js
  81. 34 0
      plugin/uni-simple-router/appRouter/uniNav.js
  82. 209 0
      plugin/uni-simple-router/appRouter/util.js
  83. 23 0
      plugin/uni-simple-router/appletsRouter/appletsNav.js
  84. 319 0
      plugin/uni-simple-router/appletsRouter/hooks.js
  85. 13 0
      plugin/uni-simple-router/appletsRouter/init.js
  86. 169 0
      plugin/uni-simple-router/appletsRouter/util.js
  87. 75 0
      plugin/uni-simple-router/component/h5-dom.js
  88. 79 0
      plugin/uni-simple-router/component/router-link.vue
  89. 35 0
      plugin/uni-simple-router/helpers/compile.js
  90. 93 0
      plugin/uni-simple-router/helpers/config.js
  91. 60 0
      plugin/uni-simple-router/helpers/mixins.js
  92. 103 0
      plugin/uni-simple-router/helpers/navJump.js
  93. 157 0
      plugin/uni-simple-router/helpers/urlQuery.js
  94. 255 0
      plugin/uni-simple-router/helpers/util.js
  95. 34 0
      plugin/uni-simple-router/helpers/warn.js
  96. 177 0
      plugin/uni-simple-router/index.js
  97. 38 0
      plugin/uni-simple-router/lifeCycle/hooks.js
  98. 33 0
      plugin/uni-simple-router/package.json
  99. 8 0
      plugin/uni-simple-router/patch/app-patch.js
  100. 10 0
      plugin/uni-simple-router/patch/applets-patch.js

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/unpackage/
+/.idea/

+ 278 - 0
App.vue

@@ -0,0 +1,278 @@
+<script>
+	import Vue from 'vue'
+	import appUpdate from 'common/util/appUpdate.js'
+	export default {
+		onLaunch: function() {
+			uni.getSystemInfo({
+				success: function(e) {
+					
+					// #ifdef APP-PLUS
+					// 检测升级
+					appUpdate()
+					// #endif
+					// #ifndef MP
+					Vue.prototype.StatusBar = e.statusBarHeight;
+					if (e.platform == 'android') {
+						Vue.prototype.CustomBar = e.statusBarHeight + 50;
+					} else {
+						Vue.prototype.CustomBar = e.statusBarHeight + 45;
+					};
+					// #endif
+
+					// #ifdef MP-WEIXIN
+					Vue.prototype.StatusBar = e.statusBarHeight;
+					let custom = wx.getMenuButtonBoundingClientRect();
+					Vue.prototype.Custom = custom;
+					Vue.prototype.CustomBar = custom.bottom + custom.top - e.statusBarHeight;
+					// #endif		
+
+					// #ifdef MP-ALIPAY
+					Vue.prototype.StatusBar = e.statusBarHeight;
+					Vue.prototype.CustomBar = e.statusBarHeight + e.titleBarHeight;
+					// #endif
+					
+					// #ifdef APP-PLUS
+					//Vue.prototype.$api.listenTranMsg()
+			// 		var info = plus.push.getClientInfo();
+			
+			// 		/* 5+  push 消息推送 ps:使用:H5+的方式监听,实现推送*/
+			// 		plus.push.addEventListener("click", function(msg) {
+			// 			console.log("click:" + JSON.stringify(msg));
+			// 			console.log(msg.payload);
+			// 			console.log(JSON.stringify(msg));
+			// 			//这里可以写跳转业务代码
+			// 		}, false);
+			// 		// 监听在线消息事件    
+			// 		plus.push.addEventListener("receive", function(msg) {
+			// 			// plus.ui.alert(2);  
+			// 			//这里可以写跳转业务代码
+			// 			console.log("recevice:" + JSON.stringify(msg))
+			// 		}, false);
+					// #endif
+					
+					//Vue.prototype.$api.initLogin()
+					
+				}
+			})
+
+			Vue.prototype.ColorList = [{
+					title: '嫣红',
+					name: 'red',
+					color: '#e54d42'
+				},
+				{
+					title: '桔橙',
+					name: 'orange',
+					color: '#f37b1d'
+				},
+				{
+					title: '明黄',
+					name: 'yellow',
+					color: '#fbbd08'
+				},
+				{
+					title: '橄榄',
+					name: 'olive',
+					color: '#8dc63f'
+				},
+				{
+					title: '森绿',
+					name: 'green',
+					color: '#39b54a'
+				},
+				{
+					title: '天青',
+					name: 'cyan',
+					color: '#1cbbb4'
+				},
+				{
+					title: '海蓝',
+					name: 'blue',
+					color: '#0081ff'
+				},
+				{
+					title: '姹紫',
+					name: 'purple',
+					color: '#6739b6'
+				},
+				{
+					title: '木槿',
+					name: 'mauve',
+					color: '#9c26b0'
+				},
+				{
+					title: '桃粉',
+					name: 'pink',
+					color: '#e03997'
+				},
+				{
+					title: '棕褐',
+					name: 'brown',
+					color: '#a5673f'
+				},
+				{
+					title: '玄灰',
+					name: 'grey',
+					color: '#8799a3'
+				},
+				{
+					title: '草灰',
+					name: 'gray',
+					color: '#aaaaaa'
+				},
+				{
+					title: '墨黑',
+					name: 'black',
+					color: '#333333'
+				},
+				{
+					title: '雅白',
+					name: 'white',
+					color: '#ffffff'
+				},
+			]
+
+		},
+		onShow: function() {
+			console.log('App Show')
+		},
+		onHide: function() {
+			console.log('App Hide')
+		}
+
+	}
+</script>
+
+<style>
+	@import "plugin/colorui/main.css";
+	@import "plugin/colorui/icon.css";
+    @import "plugin/colorui/animation.css";
+	.nav-list {
+		display: flex;
+		flex-wrap: wrap;
+		padding: 0px 40upx 0px;
+		justify-content: space-between;
+	}
+
+	.nav-li {
+		padding: 30upx;
+		border-radius: 12upx;
+		width: 45%;
+		margin: 0 2.5% 40upx;
+		background-image: url(https://cdn.nlark.com/yuque/0/2019/png/280374/1552996358352-assets/web-upload/cc3b1807-c684-4b83-8f80-80e5b8a6b975.png);
+		background-size: cover;
+		background-position: center;
+		position: relative;
+		z-index: 1;
+	}
+
+	.nav-li::after {
+		content: "";
+		position: absolute;
+		z-index: -1;
+		background-color: inherit;
+		width: 100%;
+		height: 100%;
+		left: 0;
+		bottom: -10%;
+		border-radius: 10upx;
+		opacity: 0.2;
+		transform: scale(0.9, 0.9);
+	}
+
+	.nav-li.cur {
+		color: #fff;
+		background: rgb(94, 185, 94);
+		box-shadow: 4upx 4upx 6upx rgba(94, 185, 94, 0.4);
+	}
+
+	.nav-title {
+		font-size: 32upx;
+		font-weight: 300;
+	}
+
+	.nav-title::first-letter {
+		font-size: 40upx;
+		margin-right: 4upx;
+	}
+
+	.nav-name {
+		font-size: 28upx;
+		text-transform: Capitalize;
+		margin-top: 20upx;
+		position: relative;
+	}
+
+	.nav-name::before {
+		content: "";
+		position: absolute;
+		display: block;
+		width: 40upx;
+		height: 6upx;
+		background: #fff;
+		bottom: 0;
+		right: 0;
+		opacity: 0.5;
+	}
+
+	.nav-name::after {
+		content: "";
+		position: absolute;
+		display: block;
+		width: 100upx;
+		height: 1px;
+		background: #fff;
+		bottom: 0;
+		right: 40upx;
+		opacity: 0.3;
+	}
+
+	.nav-name::first-letter {
+		font-weight: bold;
+		font-size: 36upx;
+		margin-right: 1px;
+	}
+
+	.nav-li text {
+		position: absolute;
+		right: 30upx;
+		top: 30upx;
+		font-size: 52upx;
+		width: 60upx;
+		height: 60upx;
+		text-align: center;
+		line-height: 60upx;
+	}
+
+	.text-light {
+		font-weight: 300;
+	}
+
+	@keyframes show {
+		0% {
+			transform: translateY(-50px);
+		}
+
+		60% {
+			transform: translateY(40upx);
+		}
+
+		100% {
+			transform: translateY(0px);
+		}
+	}
+
+	@-webkit-keyframes show {
+		0% {
+			transform: translateY(-50px);
+		}
+
+		60% {
+			transform: translateY(40upx);
+		}
+
+		100% {
+			transform: translateY(0px);
+		}
+	}
+</style>

+ 39 - 0
api/api.js

@@ -0,0 +1,39 @@
+import { http } from '@/common/service/service.js' 
+import configService from '@/common/service/config.service.js';
+const apiService = {
+	 
+	 /**
+	  * 登录
+	  */
+	login(params) {
+		return http.post('/sys/mLogin',params)	
+	},
+	/**
+	  * 手机号码登录
+	  */
+	phoneNoLogin(params) {
+		return http.post('/sys/phoneLogin',params);
+	},
+	/**
+	  * 退出
+	  */
+	logout(params) {
+		return http.post('/sys/logout',params);
+	},
+	/**
+	 * 获取文件访问路径
+	 * @param avatar
+	 * @param subStr
+	 * @returns {*}
+	 */
+	getFileAccessHttpUrl(avatar,subStr){
+	    if(!subStr) subStr = 'http'
+	    if(avatar && avatar.startsWith(subStr)){
+	        return avatar;
+	    }else{
+	        return configService.staticDomainURL + "/" + avatar;
+	    }
+	}
+};
+
+export default apiService;

+ 438 - 0
common/luch-request/core/Request.js

@@ -0,0 +1,438 @@
+/**
+ * Request 2.0.1
+ * @Class Request
+ * @description luch-request 2.0.1 http请求插件
+ * @Author lu-ch
+ * @Date 2020-05-01
+ * @Email webwork.s@qq.com
+ * http://ext.dcloud.net.cn/plugin?id=392
+ * hbuilderx:2.6.15
+ */
+
+import buildURL from '../helpers/buildURL'
+import buildFullPath from './buildFullPath'
+import { isBoolean } from '../utils'
+
+export default class Request {
+  config = {
+    baseUrl: '',
+    header: {},
+    method: 'GET',
+    dataType: 'json',
+    // #ifndef MP-ALIPAY || APP-PLUS
+    responseType: 'text',
+    // #endif
+    custom: {},
+    // #ifdef MP-ALIPAY || MP-WEIXIN
+    timeout: 30000,
+    // #endif
+    // #ifdef APP-PLUS
+    sslVerify: true,
+    // #endif
+    // #ifdef H5
+    withCredentials: false
+    // #endif
+  }
+
+  /**
+   * @property {Function} request 请求拦截器
+   * @property {Function} response 响应拦截器
+   * @type {{request: Request.interceptor.request, response: Request.interceptor.response}}
+   */
+  interceptor = {
+    /**
+     * @param {Request~requestCallback} cb - 请求之前拦截,接收一个函数(config, cancel)=> {return config}。第一个参数为全局config,第二个参数为函数,调用则取消本次请求。
+     */
+    request: (cb) => {
+      if (cb) {
+        this.requestBeforeFun = cb
+      }
+    },
+    /**
+     * @param {Request~responseCallback} cb 响应拦截器,对响应数据做点什么
+     * @param {Request~responseErrCallback} ecb 响应拦截器,对响应错误做点什么
+     */
+    response: (cb, ecb) => {
+      if (cb) {
+        this.requestComFun = cb
+      }
+      if (ecb) {
+        this.requestComFail = ecb
+      }
+    }
+  }
+
+  requestBeforeFun = (config) => {
+    return config
+  }
+
+  requestComFun = (response) => {
+    return response
+  }
+
+  requestComFail = (response) => {
+    return response
+  }
+
+  /**
+   * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject)
+   * @param { Number } statusCode - 请求响应体statusCode(只读)
+   * @return { Boolean } 如果为true,则 resolve, 否则 reject
+   */
+  validateStatus(statusCode) {
+    return statusCode === 200
+  }
+
+  /**
+   * @Function
+   * @param {Request~setConfigCallback} f - 设置全局默认配置
+   */
+  setConfig(f) {
+    this.config = f(this.config)
+  }
+
+  /**
+   * @Function
+   * @param {Object} options - 请求配置项
+   * @prop {String} options.url - 请求路径
+   * @prop {Object} options.data - 请求参数
+   * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型
+   * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse
+   * @prop {Object} [options.header = config.header] - 请求header
+   * @prop {Object} [options.method = config.method] - 请求方法
+   * @returns {Promise<unknown>}
+   */
+  async request(options = {}) {
+    return new Promise((resolve, reject) => {
+      options.baseUrl = this.config.baseUrl
+      options.dataType = options.dataType || this.config.dataType
+      // #ifndef MP-ALIPAY || APP-PLUS
+      options.responseType = options.responseType || this.config.responseType
+      // #endif
+      // #ifdef MP-ALIPAY || MP-WEIXIN
+      options.timeout = options.timeout || this.config.timeout
+      // #endif
+      // #ifdef H5
+      options.withCredentials = isBoolean(options.withCredentials) ? options.withCredentials : this.config.withCredentials
+      // #endif
+      options.url = options.url || ''
+      options.data = options.data || {}
+      options.params = options.params || {}
+      options.header = {...this.config.header, ...(options.header || {})}
+      options.method = options.method || this.config.method
+      options.custom =  {...this.config.custom,...(options.custom || {})}
+      // #ifdef APP-PLUS
+      options.sslVerify = options.sslVerify === undefined ? this.config.sslVerify : options.sslVerify
+      // #endif
+      options.getTask = options.getTask || this.config.getTask
+      let next = true
+      const cancel = (t = 'handle cancel', config = options) => {
+        const err = {
+          errMsg: t,
+          config: config
+        }
+        reject(err)
+        next = false
+      }
+
+      const handleRe =  {...this.requestBeforeFun(options, cancel)}
+      const _config = {...handleRe}
+      if (!next) return
+      const requestTask = uni.request({
+        url: buildURL(buildFullPath(_config.baseUrl, _config.url), _config.params),
+        data: _config.data,
+        header: _config.header,
+        method: _config.method,
+        // #ifdef MP-ALIPAY || MP-WEIXIN
+        timeout: _config.timeout,
+        // #endif
+        dataType: _config.dataType,
+        // #ifndef MP-ALIPAY || APP-PLUS
+        responseType: _config.responseType,
+        // #endif
+        // #ifdef APP-PLUS
+        sslVerify: _config.sslVerify,
+        // #endif
+        // #ifdef H5
+        withCredentials: _config.withCredentials,
+        // #endif
+        complete: (response) => {
+          response.config = handleRe
+          if (this.validateStatus(response.statusCode)) { // 成功
+            response = this.requestComFun(response)
+            resolve(response)
+          } else {
+            response = this.requestComFail(response)
+            reject(response)
+          }
+        }
+      })
+      if (handleRe.getTask) {
+        handleRe.getTask(requestTask, handleRe)
+      }
+    })
+  }
+
+  get(url, options = {}) {
+    return this.request({
+      url,
+      method: 'GET',
+      ...options
+    })
+  }
+
+  post(url, data, options = {}) {
+    return this.request({
+      url,
+      data,
+      method: 'POST',
+      ...options
+    })
+  }
+
+  // #ifndef MP-ALIPAY
+  put(url, data, options = {}) {
+    return this.request({
+      url,
+      data,
+      method: 'PUT',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
+  delete(url, data, options = {}) {
+    return this.request({
+      url,
+      data,
+      method: 'DELETE',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN
+  connect(url, data, options = {}) {
+    return this.request({
+      url,
+      data,
+      method: 'CONNECT',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
+  head(url, data, options = {}) {
+    return this.request({
+      url,
+      data,
+      method: 'HEAD',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
+  options(url, data, options = {}) {
+    return this.request({
+      url,
+      data,
+      method: 'OPTIONS',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN
+  trace(url, data, options = {}) {
+    return this.request({
+      url,
+      data,
+      method: 'TRACE',
+      ...options
+    })
+  }
+
+  // #endif
+
+  upload(url, {
+    // #ifdef APP-PLUS || H5
+    files,
+    // #endif
+    // #ifdef MP-ALIPAY
+    fileType,
+    // #endif
+    filePath,
+    name,
+    // #ifdef H5
+    file,
+    // #endif
+    header = {},
+    formData = {},
+    custom = {},
+    params = {},
+    getTask
+  }) {
+    return new Promise((resolve, reject) => {
+      let next = true
+      const globalHeader = {...this.config.header}
+      delete globalHeader['content-type']
+      delete globalHeader['Content-Type']
+      const pubConfig = {
+        baseUrl: this.config.baseUrl,
+        url,
+        // #ifdef MP-ALIPAY
+        fileType,
+        // #endif
+        filePath,
+        method: 'UPLOAD',
+        name,
+        header: {...globalHeader, ...header},
+        formData,
+        params,
+        custom: {...this.config.custom, ...custom},
+        getTask: getTask || this.config.getTask
+      }
+      // #ifdef APP-PLUS || H5
+      if (files) {
+        pubConfig.files = files
+      }
+      // #endif
+      // #ifdef H5
+      if (file) {
+        pubConfig.file = file
+      }
+      // #endif
+      const cancel = (t = 'handle cancel', config = pubConfig) => {
+        const err = {
+          errMsg: t,
+          config: config
+        }
+        reject(err)
+        next = false
+      }
+
+      const handleRe = {...this.requestBeforeFun(pubConfig, cancel)}
+      const _config = {
+        url: buildURL(buildFullPath(handleRe.baseUrl, handleRe.url), handleRe.params),
+        // #ifdef MP-ALIPAY
+        fileType: handleRe.fileType,
+        // #endif
+        filePath: handleRe.filePath,
+        name: handleRe.name,
+        header: handleRe.header,
+        formData: handleRe.formData,
+        complete: (response) => {
+          response.config = handleRe
+          try {
+            // 对可能字符串不是json 的情况容错
+            if (typeof response.data === 'string') {
+              response.data = JSON.parse(response.data)
+            }
+            // eslint-disable-next-line no-empty
+          } catch (e) {
+          }
+          if (this.validateStatus(response.statusCode)) { // 成功
+            response = this.requestComFun(response)
+            resolve(response)
+          } else {
+            response = this.requestComFail(response)
+            reject(response)
+          }
+        }
+      }
+      // #ifdef APP-PLUS || H5
+      if (handleRe.files) {
+        _config.files = handleRe.files
+      }
+      // #endif
+      // #ifdef H5
+      if (handleRe.file) {
+        _config.file = handleRe.file
+      }
+      // #endif
+      if (!next) return
+      const requestTask = uni.uploadFile(_config)
+      if (handleRe.getTask) {
+        handleRe.getTask(requestTask, handleRe)
+      }
+    })
+  }
+
+  download(url, options = {}) {
+    return new Promise((resolve, reject) => {
+      let next = true
+      const pubConfig = {
+        baseUrl: this.config.baseUrl,
+        url,
+        method: 'DOWNLOAD',
+        header: {...this.config.header, ...(options.header || {})},
+        params: options.params || {},
+        custom: {...this.config.custom, ...(options.custom || {})},
+        getTask: options.getTask || this.config.getTask
+      }
+      const cancel = (t = 'handle cancel', config = pubConfig) => {
+        const err = {
+          errMsg: t,
+          config: config
+        }
+        reject(err)
+        next = false
+      }
+
+      const handleRe = {...this.requestBeforeFun(pubConfig, cancel)}
+      if (!next) return
+      const requestTask = uni.downloadFile({
+        url: buildURL(buildFullPath(handleRe.baseUrl, handleRe.url), handleRe.params),
+        header: handleRe.header,
+        complete: (response) => {
+          response.config = handleRe
+          if (this.validateStatus(response.statusCode)) { // 成功
+            response = this.requestComFun(response)
+            resolve(response)
+          } else {
+            response = this.requestComFail(response)
+            reject(response)
+          }
+        }
+      })
+      if (handleRe.getTask) {
+        handleRe.getTask(requestTask, handleRe)
+      }
+    })
+  }
+}
+
+
+/**
+ * setConfig回调
+ * @return {Object} - 返回操作后的config
+ * @callback Request~setConfigCallback
+ * @param {Object} config - 全局默认config
+ */
+/**
+ * 请求拦截器回调
+ * @return {Object} - 返回操作后的config
+ * @callback Request~requestCallback
+ * @param {Object} config - 全局config
+ * @param {Function} [cancel] - 取消请求钩子,调用会取消本次请求
+ */
+/**
+ * 响应拦截器回调
+ * @return {Object} - 返回操作后的response
+ * @callback Request~responseCallback
+ * @param {Object} response - 请求结果 response
+ */
+/**
+ * 响应错误拦截器回调
+ * @return {Object} - 返回操作后的response
+ * @callback Request~responseErrCallback
+ * @param {Object} response - 请求结果 response
+ */

+ 20 - 0
common/luch-request/core/buildFullPath.js

@@ -0,0 +1,20 @@
+'use strict'
+
+import isAbsoluteURL from '../helpers/isAbsoluteURL'
+import combineURLs from '../helpers/combineURLs'
+
+/**
+ * Creates a new URL by combining the baseURL with the requestedURL,
+ * only when the requestedURL is not already an absolute URL.
+ * If the requestURL is absolute, this function returns the requestedURL untouched.
+ *
+ * @param {string} baseURL The base URL
+ * @param {string} requestedURL Absolute or relative URL to combine
+ * @returns {string} The combined full path
+ */
+export default function buildFullPath(baseURL, requestedURL) {
+  if (baseURL && !isAbsoluteURL(requestedURL)) {
+    return combineURLs(baseURL, requestedURL)
+  }
+  return requestedURL
+}

+ 69 - 0
common/luch-request/helpers/buildURL.js

@@ -0,0 +1,69 @@
+'use strict'
+
+import * as utils from './../utils'
+
+function encode(val) {
+  return encodeURIComponent(val).
+    replace(/%40/gi, '@').
+    replace(/%3A/gi, ':').
+    replace(/%24/g, '$').
+    replace(/%2C/gi, ',').
+    replace(/%20/g, '+').
+    replace(/%5B/gi, '[').
+    replace(/%5D/gi, ']')
+}
+
+/**
+ * Build a URL by appending params to the end
+ *
+ * @param {string} url The base of the url (e.g., http://www.google.com)
+ * @param {object} [params] The params to be appended
+ * @returns {string} The formatted url
+ */
+export default function buildURL(url, params) {
+  /*eslint no-param-reassign:0*/
+  if (!params) {
+    return url
+  }
+
+  var serializedParams
+  if (utils.isURLSearchParams(params)) {
+    serializedParams = params.toString()
+  } else {
+    var parts = []
+
+    utils.forEach(params, function serialize(val, key) {
+      if (val === null || typeof val === 'undefined') {
+        return
+      }
+
+      if (utils.isArray(val)) {
+        key = key + '[]'
+      } else {
+        val = [val]
+      }
+
+      utils.forEach(val, function parseValue(v) {
+        if (utils.isDate(v)) {
+          v = v.toISOString()
+        } else if (utils.isObject(v)) {
+          v = JSON.stringify(v)
+        }
+        parts.push(encode(key) + '=' + encode(v))
+      })
+    })
+
+    serializedParams = parts.join('&')
+  }
+
+  if (serializedParams) {
+    var hashmarkIndex = url.indexOf('#')
+    if (hashmarkIndex !== -1) {
+      url = url.slice(0, hashmarkIndex)
+    }
+
+    url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
+  }
+
+  return url
+}

+ 14 - 0
common/luch-request/helpers/combineURLs.js

@@ -0,0 +1,14 @@
+'use strict'
+
+/**
+ * Creates a new URL by combining the specified URLs
+ *
+ * @param {string} baseURL The base URL
+ * @param {string} relativeURL The relative URL
+ * @returns {string} The combined URL
+ */
+export default function combineURLs(baseURL, relativeURL) {
+  return relativeURL
+    ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
+    : baseURL
+}

+ 14 - 0
common/luch-request/helpers/isAbsoluteURL.js

@@ -0,0 +1,14 @@
+'use strict'
+
+/**
+ * Determines whether the specified URL is absolute
+ *
+ * @param {string} url The URL to test
+ * @returns {boolean} True if the specified URL is absolute, otherwise false
+ */
+export default function isAbsoluteURL(url) {
+  // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
+  // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
+  // by any combination of letters, digits, plus, period, or hyphen.
+  return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
+}

+ 2 - 0
common/luch-request/index.js

@@ -0,0 +1,2 @@
+import Request from './core/Request'
+export default Request

+ 95 - 0
common/luch-request/utils.js

@@ -0,0 +1,95 @@
+'use strict'
+
+// utils is a library of generic helper functions non-specific to axios
+
+var toString = Object.prototype.toString
+
+/**
+ * Determine if a value is an Array
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is an Array, otherwise false
+ */
+export function isArray (val) {
+  return toString.call(val) === '[object Array]'
+}
+
+
+/**
+ * Determine if a value is an Object
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is an Object, otherwise false
+ */
+export function isObject (val) {
+  return val !== null && typeof val === 'object'
+}
+
+/**
+ * Determine if a value is a Date
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is a Date, otherwise false
+ */
+export function isDate (val) {
+  return toString.call(val) === '[object Date]'
+}
+
+/**
+ * Determine if a value is a URLSearchParams object
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is a URLSearchParams object, otherwise false
+ */
+export function isURLSearchParams (val) {
+  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams
+}
+
+
+/**
+ * Iterate over an Array or an Object invoking a function for each item.
+ *
+ * If `obj` is an Array callback will be called passing
+ * the value, index, and complete array for each item.
+ *
+ * If 'obj' is an Object callback will be called passing
+ * the value, key, and complete object for each property.
+ *
+ * @param {Object|Array} obj The object to iterate
+ * @param {Function} fn The callback to invoke for each item
+ */
+export function forEach (obj, fn) {
+  // Don't bother if no value provided
+  if (obj === null || typeof obj === 'undefined') {
+    return
+  }
+
+  // Force an array if not already something iterable
+  if (typeof obj !== 'object') {
+    /*eslint no-param-reassign:0*/
+    obj = [obj]
+  }
+
+  if (isArray(obj)) {
+    // Iterate over array values
+    for (var i = 0, l = obj.length; i < l; i++) {
+      fn.call(null, obj[i], i, obj)
+    }
+  } else {
+    // Iterate over object keys
+    for (var key in obj) {
+      if (Object.prototype.hasOwnProperty.call(obj, key)) {
+        fn.call(null, obj[key], key, obj)
+      }
+    }
+  }
+}
+
+/**
+ * 是否为boolean 值
+ * @param val
+ * @returns {boolean}
+ */
+export function isBoolean(val) {
+  return typeof val === 'boolean'
+}

+ 31 - 0
common/router/index.js

@@ -0,0 +1,31 @@
+import modules from './modules'
+import Vue from 'vue'
+import Router from '@/plugin/uni-simple-router/index.js'
+import {ACCESS_TOKEN} from '@/common/util/constants.js'
+
+Vue.use(Router)
+//初始化
+const router = new Router({
+	encodeURI:true,  
+    routes: [...modules]//路由表
+});
+
+const whiteList = ['/pages/login/login'] 
+//全局路由前置守卫
+router.beforeEach((to, from, next) => {
+	let token=uni.getStorageSync(ACCESS_TOKEN);
+	if(token){
+		 next()
+	}else{
+		if (whiteList.indexOf(to.path) !== -1) {
+		  next()
+		}else{
+		  next({ path: '/pages/login/login'})
+		}
+	} 
+})
+// 全局路由后置守卫
+router.afterEach((to, from) => {
+	console.log("afterEach")
+})
+export default router;

+ 10 - 0
common/router/modules/index.js

@@ -0,0 +1,10 @@
+const files = require.context('.', false, /\.js$/)
+const modules = []
+
+files.keys().forEach(key => {
+  if (key === './index.js') return
+  const item = files(key).default
+  modules.push(...item)
+})
+
+export default modules

+ 69 - 0
common/router/modules/routes.js

@@ -0,0 +1,69 @@
+const routes = [
+	{
+	 path: "/pages/login/login",
+	 name: 'login',
+		 meta: {
+			 title: '登录',
+		 },
+	},
+	{
+        //注意:path必须跟pages.json中的地址对应,最前面别忘了加'/'哦
+      path: '/pages/index/index',
+      name: 'index',
+        meta: {
+	        title: '主页',
+	    },
+    },
+	{
+	    //注意:path必须跟pages.json中的地址对应,最前面别忘了加'/'哦
+	  path: '/pages/home/home',
+	  //aliasPath:'/',  //对于h5端你必须在首页加上aliasPath并设置为/
+	  name: 'home',
+	    meta: {
+	        title: '首页',
+	    },
+	},
+    {
+	    path: '/pages/user/people',
+        name: 'people',
+        meta: {
+	        title: '个人中心',
+	    },
+	},
+	{
+	    path: '/pages/user/userdetail',
+	    name: 'userdetail',
+	    meta: {
+	        title: '个人详情',
+	    },
+	},
+	{
+	    path: '/pages/user/useredit',
+	    name: 'useredit',
+	    meta: {
+	        title: '个人编辑',
+	    },
+	},
+	{
+	    path: '/pages/user/userexit',
+	    name: 'userexit',
+	    meta: {
+	        title: '退出',
+	    },
+	},
+	{
+	    path: '/pages/common/exit',
+	    name: 'exit',
+	    meta: {
+	        title: '退出',
+	    },
+	},
+	{
+	    path: '/pages/common/success',
+	    name: 'success',
+	    meta: {
+	        title: 'success',
+	    },
+	},
+]
+export default routes

+ 16 - 0
common/service/config.service.js

@@ -0,0 +1,16 @@
+let BASE_URL = ''
+
+
+if (process.env.NODE_ENV == 'development') {
+    BASE_URL = 'http://boot.jeecg.org:8080/jeecg-boot' // 开发环境
+} else {
+	BASE_URL = 'http://boot.jeecg.org:8080/jeecg-boot' // 生产环境
+}
+let staticDomainURL = BASE_URL+ '/sys/common/static';
+
+const configService = {
+	apiUrl: BASE_URL,
+	staticDomainURL: staticDomainURL
+};
+
+export default configService

+ 110 - 0
common/service/service.js

@@ -0,0 +1,110 @@
+import Request from '@/common/luch-request/index.js'
+import {ACCESS_TOKEN} from '@/common/util/constants.js'
+import configService from './config.service.js'
+import tip from '@/common/util/tip.js';
+import store from '@/store/index.js';
+
+let apiUrl = configService.apiUrl;
+
+const getTokenStorage = () => {
+	let token = ''
+	try{
+		token = uni.getStorageSync(ACCESS_TOKEN)
+	}catch(e){
+		//TODO handle the exception
+		console.log("getTokenStorage",token)
+	}
+	return token
+}
+
+
+
+const http = new Request()
+http.setConfig((config) => { /* 设置全局配置 */
+  config.baseUrl = apiUrl /* 根域名不同 */
+  config.header = {
+    ...config.header
+  }
+  return config
+})
+
+/**
+ * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject)
+ * @param { Number } statusCode - 请求响应体statusCode(只读)
+ * @return { Boolean } 如果为true,则 resolve, 否则 reject
+ */
+// 有默认,非必写
+http.validateStatus = (statusCode) => {
+  return statusCode === 200
+}
+
+http.interceptor.request((config, cancel) => { /* 请求之前拦截器 */
+  tip.alert(config.baseUrl)
+  config.header = {
+    ...config.header,
+     'X-Access-Token':getTokenStorage()
+  }
+ config.timeout = 9000
+  /*
+  if (!token) { // 如果token不存在,调用cancel 会取消本次请求,但是该函数的catch() 仍会执行
+    cancel('token 不存在') // 接收一个参数,会传给catch((err) => {}) err.errMsg === 'token 不存在'
+  }
+  */
+  return config
+})
+
+// 必须使用异步函数,注意
+http.interceptor.response(async (response) => { /* 请求之后拦截器 */
+  // if (response.data.code !== 200) { // 服务端返回的状态码不等于200,则reject()
+  //   return Promise.reject(response)
+  // }
+  return response
+}, (response) => {
+	// 请求错误做点什么
+  console.log("请求错误做点什么",response);
+  if (response) {
+      let data = response.data
+      const token = uni.getStorageSync(ACCESS_TOKEN)
+      console.log("------异常响应------",token)
+      console.log("------异常响应------",data.status)
+      switch (data.status) {
+        case 403:
+          tip.error('拒绝访问');
+          break
+        case 500:
+          if(!token || data.message=="Token失效,请重新登录"){
+            let timeout=setTimeout(tip.alert('登录已过期'), 1000);
+            store.dispatch('Logout').then(() => {
+				clearTimeout(timeout)
+                window.location.reload()
+            }) 
+          }
+          break
+        case 404:
+          break
+        case 504:
+         break
+        case 401:
+          if (token) {
+           /* store.dispatch('Logout').then(() => {
+              setTimeout(() => {
+                window.location.reload()
+              }, 1500)
+            }) */
+          }
+          break
+        default:
+          tip.error({
+            duration: 0,
+            forbidClick: true,
+            message: data.message
+          });
+          break
+      }
+    }
+  return response
+})
+
+export {
+  http
+}

+ 101 - 0
common/util/MinCache.js

@@ -0,0 +1,101 @@
+let cacheMap =  new Map()
+let timeoutDefault = 1200
+ 
+function isTimeout (name) {
+  const data = cacheMap.get(name)
+  if (!data) return true
+  if (data.timeout === 0) return false 
+  const currentTime = Date.now()
+  const overTime = (currentTime - data.createTime) / 1000
+  if (overTime > data.timeout) {
+    cacheMap.delete(name)
+    if (name.startsWith('_')) {
+      try {
+        uni.removeStorageSync(name)
+      } catch (e) {
+        console.log(e)
+      }
+    }
+    return true
+  }
+  return false
+}
+ 
+class CacheCell {
+  constructor (data, timeout) {
+    this.data = data
+    this.timeout = timeout
+    this.createTime = Date.now()
+  }
+}
+ 
+class MinCache {
+  constructor (timeout) {
+    try {
+      const res = uni.getStorageInfoSync()
+      res.keys.forEach(name => {
+        try {
+          const value = uni.getStorageSync(name)
+          cacheMap.set(name, value)
+        } catch (e) {
+          console.log(e)
+        }
+      })
+    } catch (e) {
+      console.log(e)
+    }
+    timeoutDefault = timeout
+  }
+  set (name, data, timeout = timeoutDefault) {
+    const cachecell = new CacheCell(data, timeout)
+    let cache = null
+    if (name.startsWith('_')) {
+      try {
+        uni.setStorageSync(name, cachecell)
+        cache = cacheMap.set(name, cachecell)
+      } catch (e) {
+        console.log(e)
+      }
+    } else {
+      cache = cacheMap.set(name, cachecell)
+    }
+    return cache
+  }
+  get (name) {
+    return isTimeout(name) ? null : cacheMap.get(name).data
+  }
+  delete (name) {
+    let value = false
+    if (name.startsWith('_')) {
+      try {
+        uni.removeStorageSync(name)
+        value = cacheMap.delete(name)
+      } catch (e) {
+        console.log(e)
+      }
+    } else {
+      value = cacheMap.delete(name)
+    }
+    return value
+  }
+  has (name) {
+    return !isTimeout(name)
+  }
+  clear () {
+    let value = false
+    try {
+      uni.clearStorageSync()
+      cacheMap.clear()
+      value = true
+    } catch (e) {
+      console.log(e)
+    }
+    return value
+  }
+}
+ 
+MinCache.install = function (Vue, {timeout = 1200} = {}) {
+  Vue.prototype.$cache = new MinCache(timeout)
+}
+ 
+export default MinCache

+ 73 - 0
common/util/appUpdate.js

@@ -0,0 +1,73 @@
+//APP更新
+
+export default function appUpdate() {
+	uni.request({
+		url: 'http://app.myhjdc.cn/update.json', //检查更新的服务器地址
+		data: {
+			appid: plus.runtime.appid,
+			version: plus.runtime.version,
+			imei: plus.device.imei
+		},
+		success: (res) => {
+			plus.runtime.getProperty(plus.runtime.appid, function(wgtinfo) {
+				let client_version = wgtinfo.version
+				var flag_update = client_version.split(".").splice(0, 2).join(".") != res.data.version.split(".").splice(0, 2)
+					.join(".")
+				var flag_hot = (Number(client_version.split(".")[2]) < Number(res.data.version.split(".")[2])) & !flag_update
+				console.log(client_version)
+				console.log(flag_update)
+				console.log(flag_hot)
+
+				if (flag_update) {
+					// 提醒用户更新
+					uni.showModal({
+						title: '更新提示',
+						content: res.data.note,
+						success: (showResult) => {
+							if (showResult.confirm) {
+								plus.nativeUI.toast("正在准备环境,请稍后!");
+								console.log(res.data.url, )
+								var dtask = plus.downloader.createDownload(res.data.url, {
+									method: 'GET',
+									filename: '_doc/update/'
+								}, function(d, status) {
+									if (status == 200) {
+										var path = d.filename; //下载apk
+										plus.runtime.install(path); // 自动安装apk文件
+									} else {
+										plus.nativeUI.alert('版本更新失败:' + status);
+									}
+								});
+								dtask.start();
+							}
+						}
+					})
+				} else if (flag_hot) {
+					uni.downloadFile({
+						url: res.data.wgtUrl,
+						success: (downloadResult) => {
+							console.log(downloadResult.tempFilePath)
+							if (downloadResult.statusCode === 200) {
+								plus.nativeUI.toast(`正在热更新!${res.data.versionCode}`);
+								plus.runtime.install(downloadResult.tempFilePath, {
+									force: false
+								}, function() {
+									plus.nativeUI.toast("热更新成功");
+									plus.runtime.restart();
+								}, function(e) {
+									console.log(e)
+									plus.nativeUI.toast(`热更新失败:${e.message}`);
+								});
+							}
+						}
+					});
+				}
+
+			});
+
+
+
+
+		}
+	})
+}

+ 14 - 0
common/util/constants.js

@@ -0,0 +1,14 @@
+export const ACCESS_TOKEN = 'Access-Token'
+export const USER_NAME = 'login_username'
+export const USER_INFO = 'login_user_info'
+
+
+const STORAGE_OPTIONS = {
+  namespace: 'pro__', // key prefix
+    name: 'ls', // name variable Vue.[ls] or this.[$ls],
+    storage: 'local', // storage name session, local, memory
+}
+
+export default STORAGE_OPTIONS;
+
+

+ 130 - 0
common/util/tip.js

@@ -0,0 +1,130 @@
+/**
+ * 提示与加载工具类
+ */
+export default class Tips {
+  constructor() {
+    this.isLoading = false;
+  }
+  /**
+   * 弹出提示框
+   */
+
+  static success(title, duration = 1000) {
+    setTimeout(() => {
+      uni.showToast({
+        title: title,
+        icon: "success",
+        mask: true,
+        duration: duration
+      });
+    }, 300);
+    if (duration > 0) {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve();
+        }, duration);
+      });
+    }
+  }
+
+  /**
+   * 弹出确认窗口
+   */
+  static confirm(text,showCancel, payload = {}, title = "提示") {
+    return new Promise((resolve, reject) => {
+      uni.showModal({
+        title: title,
+        content: text,
+        showCancel: showCancel,
+        success: res => {
+          if (res.confirm) {
+            resolve(payload);
+          } else if (res.cancel) {
+            reject(payload);
+          }
+        },
+        fail: res => {
+          reject(payload);
+        }
+      });
+    });
+  }
+
+  static toast(title, onHide, icon = "none") {
+    setTimeout(() => {
+      uni.showToast({
+        title: title,
+        icon: icon,
+        mask: true,
+        duration:1000
+      });
+    }, 300);
+
+    // 隐藏结束回调
+    if (onHide) {
+      setTimeout(() => {
+        onHide();
+      }, 500);
+    }
+  }
+
+  /**
+   * 警告框
+   */
+  static alert(title) {
+    uni.showToast({
+      title: title,
+      image: "../../static/alert.png",
+      mask: true,
+      duration: 1500
+    });
+  }
+
+  /**
+   * 错误框
+   */
+
+  static error(title, onHide) {
+    uni.showToast({
+      title: title,
+      image: "../../static/error.png",
+      mask: true,
+      duration: 1500
+    });
+    // 隐藏结束回调
+    if (onHide) {
+      setTimeout(() => {
+        onHide();
+      }, 500);
+    }
+  }
+
+  /**
+   * 弹出加载提示
+   */
+  static loading(title = "加载中") {
+    if (Tips.isLoading) {
+      return;
+    }
+    Tips.isLoading = true;
+    uni.showLoading({
+      title: title,
+      mask: true
+    });
+  }
+
+  /**
+   * 加载完毕
+   */
+  static loaded() {
+    if (Tips.isLoading) {
+      Tips.isLoading = false;
+      uni.hideLoading();
+    }
+  }
+}
+
+/**
+ * 静态变量,是否加载中
+ */
+Tips.isLoading = false;

+ 118 - 0
common/util/work.js

@@ -0,0 +1,118 @@
+/**
+ * 常用服务
+ * useful server
+ */
+export const us = {
+  data:[
+    {
+      title:"日报",
+      icon:"/static/icon/daycall.png",
+      description:"记录每天的工作经验和心得",
+      useCount:1000
+    },{
+      title:"周报",
+      icon:"/static/icon/week.png",
+      description:"总结每周的工作情况和下周计划",
+      useCount:10000
+    },{
+      title:"考勤",
+      icon:"/static/icon/kaoqin.png",
+      description:"工作考勤",
+      page:'clockHome',
+      useCount:10000
+    },{
+      title:"日程",
+      icon:"/static/icon/richeng.png",
+      description:"建立和查看个人工作安排",
+      useCount:10000,
+      page:'planList'
+    },{
+      title:"请假申请",
+      icon:"/static/icon/liucheng.png",
+      description:"请假申请",
+      useCount:10000,
+      page:'leave'
+    },
+      {
+          title:"出差申请",
+          icon:"/static/icon/liucheng.png",
+          description:"出差申请",
+          useCount:10000,
+          page:'businesStrip'
+      },
+      {
+          title:"公文发文",
+          icon:"/static/icon/liucheng.png",
+          description:"公文发文",
+          useCount:10000,
+          page:'docSend'
+      },
+      {
+          title:"通知公告",
+          icon:"/static/icon/tongzhi.png",
+          description:"查看企业对员工下发的通知公告",
+          useCount:10000,
+          page:'annotationList'
+    },{
+          title:"内部邮件",
+          icon:"/static/icon/duanxin.png",
+          description:"查看内部消息",
+          useCount:10000,
+          page:'mailHome',
+          dot:false
+      },{
+          title:"通讯录",
+          icon:"/static/icon/duanxin.png",
+          description:"查看部门,组员",
+          useCount:10000,
+          page:'communication',
+      }
+  ]
+}
+
+
+/**
+ * other server 其他服务
+ */
+export const os = {
+  data:[
+    {
+      title:"新闻中心",
+      icon:"/static/icon/daycall.png",
+      description:"新闻中心",
+      page:'columnList',
+      useCount:10000
+    },{
+      title:"投票中心",
+      icon:"/static/icon/week.png",
+      description:"投票中心",
+      useCount:10000
+    },{
+      title:"任务中心",
+      icon:"/static/icon/kaoqin.png",
+      description:"任务中心",
+      useCount:10000
+    },{
+      title:"文档中心",
+      icon:"/static/icon/richeng.png",
+      description:"文档中心",
+      useCount:10000,
+      page:'fileHome'
+    },{
+      title:"合同",
+      icon:"/static/icon/liucheng.png",
+      description:"合同",
+      useCount:10000
+    },{
+      title:"会议",
+      icon:"/static/icon/tongzhi.png",
+      description:"会议",
+      useCount:10000
+    },{
+      title:"客户关系",
+      icon:"/static/icon/duanxin.png",
+      description:"客户关系",
+      useCount:10000
+    }
+  ]
+}

+ 106 - 0
components/my-componets/my-image-upload.vue

@@ -0,0 +1,106 @@
+<template>
+	<view class="margin-top">
+		<view class="cu-bar bg-white ">
+			<view class="action">
+				{{label}}
+			</view>
+			<view class="action">
+				{{imgList.length}}/{{maxImg}}
+			</view>
+		</view>
+		<view class="cu-form-group">
+			<view class="grid col-4 grid-square flex-sub">
+				<view class="bg-img" v-for="(item,index) in imgList" :key="index" @tap="ViewImage" :data-url="imgList[index]">
+					<image :src="imgList[index]" mode="aspectFill"></image>
+					<view class="cu-tag bg-red" @tap.stop="DelImg" :data-index="index">
+						<text class='cuIcon-close'></text>
+					</view>
+				</view>
+				<view class="solids" @tap="ChooseImage" v-if="imgList.length<maxImg">
+					<text class='cuIcon-cameraadd'></text>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	
+	export default {
+		name: 'MyImageUpoad',
+		props: {
+			value: {type:String,default:''},
+			label:{type:String,default:'图片上传'},
+			maxImg: {
+				type: Number,
+				default: 3
+			},
+
+		},
+		mounted:function(){
+			if (this.value.split(',')!=''){
+				this.value.split(',').forEach(res=>{
+					this.imgList.push(baseurl+res)
+				})
+			}
+		},
+		data() {
+			return {
+				imgList: [],
+				pathlist:[],
+			}
+		},
+		methods: {
+			ChooseImage() {
+				uni.chooseImage({
+					count: this.maxImg, //默认9
+					sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
+					sourceType: ['album','camera'], //从相册选择
+					success: (res) => {
+						uni.uploadFile({
+							url: `${baseurl}systemController/filedeal.do?isup=1`,
+							filePath: res.tempFilePaths[0],
+							name: 'file',
+							success: (uploadFileRes) => {
+								let path = JSON.parse(uploadFileRes.data).obj
+								this.pathlist.push(path);
+								this.$emit('input',this.pathlist.join(','))
+								if (this.imgList.length != 0) {
+									this.imgList = this.imgList.concat(res.tempFilePaths)
+								} else {
+									this.imgList = res.tempFilePaths
+								}
+							}
+						})
+
+					}
+				});
+			},
+			ViewImage(e) {
+				uni.previewImage({
+					urls: this.imgList,
+					current: e.currentTarget.dataset.url
+				});
+			},
+			DelImg(e) {
+				uni.showModal({
+					title: '提示',
+					content: '确认要删除吗',
+					cancelText: '取消',
+					confirmText: '确认',
+					success: res => {
+						if (res.confirm) {
+							this.pathlist.splice(e.currentTarget.dataset.index,1)
+							this.imgList.splice(e.currentTarget.dataset.index, 1)
+							this.$emit('input',this.pathlist.join(','))
+						}
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 46 - 0
components/my-componets/my-page.vue

@@ -0,0 +1,46 @@
+<template>
+	<view>
+		<scroll-view :scroll-y="modalName==null" class="page" :class="modalName!=null?'show':''">
+			<cu-custom bgColor="bg-gradual-pink" :isBack="true">
+				<block slot="backText">{{back}}</block>
+				<block slot="content">{{title}}</block>
+			</cu-custom>
+			<slot></slot>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'MyPage',
+		props: {
+			title: {
+				type: String,
+				default: '标题'
+			},
+			back: {
+				type: String,
+				default: '返回'
+			},
+			modalName:  {
+				type: String,
+				default: null
+			},
+		},
+		watch: {
+
+		},
+		computed: {
+
+		},
+		data() {
+			return {
+				
+			}
+		},
+		methods: {}
+	}
+</script>
+
+<style>
+</style>

+ 80 - 0
components/my-componets/my-select.vue

@@ -0,0 +1,80 @@
+<template>
+		<view class="cu-form-group">
+			<view class="title">{{label}}</view>
+		<picker @change="PickerChange" :value="index" :range-key="rangeKey" :range="dictOptions">
+			<view class="picker">
+				{{index>-1?dictOptions[index][rangeKey]:'请选择'}}
+			</view>
+		</picker>
+		</view>
+</template>
+
+<script>
+	export default {
+		name: 'MySelect',
+		props: {
+			dictCode: String,
+			value: String,
+			label:String,
+			rangeKey:{type:String,default:'label'},
+			valueKey:{type:String,default:'value'},
+			searchUrl:String,
+
+		},
+		watch: {
+			dictCode: {
+				immediate: true,
+				handler() {
+					this.initDictData()
+				},
+			},
+		},
+		computed: {
+			
+		},
+		data() {
+			return {
+				dictOptions: [],
+				index: -1,
+			}
+		},
+		methods: {
+			initDictData() {
+				//根据字典Code, 初始化字典数组
+				if (this.searchUrl){
+					this.$api.get(this.searchUrl,{"code":this.dictCode}).then(res=>{
+						this.dictOptions=res;
+						this.getIndex()
+					})
+				}else{
+					this.$api.getDict(this.dictCode).then(res => {
+						this.dictOptions = res;
+						this.getIndex()
+					})
+				}
+			},
+			PickerChange(e) {
+				this.index=e.detail.value
+				if(this.index==-1){
+					this.index=0
+					this.$emit('input',this.dictOptions[0][this.valueKey])
+				}else{
+					this.$emit('input', this.dictOptions[this.index][this.valueKey]);
+				}
+			},
+			getIndex() {
+				for (var i = 0; i < this.dictOptions.length; i++) {
+					if (this.dictOptions[i].value == this.value) {
+						this.index = i
+						return
+					}
+				}
+				this.index=-1
+			},
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 29 - 0
components/uni-popup/message.js

@@ -0,0 +1,29 @@
+export default {
+	created() {
+		if (this.type === 'message') {
+			// 获取自组件对象
+			this.maskShow = false
+			this.children = null
+		}
+	},
+	created() {
+		if (this.type === 'message') {
+			// 不显示遮罩
+			this.maskShow = false 
+			// 获取子组件对象
+			this.childrenMsg = null
+		}
+	},
+	methods: {
+		customOpen() {
+			if (this.childrenMsg) {
+				this.childrenMsg.open()
+			}
+		},
+		customClose() {
+			if (this.childrenMsg) {
+				this.childrenMsg.close()
+			}
+		}
+	}
+}

+ 25 - 0
components/uni-popup/popup.js

@@ -0,0 +1,25 @@
+import message from './message.js';
+// 定义 type 类型:弹出类型:top/bottom/center
+const config = {
+	// 顶部弹出
+	top:'top',
+	// 底部弹出
+	bottom:'bottom',
+	// 居中弹出
+	center:'center',
+	// 消息提示
+	message:'top',
+	// 对话框
+	dialog:'center',
+	// 分享
+	share:'bottom',
+}
+
+export default {
+	data(){
+		return {
+			config:config
+		}
+	},
+	mixins: [message],
+}

+ 243 - 0
components/uni-popup/uni-popup-dialog.vue

@@ -0,0 +1,243 @@
+<template>
+	<view class="uni-popup-dialog">
+		<view class="uni-dialog-title">
+			<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{title}}</text>
+		</view>
+		<view class="uni-dialog-content">
+			<text class="uni-dialog-content-text" v-if="mode === 'base'">{{content}}</text>
+			<input v-else class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholder" :focus="focus" >
+		</view>
+		<view class="uni-dialog-button-group">
+			<view class="uni-dialog-button" @click="close">
+				<text class="uni-dialog-button-text">取消</text>
+			</view>
+			<view class="uni-dialog-button uni-border-left" @click="onOk">
+				<text class="uni-dialog-button-text uni-button-color">确定</text>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	/**
+	 * PopUp 弹出层-对话框样式
+	 * @description 弹出层-对话框样式
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} value input 模式下的默认值
+	 * @property {String} placeholder input 模式下输入提示
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} mode = [base|input] 模式、
+	 * 	@value base 基础对话框
+	 * 	@value input 可输入对话框
+	 * @property {String} content 对话框内容
+	 * @property {Boolean} beforeClose 是否拦截取消事件
+	 * @event {Function} confirm 点击确认按钮触发
+	 * @event {Function} close 点击取消按钮触发
+	 */
+
+	export default {
+		name: "uniPopupDialog",
+		props: {
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			placeholder: {
+				type: [String, Number],
+				default: '请输入内容'
+			},
+			/**
+			 * 对话框主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'error'
+			},
+			/**
+			 * 对话框模式 base/input
+			 */
+			mode: {
+				type: String,
+				default: 'base'
+			},
+			/**
+			 * 对话框标题
+			 */
+			title: {
+				type: String,
+				default: '提示'
+			},
+			/**
+			 * 对话框内容
+			 */
+			content: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 拦截取消事件 ,如果拦截取消事件,必须监听close事件,执行 done()
+			 */
+			beforeClose: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				dialogType: 'error',
+				focus: false,
+				val: ""
+			}
+		},
+		inject: ['popup'],
+		watch: {
+			type(val) {
+				this.dialogType = val
+			},
+			mode(val) {
+				if (val === 'input') {
+					this.dialogType = 'info'
+				}
+			},
+			value(val) {
+				this.val = val
+			}
+		},
+		created() {
+			// 对话框遮罩不可点击
+			this.popup.mkclick = false
+			if (this.mode === 'input') {
+				this.dialogType = 'info'
+				this.val = this.value
+			} else {
+				this.dialogType = this.type
+			}
+		},
+		mounted() {
+			this.focus = true
+		},
+		methods: {
+			/**
+			 * 点击确认按钮
+			 */
+			onOk() {
+				this.$emit('confirm', () => {
+					this.popup.close()
+					if (this.mode === 'input') this.val = this.value
+				}, this.mode === 'input' ? this.val : '')
+			},
+			/**
+			 * 点击取消按钮
+			 */
+			close() {
+				if (this.beforeClose) {
+					this.$emit('close', () => {
+						this.popup.close()
+					})
+					return
+				}
+				this.popup.close()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-popup-dialog {
+		width: 300px;
+		border-radius: 15px;
+		background-color: #fff;
+	}
+
+	.uni-dialog-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		padding-top: 15px;
+		padding-bottom: 5px;
+	}
+
+	.uni-dialog-title-text {
+		font-size: 16px;
+		font-weight: 500;
+	}
+
+	.uni-dialog-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 5px 15px 15px 15px;
+	}
+
+	.uni-dialog-content-text {
+		font-size: 14px;
+		color: #6e6e6e;
+	}
+
+	.uni-dialog-button-group {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		border-top-color: #f5f5f5;
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-dialog-button {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+
+		flex: 1;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 45px;
+	}
+
+	.uni-border-left {
+		border-left-color: #f0f0f0;
+		border-left-style: solid;
+		border-left-width: 1px;
+	}
+
+	.uni-dialog-button-text {
+		font-size: 14px;
+	}
+
+	.uni-button-color {
+		color: $uni-color-primary;
+	}
+
+	.uni-dialog-input {
+		flex: 1;
+		font-size: 14px;
+	}
+
+	.uni-popup__success {
+		color: $uni-color-success;
+	}
+
+	.uni-popup__warn {
+		color: $uni-color-warning;
+	}
+
+	.uni-popup__error {
+		color: $uni-color-error;
+	}
+
+	.uni-popup__info {
+		color: #909399;
+	}
+</style>

+ 116 - 0
components/uni-popup/uni-popup-message.vue

@@ -0,0 +1,116 @@
+<template>
+	<view class="uni-popup-message" :class="'uni-popup__'+[type]">
+		<text class="uni-popup-message-text" :class="'uni-popup__'+[type]+'-text'">{{message}}</text>
+	</view>
+</template>
+
+<script>
+	
+	/**
+	 * PopUp 弹出层-消息提示
+	 * @description 弹出层-消息提示
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} message 消息提示文字
+	 * @property {String} duration 显示时间,设置为 0 则不会自动关闭
+	 */
+	
+	export default {
+		name: 'UniPopupMessage',
+		props: {
+			/**
+			 * 主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'success'
+			},
+			/**
+			 * 消息文字
+			 */
+			message: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 显示时间,设置为 0 则不会自动关闭
+			 */
+			duration: {
+				type: Number,
+				default: 3000
+			}
+		},
+		inject: ['popup'],
+		data() {
+			return {}
+		},
+		created() {
+			this.popup.childrenMsg = this
+		},
+		methods: {
+			open() {
+				if (this.duration === 0) return
+				clearTimeout(this.popuptimer)
+				this.popuptimer = setTimeout(() => {
+					this.popup.close()
+				}, this.duration)
+			},
+			close() {
+				clearTimeout(this.popuptimer)
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup-message {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		background-color: #e1f3d8;
+		padding: 10px 15px;
+		border-color: #eee;
+		border-style: solid;
+		border-width: 1px;
+	}
+	.uni-popup-message-text {
+		font-size: 14px;
+		padding: 0;
+	}
+
+	.uni-popup__success {
+		background-color: #e1f3d8;
+	}
+
+	.uni-popup__success-text {
+		color: #67C23A;
+	}
+
+	.uni-popup__warn {
+		background-color: #faecd8;
+	}
+
+	.uni-popup__warn-text {
+		color: #E6A23C;
+	}
+
+	.uni-popup__error {
+		background-color: #fde2e2;
+	}
+
+	.uni-popup__error-text {
+		color: #F56C6C;
+	}
+
+	.uni-popup__info {
+		background-color: #F2F6FC;
+	}
+
+	.uni-popup__info-text {
+		color: #909399;
+	}
+</style>

+ 165 - 0
components/uni-popup/uni-popup-share.vue

@@ -0,0 +1,165 @@
+<template>
+	<view class="uni-popup-share">
+		<view class="uni-share-title"><text class="uni-share-title-text">{{title}}</text></view>
+		<view class="uni-share-content">
+			<view class="uni-share-content-box">
+				<view class="uni-share-content-item" v-for="(item,index) in bottomData" :key="index" @click.stop="select(item,index)">
+					<image class="uni-share-image" :src="item.icon" mode="aspectFill"></image>
+					<text class="uni-share-text">{{item.text}}</text>
+				</view>
+
+			</view>
+		</view>
+		<view class="uni-share-button-box">
+			<button class="uni-share-button" @click="close">取消</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'UniPopupShare',
+		props: {
+			title: {
+				type: String,
+				default: '分享到'
+			}
+		},
+		inject: ['popup'],
+		data() {
+			return {
+				bottomData: [{
+						text: '微信',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-2.png',
+						name: 'wx'
+					},
+					{
+						text: '支付宝',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-8.png',
+						name: 'wx'
+					},
+					{
+						text: 'QQ',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/gird-3.png',
+						name: 'qq'
+					},
+					{
+						text: '新浪',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-1.png',
+						name: 'sina'
+					},
+					{
+						text: '百度',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-7.png',
+						name: 'copy'
+					},
+					{
+						text: '其他',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-5.png',
+						name: 'more'
+					}
+				]
+			}
+		},
+		created() {},
+		methods: {
+			/**
+			 * 选择内容
+			 */
+			select(item, index) {
+				this.$emit('select', {
+					item,
+					index
+				}, () => {
+					this.popup.close()
+				})
+			},
+			/**
+			 * 关闭窗口
+			 */
+			close() {
+				this.popup.close()
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup-share {
+		background-color: #fff;
+	}
+	.uni-share-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		height: 40px;
+	}
+	.uni-share-title-text {
+		font-size: 14px;
+		color: #666;
+	}
+	.uni-share-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		padding-top: 10px;
+	}
+	
+	.uni-share-content-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		flex-wrap: wrap;
+		width: 360px;
+	}
+	
+	.uni-share-content-item {
+		width: 90px;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		padding: 10px 0;
+		align-items: center;
+	}
+	
+	.uni-share-content-item:active {
+		background-color: #f5f5f5;
+	}
+	
+	.uni-share-image {
+		width: 30px;
+		height: 30px;
+	}
+	
+	.uni-share-text {
+		margin-top: 10px;
+		font-size: 14px;
+		color: #3B4144;
+	}
+	
+	.uni-share-button-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		padding: 10px 15px;
+	}
+	
+	.uni-share-button {
+		flex: 1;
+		border-radius: 50px;
+		color: #666;
+		font-size: 16px;
+	}
+	
+	.uni-share-button::after {
+		border-radius: 50px;
+	}
+</style>

+ 294 - 0
components/uni-popup/uni-popup.vue

@@ -0,0 +1,294 @@
+<template>
+	<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">
+		<uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans"
+		 @click="onTap" />
+		<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
+			<view class="uni-popup__wrapper-box" @click.stop="clear">
+				<slot />
+			</view>
+		</uni-transition>
+	</view>
+</template>
+
+<script>
+	import uniTransition from '../uni-transition/uni-transition.vue'
+	import popup from './popup.js'
+	/**
+	 * PopUp 弹出层
+	 * @description 弹出层组件,为了解决遮罩弹层的问题
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} type = [top|center|bottom] 弹出方式
+	 * 	@value top 顶部弹出
+	 * 	@value center 中间弹出
+	 * 	@value bottom 底部弹出
+	 * 	@value message 消息提示
+	 * 	@value dialog 对话框
+	 * 	@value share 底部分享示例
+	 * @property {Boolean} animation = [ture|false] 是否开启动画
+	 * @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
+	 * @event {Function} change 打开关闭弹窗触发,e={show: false}
+	 */
+
+	export default {
+		name: 'UniPopup',
+		components: {
+			uniTransition
+		},
+		props: {
+			// 开启动画
+			animation: {
+				type: Boolean,
+				default: true
+			},
+			// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
+			// message: 消息提示 ; dialog : 对话框
+			type: {
+				type: String,
+				default: 'center'
+			},
+			// maskClick
+			maskClick: {
+				type: Boolean,
+				default: true
+			}
+		},
+		provide() {
+			return {
+				popup: this
+			}
+		},
+		mixins: [popup],
+		watch: {
+			/**
+			 * 监听type类型
+			 */
+			type: {
+				handler: function(newVal) {
+					this[this.config[newVal]]()
+				},
+				immediate: true
+			},
+			/**
+			 * 监听遮罩是否可点击
+			 * @param {Object} val
+			 */
+			maskClick(val) {
+				this.mkclick = val
+			}
+		},
+		data() {
+			return {
+				duration: 300,
+				ani: [],
+				showPopup: false,
+				showTrans: false,
+				maskClass: {
+					'position': 'fixed',
+					'bottom': 0,
+					'top': 0,
+					'left': 0,
+					'right': 0,
+					'backgroundColor': 'rgba(0, 0, 0, 0.4)'
+				},
+				transClass: {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+				},
+				maskShow: true,
+				mkclick: true,
+				popupstyle: 'top'
+			}
+		},
+		created() {
+			this.mkclick = this.maskClick
+			if (this.animation) {
+				this.duration = 300
+			} else {
+				this.duration = 0
+			}
+		},
+		methods: {
+			clear(e) {
+				// TODO nvue 取消冒泡
+				e.stopPropagation()
+			},
+			open() {
+				this.showPopup = true
+				this.$nextTick(() => {
+					new Promise(resolve => {
+						clearTimeout(this.timer)
+						this.timer = setTimeout(() => {
+							this.showTrans = true
+							// fixed by mehaotian 兼容 app 端
+							this.$nextTick(() => {
+								resolve();
+							})
+						}, 50);
+					}).then(res => {
+						// 自定义打开事件
+						clearTimeout(this.msgtimer)
+						this.msgtimer = setTimeout(() => {
+							this.customOpen && this.customOpen()
+						}, 100)
+						this.$emit('change', {
+							show: true,
+							type: this.type
+						})
+					})
+				})
+			},
+			close(type) {
+				this.showTrans = false
+				this.$nextTick(() => {
+					this.$emit('change', {
+						show: false,
+						type: this.type
+					})
+					clearTimeout(this.timer)
+					// 自定义关闭事件
+					this.customOpen && this.customClose()
+					this.timer = setTimeout(() => {
+						this.showPopup = false
+					}, 300)
+				})
+			},
+			onTap() {
+				if (!this.mkclick) return
+				this.close()
+			},
+			/**
+			 * 顶部弹出样式处理
+			 */
+			top() {
+				this.popupstyle = 'top'
+				this.ani = ['slide-top']
+				this.transClass = {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+				}
+			},
+			/**
+			 * 底部弹出样式处理
+			 */
+			bottom() {
+				this.popupstyle = 'bottom'
+				this.ani = ['slide-bottom']
+				this.transClass = {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+					'bottom': 0
+				}
+			},
+			/**
+			 * 中间弹出样式处理
+			 */
+			center() {
+				this.popupstyle = 'center'
+				this.ani = ['zoom-out', 'fade']
+				this.transClass = {
+					'position': 'fixed',
+					/* #ifndef APP-NVUE */
+					'display': 'flex',
+					'flexDirection': 'column',
+					/* #endif */
+					'bottom': 0,
+					'left': 0,
+					'right': 0,
+					'top': 0,
+					'justifyContent': 'center',
+					'alignItems': 'center'
+				}
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup {
+		position: fixed;
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+	.uni-popup__mask {
+		position: absolute;
+		top: 0;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		background-color: $uni-bg-color-mask;
+		opacity: 0;
+	}
+
+	.mask-ani {
+		transition-property: opacity;
+		transition-duration: 0.2s;
+	}
+
+	.uni-top-mask {
+		opacity: 1;
+	}
+
+	.uni-bottom-mask {
+		opacity: 1;
+	}
+
+	.uni-center-mask {
+		opacity: 1;
+	}
+
+	.uni-popup__wrapper {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: absolute;
+	}
+
+	.top {
+		/* #ifdef H5 */
+		top: var(--window-top);
+		/* #endif */
+		/* #ifndef H5 */
+		top: 0;
+		/* #endif */
+	}
+
+	.bottom {
+		bottom: 0;
+	}
+
+	.uni-popup__wrapper-box {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: relative;
+		/* iphonex 等安全区设置,底部安全区适配 */
+		/* #ifndef APP-NVUE */
+		padding-bottom: constant(safe-area-inset-bottom);
+		padding-bottom: env(safe-area-inset-bottom);
+		/* #endif */
+	}
+
+	.content-ani {
+		// transition: transform 0.3s;
+		transition-property: transform, opacity;
+		transition-duration: 0.2s;
+	}
+
+
+	.uni-top-content {
+		transform: translateY(0);
+	}
+
+	.uni-bottom-content {
+		transform: translateY(0);
+	}
+
+	.uni-center-content {
+		transform: scale(1);
+		opacity: 1;
+	}
+</style>

+ 279 - 0
components/uni-transition/uni-transition.vue

@@ -0,0 +1,279 @@
+<template>
+	<view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject"
+	 @click="change">
+		 <slot></slot>
+	</view>
+</template>
+
+<script>
+	// #ifdef APP-NVUE
+	const animation = uni.requireNativePlugin('animation');
+	// #endif
+	/**
+	 * Transition 过渡动画
+	 * @description 简单过渡动画组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=985
+	 * @property {Boolean} show = [false|true] 控制组件显示或隐藏
+     * @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
+     *  @value fade 渐隐渐出过渡
+     *  @value slide-top 由上至下过渡
+     *  @value slide-right 由右至左过渡
+     *  @value slide-bottom 由下至上过渡
+     *  @value slide-left 由左至右过渡
+     *  @value zoom-in 由小到大过渡
+     *  @value zoom-out 由大到小过渡
+	 * @property {Number} duration 过渡动画持续时间
+	 * @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
+	 */
+	export default {
+		name: 'uniTransition',
+		props: {
+			show: {
+				type: Boolean,
+				default: false
+			},
+			modeClass: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			duration: {
+				type: Number,
+				default: 300
+			},
+			styles: {
+				type: Object,
+				default () {
+					return {}
+				}
+			}
+		},
+		data() {
+			return {
+				isShow: false,
+				transform: '',
+				ani: { in: '',
+					active: ''
+				}
+			};
+		},
+		watch: {
+			show: {
+				handler(newVal) {
+					if (newVal) {
+						this.open()
+					} else {
+						this.close()
+					}
+				},
+				immediate: true
+			}
+		},
+		computed: {
+			stylesObject() {
+				let styles = {
+					...this.styles,
+					'transition-duration': this.duration / 1000 + 's'
+				}
+				let transfrom = ''
+				for (let i in styles) {
+					let line = this.toLine(i)
+					transfrom += line + ':' + styles[i] + ';'
+				}
+				return transfrom
+			}
+		},
+		created() {
+			// this.timer = null
+			// this.nextTick = (time = 50) => new Promise(resolve => {
+			// 	clearTimeout(this.timer)
+			// 	this.timer = setTimeout(resolve, time)
+			// 	return this.timer
+			// });
+		},
+		methods: {
+			change() {
+				this.$emit('click', {
+					detail: this.isShow
+				})
+			},
+			open() {
+				clearTimeout(this.timer)
+				this.isShow = true
+				this.transform = ''
+				this.ani.in = ''
+				for (let i in this.getTranfrom(false)) {
+					if (i === 'opacity') {
+						this.ani.in = 'fade-in'
+					} else {
+						this.transform += `${this.getTranfrom(false)[i]} `
+					}
+				}
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this._animation(true)
+					}, 50)
+				})
+
+			},
+			close(type) {
+				clearTimeout(this.timer)
+				this._animation(false)
+			},
+			_animation(type) {
+				let styles = this.getTranfrom(type)
+				// #ifdef APP-NVUE
+				if(!this.$refs['ani']) return
+				animation.transition(this.$refs['ani'].ref, {
+					styles,
+					duration: this.duration, //ms
+					timingFunction: 'ease',
+					needLayout: false,
+					delay: 0 //ms
+				}, () => {
+					if (!type) {
+						this.isShow = false
+					}
+					this.$emit('change', {
+						detail: this.isShow
+					})
+				})
+				// #endif
+				// #ifndef APP-NVUE
+				this.transform = ''
+				for (let i in styles) {
+					if (i === 'opacity') {
+						this.ani.in = `fade-${type?'out':'in'}`
+					} else {
+						this.transform += `${styles[i]} `
+					}
+				}
+				this.timer = setTimeout(() => {
+					if (!type) {
+						this.isShow = false
+					}
+					this.$emit('change', {
+						detail: this.isShow
+					})
+
+				}, this.duration)
+				// #endif
+
+			},
+			getTranfrom(type) {
+				let styles = {
+					transform: ''
+				}
+				this.modeClass.forEach((mode) => {
+					switch (mode) {
+						case 'fade':
+							styles.opacity = type ? 1 : 0
+							break;
+						case 'slide-top':
+							styles.transform += `translateY(${type?'0':'-100%'}) `
+							break;
+						case 'slide-right':
+							styles.transform += `translateX(${type?'0':'100%'}) `
+							break;
+						case 'slide-bottom':
+							styles.transform += `translateY(${type?'0':'100%'}) `
+							break;
+						case 'slide-left':
+							styles.transform += `translateX(${type?'0':'-100%'}) `
+							break;
+						case 'zoom-in':
+							styles.transform += `scale(${type?1:0.8}) `
+							break;
+						case 'zoom-out':
+							styles.transform += `scale(${type?1:1.2}) `
+							break;
+					}
+				})
+				return styles
+			},
+			_modeClassArr(type) {
+				let mode = this.modeClass
+				if (typeof(mode) !== "string") {
+					let modestr = ''
+					mode.forEach((item) => {
+						modestr += (item + '-' + type + ',')
+					})
+					return modestr.substr(0, modestr.length - 1)
+				} else {
+					return mode + '-' + type
+				}
+			},
+			// getEl(el) {
+			// 	console.log(el || el.ref || null);
+			// 	return el || el.ref || null
+			// },
+			toLine(name) {
+				return name.replace(/([A-Z])/g, "-$1").toLowerCase();
+			}
+		}
+	}
+</script>
+
+<style>
+	.uni-transition {
+		transition-timing-function: ease;
+		transition-duration: 0.3s;
+		transition-property: transform, opacity;
+	}
+
+	.fade-in {
+		opacity: 0;
+	}
+
+	.fade-active {
+		opacity: 1;
+	}
+
+	.slide-top-in {
+		/* transition-property: transform, opacity; */
+		transform: translateY(-100%);
+	}
+
+	.slide-top-active {
+		transform: translateY(0);
+		/* opacity: 1; */
+	}
+
+	.slide-right-in {
+		transform: translateX(100%);
+	}
+
+	.slide-right-active {
+		transform: translateX(0);
+	}
+
+	.slide-bottom-in {
+		transform: translateY(100%);
+	}
+
+	.slide-bottom-active {
+		transform: translateY(0);
+	}
+
+	.slide-left-in {
+		transform: translateX(-100%);
+	}
+
+	.slide-left-active {
+		transform: translateX(0);
+		opacity: 1;
+	}
+
+	.zoom-in-in {
+		transform: scale(0.8);
+	}
+
+	.zoom-out-active {
+		transform: scale(1);
+	}
+
+	.zoom-out-in {
+		transform: scale(1.2);
+	}
+</style>

+ 84 - 0
main.js

@@ -0,0 +1,84 @@
+import Vue from 'vue'
+import App from './App'
+import store from './store'
+import MinCache from'./common/util/MinCache.js'
+import tip from'./common/util/tip.js'
+import configService from'./common/service/config.service.js'
+
+import router from './common/router'
+import {RouterMount} from './plugin/uni-simple-router/index.js'
+
+// 注册缓存器
+Vue.use(MinCache,{timeout: 6})
+
+// store
+Vue.prototype.$store=store;
+// tip
+Vue.prototype.$tip=tip;
+// config
+Vue.prototype.$config=configService;
+
+// request请求
+import { http } from '@/common/service/service.js' 
+Vue.prototype.$http = http
+
+import home from './pages/home/home.vue'
+Vue.component('home',home)
+
+
+import people from './pages/user/people.vue'
+Vue.component('people',people)
+
+// 自定义组件
+import mySelect from './components/my-componets/my-select.vue'
+Vue.component('mySelect',mySelect)
+
+import myImageUpload from './components/my-componets/my-image-upload.vue'
+Vue.component('myImageUpload',myImageUpload)
+
+
+import myPage from './components/my-componets/my-page.vue'
+Vue.component('myPage',myPage)
+
+
+
+import basics from './pages/basics/home.vue'
+Vue.component('basics',basics)
+
+import components from './pages/component/home.vue'
+Vue.component('components',components)
+
+import plugin from './pages/plugin/home.vue'
+Vue.component('plugin',plugin)
+
+import cuCustom from './plugin/colorui/components/cu-custom.vue'
+Vue.component('cu-custom',cuCustom)
+
+// import VConsole from './js_sdk/vconsole.min'
+
+//   var vConsole = new VConsole();
+
+Vue.config.productionTip = false
+
+App.mpType = 'app'
+
+const app = new Vue({
+	store,
+	MinCache,
+    ...App
+})
+//v1.3.5起 H5端 你应该去除原有的app.$mount();使用路由自带的渲染方式
+// #ifdef H5
+	RouterMount(app,'#app');
+// #endif
+
+// #ifndef H5
+	app.$mount(); //为了兼容小程序及app端必须这样写才有效果
+// #endif
+
+
+
+ 
+
+
+

+ 81 - 0
manifest.json

@@ -0,0 +1,81 @@
+{
+    "name" : "即日办",
+    "appid" : "__UNI__44A8AB0",
+    "description" : "",
+    "versionName" : "2.2.22",
+    "versionCode" : 233,
+    "transformPx" : false,
+    "app-plus" : {
+        /* 5+App特有相关 */
+        "modules" : {
+            "Maps" : {},
+            "Push" : {}
+        },
+        /* 模块配置 */
+        "distribute" : {
+            /* 应用发布信息 */
+            "android" : {
+                /* android打包配置 */
+                "permissions" : [
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.INTERNET\"/>",
+                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            "ios" : {},
+            /* ios打包配置 */
+            "sdkConfigs" : {
+                "ad" : {},
+                "maps" : {
+                    "amap" : {
+                        "appkey_ios" : "87f4d2a4a0c42e0c86cf312c8b8154e8",
+                        "appkey_android" : "87f4d2a4a0c42e0c86cf312c8b8154e8"
+                    }
+                },
+                "push" : {
+                    "unipush" : {}
+                }
+            }
+        }
+    },
+    /* SDK配置 */
+    "quickapp" : {},
+    /* 快应用特有相关 */
+    "mp-weixin" : {
+        "appid" : "wx2ba5c5690b35d173",
+        "setting" : {
+            "urlCheck" : false,
+            "es6" : true
+        },
+        "permission" : {
+            "scope.userLocation" : {
+                "desc" : "有定位功能需要导航定位"
+            }
+        }
+    },
+    "h5" : {
+        "title" : "Do it today",
+        "domain" : "myhjdc.cn"
+    }
+}

BIN
myhjdc.keystore


+ 44 - 0
package-lock.json

@@ -0,0 +1,44 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+    },
+    "prettier": {
+      "version": "1.12.1",
+      "resolved": "http://registry.npm.taobao.org/prettier/download/prettier-1.12.1.tgz",
+      "integrity": "sha1-wa0g6APndJ+vkFpAnSNn4Gu+cyU="
+    },
+    "query-string": {
+      "version": "6.12.1",
+      "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.12.1.tgz",
+      "integrity": "sha512-OHj+zzfRMyj3rmo/6G8a5Ifvw3AleL/EbcHMD27YA31Q+cO5lfmQxECkImuNVjcskLcvBRVHNAB3w6udMs1eAA==",
+      "requires": {
+        "decode-uri-component": "^0.2.0",
+        "split-on-first": "^1.0.0",
+        "strict-uri-encode": "^2.0.0"
+      }
+    },
+    "split-on-first": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
+      "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
+    },
+    "strict-uri-encode": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
+      "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
+    },
+    "uni-simple-router": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-1.5.5.tgz",
+      "integrity": "sha512-VjBnwhvmWYHVNsj2zcPjYBwb9TqG7miR87qLBBLI4gHOnJVYmCyjZK/bj06f9slvTMbWXrze7LJ9/Hi/8DB0ag==",
+      "requires": {
+        "query-string": "^6.12.1"
+      }
+    }
+  }
+}

+ 151 - 0
pages.json

@@ -0,0 +1,151 @@
+{
+	"pages": [
+		//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/index/index",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/layout",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/background",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/text",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/icon",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/button",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/design",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/tag",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/avatar",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/progress",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/shadow",
+			"style": {}
+		},
+		{
+			"path": "pages/basics/loading",
+			"style": {}
+		},
+		{
+			"path": "pages/component/bar",
+			"style": {}
+		},
+		{
+			"path": "pages/component/nav",
+			"style": {}
+		},
+		{
+			"path": "pages/component/list",
+			"style": {}
+		},
+		{
+			"path": "pages/component/card",
+			"style": {}
+		},
+		{
+			"path": "pages/component/form",
+			"style": {}
+		},
+		{
+			"path": "pages/component/timeline",
+			"style": {}
+		},
+		{
+			"path": "pages/component/chat",
+			"style": {}
+		},
+		{
+			"path": "pages/component/swiper",
+			"style": {}
+		},
+		{
+			"path": "pages/component/modal",
+			"style": {}
+		},
+		{
+			"path": "pages/component/steps",
+			"style": {}
+		}, {
+			"path": "pages/plugin/indexes",
+			"style": {}
+		}, {
+			"path": "pages/plugin/animation",
+			"style": {}
+		}, {
+			"path": "pages/plugin/drawer",
+			"style": {}
+		}, {
+			"path": "pages/plugin/verticalnav",
+			"style": {}
+		}, {
+			"path": "pages/home/home",
+			"style": {}
+		}, {
+			"path": "pages/login/login",
+			"style": {}
+		}, {
+			"path": "pages/user/userexit",
+			"style": {}
+		}, {
+			"path": "pages/user/userdetail",
+			"style": {}
+		},{
+			"path": "pages/user/useredit",
+			"style": {}
+		}, {
+			"path": "pages/user/people",
+			"style": {}
+		}, {
+			"path": "pages/common/exit",
+			"style": {}
+		}, {
+			"path": "pages/common/success",
+			"style": {}
+		}
+
+	],
+	"globalStyle": {
+		"mp-alipay": {
+			/* 支付宝小程序特有相关 */
+			"transparentTitle": "always",
+			"allowsBounceVertical": "NO"
+		},
+		"navigationBarBackgroundColor": "#0081ff",
+		"navigationBarTitleText": "JEECG BOOT",
+		"navigationStyle": "custom",
+		"navigationBarTextStyle": "white"
+	},
+	"usingComponts": true,
+	"condition": { //模式配置,仅开发期间生效
+		"current": 0, //当前激活的模式(list 的索引项)
+		"list": [{
+			"name": "表单", //模式名称
+			"path": "pages/index/index", //启动页面
+			"query": "" //启动参数
+		}]
+	}
+
+}

+ 108 - 0
pages/basics/avatar.vue

@@ -0,0 +1,108 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">头像</block></cu-custom>
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>头像形状
+			</view>
+		</view>
+		<view class="padding">
+			<view class="cu-avatar round" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg)"></view>
+			<view class="cu-avatar radius margin-left" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg);"></view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>头像尺寸
+			</view>
+		</view>
+		<view class="padding">
+			<view class="cu-avatar sm round margin-left" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg)"></view>
+			<view class="cu-avatar round margin-left" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg);"></view>
+			<view class="cu-avatar lg round margin-left" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big25002.jpg);"></view>
+			<view class="cu-avatar xl round margin-left" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg);"></view>
+		</view>
+		<view class="padding">
+			<view class="cu-avatar sm round margin-left bg-red"> A</view>
+			<view class="cu-avatar round margin-left bg-red">B</view>
+			<view class="cu-avatar lg round margin-left bg-red">C</view>
+			<view class="cu-avatar xl round margin-left bg-red">D</view>
+		</view>
+		<view class="padding">
+			<view class="cu-avatar sm round margin-left bg-red"> 蔚</view>
+			<view class="cu-avatar round margin-left bg-red">蓝</view>
+			<view class="cu-avatar lg round margin-left bg-red">
+				<text>wl</text>
+			</view>
+			<view class="cu-avatar xl round margin-left bg-red">
+				<text class="avatar-text">网络</text>
+			</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>内嵌文字(图标)
+			</view>
+		</view>
+		<view class="padding">
+			<view class="cu-avatar radius">
+				<text class="cuIcon-people"></text>
+			</view>
+			<view class="cu-avatar radius margin-left">
+				<text>港</text>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>头像颜色
+			</view>
+		</view>
+		<view class="padding-sm">
+			<view class="cu-avatar round lg margin-xs" :class="'bg-' + item.name" v-for="(item,index) in ColorList" :key="index">
+				<text class="avatar-text">{{item.name}}</text>
+			</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>头像组
+			</view>
+		</view>
+		<view class="padding">
+			<view class="cu-avatar-group">
+				<view class="cu-avatar round lg" v-for="(item,index) in avatar" :key="index" :style="[{ backgroundImage:'url(' + avatar[index] + ')' }]"></view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>头像标签
+			</view>
+		</view>
+		<view class="padding">
+			<view class="cu-avatar round lg margin-left"  v-for="(item,index) in avatar" :key="index" :style="[{ backgroundImage:'url(' + avatar[index] + ')' }]">
+				<view class="cu-tag badge" :class="index%2==0?'cuIcon-female bg-pink':'cuIcon-male bg-blue'"></view>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				ColorList: this.ColorList,
+				avatar: [
+					'https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg',
+					'https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg',
+					'https://ossweb-img.qq.com/images/lol/web201310/skin/big25002.jpg',
+					'https://ossweb-img.qq.com/images/lol/web201310/skin/big91012.jpg'
+				],
+
+			};
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 141 - 0
pages/basics/background.vue

@@ -0,0 +1,141 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true">
+			<block slot="backText">返回</block>
+			<block slot="content">背景</block>
+		</cu-custom>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class='cuIcon-title text-blue'></text>深色背景
+			</view>
+		</view>
+		<view class="grid col-3 padding-sm">
+			<view class="padding-sm" v-for="(item,index) in ColorList" :key="index">
+				<view class="padding radius text-center shadow-blur" :class="'bg-' + item.name">
+					<view class="text-lg">{{item.title}}</view>
+					<view class="margin-top-sm text-Abc">{{item.name}}</view>
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>淡色背景
+			</view>
+		</view>
+		<view class="grid col-3 bg-white padding-sm">
+			<view class="padding-sm" v-for="(item,index) in ColorList" :key="index" v-if="index<12">
+				<view class="padding radius text-center light" :class="'bg-' + item.name">
+					<view class="text-lg">{{item.title}}</view>
+					<view class="margin-top-sm text-Abc">{{item.name}}</view>
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>渐变背景
+			</view>
+		</view>
+		<view class="grid col-2 padding-sm">
+			<view class="padding-sm">
+				<view class="bg-gradual-red padding radius text-center shadow-blur">
+					<view class="text-lg">魅红</view>
+					<view class="margin-top-sm text-Abc">#f43f3b - #ec008c</view>
+				</view>
+			</view>
+			<view class="padding-sm">
+				<view class="bg-gradual-orange padding radius text-center shadow-blur">
+					<view class="text-lg">鎏金</view>
+					<view class="margin-top-sm text-Abc">#ff9700 - #ed1c24</view>
+				</view>
+			</view>
+			<view class="padding-sm">
+				<view class="bg-gradual-green padding radius text-center shadow-blur">
+					<view class="text-lg">翠柳</view>
+					<view class="margin-top-sm text-Abc">#39b54a - #8dc63f</view>
+				</view>
+			</view>
+			<view class="padding-sm">
+				<view class="bg-gradual-blue padding radius text-center shadow-blur">
+					<view class="text-lg">靛青</view>
+					<view class="margin-top-sm text-Abc">#0081ff - #1cbbb4</view>
+				</view>
+			</view>
+			<view class="padding-sm">
+				<view class="bg-gradual-purple padding radius text-center shadow-blur">
+					<view class="text-lg">惑紫</view>
+					<view class="margin-top-sm text-Abc">#9000ff - #5e00ff</view>
+				</view>
+			</view>
+			<view class="padding-sm">
+				<view class="bg-gradual-pink padding radius text-center shadow-blur">
+					<view class="text-lg">霞彩</view>
+					<view class="margin-top-sm text-Abc">#ec008c - #6739b6</view>
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>图片背景
+			</view>
+		</view>
+		<view class="bg-img bg-mask flex align-center" style="background-image: url('https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg');height: 414upx;">
+			<view class="padding-xl text-white">
+				<view class="padding-xs text-xxl text-bold">
+					钢铁之翼
+				</view>
+				<view class="padding-xs text-lg">
+					Only the guilty need fear me.
+				</view>
+			</view>
+		</view>
+<!-- 		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>视频背景
+			</view>
+		</view>
+		<view class="bg-video bg-mask flex align-center" style="height: 422upx;">
+			<video src="https://yz.lol.qq.com/v1/assets/videos/aatrox-splashvideo.webm" autoplay loop muted :show-play-btn="false"
+			 :controls="false" objectFit="cover"></video>
+			<cover-view class="padding-xl text-white ">
+				<cover-view class="padding-xs  text-xxl text-bold">
+					暗裔剑魔
+				</cover-view>
+				<cover-view class="padding-xs">
+					我必须连同希望一起毁坏……
+				</cover-view>
+			</cover-view>
+		</view> -->
+		
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>透明背景(文字层)
+			</view>
+		</view>
+		<view class="grid col-2">
+			<view class="bg-img padding-bottom-xl" style="background-image: url('https://ossweb-img.qq.com/images/lol/web201310/skin/big10007.jpg');height: 207upx;">
+				<view class="bg-shadeTop padding padding-bottom-xl">
+					上面开始
+				</view>
+			</view>
+			<view class="bg-img padding-top-xl flex align-end" style="background-image: url('https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg');height: 207upx;">
+				<view class="bg-shadeBottom padding padding-top-xl flex-sub">
+					下面开始
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				ColorList: this.ColorList,
+			};
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 123 - 0
pages/basics/button.vue

@@ -0,0 +1,123 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">按钮</block></cu-custom>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>按钮形状
+			</view>
+			<view class="action">
+				<navigator class="action" url="design" hover-class="none">
+					<text class="cuIcon-skinfill"></text>
+					<text class="text-df">设计</text>
+				</navigator>
+			</view>
+		</view>
+		<view class="padding flex flex-wrap justify-between align-center bg-white">
+			<button class="cu-btn">默认</button>
+			<button class="cu-btn round">圆角</button>
+			<button class="cu-btn cuIcon">
+				<text class="cuIcon-emojifill"></text>
+			</button>
+		</view>
+		<view class="cu-bar margin-top bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>按钮尺寸
+			</view>
+		</view>
+		<view class="padding flex flex-wrap justify-between align-center bg-white">
+			<button class="cu-btn round sm">小尺寸</button>
+			<button class="cu-btn round">默认</button>
+			<button class="cu-btn round lg">大尺寸</button>
+		</view>
+		<view class="cu-bar margin-top bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>按钮颜色
+			</view>
+			<view class="action">
+				<text class="text-df margin-right-sm">阴影</text>
+				<switch @change="SetShadow" :class="shadow?'checked':''" color="#39B54A"></switch>
+			</view>
+		</view>
+		<view class="grid col-5 padding-sm">
+			<view class="margin-tb-sm text-center" v-for="(item,index) in ColorList" :key="index">
+				<button class="cu-btn round" :class="['bg-' + item.name , shadow?'shadow':'']">{{item.title}}</button>
+			</view>
+		</view>
+		<view class="cu-bar margin-top bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>镂空按钮
+			</view>
+			<view class="action">
+				<radio-group @change="SetBorderSize">
+					<label class="margin-left-sm">
+						<radio class="blue radio" value="" checked></radio>
+						<text class="margin-left-sm">小</text>
+					</label>
+					<label class="margin-left-sm">
+						<radio class="blue radio" value="s"></radio>
+						<text class="margin-left-sm">大</text>
+					</label>
+				</radio-group>
+			</view>
+		</view>
+		<view class="grid col-5 padding-sm">
+			<view class="margin-tb-sm text-center" v-for="(item,index) in ColorList" :key="index" v-if="item.name!='white'">
+				<button class="cu-btn round" :class="[bordersize?'lines-' + item.name:'line-' + item.name, shadow?'shadow':'']">{{item.title}}</button>
+			</view>
+		</view>
+		<view class="cu-bar margin-top bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>块状按钮
+			</view>
+		</view>
+		<view class="padding flex flex-direction">
+			<button class="cu-btn bg-grey lg">玄灰</button>
+			<button class="cu-btn bg-red margin-tb-sm lg">嫣红</button>
+		</view>
+		<view class="cu-bar margin-top bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>无效状态
+			</view>
+		</view>
+		<view class="padding">
+			<button class="cu-btn block bg-blue margin-tb-sm lg" disabled type="">无效状态</button>
+			<button class="cu-btn block line-blue margin-tb-sm lg" disabled>无效状态</button>
+		</view>
+		<view class="cu-bar margin-top bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>按钮加图标
+			</view>
+		</view>
+		<view class="padding-xl">
+			<button class="cu-btn block line-orange lg">
+				<text class="cuIcon-upload"></text> 图标</button>
+			<button class="cu-btn block bg-blue margin-tb-sm lg">
+				<text class="cuIcon-loading2 cuIconfont-spin"></text> 加载</button>
+			<button class="cu-btn block bg-black margin-tb-sm lg" loading> 原生加载</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				ColorList: this.ColorList,
+				shadow: false,
+				bordersize: ''
+			};
+		},
+		methods: {
+			SetShadow(e) {
+				this.shadow = e.detail.value
+			},
+			SetBorderSize(e) {
+				this.bordersize = e.detail.value
+			}
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 130 - 0
pages/basics/design.vue

@@ -0,0 +1,130 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content"> 按钮 / 设计</block></cu-custom>
+		<view class="padding-xl">
+			<view class="box bg-white text-center radius">
+				<button class="cu-btn" :class="[border?bordersize?'lines-' + color:'line-' + color:'bg-'+ color,round?'round':'',size,shadow?'shadow':'']">我是一个按钮</button>
+			</view>
+			<view class="padding text-center">
+				class="cu-btn <text v-if="color">{{' '}} {{border?bordersize?'lines-' + color:'line-' + color:'bg-'+ color}} {{round?'round':''}} {{size}} {{shadow?'shadow':''}}</text>"
+			</view>
+		</view>
+		<view class="cu-form-group margin-top" @tap="showModal" data-target="ColorModal">
+			<view class="title">选择颜色</view>
+			<view class="padding solid radius shadow-blur" :class="'bg-'+color"></view>
+		</view>
+		<view class="cu-form-group">
+			<view class="title">是否圆角</view>
+			<switch @change="SetRound" class="blue" :class="round?'checked':''"></switch>
+		</view>
+		<view class="cu-form-group">
+			<view class="title">选择尺寸</view>
+			<radio-group @change="SetSize">
+				<label class="margin-left-sm">
+					<radio class="blue radio" value="sm"></radio>
+					<text class="margin-left-sm"> 小</text>
+				</label>
+				<label class="margin-left-sm">
+					<radio class="blue radio" value="" checked></radio>
+					<text class="margin-left-sm"> 中</text>
+				</label>
+				<label class="margin-left-sm">
+					<radio class="blue radio" value="lg"></radio>
+					<text class="margin-left-sm"> 大</text>
+				</label>
+			</radio-group>
+		</view>
+		<view class="cu-form-group">
+			<view class="title">是否添加阴影</view>
+			<switch @change="SetShadow" :class="shadow?'checked':''"></switch>
+		</view>
+		<view class="cu-form-group">
+			<view class="title">是否镂空</view>
+			<switch @change="SetBorder" :class="border?'checked':''"></switch>
+		</view>
+		<view class="cu-form-group" v-if="border">
+			<view class="title">边框大小</view>
+			<radio-group @change="SetBorderSize">
+				<label class="margin-left-sm">
+					<radio class="blue radio" value="" checked></radio>
+					<text class="margin-left-sm"> 小</text>
+				</label>
+				<label class="margin-left-sm">
+					<radio class="blue radio" value="s"></radio>
+					<text class="margin-left-sm"> 大</text>
+				</label>
+			</radio-group>
+		</view>
+		<view class="cu-modal" :class="modalName=='ColorModal'?'show':''">
+			<view class="cu-dialog">
+				<view class="cu-bar justify-end solid-bottom">
+					<view class="content">选择颜色</view>
+					<view class="action" @tap="hideModal">
+						<text class="cuIcon-close text-red"></text>
+					</view>
+				</view>
+				<view class="grid col-5 padding">
+					<view class="padding-xs" v-for="(item,index) in ColorList" :key="index" @tap="SetColor" :data-color="item.name" v-if="item.name!='white'">
+						<view class="padding-tb radius" :class="'bg-' + item.name"> {{item.title}} </view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				ColorList: this.ColorList,
+				modalName: '',
+				round: false,
+				size: '',
+				color: 'red',
+				shadow: false,
+				border: false,
+				bordersize: ''
+			};
+		},
+		methods: {
+			showModal(e) {
+				this.modalName = e.currentTarget.dataset.target
+			},
+			hideModal(e) {
+				this.modalName = null
+			},
+			SetRound(e) {
+				this.round = e.detail.value
+			},
+			SetSize(e) {
+				this.size = e.detail.value
+			},
+			SetColor(e) {
+				this.color = e.currentTarget.dataset.color;
+				this.modalName = null
+			},
+			SetShadow(e) {
+				this.shadow = e.detail.value
+			},
+			SetBorder(e) {
+				this.border = e.detail.value
+				if (!e.detail.value) {
+					this.bordersize = false
+				}
+			},
+			SetBorderSize(e) {
+				this.bordersize = e.detail.value
+			}
+		}
+	}
+</script>
+
+<style>
+	.box {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		height: 100px;
+	}
+</style>

+ 97 - 0
pages/basics/home.vue

@@ -0,0 +1,97 @@
+<template name="basics">
+	<view>
+		<scroll-view scroll-y class="page">
+			<image src="/static/componentBg.png "
+			 mode="widthFix" class="response"></image>
+			<view class="nav-list">
+				<navigator hover-class="none" :url="'/pages/basics/' + item.name" class="nav-li" navigateTo :class="'bg-'+item.color"
+				 :style="[{animation: 'show ' + ((index+1)*0.2+1) + 's 1'}]" v-for="(item,index) in elements" :key="index">
+					<view class="nav-title">{{item.title}}</view>
+					<view class="nav-name">{{item.name}}</view>
+					<text :class="'cuIcon-' + item.cuIcon"></text>
+				</navigator>
+			</view>
+			<view class="cu-tabbar-height"></view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "basics",
+		data() {
+			return {
+				elements: [{
+						title: '布局',
+						name: 'layout',
+						color: 'cyan',
+						cuIcon: 'newsfill'
+					},
+					{
+						title: '背景',
+						name: 'background',
+						color: 'blue',
+						cuIcon: 'colorlens'
+					},
+					{
+						title: '文本',
+						name: 'text',
+						color: 'purple',
+						cuIcon: 'font'
+					},
+					{
+						title: '图标 ',
+						name: 'icon',
+						color: 'mauve',
+						cuIcon: 'cuIcon'
+					},
+					{
+						title: '按钮',
+						name: 'button',
+						color: 'pink',
+						cuIcon: 'btn'
+					},
+					{
+						title: '标签',
+						name: 'tag',
+						color: 'brown',
+						cuIcon: 'tagfill'
+					},
+					{
+						title: '头像',
+						name: 'avatar',
+						color: 'red',
+						cuIcon: 'myfill'
+					},
+					{
+						title: '进度条',
+						name: 'progress',
+						color: 'orange',
+						cuIcon: 'icloading'
+					},
+					{
+						title: '边框阴影',
+						name: 'shadow',
+						color: 'olive',
+						cuIcon: 'copy'
+					},
+					{
+						title: '加载',
+						name: 'loading',
+						color: 'green',
+						cuIcon: 'loading2'
+					}
+				],
+			};
+		},
+		onShow() {
+			console.log("success")
+		}
+	}
+</script>
+
+<style>
+	.page {
+		height: 100vh;
+	}
+</style>

+ 939 - 0
pages/basics/icon.vue

@@ -0,0 +1,939 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">图标</block></cu-custom>
+		<view class="cu-bar bg-white search fixed" :style="[{top:CustomBar + 'px'}]">
+			<view class="search-form round">
+				<text class="cuIcon-search"></text>
+				<input type="text" placeholder="搜索cuIcon" confirm-type="search" @input="searchIcon"></input>
+			</view>
+		</view>
+		<view class="cu-list grid col-3">
+			<view class="cu-item" v-for="(item,index) in cuIcon" :key="index" v-if="item.isShow">
+				<text class="lg text-gray" :class="'cuIcon-' + item.name"></text>
+				<text>{{item.name}}</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				CustomBar: this.CustomBar,
+				cuIcon: [{
+					name: 'appreciate',
+					isShow: true
+				}, {
+					name: 'check',
+					isShow: true
+				}, {
+					name: 'close',
+					isShow: true
+				}, {
+					name: 'edit',
+					isShow: true
+				}, {
+					name: 'emoji',
+					isShow: true
+				}, {
+					name: 'favorfill',
+					isShow: true
+				}, {
+					name: 'favor',
+					isShow: true
+				}, {
+					name: 'loading',
+					isShow: true
+				}, {
+					name: 'locationfill',
+					isShow: true
+				}, {
+					name: 'location',
+					isShow: true
+				}, {
+					name: 'phone',
+					isShow: true
+				}, {
+					name: 'roundcheckfill',
+					isShow: true
+				}, {
+					name: 'roundcheck',
+					isShow: true
+				}, {
+					name: 'roundclosefill',
+					isShow: true
+				}, {
+					name: 'roundclose',
+					isShow: true
+				}, {
+					name: 'roundrightfill',
+					isShow: true
+				}, {
+					name: 'roundright',
+					isShow: true
+				}, {
+					name: 'search',
+					isShow: true
+				}, {
+					name: 'taxi',
+					isShow: true
+				}, {
+					name: 'timefill',
+					isShow: true
+				}, {
+					name: 'time',
+					isShow: true
+				}, {
+					name: 'unfold',
+					isShow: true
+				}, {
+					name: 'warnfill',
+					isShow: true
+				}, {
+					name: 'warn',
+					isShow: true
+				}, {
+					name: 'camerafill',
+					isShow: true
+				}, {
+					name: 'camera',
+					isShow: true
+				}, {
+					name: 'commentfill',
+					isShow: true
+				}, {
+					name: 'comment',
+					isShow: true
+				}, {
+					name: 'likefill',
+					isShow: true
+				}, {
+					name: 'like',
+					isShow: true
+				}, {
+					name: 'notificationfill',
+					isShow: true
+				}, {
+					name: 'notification',
+					isShow: true
+				}, {
+					name: 'order',
+					isShow: true
+				}, {
+					name: 'samefill',
+					isShow: true
+				}, {
+					name: 'same',
+					isShow: true
+				}, {
+					name: 'deliver',
+					isShow: true
+				}, {
+					name: 'evaluate',
+					isShow: true
+				}, {
+					name: 'pay',
+					isShow: true
+				}, {
+					name: 'send',
+					isShow: true
+				}, {
+					name: 'shop',
+					isShow: true
+				}, {
+					name: 'ticket',
+					isShow: true
+				}, {
+					name: 'back',
+					isShow: true
+				}, {
+					name: 'cascades',
+					isShow: true
+				}, {
+					name: 'discover',
+					isShow: true
+				}, {
+					name: 'list',
+					isShow: true
+				}, {
+					name: 'more',
+					isShow: true
+				}, {
+					name: 'scan',
+					isShow: true
+				}, {
+					name: 'settings',
+					isShow: true
+				}, {
+					name: 'questionfill',
+					isShow: true
+				}, {
+					name: 'question',
+					isShow: true
+				}, {
+					name: 'shopfill',
+					isShow: true
+				}, {
+					name: 'form',
+					isShow: true
+				}, {
+					name: 'pic',
+					isShow: true
+				}, {
+					name: 'filter',
+					isShow: true
+				}, {
+					name: 'footprint',
+					isShow: true
+				}, {
+					name: 'top',
+					isShow: true
+				}, {
+					name: 'pulldown',
+					isShow: true
+				}, {
+					name: 'pullup',
+					isShow: true
+				}, {
+					name: 'right',
+					isShow: true
+				}, {
+					name: 'refresh',
+					isShow: true
+				}, {
+					name: 'moreandroid',
+					isShow: true
+				}, {
+					name: 'deletefill',
+					isShow: true
+				}, {
+					name: 'refund',
+					isShow: true
+				}, {
+					name: 'cart',
+					isShow: true
+				}, {
+					name: 'qrcode',
+					isShow: true
+				}, {
+					name: 'remind',
+					isShow: true
+				}, {
+					name: 'delete',
+					isShow: true
+				}, {
+					name: 'profile',
+					isShow: true
+				}, {
+					name: 'home',
+					isShow: true
+				}, {
+					name: 'cartfill',
+					isShow: true
+				}, {
+					name: 'discoverfill',
+					isShow: true
+				}, {
+					name: 'homefill',
+					isShow: true
+				}, {
+					name: 'message',
+					isShow: true
+				}, {
+					name: 'addressbook',
+					isShow: true
+				}, {
+					name: 'link',
+					isShow: true
+				}, {
+					name: 'lock',
+					isShow: true
+				}, {
+					name: 'unlock',
+					isShow: true
+				}, {
+					name: 'vip',
+					isShow: true
+				}, {
+					name: 'weibo',
+					isShow: true
+				}, {
+					name: 'activity',
+					isShow: true
+				}, {
+					name: 'friendaddfill',
+					isShow: true
+				}, {
+					name: 'friendadd',
+					isShow: true
+				}, {
+					name: 'friendfamous',
+					isShow: true
+				}, {
+					name: 'friend',
+					isShow: true
+				}, {
+					name: 'goods',
+					isShow: true
+				}, {
+					name: 'selection',
+					isShow: true
+				}, {
+					name: 'explore',
+					isShow: true
+				}, {
+					name: 'present',
+					isShow: true
+				}, {
+					name: 'squarecheckfill',
+					isShow: true
+				}, {
+					name: 'square',
+					isShow: true
+				}, {
+					name: 'squarecheck',
+					isShow: true
+				}, {
+					name: 'round',
+					isShow: true
+				}, {
+					name: 'roundaddfill',
+					isShow: true
+				}, {
+					name: 'roundadd',
+					isShow: true
+				}, {
+					name: 'add',
+					isShow: true
+				}, {
+					name: 'notificationforbidfill',
+					isShow: true
+				}, {
+					name: 'explorefill',
+					isShow: true
+				}, {
+					name: 'fold',
+					isShow: true
+				}, {
+					name: 'game',
+					isShow: true
+				}, {
+					name: 'redpacket',
+					isShow: true
+				}, {
+					name: 'selectionfill',
+					isShow: true
+				}, {
+					name: 'similar',
+					isShow: true
+				}, {
+					name: 'appreciatefill',
+					isShow: true
+				}, {
+					name: 'infofill',
+					isShow: true
+				}, {
+					name: 'info',
+					isShow: true
+				}, {
+					name: 'forwardfill',
+					isShow: true
+				}, {
+					name: 'forward',
+					isShow: true
+				}, {
+					name: 'rechargefill',
+					isShow: true
+				}, {
+					name: 'recharge',
+					isShow: true
+				}, {
+					name: 'vipcard',
+					isShow: true
+				}, {
+					name: 'voice',
+					isShow: true
+				}, {
+					name: 'voicefill',
+					isShow: true
+				}, {
+					name: 'friendfavor',
+					isShow: true
+				}, {
+					name: 'wifi',
+					isShow: true
+				}, {
+					name: 'share',
+					isShow: true
+				}, {
+					name: 'wefill',
+					isShow: true
+				}, {
+					name: 'we',
+					isShow: true
+				}, {
+					name: 'lightauto',
+					isShow: true
+				}, {
+					name: 'lightforbid',
+					isShow: true
+				}, {
+					name: 'lightfill',
+					isShow: true
+				}, {
+					name: 'camerarotate',
+					isShow: true
+				}, {
+					name: 'light',
+					isShow: true
+				}, {
+					name: 'barcode',
+					isShow: true
+				}, {
+					name: 'flashlightclose',
+					isShow: true
+				}, {
+					name: 'flashlightopen',
+					isShow: true
+				}, {
+					name: 'searchlist',
+					isShow: true
+				}, {
+					name: 'service',
+					isShow: true
+				}, {
+					name: 'sort',
+					isShow: true
+				}, {
+					name: 'down',
+					isShow: true
+				}, {
+					name: 'mobile',
+					isShow: true
+				}, {
+					name: 'mobilefill',
+					isShow: true
+				}, {
+					name: 'copy',
+					isShow: true
+				}, {
+					name: 'countdownfill',
+					isShow: true
+				}, {
+					name: 'countdown',
+					isShow: true
+				}, {
+					name: 'noticefill',
+					isShow: true
+				}, {
+					name: 'notice',
+					isShow: true
+				}, {
+					name: 'upstagefill',
+					isShow: true
+				}, {
+					name: 'upstage',
+					isShow: true
+				}, {
+					name: 'babyfill',
+					isShow: true
+				}, {
+					name: 'baby',
+					isShow: true
+				}, {
+					name: 'brandfill',
+					isShow: true
+				}, {
+					name: 'brand',
+					isShow: true
+				}, {
+					name: 'choicenessfill',
+					isShow: true
+				}, {
+					name: 'choiceness',
+					isShow: true
+				}, {
+					name: 'clothesfill',
+					isShow: true
+				}, {
+					name: 'clothes',
+					isShow: true
+				}, {
+					name: 'creativefill',
+					isShow: true
+				}, {
+					name: 'creative',
+					isShow: true
+				}, {
+					name: 'female',
+					isShow: true
+				}, {
+					name: 'keyboard',
+					isShow: true
+				}, {
+					name: 'male',
+					isShow: true
+				}, {
+					name: 'newfill',
+					isShow: true
+				}, {
+					name: 'new',
+					isShow: true
+				}, {
+					name: 'pullleft',
+					isShow: true
+				}, {
+					name: 'pullright',
+					isShow: true
+				}, {
+					name: 'rankfill',
+					isShow: true
+				}, {
+					name: 'rank',
+					isShow: true
+				}, {
+					name: 'bad',
+					isShow: true
+				}, {
+					name: 'cameraadd',
+					isShow: true
+				}, {
+					name: 'focus',
+					isShow: true
+				}, {
+					name: 'friendfill',
+					isShow: true
+				}, {
+					name: 'cameraaddfill',
+					isShow: true
+				}, {
+					name: 'apps',
+					isShow: true
+				}, {
+					name: 'paintfill',
+					isShow: true
+				}, {
+					name: 'paint',
+					isShow: true
+				}, {
+					name: 'picfill',
+					isShow: true
+				}, {
+					name: 'refresharrow',
+					isShow: true
+				}, {
+					name: 'colorlens',
+					isShow: true
+				}, {
+					name: 'markfill',
+					isShow: true
+				}, {
+					name: 'mark',
+					isShow: true
+				}, {
+					name: 'presentfill',
+					isShow: true
+				}, {
+					name: 'repeal',
+					isShow: true
+				}, {
+					name: 'album',
+					isShow: true
+				}, {
+					name: 'peoplefill',
+					isShow: true
+				}, {
+					name: 'people',
+					isShow: true
+				}, {
+					name: 'servicefill',
+					isShow: true
+				}, {
+					name: 'repair',
+					isShow: true
+				}, {
+					name: 'file',
+					isShow: true
+				}, {
+					name: 'repairfill',
+					isShow: true
+				}, {
+					name: 'taoxiaopu',
+					isShow: true
+				}, {
+					name: 'weixin',
+					isShow: true
+				}, {
+					name: 'attentionfill',
+					isShow: true
+				}, {
+					name: 'attention',
+					isShow: true
+				}, {
+					name: 'commandfill',
+					isShow: true
+				}, {
+					name: 'command',
+					isShow: true
+				}, {
+					name: 'communityfill',
+					isShow: true
+				}, {
+					name: 'community',
+					isShow: true
+				}, {
+					name: 'read',
+					isShow: true
+				}, {
+					name: 'calendar',
+					isShow: true
+				}, {
+					name: 'cut',
+					isShow: true
+				}, {
+					name: 'magic',
+					isShow: true
+				}, {
+					name: 'backwardfill',
+					isShow: true
+				}, {
+					name: 'playfill',
+					isShow: true
+				}, {
+					name: 'stop',
+					isShow: true
+				}, {
+					name: 'tagfill',
+					isShow: true
+				}, {
+					name: 'tag',
+					isShow: true
+				}, {
+					name: 'group',
+					isShow: true
+				}, {
+					name: 'all',
+					isShow: true
+				}, {
+					name: 'backdelete',
+					isShow: true
+				}, {
+					name: 'hotfill',
+					isShow: true
+				}, {
+					name: 'hot',
+					isShow: true
+				}, {
+					name: 'post',
+					isShow: true
+				}, {
+					name: 'radiobox',
+					isShow: true
+				}, {
+					name: 'rounddown',
+					isShow: true
+				}, {
+					name: 'upload',
+					isShow: true
+				}, {
+					name: 'writefill',
+					isShow: true
+				}, {
+					name: 'write',
+					isShow: true
+				}, {
+					name: 'radioboxfill',
+					isShow: true
+				}, {
+					name: 'punch',
+					isShow: true
+				}, {
+					name: 'shake',
+					isShow: true
+				}, {
+					name: 'move',
+					isShow: true
+				}, {
+					name: 'safe',
+					isShow: true
+				}, {
+					name: 'activityfill',
+					isShow: true
+				}, {
+					name: 'crownfill',
+					isShow: true
+				}, {
+					name: 'crown',
+					isShow: true
+				}, {
+					name: 'goodsfill',
+					isShow: true
+				}, {
+					name: 'messagefill',
+					isShow: true
+				}, {
+					name: 'profilefill',
+					isShow: true
+				}, {
+					name: 'sound',
+					isShow: true
+				}, {
+					name: 'sponsorfill',
+					isShow: true
+				}, {
+					name: 'sponsor',
+					isShow: true
+				}, {
+					name: 'upblock',
+					isShow: true
+				}, {
+					name: 'weblock',
+					isShow: true
+				}, {
+					name: 'weunblock',
+					isShow: true
+				}, {
+					name: 'my',
+					isShow: true
+				}, {
+					name: 'myfill',
+					isShow: true
+				}, {
+					name: 'emojifill',
+					isShow: true
+				}, {
+					name: 'emojiflashfill',
+					isShow: true
+				}, {
+					name: 'flashbuyfill',
+					isShow: true
+				}, {
+					name: 'text',
+					isShow: true
+				}, {
+					name: 'goodsfavor',
+					isShow: true
+				}, {
+					name: 'musicfill',
+					isShow: true
+				}, {
+					name: 'musicforbidfill',
+					isShow: true
+				}, {
+					name: 'card',
+					isShow: true
+				}, {
+					name: 'triangledownfill',
+					isShow: true
+				}, {
+					name: 'triangleupfill',
+					isShow: true
+				}, {
+					name: 'roundleftfill-copy',
+					isShow: true
+				}, {
+					name: 'font',
+					isShow: true
+				}, {
+					name: 'title',
+					isShow: true
+				}, {
+					name: 'recordfill',
+					isShow: true
+				}, {
+					name: 'record',
+					isShow: true
+				}, {
+					name: 'cardboardfill',
+					isShow: true
+				}, {
+					name: 'cardboard',
+					isShow: true
+				}, {
+					name: 'formfill',
+					isShow: true
+				}, {
+					name: 'coin',
+					isShow: true
+				}, {
+					name: 'cardboardforbid',
+					isShow: true
+				}, {
+					name: 'circlefill',
+					isShow: true
+				}, {
+					name: 'circle',
+					isShow: true
+				}, {
+					name: 'attentionforbid',
+					isShow: true
+				}, {
+					name: 'attentionforbidfill',
+					isShow: true
+				}, {
+					name: 'attentionfavorfill',
+					isShow: true
+				}, {
+					name: 'attentionfavor',
+					isShow: true
+				}, {
+					name: 'titles',
+					isShow: true
+				}, {
+					name: 'icloading',
+					isShow: true
+				}, {
+					name: 'full',
+					isShow: true
+				}, {
+					name: 'mail',
+					isShow: true
+				}, {
+					name: 'peoplelist',
+					isShow: true
+				}, {
+					name: 'goodsnewfill',
+					isShow: true
+				}, {
+					name: 'goodsnew',
+					isShow: true
+				}, {
+					name: 'medalfill',
+					isShow: true
+				}, {
+					name: 'medal',
+					isShow: true
+				}, {
+					name: 'newsfill',
+					isShow: true
+				}, {
+					name: 'newshotfill',
+					isShow: true
+				}, {
+					name: 'newshot',
+					isShow: true
+				}, {
+					name: 'news',
+					isShow: true
+				}, {
+					name: 'videofill',
+					isShow: true
+				}, {
+					name: 'video',
+					isShow: true
+				}, {
+					name: 'exit',
+					isShow: true
+				}, {
+					name: 'skinfill',
+					isShow: true
+				}, {
+					name: 'skin',
+					isShow: true
+				}, {
+					name: 'moneybagfill',
+					isShow: true
+				}, {
+					name: 'usefullfill',
+					isShow: true
+				}, {
+					name: 'usefull',
+					isShow: true
+				}, {
+					name: 'moneybag',
+					isShow: true
+				}, {
+					name: 'redpacket_fill',
+					isShow: true
+				}, {
+					name: 'subscription',
+					isShow: true
+				}, {
+					name: 'loading1',
+					isShow: true
+				}, {
+					name: 'github',
+					isShow: true
+				}, {
+					name: 'global',
+					isShow: true
+				}, {
+					name: 'settingsfill',
+					isShow: true
+				}, {
+					name: 'back_android',
+					isShow: true
+				}, {
+					name: 'expressman',
+					isShow: true
+				}, {
+					name: 'evaluate_fill',
+					isShow: true
+				}, {
+					name: 'group_fill',
+					isShow: true
+				}, {
+					name: 'play_forward_fill',
+					isShow: true
+				}, {
+					name: 'deliver_fill',
+					isShow: true
+				}, {
+					name: 'notice_forbid_fill',
+					isShow: true
+				}, {
+					name: 'fork',
+					isShow: true
+				}, {
+					name: 'pick',
+					isShow: true
+				}, {
+					name: 'wenzi',
+					isShow: true
+				}, {
+					name: 'ellipse',
+					isShow: true
+				}, {
+					name: 'qr_code',
+					isShow: true
+				}, {
+					name: 'dianhua',
+					isShow: true
+				}, {
+					name: 'cuIcon',
+					isShow: true
+				}, {
+					name: 'loading2',
+					isShow: true
+				}, {
+					name: 'btn',
+					isShow: true
+				}]
+
+			};
+		},
+		methods: {
+			searchIcon(e) {
+				let key = e.detail.value.toLowerCase();
+				let list = this.cuIcon;
+				for (let i = 0; i < list.length; i++) {
+					let a = key;
+					let b = list[i].name.toLowerCase();
+					if (b.search(a) != -1) {
+						list[i].isShow = true
+					} else {
+						list[i].isShow = false
+					}
+				}
+				this.cuIcon = list
+			}
+		}
+	}
+</script>
+
+<style>
+	page {
+		padding-top: 50px;
+	}
+</style>

+ 207 - 0
pages/basics/layout.vue

@@ -0,0 +1,207 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">布局</block></cu-custom>
+		<scroll-view scroll-x class="bg-white nav text-center fixed" :style="[{top:CustomBar + 'px'}]">
+			<view class="cu-item" :class="index==TabCur?'text-blue cur':''" v-for="(item,index) in tabNav" :key="index" @tap="tabSelect"
+			 :data-id="index">
+				{{tabNav[index]}}
+			</view>
+		</scroll-view>
+		<block v-if="TabCur==0">
+			<view class="cu-bar bg-white solid-bottom margin-top">
+				<view class="action">
+					<text class="cuIcon-title text-blue"></text>固定尺寸
+				</view>
+			</view>
+			<view class="padding bg-white">
+				<view class="flex flex-wrap">
+					<view class="basis-xs bg-grey margin-xs padding-sm radius">xs(20%)</view>
+					<view class="basis-df"></view>
+					<view class="basis-sm bg-grey margin-xs padding-sm radius">sm(40%)</view>
+					<view class="basis-df"></view>
+					<view class="basis-df bg-grey margin-xs padding-sm radius">sub(50%)</view>
+					<view class="basis-lg bg-grey margin-xs padding-sm radius">lg(60%)</view>
+					<view class="basis-xl bg-grey margin-xs padding-sm radius">xl(80%)</view>
+				</view>
+			</view>
+			<view class="cu-bar bg-white  margin-top solid-bottom">
+				<view class="action">
+					<text class="cuIcon-title text-blue"></text>比例布局
+				</view>
+			</view>
+			<view class="padding bg-white">
+				<view class="flex">
+					<view class="flex-sub bg-grey padding-sm margin-xs radius">1</view>
+					<view class="flex-sub bg-grey padding-sm margin-xs radius">1</view>
+				</view>
+				<view class="flex  p-xs margin-bottom-sm mb-sm">
+					<view class="flex-sub bg-grey padding-sm margin-xs radius">1</view>
+					<view class="flex-twice bg-grey padding-sm margin-xs radius">2</view>
+				</view>
+				<view class="flex  p-xs margin-bottom-sm mb-sm">
+					<view class="flex-sub bg-grey padding-sm margin-xs radius">1</view>
+					<view class="flex-twice bg-grey padding-sm margin-xs radius">2</view>
+					<view class="flex-treble bg-grey padding-sm margin-xs radius">3</view>
+				</view>
+			</view>
+			<view class="cu-bar bg-white  margin-top solid-bottom">
+				<view class="action">
+					<text class="cuIcon-title text-blue"></text>水平对齐(justify)
+				</view>
+			</view>
+			<view class="bg-white">
+				<view class="flex solid-bottom padding justify-start">
+					<view class="bg-grey padding-sm margin-xs radius">start</view>
+					<view class="bg-grey padding-sm margin-xs radius">start</view>
+				</view>
+				<view class="flex solid-bottom padding justify-end">
+					<view class="bg-grey padding-sm margin-xs radius">end</view>
+					<view class="bg-grey padding-sm margin-xs radius">end</view>
+				</view>
+				<view class="flex solid-bottom padding justify-center">
+					<view class="bg-grey padding-sm margin-xs radius">center</view>
+					<view class="bg-grey padding-sm margin-xs radius">center</view>
+				</view>
+				<view class="flex solid-bottom padding justify-between">
+					<view class="bg-grey padding-sm margin-xs radius">between</view>
+					<view class="bg-grey padding-sm margin-xs radius">between</view>
+				</view>
+				<view class="flex solid-bottom padding justify-around">
+					<view class="bg-grey padding-sm margin-xs radius">around</view>
+					<view class="bg-grey padding-sm margin-xs radius">around</view>
+				</view>
+			</view>
+			<view class="cu-bar bg-white  margin-top solid-bottom">
+				<view class="action">
+					<text class="cuIcon-title text-blue"></text>垂直对齐(align)
+				</view>
+			</view>
+			<view class="bg-white">
+				<view class="flex solid-bottom padding align-start">
+					<view class="bg-grey padding-lg margin-xs radius">ColorUi</view>
+					<view class="bg-grey padding-sm margin-xs radius">start</view>
+				</view>
+				<view class="flex solid-bottom padding align-end">
+					<view class="bg-grey padding-lg margin-xs radius">ColorUi</view>
+					<view class="bg-grey padding-sm margin-xs radius">end</view>
+				</view>
+				<view class="flex solid-bottom padding align-center">
+					<view class="bg-grey padding-lg margin-xs radius">ColorUi</view>
+					<view class="bg-grey padding-sm margin-xs radius">center</view>
+				</view>
+			</view>
+		</block>
+		<block v-if="TabCur==1">
+			<view class="cu-bar bg-white  margin-top solid-bottom">
+				<view class="action">
+					<text class="cuIcon-title text-blue"></text>等分列
+				</view>
+				<view class="action"></view>
+			</view>
+			<view class="bg-white padding">
+				<view class="grid margin-bottom text-center" v-for="(item,index) in 5" :key="index" :class="'col-' + (index+1)">
+					<view class="padding" :class="indexs%2==0?'bg-cyan':'bg-blue'" v-for="(item,indexs) in (index+1)*2" :key="indexs">{{indexs+1}}</view>
+				</view>
+			</view>
+			<view class="cu-bar bg-white  margin-top solid-bottom">
+				<view class="action">
+					<text class="cuIcon-title text-blue"></text>等高
+				</view>
+				<view class="action"></view>
+			</view>
+			<view class="bg-white padding">
+				<view class="grid col-4 grid-square">
+					<view class="bg-img" v-for="(item,index) in avatar" :key="index" :style="[{ backgroundImage:'url(' + avatar[index] + ')' }]"></view>
+				</view>
+			</view>
+		</block>
+		<block v-if="TabCur==2">
+			<view class="cu-bar bg-white margin-top solid-bottom">
+				<view class="action">
+					<text class="cuIcon-title text-blue"></text>浮动
+				</view>
+			</view>
+			<view class="bg-white padding">
+				<view class=" cf padding-sm">
+					<view class="bg-grey radius fl padding-sm">ColorUi fl</view>
+					<view class="bg-grey radius fr padding-sm">ColorUi fr</view>
+				</view>
+			</view>
+			<view class="cu-bar bg-white  solid-bottom margin-top solid-bottom">
+				<view class="action">
+					<text class="cuIcon-title text-blue"></text>内外边距
+				</view>
+			</view>
+			<view class="bg-white">
+				<view class="padding bg-gray">{size}的尺寸有xs/sm/df/lg/xl</view>
+				<view class="flex flex-wrap padding solid-top">
+					<view class="basis-df padding-bottom-xs">外边距</view>
+					<view class="basis-df padding-bottom-xs">内边距</view>
+					<view class="basis-df">.margin-{size}</view>
+					<view class="basis-df">.padding-{size}</view>
+				</view>
+				<view class="flex flex-wrap padding solid-top">
+					<view class="basis-df padding-bottom-xs">水平方向外边距</view>
+					<view class="basis-df padding-bottom-xs">水平方向内边距</view>
+					<view class="basis-df">.margin-lr-{size}</view>
+					<view class="basis-df">.padding-lr-{size}</view>
+				</view>
+				<view class="flex flex-wrap padding solid-top">
+					<view class="basis-df padding-bottom-xs">垂直方向外边距</view>
+					<view class="basis-df padding-bottom-xs">垂直方向内边距</view>
+					<view class="basis-df">.margin-tb-{size}</view>
+					<view class="basis-df">.padding-tb-{size}</view>
+				</view>
+				<view class="flex flex-wrap padding solid-top">
+					<view class="basis-df padding-bottom-xs">上外边距</view>
+					<view class="basis-df padding-bottom-xs">上内边距</view>
+					<view class="basis-df">.margin-top-{size}</view>
+					<view class="basis-df">.padding-top-{size}</view>
+				</view>
+				<view class="flex flex-wrap padding solid-top">
+					<view class="basis-df padding-bottom-xs">右外边距</view>
+					<view class="basis-df padding-bottom-xs">右内边距</view>
+					<view class="basis-df">.margin-right-{size}</view>
+					<view class="basis-df">.padding-right-{size}</view>
+				</view>
+				<view class="flex flex-wrap padding solid-top">
+					<view class="basis-df padding-bottom-xs">下外边距</view>
+					<view class="basis-df padding-bottom-xs">下内边距</view>
+					<view class="basis-df">margin-bottom-{size}</view>
+					<view class="basis-df">.padding-bottom-{size}</view>
+				</view>
+				<view class="flex flex-wrap padding solid-top">
+					<view class="basis-df padding-bottom-xs">左外边距</view>
+					<view class="basis-df padding-bottom-xs">左内边距</view>
+					<view class="basis-df">.margin-left-{size}</view>
+					<view class="basis-df">.padding-left-{size}</view>
+				</view>
+			</view>
+		</block>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				CustomBar: this.CustomBar,
+				TabCur: 0,
+				avatar:['https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg','https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg','https://ossweb-img.qq.com/images/lol/web201310/skin/big25002.jpg','https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg'],
+				tabNav: ['Flex布局', 'Grid布局', '辅助布局']
+			};
+		},
+		methods: {
+			tabSelect(e) {
+				this.TabCur = e.currentTarget.dataset.id;
+				this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60
+			}
+		}
+	}
+</script>
+
+<style>
+	page {
+		padding-top: 45px;
+	}
+</style>

+ 101 - 0
pages/basics/loading.vue

@@ -0,0 +1,101 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">加载</block>
+			<block slot="right">
+				<view class="action">
+					<view class="cu-load load-cuIcon" :class="!isLoad?'loading':'over'"></view>
+				</view>
+			</block>
+		</cu-custom>
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>背景
+			</view>
+		</view>
+		<view class="cu-load bg-blue" :class="!isLoad?'loading':'over'"></view>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>加载状态
+			</view>
+			<view class="action">
+				<switch @change="isLoading" :class="isLoad?'checked':''"></switch>
+			</view>
+		</view>
+		<view class="cu-load bg-grey" :class="!isLoad?'loading':'over'"></view>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>加载错误
+			</view>
+		</view>
+		<view class="cu-load bg-red erro"></view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>弹框加载
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="LoadModal">
+					点我
+				</button>
+			</view>
+		</view>
+		<view class="cu-load load-modal" v-if="loadModal">
+			<!-- <view class="cuIcon-emojifill text-orange"></view> -->
+			<image src="/static/logo.png" mode="aspectFit"></image>
+			<view class="gray-text">加载中...</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>进度条加载
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="LoadProgress">
+					点我
+				</button>
+			</view>
+		</view>
+		<view class="load-progress" :class="loadProgress!=0?'show':'hide'" :style="[{top:CustomBar+'px'}]">
+			<view class="load-progress-bar bg-green" :style="[{transform: 'translate3d(-' + (100-loadProgress) + '%, 0px, 0px)'}]"></view>
+			<view class="load-progress-spinner text-green"></view>
+		</view>
+	</view>
+</template>
+
+
+<script>
+	export default {
+		data() {
+			return {
+				CustomBar: this.CustomBar,
+				isLoad:false,
+				loadModal: false,
+				loadProgress: 0
+			};
+		},
+		methods: {
+			isLoading(e) {
+				this.isLoad = e.detail.value;
+			},
+			LoadModal(e) {
+				this.loadModal = true;
+				setTimeout(() => {
+					this.loadModal = false;
+				}, 2000)
+			},
+			LoadProgress(e) {
+				this.loadProgress = this.loadProgress + 3;
+				if (this.loadProgress < 100) {
+					setTimeout(() => {
+						this.LoadProgress();
+					}, 100)
+				} else {
+					this.loadProgress = 0;
+				}
+			}
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 153 - 0
pages/basics/progress.vue

@@ -0,0 +1,153 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">进度条</block></cu-custom>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>进度条形状
+			</view>
+		</view>
+		<view class="padding bg-white">
+			<view class="cu-progress">
+				<view class="bg-red" :style="[{ width:loading?'61.8%':''}]">61.8%</view>
+			</view>
+			<view class="cu-progress radius margin-top">
+				<view class="bg-red" :style="[{ width:loading?'61.8%':''}]">61.8%</view>
+			</view>
+			<view class="cu-progress round margin-top">
+				<view class="bg-red" :style="[{ width:loading?'61.8%':''}]">61.8%</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>进度条尺寸
+			</view>
+		</view>
+		<view class="padding bg-white">
+			<view class="cu-progress round">
+				<view class="bg-red" :style="[{ width:loading?'61.8%':''}]"></view>
+			</view>
+			<view class="cu-progress round margin-top sm">
+				<view class="bg-red" :style="[{ width:loading?'61.8%':''}]"></view>
+			</view>
+			<view class="cu-progress round margin-top xs">
+				<view class="bg-red" :style="[{ width:loading?'61.8%':''}]"></view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white solid-bottom margin-top" @tap="showModal" data-target="ColorModal">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>进度条颜色
+			</view>
+			<view class="action">
+				<view class="padding solid radius shadow-blur" :class="'bg-' + color"></view>
+			</view>
+		</view>
+		<view class="padding" :class="color=='white'?'bg-grey':'bg-white'">
+			<view class="cu-progress round">
+				<view :class="'bg-' + color" :style="[{ width:loading?'61.8%':''}]"></view>
+			</view>
+		</view>
+
+
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>进度条条纹
+			</view>
+			<switch class="margin-right-sm" :class="active?'checked':''" @change="SetActive"></switch>
+		</view>
+		<view class="padding bg-white">
+			<view class="cu-progress round sm striped" :class="active?'active':''">
+				<view class="bg-green" :style="[{ width:loading?'60%':''}]"></view>
+			</view>
+			<view class="cu-progress round sm margin-top-sm striped" :class="active?'active':''">
+				<view class="bg-black" :style="[{ width:loading?'40%':''}]"></view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>进度条比例
+			</view>
+		</view>
+		<view class="padding bg-white">
+			<view class="cu-progress radius striped active">
+				<view class="bg-red" :style="[{ width:loading?'30%':''}]">30%</view>
+				<view class="bg-olive" :style="[{ width:loading?'45%':''}]">45%</view>
+				<view class="bg-cyan" :style="[{ width:loading?'25%':''}]">25%</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>进度条布局
+			</view>
+		</view>
+		<view class="padding bg-white ">
+			<view class="flex">
+				<view class="cu-progress round">
+					<view class="bg-green" :style="[{ width:loading?'100%':''}]"></view>
+				</view>
+				<text class="cuIcon-roundcheckfill text-green margin-left-sm"></text>
+			</view>
+			<view class="flex margin-top">
+				<view class="cu-progress round">
+					<view class="bg-green" :style="[{ width:loading?'80%':''}]"></view>
+				</view>
+				<text class="margin-left">80%</text>
+			</view>
+		</view>
+
+		<view class="cu-modal" :class="modalName=='ColorModal'?'show':''">
+			<view class="cu-dialog">
+				<view class="cu-bar justify-end solid-bottom">
+					<view class="content">选择颜色</view>
+					<view class="action" @tap="hideModal">
+						<text class="cuIcon-close text-red"></text>
+					</view>
+				</view>
+				<view class="grid col-5 padding">
+					<view class="padding-xs" v-for="(item,index) in ColorList" :key="index" @tap="SetColor" :data-color="item.name" v-if="item.name!='gray' && item.name!='white'">
+						<view class="padding-tb radius" :class="'bg-' + item.name"> {{item.title}} </view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				ColorList: this.ColorList,
+				color: 'red',
+				loading: false,
+				modalName: '',
+				active: false
+			};
+		},
+		onLoad: function() {
+			let that = this;
+			setTimeout(function() {
+				that.loading = true
+			}, 500)
+		},
+		methods: {
+			showModal(e) {
+				this.modalName = e.currentTarget.dataset.target
+			},
+			hideModal(e) {
+				this.modalName = null
+			},
+			SetColor(e) {
+				this.color = e.currentTarget.dataset.color;
+				this.modalName = null
+			},
+			SetActive(e) {
+				this.active = e.detail.value
+			},
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 54 - 0
pages/basics/shadow.vue

@@ -0,0 +1,54 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">边框阴影</block></cu-custom>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>边框
+			</view>
+			<view class="action">
+				<switch class="sm" @change="SetSize" :class="size?'checked':''"></switch>
+			</view>
+		</view>
+		<view class="padding bg-white text-center">
+			<view class="padding" :class="size?'solids':'solid'">四周</view>
+			<view class="padding margin-top" :class="size?'solids-top':'solid-top'">上</view>
+			<view class="padding margin-top" :class="size?'solids-right':'solid-right'">右</view>
+			<view class="padding margin-top" :class="size?'solids-bottom':'solid-bottom'">下</view>
+			<view class="padding margin-top" :class="size?'solids-left':'solid-left'">左</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>阴影
+			</view>
+		</view>
+		<view class="padding text-center">
+			<view class="padding-xl radius shadow bg-white">默认阴影</view>
+			<view class="padding-xl radius shadow bg-blue margin-top">根据背景颜色而改变的阴影</view>
+			<view class="padding-xl radius shadow shadow-lg bg-white margin-top">长阴影</view>
+			<view class="padding-xl radius shadow shadow-lg bg-blue margin-top">长阴影</view>
+			<view class="padding-xl radius shadow-warp bg-white margin-top">翘边阴影</view>
+			<view class="padding-xl radius shadow-blur bg-red margin-top bg-img" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big91005.jpg);">
+				<view>根据背景图而改变的阴影</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				size: false
+			};
+		},
+		methods: {
+			SetSize(e) {
+				this.size = e.detail.value
+			}
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 130 - 0
pages/basics/tag.vue

@@ -0,0 +1,130 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">标签</block></cu-custom>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class='action'>
+				<text class='cuIcon-title text-blue'></text>标签形状
+			</view>
+		</view>
+		<view class="padding bg-white solid-bottom">
+			<view class='cu-tag'>默认</view>
+			<view class='cu-tag round'>椭圆</view>
+			<view class='cu-tag radius'>圆角</view>
+		</view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class='action'>
+				<text class='cuIcon-title text-blue'></text>标签尺寸
+			</view>
+		</view>
+		<view class="padding bg-white">
+			<view class='cu-tag radius sm'>小尺寸</view>
+			<view class='cu-tag radius'>普通尺寸</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class='action'>
+				<text class='cuIcon-title text-blue'></text>标签颜色
+			</view>
+		</view>
+		<view class='padding-sm flex flex-wrap'>
+			<view class="padding-xs" v-for="(item,index) in ColorList" :key="index" v-if="item.name!='gray'">
+				<view class='cu-tag' :class="'bg-' + item.name">{{item.title}}</view>
+			</view>
+			<view class="padding-xs" v-for="(item,index) in ColorList" :key="index" v-if="item.name!='gray' && item.name!='black' && item.name!='white'">
+				<view class='cu-tag light' :class="'bg-' + item.name">{{item.title}}</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class='action'>
+				<text class='cuIcon-title text-blue'></text>镂空标签
+			</view>
+		</view>
+		<view class='padding-sm flex flex-wrap'>
+			<view class="padding-xs" v-for="(item,index) in ColorList" :key="index" v-if="item.name!='white'">
+				<view class='cu-tag' :class="'line-' + item.name">{{item.title}}</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class='action'>
+				<text class='cuIcon-title text-blue'></text>胶囊样式
+			</view>
+		</view>
+		<view class="padding">
+			<view class="cu-capsule">
+				<view class='cu-tag bg-red'>
+					<text class='cuIcon-likefill'></text>
+				</view>
+				<view class="cu-tag line-red">
+					12
+				</view>
+			</view>
+			<view class="cu-capsule round">
+				<view class='cu-tag bg-blue '>
+					<text class='cuIcon-likefill'></text>
+				</view>
+				<view class="cu-tag line-blue">
+					23
+				</view>
+			</view>
+			<view class="cu-capsule round">
+				<view class='cu-tag bg-blue '>
+					说明
+				</view>
+				<view class="cu-tag line-blue">
+					123
+				</view>
+			</view>
+			<view class="cu-capsule radius">
+				<view class='cu-tag bg-grey '>
+					<text class='cuIcon-likefill'></text>
+				</view>
+				<view class="cu-tag line-grey">
+					23
+				</view>
+			</view>
+			<view class="cu-capsule radius">
+				<view class='cu-tag bg-brown sm'>
+					<text class='cuIcon-likefill'></text>
+				</view>
+				<view class="cu-tag line-brown sm">
+					23
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white margin-top">
+			<view class='action'>
+				<text class='cuIcon-title text-blue'></text>数字标签
+			</view>
+		</view>
+		<view class="padding flex justify-between align-center">
+			<view class='cu-avatar xl radius'>
+				港
+				<view class="cu-tag badge">99+</view>
+			</view>
+			<view class='cu-avatar xl radius' style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg)">
+				<view class='cu-tag badge'>9</view>
+			</view>
+			<view class='cu-avatar xl radius'>
+				<view class='cu-tag badge'>99</view>
+				<text class='cuIcon-people'></text>
+			</view>
+			<view class='cu-avatar xl radius'>
+				<view class='cu-tag badge'>99+</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				ColorList: this.ColorList,
+			};
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 169 - 0
pages/basics/text.vue

@@ -0,0 +1,169 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block><block slot="content">文本</block></cu-custom>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>文字大小
+			</view>
+		</view>
+		<view class="bg-white padding-lr">
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="padding">60</view>
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-xsl padding">
+						<text class=" cuIcon-roundcheckfill text-green"></text>
+					</view>
+					<view class="padding">用于图标、数字等特大显示</view>
+				</view>
+			</view>
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="padding">40</view>
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-sl padding">
+						<text class=" cuIcon-roundcheckfill text-green"></text>
+					</view>
+					<view class="padding">用于图标、数字等较大显示</view>
+				</view>
+			</view>
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="padding">22</view>
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-xxl padding">
+						<text class="text-price text-red">80.00</text>
+					</view>
+					<view class="padding">用于金额数字等信息</view>
+				</view>
+			</view>
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="padding">18</view>
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-xl padding">
+						<text class="text-black text-bold">您的订单已提交成功!</text>
+					</view>
+					<view class="padding">页面大标题,用于结果页等单一信息页</view>
+				</view>
+			</view>
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="padding">16</view>
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-lg padding">
+						<text class="text-black">ColorUI组件库</text>
+					</view>
+					<view class="padding">页面小标题,首要层级显示内容</view>
+				</view>
+			</view>
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="padding">14</view>
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-df padding">专注视觉的小程序组件库</view>
+					<view class="padding">页面默认字号,用于摘要或阅读文本</view>
+				</view>
+			</view>
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="padding">12</view>
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-sm padding">
+						<text class="text-grey">衬衫的价格是9磅15便士</text>
+					</view>
+					<view class="padding">页面辅助信息,次级内容等</view>
+				</view>
+			</view>
+			<view class="padding-xs flex align-center">
+				<view class="padding">10</view>
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-xs padding">
+						<text class="text-gray">我于杀戮之中绽放 亦如黎明中的花朵</text>
+					</view>
+					<view class="padding">说明文本,标签文字等关注度低的文字</view>
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>文字颜色
+			</view>
+		</view>
+		<view class="grid col-5 padding-sm">
+			<view class="padding-sm" v-for="(item,index) in ColorList" :key="index">
+				<view class="text-center" :class="'text-' + item.name">
+					{{item.title}}
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>文字阴影
+			</view>
+		</view>
+		<view class="grid col-5 padding-sm">
+			<view class="padding-sm" v-for="(item,index) in ColorList" :key="index">
+				<view class="text-center text-shadow" :class="'text-' + item.name">
+					<view class="cuIcon-ellipse text-xxl"></view>
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>文字截断
+			</view>
+		</view>
+		<view class="padding bg-white">
+			<view class="text-cut padding bg-grey radius" style="width:220px">我于杀戮之中绽放 ,亦如黎明中的花朵</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>文字对齐
+			</view>
+		</view>
+		<view class="padding bg-white">
+			<view class="text-left padding">我于杀戮之中绽放 ,亦如黎明中的花朵</view>
+			<view class="text-center padding">我于杀戮之中绽放 ,亦如黎明中的花朵</view>
+			<view class="text-right padding">我于杀戮之中绽放 ,亦如黎明中的花朵</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-blue"></text>特殊文字
+			</view>
+		</view>
+		<view class="padding text-center">
+			<view class="padding-lr bg-white">
+				<view class="solid-bottom padding">
+					<text class="text-price">80.00</text>
+				</view>
+				<view class="padding">价格文本,利用伪元素添加"¥"符号</view>
+			</view>
+			<view class="padding-lr bg-white margin-top">
+				<view class="solid-bottom padding">
+					<text class="text-Abc">color Ui</text>
+				</view>
+				<view class="padding">英文单词首字母大写</view>
+			</view>
+			<view class="padding-lr bg-white margin-top">
+				<view class="solid-bottom padding">
+					<text class="text-ABC">color Ui</text>
+				</view>
+				<view class="padding">全部字母大写</view>
+			</view>
+			<view class="padding-lr bg-white margin-top">
+				<view class="solid-bottom padding">
+					<text class="text-abc">color Ui</text>
+				</view>
+				<view class="padding">全部字母小写</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				ColorList: this.ColorList,
+			};
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 51 - 0
pages/common/exit.vue

@@ -0,0 +1,51 @@
+<template>
+	<view>
+		<scroll-view :scroll-y="modalName==null" class="page" :class="modalName!=null?'show':''">
+			<cu-custom bgColor="bg-gradual-pink" :isBack="false">
+				<!-- <block slot="backText">返回</block> -->
+				<block slot="content">退出页</block>
+			</cu-custom>
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-xsl padding">
+						<text class=" cuIcon-roundcheckfill text-green"></text>
+					</view>
+					<view class="padding">{{item.msg}}</view>
+				</view>
+			</view>
+			<view class="padding flex flex-direction">
+				<button class="cu-btn bg-green shadow-blur round lg" @tap="goback()">返回登录
+				</button>
+			</view>
+		</scroll-view>
+	</view>
+
+</template>
+
+<script>
+	import api from "@/api/api";
+	
+	export default {
+		data() {
+			return {
+				modalName: null,
+				item:{msg:'退出成功'},
+			}
+		},
+		onLoad: function (option) {
+			api.logout().then(res=>{
+				uni.clearStorageSync()
+			})
+		},
+		methods: {
+			goback(){
+				uni.navigateTo({
+					url:'/pages/login/login'
+				})
+			}
+		}
+	}
+</script>
+
+<style>
+</style>

+ 48 - 0
pages/common/success.vue

@@ -0,0 +1,48 @@
+<template>
+	<view>
+		<scroll-view :scroll-y="modalName==null" class="page" :class="modalName!=null?'show':''">
+			<cu-custom bgColor="bg-gradual-pink" :isBack="true">
+				<block slot="backText">返回</block>
+				<block slot="content">结果</block>
+			</cu-custom>
+			<view class="solids-bottom padding-xs flex align-center">
+				<view class="flex-sub text-center">
+					<view class="solid-bottom text-xsl padding">
+						<text class=" cuIcon-roundcheckfill text-green"></text>
+					</view>
+					<view class="padding">{{item.msg}}</view>
+				</view>
+			</view>
+			<view class="padding flex flex-direction">
+				<button class="cu-btn bg-green shadow-blur round lg" @tap="goback()">返回主页
+				</button>
+			</view>
+		</scroll-view>
+	</view>
+
+</template>
+
+<script>
+	
+	export default {
+		data() {
+			return {
+				modalName: null,
+				item:{},
+			}
+		},
+		onLoad: function (option) {
+		    this.item = JSON.parse(decodeURIComponent(option.item));
+		},
+		methods: {
+			goback(){
+				uni.navigateTo({
+					url:'/pages/index/index'
+				})
+			}
+		}
+	}
+</script>
+
+<style>
+</style>

+ 448 - 0
pages/component/bar.vue

@@ -0,0 +1,448 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true"><block slot="backText">返回</block><block slot="content">操作条</block></cu-custom>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-green"></text>
+				<text>底部操作条</text>
+			</view>
+		</view>
+		<view class="box">
+			<view class="cu-bar tabbar bg-white">
+				<view class="action">
+					<view class="cuIcon-cu-image">
+						<image src="/static/tabbar/basics_cur.png"></image>
+					</view>
+					<view class="text-green">元素</view>
+				</view>
+				<view class="action">
+					<view class="cuIcon-cu-image">
+						<image src="/static/tabbar/component.png"></image>
+					</view>
+					<view class="text-gray">组件</view>
+				</view>
+				<view class="action">
+					<view class="cuIcon-cu-image">
+						<image src="/static/tabbar/plugin.png"></image>
+						<view class="cu-tag badge">99</view>
+					</view>
+					<view class="text-gray">扩展</view>
+				</view>
+				<view class="action">
+					<view class="cuIcon-cu-image">
+						<image src="/static/tabbar/about.png"></image>
+						<view class="cu-tag badge"></view>
+					</view>
+					<view class="text-gray">关于</view>
+				</view>
+			</view>
+			<view class="cu-bar tabbar margin-bottom-xl bg-black">
+				<view class="action text-orange">
+					<view class="cuIcon-homefill"></view> 首页
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-similar"></view> 分类
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-recharge"></view>
+					积分
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-cart">
+						<view class="cu-tag badge">99</view>
+					</view>
+					购物车
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-my">
+						<view class="cu-tag badge"></view>
+					</view>
+					我的
+				</view>
+			</view>
+			<view class="cu-bar tabbar margin-bottom-xl bg-white">
+				<view class="action text-green">
+					<view class="cuIcon-homefill"></view> 首页
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-similar"></view> 分类
+				</view>
+				<view class="action text-gray add-action">
+					<button class="cu-btn cuIcon-add bg-green shadow"></button>
+					发布
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-cart">
+						<view class="cu-tag badge">99</view>
+					</view>
+					购物车
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-my">
+						<view class="cu-tag badge"></view>
+					</view>
+					我的
+				</view>
+			</view>
+			<view class="cu-bar tabbar bg-black">
+				<view class="action text-green">
+					<view class="cuIcon-homefill"></view> 首页
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-similar"></view> 分类
+				</view>
+				<view class="action text-gray add-action">
+					<button class="cu-btn cuIcon-add bg-green shadow"></button>
+					发布
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-cart">
+						<view class="cu-tag badge">99</view>
+					</view>
+					购物车
+				</view>
+				<view class="action text-gray">
+					<view class="cuIcon-my">
+						<view class="cu-tag badge"></view>
+					</view>
+					我的
+				</view>
+			</view>
+
+			<view class="cu-bar bg-white tabbar border shop">
+				<button class="action" open-type="contact">
+					<view class="cuIcon-service text-green">
+						<view class="cu-tag badge"></view>
+					</view>
+					客服
+				</button>
+				<view class="action text-orange">
+					<view class="cuIcon-favorfill"></view> 已收藏
+				</view>
+				<view class="action">
+					<view class="cuIcon-cart">
+						<view class="cu-tag badge">99</view>
+					</view>
+					购物车
+				</view>
+				<view class="bg-red submit">立即订购</view>
+			</view>
+
+			<view class="cu-bar bg-white tabbar border shop">
+				<button class="action" open-type="contact">
+					<view class="cuIcon-service text-green">
+						<view class="cu-tag badge"></view>
+					</view>
+					客服
+				</button>
+				<view class="action">
+					<view class="cuIcon-cart">
+						<view class="cu-tag badge">99</view>
+					</view>
+					购物车
+				</view>
+				<view class="bg-orange submit">加入购物车</view>
+				<view class="bg-red submit">立即订购</view>
+			</view>
+
+			<view class="cu-bar bg-white tabbar border shop">
+				<button class="action" open-type="contact">
+					<view class="cuIcon-service text-green">
+						<view class="cu-tag badge"></view>
+					</view>
+					客服
+				</button>
+				<view class="action">
+					<view class=" cuIcon-shop"></view> 店铺
+				</view>
+				<view class="action">
+					<view class="cuIcon-cart">
+						<view class="cu-tag badge">99</view>
+					</view>
+					购物车
+				</view>
+				<view class="btn-group">
+					<button class="cu-btn bg-red round shadow-blur">立即订购</button>
+				</view>
+			</view>
+			<view class="cu-bar bg-white tabbar border shop">
+				<button class="action" open-type="contact">
+					<view class="cuIcon-service text-green">
+						<view class="cu-tag badge"></view>
+					</view> 客服
+				</button>
+				<view class="action">
+					<view class="cuIcon-cart">
+						<view class="cu-tag badge">99</view>
+					</view>
+					购物车
+				</view>
+				<view class="btn-group">
+					<button class="cu-btn bg-orange round shadow-blur">加入购物车</button>
+					<button class="cu-btn bg-red round shadow-blur">立即订购</button>
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-green"></text>
+				<text>标题操作条</text>
+			</view>
+		</view>
+		<view class="box" v-if="false">
+			<view class="cu-bar justify-center bg-white">
+				<view class="action border-title">
+					<text class="text-xl text-bold">关于我们</text>
+					<text class="bg-grey" style="width:2rem"></text>
+					<!-- 底部样式 last-child选择器-->
+				</view>
+			</view>
+			<view class="cu-bar justify-center bg-white">
+				<view class="action border-title">
+					<text class="text-xl text-bold text-blue">关于我们</text>
+					<text class="bg-gradual-blue" style="width:3rem"></text>
+				</view>
+			</view>
+			<view class="cu-bar justify-center bg-white">
+				<view class="action sub-title">
+					<text class="text-xl text-bold text-green">关于我们</text>
+					<text class="bg-green" style="width:2rem"></text>
+					<!-- last-child选择器-->
+				</view>
+			</view>
+			<view class="cu-bar justify-center bg-white">
+				<view class="action sub-title">
+					<text class="text-xl text-bold text-blue">关于我们</text>
+					<text class="text-ABC text-blue">about</text>
+					<!-- last-child选择器-->
+				</view>
+			</view>
+		</view>
+		<view class="box">
+			<view class="cu-bar bg-white">
+				<view class="action border-title">
+					<text class="text-xl text-bold">关于我们</text>
+					<text class="bg-grey" style="width:2rem"></text>
+					<!-- 底部样式 last-child选择器-->
+				</view>
+			</view>
+			<view class="cu-bar bg-white">
+				<view class="action border-title">
+					<text class="text-xl text-bold text-blue">关于我们</text>
+					<text class="bg-gradual-blue" style="width:3rem"></text>
+				</view>
+			</view>
+			<view class="cu-bar bg-white">
+				<view class="action sub-title">
+					<text class="text-xl text-bold text-green">关于我们</text>
+					<text class="bg-green"></text>
+					<!-- last-child选择器-->
+				</view>
+			</view>
+			<view class="cu-bar bg-white">
+				<view class="action sub-title">
+					<text class="text-xl text-bold text-blue">关于我们</text>
+					<text class="text-ABC text-blue">about</text>
+					<!-- last-child选择器-->
+				</view>
+			</view>
+			<view class="cu-bar bg-white">
+				<view class="action title-style-3">
+					<text class="text-xl text-bold">关于我们</text>
+					<text class="text-Abc text-gray self-end margin-left-sm">about</text>
+				</view>
+			</view>
+			<view class="cu-bar bg-white">
+				<view class="action">
+					<text class="cuIcon-title text-green"></text>
+					<text class="text-xl text-bold">关于我们</text>
+				</view>
+			</view>
+			<view class="cu-bar bg-white">
+				<view class="action">
+					<text class="cuIcon-titles text-green"></text>
+					<text class="text-xl text-bold">关于我们</text>
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-green"></text>
+				<text>顶部操作条</text>
+			</view>
+		</view>
+		<view class="box">
+			<view class="cu-bar bg-white">
+				<view class="action">
+					<text class="cuIcon-back text-gray"></text> 返回
+				</view>
+				<view class="content text-bold">
+					操作条
+				</view>
+			</view>
+			<view class="cu-bar bg-white">
+				<view class="action">
+					<text class="cuIcon-homefill text-gray"></text> 首页
+				</view>
+				<view class="content text-bold">
+					鲜亮的高饱和色彩,专注视觉的小程序组件库
+				</view>
+				<view class="action">
+					<text class="cuIcon-cardboardfill text-grey"></text>
+					<text class="cuIcon-recordfill text-red"></text>
+				</view>
+			</view>
+			<view class="cu-bar bg-blue">
+				<view class="action">
+					<text class="cuIcon-close"></text> 关闭
+				</view>
+				<view class="content text-bold">
+					海蓝
+				</view>
+			</view>
+			<view class="cu-bar bg-black search">
+				<view class="cu-avatar round" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big91012.jpg);"></view>
+				<view class="content">
+					ColorUI
+				</view>
+				<view class="action">
+					<text class="cuIcon-more"></text>
+				</view>
+			</view>
+		</view>
+
+
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-green"></text>
+				<text>搜索操作条</text>
+			</view>
+		</view>
+		<view class="box">
+			<view class="cu-bar search bg-white">
+				<view class="search-form round">
+					<text class="cuIcon-search"></text>
+					<input @focus="InputFocus" @blur="InputBlur" :adjust-position="false" type="text" placeholder="搜索图片、文章、视频" confirm-type="search"></input>
+				</view>
+				<view class="action">
+					<button class="cu-btn bg-green shadow-blur round">搜索</button>
+				</view>
+			</view>
+			<view class="cu-bar search bg-white">
+				<view class="cu-avatar round" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big11010.jpg"></view>
+				<view class="search-form round">
+					<text class="cuIcon-search"></text>
+					<input @focus="InputFocus" @blur="InputBlur" :adjust-position="false" type="text" placeholder="搜索图片、文章、视频" confirm-type="search"></input>
+				</view>
+				<view class="action">
+					<text>广州</text>
+					<text class="cuIcon-triangledownfill"></text>
+				</view>
+			</view>
+			<view class="cu-bar bg-red search">
+				<view class="cu-avatar round" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big114004.jpg);"></view>
+				<view class="search-form radius">
+					<text class="cuIcon-search"></text>
+					<input @focus="InputFocus" @blur="InputBlur" :adjust-position="false" type="text" placeholder="搜索图片、文章、视频" confirm-type="search"></input>
+				</view>
+				<view class="action">
+					<text>广州</text>
+					<text class="cuIcon-triangledownfill"></text>
+				</view>
+			</view>
+			<view class="cu-bar bg-cyan search">
+				<view class="search-form radius">
+					<text class="cuIcon-search"></text>
+					<input @focus="InputFocus" @blur="InputBlur" :adjust-position="false" type="text" placeholder="搜索图片、文章、视频" confirm-type="search"></input>
+				</view>
+				<view class="action">
+					<text class="cuIcon-close"></text>
+					<text>取消</text>
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-green"></text>
+				<text>操作条按钮组</text>
+			</view>
+		</view>
+
+		<view class="box">
+			<view class="cu-bar btn-group">
+				<button class="cu-btn bg-green shadow-blur round lg">保存</button>
+			</view>
+			<view class="cu-bar btn-group">
+				<button class="cu-btn bg-green shadow-blur">保存</button>
+				<button class="cu-btn text-green line-green shadow">上传</button>
+			</view>
+			<view class="cu-bar btn-group">
+				<button class="cu-btn bg-green shadow-blur round">保存</button>
+				<button class="cu-btn bg-blue shadow-blur round">提交</button>
+			</view>
+		</view>
+
+
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-green"></text>
+				<text>输入操作条</text>
+			</view>
+		</view>
+		<view class="box">
+			<view class="cu-bar input">
+				<view class="action">
+					<text class="cuIcon-sound text-grey"></text>
+				</view>
+				<input @focus="InputFocus" @blur="InputBlur" :adjust-position="false" class="solid-bottom" :focus="false" maxlength="300" cursor-spacing="10"></input>
+				<view class="action">
+					<text class="cuIcon-emojifill text-grey"></text>
+				</view>
+				<button class="cu-btn bg-green shadow-blur">发送</button>
+			</view>
+
+			<view class="cu-bar input">
+				<view class="cu-avatar round" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big91012.jpg);"></view>
+				<view class="action">
+					<text class="cuIcon-roundaddfill text-grey"></text>
+				</view>
+				<input @focus="InputFocus" @blur="InputBlur" :adjust-position="false" class="solid-bottom" maxlength="300" cursor-spacing="10"></input>
+				<view class="action">
+					<text class="cuIcon-emojifill text-grey"></text>
+				</view>
+				<button class="cu-btn bg-green shadow-blur">发送</button>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				InputBottom: 0
+			};
+		},
+		methods: {
+			InputFocus(e) {
+				this.InputBottom = e.detail.height
+			},
+			InputBlur(e) {
+				this.InputBottom = 0
+			}
+		}
+	}
+</script>
+
+<style>
+	.box {
+		margin: 20upx 0;
+	}
+
+	.box view.cu-bar {
+		margin-top: 20upx;
+	}
+</style>

+ 167 - 0
pages/component/card.vue

@@ -0,0 +1,167 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true"><block slot="backText">返回</block><block slot="content">卡片</block></cu-custom>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-titles text-orange"></text> 案例类卡片
+			</view>
+			<view class="action">
+				<switch :class="isCard?'checked':''" :checked="isCard?true:false" @change="IsCard"></switch>
+			</view>
+		</view>
+		<view class="cu-card case" :class="isCard?'no-card':''">
+			<view class="cu-item shadow">
+				<view class="image">
+					<image src="https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg"
+					 mode="widthFix"></image>
+					<view class="cu-tag bg-blue">史诗</view>
+					<view class="cu-bar bg-shadeBottom"> <text class="text-cut">我已天理为凭,踏入这片荒芜,不再受凡人的枷锁遏制。我已天理为凭,踏入这片荒芜,不再受凡人的枷锁遏制。</text></view>
+				</view>
+				<view class="cu-list menu-avatar">
+					<view class="cu-item">
+						<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg);"></view>
+						<view class="content flex-sub">
+							<view class="text-grey">正义天使 凯尔</view>
+							<view class="text-gray text-sm flex justify-between">
+								十天前
+								<view class="text-gray text-sm">
+									<text class="cuIcon-attentionfill margin-lr-xs"></text> 10
+									<text class="cuIcon-appreciatefill margin-lr-xs"></text> 20
+									<text class="cuIcon-messagefill margin-lr-xs"></text> 30
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom" :class="isCard?'margin-top':''">
+			<view class="action">
+				<text class="cuIcon-titles text-orange "></text> 动态类卡片
+			</view>
+			<view class="action">
+				<switch :class="isCard?'checked':''" :checked="isCard?true:false" @change="IsCard"></switch>
+			</view>
+		</view>
+		<view class="cu-card dynamic" :class="isCard?'no-card':''">
+			<view class="cu-item shadow">
+				<view class="cu-list menu-avatar">
+					<view class="cu-item">
+						<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg);"></view>
+						<view class="content flex-sub">
+							<view>凯尔</view>
+							<view class="text-gray text-sm flex justify-between">
+								2019年12月3日
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="text-content">
+					折磨生出苦难,苦难又会加剧折磨,凡间这无穷的循环,将有我来终结!
+				</view>
+				<view class="grid flex-sub padding-lr" :class="isCard?'col-3 grid-square':'col-1'">
+					<view class="bg-img" :class="isCard?'':'only-img'" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg);"
+					 v-for="(item,index) in isCard?9:1" :key="index">
+					</view>
+				</view>
+				<view class="text-gray text-sm text-right padding">
+					<text class="cuIcon-attentionfill margin-lr-xs"></text> 10
+					<text class="cuIcon-appreciatefill margin-lr-xs"></text> 20
+					<text class="cuIcon-messagefill margin-lr-xs"></text> 30
+				</view>
+
+				<view class="cu-list menu-avatar comment solids-top">
+					<view class="cu-item">
+						<view class="cu-avatar round" style="background-image:url(https://ossweb-img.qq.com/images/lol/img/champion/Morgana.png);"></view>
+						<view class="content">
+							<view class="text-grey">莫甘娜</view>
+							<view class="text-gray text-content text-df">
+								凯尔,你被自己的光芒变的盲目。
+							</view>
+							<view class="bg-grey padding-sm radius margin-top-sm  text-sm">
+								<view class="flex">
+									<view>凯尔:</view>
+									<view class="flex-sub">妹妹,你在帮他们给黑暗找借口吗?</view>
+								</view>
+							</view>
+							<view class="margin-top-sm flex justify-between">
+								<view class="text-gray text-df">2018年12月4日</view>
+								<view>
+									<text class="cuIcon-appreciatefill text-red"></text>
+									<text class="cuIcon-messagefill text-gray margin-left-sm"></text>
+								</view>
+							</view>
+						</view>
+					</view>
+
+					<view class="cu-item">
+						<view class="cu-avatar round" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg);"></view>
+						<view class="content">
+							<view class="text-grey">凯尔</view>
+							<view class="text-gray text-content text-df">
+								妹妹,如果不是为了飞翔,我们要这翅膀有什么用?
+							</view>
+							<view class="bg-grey padding-sm radius margin-top-sm  text-sm">
+								<view class="flex">
+									<view>莫甘娜:</view>
+									<view class="flex-sub">如果不能立足于大地,要这双脚又有何用?</view>
+								</view>
+							</view>
+							<view class="margin-top-sm flex justify-between">
+								<view class="text-gray text-df">2018年12月4日</view>
+								<view>
+									<text class="cuIcon-appreciate text-gray"></text>
+									<text class="cuIcon-messagefill text-gray margin-left-sm"></text>
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-titles text-orange "></text> 文章类卡片
+			</view>
+			<view class="action">
+				<switch :class="isCard?'checked':''" :checked="isCard?true:false" @change="IsCard"></switch>
+			</view>
+		</view>
+		<view class="cu-card article" :class="isCard?'no-card':''">
+			<view class="cu-item shadow">
+				<view class="title"><view class="text-cut">无意者 烈火焚身;以正义的烈火拔出黑暗。我有自己的正义,见证至高的烈火吧。</view></view>
+				<view class="content">
+					<image src="https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg"
+					 mode="aspectFill"></image>
+					<view class="desc">
+						<view class="text-content"> 折磨生出苦难,苦难又会加剧折磨,凡间这无穷的循环,将有我来终结!真正的恩典因不完整而美丽,因情感而真诚,因脆弱而自由!</view>
+						<view>
+							<view class="cu-tag bg-red light sm round">正义天使</view>
+							<view class="cu-tag bg-green light sm round">史诗</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				isCard: false
+			};
+		},
+		methods: {
+			IsCard(e) {
+				this.isCard = e.detail.value
+			},
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 113 - 0
pages/component/chat.vue

@@ -0,0 +1,113 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true"><block slot="backText">返回</block><block slot="content">聊天</block></cu-custom>
+		<view class="cu-chat">
+			<view class="cu-item self">
+				<view class="main">
+					<view class="content bg-green shadow">
+						<text>喵喵喵!喵喵喵!喵喵喵!喵喵!喵喵!!喵!喵喵喵!</text>
+					</view>
+				</view>
+				<view class="cu-avatar radius" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big107000.jpg);"></view>
+				<view class="date">2018年3月23日 13:23</view>
+			</view>
+			<view class="cu-info round">对方撤回一条消息!</view>
+			<view class="cu-item">
+				<view class="cu-avatar radius" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg);"></view>
+				<view class="main">
+					<view class="content shadow">
+						<text>喵喵喵!喵喵喵!</text>
+					</view>
+				</view>
+				<view class="date "> 13:23</view>
+			</view>
+			<view class="cu-info">
+				<text class="cuIcon-roundclosefill text-red "></text> 对方拒绝了你的消息
+			</view>
+			<view class="cu-info">
+				对方开启了好友验证,你还不是他(她)的好友。请先发送好友验证请求,对方验证通过后,才能聊天。
+				<text class="text-blue">发送好友验证</text>
+			</view>
+			<view class="cu-item self">
+				<view class="main">
+					<image src="https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg" class="radius" mode="widthFix"></image>
+				</view>
+				<view class="cu-avatar radius" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big107000.jpg);"></view>
+				<view class="date"> 13:23</view>
+			</view>
+			<view class="cu-item self">
+				<view class="main">
+					<view class="action text-bold text-grey">
+						3"
+					</view>
+					<view class="content shadow">
+						<text class="cuIcon-sound text-xxl padding-right-xl"> </text>
+					</view>
+				</view>
+				<view class="cu-avatar radius" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big107000.jpg);"></view>
+				<view class="date">13:23</view>
+			</view>
+			<view class="cu-item self">
+				<view class="main">
+					<view class="action">
+						<text class="cuIcon-locationfill text-orange text-xxl"></text>
+					</view>
+					<view class="content shadow">
+						喵星球,喵喵市
+					</view>
+				</view>
+				<view class="cu-avatar radius" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big107000.jpg);"></view>
+				<view class="date">13:23</view>
+			</view>
+			<view class="cu-item">
+				<view class="cu-avatar radius" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg);"></view>
+				<view class="main">
+					<view class="content shadow">
+						@#$^&**
+					</view>
+					<view class="action text-grey">
+						<text class="cuIcon-warnfill text-red text-xxl"></text> <text class="text-sm margin-left-sm">翻译错误</text>
+					</view>
+				</view>
+				<view class="date">13:23</view>
+			</view>
+		</view>
+
+		<view class="cu-bar foot input" :style="[{bottom:InputBottom+'px'}]">
+			<view class="action">
+				<text class="cuIcon-sound text-grey"></text>
+			</view>
+			<input class="solid-bottom" :adjust-position="false" :focus="false" maxlength="300" cursor-spacing="10"
+			 @focus="InputFocus" @blur="InputBlur"></input>
+			<view class="action">
+				<text class="cuIcon-emojifill text-grey"></text>
+			</view>
+			<button class="cu-btn bg-green shadow">发送</button>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				InputBottom: 0
+			};
+		},
+		methods: {
+			InputFocus(e) {
+				this.InputBottom = e.detail.height
+			},
+			InputBlur(e) {
+				this.InputBottom = 0
+			}
+		}
+	}
+</script>
+
+<style>
+page{
+  padding-bottom: 100upx;
+}
+</style>

+ 415 - 0
pages/component/form.vue

@@ -0,0 +1,415 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true">
+			<block slot="backText">返回</block>
+			<block slot="content">表单</block>
+		</cu-custom>
+		<form>
+			<view class="cu-form-group margin-top">
+				<view class="title">邮件</view>
+				<input placeholder="两字短标题" name="input"></input>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">输入框</view>
+				<input placeholder="三字标题" name="input"></input>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">收货地址</view>
+				<input placeholder="统一标题的宽度" name="input"></input>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">收货地址</view>
+				<input placeholder="输入框带个图标" name="input"></input>
+				<text class='cuIcon-locationfill text-orange'></text>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">验证码</view>
+				<input placeholder="输入框带个按钮" name="input"></input>
+				<button class='cu-btn bg-green shadow'>验证码</button>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">手机号码</view>
+				<input placeholder="输入框带标签" name="input"></input>
+				<view class="cu-capsule radius">
+					<view class='cu-tag bg-blue '>
+						+86
+					</view>
+					<view class="cu-tag line-blue">
+						中国大陆
+					</view>
+				</view>
+			</view>
+			<view class="cu-form-group margin-top">
+				<view class="title">普通选择</view>
+				<picker @change="PickerChange" :value="index" :range="picker">
+					<view class="picker">
+						{{index>-1?picker[index]:'禁止换行,超出容器部分会以 ... 方式截断'}}
+					</view>
+				</picker>
+			</view>
+			<!-- #ifndef MP-ALIPAY -->
+			<view class="cu-form-group">
+				<view class="title">多列选择</view>
+				<picker mode="multiSelector" @change="MultiChange" @columnchange="MultiColumnChange" :value="multiIndex" :range="multiArray">
+					<view class="picker">
+						{{multiArray[0][multiIndex[0]]}},{{multiArray[1][multiIndex[1]]}},{{multiArray[2][multiIndex[2]]}}
+					</view>
+				</picker>
+			</view>
+			<!-- #endif -->
+			<view class="cu-form-group">
+				<view class="title">时间选择</view>
+				<picker mode="time" :value="time" start="09:01" end="21:01" @change="TimeChange">
+					<view class="picker">
+						{{time}}
+					</view>
+				</picker>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">日期选择</view>
+				<picker mode="date" :value="date" start="2015-09-01" end="2020-09-01" @change="DateChange">
+					<view class="picker">
+						{{date}}
+					</view>
+				</picker>
+			</view>
+			<!-- #ifndef H5 || APP-PLUS || MP-ALIPAY -->
+			<view class="cu-form-group">
+				<view class="title">地址选择</view>
+				<picker mode="region" @change="RegionChange" :value="region">
+					<view class="picker">
+						{{region[0]}},{{region[1]}},{{region[2]}}
+					</view>
+				</picker>
+			</view>
+			<!-- #endif -->
+			<view class="cu-form-group margin-top">
+				<view class="title">开关选择</view>
+				<switch @change="SwitchA" :class="switchA?'checked':''" :checked="switchA?true:false"></switch>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">定义颜色</view>
+				<!-- #ifdef MP-ALIPAY -->
+				<switch class='red' @change="SwitchB" :class="switchB?'checked':''" :checked="switchB?true:false" color="#e54d42"></switch>
+				<!-- #endif -->
+
+				<!-- #ifndef MP-ALIPAY -->
+				<switch class='red' @change="SwitchB" :class="switchB?'checked':''" :checked="switchB?true:false"></switch>
+				<!-- #endif -->
+			</view>
+			<view class="cu-form-group">
+				<view class="title">定义图标</view>
+				<switch class='switch-sex' @change="SwitchC" :class="switchC?'checked':''" :checked="switchC?true:false"></switch>
+			</view>
+			<!-- #ifndef MP-ALIPAY -->
+			<view class="cu-form-group">
+				<view class="title">方形开关</view>
+				<switch class='orange radius' @change="SwitchD" :class="switchD?'checked':''" :checked="switchD?true:false"></switch>
+			</view>
+			<!-- #endif -->
+			<radio-group class="block" @change="RadioChange">
+				<view class="cu-form-group margin-top">
+					<view class="title">单选操作(radio)</view>
+					<radio :class="radio=='A'?'checked':''" :checked="radio=='A'?true:false" value="A"></radio>
+				</view>
+				<!-- #ifndef MP-ALIPAY -->
+				<view class="cu-form-group">
+					<view class="title">定义样式</view>
+					<radio class='radio' :class="radio=='B'?'checked':''" :checked="radio=='B'?true:false" value="B"></radio>
+				</view>
+				<view class="cu-form-group">
+					<view class="title">定义颜色</view>
+					<view>
+						<radio class='blue radio' :class="radio=='C'?'checked':''" :checked="radio=='C'?true:false" value="C"></radio>
+						<radio class='red margin-left-sm' :class="radio=='D'?'checked':''" :checked="radio=='D'?true:false" value="D"></radio>
+					</view>
+				</view>
+				<!-- #endif -->
+			</radio-group>
+			<checkbox-group class="block" @change="CheckboxChange">
+				<view class="cu-form-group margin-top">
+					<view class="title">复选选操作(checkbox)</view>
+					<checkbox :class="checkbox[0].checked?'checked':''" :checked="checkbox[0].checked?true:false" value="A"></checkbox>
+				</view>
+				<!-- #ifndef MP-ALIPAY -->
+				<view class="cu-form-group">
+					<view class="title">定义形状</view>
+					<checkbox class='round' :class="checkbox[1].checked?'checked':''" :checked="checkbox[1].checked?true:false" value="B"></checkbox>
+				</view>
+				<view class="cu-form-group">
+					<view class="title">定义颜色</view>
+					<checkbox class='round blue' :class="checkbox[2].checked?'checked':''" :checked="checkbox[2].checked?true:false"
+					 value="C"></checkbox>
+				</view>
+				<!-- #endif -->
+			</checkbox-group>
+			<view class="cu-bar bg-white margin-top">
+				<view class="action">
+					图片上传
+				</view>
+				<view class="action">
+					{{imgList.length}}/4
+				</view>
+			</view>
+			<view class="cu-form-group">
+				<view class="grid col-4 grid-square flex-sub">
+					<view class="bg-img" v-for="(item,index) in imgList" :key="index" @tap="ViewImage" :data-url="imgList[index]">
+					 <image :src="imgList[index]" mode="aspectFill"></image>
+						<view class="cu-tag bg-red" @tap.stop="DelImg" :data-index="index">
+							<text class='cuIcon-close'></text>
+						</view>
+					</view>
+					<view class="solids" @tap="ChooseImage" v-if="imgList.length<4">
+						<text class='cuIcon-cameraadd'></text>
+					</view>
+				</view>
+			</view>
+			<view class="cu-form-group margin-top">
+				<view class="title">头像</view>
+				<view class="cu-avatar radius bg-gray"></view>
+			</view>
+			<!-- !!!!! placeholder 在ios表现有偏移 建议使用 第一种样式 -->
+			<view class="cu-form-group margin-top">
+				<textarea maxlength="-1" :disabled="modalName!=null" @input="textareaAInput" placeholder="多行文本输入框"></textarea>
+			</view>
+			<view class="cu-form-group align-start">
+				<view class="title">文本框</view>
+				<textarea maxlength="-1" :disabled="modalName!=null" @input="textareaBInput" placeholder="多行文本输入框"></textarea>
+			</view>
+		</form>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				index: -1,
+				picker: ['喵喵喵', '汪汪汪', '哼唧哼唧'],
+				multiArray: [
+					['无脊柱动物', '脊柱动物'],
+					['扁性动物', '线形动物', '环节动物', '软体动物', '节肢动物'],
+					['猪肉绦虫', '吸血虫']
+				],
+				objectMultiArray: [
+					[{
+							id: 0,
+							name: '无脊柱动物'
+						},
+						{
+							id: 1,
+							name: '脊柱动物'
+						}
+					],
+					[{
+							id: 0,
+							name: '扁性动物'
+						},
+						{
+							id: 1,
+							name: '线形动物'
+						},
+						{
+							id: 2,
+							name: '环节动物'
+						},
+						{
+							id: 3,
+							name: '软体动物'
+						},
+						{
+							id: 3,
+							name: '节肢动物'
+						}
+					],
+					[{
+							id: 0,
+							name: '猪肉绦虫'
+						},
+						{
+							id: 1,
+							name: '吸血虫'
+						}
+					]
+				],
+				multiIndex: [0, 0, 0],
+				time: '12:01',
+				date: '2018-12-25',
+				region: ['广东省', '广州市', '海珠区'],
+				switchA: false,
+				switchB: true,
+				switchC: false,
+				switchD: false,
+				radio: 'A',
+				checkbox: [{
+					value: 'A',
+					checked: true
+				}, {
+					value: 'B',
+					checked: true
+				}, {
+					value: 'C',
+					checked: false
+				}],
+				imgList: [],
+				modalName: null,
+				textareaAValue: '',
+				textareaBValue: ''
+			};
+		},
+		methods: {
+			PickerChange(e) {
+				this.index = e.detail.value
+			},
+			MultiChange(e) {
+				this.multiIndex = e.detail.value
+			},
+			MultiColumnChange(e) {
+				let data = {
+					multiArray: this.multiArray,
+					multiIndex: this.multiIndex
+				};
+				data.multiIndex[e.detail.column] = e.detail.value;
+				switch (e.detail.column) {
+					case 0:
+						switch (data.multiIndex[0]) {
+							case 0:
+								data.multiArray[1] = ['扁性动物', '线形动物', '环节动物', '软体动物', '节肢动物'];
+								data.multiArray[2] = ['猪肉绦虫', '吸血虫'];
+								break;
+							case 1:
+								data.multiArray[1] = ['鱼', '两栖动物', '爬行动物'];
+								data.multiArray[2] = ['鲫鱼', '带鱼'];
+								break;
+						}
+						data.multiIndex[1] = 0;
+						data.multiIndex[2] = 0;
+						break;
+					case 1:
+						switch (data.multiIndex[0]) {
+							case 0:
+								switch (data.multiIndex[1]) {
+									case 0:
+										data.multiArray[2] = ['猪肉绦虫', '吸血虫'];
+										break;
+									case 1:
+										data.multiArray[2] = ['蛔虫'];
+										break;
+									case 2:
+										data.multiArray[2] = ['蚂蚁', '蚂蟥'];
+										break;
+									case 3:
+										data.multiArray[2] = ['河蚌', '蜗牛', '蛞蝓'];
+										break;
+									case 4:
+										data.multiArray[2] = ['昆虫', '甲壳动物', '蛛形动物', '多足动物'];
+										break;
+								}
+								break;
+							case 1:
+								switch (data.multiIndex[1]) {
+									case 0:
+										data.multiArray[2] = ['鲫鱼', '带鱼'];
+										break;
+									case 1:
+										data.multiArray[2] = ['青蛙', '娃娃鱼'];
+										break;
+									case 2:
+										data.multiArray[2] = ['蜥蜴', '龟', '壁虎'];
+										break;
+								}
+								break;
+						}
+						data.multiIndex[2] = 0;
+						break;
+				}
+				this.multiArray = data.multiArray;
+				this.multiIndex = data.multiIndex;
+			},
+			TimeChange(e) {
+				this.time = e.detail.value
+			},
+			DateChange(e) {
+				this.date = e.detail.value
+			},
+			RegionChange(e) {
+				this.region = e.detail.value
+			},
+			SwitchA(e) {
+				this.switchA = e.detail.value
+			},
+			SwitchB(e) {
+				this.switchB = e.detail.value
+			},
+			SwitchC(e) {
+				this.switchC = e.detail.value
+			},
+			SwitchD(e) {
+				this.switchD = e.detail.value
+			},
+			RadioChange(e) {
+				this.radio = e.detail.value
+			},
+			CheckboxChange(e) {
+				var items = this.checkbox,
+					values = e.detail.value;
+				for (var i = 0, lenI = items.length; i < lenI; ++i) {
+					items[i].checked = false;
+					for (var j = 0, lenJ = values.length; j < lenJ; ++j) {
+						if (items[i].value == values[j]) {
+							items[i].checked = true;
+							break
+						}
+					}
+				}
+			},
+			ChooseImage() {
+				uni.chooseImage({
+					count: 4, //默认9
+					sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
+					sourceType: ['album'], //从相册选择
+					success: (res) => {
+						uni.uploadFile(res)
+						console.log(res)
+						if (this.imgList.length != 0) {
+							this.imgList = this.imgList.concat(res.tempFilePaths)
+						} else {
+							this.imgList = res.tempFilePaths
+						}
+					}
+				});
+			},
+			ViewImage(e) {
+				uni.previewImage({
+					urls: this.imgList,
+					current: e.currentTarget.dataset.url
+				});
+			},
+			DelImg(e) {
+				uni.showModal({
+					title: '召唤师',
+					content: '确定要删除这段回忆吗?',
+					cancelText: '再看看',
+					confirmText: '再见',
+					success: res => {
+						if (res.confirm) {
+							this.imgList.splice(e.currentTarget.dataset.index, 1)
+						}
+					}
+				})
+			},
+			textareaAInput(e) {
+				this.textareaAValue = e.detail.value
+			},
+			textareaBInput(e) {
+				this.textareaBValue = e.detail.value
+			}
+		}
+	}
+</script>
+
+<style>
+	.cu-form-group .title {
+		min-width: calc(4em + 15px);
+	}
+</style>

+ 92 - 0
pages/component/home.vue

@@ -0,0 +1,92 @@
+<template name="components">
+	<view>
+		<scroll-view scroll-y class="page">
+			<image src="/static/componentBg.png" mode="widthFix" class="response"></image>
+			<view class="nav-list">
+				<navigator hover-class='none' :url="'/pages/component/' + item.name" class="nav-li" navigateTo :class="'bg-'+item.color"
+				 :style="[{animation: 'show ' + ((index+1)*0.2+1) + 's 1'}]" v-for="(item,index) in elements" :key="index">
+					<view class="nav-title">{{item.title}}</view>
+					<view class="nav-name">{{item.name}}</view>
+					<text :class="'cuIcon-' + item.cuIcon"></text>
+				</navigator>
+			</view>
+			<view class="cu-tabbar-height"></view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				elements: [{
+						title: '操作条',
+						name: 'bar',
+						color: 'purple',
+						cuIcon: 'vipcard'
+					},
+					{
+						title: '导航栏 ',
+						name: 'nav',
+						color: 'mauve',
+						cuIcon: 'formfill'
+					},
+					{
+						title: '列表',
+						name: 'list',
+						color: 'pink',
+						cuIcon: 'list'
+					},
+					{
+						title: '卡片',
+						name: 'card',
+						color: 'brown',
+						cuIcon: 'newsfill'
+					},
+					{
+						title: '表单',
+						name: 'form',
+						color: 'red',
+						cuIcon: 'formfill'
+					},
+					{
+						title: '时间轴',
+						name: 'timeline',
+						color: 'orange',
+						cuIcon: 'timefill'
+					},
+					{
+						title: '聊天',
+						name: 'chat',
+						color: 'green',
+						cuIcon: 'messagefill'
+					},
+					{
+						title: '轮播',
+						name: 'swiper',
+						color: 'olive',
+						cuIcon: 'album'
+					},
+					{
+						title: '模态框',
+						name: 'modal',
+						color: 'grey',
+						cuIcon: 'squarecheckfill'
+					},
+					{
+						title: '步骤条',
+						name: 'steps',
+						color: 'cyan',
+						cuIcon: 'roundcheckfill'
+					}
+				],
+			};
+		}
+	}
+</script>
+
+<style>
+	.page {
+		height: 100vh;
+	}
+</style>

+ 425 - 0
pages/component/list.vue

@@ -0,0 +1,425 @@
+<template>
+	<view>
+		<scroll-view :scroll-y="modalName==null" class="page" :class="modalName!=null?'show':''">
+			<cu-custom bgColor="bg-gradual-pink" :isBack="true">
+				<block slot="backText">返回</block>
+				<block slot="content">列表</block>
+			</cu-custom>
+			<view class="cu-bar bg-white solid-bottom margin-top">
+				<view class="action">
+					<text class="cuIcon-title text-orange "></text> 宫格列表
+				</view>
+				<view class="action">
+					<button class="cu-btn bg-green shadow" @tap="showModal" data-target="gridModal">设置</button>
+				</view>
+			</view>
+			<view class="cu-modal" :class="modalName=='gridModal'?'show':''" @tap="hideModal">
+				<view class="cu-dialog" @tap.stop>
+					<radio-group class="block" @change="Gridchange">
+						<view class="cu-list menu text-left">
+							<view class="cu-item" v-for="(item,index) in 3" :key="index">
+								<label class="flex justify-between align-center flex-sub">
+									<view class="flex-sub">{{index +3}} 列</view>
+									<radio class="round" :value="(index + 3) + ''" :class="gridCol==index+3?'checked':''" :checked="gridCol==index+3"></radio>
+								</label>
+							</view>
+						</view>
+					</radio-group>
+					<view class="cu-list menu text-left solid-top">
+						<view class="cu-item">
+							<view class="content">
+								<text class="text-grey">边框</text>
+							</view>
+							<view class="action">
+								<switch @change="Gridswitch" :class="gridBorder?'checked':''" :checked="gridBorder?true:false"></switch>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="cu-list grid" :class="['col-' + gridCol,gridBorder?'':'no-border']">
+				<view class="cu-item" v-for="(item,index) in cuIconList" :key="index" v-if="index<gridCol*2">
+					<view :class="['cuIcon-' + item.cuIcon,'text-' + item.color]">
+						<view class="cu-tag badge" v-if="item.badge!=0">
+							<block v-if="item.badge!=1">{{item.badge>99?'99+':item.badge}}</block>
+						</view>
+					</view>
+					<text>{{item.name}}</text>
+				</view>
+			</view>
+
+
+			<view class="cu-bar bg-white solid-bottom margin-top">
+				<view class="action">
+					<text class="cuIcon-title text-orange"></text> 菜单列表
+				</view>
+				<view class="action">
+					<button class="cu-btn bg-green shadow" @tap="showModal" data-target="menuModal">设置</button>
+				</view>
+			</view>
+			<view class="cu-modal" :class="modalName=='menuModal'?'show':''" @tap="hideModal">
+				<view class="cu-dialog" @tap.stop>
+					<view class="cu-list menu text-left solid-top">
+						<view class="cu-item">
+							<view class="content">
+								<text class="text-grey">短边框</text>
+							</view>
+							<view class="action">
+								<switch @change="MenuBorder" :class="menuBorder?'checked':''" :checked="menuBorder?true:false"></switch>
+							</view>
+						</view>
+						<view class="cu-item">
+							<view class="content">
+								<text class="text-grey">箭头</text>
+							</view>
+							<view class="action">
+								<switch @change="MenuArrow" :class="menuArrow?'checked':''" :checked="menuArrow?true:false"></switch>
+							</view>
+						</view>
+						<view class="cu-item">
+							<view class="content">
+								<text class="text-grey">卡片</text>
+							</view>
+							<view class="action">
+								<switch @change="MenuCard" :class="menuCard?'checked':''" :checked="menuCard?true:false"></switch>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="cu-list menu" :class="[menuBorder?'sm-border':'',menuCard?'card-menu margin-top':'']">
+				<view class="cu-item" :class="menuArrow?'arrow':''">
+					<view class="content">
+						<text class="cuIcon-circlefill text-grey"></text>
+						<text class="text-grey">图标 + 标题</text>
+					</view>
+				</view>
+				<view class="cu-item" :class="menuArrow?'arrow':''">
+					<view class="content">
+						<image src="/static/logo.png" class="png" mode="aspectFit"></image>
+						<text class="text-grey">图片 + 标题</text>
+					</view>
+				</view>
+				<view class="cu-item" :class="menuArrow?'arrow':''">
+					<button class="cu-btn content" open-type="contact">
+						<text class="cuIcon-btn text-olive"></text>
+						<text class="text-grey">Open-type 按钮</text>
+					</button>
+				</view>
+				<view class="cu-item" :class="menuArrow?'arrow':''">
+					<navigator class="content" hover-class="none" url="../list/list" open-type="redirect">
+						<text class="cuIcon-discoverfill text-orange"></text>
+						<text class="text-grey">Navigator 跳转</text>
+					</navigator>
+				</view>
+				<view class="cu-item" :class="menuArrow?'arrow':''">
+					<view class="content">
+						<text class="cuIcon-emojiflashfill text-pink"></text>
+						<text class="text-grey">头像组</text>
+					</view>
+					<view class="action">
+						<view class="cu-avatar-group">
+							<view class="cu-avatar round sm" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg);"></view>
+							<view class="cu-avatar round sm" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg);"></view>
+							<view class="cu-avatar round sm" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big25002.jpg);"></view>
+							<view class="cu-avatar round sm" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big91012.jpg);"></view>
+						</view>
+						<text class="text-grey text-sm">4 人</text>
+					</view>
+				</view>
+				<view class="cu-item" :class="menuArrow?'arrow':''">
+					<view class="content">
+						<text class="cuIcon-btn text-green"></text>
+						<text class="text-grey">按钮</text>
+					</view>
+					<view class="action">
+						<button class="cu-btn round bg-green shadow">
+							<text class="cuIcon-upload"></text> 上传</button>
+					</view>
+				</view>
+				<view class="cu-item" :class="menuArrow?'arrow':''">
+					<view class="content">
+						<text class="cuIcon-tagfill text-red  margin-right-xs"></text>
+						<text class="text-grey">标签</text>
+					</view>
+					<view class="action">
+						<view class="cu-tag round bg-orange light">音乐</view>
+						<view class="cu-tag round bg-olive light">电影</view>
+						<view class="cu-tag round bg-blue light">旅行</view>
+					</view>
+				</view>
+				<view class="cu-item" :class="menuArrow?'arrow':''">
+					<view class="content">
+						<text class="cuIcon-warn text-green"></text>
+						<text class="text-grey">文本</text>
+					</view>
+					<view class="action">
+						<text class="text-grey text-sm">小目标还没有实现!</text>
+					</view>
+				</view>
+				<view class="cu-item">
+					<view class="content padding-tb-sm">
+						<view>
+							<text class="cuIcon-clothesfill text-blue margin-right-xs"></text> 多行Item</view>
+						<view class="text-gray text-sm">
+							<text class="cuIcon-infofill margin-right-xs"></text> 小目标还没有实现!</view>
+					</view>
+					<view class="action">
+						<switch class="switch-sex" @change="SwitchSex" :class="skin?'checked':''" :checked="skin?true:false"></switch>
+					</view>
+				</view>
+			</view>
+
+			<view class="cu-bar bg-white solid-bottom margin-top">
+				<view class="action">
+					<text class="cuIcon-title text-orange "></text> 消息列表
+				</view>
+			</view>
+			<view class="cu-list menu-avatar">
+				<view class="cu-item">
+					<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg);"></view>
+					<view class="content">
+						<view class="text-grey">凯尔</view>
+						<view class="text-gray text-sm flex">
+							<view class="text-cut">
+								<text class="cuIcon-infofill text-red  margin-right-xs"></text>
+								我已天理为凭,踏入这片荒芜,不再受凡人的枷锁遏制。我已天理为凭,踏入这片荒芜,不再受凡人的枷锁遏制。
+							</view> </view>
+					</view>
+					<view class="action">
+						<view class="text-grey text-xs">22:20</view>
+						<view class="cu-tag round bg-grey sm">5</view>
+					</view>
+				</view>
+				<view class="cu-item">
+					<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/img/champion/Taric.png);">
+						<view class="cu-tag badge">99+</view>
+					</view>
+					<view class="content">
+						<view class="text-grey">
+							<view class="text-cut">瓦洛兰之盾-塔里克</view>
+							<view class="cu-tag round bg-orange sm">战士</view>
+						</view>
+						<view class="text-gray text-sm flex">
+							<view class="text-cut">
+								塔里克是保护者星灵,用超乎寻常的力量守护着符文之地的生命、仁爱以及万物之美。塔里克由于渎职而被放逐,离开了祖国德玛西亚,前去攀登巨神峰寻找救赎,但他找到的却是来自星界的更高层的召唤。现在的塔里克与古代巨神族的神力相融合,以瓦洛兰之盾的身份,永不疲倦地警惕着阴险狡诈的虚空腐化之力。
+							</view>
+						</view>
+					</view>
+					<view class="action">
+						<view class="text-grey text-xs">22:20</view>
+						<view class="cuIcon-notice_forbid_fill text-gray"></view>
+					</view>
+				</view>
+				<view class="cu-item ">
+					<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/img/champion/Morgana.png);"></view>
+					<view class="content">
+						<view class="text-pink"><view class="text-cut">莫甘娜</view></view>
+						<view class="text-gray text-sm flex"> <view class="text-cut">凯尔,你被自己的光芒变的盲目!</view></view>
+					</view>
+					<view class="action">
+						<view class="text-grey text-xs">22:20</view>
+						<view class="cu-tag round bg-red sm">5</view>
+					</view>
+				</view>
+				<view class="cu-item grayscale">
+					<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81007.jpg);"></view>
+					<view class="content">
+						<view><view class="text-cut">伊泽瑞尔</view>
+							<view class="cu-tag round bg-orange sm">断开连接...</view>
+						</view>
+						<view class="text-gray text-sm flex"> <view class="text-cut"> 等我回来一个打十个</view></view>
+					</view>
+					<view class="action">
+						<view class="text-grey text-xs">22:20</view>
+						<view class="cu-tag round bg-red sm">5</view>
+					</view>
+				</view>
+				<view class="cu-item cur">
+					<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81020.jpg);">
+						<view class="cu-tag badge"></view>
+					</view>
+					<view class="content">
+						<view>
+							<view class="text-cut">瓦罗兰大陆-睡衣守护者-新手保护营</view>
+							<view class="cu-tag round bg-orange sm">6人</view>
+						</view>
+						<view class="text-gray text-sm flex">
+							<view class="text-cut"> 伊泽瑞尔:<text class="cuIcon-locationfill text-orange margin-right-xs"></text> 传送中...</view></view>
+					</view>
+					<view class="action">
+						<view class="text-grey text-xs">22:20</view>
+						<view class="cuIcon-notice_forbid_fill text-gray"></view>
+					</view>
+				</view>
+			</view>
+			<view class="cu-bar bg-white solid-bottom margin-top">
+				<view class="action">
+					<text class="cuIcon-title text-orange "></text> 列表左滑
+				</view>
+			</view>
+			<view class="cu-list menu-avatar">
+				<view class="cu-item" :class="modalName=='move-box-'+ index?'move-cur':''" v-for="(item,index) in 4" :key="index"
+				 @touchstart="ListTouchStart" @touchmove="ListTouchMove" @touchend="ListTouchEnd" :data-target="'move-box-' + index">
+					<view class="cu-avatar round lg" :style="[{backgroundImage:'url(https://ossweb-img.qq.com/images/lol/web201310/skin/big2100'+ (index+2) +'.jpg)'}]"></view>
+					<view class="content">
+						<view class="text-grey">文晓港</view>
+						<view class="text-gray text-sm">
+							<text class="cuIcon-infofill text-red  margin-right-xs"></text> 消息未送达</view>
+					</view>
+					<view class="action">
+						<view class="text-grey text-xs">22:20</view>
+						<view class="cu-tag round bg-grey sm">5</view>
+					</view>
+					<view class="move">
+						<view class="bg-grey">置顶</view>
+						<view class="bg-red">删除</view>
+					</view>
+				</view>
+			</view>
+
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				cuIconList: [{
+					cuIcon: 'cardboardfill',
+					color: 'red',
+					badge: 120,
+					name: 'VR'
+				}, {
+					cuIcon: 'recordfill',
+					color: 'orange',
+					badge: 1,
+					name: '录像'
+				}, {
+					cuIcon: 'picfill',
+					color: 'yellow',
+					badge: 0,
+					name: '图像'
+				}, {
+					cuIcon: 'noticefill',
+					color: 'olive',
+					badge: 22,
+					name: '通知'
+				}, {
+					cuIcon: 'upstagefill',
+					color: 'cyan',
+					badge: 0,
+					name: '排行榜'
+				}, {
+					cuIcon: 'clothesfill',
+					color: 'blue',
+					badge: 0,
+					name: '皮肤'
+				}, {
+					cuIcon: 'discoverfill',
+					color: 'purple',
+					badge: 0,
+					name: '发现'
+				}, {
+					cuIcon: 'questionfill',
+					color: 'mauve',
+					badge: 0,
+					name: '帮助'
+				}, {
+					cuIcon: 'commandfill',
+					color: 'purple',
+					badge: 0,
+					name: '问答'
+				}, {
+					cuIcon: 'brandfill',
+					color: 'mauve',
+					badge: 0,
+					name: '版权'
+				}],
+				modalName: null,
+				gridCol: 3,
+				gridBorder: false,
+				menuBorder: false,
+				menuArrow: false,
+				menuCard: false,
+				skin: false,
+				listTouchStart: 0,
+				listTouchDirection: null,
+			};
+		},
+		methods: {
+			showModal(e) {
+				this.modalName = e.currentTarget.dataset.target
+			},
+			hideModal(e) {
+				this.modalName = null
+			},
+			Gridchange(e) {
+				this.gridCol = e.detail.value
+			},
+			Gridswitch(e) {
+				this.gridBorder = e.detail.value
+			},
+			MenuBorder(e) {
+				this.menuBorder = e.detail.value
+			},
+			MenuArrow(e) {
+				this.menuArrow = e.detail.value
+			},
+			MenuCard(e) {
+				this.menuCard = e.detail.value
+			},
+			SwitchSex(e) {
+				this.skin = e.detail.value
+			},
+
+			// ListTouch触摸开始
+			ListTouchStart(e) {
+				this.listTouchStart = e.touches[0].pageX
+			},
+
+			// ListTouch计算方向
+			ListTouchMove(e) {
+				this.listTouchDirection = e.touches[0].pageX - this.listTouchStart > 0 ? 'right' : 'left'
+			},
+
+			// ListTouch计算滚动
+			ListTouchEnd(e) {
+				if (this.listTouchDirection == 'left') {
+					this.modalName = e.currentTarget.dataset.target
+				} else {
+					this.modalName = null
+				}
+				this.listTouchDirection = null
+			}
+		}
+	}
+</script>
+
+<style>
+	.page {
+		height: 100Vh;
+		width: 100vw;
+	}
+
+	.page.show {
+		overflow: hidden;
+	}
+
+	.switch-sex::after {
+		content: "\e716";
+	}
+
+	.switch-sex::before {
+		content: "\e7a9";
+	}
+
+	.switch-music::after {
+		content: "\e66a";
+	}
+
+	.switch-music::before {
+		content: "\e6db";
+	}
+</style>

+ 279 - 0
pages/component/modal.vue

@@ -0,0 +1,279 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true">
+			<block slot="backText">返回</block>
+			<block slot="content">模态窗口</block>
+		</cu-custom>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange "></text> 普通窗口
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="showModal" data-target="Modal">Modal</button>
+			</view>
+		</view>
+		<view class="cu-modal" :class="modalName=='Modal'?'show':''">
+			<view class="cu-dialog">
+				<view class="cu-bar bg-white justify-end">
+					<view class="content">Modal标题</view>
+					<view class="action" @tap="hideModal">
+						<text class="cuIcon-close text-red"></text>
+					</view>
+				</view>
+				<view class="padding-xl">
+					Modal 内容。
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange "></text> 底部窗口
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="showModal" data-target="bottomModal">Bottom</button>
+			</view>
+		</view>
+		<view class="cu-modal bottom-modal" :class="modalName=='bottomModal'?'show':''">
+			<view class="cu-dialog">
+				<view class="cu-bar bg-white">
+					<view class="action text-green">确定</view>
+					<view class="action text-blue" @tap="hideModal">取消</view>
+				</view>
+				<view class="padding-xl">
+					Modal 内容。
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange "></text> 对话窗口
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="showModal" data-target="DialogModal1">Dialog</button>
+				<button class="cu-btn bg-blue shadow margin-left" @tap="showModal" data-target="DialogModal2">Dialog</button>
+			</view>
+		</view>
+		<view class="cu-modal" :class="modalName=='DialogModal1'?'show':''">
+			<view class="cu-dialog">
+				<view class="cu-bar bg-white justify-end">
+					<view class="content">Modal标题</view>
+					<view class="action" @tap="hideModal">
+						<text class="cuIcon-close text-red"></text>
+					</view>
+				</view>
+				<view class="padding-xl">
+					Modal 内容。
+				</view>
+				<view class="cu-bar bg-white justify-end">
+					<view class="action">
+						<button class="cu-btn line-green text-green" @tap="hideModal">取消</button>
+						<button class="cu-btn bg-green margin-left" @tap="hideModal">确定</button>
+
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-modal" :class="modalName=='DialogModal2'?'show':''">
+			<view class="cu-dialog">
+				<view class="cu-bar bg-white justify-end">
+					<view class="content">Modal标题</view>
+					<view class="action" @tap="hideModal">
+						<text class="cuIcon-close text-red"></text>
+					</view>
+				</view>
+				<view class="padding-xl">
+					Modal 内容。
+				</view>
+				<view class="cu-bar bg-white">
+					<view class="action margin-0 flex-sub text-green " @tap="hideModal">
+						<text class="cuIcon-moneybag"></text>微信支付</view>
+					<view class="action margin-0 flex-sub text-green solid-left" @tap="hideModal">取消</view>
+					<view class="action margin-0 flex-sub  solid-left" @tap="hideModal">确定</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange "></text> 图片窗口
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="showModal" data-target="Image">Image</button>
+			</view>
+		</view>
+
+		<view class="cu-modal" :class="modalName=='Image'?'show':''">
+			<view class="cu-dialog">
+				<view class="bg-img" style="background-image: url('https://ossweb-img.qq.com/images/lol/web201310/skin/big91012.jpg');height:200px;">
+					<view class="cu-bar justify-end text-white">
+						<view class="action" @tap="hideModal">
+							<text class="cuIcon-close "></text>
+						</view>
+					</view>
+				</view>
+				<view class="cu-bar bg-white">
+					<view class="action margin-0 flex-sub  solid-left" @tap="hideModal">我知道了</view>
+				</view>
+			</view>
+		</view>
+
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange "></text> 单选窗口
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="showModal" data-target="RadioModal">Radio</button>
+			</view>
+		</view>
+
+		<view class="cu-modal" :class="modalName=='RadioModal'?'show':''" @tap="hideModal">
+			<view class="cu-dialog" @tap.stop="">
+				<radio-group class="block" @change="RadioChange">
+					<view class="cu-list menu text-left">
+						<view class="cu-item" v-for="(item,index) in 5" :key="index">
+							<label class="flex justify-between align-center flex-sub">
+								<view class="flex-sub">Item {{index +1}}</view>
+								<radio class="round" :class="radio=='radio' + index?'checked':''" :checked="radio=='radio' + index?true:false"
+								 :value="'radio' + index"></radio>
+							</label>
+						</view>
+					</view>
+				</radio-group>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange "></text> 多选窗口
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="showModal" data-target="ChooseModal">Choose</button>
+			</view>
+		</view>
+		<view class="cu-modal bottom-modal" :class="modalName=='ChooseModal'?'show':''" @tap="hideModal">
+			<view class="cu-dialog" @tap.stop="">
+				<view class="cu-bar bg-white">
+					<view class="action text-blue" @tap="hideModal">取消</view>
+					<view class="action text-green" @tap="hideModal">确定</view>
+				</view>
+				<view class="grid col-3 padding-sm">
+					<view v-for="(item,index) in checkbox" class="padding-xs" :key="index">
+						<button class="cu-btn orange lg block" :class="item.checked?'bg-orange':'line-orange'" @tap="ChooseCheckbox"
+						 :data-value="item.value"> {{item.name}}
+							<view class="cu-tag sm round" :class="item.checked?'bg-white text-orange':'bg-orange'" v-if="item.hot">HOT</view>
+						</button>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange "></text> 侧边抽屉
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="showModal" data-target="DrawerModalL">Left</button>
+				<button class="cu-btn bg-blue shadow margin-left" @tap="showModal" data-target="DrawerModalR">Right</button>
+			</view>
+		</view>
+		<view class="cu-modal drawer-modal justify-start" :class="modalName=='DrawerModalL'?'show':''" @tap="hideModal">
+			<view class="cu-dialog basis-lg" @tap.stop="" :style="[{top:CustomBar+'px',height:'calc(100vh - ' + CustomBar + 'px)'}]">
+				<view class="cu-list menu text-left">
+					<view class="cu-item arrow" v-for="(item,index) in 5" :key="index">
+						<view class="content">
+							<view>Item {{index +1}}</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-modal drawer-modal justify-end" :class="modalName=='DrawerModalR'?'show':''" @tap="hideModal">
+			<view class="cu-dialog basis-lg" @tap.stop="" :style="[{top:CustomBar+'px',height:'calc(100vh - ' + CustomBar + 'px)'}]">
+				<view class="cu-list menu text-left">
+					<view class="cu-item arrow" v-for="(item,index) in 5" :key="index">
+						<view class="content">
+							<view>Item {{index +1}}</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				CustomBar: this.CustomBar,
+				modalName: null,
+				radio: 'radio1',
+				checkbox: [{
+					value: 0,
+					name: '10元',
+					checked: false,
+					hot: false,
+				}, {
+					value: 1,
+					name: '20元',
+					checked: true,
+					hot: false,
+				}, {
+					value: 2,
+					name: '30元',
+					checked: true,
+					hot: true,
+				}, {
+					value: 3,
+					name: '60元',
+					checked: false,
+					hot: true,
+				}, {
+					value: 4,
+					name: '80元',
+					checked: false,
+					hot: false,
+				}, {
+					value: 5,
+					name: '100元',
+					checked: false,
+					hot: false,
+				}]
+			};
+		},
+		methods: {
+			showModal(e) {
+				this.modalName = e.currentTarget.dataset.target
+			},
+			hideModal(e) {
+				this.modalName = null
+			},
+			RadioChange(e) {
+				this.radio = e.detail.value
+			},
+			ChooseCheckbox(e) {
+				let items = this.checkbox;
+				let values = e.currentTarget.dataset.value;
+				for (let i = 0, lenI = items.length; i < lenI; ++i) {
+					if (items[i].value == values) {
+						items[i].checked = !items[i].checked;
+						break
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<style>
+	button .cu-tag {
+		position: absolute;
+		top: 8upx;
+		right: 8upx;
+	}
+</style>

+ 90 - 0
pages/component/nav.vue

@@ -0,0 +1,90 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true"><block slot="backText">返回</block><block slot="content">导航栏</block></cu-custom>
+		<view v-for="(item,index) in 10" :key="index" v-if="index==TabCur" class="bg-grey padding margin text-center">
+			Tab{{index}}
+		</view>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 默认
+			</view>
+		</view>
+		<scroll-view scroll-x class="bg-white nav" scroll-with-animation :scroll-left="scrollLeft">
+			<view class="cu-item" :class="index==TabCur?'text-green cur':''" v-for="(item,index) in 10" :key="index" @tap="tabSelect" :data-id="index">
+				Tab{{index}}
+			</view>
+		</scroll-view>
+
+		<view class="cu-bar bg-white margin-top solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 居中
+			</view>
+		</view>
+		<scroll-view scroll-x class="bg-white nav text-center">
+			<view class="cu-item" :class="index==TabCur?'text-blue cur':''" v-for="(item,index) in 3" :key="index" @tap="tabSelect" :data-id="index">
+				Tab{{index}}
+			</view>
+		</scroll-view>
+
+		<view class="cu-bar bg-white margin-top solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 平分
+			</view>
+		</view>
+		<scroll-view scroll-x class="bg-white nav">
+			<view class="flex text-center">
+				<view class="cu-item flex-sub" :class="index==TabCur?'text-orange cur':''" v-for="(item,index) in 4" :key="index" @tap="tabSelect" :data-id="index">
+					Tab{{index}}
+				</view>
+			</view>
+		</scroll-view>
+		<view class="cu-bar bg-white margin-top solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 背景
+			</view>
+		</view>
+		<scroll-view scroll-x class="bg-red nav text-center">
+			<view class="cu-item" :class="index==TabCur?'text-white cur':''" v-for="(item,index) in 3" :key="index" @tap="tabSelect" :data-id="index">
+				Tab{{index}}
+			</view>
+		</scroll-view>
+		<view class="cu-bar bg-white margin-top solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 图标
+			</view>
+		</view>
+		<scroll-view scroll-x class="bg-green nav text-center">
+			<view class="cu-item" :class="0==TabCur?'text-white cur':''" @tap="tabSelect" data-id="0">
+				<text class="cuIcon-camerafill"></text> 数码
+			</view>
+			<view class="cu-item" :class="1==TabCur?'text-white cur':''" @tap="tabSelect" data-id="1">
+				<text class="cuIcon-upstagefill"></text> 排行榜
+			</view>
+			<view class="cu-item" :class="2==TabCur?'text-white cur':''" @tap="tabSelect" data-id="2">
+				<text class="cuIcon-clothesfill"></text> 皮肤
+			</view>
+		</scroll-view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				TabCur: 0,
+				scrollLeft: 0
+			};
+		},
+		methods: {
+			tabSelect(e) {
+				this.TabCur = e.currentTarget.dataset.id;
+				this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60
+			}
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 114 - 0
pages/component/steps.vue

@@ -0,0 +1,114 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true"><block slot="backText">返回</block><block slot="content">步骤条</block></cu-custom>
+		<view class="cu-bar bg-white solid-bottom">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 基本用法
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="BasicsSteps">下一步</button>
+			</view>
+		</view>
+		<view class="bg-white padding">
+			<view class="cu-steps">
+				<view class="cu-item" :class="index>basics?'':'text-red'" v-for="(item,index) in basicsList" :key="index">
+					<text :class="'cuIcon-' + item.cuIcon"></text> {{item.name}}
+				</view>
+			</view>
+		</view>
+
+		<view class="bg-white padding margin-top-xs">
+			<view class="cu-steps">
+				<view class="cu-item" :class="index>basics?'':'text-orange'" v-for="(item,index) in basicsList" :key="index">
+					<text :class="index>basics?'cuIcon-title':'cuIcon-' + item.cuIcon"></text> {{item.name}}
+				</view>
+			</view>
+		</view>
+
+		<view class="bg-white padding  margin-top-xs">
+			<view class="cu-steps steps-arrow">
+				<view class="cu-item" :class="index>basics?'':'text-blue'" v-for="(item,index) in basicsList" :key="index">
+					<text :class="'cuIcon-' + item.cuIcon"></text> {{item.name}}
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 数字完成
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="NumSteps">下一步</button>
+			</view>
+		</view>
+		<view class="bg-white padding">
+			<view class="cu-steps">
+				<view class="cu-item" :class="index>num?'':'text-blue'" v-for="(item,index) in numList" :key="index">
+					<text class="num" :class="index==2?'err':''" :data-index="index + 1"></text> {{item.name}}
+				</view>
+			</view>
+		</view>
+		<view class="cu-bar bg-white solid-bottom margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 多级显示
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-green shadow" @tap="ScrollSteps">下一步</button>
+			</view>
+		</view>
+		<scroll-view scroll-x class="bg-white padding response cu-steps steps-bottom" :scroll-into-view="'scroll-' + scroll"
+		 scroll-with-animation>
+			<view class="cu-item padding-lr-xl" :class="index>scroll?'':'text-blue'" v-for="(item,index) in 10" :key="index" :id="'scroll-' + index">
+				Level {{index + 1}} <text class="num" :data-index="index + 1"></text>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				basicsList: [{
+					cuIcon: 'usefullfill',
+					name: '开始'
+				}, {
+					cuIcon: 'radioboxfill',
+					name: '等待'
+				}, {
+					cuIcon: 'roundclosefill',
+					name: '错误'
+				}, {
+					cuIcon: 'roundcheckfill',
+					name: '完成'
+				}, ],
+				basics: 0,
+				numList: [{
+					name: '开始'
+				}, {
+					name: '等待'
+				}, {
+					name: '错误'
+				}, {
+					name: '完成'
+				}, ],
+				num: 0,
+				scroll: 0
+			};
+		},
+		methods: {
+			BasicsSteps() {
+				this.basics= this.basics == this.basicsList.length - 1 ? 0 : this.basics + 1				
+			},
+			NumSteps() {
+				this.num= this.num == this.numList.length - 1 ? 0 : this.num + 1				
+			},
+			ScrollSteps() {
+				this.scroll= this.scroll == 9 ? 0 : this.scroll + 1				
+			}
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 162 - 0
pages/component/swiper.vue

@@ -0,0 +1,162 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true"><block slot="backText">返回</block>
+			<block slot="content">轮播图</block>
+		</cu-custom>
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-pink"></text> 全屏限高轮播
+			</view>
+			<view class="action">
+				<switch @change="DotStyle" :class="dotStyle?'checked':''" :checked="dotStyle?true:false"></switch>
+			</view>
+		</view>
+		<swiper class="screen-swiper" :class="dotStyle?'square-dot':'round-dot'" :indicator-dots="true" :circular="true"
+		 :autoplay="true" interval="5000" duration="500">
+			<swiper-item v-for="(item,index) in swiperList" :key="index">
+				<image :src="item.url" mode="aspectFill" v-if="item.type=='image'"></image>
+				<video :src="item.url" autoplay loop muted :show-play-btn="false" :controls="false" objectFit="cover" v-if="item.type=='video'"></video>
+			</swiper-item>
+		</swiper>
+		<!-- #ifndef MP-ALIPAY -->
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-pink"></text> 卡片式轮播
+			</view>
+		</view>
+		<swiper class="card-swiper" :class="dotStyle?'square-dot':'round-dot'" :indicator-dots="true" :circular="true"
+		 :autoplay="true" interval="5000" duration="500" @change="cardSwiper" indicator-color="#8799a3"
+		 indicator-active-color="#0081ff">
+			<swiper-item v-for="(item,index) in swiperList" :key="index" :class="cardCur==index?'cur':''">
+				<view class="swiper-item">
+					<image :src="item.url" mode="aspectFill" v-if="item.type=='image'"></image>
+					<video :src="item.url" autoplay loop muted :show-play-btn="false" :controls="false" objectFit="cover" v-if="item.type=='video'"></video>
+				</view>
+			</swiper-item>
+		</swiper>
+		<view class="cu-bar bg-white margin-top">
+			<view class="action">
+				<text class="cuIcon-title text-pink"></text> 堆叠式轮播 
+			</view>
+		</view>
+		<view class="tower-swiper" @touchmove="TowerMove" @touchstart="TowerStart" @touchend="TowerEnd">
+			<view class="tower-item" :class="item.zIndex==1?'none':''" v-for="(item,index) in swiperList" :key="index" :style="[{'--index': item.zIndex,'--left':item.mLeft}]" :data-direction="direction">
+				<view class="swiper-item">
+					<image :src="item.url" mode="aspectFill" v-if="item.type=='image'"></image>
+					<video :src="item.url" autoplay loop muted :show-play-btn="false" :controls="false" objectFit="cover" v-if="item.type=='video'"></video>
+				</view>
+			</view>
+		</view>
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				cardCur: 0,
+				swiperList: [{
+					id: 0,
+					type: 'image',
+					url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big84000.jpg'
+				}, {
+					id: 1,
+					type: 'image',
+					url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big37006.jpg',
+				}, {
+					id: 2,
+					type: 'image',
+					url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big39000.jpg'
+				}, {
+					id: 3,
+					type: 'image',
+					url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg'
+				}, {
+					id: 4,
+					type: 'image',
+					url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big25011.jpg'
+				}, {
+					id: 5,
+					type: 'image',
+					url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big21016.jpg'
+				}, {
+					id: 6,
+					type: 'image',
+					url: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg'
+				}],
+				dotStyle: false,
+				towerStart: 0,
+				direction: ''
+			};
+		},
+		onLoad() {
+			this.TowerSwiper('swiperList');
+			// 初始化towerSwiper 传已有的数组名即可
+		},
+		methods: {
+			DotStyle(e) {
+				this.dotStyle = e.detail.value
+			},
+			// cardSwiper
+			cardSwiper(e) {
+				this.cardCur = e.detail.current
+			},
+			// towerSwiper
+			// 初始化towerSwiper
+			TowerSwiper(name) {
+				let list = this[name];
+				for (let i = 0; i < list.length; i++) {
+					list[i].zIndex = parseInt(list.length / 2) + 1 - Math.abs(i - parseInt(list.length / 2))
+					list[i].mLeft = i - parseInt(list.length / 2)
+				}
+				this.swiperList = list
+			},
+
+			// towerSwiper触摸开始
+			TowerStart(e) {
+				this.towerStart = e.touches[0].pageX
+			},
+
+			// towerSwiper计算方向
+			TowerMove(e) {
+				this.direction = e.touches[0].pageX - this.towerStart > 0 ? 'right' : 'left'
+			},
+
+			// towerSwiper计算滚动
+			TowerEnd(e) {
+				let direction = this.direction;
+				let list = this.swiperList;
+				if (direction == 'right') {
+					let mLeft = list[0].mLeft;
+					let zIndex = list[0].zIndex;
+					for (let i = 1; i < this.swiperList.length; i++) {
+						this.swiperList[i - 1].mLeft = this.swiperList[i].mLeft
+						this.swiperList[i - 1].zIndex = this.swiperList[i].zIndex
+					}
+					this.swiperList[list.length - 1].mLeft = mLeft;
+					this.swiperList[list.length - 1].zIndex = zIndex;
+				} else {
+					let mLeft = list[list.length - 1].mLeft;
+					let zIndex = list[list.length - 1].zIndex;
+					for (let i = this.swiperList.length - 1; i > 0; i--) {
+						this.swiperList[i].mLeft = this.swiperList[i - 1].mLeft
+						this.swiperList[i].zIndex = this.swiperList[i - 1].zIndex
+					}
+					this.swiperList[0].mLeft = mLeft;
+					this.swiperList[0].zIndex = zIndex;
+				}
+				this.direction = ""
+				this.swiperList = this.swiperList
+			},
+		}
+	}
+</script>
+
+<style>
+	.tower-swiper .tower-item {
+		transform: scale(calc(0.5 + var(--index) / 10));
+		margin-left: calc(var(--left) * 100upx - 150upx);
+		z-index: var(--index);
+	}
+</style>

+ 101 - 0
pages/component/timeline.vue

@@ -0,0 +1,101 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true"><block slot="backText">返回</block><block slot="content">时间轴</block></cu-custom>
+		<view class="cu-timeline">
+			<view class="cu-time">昨天</view>
+			<view class="cu-item cur cuIcon-noticefill">
+				<view class="content bg-green shadow-blur">
+					<text>22:22</text> 【广州市】快件已到达地球
+				</view>
+			</view>
+			<view class="cu-item text-red cuIcon-attentionforbidfill">
+				<view class="content bg-red shadow-blur">
+					这是第一次,我家的铲屎官走了这么久。久到足足有三天!!
+				</view>
+			</view>
+			<view class="cu-item text-grey cuIcon-evaluate_fill">
+				<view class="content bg-grey shadow-blur">
+					这是第一次,我家的铲屎官走了这么久。
+				</view>
+			</view>
+			<view class="cu-item text-blue">
+				<view class="bg-blue content">
+					<text>20:00</text> 【月球】快件已到达月球,准备发往地球
+				</view>
+				<view class="bg-cyan content">
+					<text>10:00</text> 【银河系】快件已到达银河系,准备发往月球
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-timeline">
+			<view class="cu-time">06-17</view>
+			<view class="cu-item">
+				<view class="content">
+					<text>01:30</text> 【喵星】 MX-12138 已揽收,准备发往银河系
+				</view>
+			</view>
+		</view>
+
+		<view class="cu-timeline">
+			<view class="cu-time">06-17</view>
+			<view class="cu-item">
+				<view class="content">
+					<view class="cu-capsule radius">
+						<view class="cu-tag bg-cyan">上午</view>
+						<view class="cu-tag line-cyan">10:00</view>
+					</view>
+					<view class="margin-top">这是第一次,我家的铲屎官走了这么久。久到足足有三天!! 在听到他的脚步声响在楼梯间的那一刻,我简直想要破门而出,对着他狠狠地吼上10分钟,然后再看心情要不要他进门。</view>
+				</view>
+			</view>
+			<view class="cu-item text-blue">
+				<view class="bg-blue shadow-blur content">
+					<view class="cu-list menu-avatar radius">
+						<view class="cu-item">
+							<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg);"></view>
+							<view class="content">
+								<view class="text-grey">文晓港</view>
+								<view class="text-gray text-sm">
+									<text class="cuIcon-infofill text-red"></text> 消息未送达</view>
+							</view>
+							<view class="action">
+								<view class="text-grey text-xs">22:20</view>
+								<view class="cu-tag round bg-grey sm">5</view>
+							</view>
+						</view>
+						<view class="cu-item">
+							<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg);">
+								<view class="cu-tag badge">99+</view>
+							</view>
+							<view class="content">
+								<view class="text-grey">文晓港
+									<view class="cu-tag round orange sm">SVIP</view>
+								</view>
+								<view class="text-gray text-sm">
+									<text class="cuIcon-redpacket_fill text-red"></text> 收到红包</view>
+							</view>
+							<view class="action">
+								<view class="text-grey text-xs">22:20</view>
+								<text class="cuIcon-notice_forbid_fill text-gray"></text>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+
+			};
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 208 - 0
pages/home/home.vue

@@ -0,0 +1,208 @@
+<template name="home">
+	<view>
+		<scroll-view>
+			<!-- 轮播 -->
+			<swiper class="screen-swiper square-dot"  :indicator-dots="true" :circular="true"
+			 :autoplay="true" interval="5000" duration="500" :style="[{animation: 'show 0.2s 1'}]">
+				<swiper-item v-for="(item,index) in swiperList" :key="index">
+					<image :src="item.url" mode="aspectFill" v-if="item.type=='image'"></image>
+					<video :src="item.url" autoplay loop muted :show-play-btn="false" :controls="false" objectFit="cover" v-if="item.type=='video'"></video>
+				</swiper-item>
+			</swiper>
+			<!-- 中部应用宫格 -->
+			<view class="bg-white"  :style="[{animation: 'show 0.4s 1'}]">
+				<view class="grid margin-bottom col-2 ">
+				  <navigator  v-for="(item,index) in middleApps" :key="index" :url="'/pages/home/' + item.name" class="nav-li" navigateTo
+					 :style="[{animation: 'show ' + ((index+1)*0.2+1) + 's 1'}]" hover-class="none">
+						<view class="flex align-center">
+							<image :src="'/static/home/'+item.icon"  mode="aspectFill" class="line2-icon"></image>
+							<view class="text-df">{{item.title}} <br/> <span class="text-light">{{item.text}}</span></view>
+						</view>
+					</navigator>	
+				</view>
+			</view>
+			<!-- 常用服务 -->
+			<view class="cu-bar bg-white solid-bottom"   :style="[{animation: 'show 0.6s 1'}]">
+				<view class="action">
+					<text class='cuIcon-title text-blue'></text>常用服务
+				</view>
+			</view>
+			<view class=" bg-white grid col-3 padding-sm">
+				<view class="padding-sm animation-slide-bottom" :style="[{animationDelay: (index + 1)*0.1 + 's'}]" v-for="(item,index) in usList" :key="index" @tap="goPage(item.page)">
+					<view class="padding radius text-center shadow-blur solid-right ">
+						<!-- <image :src="item.icon"  mode="aspectFill" class="line2-icon"></image> -->
+						<view class="cu-avatar lg " 
+						 :style="{background: 'url(' + item.icon + ') no-repeat',backgroundSize:'100upx 100upx'}">
+						   <view class="cu-tag badge" v-if="getTtemDotInfo(item)">{{getTtemDotInfo(item)}}</view>
+						</view>
+						<view class="text-lg margin-top">{{item.title}}</view>
+					</view>
+				</view>
+			</view>
+			
+			<!-- 其他服务 -->
+			<view class="cu-bar bg-white solid-bottom margin-top"  :style="[{animation: 'show 0.6s 1'}]">
+				<view class="action">
+					<text class='cuIcon-title text-yellow'></text>其他服务
+				</view>
+			</view>
+			<view class=" bg-white grid col-3 padding-sm">
+				<view class="padding-sm animation-slide-bottom" :style="[{animationDelay: (index + 1)*0.1 + 's'}]" v-for="(item,index) in osList" :key="index">
+					<view class="padding radius text-center shadow-blur solid-right ">
+						<view class="cu-avatar lg "  :style="{background: 'url(' + item.icon + ') no-repeat',backgroundSize:'100upx 100upx'}"><!-- <view class="cu-tag badge">99</view> --></view>
+						<view class="text-lg margin-top">{{item.title}}</view>
+					</view>
+				</view>
+			</view>
+			
+			<view class="cu-tabbar-height">
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import { us,os } from '@/common/util/work.js'
+	export default {
+		name: 'home',
+		props:{
+			cur:String,
+		},
+		watch: {
+			cur: {
+				immediate: true,
+				handler() {
+					console.log('watch',this.cur)
+				    this.initMenu()
+				},
+			},
+		},
+		data() {
+			return {
+			 swiperList: [
+				  {id:1,type: 'image',url: '/static/banner/banner1.png', link: ''},
+				  {id:2,type: 'image',url: '/static/banner/banner2.jpg', link: ''},
+				  {id:3,type: 'image',url: '/static/banner/banner3.jpg', link: ''},
+				  {id:4,type: 'image',url: '/static/banner/banner4.jpg', link: ''},
+				],
+				middleApps: [
+				  {icon: 'line2_icon1.png', title: '审批', 'text': '个人审批'},
+				  {icon: 'line2_icon2.png', title: '审批稿', 'text': '审批草稿箱'},
+				],
+				usList:us.data,
+				osList:os.data,
+				websock:'',
+				heartCheck:null,
+				lockReconnect:false,
+				msgCount:0,
+				dot:{
+				  mailHome:false
+				}
+			}
+		},
+		methods: {
+			initMenu(){
+				console.log("-----------home------------")
+			    this.initWebSocket();
+			    this.loadCount(0);
+			},
+			goPage(page){
+				if(!page){
+					return false;
+				}
+				if(page==='annotationList'){
+				  this.msgCount = 0
+				}
+				this.dot[page]=false
+				this.$router.push({name: page})
+			},
+			initWebSocket: function () {
+				// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
+				var userId = this.$store.getters.userid;
+				var url = this.$config.apiUrl.replace("https://","wss://").replace("http://","ws://")+"/websocket/"+userId;
+				console.log('websocket url>>'+url);
+				this.websock = new WebSocket(url);
+				this.websock.onopen = this.websocketOnopen;
+				this.websock.onerror = this.websocketOnerror;
+				this.websock.onmessage = this.websocketOnmessage;
+				this.websock.onclose = this.websocketOnclose;
+			},
+			websocketOnopen: function () {
+				console.log("WebSocket连接成功");
+				//心跳检测重置
+				//this.heartCheck.reset().start();
+			},
+			websocketOnerror: function () {
+				console.log("WebSocket连接发生错误");
+				this.reconnect();
+			},
+			websocketOnmessage: function (e) {
+				console.log("-----接收消息-------",e.data);
+				var data = eval("(" + e.data + ")"); //解析对象
+				if(data.cmd == "topic"){
+				  //系统通知
+				  this.loadCount('1')
+				}else if(data.cmd == "user"){
+				  //用户消息
+				  this.loadCount('2')
+				} else if(data.cmd == 'email'){
+				  this.loadEmailCount()
+				}
+		
+				//心跳检测重置
+				//this.heartCheck.reset().start();
+			},
+			websocketOnclose: function (e) {
+				console.log("connection closed (" + e.code + ")");
+				this.reconnect();
+			},
+			websocketSend(text) { // 数据发送
+				try {
+				  this.websock.send(text);
+				} catch (err) {
+				  console.log("send failed (" + err.code + ")");
+				}
+			},
+			reconnect() {
+				var that = this;
+				if(that.lockReconnect) return;
+				that.lockReconnect = true;
+				//没连接上会一直重连,设置延迟避免请求过多
+				setTimeout(function () {
+				  console.info("尝试重连...");
+				  that.initWebSocket();
+				  that.lockReconnect = false;
+				}, 5000);
+			},
+			loadCount(flag){
+				console.log("loadCount::flag",flag)
+				let url = '/sys/annountCement/listByUser';
+				this.$http.get(url).then(res=>{
+					console.log("res::",res)
+				  if(res.data.success){
+					let msg1Count = res.data.result.anntMsgTotal;
+					let msg2Count = res.data.result.sysMsgTotal;
+					this.msgCount = msg1Count + msg2Count
+					console.log("this.msgCount",this.msgCount)
+				  }
+				})
+			},
+			loadEmailCount(){
+				this.dot.mailHome = true
+			},
+			getTtemDotInfo(item){
+				if(item.page==='annotationList' && this.msgCount>0){
+				  return this.msgCount
+				}
+				return '';
+			}
+		}
+	}
+</script>
+
+<style>
+  .line2-icon {
+	width: 60px;
+	height: 60px;
+  }
+</style>

+ 47 - 0
pages/index/index.vue

@@ -0,0 +1,47 @@
+<template>
+	<view>
+		<home :cur="PageCur" v-if="PageCur=='home'" :key="commponent1Key"></home>
+		<people v-if="PageCur=='people'" :key="commponent2Key"></people>
+		<view class="cu-bar tabbar bg-white shadow foot">
+			<view :class="PageCur=='home'?'action text-green':'action text-gray'" @click="NavChange" data-cur="home">
+				<view class='cuIcon-homefill'></view>主页
+			</view>
+			<view :class="PageCur=='peoplelis'?'action text-green':'action text-gray'" @click="NavChange" data-cur="peoplelis">
+				<view class='cuIcon-peoplelist'></view>审批
+			</view>
+			<view :class="PageCur=='profile'?'action text-green':'action text-gray'" @click="NavChange" data-cur="profile">
+				<view class='cuIcon-profile'></view>发起
+			</view>
+			<view :class="PageCur=='people'?'action text-green':'action text-gray'" @click="NavChange" data-cur="people">
+				<view class='cuIcon-people'></view>个人
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+		return {
+				PageCur: 'home',
+				commponent1Key: 0,
+				commponent2Key: 0,
+			}
+		},
+		onLoad:function(){
+			this.PageCur='home'
+			++this.commponent1Key
+			++this.commponent2Key
+		},
+		methods: {
+			NavChange: function(e) {
+				this.PageCur = e.currentTarget.dataset.cur
+			}
+			
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 169 - 0
pages/login/login.vue

@@ -0,0 +1,169 @@
+ <template>
+    <view class="zai-box">
+        <scroll-view scroll-y class="page">
+            <view style="text-align: center;" :style="[{animation: 'show ' + 0.4+ 's 1'}]">
+				<image src="/static/login3.png" mode='aspectFit' class="zai-logo"></image>
+				<view class="zai-title">JEECG BOOT</view>
+			</view>
+            <view class="box padding-lr-xl login-paddingtop" :style="[{animation: 'show ' + 0.6+ 's 1'}]">
+
+                <view class="cu-form-group margin-top round shadow-blur">
+                    <view class="title">账号:</view>
+                    <input placeholder="请输入账号" name="input" v-model="userName"></input>
+                </view>
+                <view class="cu-form-group margin-top round">
+                    <view class="title">密码:</view>
+                    <input placeholder="请输入密码" name="input" type="password" v-model="password"></input>
+                </view>
+                <view class="padding  flex  flex-direction">
+                    <button class="cu-btn bg-green shadow-blur round lg" :loading="loading"
+                            @tap="onLogin"> {{loading ? "登录中...":"登 录"}}
+                    </button>
+                </view>
+				<!-- #ifdef APP-PLUS -->
+				<view class="padding flex flex-direction  text-center  ">
+						当前版本:{{version}}
+				</view>
+				<!-- #endif -->
+				
+            </view>
+        </scroll-view>
+		<!-- 登录加载弹窗 -->
+		<view class="cu-load load-modal" v-if="loading">
+			<!-- <view class="cuIcon-emojifill text-orange"></view> -->
+			<image src="/static/login3.png" mode="aspectFit"></image>
+			<view class="gray-text">登录中...</view>
+		</view>
+		<!-- <my-image-upload></my-image-upload>
+		<my-select></my-select> -->
+		<!-- <my-page></my-page> -->
+    </view>
+
+</template>
+
+<script>
+	import { ACCESS_TOKEN,USER_NAME,USER_INFO } from "@/common/util/constants"
+	import { mapActions } from "vuex"
+	import myImageUpload from "@/components/my-componets/my-image-upload.vue"
+	import mypage from "@/components/my-componets/my-page.vue"
+	import myselect from "@/components/my-componets/my-select.vue"
+	
+    export default {
+		components:{
+			'my-image-upload':myImageUpload,
+			'my-select':myselect
+		},
+        data() {
+            return {
+				loading: false,
+				userName: '',
+				password: '',
+				phoneNo: '',
+				smsCode: '',
+				showPassword: false, //是否显示明文
+				loginWay: 1, //1: 账密,2:验证码
+				smsCountDown: 0,
+				smsCountInterval: null,
+				toggleDelay: false,
+				version:''
+            };
+        },
+		onLoad:function(){
+			// #ifdef APP-PLUS
+			var that=this
+			plus.runtime.getProperty( plus.runtime.appid, function ( wgtinfo ) {
+					that.version=wgtinfo.version
+				} );
+			// #endif
+		},
+        methods: {
+			 ...mapActions([ "mLogin","PhoneLogin" ]),
+			
+			onLogin: function (){
+			        if(!this.userName || this.userName.length==0){
+			          this.$tip.toast('请填写用户名');
+			          return;
+			        }
+			        if(!this.password || this.password.length==0){
+			           this.$tip.toast('请填写密码');
+			          return;
+			        }
+			        let loginParams = {
+			          username:this.userName,
+			          password:this.password
+			        }
+					this.loading=true;
+			        this.mLogin(loginParams).then((res) => {
+					  console.log("mLogin",res)
+					  this.loading=false;
+			          if(res.data.success){
+						  this.$tip.success('登录成功!')
+						  this.$Router.replaceAll({name:'index'})
+						 /* uni.reLaunch({
+							url: '/pages/index/index'
+						  }); */
+			          }else{
+			              this.$tip.alert(res.data.message);
+			          }
+			        }).catch((err) => {
+			          let msg = err.data.message || "请求出现错误,请稍后再试"
+			          this.$tip.alert(msg);
+			        }).finally(()=>{
+					  this.loading=false;
+					})
+			      }
+        }
+    }
+</script>
+
+<style>
+    .login-paddingtop {
+        padding-top: 200 upx;
+    }
+
+    .zai-box {
+        padding: 0 20 upx;
+        padding-top: 100 upx;
+        position: relative;
+    }
+
+    .zai-logo {
+        width: 200upx;
+        height: 300 upx;
+    }
+
+    .zai-title {
+       font-size: 58upx;
+       color: #000000;
+       text-align: center;
+    }
+
+    .input-placeholder, .zai-input {
+        color: #94afce;
+    }
+
+    .zai-label {
+        padding: 60 upx 0;
+        text-align: center;
+        font-size: 30 upx;
+        color: #a7b6d0;
+    }
+
+    .zai-btn {
+        background: #ff65a3;
+        color: #fff;
+        border: 0;
+        border-radius: 100 upx;
+        font-size: 36 upx;
+    }
+
+    .zai-btn:after {
+        border: 0;
+    }
+
+    /*按钮点击效果*/
+    .zai-btn.button-hover {
+        transform: translate(1 upx, 1 upx);
+    }
+
+</style>

+ 145 - 0
pages/plugin/animation.vue

@@ -0,0 +1,145 @@
+<template>
+	<view>
+		<cu-custom bgImage="https://image.weilanwl.com/color2.0/plugin/wdh2236.jpg" :isBack="true"><block slot="backText">返回</block>
+			<block slot="content">微动画</block>
+		</cu-custom>
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 默认效果
+			</view>
+		</view>
+		<view class="padding-sm">
+			<view class="flex flex-wrap justify-around">
+				<button class="cu-btn margin-sm basis-sm shadow" :class="['bg-' + item.color,animation==item.name?'animation-' +item.name :'']"
+				 @tap="Toggle" :data-class="item.name" v-for="(item,index) in list" :key="index">{{item.name}}</button>
+			</view>
+		</view>
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 反向动画
+			</view>
+		</view>
+
+		<view class="padding-sm">
+			<view class="flex flex-wrap justify-around">
+				<button class="cu-btn animation-reverse margin-sm basis-sm shadow" :class="['bg-' + item.color,animation==item.name+'s'?'animation-' +item.name:'']"
+				 @tap="Toggle" :data-class="item.name+'s'" v-for="(item,index) in list" :key="index">{{item.name}}</button>
+			</view>
+		</view>
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> 延迟执行
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-cyan shadow" @tap="ToggleDelay">开始执行</button>
+			</view>
+		</view>
+
+		<view class="padding-sm">
+			<view class="flex flex-wrap justify-around">
+				<button class="margin-sm basis-sm shadow cu-btn" :class="['bg-' + item.color,toggleDelay?'animation-slide-bottom':'']"
+				 :style="[{animationDelay: (index + 1)*0.1 + 's'}]" v-for="(item,index) in list" :key="index">0.{{index+1}}s</button>
+			</view>
+		</view>
+		<view class="cu-bar bg-white">
+			<view class="action">
+				<text class="cuIcon-title text-orange"></text> Gif动画
+			</view>
+		</view>
+		<view class="margin radius bg-gradual-green shadow-blur">
+			<image src="https://image.weilanwl.com/gif/wave.gif" mode="scaleToFill" class="gif-black response" style="height:100upx"></image>
+		</view>
+		<view class="margin flex">
+			<view class="bg-black flex-sub margin-right radius shadow-lg">
+				<image src="https://image.weilanwl.com/gif/loading-black.gif" mode="aspectFit" class="gif-black response" style="height:240upx"></image>
+			</view>
+			<view class="bg-white flex-sub radius shadow-lg">
+				<image src="https://image.weilanwl.com/gif/loading-white.gif" mode="aspectFit" class="gif-white response" style="height:240upx"></image>
+			</view>
+		</view>
+		<view class="margin flex">
+			<view class="bg-gradual-blue flex-sub margin-right radius shadow-lg">
+				<image src="https://image.weilanwl.com/gif/rhomb-black.gif" mode="aspectFit" class="gif-black response" style="height:240upx"></image>
+			</view>
+			<view class="bg-white flex-sub radius shadow-lg">
+				<image src="https://image.weilanwl.com/gif/rhomb-white.gif" mode="aspectFit" class="gif-white response" style="height:240upx"></image>
+			</view>
+		</view>
+		<view class="margin flex">
+			<view class="bg-white flex-sub margin-right radius shadow-lg">
+				<image src="https://image.weilanwl.com/gif/loading-1.gif" mode="aspectFit" class="gif-white response" style="height:240upx"></image>
+			</view>
+			<view class="bg-black flex-sub radius shadow-lg">
+				<image src="https://image.weilanwl.com/gif/loading-2.gif" mode="aspectFit" class="gif-black response" style="height:240upx"></image>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				animation:'',
+				list: [{
+						name: 'fade',
+						color: 'red'
+					},
+					{
+						name: 'scale-up',
+						color: 'orange'
+					},
+					{
+						name: 'scale-down',
+						color: 'olive'
+					},
+					{
+						name: 'slide-top',
+						color: 'green'
+					}, {
+						name: 'slide-bottom',
+						color: 'cyan'
+					},
+					{
+						name: 'slide-left',
+						color: 'blue'
+					},
+					{
+						name: 'slide-right',
+						color: 'purple'
+					},
+					{
+						name: 'shake',
+						color: 'mauve'
+					}
+				],
+				toggleDelay: false
+
+			};
+		},
+		methods: {
+			Toggle(e) {
+				var anmiaton = e.currentTarget.dataset.class;
+				this.animation= anmiaton;
+				setTimeout(()=>{
+					this.animation= '';
+				}, 1000)
+			},
+			ToggleDelay() {
+				this.toggleDelay= true;
+				setTimeout(()=>{
+					this.toggleDelay= false
+				}, 1000)
+			}
+		},
+	}
+</script>
+
+<style>
+	@import "/plugin/colorui/animation.css";
+	
+	image[class*="gif-"] {
+		border-radius: 6upx;
+		display: block;
+	}
+</style>

+ 170 - 0
pages/plugin/drawer.vue

@@ -0,0 +1,170 @@
+<template>
+	<view class="bg-gradual-blue">
+		<scroll-view scroll-y class="DrawerPage" :class="modalName=='viewModal'?'show':''">
+			<cu-custom bgColor="bg-gradual-blue" :isBack="true"><block slot="backText">返回</block>
+				<block slot="content">全屏抽屉</block>
+			</cu-custom>			
+			<view class='padding margin text-center'>
+				<view class='cu-btn bg-green lg block shadow radius margin-xl' @tap="showModal" data-target="viewModal">
+					打开抽屉
+				</view>
+			</view>
+			<view class="cu-list menu card-menu margin-top-xl margin-bottom-xl shadow-lg">
+				<view class="cu-item arrow" v-for="(item,index) in 20" :key="index">
+					<view class="content">
+						<text class="cuIcon-github text-grey"></text>
+						<text class="text-grey">{{index +1}}</text>
+					</view>
+				</view>
+			</view>
+			
+			<view class='padding margin text-center'>
+				<view class='cu-btn bg-green lg block shadow radius margin-xl' @tap="showModal" data-target="viewModal">
+					打开抽屉
+				</view>
+			</view>
+		</scroll-view>
+		<view class="DrawerClose" :class="modalName=='viewModal'?'show':''" @tap="hideModal">
+			<text class="cuIcon-pullright"></text>
+		</view>
+		<scroll-view scroll-y class="DrawerWindow" :class="modalName=='viewModal'?'show':''">
+			<view class="cu-list menu card-menu margin-top-xl margin-bottom-xl shadow-lg">
+				<view class="cu-item arrow" v-for="(item,index) in 20" :key="index">
+					<view class="content">
+						<text class="cuIcon-github text-grey"></text>
+						<text class="text-grey">{{index +1}}</text>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				modalName:null
+			};
+		},
+		methods: {
+			showModal(e) {
+				this.modalName = e.currentTarget.dataset.target
+			},
+			hideModal(e) {
+				this.modalName = null
+			},
+			tabSelect(e) {
+				this.TabCur = e.currentTarget.dataset.id;
+				this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60
+			}
+		},
+	}
+</script>
+
+<style>
+	page {
+		background-image: var(--gradualBlue);
+		width: 100vw;
+		overflow: hidden;
+	}
+
+	.DrawerPage {
+		position: fixed;
+		width: 100vw;
+		height: 100vh;
+		left: 0vw;
+		background-color: #f1f1f1;
+		transition: all 0.4s;
+	}
+
+	.DrawerPage.show {
+		transform: scale(0.9, 0.9);
+		left: 85vw;
+		box-shadow: 0 0 60upx rgba(0, 0, 0, 0.2);
+		transform-origin: 0;
+	}
+
+	.DrawerWindow {
+		position: absolute;
+		width: 85vw;
+		height: 100vh;
+		left: 0;
+		top: 0;
+		transform: scale(0.9, 0.9) translateX(-100%);
+		opacity: 0;
+		pointer-events: none;
+		transition: all 0.4s;
+		padding: 100upx 0;
+	}
+
+	.DrawerWindow.show {
+		transform: scale(1, 1) translateX(0%);
+		opacity: 1;
+		pointer-events: all;
+	}
+
+	.DrawerClose {
+		position: absolute;
+		width: 40vw;
+		height: 100vh;
+		right: 0;
+		top: 0;
+		color: transparent;
+		padding-bottom: 30upx;
+		display: flex;
+		align-items: flex-end;
+		justify-content: center;
+		background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 0.6));
+		letter-spacing: 5px;
+		font-size: 50upx;
+		opacity: 0;
+		pointer-events: none;
+		transition: all 0.4s;
+	}
+
+	.DrawerClose.show {
+		opacity: 1;
+		pointer-events: all;
+		width: 15vw;
+		color: #fff;
+	}
+
+	.DrawerPage .cu-bar.tabbar .action button.cuIcon {
+		width: 64upx;
+		height: 64upx;
+		line-height: 64upx;
+		margin: 0;
+		display: inline-block;
+	}
+
+	.DrawerPage .cu-bar.tabbar .action .cu-avatar {
+		margin: 0;
+	}
+
+	.DrawerPage .nav {
+		flex: 1;
+	}
+
+	.DrawerPage .nav .cu-item.cur {
+		border-bottom: 0;
+		position: relative;
+	}
+
+	.DrawerPage .nav .cu-item.cur::after {
+		content: "";
+		width: 10upx;
+		height: 10upx;
+		background-color: currentColor;
+		position: absolute;
+		bottom: 10upx;
+		border-radius: 10upx;
+		left: 0;
+		right: 0;
+		margin: auto;
+	}
+
+	.DrawerPage .cu-bar.tabbar .action {
+		flex: initial;
+	}
+</style>

+ 103 - 0
pages/plugin/home.vue

@@ -0,0 +1,103 @@
+<template name="components">
+	<view>
+		<scroll-view scroll-y class="page">
+			<cu-custom bgImage="https://image.weilanwl.com/color2.0/plugin/cjkz2329.jpg">
+				<block slot="content">
+					<image src="/static/cjkz.png" mode="aspectFill" style="width: 240upx;height: 60upx;"></image>
+				</block>
+			</cu-custom>
+			<view class="cu-card">
+				<view class="cu-item bg-img shadow-blur" :style="[{backgroundImage:'url('+item.img+')'}]" @tap="toChild" :data-url="item.url"
+				 v-for="(item,index) in list" :key="index">
+					<view class="cardTitle">
+						{{item.title}}
+					</view>
+				</view>
+			</view>
+			<view class="cu-tabbar-height"></view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "components",
+		data() {
+			return {
+				StatusBar: this.StatusBar,
+				CustomBar: this.CustomBar,
+				list: [{
+						title: '索引列表',
+						img: 'https://image.weilanwl.com/color2.0/plugin/sylb2244.jpg',
+						url: '../plugin/indexes'
+					},
+					{
+						title: '微动画',
+						img: 'https://image.weilanwl.com/color2.0/plugin/wdh2236.jpg',
+						url: '../plugin/animation'
+					},
+					{
+						title: '全屏抽屉',
+						img: 'https://image.weilanwl.com/color2.0/plugin/qpct2148.jpg',
+						url: '../plugin/drawer'
+					},
+					{
+						title: '垂直导航',
+						img: 'https://image.weilanwl.com/color2.0/plugin/qpczdh2307.jpg',
+						url: '../plugin/verticalnav'
+					}
+				]
+			};
+		},
+		methods: {
+			toChild(e) {
+				uni.navigateTo({
+					url: e.currentTarget.dataset.url
+				})
+			},
+		},
+	}
+</script>
+
+<style>
+	.page {
+		height: 100vh;
+	}
+
+	.cardTitle {
+		color: #fff;
+		padding: 90upx 60upx;
+		font-size: 40upx;
+		font-weight: 300;
+		transform: skew(-10deg, 0deg);
+		position: relative;
+		text-shadow: 0px 0px 6upx rgba(0, 0, 0, 0.3)
+	}
+
+	.cardTitle::before {
+		content: "";
+		position: absolute;
+		width: 60upx;
+		height: 6upx;
+		border-radius: 20upx;
+		background-color: #fff;
+		display: block;
+		top: 60upx;
+		left: 50upx;
+		transform: skew(10deg, 0deg);
+	}
+
+	.cardTitle::after {
+		content: "";
+		position: absolute;
+		width: 140upx;
+		border-radius: 6upx;
+		height: 24upx;
+		background-color: #fff;
+		display: block;
+		bottom: 76upx;
+		left: 90upx;
+		transform: skew(10deg, 0deg);
+		opacity: 0.1;
+	}
+</style>

+ 197 - 0
pages/plugin/indexes.vue

@@ -0,0 +1,197 @@
+<template>
+	<view>
+		<cu-custom bgImage="https://image.weilanwl.com/color2.0/plugin/sylb2244.jpg" :isBack="true"><block slot="backText">返回</block>
+			<block slot="content">索引</block>
+		</cu-custom>
+		<view class="cu-bar bg-white search fixed" :style="[{top:CustomBar + 'px'}]">
+			<view class="search-form round">
+				<text class="cuIcon-search"></text>
+				<input type="text" placeholder="输入搜索的关键词" confirm-type="search"></input>
+			</view>
+			<view class="action">
+				<button class="cu-btn bg-gradual-green shadow-blur round">搜索</button>
+			</view>
+		</view>
+		<scroll-view scroll-y class="indexes" :scroll-into-view="'indexes-'+ listCurID" :style="[{height:'calc(100vh - '+ CustomBar + 'px - 50px)'}]"
+		 :scroll-with-animation="true" :enable-back-to-top="true">
+			<block v-for="(item,index) in list" :key="index">
+				<view :class="'indexItem-' + item.name" :id="'indexes-' + item.name" :data-index="item.name">
+					<view class="padding">{{item.name}}</view>
+					<view class="cu-list menu-avatar no-padding">
+						<view class="cu-item" v-for="(items,sub) in 2" :key="sub">
+							<view class="cu-avatar round lg">{{item.name}}</view>
+							<view class="content">
+								<view class="text-grey">{{item.name}}<text class="text-abc">{{list[sub].name}}</text>君</view>
+								<view class="text-gray text-sm">
+									有{{sub+2}}个主子需要伺候
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</block>
+		</scroll-view>
+		<view class="indexBar" :style="[{height:'calc(100vh - ' + CustomBar + 'px - 50px)'}]">
+			<view class="indexBar-box" @touchstart="tStart" @touchend="tEnd" @touchmove.stop="tMove">
+				<view class="indexBar-item" v-for="(item,index) in list" :key="index" :id="index" @touchstart="getCur" @touchend="setCur"> {{item.name}}</view>
+			</view>
+		</view>
+		<!--选择显示-->
+		<view v-show="!hidden" class="indexToast">
+			{{listCur}}
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				StatusBar: this.StatusBar,
+				CustomBar: this.CustomBar,
+				hidden: true,
+				listCurID: '',
+				list: [],
+				listCur: '',
+			};
+		},
+		onLoad() {
+			let list = [{}];
+			for (let i = 0; i < 26; i++) {
+				list[i] = {};
+				list[i].name = String.fromCharCode(65 + i);
+			}
+			this.list = list;
+			this.listCur = list[0];
+		},
+		onReady() {
+			let that = this;
+			uni.createSelectorQuery().select('.indexBar-box').boundingClientRect(function(res) {
+				that.boxTop = res.top
+			}).exec();
+			uni.createSelectorQuery().select('.indexes').boundingClientRect(function(res) {
+				that.barTop = res.top
+			}).exec()
+		},
+		methods: {
+			//获取文字信息
+			getCur(e) {
+				this.hidden = false;
+				this.listCur = this.list[e.target.id].name;
+			},
+			setCur(e) {
+				this.hidden = true;
+				this.listCur = this.listCur
+			},
+			//滑动选择Item
+			tMove(e) {
+				let y = e.touches[0].clientY,
+					offsettop = this.boxTop,
+					that = this;
+				//判断选择区域,只有在选择区才会生效
+				if (y > offsettop) {
+					let num = parseInt((y - offsettop) / 20);
+					this.listCur = that.list[num].name
+				};
+			},
+
+			//触发全部开始选择
+			tStart() {
+				this.hidden = false
+			},
+
+			//触发结束选择
+			tEnd() {
+				this.hidden = true;
+				this.listCurID = this.listCur
+			},
+			indexSelect(e) {
+				let that = this;
+				let barHeight = this.barHeight;
+				let list = this.list;
+				let scrollY = Math.ceil(list.length * e.detail.y / barHeight);
+				for (let i = 0; i < list.length; i++) {
+					if (scrollY < i + 1) {
+						that.listCur = list[i].name;
+						that.movableY = i * 20
+						return false
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<style>
+	page {
+		padding-top: 100upx;
+	}
+
+	.indexes {
+		position: relative;
+	}
+
+	.indexBar {
+		position: fixed;
+		right: 0px;
+		bottom: 0px;
+		padding: 20upx 20upx 20upx 60upx;
+		display: flex;
+		align-items: center;
+	}
+
+	.indexBar .indexBar-box {
+		width: 40upx;
+		height: auto;
+		background: #fff;
+		display: flex;
+		flex-direction: column;
+		box-shadow: 0 0 20upx rgba(0, 0, 0, 0.1);
+		border-radius: 10upx;
+	}
+
+	.indexBar-item {
+		flex: 1;
+		width: 40upx;
+		height: 40upx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		font-size: 24upx;
+		color: #888;
+	}
+
+	movable-view.indexBar-item {
+		width: 40upx;
+		height: 40upx;
+		z-index: 9;
+		position: relative;
+	}
+
+	movable-view.indexBar-item::before {
+		content: "";
+		display: block;
+		position: absolute;
+		left: 0;
+		top: 10upx;
+		height: 20upx;
+		width: 4upx;
+		background-color: #f37b1d;
+	}
+
+	.indexToast {
+		position: fixed;
+		top: 0;
+		right: 80upx;
+		bottom: 0;
+		background: rgba(0, 0, 0, 0.5);
+		width: 100upx;
+		height: 100upx;
+		border-radius: 10upx;
+		margin: auto;
+		color: #fff;
+		line-height: 100upx;
+		text-align: center;
+		font-size: 48upx;
+	}
+</style>

+ 226 - 0
pages/plugin/verticalnav.vue

@@ -0,0 +1,226 @@
+<template>
+	<view>
+		<view class="fixed">
+			<cu-custom :isBack="true" bgColor="bg-shadeTop text-white">
+				<block slot="backText">返回</block>
+				<block slot="content">垂直导航</block>
+			</cu-custom>
+		</view>
+		<swiper class="screen-swiper round-dot" :indicator-dots="true" :circular="true" :autoplay="true" interval="5000"
+		 duration="500">
+			<swiper-item v-for="(item,index) in 4" :key="index">
+				<image :src="'https://ossweb-img.qq.com/images/lol/web201310/skin/big3900'+index+ '.jpg'" mode="aspectFill"></image>
+			</swiper-item>
+		</swiper>
+		<view class="VerticalBox">
+			<scroll-view class="VerticalNav nav" scroll-y scroll-with-animation :scroll-top="verticalNavTop" style="height:calc(100vh - 375upx)">
+				<view class="cu-item" :class="index==tabCur?'text-green cur':''" v-for="(item,index) in list" :key="index" @tap="TabSelect"
+				 :data-id="index">
+					Tab-{{item.name}}
+				</view>
+			</scroll-view>
+			<scroll-view class="VerticalMain" scroll-y scroll-with-animation style="height:calc(100vh - 375upx)"
+			 :scroll-into-view="'main-'+mainCur" @scroll="VerticalMain">
+				<view class="padding-top padding-lr" v-for="(item,index) in list" :key="index" :id="'main-'+index">
+					<view class="cu-bar solid-bottom bg-white">
+						<view class="action">
+							<text class="cuIcon-title text-green"></text> Tab-{{item.name}}</view>
+					</view>
+					<view class="cu-list menu-avatar">
+						<view class="cu-item">
+							<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10001.jpg);"></view>
+							<view class="content">
+								<view class="text-grey">凯尔</view>
+								<view class="text-gray text-sm flex">
+									<text class="text-cut">
+										<text class="cuIcon-infofill text-red  margin-right-xs"></text>
+										我已天理为凭,踏入这片荒芜,不再受凡人的枷锁遏制。我已天理为凭,踏入这片荒芜,不再受凡人的枷锁遏制。
+									</text> </view>
+							</view>
+							<view class="action">
+								<view class="text-grey text-xs">22:20</view>
+								<view class="cu-tag round bg-grey sm">5</view>
+							</view>
+						</view>
+						<view class="cu-item">
+							<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/img/champion/Taric.png);">
+								<view class="cu-tag badge">99+</view>
+							</view>
+							<view class="content">
+								<view class="text-grey">
+									<text class="text-cut">瓦洛兰之盾-塔里克</text>
+									<view class="cu-tag round bg-orange sm">战士</view>
+								</view>
+								<view class="text-gray text-sm flex">
+									<text class="text-cut">
+										塔里克是保护者星灵,用超乎寻常的力量守护着符文之地的生命、仁爱以及万物之美。塔里克由于渎职而被放逐,离开了祖国德玛西亚,前去攀登巨神峰寻找救赎,但他找到的却是来自星界的更高层的召唤。现在的塔里克与古代巨神族的神力相融合,以瓦洛兰之盾的身份,永不疲倦地警惕着阴险狡诈的虚空腐化之力。
+									</text>
+								</view>
+							</view>
+							<view class="action">
+								<view class="text-grey text-xs">22:20</view>
+								<view class="cuIcon-notice_forbid_fill text-gray"></view>
+							</view>
+						</view>
+						<view class="cu-item ">
+							<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/img/champion/Morgana.png);"></view>
+							<view class="content">
+								<view class="text-pink"><text class="text-cut">莫甘娜</text></view>
+								<view class="text-gray text-sm flex"> <text class="text-cut">凯尔,你被自己的光芒变的盲目!</text></view>
+							</view>
+							<view class="action">
+								<view class="text-grey text-xs">22:20</view>
+								<view class="cu-tag round bg-red sm">5</view>
+							</view>
+						</view>
+						<view class="cu-item grayscale">
+							<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81007.jpg);"></view>
+							<view class="content">
+								<view><text class="text-cut">伊泽瑞尔</text>
+									<view class="cu-tag round bg-orange sm">断开连接...</view>
+								</view>
+								<view class="text-gray text-sm flex"> <text class="text-cut"> 等我回来一个打十个</text></view>
+							</view>
+							<view class="action">
+								<view class="text-grey text-xs">22:20</view>
+								<view class="cu-tag round bg-red sm">5</view>
+							</view>
+						</view>
+						<view class="cu-item cur">
+							<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81020.jpg);">
+								<view class="cu-tag badge"></view>
+							</view>
+							<view class="content">
+								<view>
+									<text class="text-cut">瓦罗兰大陆-睡衣守护者-新手保护营</text>
+									<view class="cu-tag round bg-orange sm">6人</view>
+								</view>
+								<view class="text-gray text-sm flex">
+									<text class="text-cut"> 伊泽瑞尔:<text class="cuIcon-locationfill text-orange margin-right-xs"></text> 传送中...</text></view>
+							</view>
+							<view class="action">
+								<view class="text-grey text-xs">22:20</view>
+								<view class="cuIcon-notice_forbid_fill text-gray"></view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				list: [],
+				tabCur: 0,
+				mainCur: 0,
+				verticalNavTop: 0,
+				load: true
+			};
+		},
+		onLoad() {
+			uni.showLoading({
+				title: '加载中...',
+				mask: true
+			});
+			let list = [{}];
+			for (let i = 0; i < 26; i++) {
+				list[i] = {};
+				list[i].name = String.fromCharCode(65 + i);
+				list[i].id = i;
+			}
+			this.list = list;
+			this.listCur = list[0];
+		},
+		onReady() {
+			uni.hideLoading()
+		},
+		methods: {
+			TabSelect(e) {
+				this.tabCur = e.currentTarget.dataset.id;
+				this.mainCur = e.currentTarget.dataset.id;
+				this.verticalNavTop = (e.currentTarget.dataset.id - 1) * 50
+			},
+			VerticalMain(e) {
+				// #ifdef MP-ALIPAY
+				   return false  //支付宝小程序暂时不支持双向联动 
+				// #endif
+				let that = this;
+				let tabHeight = 0;
+				if (this.load) {
+					for (let i = 0; i < this.list.length; i++) {
+						let view = uni.createSelectorQuery().select("#main-" + this.list[i].id);
+						view.fields({
+							size: true
+						}, data => {
+							this.list[i].top = tabHeight;
+							tabHeight = tabHeight + data.height;
+							this.list[i].bottom = tabHeight;
+						}).exec();
+					}
+					this.load = false
+				}
+				let scrollTop = e.detail.scrollTop + 10;
+				for (let i = 0; i < this.list.length; i++) {
+					if (scrollTop > this.list[i].top && scrollTop < this.list[i].bottom) {
+						this.verticalNavTop = (this.list[i].id - 1) * 50
+						this.tabCur = this.list[i].id
+						console.log(scrollTop)
+						return false
+					}
+				}
+			}
+		},
+	}
+</script>
+
+<style>
+	.fixed {
+		position: fixed;
+		z-index: 99;
+	}
+
+	.VerticalNav.nav {
+		width: 200upx;
+		white-space: initial;
+	}
+
+	.VerticalNav.nav .cu-item {
+		width: 100%;
+		text-align: center;
+		background-color: #fff;
+		margin: 0;
+		border: none;
+		height: 50px;
+		position: relative;
+	}
+
+	.VerticalNav.nav .cu-item.cur {
+		background-color: #f1f1f1;
+	}
+
+	.VerticalNav.nav .cu-item.cur::after {
+		content: "";
+		width: 8upx;
+		height: 30upx;
+		border-radius: 10upx 0 0 10upx;
+		position: absolute;
+		background-color: currentColor;
+		top: 0;
+		right: 0upx;
+		bottom: 0;
+		margin: auto;
+	}
+
+	.VerticalBox {
+		display: flex;
+	}
+
+	.VerticalMain {
+		background-color: #f1f1f1;
+		flex: 1;
+	}
+</style>

+ 167 - 0
pages/user/people.vue

@@ -0,0 +1,167 @@
+<template>
+	<view>
+		<scroll-view scroll-y class="page">
+			  <!-- 头部logo-->
+		  <view class="UCenter-bg" @click="remove">
+		    <image :src="personalList.avatar" round class="png animation-slide-right margin-bottom-sm" mode="widthFix" :style="[{animationDelay: '0.1s'}]"></image>
+		    <view class="text-xl animation-slide-left" :style="[{animationDelay: '0.2s'}]">
+		       {{personalList.depart}}
+		    </view>
+		    <image src="/static/wave.gif" mode="scaleToFill" class="gif-wave"></image>
+		  </view>
+		   <!-- 个人信息卡片-->
+		  <!-- <view class="cu-list menu-avatar">
+		   	<view class="cu-item">
+		   		<view class="cu-avatar round lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big10006.jpg);"></view>
+		   		<view class="content flex-sub">
+		   			<view class="text-grey">{{personalList.avatar}}</view>
+		   			<view class="text-gray text-sm flex justify-between">
+		   				经理
+		   			</view>
+		   		</view>
+		   	</view>
+		   </view> -->
+		  <view class="padding flex text-center text-grey bg-white shadow-warp">
+		    <view class="flex flex-sub flex-direction solid-right animation-slide-top" :style="[{animationDelay: '0.2s'}]">
+		      <view class="text-xl text-orange">{{personalList.username}}</view>
+			  <view class="margin-top-sm"><text class="cuIcon-people"></text> 用户</view>
+		    </view>
+		    
+		    <view class="flex flex-sub flex-direction animation-slide-top" :style="[{animationDelay: '0.2s'}]">
+		      <view class="text-xl text-green">{{personalList.post?personalList.post:'员工'}}</view>
+		      <view class="margin-top-sm"><text class="cuIcon-news"></text> 职务</view>
+		    </view>
+		  </view>
+		  <!-- 列表list-->
+		  <view class="cu-list menu card-menu margin-top-xl margin-bottom-xl shadow-lg radius">
+		    <view class="cu-item arrow animation-slide-bottom" :style="[{animationDelay: '0.1s'}]">
+		      <view class="content" >
+		        <text class="cuIcon-favorfill text-yellow"></text>
+		        <text class="text-grey">收藏</text>
+		      </view>
+		    </view>
+		    <view class="cu-item arrow animation-slide-bottom" :style="[{animationDelay: '0.3s'}]">
+		      <view class="content">
+		        <text class="cuIcon-redpacket_fill text-red"></text>
+		        <text class="text-grey">红包</text>
+		      </view>
+		    </view>
+		    <view class="cu-item arrow animation-slide-bottom" :style="[{animationDelay: '0.5s'}]">
+				<navigator class="content" url="/pages/user/userdetail" hover-class="none">
+				    <text class="cuIcon-settingsfill text-cyan"></text>
+					<text class="text-grey">设置</text>
+				</navigator>
+		    </view>
+			<view class="cu-item arrow animation-slide-bottom" :style="[{animationDelay: '0.7s'}]">
+				<navigator class="content" url="/pages/user/userexit" hover-class="none">
+				    <text class="cuIcon-exit text-cyan"></text>
+					<text class="text-grey">退出</text>
+				</navigator>
+			</view>
+		  </view>
+		  <view class="cu-tabbar-height"></view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import api from '@/api/api'
+	export default {
+		name: "people",
+		data() {
+			return {
+				personalList:{
+				  avatar:'',
+				  realname:'',
+				  username:'',
+				  post:''
+				},
+				  positionUrl:'/sys/position/list',
+				  departUrl:'/sys/user/userDepartList',
+				  userUrl:'/sys/user/queryById',
+				  userId:'',
+				  id:''
+			};
+		},
+		watch: {
+			cur: {
+				immediate: true,
+				handler() {
+					console.log('watch',this.cur)
+				    this.load()
+				},
+			},
+		},
+		methods: {
+			remove(){
+				 uni.removeStorageSync('Access-Token')
+			},
+			load(){
+				this.$http.get(this.userUrl,{params:{id:this.$store.getters.userid}}).then(res=>{
+					console.log("res",res)
+					 if (res.data.success) {
+						let perArr = res.data.result
+				        let avatar=(perArr.avatar && perArr.avatar.length > 0)? api.getFileAccessHttpUrl(perArr.avatar):'/static/avatar_boy.png'
+						this.personalList.avatar =avatar
+						this.personalList.realname = perArr.realname
+						this.personalList.username = perArr.username
+						this.personalList.post = perArr.post
+						this.personalList.depart = perArr.departIds
+					}
+				}).catch(err => {
+					console.log(err);
+				});
+				
+			}		
+		}
+	}
+</script>
+
+<style>
+.UCenter-bg {
+  background-image: url(https://image.weilanwl.com/color2.0/index.jpg);
+  background-size: cover;
+  height: 400rpx;
+  display: flex;
+  justify-content: center;
+  padding-top: 40rpx;
+  overflow: hidden;
+  position: relative;
+  flex-direction: column;
+  align-items: center;
+  color: #fff;
+  font-weight: 300;
+  text-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
+}
+
+.UCenter-bg text {
+  opacity: 0.8;
+}
+
+.UCenter-bg image {
+  width: 200rpx;
+  height: 200rpx;
+}
+
+.UCenter-bg .gif-wave{
+  position: absolute;
+  width: 100%;
+  bottom: 0;
+  left: 0;
+  z-index: 99;
+  mix-blend-mode: screen;  
+  height: 100rpx;   
+}
+
+map,.mapBox{
+  left: 0;
+  z-index: 99;
+  mix-blend-mode: screen;  
+  height: 100rpx;   
+}
+
+map,.mapBox{
+  width: 750rpx;
+  height: 300rpx;
+}
+</style>

+ 39 - 0
pages/user/user.vue

@@ -0,0 +1,39 @@
+<template name="user">
+	<view>
+		<scroll-view scroll-y class="page">
+			<image src="/static/componentBg.png " mode="widthFix" class="response"></image>
+			<view class="nav-list">
+				<navigator hover-class="none" :url="'/pages/common/' + item.name" class="nav-li" navigateTo :class="'bg-'+item.color"
+				 :style="[{animation: 'show ' + ((index+1)*0.2+1) + 's 1'}]" v-for="(item,index) in elements" :key="index">
+					<view class="nav-title">{{item.title}}</view>
+					<view class="nav-name">{{item.name}}</view>
+					<text :class="'cuIcon-' + item.cuIcon"></text>
+				</navigator>
+			</view>
+			<view class="cu-tabbar-height"></view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'user',
+		data() {
+			return {
+				elements: [{
+						title: '退出',
+						name: 'exit',
+						color: 'cyan',
+						cuIcon: 'newsfill',
+						auth: 'ac'
+					}
+				],
+			}
+		},
+		methods: {}
+	}
+</script>
+
+<style>
+
+</style>

+ 258 - 0
pages/user/userdetail.vue

@@ -0,0 +1,258 @@
+<template>
+	<view>
+		<scroll-view scroll-y class="page">
+			<cu-custom bgColor="bg-gradual-pink" :isBack="true">
+				<block slot="backText">返回</block>
+				<block slot="content">用户详情</block>
+				<view slot="right"  @tap="rightClick">编辑</view>
+			</cu-custom>
+			<!-- list列表 -->
+			<view class="cu-list menu">
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.1s'}]">
+					<view class="content">
+						<text class="text-grey">头像</text>
+					</view>
+					<view class="action">
+						<view class="cu-avatar round sm" :style="{backgroundImage: 'url(' + personalMsg.avatar + ')'}"></view>
+					</view>
+				
+				</view>
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.2s'}]">
+					<view class="content">
+						<text class="text-grey">姓名</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.realname}}</text>
+					</view>
+				</view>
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.3s'}]">
+					<view class="content">
+						<text class="text-grey">性别</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.sex}}</text>
+					</view>
+				</view>
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.4s'}]">
+					<view class="content">
+						<text class="text-grey">生日</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.birthday}}</text>
+					</view>
+				</view>
+			</view>
+			
+			<view class="cu-list menu">
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.5s'}]">
+					<view class="content">
+						<text class="text-grey">对外信息展示</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{getSubStringText(personalMsg.realname+'@'+personalMsg.orgCode,11)}}</text>
+					</view>
+				</view>
+			</view>
+			
+			<view class="cu-list menu">
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.6s'}]">
+					<view class="content">
+						<text class="text-grey">所在部门</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.orgCode}}</text>
+					</view>
+				</view>
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.7s'}]">
+					<view class="content">
+						<text class="text-grey">工号</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.workNo}}</text>
+					</view>
+				</view>
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.8s'}]">
+					<view class="content">
+						<text class="text-grey">状态</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.status}}</text>
+					</view>
+				</view>
+			</view>
+			
+			<view class="cu-list menu">
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '0.9s'}]">
+					<view class="content">
+						<text class="text-grey">手机</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.phone}}</text>
+					</view>
+				</view>
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '1s'}]">
+					<view class="content">
+						<text class="text-grey">邮箱</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.email}}</text>
+					</view>
+				</view>
+			</view>
+			
+			<view class="cu-list menu">
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '1.1s'}]">
+					<view class="content">
+						<text class="text-grey">职务</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.post}}</text>
+					</view>
+				</view>
+				<view class="cu-item animation-slide-bottom" :style="[{animationDelay: '1.2s'}]">
+					<view class="content">
+						<text class="text-grey">身份</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.identity}}</text>
+					</view>
+				</view>
+				<view class="cu-item animation-slide-bottom" v-if="personalMsg.identity =='上级'" >
+					<view class="content">
+						<text class="text-grey">负责部门</text>
+					</view>
+					<view class="action">
+						<text class="text-grey">{{personalMsg.departIds}}</text>
+					</view>
+				</view>
+			</view>
+
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import api from '@/api/api.js'
+	export default {
+		data() {
+			return {
+				 personalMsg:{
+					avatar:'',
+					realname:'',
+					username:'',
+					sex:1,
+					birthday:new Date(),
+					orgCode:'',
+					workNo:'',
+					status:1,
+					phone:'',
+					telephone:'',
+					email:'',
+					post:'',
+					departIds:'',
+					identity:'',
+				},
+				userUrl:'/sys/user/queryById',
+				positionUrl:'/sys/position/list',
+				departUrl:'/sys/user/userDepartList'
+			};
+		},
+		onLoad() {
+			this.loadinfo()
+		},
+		methods: {
+			getSubStringText(text,len){
+				if(!text || text.length==0){
+					return ''
+				}
+				if(text.length<len){
+					return text;
+				}
+				return text.substr(0,len)+"..."
+			},
+			rightClick(){
+				this.$Router.push({name:'useredit', params:this.personalMsg})
+				/* uni.navigateTo({
+				    url: '/pages/user/useredit?item='+item
+				}); */
+			},
+			loadinfo(){
+				this.$http.get(this.userUrl,{params:{id:this.$store.getters.userid}}).then(res=> {
+					console.log("用户",res)
+					if (res.data.success) {
+						let result = res.data.result
+						if(result.avatar&&result.avatar.length >0)
+						this.personalMsg.avatar = api.getFileAccessHttpUrl(result.avatar)
+						this.personalMsg.realname = result.realname
+						this.personalMsg.username= result.username
+						this.personalMsg.post = result.post
+						this.personalMsg.sex = result.sex===1?'男':'女'
+						this.personalMsg.birthday = result.birthday== null?'无':result.birthday
+						this.personalMsg.departIds= result.departIds
+						this.personalMsg.workNo= result.workNo
+						this.personalMsg.phone= result.phone
+						this.personalMsg.telephone= result.telephone== null?'无':result.telephone
+						this.personalMsg.email= result.email
+						this.personalMsg.post= result.post
+						this.personalMsg.identity= result.identity=== 1?'普通成员':'上级'
+						this.personalMsg.status= result.status === 1?'正常':'冻结'
+						this.personalMsg.orgCode= result.orgCode
+					}
+				}).catch(e=>{
+					console.log("请求错误",e)
+				})
+				
+				this.$http.get(this.departUrl,{params:{userId:this.$store.getters.userid}}).then(res=> {
+					if (res.success) {
+						for (let item of res.result){
+							this.personalMsg.orgCode = item.title
+							this.personalMsg.departIds = item.title
+						}
+					}
+				}).catch(e=>{
+					console.log("请求错误",e)
+				})
+				
+				this.$http.get(this.positionUrl).then(res=> {
+					if (res.success) {
+						let postArr = res.result.records
+						for (let item of postArr ){
+							if (this.personalMsg.post == item.code){
+								this.personalMsg.post = item.name
+							}
+						}
+					}
+				}).catch(e=>{
+					console.log("请求错误",e)
+				})
+			},
+		}
+	}
+</script>
+
+<style>
+	.page {
+		height: 100Vh;
+		width: 100vw;
+	}
+
+	.page.show {
+		overflow: hidden;
+	}
+
+	.switch-sex::after {
+		content: "\e716";
+	}
+
+	.switch-sex::before {
+		content: "\e7a9";
+	}
+
+	.switch-music::after {
+		content: "\e66a";
+	}
+
+	.switch-music::before {
+		content: "\e6db";
+	}
+</style>

+ 229 - 0
pages/user/useredit.vue

@@ -0,0 +1,229 @@
+<template>
+	<view>
+		<cu-custom bgColor="bg-gradual-pink" :isBack="true">
+			<block slot="backText">返回</block>
+			<block slot="content">编辑资料</block>
+		</cu-custom>
+		<form>
+			<view class="cu-form-group">
+				<view class="title">姓名</view>
+				<input placeholder="请输入姓名" name="input" v-model="myFormData.realname"></input>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">用户名</view>
+				<input placeholder="用户名" name="input" v-model="myFormData.username" disabled></input>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">头像</view>
+				<view class="grid col-4 grid-square flex-sub">
+					<view class="bg-img" v-for="(item,index) in imgList" :key="index" @tap="ViewImage" :data-url="imgList[index]">
+					 <image :src="imgList[index]" mode="aspectFill"></image>
+						<view class="cu-tag bg-red radius" @tap.stop="DelImg" :data-index="index">
+							<text class='cuIcon-close'></text>
+						</view>
+					</view>
+					<view class="solids" @tap="ChooseImage" v-if="imgList.length<1">
+						<text class='cuIcon-cameraadd'></text>
+					</view>
+				</view>
+			</view>
+			
+			<view class="cu-form-group margin-top">
+				<view class="title">性别</view>
+				<switch class='switch-sex' @change="SwitchC" :class="switchC?'checked':''" :checked="switchC?true:false"></switch>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">生日</view>
+				<picker mode="date" :value="myFormData.birthday" @change="DateChange">
+					<view class="picker">
+						{{myFormData.birthday}}
+					</view>
+				</picker>
+			</view>
+			
+			<view class="cu-form-group margin-top">
+				<view class="title">所在部门</view>
+				<input placeholder="所在部门" name="input" v-model="myFormData.orgCode" disabled></input>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">工号</view>
+				<input placeholder="工号" name="input"  v-model="myFormData.workNo" disabled></input>
+			</view>
+			
+			<view class="cu-form-group margin-top">
+				<view class="title">手机号码</view>
+				<input placeholder="输入手机号码" name="input" v-model="myFormData.phone"></input>
+				<view class="cu-capsule radius">
+					<view class='cu-tag bg-blue '>
+						+86
+					</view>
+					<view class="cu-tag line-blue">
+						中国大陆
+					</view>
+				</view>
+			</view>
+			<view class="cu-form-group">
+				<view class="title">邮箱</view>
+				<input placeholder="输入邮箱" name="input"  v-model="myFormData.email"></input>
+			</view>
+			<view class="padding flex flex-direction">
+				<button class="cu-btn bg-blue lg"  @click="onSubmit">提交</button>
+			</view>
+		</form>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				index: -1,
+				switchC: true,
+				imgList: [],
+				uploadUrl:"/sys/common/upload",
+				myFormData:{
+					avatar:'',
+					realname:'',
+					username:'',
+					sex:1,
+					birthday:'',
+					orgCode:'',
+					workNo:'',
+					phone:'',
+					email:'',
+					id:'',
+				},
+			};
+		},
+		onLoad: function (option) {
+			console.log("this.$Route.query",this.$Route.query);
+			let query=this.$Route.query
+			if(query){
+				this.myFormData=query;
+				if(this.myFormData.sex=='女'){
+				  this.switchC = false
+				}else if(this.myFormData.sex=='男'){
+				  this.switchC = true
+				}
+				if(this.myFormData.avatar){
+				  this.imgList=[this.myFormData.avatar]
+				}
+				if(!this.myFormData.birthday){
+				  this.myFormData.birthday= '无'
+				}
+				if(this.myFormData.identity=='普通成员'){
+				  this.myFormData.identity = 1
+				}else if(this.myFormData.identity=='上级'){
+				  this.myFormData.identity = 2
+				}
+				if(this.myFormData.status=='正常'){
+				  this.myFormData.status = 1
+				}else if(this.myFormData.status=='冻结'){
+				  this.myFormData.status = 2
+				}
+				 this.Avatar=this.myFormData.avatar
+	
+				Object.keys(this.myFormData).map(key=>{
+				  if(this.myFormData[key]=='无'){
+					this.myFormData[key] = ''
+				  }
+				})
+				console.log("this.myFormData",this.myFormData)
+			}
+		},
+		methods: {
+			onSubmit() {
+			  let myForm = this.myFormData
+			  let checkPhone = new RegExp(/^[1]([3-9])[0-9]{9}$/);
+			  let checkEmail = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/;
+			  console.log("myForm",myForm)
+			  if(!myForm.phone || myForm.phone.length==0){
+				this.$tip.alert('请输入手机号');
+				return false
+			  }
+			  if(!checkPhone.test(myForm.phone)){
+				this.$tip.alert('请输入正确的手机号');
+				return false
+			  }
+			  if(!checkEmail.test(myForm.email)){
+				this.$tip.alert('请输入正确的邮箱地址');
+				return false
+			  }
+				this.myFormData.id = this.$store.getters.userid
+				if(this.switchC){
+					this.myFormData.sex=1
+				}else{
+					this.myFormData.sex=2
+				}
+				console.log('myform',this.myFormData)
+				this.$tip.loading();
+				this.$http.put('/sys/user/appEdit',this.myFormData).then(res=>{
+					console.log(res)
+					this.$tip.loaded();
+					if (res.data.success){
+						this.$tip.toast('提交成功')
+						this.$Router.replace({name:'userdetail'})
+						/* uni.navigateTo({
+							url: '/pages/user/userdetail'
+						}) */
+					}
+				}).catch(()=>{
+					this.$tip.loaded();
+					this.$tip.error('提交失败')
+				});
+			},
+			DateChange(e) {
+				this.myFormData.birthday = e.detail.value
+			},
+			SwitchC(e) {
+				this.switchC = e.detail.value
+			},
+			ChooseImage() {
+				var that=this;
+				uni.chooseImage({
+					count: 4, //默认9
+					sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
+					sourceType: ['album'], //从相册选择
+					success: (res) => {
+						that.$http.upload(that.$config.apiUrl+that.uploadUrl, {
+								filePath: res.tempFilePaths[0],
+								name: 'file'
+							})
+							.then(res => {
+								that.myFormData.avatar=res.data.message;
+							})
+							.catch(err => {
+								that.$tip.error(err.data.message)
+							});
+						this.imgList = res.tempFilePaths
+					}
+				});
+			},
+			ViewImage(e) {
+				uni.previewImage({
+					urls: this.imgList,
+					current: e.currentTarget.dataset.url
+				});
+			},
+			DelImg(e) {
+				uni.showModal({
+					title: '召唤师',
+					content: '确定要删除这段回忆吗?',
+					cancelText: '再看看',
+					confirmText: '再见',
+					success: res => {
+						if (res.confirm) {
+							this.imgList.splice(e.currentTarget.dataset.index, 1)
+						}
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style>
+	.cu-form-group .title {
+		min-width: calc(4em + 15px);
+	}
+</style>

+ 39 - 0
pages/user/userexit.vue

@@ -0,0 +1,39 @@
+<template name="user">
+	<view>
+		<scroll-view scroll-y class="page">
+			<image src="/static/componentBg.png " mode="widthFix" class="response"></image>
+			<view class="nav-list">
+				<navigator hover-class="none" :url="'/pages/common/' + item.name" class="nav-li" navigateTo :class="'bg-'+item.color"
+				 :style="[{animation: 'show ' + ((index+1)*0.2+1) + 's 1'}]" v-for="(item,index) in elements" :key="index">
+					<view class="nav-title">{{item.title}}</view>
+					<view class="nav-name">{{item.name}}</view>
+					<text :class="'cuIcon-' + item.cuIcon"></text>
+				</navigator>
+			</view>
+			<view class="cu-tabbar-height"></view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'user',
+		data() {
+			return {
+				elements: [{
+						title: '退出',
+						name: 'exit',
+						color: 'cyan',
+						cuIcon: 'newsfill',
+						auth: 'ac'
+					}
+				],
+			}
+		},
+		methods: {}
+	}
+</script>
+
+<style>
+
+</style>

+ 184 - 0
plugin/colorui/animation.css

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

+ 67 - 0
plugin/colorui/components/cu-custom.vue

@@ -0,0 +1,67 @@
+<template>
+	<view>
+		<view class="cu-custom" :style="[{height:CustomBar + 'px'}]">
+			<view class="cu-bar fixed" :style="style" :class="[bgImage!=''?'none-bg text-white bg-img':'',bgColor]">
+				<view class="action" @tap="BackPage" v-if="isBack">
+					<text class="cuIcon-back"></text>
+					<slot name="backText"></slot>
+				</view>
+				<view class="content" :style="[{top:StatusBar + 'px'}]">
+					<slot name="content"></slot>
+				</view>
+				<view class="action">
+					<slot name="right"></slot>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				StatusBar: this.StatusBar,
+				CustomBar: this.CustomBar
+			};
+		},
+		name: 'cu-custom',
+		computed: {
+			style() {
+				var StatusBar= this.StatusBar;
+				var CustomBar= this.CustomBar;
+				var bgImage = this.bgImage;
+				var style = `height:${CustomBar}px;padding-top:${StatusBar}px;`;
+				if (this.bgImage) {
+					style = `${style}background-image:url(${bgImage});`;
+				}
+				return style
+			}
+		},
+		props: {
+			bgColor: {
+				type: String,
+				default: ''
+			},
+			isBack: {
+				type: [Boolean, String],
+				default: false
+			},
+			bgImage: {
+				type: String,
+				default: ''
+			},
+		},
+		methods: {
+			BackPage() {
+				uni.navigateBack({
+					delta: 1
+				});
+			}
+		}
+	}
+</script>
+
+<style>
+
+</style>

Разница между файлами не показана из-за своего большого размера
+ 36 - 0
plugin/colorui/icon.css


+ 3912 - 0
plugin/colorui/main.css

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

+ 41 - 0
plugin/uni-simple-router/README.md

@@ -0,0 +1,41 @@
+# uni-simple-router
+
+> 一个更为简洁的[Vue-router](https://router.vuejs.org/zh/),专为 [uni-app](https://uniapp.dcloud.io/) 量身打造
+
+## 介绍
+
+`uni-simple-router` 是专为 [uni-app](https://uniapp.dcloud.io/) 打造的路由器。它与 [uni-app](https://uniapp.dcloud.io/) 核心深度集成,使使用 [uni-app](https://uniapp.dcloud.io/) 轻松构建单页应用程序变得轻而易举。功能包括:
+
+* `H5端` 能完全使用 `vue-router` 进行开发。
+
+* 模块化,基于组件的路由器配置。
+
+* 路由参数,查询,通配符。
+
+* `H5端` 查看由 `uni-simple-router` 过渡系统提供动力的过渡效果。
+
+* 更细粒度的导航控制。
+
+* `H端`自动控制活动的CSS类链接。
+
+* 通配小程序端、APP端、H5端。
+
+
+开始使用 [查看文档](http://hhyang.cn),或 [使用示例](https://github.com/SilurianYang/uni-simple-router/tree/master/examples)(请参见下面的示例)。
+
+## 问题
+在提交问题的之前,请确保阅读 [“问题报告清单”](https://github.com/SilurianYang/uni-simple-router/issues/new?assignees=&labels=&template=bug_report.md&title=) 。不符合准则的问题可能会立即被解决。
+
+## 贡献
+提出拉取请求之前,请务必先阅读 [查看文档](http://hhyang.cn)(请参见下面的示例)。。
+
+## 变更日志
+[发行说明](https://github.com/SilurianYang/uni-simple-router/releases) 中记录了每个发行版的详细信息更改。
+
+## 特别感谢
+
+特别感谢 [markrgba](https://github.com/markrgba) 一直以来对文档和相关测试的维护。
+
+## 技术交流
+
+<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=0f4d7f38e5d15dd49bf7c3032c80ed3f54ecfa3dd800053d6ae145c869f9eb47"><img border="0" src="http://pub.idqqimg.com/wpa/images/group.png" alt="uni-app  插件" title="uni-app  插件"></a>

+ 361 - 0
plugin/uni-simple-router/appRouter/hooks.js

@@ -0,0 +1,361 @@
+import { uniAppHook, Global } from '../helpers/config';
+import {
+    callAppHook, getPages, getPageVmOrMp, ruleToUniNavInfo, formatTo, formatFrom, APPGetPageRoute, getPageOnBeforeBack,
+} from './util';
+import { noop } from '../helpers/util';
+import { warn } from '../helpers/warn';
+import uniPushTo from './uniNav';
+
+let startBack = false;	// 主要是兼容低端手机返回卡 然后多次返回直接提示退出的问题
+
+/**
+ * 还原并执行所有 拦截下来的生命周期 app.vue 及 index 下的生命周期
+ * @param {Boolean} callHome // 是否触发首页的生命周期
+ *
+ * this 为当前 page 对象
+ */
+const callwaitHooks = function (callHome) {
+    return new Promise(async (resolve) => {
+        const variation = [];	// 存储一下在uni-app上的变异生命钩子  奇葩的要死
+        const {
+            appVue, indexVue, onLaunch, onShow, waitHooks, variationFuns, indexCallHooks,
+        } = uniAppHook;
+        const app = appVue.$options;
+        await onLaunch.fun[onLaunch.fun.length - 1].call(appVue, onLaunch.args);	// 确保只执行最后一个 并且强化异步操作
+        onShow.fun[onShow.fun.length - 1].call(appVue, onShow.args);	// onshow 不保证异步 直接确保执行最后一个
+        if (callHome) {	// 触发首页生命周期
+            // eslint-disable-next-line
+            for (const key in waitHooks) {
+                if (indexCallHooks.includes(key)) {	// 只有在被包含的情况下才执行
+                    callAppHook.call(this, waitHooks[key].fun);
+                }
+            }
+        }
+        if (onLaunch.isHijack) {	// 还原 onLaunch生命钩子
+            app.onLaunch.splice(app.onLaunch.length - 1, 1, onLaunch.fun[0]);
+        }
+        if (onShow.isHijack) {	// 继续还原 onShow
+            app.onShow.splice(app.onShow.length - 1, 1, onShow.fun[0]);
+        }
+        // eslint-disable-next-line
+        for (const key in waitHooks) {	// 还原 首页下的生命钩子
+            const item = waitHooks[key];
+            if (item.isHijack) {
+                if (variationFuns.includes(key)) {	// 变异方法
+                    variation.push({ key, fun: item.fun[0] });
+                } else {
+                    const indeHooks = indexVue[key];
+                    // 修复 https://github.com/SilurianYang/uni-simple-router/issues/76
+                    setTimeout(() => {	// 异步延迟还原 不然 uni-app 给给触发了
+                        indeHooks.splice(indeHooks.length - 1, 1, item.fun[0]);
+                    }, 50);
+                }
+            }
+        }
+        resolve(variation);
+    });
+};
+/**
+ * 还原剩下的奇葩生命钩子
+ * @param {Object} variation 当前uni-app中的一些变异方法  奇葩生命钩子
+ */
+const callVariationHooks = function (variation) {
+    for (let i = 0; i < variation.length; i += 1) {
+        const { key, fun } = variation[i];
+        const indeHooks = uniAppHook.indexVue[key];
+        indeHooks.splice(indeHooks.length - 1, 1, fun);
+    }
+};
+
+/**
+ * 主要是对app.vue下onLaunch和onShow生命周期进行劫持
+ *
+ * this 为当前 page 对象
+ */
+export const proxyLaunchHook = function () {
+    const {
+        onLaunch,
+        onShow,
+    } = this.$options;
+    uniAppHook.appVue = this;		// 缓存 当前app.vue组件对象
+    if (onLaunch.length > 1) {	// 确保有写 onLaunch 可能有其他混入 那也办法
+        uniAppHook.onLaunch.isHijack = true;
+        uniAppHook.onLaunch.fun = onLaunch.splice(onLaunch.length - 1, 1, (arg) => {
+            uniAppHook.onLaunch.args = arg;
+        });		// 替换uni-app自带的生命周期
+    }
+    if (onShow.length > 0) {
+        uniAppHook.onShow.isHijack = true;
+        uniAppHook.onShow.fun = onShow.splice(onShow.length - 1, 1, (arg) => {
+            uniAppHook.onShow.args = arg;
+            if (uniAppHook.pageReady) {		// 因为还有app切前台后台的操作
+                callAppHook.call(this, uniAppHook.onShow.fun, arg);
+            }
+        });	// 替换替换 都替换
+    }
+};
+
+/**
+ * 把指定页面的生命钩子函数保存并替换
+ * this 为当前 page 对象
+ */
+export const proxyIndexHook = function (Router) {
+    const { needHooks, waitHooks } = uniAppHook;
+    const options = this.$options;
+    uniAppHook.indexVue = options;
+    for (let i = 0; i < needHooks.length; i += 1) {
+        const key = needHooks[i];
+        if (options[key] != null) {	// 只劫持开发者声明的生命周期
+            const { length } = options[key];
+            // eslint-disable-next-line
+            const whObject= waitHooks[key]={};
+            whObject.fun = options[key].splice(length - 1, 1, noop);	// 把实际的页面生命钩子函数缓存起来,替换原有的生命钩子
+            whObject.isHijack = true;
+        }
+    }
+    // eslint-disable-next-line
+    triggerLifeCycle.call(this, Router);	// 接着 主动我们触发导航守卫
+};
+/**
+ * 触发全局beforeHooks 生命钩子
+ * @param {Object} _from // from  参数
+ * @param {Object} _to  // to 参数
+ *
+ * this 为当前 Router 对象
+ */
+const beforeHooks = function (_from, _to) {
+    return new Promise(async (resolve) => {
+        const beforeHooksFun = this.lifeCycle.beforeHooks[0];
+        if (beforeHooksFun == null) {
+            return resolve();
+        }
+        await beforeHooksFun.call(this, _to, _from, resolve);
+    });
+};
+/**
+ * 触发全局afterEachHooks 生命钩子
+ * @param {Object} _from // from  参数
+ * @param {Object} _to  // to 参数
+ *
+ * this 为当前 Router 对象
+ */
+const afterEachHooks = function (_from, _to) {
+    const afterHooks = this.lifeCycle.afterHooks[0];
+    if (afterHooks != null && afterHooks.constructor === Function) {
+        afterHooks.call(this, _to, _from);
+    }
+};
+/**
+ * 触发全局 beforeEnter 生命钩子
+ * @param {Object} finalRoute 	// 当前格式化后的路由参数
+ * @param {Object} _from // from  参数
+ * @param {Object} _to  // to 参数
+ *
+ * this 为当前 Router 对象
+ */
+const beforeEnterHooks = function (finalRoute, _from, _to) {
+    return new Promise(async (resolve) => {
+        const { beforeEnter } = finalRoute.route;
+        if (beforeEnter == null || beforeEnter.constructor !== Function) {	// 当前这个beforeEnter不存在 或者类型错误
+            return resolve();
+        }
+        await beforeEnter.call(this, _to, _from, resolve);
+    });
+};
+/**
+ * 触发返回事件公共方法
+ * @param {Object} page	用getPages获取到的页面栈对象
+ * @param {Object} options 	当前vue页面对象
+ * @param {Object} backLayerC	需要返回页面的层级
+   *
+ * this 为当前 Router 对象
+ */
+const backCallHook = function (page, options, backLayerC = 1) {
+    const route = APPGetPageRoute([page]);
+    const NAVTYPE = 'RouterBack';
+    // eslint-disable-next-line
+    transitionTo.call(this, { path: route.path, query: route.query }, NAVTYPE, (finalRoute, fnType) => {
+        if (fnType != NAVTYPE) { // 返回时的api如果有next到其他页面 那么必须带上NAVTYPE  不相同则表示需要跳转到其他页面
+            return uniPushTo(finalRoute, fnType);
+        }
+        if (startBack) { // 如果当前处于正在返回的状态
+            return warn('当前处于正在返回的状态,请稍后再试!');
+        }
+        startBack = true;	// 标记开始返回
+        options.onBackPress = [noop];	// 改回uni-app可执行的状态
+        setTimeout(() => {
+            this.back(backLayerC, undefined, true); // 越过加锁验证
+            startBack = false;	// 返回结束
+        });
+    });
+};
+/**
+ * 处理返回按钮的生命钩子
+ * @param {Object} options 当前 vue 组件对象下的$options对象
+ * @param {Array} args  当前页面是点击头部返回还是底部返回
+ *
+ * this 为当前 Router 对象
+ */
+export const beforeBackHooks = async function (options, args) {
+    const isNext = await getPageOnBeforeBack(args); // 执行onBeforeBack
+    if (isNext === false) { // onBeforeBack  返回了true 阻止了跳转
+        Global.LockStatus = false; // 也需要解锁
+        return false;
+    }
+    const page = getPages(-3);	// 上一个页面对象
+    backCallHook.call(this, page, options);
+};
+/**
+ * 处理back api的生命钩子
+ * @param {Object} options 当前 vue 组件对象下的$options对象
+ * @param {Array} args  当前页面是点击头部返回还是底部返回
+ *
+ * this 为当前 Router 对象
+ */
+export const backApiCallHook = async function (options, args) {
+    await getPageOnBeforeBack(args);
+    const { backLayerC } = Global;
+    const pages = getPages();
+    let page = null;
+    if (backLayerC > pages.length - 1 || backLayerC == pages.length - 1) {	// 返回的首页 我们需要显示tabbar拦截
+        // eslint-disable-next-line
+        page = pages[0];
+    } else {
+        page = pages[pages.length - 2];
+    }
+    backCallHook.call(this, page, options, backLayerC);
+};
+/**
+ *  v1.5.4+
+ * beforeRouteLeave 生命周期
+ * @param {Object} to       将要去的那个页面 to对象
+ * @param {Object} from     从那个页面触发的 from对象
+ *  @param {Boolean} leaveHook:? 是否为 beforeRouteLeave 触发的next 到别处 如果是则不再触发 beforeRouteLeave 生命钩子
+ * this 为当前 Router 对象
+ */
+const beforeRouteLeaveHooks = function (from, to, leaveHook) {
+    return new Promise((resolve) => {
+        if (leaveHook) { // 我们知道这个是来自页面beforeRouteLeave next到其他地方,所有不必再执行啦
+            warn('beforeRouteLeave next到其他地方,无须再执行!');
+            return resolve();
+        }
+        if (from.path == to.path) { // 进入首页的时候不触发
+            return resolve();
+        }
+        const currentPage = getPages(-2); // 获取到全部的页面对象
+        const callThis = getPageVmOrMp(currentPage); // 获取到页面的 $vm 对象 及 page页面的this对象
+        const { beforeRouteLeave } = callThis.$options; // 查看当前是否有开发者声明
+        if (beforeRouteLeave == null) {
+            warn('当前页面下无 beforeRouteLeave 钩子声明,无须执行!');
+            return resolve();
+        }
+        if (beforeRouteLeave != null && beforeRouteLeave.constructor !== Function) {
+            warn('beforeRouteLeave 生命钩子声明错误,必须是一个函数!');
+            return resolve();
+        }
+        beforeRouteLeave.call(callThis, to, from, resolve); // 执行生命钩子
+    });
+};
+
+/**
+ * 验证当前 next() 管道函数是否支持下一步
+ *
+ * @param {Object} Intercept 拦截到的新路由规则
+ * @param {Object} fnType 跳转页面的类型方法 原始的
+ * @param {Object} navCB 回调函数 原始的
+ * @param {Boolean} leaveHookCall:? 是否为 beforeRouteLeave 触发的next 做拦截判断
+ * this 为当前 Router 对象
+ *
+ */
+const isNext = function (Intercept, fnType, navCB, leaveHookCall = false) {
+    return new Promise((resolve, reject) => {
+        if (Intercept == null) {		// 什么也不做 直接执行下一个钩子
+            return resolve();
+        }
+        if (Intercept === false) {		// 路由中断
+            Global.LockStatus = false; // 解锁跳转状态
+            return reject('路由终止');
+        }
+        if (Intercept.constructor === String) {		// 说明 开发者直接传的path 并且没有指定 NAVTYPE 那么采用原来的navType
+            reject('next到其他页面');
+            // eslint-disable-next-line
+            return transitionTo.call(this, Intercept, fnType, navCB,leaveHookCall);
+        }
+        if (Intercept.constructor === Object) {	// 有一系列的配置 包括页面切换动画什么的
+            reject('next到其他页面');
+            // eslint-disable-next-line
+            return transitionTo.call(this, Intercept, Intercept.NAVTYPE || fnType, navCB,leaveHookCall);
+        }
+    });
+};
+/**
+ * 核心方法 处理一系列的跳转配置
+ * @param {Object} rule 当前跳转规则
+ * @param {Object} fnType 跳转页面的类型方法
+ * @param {Object} navCB:? 回调函数
+ * @param {Boolean} leaveHook:? 是否为 beforeRouteLeave 触发的next 到别处 如果是则不再触发 beforeRouteLeave 生命钩子
+ *
+ * this 为当前 Router 对象
+ */
+export const transitionTo = async function (rule, fnType, navCB, leaveHook = false) {
+    await this.lifeCycle.routerbeforeHooks[0].call(this); // 触发内部跳转前的生命周期
+    const finalRoute = ruleToUniNavInfo(rule, this.CONFIG.routes);		// 获得到最终的 route 对象
+    const _from = formatFrom(this.CONFIG.routes);	// 先根据跳转类型获取 from 数据
+    const _to = formatTo(finalRoute);	// 再根据跳转类型获取 to 数据
+    try {
+        const leaveResult = await beforeRouteLeaveHooks.call(this, _from, _to, leaveHook); // 执行页面中的 beforeRouteLeave 生命周期 v1.5.4+
+        await isNext.call(this, leaveResult, fnType, navCB, true);	// 验证当前是否继续  可能需要递归  那么 我们把参数传递过去
+
+        const beforeResult = await beforeHooks.call(this, _from, _to);		// 执行 beforeEach 生命周期
+        await isNext.call(this, beforeResult, fnType, navCB);	// 验证当前是否继续  可能需要递归  那么 我们把参数传递过去
+
+        const enterResult = await beforeEnterHooks.call(this, finalRoute, _from, _to);	// 接着执行 beforeEnter 生命周期
+        await isNext.call(this, enterResult, fnType, navCB);	// 再次验证  如果生命钩子多的话应该写成递归或者循环
+    } catch (e) {
+        warn(e); // 打印开发者操作的日志
+        return false;
+    }
+    if (navCB) {
+        navCB.call(this, finalRoute, fnType);	// 执行当前回调生命周期
+    }
+    afterEachHooks.call(this, _from, _to);
+    await this.lifeCycle.routerAfterHooks[0].call(this); // 触发内部跳转前的生命周期
+};
+/**
+ * 主动触发导航守卫
+ * @param {Object} Router 当前路由对象
+ *
+ * this  当前vue页面组件对象
+ */
+export const triggerLifeCycle = function (Router) {
+    const topPage = getCurrentPages()[0];
+    if (topPage == null) {
+        return warn('打扰了,当前一个页面也没有 这不是官方的bug是什么??');
+    }
+    const { query, page } = getPageVmOrMp(topPage, false);
+    transitionTo.call(Router, { path: page.route, query }, 'push', async (finalRoute, fnType) => {
+        let variation = [];
+        if (`/${page.route}` == finalRoute.route.path) {		// 在首页不动的情况下
+            uniAppHook.pageReady = true;		// 标致着路由已经就绪 可能准备起飞
+            await callwaitHooks.call(this, true);
+        } else {	// 需要跳转
+            variation = await callwaitHooks.call(this, false);	// 只触发app.vue中的生命周期
+            await uniPushTo(finalRoute, fnType);
+        }
+        plus.nativeObj.View.getViewById('router-loadding').close();
+        callVariationHooks(variation);
+        uniAppHook.pageReady = true;		// 标致着路由已经就绪 可能准备起飞
+    });
+};
+
+/**
+ * 处理tabbar点击拦截事件
+ * @param {Object} path 当前需要跳转的tab页面路径
+ *
+ * this 为当前 Router 对象
+ */
+export const beforeTabHooks = function (path) {
+    transitionTo.call(this, { path: `/${path}`, query: {} }, 'pushTab', (finalRoute, fnType) => {
+        uniPushTo(finalRoute, fnType);
+    });
+};

+ 108 - 0
plugin/uni-simple-router/appRouter/init.js

@@ -0,0 +1,108 @@
+import {
+    proxyLaunchHook, beforeBackHooks, beforeTabHooks, backApiCallHook,
+} from './hooks';
+import { Global, uniAppHook } from '../helpers/config';
+import { assertCanBack } from './util';
+import { warn } from '../helpers/warn';
+
+/**
+ * 重写掉uni-app的 uni.getLocation 和 uni.chooseLocation APi
+ * @param {Object} Router  当前路由对象
+ */
+export const rewriteUniFun = function (Router) {
+    const oldSwitchTab = uni.switchTab; // 缓存 跳转到 tabBar 页面
+    uni.switchTab = function ({ url, ...args }, normal = false) {
+        if (normal === true || uniAppHook.pageReady === false) { // 调用原始的uni-app  api
+            oldSwitchTab({
+                url,
+                ...args,
+            });
+        } else {
+            if (uniAppHook.pageReady) { // 只有在路由守卫等  处理完所有操作后才能触发
+                const { path } = Router.$Route; // 获取当前路径
+                if (path == url) { // 路径相同不执行
+                    return warn(`当前跳转路径:${url}  已在本页面无须跳转`);
+                }
+                beforeTabHooks.call(Router, url.substring(1)); // 不要 /
+            } else {
+                warn('路由守卫正在忙碌中 不允许执行 ‘uni.switchTab’');
+            }
+        }
+    };
+};
+
+/**
+ * 对当前app做一个动画页面 用来过渡首次next 等待时间过长的尴尬
+ * @param {Object} Router 当前路由对象
+ */
+export const registerLoddingPage = function (Router) {
+    const { loddingPageHook, loddingPageStyle } = Router.CONFIG.APP;	// 获取app所有配置
+    const view = new plus.nativeObj.View('router-loadding', {
+        top: '0px',
+        left: '0px',
+        height: '100%',
+        width: '100%',
+        ...loddingPageStyle.call(Router),
+    });
+    loddingPageHook.call(Router, view);	// 触发等待页面生命周期
+};
+/**
+ * 移除当前 页面上 非router 声明的 onBackPress 事件
+ * @param {Object} page 当前 vue 组件对象
+ * @param {Object} options	当前page对象的 $options
+ * 修复 https://github.com/SilurianYang/uni-simple-router/issues/106
+ */
+export const removeBackPressEvent = function (page, options) {
+    const isBack = assertCanBack(page);
+    if (isBack) {	// 可返回
+        options.onBackPress = [options.onBackPress[0]];		// 路由混入的都干掉
+    }
+};
+/**
+ * 判断当前页面是否需要拦截返回
+ *
+ * @param {Object} page 当前 vue 组件对象
+ * @param {Object} options 当前 vue 组件对象下的$options对象
+ * @param {Array} args  当前页面是点击头部返回还是底部返回
+ * 修复 https://github.com/SilurianYang/uni-simple-router/issues/66
+ *
+ * this 为当前 Router 对象
+ */
+export const pageIsHeadBack = function (page, options, args) {
+    if (args[0].from == 'navigateBack') {		// 调用api返回
+        if (Global.LockStatus) { // 正在跳转的时候 返回按键按的太快啦
+            warn('当前页面正在处于跳转状态,请稍后再进行跳转....');
+            return true;
+        }
+        Global.LockStatus = true; // 设置为锁住状态
+        backApiCallHook.call(this, options, args);
+        return true;
+    }
+    const isBack = assertCanBack(page);
+    if (isBack) {	// 可返回
+        if (Global.LockStatus) { // 正在跳转的时候 返回按键按的太快啦
+            warn('当前页面正在处于跳转状态,请稍后再进行跳转....');
+            return true;
+        }
+        Global.LockStatus = true; // 设置为锁住状态
+        beforeBackHooks.call(this, options, args);
+        return true;
+    }
+    return false;
+};
+
+/**
+ * 开始初始化app端路由配置
+ *
+ * @param {Object} Router
+ *
+ * this 为当前 page 对象
+ */
+export const appInit = function (Router) {
+    proxyLaunchHook.call(this);
+    const { holdTabbar } = Router.CONFIG.APP;
+    if (holdTabbar) { // 开启tab拦截时
+        rewriteUniFun(Router);
+    }
+    registerLoddingPage(Router);
+};

+ 34 - 0
plugin/uni-simple-router/appRouter/uniNav.js

@@ -0,0 +1,34 @@
+import { methods, baseConfig, Global } from '../helpers/config';
+import { noop, formatURLQuery } from '../helpers/util';
+
+let stop = null;
+
+/**
+ * @param {Object} finalRoute 格式化后的路由跳转规则
+ * @param {Object} NAVTYPE 需要调用的跳转方法
+ */
+const uniPushTo = function (finalRoute, NAVTYPE) {
+    return new Promise((resolve) => {
+        const query = formatURLQuery(`?${finalRoute.uniRoute.query}`);
+        const { APP } = baseConfig;
+        const { url } = finalRoute.uniRoute;
+        stop = setTimeout(() => {
+            resolve(url);
+            resolve = noop;	// 执行完了就没了 确保不会被下一次执行
+            Global.LockStatus = false; // 跳转完成解锁状态
+        }, APP.switchPageOutTime);
+
+        uni[methods[NAVTYPE]]({
+            url: url + query,
+            ...finalRoute.route.animation,
+            complete: () => {
+                clearTimeout(stop);
+                resolve(url);
+                resolve = noop;	// 执行完了就没了 确保不会被下一次执行
+                Global.LockStatus = false; // 跳转完成解锁状态
+            },
+        }, true); // 这里传递true 主要是兼容重写 uni.switchTab
+    });
+};
+
+export default uniPushTo;

+ 209 - 0
plugin/uni-simple-router/appRouter/util.js

@@ -0,0 +1,209 @@
+import { err } from '../helpers/warn';
+import { copyObject, parseQuery } from '../helpers/util';
+import { Global, route as mergeRoute } from '../helpers/config';
+
+/**
+ * 触发指定生命钩子
+ * @param {Array} funList	//需要执行的方法列表
+ * @param {Object} args //触发生命钩子传递的参数
+ */
+export const callAppHook = function (funList = [], args) {
+    for (let i = 0; i < funList.length; i += 1) {
+        funList[i].call(this, args);
+    }
+};
+/**
+ * @param {Number} index //需要获取的页面下标 -2:表示获取最后一个即当前页面 -1:表示全部 -3:当前页面的前一个页面
+ * @param {Boolean} all //是否获取全部的页面
+ */
+export const getPages = function (index = -1, all) {
+    const pages = getCurrentPages(all);
+    if (index === -1) {
+        return pages;
+    }
+    if (index === -2) {
+        return pages[pages.length - 1];
+    }
+    if (index === -3) {
+        return pages[pages.length - 2];
+    }
+    return pages[index];
+};
+/**
+ * 验证当前页面是否为nvue页面
+ * @param {Object} page 当前页面对象
+ */
+export const isNvuePage = function (page) {
+    const cstr = page.constructor.name;
+    const pageType = {
+        s: true,
+        z: false,
+    };
+    return pageType[cstr];
+};
+
+/**
+ * @param {Object} page //当前顶级页面对象
+ * @param {Object} vim:? //是否获取 $vm 对象还是 $mp 对象
+ */
+export const getPageVmOrMp = function (page, vim = true) {
+    if (vim) {
+        return page.$vm;
+    }
+    if (page.$vm.$mp) {
+        return page.$vm.$mp;
+    }
+    if (isNvuePage(page)) {	// nvue 页面
+        return {
+            page,
+            query: page.__displayReporter.query,
+        };
+    }
+};
+
+/**
+ * 获取 to 的配置参数
+ * @param {Object} rule 当前跳转的规则
+ */
+export const formatTo = function (finalRoute) {
+    const route = copyObject(finalRoute.route);
+    const { rule } = finalRoute;
+    route.query = rule.query || rule.params || {};
+    return route;
+};
+/**
+ * 通过一个未知的路径或者名称 在路由表中查找指定路由表 并返回
+ * @param {string} type   //path 或者 name
+ * @param {Object} routes //当前对象的所有路由表
+ */
+export const pathOrNameToRoute = function (type, routes = Global.Router.CONFIG.routes) {
+    const routesKeys = Object.keys(routes);
+    for (let i = 0; i < routesKeys.length; i += 1) {
+        const key = routesKeys[i];
+        const item = routes[key];
+        if (item.path === `/${type}`) {
+            return mergeRoute(item); // 合并一下对象,主要是合并 query:{} 及 params:{}
+        }
+        if (item.path === type) {
+            return mergeRoute(item); // 合并一下对象,主要是合并 query:{} 及 params:{}
+        }
+        if (item.name == type) {
+            return mergeRoute(item); // 合并一下对象,主要是合并 query:{} 及 params:{}
+        }
+    }
+    err(`当前 '${type}' 在路由表中没有找到匹配的 name 或者 path`);
+};
+/**
+ * 统一格式话 路由传递的参数 看看是编码还是非编码 做相应的对策
+ *
+ * @param {Object} query 当前的路由参数
+ * @param {Boolean} getter 是从页面获取 route 对象下的参数 还是编码后传输
+ */
+export const getFormatQuery = function (query = {}) {
+    if (Global.Router.CONFIG.encodeURI) {
+        try {
+            query = JSON.parse(decodeURIComponent(query.query || encodeURIComponent('{}')));
+        } catch (e) {
+            query = JSON.parse(query.query);
+        }
+    }
+    return query;
+};
+/**
+ * 获取 from 的配置参数 from 页面永远都是站在当前页面忘其它地方走 所以都是最后一个页面
+ *
+ * @param {Object} routes //当前对象的所有路由表
+ */
+export const formatFrom = function (routes) {
+    const topPage = getPages(-2);
+    const { page, query } = getPageVmOrMp(topPage, false);
+    const route = pathOrNameToRoute(page.route, routes);	// 获取到当前路由表下的 route
+    route.query = getFormatQuery(query);	// 不管是编码传输还是非编码 最后都得在 to/from 中换成json对象
+    return route;
+};
+/**
+ *
+ * 把用户的跳转路由规则格式化成uni-app可用的路由跳转规则
+ *
+ * @param {Object} rule  //当前用户跳转的路由规则
+ * @param {Object} routes //当前simple-router 下的路由表
+ */
+export const ruleToUniNavInfo = function (rule, routes) {
+    if (rule == null) {
+        return err('当前跳转规则为空,请检查跳转代码');
+    }
+    // eslint-disable-next-line
+    let [navType, route, query, animation] = ['path', null, {}, {}];
+    if (rule.constructor === String) {		// 是字符串类型 那当前就是路径啦
+        route = pathOrNameToRoute(rule, routes);	// 直接把 rule 当 path 传递 完事
+    } else if (rule.constructor === Object) {		// 对象类型 可以是 path 或者 name
+        route = pathOrNameToRoute(rule.path || (navType = 'name', rule.name), routes);	// 两则必有其一 报错自己处理
+        query = rule.query || rule.params || {};
+        animation = rule.animation || {};
+    } else {
+        return err('传的什么乱七八糟的类型?路由跳转规则只认字符串 \'path\' , 对象 \'path\' , 对象 \'name\' ');
+    }
+    animation = { ...Global.Router.CONFIG.APP.animation, ...route.animation || {}, ...animation };	// 合并多种方式声明的动画效果
+    route.animation = animation;	// 这才是最终的页面切换效果
+    // 路径处理完后   开始格式化参数
+    const uniRoute = parseQuery(route.path, query);	// uni-app 需要的跳转规则
+    return {
+        rule,
+        route,
+        uniRoute,
+    };
+};
+/**
+ * 获取当前页面下的 Route 信息
+ *
+ * @param {Object} pages 获取页面对象集合
+ * @param {Object} Vim 用户传递的当前页面对象
+ */
+export const APPGetPageRoute = function (pages, Vim) {
+    let [query, path] = [{}, ''];
+    const page = pages[pages.length - 1];	// 获取到当前页面
+    if (pages.length > 0) {
+        query = getFormatQuery(page.options, true);
+        path = page.route;
+    } else if (Vim != null) {
+        query = getFormatQuery(Vim.$mp.page.options, true);
+        path = page.route;
+    }
+    const route = pathOrNameToRoute(path);
+    route.query = query;
+    return route;
+};
+/**
+ * 获取当前页面下的 onBeforeBack 生命周期并执行
+ *
+ * @param {Object} args 当前返回页面时uni-app传递的参数
+ */
+export const getPageOnBeforeBack = function (args) {
+    return new Promise(async (resolve) => {
+        const currPage = getPages(-2);	// 获取到当前页面
+        const { onBeforeBack } = currPage.$vm.$options;
+        if (onBeforeBack != null && onBeforeBack.constructor === Function) {
+            const isNext = await onBeforeBack.call(currPage.$vm, args);
+            if (isNext === true) {
+                return resolve(false);
+            }
+        }
+        return resolve(true);
+    });
+};
+/**
+ * 断言当前页面是否可返回上一级
+ * @param {Object} page 当前页面webview对象
+ */
+export const assertCanBack = function (page) {
+    const pageStyle = page.$getAppWebview().getStyle();
+    if (pageStyle.titleNView != null && pageStyle.titleNView.autoBackButton) {	// 只有处理有带返回按钮的页面
+        return true;
+    }
+    // 两种情况 1.真的是顶级页面时  2.自定义头部
+    const { $page } = page;
+    if ($page && $page.meta.isQuit === false) {		// 自定义头部 不是顶级页面
+        return true;
+    }
+    return false;	// 不可返回 真的是顶级页面时 返回就直接退出app了
+};

+ 23 - 0
plugin/uni-simple-router/appletsRouter/appletsNav.js

@@ -0,0 +1,23 @@
+
+import { methods, Global } from '../helpers/config';
+import { formatURLQuery } from '../helpers/util';
+
+
+/**
+ * @param {Object} finalRoute 格式化后的路由跳转规则
+ * @param {Object} NAVTYPE 需要调用的跳转方法
+ */
+const appletsUniPushTo = function (finalRoute, NAVTYPE) {
+    return new Promise((resolve) => {
+        const query = formatURLQuery(`?${finalRoute.uniRoute.query}`);
+        const { url } = finalRoute.uniRoute;
+        uni[methods[NAVTYPE]]({
+            url: url + query,
+            complete: () => {
+                resolve(url);
+                Global.LockStatus = false; // 跳转完成解锁状态
+            },
+        });
+    });
+};
+export default appletsUniPushTo;

+ 319 - 0
plugin/uni-simple-router/appletsRouter/hooks.js

@@ -0,0 +1,319 @@
+import { uniAppHook, Global } from '../helpers/config';
+import {
+    callAppHook, getPageVmOrMp, ruleToUniNavInfo, formatTo, formatFrom, getPages,
+} from './util';
+import appletsUniPushTo from './appletsNav';
+import { noop } from '../helpers/util';
+import { warn } from '../helpers/warn';
+
+/**
+ *
+ * @param {String} key
+ * @param {Function} hook 需要执行及还原的生命周期函数
+ */
+const toutiaoIndexHookCall = function (key, hook) {
+    const { indexVue } = uniAppHook;
+    const indeHooks = indexVue[key];
+    indeHooks.splice(indeHooks.length - 1, 1, hook);
+};
+
+/**
+ * 还原并执行所有 拦截下来的生命周期 app.vue 及 index 下的生命周期
+ * @param {Boolean} callHome // 是否触发首页的生命周期
+ *
+ * this 为当前 page 对象
+ */
+const callwaitHooks = function (callHome) {
+    return new Promise(async (resolve) => {
+        const variation = [];	// 存储一下在uni-app上的变异生命钩子  奇葩的要死
+        const {
+            appVue, onLaunch, onShow, waitHooks, variationFuns, indexCallHooks,
+        } = uniAppHook;
+        const app = appVue.$options;
+        await onLaunch.fun[onLaunch.fun.length - 1].call(appVue, onLaunch.args);	// 确保只执行最后一个 并且强化异步操作
+        onShow.fun[onShow.fun.length - 1].call(appVue, onShow.args);	// onshow 不保证异步 直接确保执行最后一个
+        if (callHome) {	// 触发首页生命周期
+            // eslint-disable-next-line
+            for (const key in waitHooks) {
+                if (indexCallHooks.includes(key)) {	// 只有在被包含的情况下才执行
+                    callAppHook.call(this, waitHooks[key].fun);
+                }
+            }
+        }
+        if (onLaunch.isHijack) {	// 还原 onLaunch生命钩子
+            app.onLaunch.splice(app.onLaunch.length - 1, 1, onLaunch.fun[0]);
+        }
+        if (onShow.isHijack) {	// 继续还原 onShow
+            app.onShow.splice(app.onShow.length - 1, 1, onShow.fun[0]);
+        }
+        // eslint-disable-next-line
+        for (const key in waitHooks) {	// 还原 首页下的生命钩子
+            const item = waitHooks[key];
+            if (item.isHijack) {
+                if (variationFuns.includes(key)) {	// 变异方法
+                    variation.push({ key, fun: item.fun[0] });
+                } else {
+                    toutiaoIndexHookCall(key, item.fun[0]);
+                }
+            }
+        }
+        resolve(variation);
+    });
+};
+/**
+ * 还原剩下的奇葩生命钩子
+ * @param {Object} variation 当前uni-app中的一些变异方法  奇葩生命钩子
+ */
+const callVariationHooks = function (variation) {
+    for (let i = 0; i < variation.length; i += 1) {
+        const { key, fun } = variation[i];
+        toutiaoIndexHookCall(key, fun);
+    }
+};
+
+/**
+ * 主要是对app.vue下onLaunch和onShow生命周期进行劫持
+ *
+ * this 为当前 page 对象
+ */
+export const proxyLaunchHook = function () {
+    const {
+        onLaunch,
+        onShow,
+    } = this.$options;
+    uniAppHook.appVue = this;		// 缓存 当前app.vue组件对象
+    if (onLaunch.length > 1) {	// 确保有写 onLaunch 可能有其他混入 那也办法
+        uniAppHook.onLaunch.isHijack = true;
+        uniAppHook.onLaunch.fun = onLaunch.splice(onLaunch.length - 1, 1, (arg) => {
+            uniAppHook.onLaunch.args = arg;
+        });		// 替换uni-app自带的生命周期
+    }
+    if (onShow.length > 0) {
+        uniAppHook.onShow.isHijack = true;
+        uniAppHook.onShow.fun = onShow.splice(onShow.length - 1, 1, (arg) => {
+            uniAppHook.onShow.args = arg;
+            if (uniAppHook.pageReady) {		// 因为还有app切前台后台的操作
+                callAppHook.call(this, uniAppHook.onShow.fun, arg);
+            }
+        });	// 替换替换 都替换
+    }
+};
+/**
+ * 触发全局beforeHooks 生命钩子
+ * @param {Object} _from // from  参数
+ * @param {Object} _to  // to 参数
+ *
+ * this 为当前 Router 对象
+ */
+const beforeHooks = function (_from, _to) {
+    return new Promise(async (resolve) => {
+        const beforeHooksFun = this.lifeCycle.beforeHooks[0];
+        if (beforeHooksFun == null) {
+            return resolve();
+        }
+        await beforeHooksFun.call(this, _to, _from, resolve);
+    });
+};
+/**
+ * 触发全局afterEachHooks 生命钩子
+ * @param {Object} _from // from  参数
+ * @param {Object} _to  // to 参数
+ *
+ * this 为当前 Router 对象
+ */
+const afterEachHooks = function (_from, _to) {
+    const afterHooks = this.lifeCycle.afterHooks[0];
+    if (afterHooks != null && afterHooks.constructor === Function) {
+        afterHooks.call(this, _to, _from);
+    }
+};
+/**
+ * 触发全局 beforeEnter 生命钩子
+ * @param {Object} finalRoute 	// 当前格式化后的路由参数
+ * @param {Object} _from // from  参数
+ * @param {Object} _to  // to 参数
+ *
+ * this 为当前 Router 对象
+ */
+const beforeEnterHooks = function (finalRoute, _from, _to) {
+    return new Promise(async (resolve) => {
+        const { beforeEnter } = finalRoute.route;
+        if (beforeEnter == null || beforeEnter.constructor !== Function) {	// 当前这个beforeEnter不存在 或者类型错误
+            return resolve();
+        }
+        await beforeEnter.call(this, _to, _from, resolve);
+    });
+};
+/**
+ *  v1.5.4+
+ * beforeRouteLeave 生命周期
+ * @param {Object} to       将要去的那个页面 to对象
+ * @param {Object} from     从那个页面触发的 from对象
+ *  @param {Boolean} leaveHook:? 是否为 beforeRouteLeave 触发的next 到别处 如果是则不再触发 beforeRouteLeave 生命钩子
+ * this 为当前 Router 对象
+ */
+const beforeRouteLeaveHooks = function (from, to, leaveHook) {
+    return new Promise(async (resolve) => {
+        if (leaveHook) { // 我们知道这个是来自页面beforeRouteLeave next到其他地方,所有不必再执行啦
+            warn('beforeRouteLeave next到其他地方,无须再执行!');
+            return resolve();
+        }
+        if (from.path == to.path) { // 进入首页的时候不触发
+            return resolve();
+        }
+        const currentPage = getPages(-2); // 获取到全部的页面对象
+        const callThis = getPageVmOrMp(currentPage); // 获取到页面的 $vm 对象 及 page页面的this对象
+        const { beforeRouteLeave } = callThis.$options; // 查看当前是否有开发者声明
+        if (beforeRouteLeave == null) {
+            warn('当前页面下无 beforeRouteLeave 钩子声明,无须执行!');
+            return resolve();
+        }
+        if (beforeRouteLeave != null && beforeRouteLeave.constructor !== Function) {
+            warn('beforeRouteLeave 生命钩子声明错误,必须是一个函数!');
+            return resolve();
+        }
+        await beforeRouteLeave.call(callThis, to, from, resolve); // 执行生命钩子
+    });
+};
+
+/**
+ * 核心方法 处理一系列的跳转配置
+ * @param {Object} rule 当前跳转规则
+ * @param {Object} fnType 跳转页面的类型方法
+ * @param {Object} navCB:? 回调函数
+ * @param {Boolean} leaveHook:? 是否为 beforeRouteLeave 触发的next 到别处 如果是则不再触发 beforeRouteLeave 生命钩子
+ * this 为当前 Router 对象
+ *
+ */
+export const appletsTransitionTo = async function (rule, fnType, navCB, leaveHook = false) {
+    await this.lifeCycle.routerbeforeHooks[0].call(this); // 触发内部跳转前的生命周期
+    const finalRoute = ruleToUniNavInfo(rule, this.CONFIG.routes);		// 获得到最终的 route 对象
+    const _from = formatFrom(this.CONFIG.routes);	// 先根据跳转类型获取 from 数据
+    const _to = formatTo(finalRoute);	// 再根据跳转类型获取 to 数据
+    try {
+        const leaveResult = await beforeRouteLeaveHooks.call(this, _from, _to, leaveHook); // 执行页面中的 beforeRouteLeave 生命周期 v1.5.4+
+        // eslint-disable-next-line
+        await isNext.call(this, leaveResult, fnType, navCB,true);	// 验证当前是否继续  可能需要递归  那么 我们把参数传递过去
+
+        const beforeResult = await beforeHooks.call(this, _from, _to);		// 执行 beforeEach 生命周期
+        // eslint-disable-next-line
+        await isNext.call(this, beforeResult, fnType, navCB);	// 验证当前是否继续  可能需要递归  那么 我们把参数传递过去
+
+        const enterResult = await beforeEnterHooks.call(this, finalRoute, _from, _to);	// 接着执行 beforeEnter 生命周期
+        // eslint-disable-next-line
+        await isNext.call(this, enterResult, fnType, navCB);	// 再次验证  如果生命钩子多的话应该写成递归或者循环
+    } catch (e) {
+        warn(e); // 打印开发者操作的日志
+        return false;
+    }
+    if (navCB) {
+        navCB.call(this, finalRoute, fnType);	// 执行当前回调生命周期
+    }
+    afterEachHooks.call(this, _from, _to);
+    await this.lifeCycle.routerAfterHooks[0].call(this); // 触发内部跳转前的生命周期
+};
+
+/**
+ * 触发全局 返回事件
+ * @param {Number} backLayer 需要返回的页面层级
+ * @param {Function} next 正真的回调函数
+ *
+ * this 为当前 Router 对象
+ */
+export const backCallHook = function (backLayer, next) {
+    const pages = getPages(); // 获取到全部的页面对象
+    const toPage = pages.reverse()[backLayer];
+    if (toPage == null) { // 没有匹配到的时候
+        return warn('亲爱的开发者,你确定页面栈中有这么多历史记录给你返回?');
+    }
+    const { query, page } = getPageVmOrMp(toPage, false);
+    const beforeFntype = 'RouterBack';
+    appletsTransitionTo.call(this, { path: page.route, query }, beforeFntype, (finalRoute, fnType) => {
+        const toPath = finalRoute.uniRoute.url;
+        if (`/${page.route}` == toPath || page.route == toPath) { // 直接调用返回api
+            next();
+        } else { // 有拦截到其他页面时
+            if (fnType == beforeFntype) {
+                return warn('调用返回api被拦截到其他页面需要指定合理的 ‘NAVTYPE’ ');
+            }
+            appletsUniPushTo(finalRoute, fnType);
+        }
+    });
+};
+
+/**
+ * 主动触发导航守卫
+ * @param {Object} Router 当前路由对象
+ *
+ */
+export const triggerLifeCycle = function (Router) {
+    const topPage = getCurrentPages()[0];
+    if (topPage == null) {
+        return warn('打扰了,当前一个页面也没有 这不是官方的bug是什么??');
+    }
+    const { query, page } = getPageVmOrMp(topPage, false);
+    appletsTransitionTo.call(Router, { path: page.route, query }, 'push', async (finalRoute, fnType) => {
+        let variation = [];
+        if (`/${page.route}` == finalRoute.route.path || page.route == finalRoute.route.path) {		// 在首页不动的情况下
+            uniAppHook.pageReady = true;		// 标致着路由已经就绪 可能准备起飞
+            await callwaitHooks.call(this, true);
+        } else {	// 需要跳转
+            variation = await callwaitHooks.call(this, false);	// 只触发app.vue中的生命周期
+            await appletsUniPushTo(finalRoute, fnType);
+        }
+        uniAppHook.pageReady = true;		// 标致着路由已经就绪 可能准备起飞
+        callVariationHooks(variation);
+    });
+};
+/**
+ * 把指定页面的生命钩子函数保存并替换
+ * this 为当前 page 对象
+ */
+export const appletsProxyIndexHook = function (Router) {
+    if (process.env.VUE_APP_PLATFORM == 'mp-toutiao') { // 头条小程序首页生命周期由我们手动触发,缓存this
+        uniAppHook.toutiaoIndexThis = this;
+    }
+    const { needHooks, waitHooks } = uniAppHook;
+    const options = this.$options;
+    uniAppHook.indexVue = options;
+    for (let i = 0; i < needHooks.length; i += 1) {
+        const key = needHooks[i];
+        if (options[key] != null) {	// 只劫持开发者声明的生命周期
+            const { length } = options[key];
+            // eslint-disable-next-line
+            const whObject= waitHooks[key]={};
+            whObject.fun = options[key].splice(length - 1, 1, noop);	// 把实际的页面生命钩子函数缓存起来,替换原有的生命钩子
+            whObject.isHijack = true;
+        }
+    }
+    triggerLifeCycle.call(this, Router);	// 接着 主动我们触发导航守卫
+};
+/**
+ * 验证当前 next() 管道函数是否支持下一步
+ *
+ * @param {Object} Intercept 拦截到的新路由规则
+ * @param {Object} fnType 跳转页面的类型方法 原始的
+ * @param {Object} navCB 回调函数 原始的
+ * @param {Boolean} leaveHookCall:? 是否为 beforeRouteLeave 触发的next 做拦截判断
+ * this 为当前 Router 对象
+ *
+ */
+const isNext = function (Intercept, fnType, navCB, leaveHookCall = false) {
+    return new Promise((resolve, reject) => {
+        if (Intercept == null) {		// 什么也不做 直接执行下一个钩子
+            return resolve();
+        }
+        if (Intercept === false) {		// 路由中断 我们需要把防抖设置为false
+            Global.LockStatus = false; // 解锁跳转状态
+            return reject('路由终止');
+        }
+        if (Intercept.constructor === String) {		// 说明 开发者直接传的path 并且没有指定 NAVTYPE 那么采用原来的navType
+            reject('next到其他页面');
+            return appletsTransitionTo.call(this, Intercept, fnType, navCB, leaveHookCall);
+        }
+        if (Intercept.constructor === Object) {	// 有一系列的配置 包括页面切换动画什么的
+            reject('next到其他页面');
+            return appletsTransitionTo.call(this, Intercept, Intercept.NAVTYPE || fnType, navCB, leaveHookCall);
+        }
+    });
+};

+ 13 - 0
plugin/uni-simple-router/appletsRouter/init.js

@@ -0,0 +1,13 @@
+import { proxyLaunchHook } from './hooks';
+
+/**
+ * 开始初始化app端路由配置
+ *
+ * @param {Object} Router 	当前Router对象
+ *
+ * this 为当前 page 对象
+ */
+const appletsInit = function () {
+    proxyLaunchHook.call(this);
+};
+export default appletsInit;

+ 169 - 0
plugin/uni-simple-router/appletsRouter/util.js

@@ -0,0 +1,169 @@
+import { Global, route as mergeRoute } from '../helpers/config';
+import { copyObject, parseQuery } from '../helpers/util';
+import { err } from '../helpers/warn';
+import { baiduApple, touTiao } from '../helpers/compile';
+/**
+ * 触发指定生命钩子
+ * @param {Array} funList	//需要执行的方法列表
+ * @param {Object} args //触发生命钩子传递的参数
+ */
+export const callAppHook = function (funList, args) {
+    for (let i = 0; i < funList.length; i += 1) {
+        funList[i].call(this, args);
+    }
+};
+/**
+ * @param {Object} page //当前顶级页面对象
+ * @param {Object} vim:? //是否获取 $vm 对象还是 $mp 对象
+ */
+export const getPageVmOrMp = function (page, vim = true) {
+    if (vim) {
+        return page.$vm;
+    }
+    const { $mp } = page.$vm;
+    baiduApple(() => {	// 百度小程序新增一个route属性
+        $mp.page.route = $mp.page.is;
+    });
+    touTiao(() => {	// 头条小程序新增一个route属性
+        $mp.page.route = $mp.page.is;
+    });
+    return $mp;
+};
+/**
+ * 统一格式话 路由传递的参数 看看是编码还是非编码 做相应的对策
+ *
+ * @param {Object} query 当前的路由参数
+ * @param {Boolean} getter 是从页面获取 route 对象下的参数 还是编码后传输
+ */
+export const getFormatQuery = function (query = {}, getter = false) {
+    if (Global.Router.CONFIG.encodeURI) {
+        if (getter) {
+            try {		// 除去微信小程序都不需要 decodeURIComponent
+                query = JSON.parse(decodeURIComponent(query.query) || '{}');
+            } catch (e) {	// 其他小程序
+                query = JSON.parse(query.query || '{}');
+            }
+        } else {
+            try {
+                query = JSON.parse(decodeURIComponent(query.query || encodeURIComponent('{}')));
+            } catch (e) {
+                query = JSON.parse(query.query);
+            }
+        }
+    }
+    return query;
+};
+/**
+ * @param {Number} index //需要获取的页面下标 -2:表示获取最后一个即当前页面 -1:表示全部 -3:当前页面的前一个页面
+ * @param {Boolean} all //是否获取全部的页面
+ */
+export const getPages = function (index = -1, all) {
+    const pages = getCurrentPages(all);
+    if (index === -1) {
+        return pages;
+    }
+    if (index === -2) {
+        return pages[pages.length - 1];
+    }
+    if (index === -3) {
+        return pages[pages.length - 2];
+    }
+    return pages[index];
+};
+/**
+ * 通过一个未知的路径或者名称 在路由表中查找指定路由表 并返回
+ * @param {string} type   //path 或者 name
+ * @param {Object} routes //当前对象的所有路由表
+ */
+export const pathOrNameToRoute = function (type, routes = Global.Router.CONFIG.routes) {
+    const routesKeys = Object.keys(routes);
+    for (let i = 0; i < routesKeys.length; i += 1) {
+        const key = routesKeys[i];
+        const item = routes[key];
+        if (item.path === `/${type}`) {
+            return mergeRoute(item); // 合并一下对象,主要是合并 query:{} 及 params:{}
+        }
+        if (item.path === type) {
+            return mergeRoute(item); // 合并一下对象,主要是合并 query:{} 及 params:{}
+        }
+        if (item.name == type) {
+            return mergeRoute(item); // 合并一下对象,主要是合并 query:{} 及 params:{}
+        }
+    }
+    err(`当前 '${type}' 在路由表中没有找到匹配的 name 或者 path`);
+};
+
+/**
+ * 获取 to 的配置参数
+ * @param {Object} rule 当前跳转的规则
+ */
+export const formatTo = function (finalRoute) {
+    const route = copyObject(finalRoute.route);
+    const { rule } = finalRoute;
+    route.query = rule.query || rule.params || {};
+    return route;
+};
+
+/**
+ * 获取 from 的配置参数 from 页面永远都是站在当前页面忘其它地方走 所以都是最后一个页面
+ *
+ * @param {Object} routes //当前对象的所有路由表
+ */
+export const formatFrom = function (routes) {
+    const topPage = getPages(-2);
+    const { page, query } = getPageVmOrMp(topPage, false);
+    const route = pathOrNameToRoute(page.route, routes);	// 获取到当前路由表下的 route
+    route.query = getFormatQuery(query);	// 不管是编码传输还是非编码 最后都得在 to/from 中换成json对象
+    return route;
+};
+
+/**
+ *
+ * 把用户的跳转路由规则格式化成uni-app可用的路由跳转规则
+ *
+ * @param {Object} rule  //当前用户跳转的路由规则
+ * @param {Object} routes //当前simple-router 下的路由表
+ */
+export const ruleToUniNavInfo = function (rule, routes) {
+    if (rule == null) {
+        return err('当前跳转规则为空,请检查跳转代码');
+    }
+    // eslint-disable-next-line
+    let [navType, route, query] = ['path', null, {}];
+    if (rule.constructor === String) {		// 是字符串类型 那当前就是路径啦
+        route = pathOrNameToRoute(rule, routes);	// 直接把 rule 当 path 传递 完事
+    } else if (rule.constructor === Object) {		// 对象类型 可以是 path 或者 name
+        route = pathOrNameToRoute(rule.path || (navType = 'name', rule.name), routes);	// 两则必有其一 报错自己处理
+        query = rule.query || rule.params || {};
+    } else {
+        return err('传的什么乱七八糟的类型?路由跳转规则只认字符串 \'path\' , 对象 \'path\' , 对象 \'name\' ');
+    }
+    // 路径处理完后   开始格式化参数
+    const uniRoute = parseQuery(route.path, query);	// uni-app 需要的跳转规则
+    return {
+        rule,
+        route,
+        uniRoute,
+    };
+};
+/**
+ * 获取当前页面下的 Route 信息
+ *
+ * @param {Object} pages 获取页面对象集合
+ * @param {Object} Vim 用户传递的当前页面对象
+ */
+export const AppletsPageRoute = function (pages, Vim) {
+    let [query, path] = [{}, ''];
+    const page = pages[pages.length - 1];	// 获取到当前页面
+    if (pages.length > 0) {
+        const uniQuery = getPageVmOrMp(page, false).query;
+        query = getFormatQuery(uniQuery, true);
+        path = page.route;
+    } else if (Vim != null) {
+        query = getFormatQuery(Vim.$mp.page.options, true);
+        path = page.route;
+    }
+    const route = pathOrNameToRoute(path);
+    route.query = query;
+    return route;
+};

+ 75 - 0
plugin/uni-simple-router/component/h5-dom.js

@@ -0,0 +1,75 @@
+const render = function (node) {
+    if (typeof node == 'string') { // 是一个文本节点
+        return document.createTextNode(node);
+    }
+    if (node instanceof HTMLElement) {
+        return node;
+    }
+    // eslint-disable-next-line
+    return createElement(node);
+};
+/**
+ * 根据标签及属性创建一个dom
+ */
+const createElement = function ({
+    tag,
+    attrs,
+    children,
+} = {}) {
+    const $el = document.createElement(tag);
+    // eslint-disable-next-line
+    for (const [k, v] of Object.entries(attrs)) {
+        $el.setAttribute(k, v);
+    }
+    // eslint-disable-next-line
+    for (const item of children) {
+        $el.appendChild(render(item));
+    }
+    return $el;
+};
+
+const html = createElement({
+    tag: 'div',
+    attrs: {
+        id: 'router-loadding',
+    },
+    children: [
+        createElement({
+            tag: 'div',
+            attrs: {
+                class: 'loadding',
+            },
+            children: [],
+        }),
+    ],
+});
+/* eslint-disable */
+const style = createElement({
+    tag: 'style',
+    attrs: {
+        id: 'HHYANG_style',
+    },
+    children: [
+        `
+		body{padding:0;margin:0}#router-loadding{position:fixed;width:100%;height:3px;transition:all .05s;top:0;z-index:9999999999999999;}#router-loadding .loadding{position:fixed;top:0;height:3px;background-color:#47b14b;width:0;box-shadow:0 0 15px #4CAF50;transition:all .8s;border-top-right-radius:3px;border-bottom-right-radius:3px}
+		`,
+    ],
+});
+
+const script = createElement({
+    tag: 'script',
+    attrs: {
+        id: 'HHYANG_script',
+    },
+    children: [
+        `
+		var HHYANG_El=document.querySelector("#router-loadding .loadding"),HHYANG_Pel=document.querySelector("#router-loadding"),w=0,stop=null,WH=window.innerWidth,loop=function(){w=w>=WH-35?w+parseInt(5*Math.random()):w+parseInt(35*Math.random());HHYANG_El.style.cssText="width:"+w+"px";w>=WH&&clearInterval(stop)};window.startLodding=function(a){a=void 0===a?500:a;HHYANG_Pel.style.cssText="display: block;";HHYANG_El.style.cssText="transition: all 0.8s;";w=0;clearInterval(stop);stop=setInterval(function(){loop()},a)};window.stopLodding=function(a){a=void 0===a?200:a;clearInterval(stop);HHYANG_El.style.cssText="width:"+WH+"px;transition: all "+a/1E3+"s;";HHYANG_Pel.style.cssText="opacity: 0;transition: all "+a/1E3+"s;";setTimeout(function(){HHYANG_Pel.style.cssText="display: none;";HHYANG_El.style.cssText="width:0px";w=0},a)};
+		`,
+    ],
+});
+export const DOM = {
+    style,
+    html,
+    script,
+};
+/* eslint-enable */

+ 79 - 0
plugin/uni-simple-router/component/router-link.vue

@@ -0,0 +1,79 @@
+<template>
+	<view @click="gotoPage()"><slot></slot></view>
+</template>
+
+<script>
+const navType = {
+	push: 'push',
+	replace: 'replace',
+	replaceAll: 'replaceAll',
+	pushTab: 'pushTab'
+};
+export default {
+	props: {
+		to: {
+			type: [String, Object],
+		},
+		stopNavto: {
+			type: Boolean,
+			default: false
+		},
+		navType: {
+			type: String,
+			default: 'push'
+		},
+		level: {
+			type: Number,
+			default: 1
+		},
+		append: {
+			type: Boolean,
+			default: false
+		}
+	},
+	methods: {
+		formatNav(text) {
+			if (text != null && text.constructor === String) {
+				text = text.replace(/\'/g, '');
+				text = text.replace(/(\w+)(?=:)/g, function(val) {
+					return `"${val}"`;
+				});
+				text = text.replace(/:\s*([^,{}\s"]+)/g, function(val) {
+					const arr = val.split(':');
+					return `:"${arr[1].trim()}"`;
+				});
+				try {
+					text = JSON.parse(text);
+				} catch (e) {}
+			}
+			if (this.append) {
+				let pathArr = this.$Route.path.split('/');
+				pathArr.splice(pathArr.length - this.level, this.level);
+				pathArr = pathArr.join('/');
+				if (text.constructor === Object) {
+					if (text.path) {
+						text.path = pathArr + text.path;
+					}
+				} else {
+					text = pathArr + text;
+				}
+			}
+			return text;
+		},
+		gotoPage() {
+			if (this.stopNavto) {
+				return true;
+			}
+			const type = navType[this.navType];
+			if (type == null) {
+				return console.error(` "navType" unknown type \n\n value:${Object.values(navType).join('、')}`);
+			}
+			const navInfo = this.formatNav(this.to);
+
+			this.$Router[type](navInfo);
+		}
+	}
+};
+</script>
+
+<style></style>

+ 35 - 0
plugin/uni-simple-router/helpers/compile.js

@@ -0,0 +1,35 @@
+export const H5 = function (fn) {
+    // #ifdef H5
+    fn();
+    // #endif
+};
+export const APP = function (fn) {
+    // #ifdef APP-PLUS
+    fn();
+    // #endif
+};
+export const applets = function (fn) {
+    // #ifdef MP
+    fn();
+    // #endif
+};
+export const notH5 = function (fn) {
+    // #ifndef H5
+    fn();
+    // #endif
+};
+export const baiduApple = function (fn) {
+    // #ifdef MP-BAIDU
+    fn();
+    // #endif
+};
+export const touTiao = function (fn) {
+    // #ifdef MP-TOUTIAO
+    fn();
+    // #endif
+};
+export const mp = function (fn) {
+    // #ifdef MP
+    fn();
+    // #endif
+};

+ 93 - 0
plugin/uni-simple-router/helpers/config.js

@@ -0,0 +1,93 @@
+
+export const baseConfig = {
+    h5: {
+        rewriteFun: true,	// 是否对uni-app reLaunch/navigateBack 两个方法重写 处理uni刷新直接返回到首页和触发路由守卫
+        paramsToQuery: false, // h5端上通过params传参时规则是vue-router 刷新会丢失 开启此开关将变成?连接的方式
+        loading: true, // 是否显示加载动画
+        hinderTab: false, // 是否拦截uni-app自带底部菜单   TODO
+        vueRouterDev: false, // 完全使用采用vue-router的开发模式
+        useUniConfig: true, // 是否采用在pages.json下的所有页面配置信息,false时需开发者自行设置页面
+        keepUniIntercept: false, // 保留uni-app使用vue-router的拦截器
+        vueNext: false, // 在next管道函数中是否获取vueRouter next的原本参数
+        replaceStyle: false, // 是否对resetStyle函数中返回的style节点进行全部替换,否则为追加
+        resetStyle: () => JSON.parse('{}'), // 自定义加载样式函数 可返回一个包涵 html、style、script 的对象来重置Router内置的加载动画
+        mode: 'hash',
+        base: '/',
+        linkActiveClass: 'router-link-active',
+        linkExactActiveClass: 'router-link-exact-active',
+        scrollBehavior: (to, from, savedPostion) => savedPostion,
+        fallback: true,
+    },
+    APP: {
+        holdTabbar: true,	// 是否开启底部菜单拦截
+        loddingPageStyle: () => JSON.parse('{"backgroundColor":"#FFF"}'),	// 当前等待页面的样式 必须返回一个json
+        loddingPageHook: (view) => { plus.navigator.closeSplashscreen(); view.show(); },		// 刚刚打开页面处于等待状态,会触发此事件
+        animation: { animationType: 'pop-in', animationDuration: 300 },	// 页面切换动画
+        switchPageOutTime: 1000,	// 最高能忍耐的页面切换时间 达到此时间 不管切换有没有完成都会显示页面出来 这对启动页帮助很大
+    },
+    debugger: false, // 是否处于开发阶段 设置为true则打印日志
+    encodeURI: true, // 是否对url传递的参数进行编码
+    routerBeforeEach: () => {}, // router 前置路由函数 每次触发跳转前先会触发此函数
+    routerAfterEach: () => {}, // router 后置路由函数 每次触发跳转后会触发此函数
+    routes: [],
+};
+
+export const methods = {
+    push: 'navigateTo',
+    replace: 'redirectTo',
+    replaceAll: 'reLaunch',
+    pushTab: 'switchTab',
+    back: 'navigateBack',
+};
+
+export const H5FnTypeToggle = {
+    push: 'push',
+    replace: 'replace',
+    replaceAll: 'replace',
+    pushTab: 'replace',
+};
+
+export const lifeCycle = {
+    beforeHooks: [],
+    afterHooks: [],
+    routerHooks: [],
+    routerbeforeHooks: [], // 内部跳转前生命周期
+    routerAfterHooks: [], // 内部跳转后生命周期
+};
+
+export const Global = { // 缓存一些必要的对象,作为全局可以访问的参数
+    $parseQuery: null, // url query 帮助类实例
+    Router: {},
+    vueRouter: {},
+    addedRoutes: [], // 用于缓存用户动态添加的路由
+    RouterReadyPromise: () => {},
+    H5RouterReady: null, // 当前router是否就绪
+    backLayerC: 1,	// 返回api调用时开发者传递的 delta
+    LockStatus: false, // 当前是否正在进行跳转 正在跳转调用api是不给跳转的
+};
+
+export const uniAppHook = {
+    indexVue: {},	// 首页 组件对象
+    toutiaoIndexThis: {}, // 头条小程序Index this对象
+    appVue: {},	// 同getApp()获取到的对象一毛一样的  其实就是app.vue组件
+    onLaunch: {	fun: [], args: {}, isHijack: false }, // 这两个是app.vue
+    onShow: { fun: [], args: {}, isHijack: false },
+    variationFuns: ['onReady', 'onUnload'],	// 一些uni-app的变异方法 需要处理下
+    waitHooks: {},	// 首页等待中的生命钩子 一些需要等待的Hooks,就是在页面没有进来之前一些提前触发的生命钩子 主要是用户已经声明好的
+    indexCallHooks: ['onLoad', 'onReady', 'created', 'onShow'],	// 在首页首次启动时需要触发的生命周期
+    needHooks: ['onLoad', 'onReady', 'onShow', 'created', 'onHide', 'onUnload', 'onResize'],	// 首页需要拦截的生命钩子
+    pageReady: false,
+    onLaunched: false,	// 否触发onLaunch事件
+};
+
+export const appletsConfig = {	// 小程序端的一些路由所需配置
+    onLaunchEd: false,	// 当前小程序端是否触发onLaunch事件
+};
+
+export const route = function (object = {}) {
+    return {
+        ...object,
+        params: {},
+        query: {},
+    };
+};

+ 60 - 0
plugin/uni-simple-router/helpers/mixins.js

@@ -0,0 +1,60 @@
+import { uniAppHook } from './config';
+import H5init from '../vueRouter/init';
+import { appInit, removeBackPressEvent, pageIsHeadBack } from '../appRouter/init';
+import appletsInit from '../appletsRouter/init';
+import { appPlatform } from './util';
+import { proxyIndexHook } from '../appRouter/hooks';
+import { appletsProxyIndexHook } from '../appletsRouter/hooks';
+
+/**
+ * 获取一些需要在各个平台混入的事件
+ * @param {Object} Router 当前原始路由对象
+ */
+const getMixins = function (Router) {
+    return {
+        H5: {
+            beforeCreate() {
+                if (this.$options.router) {
+                    H5init(Router.$root, this.$options.router, this);
+                }
+            },
+        },
+        APP: {
+            onLaunch() {
+                uniAppHook.onLaunched = true;	// 标志已经触发了 onLaunch 事件
+                appInit.call(this, Router.$root);
+            },
+            onLoad() {
+                // 第一个页面 拦截所有生命周期
+                if (uniAppHook.onLaunched && !uniAppHook.pageReady) {
+                    uniAppHook.onLaunched = false;
+                    proxyIndexHook.call(this, Router.$root);
+                }
+                removeBackPressEvent(this.$mp.page, this.$options); // 移除页面的onBackPress事件
+            },
+            onBackPress(...args) {
+                return pageIsHeadBack.call(Router.$root, this.$mp.page, this.$options, args);
+            },
+        },
+        APPLETS: {
+            onLaunch() {
+                uniAppHook.onLaunched = true;	// 标志已经触发了 onLaunch 事件
+                appletsInit.call(this, Router.$root);
+            },
+            onLoad() {
+                if (uniAppHook.onLaunched && !uniAppHook.pageReady) {	// 必须是第一个页面
+                    uniAppHook.onLaunched = false;
+                    appletsProxyIndexHook.call(this, Router.$root);
+                }
+            },
+        },
+    };
+};
+
+const initMixins = function (Vue, Router) {
+    Vue.mixin({
+        ...getMixins(Router)[appPlatform(true)],
+    });
+};
+
+export default initMixins;

+ 103 - 0
plugin/uni-simple-router/helpers/navJump.js

@@ -0,0 +1,103 @@
+import { appPlatform } from './util';
+import { methods, H5FnTypeToggle, Global } from './config';
+import { transitionTo } from '../appRouter/hooks';
+import { appletsTransitionTo, backCallHook } from '../appletsRouter/hooks';
+import uniPushTo from '../appRouter/uniNav';
+import appletsUniPushTo from '../appletsRouter/appletsNav';
+import { err, warn } from './warn';
+import H5PushTo from '../vueRouter/routerNav';
+import * as compile from './compile';
+
+
+/**
+ * 返回api 触发的公共函数
+ * @param {Object/String} rule  当前跳转规则
+ * @param {String} fnType    跳转页面的类型方法
+ *
+ * this 为当前 Router 实例
+ */
+const isBcakNav = function ({
+    backLayer,
+    delta,
+    H5PATCH,
+}) {
+    compile.H5(() => {
+        H5PATCH.on('historyBack', {
+            backLayer,
+            delta,
+        });
+    });
+    compile.APP(() => {
+        Global.backLayerC = backLayer;	// 告诉路由需要返回几层
+        uni.navigateBack({
+            delta: backLayer,
+            complete: () => {
+                Global.LockStatus = false; // 跳转完成解锁状态
+            },
+        });
+    });
+    compile.mp(() => {
+        backCallHook.call(this, backLayer, () => {
+            uni.navigateBack({
+                delta: backLayer,
+            });
+        });
+    });
+};
+
+/**
+ * 非 返回api 触发的公共函数
+ * @param {Object/String} rule  当前跳转规则
+ * @param {String} fnType    跳转页面的类型方法
+ *
+ * this 为当前 Router 实例
+ */
+
+const notBackNav = function (rule, fnType) {
+    if (rule == null) {
+        return err('跳转规则为空,不允许这样操作');
+    }
+    if (rule.constructor === String) { // 单独 path 的情况   允许?拼接参数
+        const ruleArray = rule.split('?');
+        if (ruleArray.length > 1) {
+            rule = {
+                path: ruleArray[0],
+                query: Global.$parseQuery.parse(ruleArray[1]),
+            };
+        }
+    }
+    switch (appPlatform(true)) {
+    case 'H5':
+        return H5PushTo.call(this, H5FnTypeToggle[fnType], rule, methods[fnType]);
+    case 'APP':
+        Global.LockStatus = true; // 设置为锁住状态
+        return transitionTo.call(this, rule, fnType, uniPushTo);
+    case 'APPLETS':
+        Global.LockStatus = true; // 设置为锁住状态
+        return appletsTransitionTo.call(this, rule, fnType, appletsUniPushTo);
+    default:
+        err('糟糕!!!还有其他的执行环境???没听说过啊。一脸懵逼???加QQ群问问:769241495');
+        break;
+    }
+};
+
+/**
+ * 处理正在跳转的公共api
+ * @param {Object/String} rule  当前跳转规则
+ * @param {String} fnType    跳转页面的类型方法
+ * @param {Boolean} isBack  是否通过 back() api 调用的 默认为false
+ * @param {Boolean} enforce 是否强制越过跳转加锁检查 默认false  目前只有back() api 传递了
+ *
+ * this 为当前 Router 实例
+ */
+const navjump = function (rule, fnType, isBack = false, enforce = false) {
+    if (Global.LockStatus && !enforce) { // 正在跳转的状态下 给出提示正在跳转
+        return warn('当前页面正在处于跳转状态,请稍后再进行跳转....');
+    }
+    if (isBack) { // 是返回api触发的
+        return isBcakNav.call(this, rule, fnType);
+    }
+    return notBackNav.call(this, rule, fnType);
+};
+
+export default navjump;

+ 157 - 0
plugin/uni-simple-router/helpers/urlQuery.js

@@ -0,0 +1,157 @@
+import { Global } from './config';
+import { warn, err } from './warn';
+
+const nodeURL = require('query-string');
+
+class ParseQuery {
+    get queryName() {
+        return nodeURL;
+    }
+
+    /**
+     * 判断当前这个对象是否为深度对象
+     * @param {Object} obj
+     */
+    isDepthObject(obj) {
+        const str = JSON.stringify(obj);
+        return str.match(/}/g).length > 1;
+    }
+
+    /**
+     * 从URL中提取查询字符串
+     * @param {String} url
+     */
+    extract(url) {
+        return nodeURL.extract(url);
+    }
+
+    /**
+     * 把一个 key=value&key1=value 的字符串转成对象
+     * @param {string} strQuery key=value&key1=value 类型的字符串
+     */
+    parse(strQuery) {
+        return nodeURL.parse(strQuery);
+    }
+
+    /**
+     * 把一个对象转成 key=value&key1=value 类型的字符串
+     * @param {Object} ObjQuery 符合js标注的对象
+     * @param {Boolean} intact 是否在转成的字符串前添加?号
+     */
+    stringify(ObjQuery, intact = true) {
+        const strQuery = nodeURL.stringify(ObjQuery);
+        if (intact) {
+            return `?${strQuery}`;
+        }
+        return strQuery;
+    }
+
+    /**
+     * 把一个对象或者 key=value&key1=value 类型的数据加密成 query=encodeURIComponent(value)
+     * @param {Object|String} query 符合js标注的对象 或者 key=value&key1=value 字符串
+     * @param {Boolean} intact 是否在转成的字符串前添加?号
+     */
+    encode(query, intact = true) {
+        let [strQuery, formatQuery] = ['', ''];
+        if (query == null) {
+            warn('加密参数没有传递,你知道?', true);
+            return '';
+        }
+        if (query.constructor === String) { // 字符串 尝试 转成 对象
+            strQuery = JSON.stringify(this.parse(query));
+        } else if (query.constructor === Object) { // 直接转成字符串对象即可
+            if (Object.keys(query).length === 0) {
+                warn('当前参数不满足加密规范!');
+                return '';
+            }
+            strQuery = JSON.stringify(query);
+        }
+        if (intact) {
+            formatQuery = '?';
+        }
+        formatQuery += `query=${encodeURIComponent(strQuery)}`;
+        return formatQuery;
+    }
+
+    /**
+     * 把一个已经加密好的字符串 query=encodeURIComponent(value) 解密成 对象
+     * @param {string} strQuery  已经加密好的字符串 query=encodeURIComponent(value)
+     */
+    decode(strQuery) {
+        if (strQuery == null) {
+            warn('解密参数没有传递,你知道?', true);
+            return {};
+        }
+        let jsonQuery = strQuery;
+        if (strQuery.constructor === Object) { // 如果是对象 看能不能满足要求
+            jsonQuery = strQuery.query;
+            if (jsonQuery == null) {
+                warn('当前解密参数不满足编码规则');
+                return {};
+            }
+            jsonQuery = `query=${jsonQuery}`;
+        }
+        let decode = {};
+        // query 长这个样  query=encodeURIComponent(value)
+        const decodeStr = decodeURIComponent(jsonQuery);
+        const { query } = this.parse(decodeStr); // 转成 json 获取到正真的json字符串
+        if (query == null) {
+            warn('当前解密参数不满足编码规则');
+        } else {
+            try {
+                decode = JSON.parse(query);
+            } catch (error) {
+                warn('当前解密参数不满足编码规则');
+            }
+        }
+        return decode;
+    }
+
+    queryGet(query) {
+        const { encodeURI } = Global.Router.CONFIG; // 获取到路由配置
+        let [decode, historyObj, strQuery] = [query, query, ''];
+        switch (encodeURI) {
+        case true: { // 加密模式
+            decode = this.decode(query);
+            strQuery = this.encode(decode);
+            historyObj = {
+                query: encodeURIComponent(JSON.stringify(decode)),
+            };
+            break;
+        }
+        case false: { // 不加密模式
+            strQuery = this.stringify(query);
+            break;
+        }
+        default: {
+            err('未知参数模式,请检查 \'encodeURI\'', true);
+        }
+        }
+        return { strQuery, historyObj, decode };
+    }
+
+
+    /**
+     * 对需要传递的参数进行加密解密
+     * @param {Object|String} query get为false 必须为 Object 类型
+     * @param {String} get 是取值 还是通过api传值
+     */
+    transfer(query = {}) {
+        const { encodeURI } = Global.Router.CONFIG; // 获取到路由配置
+        switch (encodeURI) {
+        case true: {
+            // 加密模式
+            return this.encode(query, false);
+        }
+        case false: {
+            // 不加密模式
+            return this.stringify(query);
+        }
+        default: {
+            err('未知参数模式,请检查 \'encodeURI\' ', true);
+        }
+        }
+    }
+}
+
+export default ParseQuery;

+ 255 - 0
plugin/uni-simple-router/helpers/util.js

@@ -0,0 +1,255 @@
+import { route, baseConfig, Global } from './config';
+import { builtIn } from '../vueRouter/base';
+import { err, log, warn } from './warn';
+
+/**
+ * 当前是不是H5运行环境
+ */
+export const isH5 = function () {
+    return typeof window !== 'undefined' && typeof document !== 'undefined';
+};
+/**
+ * 判断当前变量是否为Object
+ * @param {Object} strObj
+ */
+export const isObject = function (strObj) {
+    return strObj.toString() === '[object Object]' && strObj.constructor === Object;
+};
+/**
+ * 获取当前运行平台
+ * @param {Boolean} applets 默认false  true时所有小程序平台统一返回 APPLETS
+ */
+export const appPlatform = function (applets = false) {
+    let platform = '';
+
+    // #ifdef APP-PLUS-NVUE
+    platform = 'APPNVUE';
+    // #endif
+
+    // #ifdef APP-PLUS
+    platform = 'APP';
+    // #endif
+
+    // #ifdef H5
+    platform = 'H5';
+    // #endif
+
+    // #ifdef MP-ALIPAY
+    platform = 'ALIPAY';
+    // #endif
+
+    // #ifdef MP-BAIDU
+    platform = 'BAIDU';
+    // #endif
+
+    // #ifdef MP-QQ
+    platform = 'QQ';
+    // #endif
+
+    // #ifdef MP-WEIXIN
+    platform = 'WEIXIN';
+    // #endif
+
+    // #ifdef MP-TOUTIAO
+    platform = 'TOUTIAO';
+    // #endif
+
+    if (applets) {
+        // #ifdef MP
+        platform = 'APPLETS';
+        // #endif
+    }
+
+    return platform;
+};
+/**
+ * 定义一个空方法 如果最后一个参数为true则打印所有参数
+ * @param  {...any} args
+ */
+export const noop = function (...args) {
+    if (args[args.length - 1] === true) {
+        log(args);
+    }
+};
+/**
+ * 格式化基础配置信息 通过new Router传递过来的参数
+ */
+export const formatConfig = function (userConfig) {
+    if (!userConfig.routes || userConfig.routes.constructor !== Array) {
+        return err(`路由参数 'routes' 必须传递 \r\n\r\n${JSON.stringify(userConfig)}`);
+    }
+    if (userConfig.h5 != null && userConfig.h5.constructor !== Object) {
+        return err(`h5参数传递错误,应该是一个 'Object' 类型 示例:\r\n\r\n${JSON.stringify(baseConfig.h5)}`);
+    }
+    const config = Object.create(null);
+    const baseConfigKeys = Object.keys(baseConfig);
+    for (let i = 0; i < baseConfigKeys.length; i += 1) {
+        const key = baseConfigKeys[i];
+        if (userConfig[key] != null) {
+            if (userConfig[key].constructor === Object) {
+                config[key] = {
+                    ...baseConfig[key],
+                    ...userConfig[key],
+                };
+            } else if (key == 'routes') { // 需要加入已知的白名单
+                config[key] = [...baseConfig[key], ...userConfig[key], ...builtIn];
+            } else {
+                config[key] = userConfig[key];
+            }
+        } else {
+            config[key] = baseConfig[key];
+        }
+    }
+    return config;
+};
+export const filter = function (str) {
+    str += '';
+    str = str.replace(/%/g, '%25');
+    str = str.replace(/\+/g, '%2B');
+    str = str.replace(/ /g, '%20');
+    str = str.replace(/\//g, '%2F');
+    str = str.replace(/\?/g, '%3F');
+    str = str.replace(/&/g, '%26');
+    str = str.replace(/=/g, '%3D');
+    str = str.replace(/#/g, '%23');
+    return str;
+};
+/**
+ * 使用encodeURI:true的情况	需要进行编码后再传递,解码等等 可以传递深度对象并会在路径后面加入一个query=
+ *
+ * @param {String} routerName //路径名称
+ * @param {JSON} query 	//需要格式化参数
+ * @param {Boolean} Encode 	//是获取还是编码后传递
+ */
+export const parseQueryN = function (routerName, query, Encode) {
+    if (Encode) {
+        return {
+            url: routerName,
+            query: JSON.parse(decodeURIComponent(query.replace(/^query=/, ''))),
+        };
+    }
+    return {
+        url: routerName,
+        query: `query=${encodeURIComponent(JSON.stringify(query))}`,
+    };
+};
+/**
+ * 使用encodeURI:false的情况 直接格式化为普通的queryURl参数形式传递即可 扁平深度对象
+ *
+ * @param {String} routerName //路径名称
+ * @param {JSON} query 	//需要格式化参数
+ * @param {Boolean} Encode 	//是获取还是编码后传递
+ */
+export const parseQueryD = function (routerName, query, Encode) {
+    if (Encode) {
+        const obj = {};
+        const reg = /([^=&\s]+)[=\s]*([^&\s]*)/g;
+        while (reg.exec(query)) {
+            obj[RegExp.$1] = RegExp.$2;
+        }
+        return {
+            url: routerName,
+            query: obj,
+        };
+    }
+    const encodeArr = [];
+    const queryKeys = Object.keys(query);
+    for (let i = 0; i < queryKeys.length; i += 1) {
+        const attr = queryKeys[i];
+        let encodeStr = '';
+        if (query[attr].constructor == Object) {
+            encodeStr = parseQueryD(routerName, query[attr], Encode).query;
+            encodeArr.push(encodeStr);
+        } else {
+            encodeStr = filter(query[attr]);
+            encodeArr.push(`${attr}=${encodeStr}`);
+        }
+    }
+    return {
+        url: routerName,
+        query: encodeArr.join('&'),
+    };
+};
+/**
+ * @param {String} routerName //路径名称
+ * @param {JSON} query 	//需要格式化参数
+ * @param {Boolean} Encode 	//是获取还是编码后传递
+ */
+export const parseQuery = function (routerName, query, Encode = false) {
+    if (Global.Router.CONFIG.encodeURI) {
+        return parseQueryN(routerName, query, Encode);
+    }
+    return parseQueryD(routerName, query, Encode);
+};
+
+export const exactRule = function (cloneRule, routes, ruleKey, getRule = false) {
+    const params = {};
+    let i = 0;
+    // eslint-disable-next-line
+    while (true) {
+        const item = routes[i];
+        if (item == null) {
+            if (!getRule) {
+                err(`路由表中未查找到 '${ruleKey}' 为 '${cloneRule[ruleKey]}'`);
+            }
+            return {
+                path: '',
+                name: '',
+            };
+        }
+        if (item[ruleKey] != null && item[ruleKey] === cloneRule[ruleKey]) {
+            if (!getRule) {
+                params.url = item.path;
+                params.rule = item;
+                if (isH5()) { // 如果是h5 则使用优先使用自定义路径名称
+                    params.url = item.aliasPath || item.path;
+                }
+                return params;
+            }
+            return item;
+        }
+        i += 1;
+    }
+};
+
+export const resolveRule = function (router, rule, query = {}, ruleKey = 'path') {
+    const ruleInfo = route(
+        exactRule({
+            ...rule,
+        },
+        router.CONFIG.routes,
+        ruleKey,
+        router),
+    );
+    return {
+        ...ruleInfo,
+        query,
+    };
+};
+/**
+ * 把一些不必要的参数进行格式化掉,完成url的美观
+ * @param {String} URLQuery URL中传递的参数
+ */
+export const formatURLQuery = function (URLQuery) {
+    switch (URLQuery.trim()) {
+    case 'query=%7B%7D':
+    case '%7B%7D':
+    case '?query=%7B%7D':
+    case '?':
+    case '?[object Object]':
+    case '?query={}':
+        URLQuery = '';
+        break;
+    default:
+        warn('url已经很完美啦,不需要格式化!');
+        break;
+    }
+    return URLQuery;
+};
+/**
+ * 拷贝对象
+ * @param {Object} object
+ */
+export const copyObject = function (object) {
+    return JSON.parse(JSON.stringify(object));
+};

+ 34 - 0
plugin/uni-simple-router/helpers/warn.js

@@ -0,0 +1,34 @@
+import { Global } from './config';
+
+
+const isLog = function (type, errText, enforce) {
+    if (!enforce) {
+        const dev = Global.Router.CONFIG.debugger;
+        const isObject = dev.toString() === '[object Object]';
+        if (dev === false) {
+            return false;
+        } if (dev === false) {
+            return false;
+        } if (isObject) {
+            if (dev[type] === false) {
+                return false;
+            }
+        }
+    }
+    /* eslint no-console:"off" */
+    console[type](errText);
+};
+export const err = function (errInfo, enforce = false) {
+    isLog('error', errInfo, enforce);
+};
+
+export const warn = function (errInfo, enforce = false) {
+    isLog('warn', errInfo, enforce);
+};
+
+export const log = function (errInfo, enforce = false) {
+    isLog('log', errInfo, enforce);
+};
+export const warnLock = function (errInfo) {
+    console.warn(errInfo);
+};

+ 177 - 0
plugin/uni-simple-router/index.js

@@ -0,0 +1,177 @@
+import { isH5, formatConfig, appPlatform } from './helpers/util';
+import navjump from './helpers/navJump';
+import { H5GetPageRoute } from './vueRouter/util';
+import { APPGetPageRoute } from './appRouter/util';
+import { AppletsPageRoute } from './appletsRouter/util';
+import { lifeCycle, Global } from './helpers/config';
+import { warn, err } from './helpers/warn';
+import { registerRouterHooks, registerHook } from './lifeCycle/hooks';
+import { vueMount } from './vueRouter/base';
+import appletsMount from './patch/applets-patch';
+import appMount from './patch/app-patch';
+import initMixins from './helpers/mixins';
+import ParseQuery from './helpers/urlQuery';
+// #ifdef H5
+import H5 from './patch/h5-patch';
+// #endif
+
+let H5PATCH = null;
+// #ifdef H5
+H5PATCH = new H5(isH5());
+// #endif
+
+const parseQuery = new ParseQuery();
+
+Global.H5RouterReady = new Promise((resolve) => Global.RouterReadyPromise = resolve);
+
+class Router {
+    constructor(arg) {
+        Router.$root = this;
+        Global.Router = this; // 全局缓存一个对象,不必使用时都传递
+        Global.$parseQuery = parseQuery;
+        this.CONFIG = formatConfig(arg);
+        this.lifeCycle = lifeCycle;
+        registerRouterHooks.call(this);	// 注册全局Router生命钩子
+        if (appPlatform() === 'H5') {
+            H5PATCH.setLoadingStatus(this.CONFIG.h5);
+        }
+    }
+
+    get $Route() {
+        return this.getPageRoute();
+    }
+
+    /**
+     * 获取 url 参数帮助类实例
+     */
+    get $parseQuery() {
+        return Global.$parseQuery;
+    }
+
+    /**
+     * 获取当前是否处于正在跳转的状态
+     * H5 状态下始终为false
+     */
+    get $lockStatus() {
+        return Global.LockStatus;
+    }
+
+    /**
+     * 动态设置拦截状态
+     */
+    set $lockStatus(status) {
+        warn('你确定要这么做?你知道后果?', true);
+        Global.LockStatus = status;
+    }
+
+    /** 动态的导航到一个新 URL 保留浏览历史
+	 * navigateTo
+	 * @param {Object} rule
+	 */
+    push(rule) {
+        navjump.call(this, rule, 'push');
+    }
+
+    /** 动态的导航到一个新 URL 关闭当前页面,跳转到的某个页面。
+	 * redirectTo
+	 * @param {Object} rule
+	 */
+    replace(rule) {
+        navjump.call(this, rule, 'replace');
+    }
+
+    /** 动态的导航到一个新 URL 关闭所有页面,打开到应用内的某个页面
+	 * 	reLaunch
+	 * @param {Object} rule
+	 */
+    replaceAll(rule) {
+        navjump.call(this, rule, 'replaceAll');
+    }
+
+    /** 动态的导航到一个新 url 关闭所有页面,打开到应用内的某个tab
+	 * @param {Object} rule
+	 */
+    pushTab(rule) {
+        navjump.call(this, rule, 'pushTab');
+    }
+
+    /**
+	 * 返回到指定层级页面上
+     * @param {Number} backLayer 需要返回的页面层级 默认 1
+     * @param {Object} delta 暂时无用
+     * @param {enforce} 是否强制越过跳转加锁检查 默认 false
+	 */
+    back(backLayer = 1, delta, enforce = false) {
+        if (backLayer.constructor != Number) {
+            return err(
+                `返回层级参数必须是一个Number类型且必须大于1:${backLayer}`,
+            );
+        }
+        navjump.call(this, {
+            backLayer, delta, H5PATCH,
+        }, 'back', true, enforce);
+    }
+
+    /**
+	 * 获取当前页面下的 Route 信息
+	 *
+	 * @param {Object} Vim 当前开发者可以传递一个 vue 组件对象 来获取当前下的 Route 信息
+	 */
+    getPageRoute(Vim) {
+        const pages = getCurrentPages();
+        switch (appPlatform(true)) {
+        case 'H5':
+            return H5GetPageRoute.call(this, pages, Vim);
+        case 'APP':
+            return APPGetPageRoute(pages, Vim);
+        case 'APPLETS':
+            return AppletsPageRoute(pages, Vim);
+        default:
+            break;
+        }
+    }
+
+    beforeEach(fn) {
+        return registerHook(this.lifeCycle.beforeHooks, fn);
+    }
+
+    afterEach(fn) {
+        return registerHook(this.lifeCycle.afterHooks, fn);
+    }
+}
+
+Router.install = function (Vue) {
+    initMixins(Vue, Router);
+    Object.defineProperty(Vue.prototype, '$Router', {
+        get() {
+            return Router.$root;
+        },
+    });
+    Object.defineProperty(Vue.prototype, '$Route', {
+        get() {
+            return Router.$root.getPageRoute(this);
+        },
+    });
+};
+export default Router;
+/**
+ *
+ * @param {VueComponent } Vim vue实例对象
+ * @param {dom} el	dom节点选择器
+ */
+export const RouterMount = function (Vim, el) {
+    switch (appPlatform(true)) {
+    case 'APP':
+        appMount(Vim, el);
+        break;
+    case 'APPLETS':
+        appletsMount(Vim, el);
+        break;
+    case 'H5':
+        vueMount.push({ Vim, el });
+        break;
+    default:
+        warn('糟糕!!!还有其他的执行环境???没听说过啊。一脸懵逼???加QQ群问问:769241495');
+        break;
+    }
+};

+ 38 - 0
plugin/uni-simple-router/lifeCycle/hooks.js

@@ -0,0 +1,38 @@
+import { appPlatform, isH5 } from '../helpers/util';
+
+// #ifdef H5
+import H5 from '../patch/h5-patch';
+
+const H5PATCH = new H5(isH5());
+// #endif
+
+export const registerHook = function (list, fn) {
+    list.push(fn);
+    return () => {
+        const i = list.indexOf(fn);
+        if (i > -1) list.splice(i, 1);
+    };
+};
+/**
+ * 注册全局Router生命钩子
+ */
+export const registerRouterHooks = function () {
+    registerHook(this.lifeCycle.routerbeforeHooks, function () {
+        return new Promise(async (resolve) => {
+            this.CONFIG.routerBeforeEach(); // 触发暴露给开发者的生命钩子
+            if (appPlatform(true) === 'H5') {
+                H5PATCH.on('toogle', 'startLodding');
+            }
+            return resolve(true);
+        });
+    });
+    registerHook(this.lifeCycle.routerAfterHooks, function (res = {}) {
+        if (res.H5Intercept !== true) {
+            this.CONFIG.routerAfterEach(); // 触发暴露给开发者的生命钩子
+        }
+        if (appPlatform(true) === 'H5') {
+            H5PATCH.on('toogle', 'stopLodding');
+        }
+        return true;
+    });
+};

+ 33 - 0
plugin/uni-simple-router/package.json

@@ -0,0 +1,33 @@
+{
+    "name": "uni-simple-router",
+    "version": "1.5.5",
+    "description": "> 一个更为简洁的[Vue-router](https://router.vuejs.org/zh/),专为 [uni-app](https://uniapp.dcloud.io/) 量身打造",
+    "main": "index.js",
+    "directories": {
+      "example": "examples"
+    },
+    "scripts": {
+      "postinstall": "node -e \"console.log('\\x1B[32m \\x1B[1m','\\n 欢迎下载 uni-simple-router ↓↓↓↓ \\n\\n  注意事项:\\n   1: 编译为app端如果开启V3,请关闭fast启动模式 \\n   2: 多看文档,特别是‘快速上手’栏目。文档地址:http://hhyang.cn/ \\n   3: 不要再问路由表是否可以不配置两遍。问就是文档有!\\n   4: 有啥问题解决不了的加群:769241495 \\n   5: 任何时候你都可以在github上提出你的想法及问题,相信我很快会得到回应 \\n\\n  showTime:\\n   1:开源不易,需要鼓励。去给 uni-simple-router 项目 点个 star 吧 \\n')\""
+    },
+    "dependencies": {
+      "query-string": "^6.12.1"
+    },
+    "repository": {
+      "type": "git",
+      "url": "git+https://github.com/SilurianYang/uni-simple-router.git"
+    },
+    "keywords": [
+      "router",
+      "uni-app-router",
+      "interceptor",
+      "uni-app",
+      "uniapp"
+    ],
+    "author": "hhyang",
+    "license": "MIT",
+    "bugs": {
+      "url": "https://github.com/SilurianYang/uni-simple-router/issues"
+    },
+    "homepage": "https://github.com/SilurianYang/uni-simple-router#readme",
+    "types": "./types/index.d.ts"
+  }

+ 8 - 0
plugin/uni-simple-router/patch/app-patch.js

@@ -0,0 +1,8 @@
+/**
+ * 截止 1.3.5 版本 不做任何操作
+ * @param {element} el dom节点
+ */
+const appMount = function (Vim) {
+    Vim.$mount();
+};
+export default appMount;

+ 10 - 0
plugin/uni-simple-router/patch/applets-patch.js

@@ -0,0 +1,10 @@
+
+/**
+ * 截止 1.3.5 版本 不做任何操作
+ * @param {element} el dom节点
+ */
+const appletsMount = function (Vim) {
+    Vim.$mount();
+};
+
+export default appletsMount;

Некоторые файлы не были показаны из-за большого количества измененных файлов