lhl 2 years ago
commit
4d68810fa7
100 changed files with 33480 additions and 0 deletions
  1. 26 0
      .gitignore
  2. 472 0
      App.vue
  3. 284 0
      README.md
  4. 28 0
      androidPrivacy.json
  5. 329 0
      api/activity.js
  6. 442 0
      api/admin.js
  7. 461 0
      api/api.js
  8. 19 0
      api/esp.js
  9. 123 0
      api/kefu.js
  10. 43 0
      api/lottery.js
  11. 305 0
      api/new_store.js
  12. 387 0
      api/order.js
  13. 20 0
      api/points_mall.js
  14. 167 0
      api/public.js
  15. 93 0
      api/short-video.js
  16. 331 0
      api/store.js
  17. 731 0
      api/user.js
  18. 101 0
      api/work.js
  19. 60 0
      components/Loading/index.vue
  20. 202 0
      components/addressWindow/index.vue
  21. 345 0
      components/authorize/index.vue
  22. 142 0
      components/cartDiscount/index.vue
  23. 218 0
      components/cartList/index.vue
  24. 134 0
      components/countDown/index.vue
  25. 282 0
      components/couponListWindow/index.vue
  26. 248 0
      components/couponWindow/index.vue
  27. 150 0
      components/cusPreviewImg/index.vue
  28. 91 0
      components/customForm/index.vue
  29. 187 0
      components/d_goodList/index.vue
  30. 49 0
      components/emptyPage.vue
  31. 185 0
      components/ewcomerPop/index.vue
  32. 310 0
      components/filterPopup/index.vue
  33. 221 0
      components/goodClass/index.vue
  34. 158 0
      components/goodList/index.vue
  35. 157 0
      components/guide/index.vue
  36. 131 0
      components/home/index.vue
  37. 152 0
      components/homeList/index.vue
  38. 814 0
      components/jyf-parser/jyf-parser.vue
  39. 102 0
      components/jyf-parser/libs/CssHandler.js
  40. 577 0
      components/jyf-parser/libs/MpHtmlParser.js
  41. 80 0
      components/jyf-parser/libs/config.js
  42. 35 0
      components/jyf-parser/libs/handler.sjs
  43. 44 0
      components/jyf-parser/libs/handler.wxs
  44. 476 0
      components/jyf-parser/libs/trees.vue
  45. 143 0
      components/kefu/index.vue
  46. 89 0
      components/kefuIcon/index.vue
  47. 330 0
      components/loginMobile/index.vue
  48. 163 0
      components/loginMobile/routine_phone.vue
  49. 215 0
      components/maramlee-waterfalls-flow/maramlee-waterfalls-flow.vue
  50. 476 0
      components/orderGoods/index.vue
  51. 149 0
      components/pageFooter/index.vue
  52. 472 0
      components/payment/index.vue
  53. 186 0
      components/productConSwiper/index.vue
  54. 781 0
      components/productWindow/index.vue
  55. 121 0
      components/recommend/index.vue
  56. 198 0
      components/skeleton/index.vue
  57. 246 0
      components/splitOrder/index.vue
  58. 197 0
      components/storeLis/index.vue
  59. 181 0
      components/thorui/tui-collapse.vue
  60. 140 0
      components/thorui/tui-drawer.vue
  61. 178 0
      components/thorui/tui-list-cell.vue
  62. 195 0
      components/timeSlot/index.vue
  63. 546 0
      components/uni-calendar/calendar.js
  64. 152 0
      components/uni-calendar/uni-calendar-item.vue
  65. 434 0
      components/uni-calendar/uni-calendar.vue
  66. 327 0
      components/uni-calendar/util.js
  67. 398 0
      components/uniNoticeBar/uni-notice-bar.vue
  68. 253 0
      components/userEvaluation/index.vue
  69. 11 0
      components/verify/utils/ase.js
  70. 6191 0
      components/verify/utils/crypto-js.js
  71. 432 0
      components/verify/verify.vue
  72. 467 0
      components/verify/verifyPoint/verifyPoint.vue
  73. 582 0
      components/verify/verifySlider/verifySlider.vue
  74. 1201 0
      components/zb-code/qrcode.js
  75. 210 0
      components/zb-code/zb-code.vue
  76. 49 0
      config/app.js
  77. 42 0
      config/cache.js
  78. 18 0
      config/socket.js
  79. 33 0
      index.html
  80. 272 0
      js_sdk/wa-permission/permission.js
  81. 138 0
      libs/login.js
  82. 9 0
      libs/network.js
  83. 259 0
      libs/new_chat.js
  84. 38 0
      libs/order.js
  85. 252 0
      libs/routine.js
  86. 334 0
      libs/wechat.js
  87. 117 0
      libs/work.js
  88. 85 0
      main.js
  89. 237 0
      manifest.json
  90. 37 0
      mixins/SendVerifyCode.js
  91. 37 0
      mixins/color.js
  92. 399 0
      package-lock.json
  93. 1948 0
      pages.json
  94. 261 0
      pages/activity/bargain/index.vue
  95. 184 0
      pages/activity/components/giftGoods/index.vue
  96. 323 0
      pages/activity/discount/index.vue
  97. 95 0
      pages/activity/goods_bargain/index.vue
  98. 422 0
      pages/activity/goods_bargain_details/index.vue
  99. 369 0
      pages/activity/goods_combination/index.vue
  100. 1946 0
      pages/activity/goods_combination_details/index.vue

+ 26 - 0
.gitignore

@@ -0,0 +1,26 @@
+.DS_Store
+node_modules
+/dist
+
+# local env files
+.env.local
+.env.*.local
+.history
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+build.sh
+.idea
+unpackage
+project.config.json
+.hbuilderx

+ 472 - 0
App.vue

@@ -0,0 +1,472 @@
+<script>
+	import {
+		checkLogin
+	} from './libs/login';
+	import {
+		HTTP_REQUEST_URL
+	} from './config/app';
+	import {
+		getShopConfig,
+		silenceAuth
+	} from '@/api/public';
+	import Auth from '@/libs/wechat.js';
+	import Routine from './libs/routine.js';
+	import {
+		colorChange
+	} from '@/api/api.js';
+	import {
+		mapGetters
+	} from "vuex"
+	// #ifdef MP
+	// let livePlayer = requirePlugin('live-player-plugin')
+	// #endif
+	let green =
+		'--view-theme: #42CA4D;--view-priceColor:#FF7600;--view-minorColor:rgba(108, 198, 94, 0.5);--view-minorColorT:rgba(66, 202, 77, 0.1);--view-bntColor:#FE960F;--view-assistColor:#FE960F;'
+	let red =
+		'--view-theme: #e93323;--view-priceColor:#e93323;--view-minorColor:rgba(233, 51, 35, 0.5);--view-minorColorT:rgba(233, 51, 35, 0.1);--view-bntColor:#FE960F;--view-assistColor:#FE960F;'
+	let blue =
+		'--view-theme: #1DB0FC;--view-priceColor:#FD502F;--view-minorColor:rgba(58, 139, 236, 0.5);--view-minorColorT:rgba(9, 139, 243, 0.1);--view-bntColor:#22CAFD;--view-assistColor:#C4D9EC;'
+	let pink =
+		'--view-theme: #FF448F;--view-priceColor:#FF448F;--view-minorColor:rgba(255, 68, 143, 0.5);--view-minorColorT:rgba(255, 68, 143, 0.1);--view-bntColor:#282828;--view-assistColor:#FEAC41;'
+	let orange =
+		'--view-theme: #FE5C2D;--view-priceColor:#FE5C2D;--view-minorColor:rgba(254, 92, 45, 0.5);--view-minorColorT:rgba(254, 92, 45, 0.1);--view-bntColor:#FDB000;--view-assistColor:#FDB000;'
+
+
+	export default {
+		globalData: {
+			spid: 0,
+			code: 0,
+			isLogin: false,
+			userInfo: {},
+			MyMenus: [],
+			globalData: false,
+			isIframe: false,
+			tabbarShow: true,
+			windowHeight: 0
+		},
+		computed: mapGetters(['isLogin', 'cartNum']),
+		watch: {
+			isLogin: {
+				deep: true, //深度监听设置为 true
+				handler: function(newV, oldV) {
+					if (newV) {
+						// this.getCartNum()
+					} else {
+						this.$store.commit('indexData/setCartNum', '')
+					}
+				}
+			},
+			cartNum(newCart, b) {
+				this.$store.commit('indexData/setCartNum', newCart + '')
+				if (newCart > 0) {
+					uni.setTabBarBadge({
+						index: 3,
+						text: newCart + ''
+					})
+				} else {
+					uni.hideTabBarRedDot({
+						index: 3
+					})
+				}
+			}
+		},
+		onLaunch: async function(option) {
+			//#ifdef APP
+			plus.screen.lockOrientation("portrait-primary");
+			//#endif
+			let that = this;
+			colorChange('color_change').then(res => {
+				let navigation = res.data.navigation; //判断悬浮导航是否显示
+				let statusColor = res.data.status; //判断显示啥颜色
+				uni.setStorageSync('navigation', navigation);
+				uni.$emit('navOk', navigation);
+				uni.setStorageSync('statusColor', statusColor);
+				uni.$emit('colorOk', statusColor);
+				switch (res.data.status) {
+					case 1:
+						uni.setStorageSync('viewColor', blue)
+						uni.$emit('ok', blue)
+						break;
+					case 2:
+						uni.setStorageSync('viewColor', green)
+						uni.$emit('ok', green)
+						break;
+					case 3:
+						uni.setStorageSync('viewColor', red)
+						uni.$emit('ok', red)
+						break;
+					case 4:
+						uni.setStorageSync('viewColor', pink)
+						uni.$emit('ok', pink)
+						break;
+					case 5:
+						uni.setStorageSync('viewColor', orange)
+						uni.$emit('ok', orange)
+						break;
+					default:
+						uni.setStorageSync('viewColor', red)
+						uni.$emit('ok', red)
+						break
+				}
+			});
+			if (option.query.pid) {
+				that.$Cache.set('spread', option.query.pid);
+			}
+			if (option.query.spread) {
+				that.$Cache.set('spread', option.query.spread);
+				that.globalData.spid = option.query.spread;
+				that.globalData.pid = option.query.spread;
+			}
+			// #ifdef APP-PLUS || H5
+			uni.getSystemInfo({
+				success: function(res) {
+					// 首页没有title获取的整个页面的高度,里面的页面有原生标题要减掉就是视口的高度
+					// 状态栏是动态的可以拿到 标题栏是固定写死的是44px
+					let height = res.windowHeight - res.statusBarHeight - 44
+					// #ifdef H5 || APP-PLUS
+					that.globalData.windowHeight = res.windowHeight + 'px'
+					// #endif
+					// // #ifdef APP-PLUS
+					// that.globalData.windowHeight = height + 'px'
+					// // #endif
+
+				}
+			});
+			// #endif	
+			// #ifdef MP
+			if (HTTP_REQUEST_URL == '') {
+				console.error(
+					"请配置根目录下的config.js文件中的 'HTTP_REQUEST_URL'\n\n请修改开发者工具中【详情】->【AppID】改为自己的Appid\n\n请前往后台【小程序】->【小程序配置】填写自己的 appId and AppSecret"
+				);
+				return false;
+			}
+			if (option.query.hasOwnProperty('scene')) {
+
+				switch (option.scene) {
+					//扫描小程序码
+					case 1047:
+						let val = that.$util.getUrlParams(decodeURIComponent(option.query.scene));
+						that.globalData.code = val.pid === undefined ? val : val.pid;
+						break;
+						//长按图片识别小程序码
+					case 1048:
+						that.globalData.code = option.query.scene;
+						break;
+						//手机相册选取小程序码
+					case 1049:
+						that.globalData.code = option.query.scene;
+						break;
+						//直接进入小程序
+					case 1001:
+						that.globalData.spid = option.query.scene;
+						break;
+				}
+			}
+			const updateManager = wx.getUpdateManager();
+
+			updateManager.onCheckForUpdate(function(res) {
+				// 请求完新版本信息的回调
+			});
+
+			updateManager.onUpdateReady(function() {
+				wx.showModal({
+					title: '更新提示',
+					content: '新版本已经准备好,是否重启应用?',
+					success: function(res) {
+						if (res.confirm) {
+							// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
+							updateManager.applyUpdate();
+						}
+					}
+				});
+			});
+
+			updateManager.onUpdateFailed(function() {
+				return that.Tips({
+					title: '新版本下载失败'
+				});
+			});
+			// #endif
+			// getShopConfig().then(res => {
+			// 	this.$store.commit('SETPHONESTATUS', res.data.status);
+			// });
+			// 获取导航高度;
+			uni.getSystemInfo({
+				success: function(res) {
+					that.globalData.navHeight = res.statusBarHeight * (750 / res.windowWidth) + 91;
+				}
+			});
+			// #ifdef MP
+			let menuButtonInfo = uni.getMenuButtonBoundingClientRect();
+			that.globalData.navH = menuButtonInfo.top * 2 + menuButtonInfo.height / 2;
+			const version = uni.getSystemInfoSync().SDKVersion
+			if (Routine.compareVersion(version, '2.21.2') >= 0) {
+				console.log(version)
+				that.$Cache.set('MP_VERSION_ISNEW', true)
+			} else {
+				that.$Cache.set('MP_VERSION_ISNEW', false)
+			}
+			// #endif
+
+			// #ifdef H5
+			// 添加crmeb chat 统计
+			var __s = document.createElement('script');
+			__s.src = `${HTTP_REQUEST_URL}/api/get_script`;
+			document.head.appendChild(__s);
+
+			uni.getSystemInfo({
+				success(e) {
+					/* 窗口宽度大于420px且不在PC页面且不在移动设备时跳转至 PC.html 页面 */
+					if (e.windowWidth > 420 && !window.top.isPC && !/iOS|Android/i.test(e.system)) {
+						window.location.pathname = '/static/html/pc.html';
+					}
+				}
+			});
+			if (option.query.hasOwnProperty('type')) {
+				this.globalData.isIframe = true;
+			} else {
+				this.globalData.isIframe = false;
+			}
+
+			if (window.location.pathname !== '/' && !this.isWork()) {
+				let snsapiBase = 'snsapi_base';
+				let urlData = location.pathname + location.search;
+				if (!that.$store.getters.isLogin && uni.getStorageSync('authIng')) {
+					uni.setStorageSync('authIng', false)
+				}
+				if (!that.$store.getters.isLogin && Auth.isWeixin()) {
+					let code,
+						state,
+						scope = ''
+
+					if (option.query.code instanceof Array) {
+						code = option.query.code[option.query.code.length - 1]
+					} else {
+						code = option.query.code
+					}
+
+
+					if (code && code != uni.getStorageSync('snsapiCode') && location.pathname.indexOf(
+							'/pages/users/wechat_login/index') === -1) {
+						// 存储静默授权code
+						uni.setStorageSync('snsapiCode', code);
+						let spread = that.globalData.spid ? that.globalData.spid : '';
+
+						try {
+							let res = await silenceAuth({
+								code: code,
+								snsapi: 'snsapi_base',
+								spread: that.$Cache.get('spread'),
+								spid: that.globalData.code
+							});
+							uni.setStorageSync('snRouter', decodeURIComponent(decodeURIComponent(option.query
+								.back_url)));
+							if (res.data.key !== undefined && res.data.key) {
+								this.$Cache.set('snsapiKey', res.data.key);
+							} else {
+								let time = res.data.expires_time - this.$Cache.time();
+								this.$store.commit('LOGIN', {
+									token: res.data.token,
+									time: time
+								});
+
+								this.$store.commit('SETUID', res.data.userInfo.uid);
+								this.$store.commit('UPDATE_USERINFO', res.data.userInfo);
+								if (option.query.back_url) {
+									location.replace(decodeURIComponent(decodeURIComponent(option.query
+										.back_url)));
+								}
+							}
+						} catch (e) {
+							let url = ''
+							if (option.query.back_url instanceof Array) {
+								url = option.query.back_url[option.query.back_url.length - 1]
+							} else {
+								url = option.query.back_url
+							}
+							if (!that.$Cache.has('snsapiKey')) {
+								if (location.pathname.indexOf('/pages/users/wechat_login/index') === -1) {
+									Auth.oAuth('snsapi_userinfo', url);
+								}
+							}
+						}
+
+
+
+						// silenceAuth({
+						// 		code: code,
+						// 		spread: that.$Cache.get('spread'),
+						// 		spid: that.globalData.code
+						// 	})
+						// 	.then(res => {
+						// 		uni.setStorageSync('snRouter', decodeURIComponent(decodeURIComponent(option.query
+						// 			.back_url)));
+						// 		if (res.data.key !== undefined && res.data.key) {
+						// 			this.$Cache.set('snsapiKey', res.data.key);
+						// 		} else {
+						// 			let time = res.data.expires_time - this.$Cache.time();
+						// 			this.$store.commit('LOGIN', {
+						// 				token: res.data.token,
+						// 				time: time
+						// 			});
+
+						// 			this.$store.commit('SETUID', res.data.userInfo.uid);
+						// 			this.$store.commit('UPDATE_USERINFO', res.data.userInfo);
+						// 			if (option.query.back_url) {
+						// 				location.replace(decodeURIComponent(decodeURIComponent(option.query
+						// 					.back_url)));
+						// 			}
+						// 		}
+						// 	})
+						// 	.catch(error => {
+						// 		let url = ''
+						// 		if (option.query.back_url instanceof Array) {
+						// 			url = option.query.back_url[option.query.back_url.length - 1]
+						// 		} else {
+						// 			url = option.query.back_url
+						// 		}
+						// 		if (!that.$Cache.has('snsapiKey')) {
+						// 			if (location.pathname.indexOf('/pages/users/wechat_login/index') === -1) {
+						// 				Auth.oAuth(snsapiBase, url);
+						// 			}
+						// 		}
+						// 	});
+					} else {
+						if (!this.$Cache.has('snsapiKey')) {
+							if (location.pathname.indexOf('/pages/users/wechat_login/index') === -1) {
+								Auth.oAuth(snsapiBase, urlData);
+							}
+						}
+					}
+				} else {
+					if (option.query.back_url) {
+						location.replace(uni.getStorageSync('snRouter'));
+					}
+				}
+			}
+			// #endif
+			// #ifdef MP
+			// 小程序静默授权
+			if (!this.$store.getters.isLogin) {
+				Routine.getCode()
+					.then(code => {
+						this.silenceAuth(code);
+					})
+					.catch(res => {
+						uni.hideLoading();
+					});
+			}
+			// #endif
+		},
+		onShow(options) {
+			let that = this;
+			//直播间分享
+			// #ifdef MP
+			// const sceneList = [1007, 1008, 1014, 1044, 1045, 1046, 1047, 1048, 1049, 1073, 1154, 1155];
+			//  if (sceneList.includes(options.scene)) {
+			// 	livePlayer.getShareParams()
+			// 		.then(res => {
+			// 			//记录推广人uid
+			// 			if(res.custom_params.pid){
+			// 				 that.$Cache.set('spread', res.custom_params.pid);
+			// 				 that.globalData.spid = res.custom_params.pid;
+			// 				 that.globalData.pid = res.custom_params.pid;
+			// 			}
+			// 		}).catch(err => {
+			// 		})
+			// }
+			// #endif
+		},
+		mounted() {
+			// setTimeout((e) => {
+			// 	if (this.$store.getters.isLogin) {
+			// 		this.getCartNum()
+			// 	}
+			// }, 100)
+		},
+		methods: {
+			// 小程序静默授权
+			silenceAuth(code) {
+				let that = this;
+				let spread = that.globalData.spid ? that.globalData.spid : '';
+				silenceAuth({
+						code: code,
+						spread_spid: spread,
+						spread_code: that.globalData.code
+					})
+					.then(res => {
+						if (res.data.token !== undefined && res.data.token) {
+							uni.hideLoading();
+							let time = res.data.expires_time - this.$Cache.time();
+							that.$store.commit('LOGIN', {
+								token: res.data.token,
+								time: time
+							});
+							that.$store.commit('SETUID', res.data.userInfo.uid);
+							that.$store.commit('UPDATE_USERINFO', res.data.userInfo);
+						}
+					})
+					.catch(res => {});
+			},
+			isWork() {
+				return navigator.userAgent.toLowerCase().indexOf('wxwork') !== -1 && navigator.userAgent.toLowerCase()
+					.indexOf("micromessenger") !== -1
+			}
+		},
+		onHide: function() {
+
+		}
+	};
+</script>
+
+<style lang="scss">
+	/* #ifndef APP-PLUS-NVUE || APP-NVUE */
+	@import url('@/plugin/emoji-awesome/css/tuoluojiang.css');
+	@import url('@/plugin/animate/animate.min.css');
+	@import 'static/css/base.css';
+	@import 'static/iconfont/iconfont.css';
+	@import 'static/css/guildford.css';
+	@import 'static/css/style.scss';
+
+	view {
+		box-sizing: border-box;
+	}
+
+	page {
+		font-family: PingFang SC;
+	}
+	
+	.placeholder{
+		color: #ccc;
+	}
+
+	.bg-color-red {
+		background-color: var(--view-theme) !important;
+	}
+
+	.syspadding {
+		padding-top: var(--status-bar-height);
+	}
+
+	.flex {
+		display: flex;
+	}
+
+	.uni-scroll-view::-webkit-scrollbar {
+		/* 隐藏滚动条,但依旧具备可以滚动的功能 */
+		display: none;
+	}
+
+	::-webkit-scrollbar {
+		width: 0;
+		height: 0;
+		color: transparent;
+	}
+
+	.uni-system-open-location .map-content.fix-position {
+		height: 100vh;
+		top: 0;
+		bottom: 0;
+	}
+	/* #endif */
+</style>

+ 284 - 0
README.md

@@ -0,0 +1,284 @@
+# CRMEB 移动端
+## 开发规范
+市面上常用的命名规范:
+
+* camelCase(小驼峰式命名法 —— 首字母小写)
+* PascalCase(大驼峰式命名法 —— 首字母大写)
+* kebab-case(短横线连接式)
+* snake_a(下划线连接式)
+
+##### 项目文件命名
+#####1、项目名
+#####全部采用小写方式, 以下划线分隔。 例:crmeb_pro_uniapp;
+#####2、组件(components)
+#####优先选择单个单词命名,多个单词命名以小驼峰式命名。例:crmebPro;
+#####3、pages里面的文件名;
+#####全部采用小写方式, 优先选择单个单词命名,多个单词命名以下划线分隔,组件参考第2条。 例:crmeb_pro_uniapp;
+#####4、css文件名;
+#####全部采用小写方式, 优先选择单个单词命名,多个单词命名以短横线分隔。例:crmeb-pro.css
+#####5、JavaScript 文件名;
+#####全部采用小写方式, 优先选择单个单词命名,多个单词命名以短横线分隔。例:crmeb-pro.js
+#####6、HTML 文件名;
+#####全部采用小写方式, 优先选择单个单词命名,多个单词命名以下划线分隔。例:crmeb_pro.html
+#####7、图像文件名;
+#####全部采用小写方式, 优先选择单个单词命名,多个单词命名以短横线分隔。例:crmeb-pro.jpg
+
+## 目录结构
+主要目录结构及说明:
+~~~
+├── api                       # 请求接口
+│   ├── activity              # 活动接口
+│   ├── admin                 # 管理端接口
+│   ├── api                   # 文章优惠券等接口
+│   ├── esp                   # esp接口
+│   ├── kefu                  # 客服接口
+│   ├── lottery               # 抽奖活动接口
+│   ├── order                 # 订单接口
+│   ├── points_mall           # 积分商城接口
+│   ├── public                # 配置类接口
+│   ├── store                 # 商品接口
+│   ├── user                  # 我的接口
+│   └──work                   # 企业微信接口
+│   ├── components            # 公共组件
+│   │    └──addressWindow          # 选择地址
+│   │    └──cartDiscount         # 购物车优惠明细
+│   │    └──cartList             # 购物车列表
+│   │    └──countDown           # 倒计时
+│   │    └──couponListWindow           # 优惠券列表
+│   │    └──couponWindow          # 首页优惠券
+│   │    └──cusPreviewImg          # 规格轮播
+│   │    └──customForm          # 自定义组件
+│   │    └──d_goodList          # 分类二的组件
+│   │    └──goodClass          # 分类三的组件
+│   │    └──goodList          # 营销组件
+│   │    └──guide          # 闪屏组件
+│   │    └──home          # 悬浮导航
+│   │    └──homeList          # 导航列表
+│   │    └──jyf-parser          # 富文本
+│   │    └──kefuIcon          # 客服
+│   │    └──Loading          # 加载
+│   │    └──orderGoods          # 订单商品
+│   │    └──pageFooter          # 底部导航
+│   │    └──payment          # 支付
+│   │    └──productConSwiper          # 商品轮播
+│   │    └──productWindow          # 商品属性
+│   │    └──recommend          # 热门推荐
+│   │    └──skeleton          # 骨架屏
+│   │    └──storeLis          # 门店列表
+│   │    └──swipers          # 轮播
+│   │    └──uni-calendar          # 日期
+│   │    └──uniNoticeBar          # 跑马灯
+│   │    └──userEvaluation          # 评价
+│   │    └──zb-code          # 二维码生成插件
+│   │    └──emptyPage          # 无数据时显示页面
+│   ├── config               # 项目配置文件
+│   ├── libs                  
+│   │    └──login            # 登录
+│   │    └──network            # 检测长链接
+│   │    └──new_chat            # 检测长链接
+│   │    └──order            # 订单跳转
+│   │    └──routine            # 授权
+│   │    └──wechat            # h5授权支付等函数
+│   │    └──work            # 企业微信
+│   ├── mixins                # 通用混合
+│   │    └──color          # 一键换色
+│   │    └──SendVerifyCode  # 获取验证码
+│   ├── pages                 # 所有页面
+│   │    └──activity              # 活动
+│   │         └──bargain # 砍价状态列表
+│   │         └──components # 组件
+│   │               └──giftGoods      # 商品赠品列表
+│   │         └──discount      # 活动折扣列表
+│   │         └──goods_bargain        # 砍价商品列表
+│   │         └──goods_bargain_details # 砍价详情
+│   │         └──goods_combination     # 拼团列表
+│   │         └──goods_combination_details    # 拼团详情
+│   │         └──goods_combination_status   # 拼团状态
+│   │         └──goods_seckill   # 秒杀列表
+│   │         └──goods_seckill_details   # 秒杀详情
+│   │         └──poster-poster   # 海报
+│   │         └──presell   # 预售列表
+│   │         └──static   # 图片
+│   │    └──admin             # 管理端
+│   │         └──components   # 组件
+│   │               └──priceChange      # 改价以及备注弹窗
+│   │               └──ucharts      # 统计图
+│   │               └──writeOffSwitching      # 核销列表
+│   │         └──custom_date   # 选择日期
+│   │         └──delivery   # 订单发货
+│   │         └──distribution   
+│   │               └──orderDetail      # 订单详情
+│   │               └──scanning      # 扫描结果
+│   │               └──index      # 配送员
+│   │         └──order   # 订单统计
+│   │         └──order_cancellation   # 订单核销
+│   │         └──orderDetail   # 订单详情
+│   │         └──orderList   # 订单列表
+│   │         └──static   # 图片
+│   │         └──statistics   # 订单数据统计
+│   │         └──store   # 门店管理
+│   │               └──custom_date      # 选择日期
+│   │               └──deliverGoods      # 订单发货
+│   │               └──order      # 订单管理
+│   │               └──orderDetail      # 订单详情
+│   │               └──scanning      # 扫描结果
+│   │               └──statistics      # 订单数据统计
+│   │               └──index      # 门店中心
+│   │    └──annex   # 会员
+│   │         └──offline_pay      # 支付
+│   │         └──offline_result      # 支付结果
+│   │         └──special      # 专题页
+│   │         └──vip_active      # 激活会员
+│   │         └──vip_clause      # 会员协议
+│   │         └──vip_coupon      # 会员优惠券
+│   │         └──vip_paid      # SVIP会员
+│   │         └──web_view      # 外部链接跳转
+│   │    └──auth   # 登录页
+│   │    └──columnGoods            
+│   │         └──HotNewGoods   
+│   │               └──feedback      # 我的客服
+│   │               └──index      # 精品推荐
+│   │         └──live_list    #推荐好货
+│   │         └──static    #图片
+│   │    └──extension
+│   │         └──components    #组件
+│   │               └──shareInfo      # 分享  
+│   │               └──vconsole.min      # 查看后台打印
+│   │         └──customer_list  
+│   │               └──chat      # 客服聊天界面  
+│   │         └──invite_friend    #邀请好友
+│   │         └──news_details    #资讯详情
+│   │         └──news_list    #资讯   
+│   │         └──static    #图片
+│   │    └──goods
+│   │         └──admin_order_detail    #订单详情
+│   │         └──components    #组件
+│   │               └──invoiceModal      # 选择发票 
+│   │               └──invoicePicker      # 添加发票信息 
+│   │               └──lottery      # 抽奖转盘 
+│   │               └──maramlee-waterfalls-flow      # 客服聊天界面 
+│   │         └──goods_comment_con    #组件
+│   │               └──comment_con      # 评价详情
+│   │               └──index      # 商品评价
+│   │               └──lottery_comment      # 订单评价
+│   │         └──goods_comment_list    #商品评分列表
+│   │         └──goods_details_store    #门店列表
+│   │         └──goods_list    #商品列表
+│   │         └──goods_logistics    #商品物流
+│   │         └──goods_return    #申请退货
+│   │         └──goods_return_list    #退货列表
+│   │         └──goods_search    #商品搜索
+│   │         └──lottery     
+│   │               └──grids
+│   │                    └──index  #抽奖活动
+│   │                    └──record   #中奖纪录
+│   │         └──order_confirm    #确认订单
+│   │         └──order_details    #订单详情
+│   │         └──order_pay    #订单支付
+│   │         └──order_pay_status    #支付成功
+│   │         └──order_refund_goods    #退回商品
+│   │         └──order_pay_status    #退回商品
+│   │         └──static    #图片
+│   │    └──goods_cate 分类
+│   │    └──goods_details 商品详情
+│   │    └──guide 闪屏
+│   │    └──index 首页
+│   │    └──order_addcart 购物车
+│   │    └──points_mall 积分商城
+│   │         └──components    #组件
+│   │               └──productWindow      #商品规格 
+│   │         └──static    #图片
+│   │         └──exchange_record    #兑换记录
+│   │         └──index    #积分商城首页
+│   │         └──integral_goods_details    #商品详情
+│   │         └──integral_goods_list    #商品列表
+│   │         └──integral_order    #积分订单
+│   │         └──integral_order_details    #兑换订单详情
+│   │         └──integral_order_status    #兑换成功
+│   │         └──logistics_details    #兑换物流详情
+│   │         └──user_address    #选择地址
+│   │    └──user 个人中心
+│   │    └──users 我的
+│   │         └──alipay_invoke    #支付提示
+│   │         └──commission_rank    #佣金排行
+│   │         └──components    #组件
+│   │               └──areaWindow      #选择地区
+│   │               └──login_mobile      #登录
+│   │               └──pageHeader      #头部导航
+│   │               └──timeSlot      #时间日期插件
+│   │         └──login    #登录
+│   │         └──message_center    
+│   │               └──index      #消息中心
+│   │               └──messageDetail      #消息详情
+│   │         └──privacy    #协议
+│   │         └──promoter_rank    #推广人排行
+│   │         └──promoter-list    #推广人列表
+│   │         └──promoter-order    #推广人订单
+│   │         └──retrievePassword    #忘记密码
+│   │         └──scan_login    #授权登录
+│   │         └──static    #图片
+│   │         └──user_address    #选择地址
+│   │         └──user_address_list    #地址管理
+│   │         └──user_bill    #账单明细
+│   │         └──user_cancellation    #注销说明
+│   │         └──user_cash    #提现
+│   │         └──user_coupon    #我的优惠券
+│   │         └──user_distribution_level    #分销等级
+│   │         └──user_get_coupon    #领取优惠券
+│   │         └──user_goods_collection    #收藏商品
+│   │         └──user_info    #个人资料
+│   │         └──user_integral    #积分详情
+│   │         └──user_invoice_form    #添加新发票
+│   │         └──user_invoice_list    #发票管理
+│   │         └──user_invoice_order    #订单详情
+│   │         └──user_money    #我的账户
+│   │         └──user_payment    #余额充值
+│   │         └──user_phone    #绑定手机
+│   │         └──user_pwd_edit    #修改密码
+│   │         └──user_return_list    #退货列表
+│   │         └──user_sgin    #签到
+│   │         └──user_sgin_list    #签到记录
+│   │         └──user_spread_code    #分销海报
+│   │         └──user_spread_money    #佣金记录
+│   │         └──user_spread_user    #我的推广
+│   │         └──user_vip    #我的等级
+│   │         └──user_vip_areer    #经验记录
+│   │         └──visit_list    #浏览记录
+│   │         └──wechat_login    #账户登录
+│   │    └──work 企业微信
+│   │         └──components    #组件
+│   │               └──tabNav      #导航 
+│   │         └──groupInfo    #群组信息
+│   │         └──orderDetail    #订单详情
+│   │         └──orderList    #交易管理
+│   │         └──record    #记录
+│   │         └──userInfo    #客户信息
+│   ├── plugins                # 插件
+│   ├── static                 # 静态文件
+│   ├── store                  # Vuex 状态管理
+│   ├── utils                  # js工具
+│   ├── App                # 入口文件
+│   ├── main.js                # 入口文件,注册vue等
+│   └── pages.json                # 页面配置
+~~~
+## 开发打包项目
+~~~
+uniapp开发工具必须为HBuilder
+
+# 启动项目(本地开发环境)
+点击运行
+
+# 打包项目
+点击发行
+~~~
+
+
+###开发团队:
+
+##### 前端开发:小小、娜娜
+##### 后端开发:等风来、zhypy
+##### 产品经理:木子刀客
+##### UI设计:xy-yyds
+##### 测试:夏天
+
+注:排名不分前后

+ 28 - 0
androidPrivacy.json

@@ -0,0 +1,28 @@
+{
+    "version" : "1",
+    "prompt" : "template",
+    "title" : "用户协议与隐私政策",
+    "message" : "\t请务必审慎阅读、充分理解“用户协议与 隐私政策”各条款,包括但不限于:为了 向你提供即时通讯、内容分享等服务,我 们需要收集你的设备信息、操作日志等个 人信息。你可以在“设置”中查看、变更、删除个人信息并管理你的授权。<br/>
+ 你可以阅读 <a href=\"pages/columnGoods/static/yhxy.html\">《用户协议》</a>与 <a href=\"pages/columnGoods/static/yszc.html\">《隐私政策》</a>了解详细信息。如你同意,请点击“我同意”开始接受我们的服务。",
+    "buttonAccept" : "同意并接受",
+    "buttonRefuse" : "暂不同意",
+    "second" : {
+        "title" : "确认提示",
+        "message" : "进入应用前,你需先同意<a href=\"pages/columnGoods/static/yhxy.html\">《用户协议》</a>与<a href=\"pages/columnGoods/static/yszc.html\">《隐私政策》</a>,否则将退出应用。",
+        "buttonAccept" : "同意并继续",
+        "buttonRefuse" : "退出应用"
+    },
+    "styles" : {
+        "backgroundColor" : "#fff",
+        "borderRadius" : "5px",
+        "title" : {
+            "color" : "#000"
+        },
+        "buttonAccept" : {
+            "color" : "#fff"
+        },
+        "buttonRefuse" : {
+            "color" : "#ccc"
+        }
+    }
+}

+ 329 - 0
api/activity.js

@@ -0,0 +1,329 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+/**
+ * 
+ * 所有活动接口 包括:拼团,砍价,秒杀
+ * 
+ */
+
+/**
+ * 拼团列表
+ * 
+ */
+export function getCombinationList(data) {
+	return request.get('combination/list', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 拼团详情
+ * 
+ */
+export function getCombinationDetail(id) {
+	return request.get('combination/detail/' + id,{},{noAuth: true});
+}
+
+/**
+ * 拼团 开团
+ */
+export function getCombinationPink(id) {
+	return request.get("combination/pink/" + id);
+}
+
+/**
+ * 拼团 取消开团
+ */
+export function postCombinationRemove(data) {
+	return request.post("combination/remove", data);
+}
+
+/**
+ * 砍价列表
+ */
+export function getBargainList(data) {
+	return request.get("bargain/list", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 拼团轮播
+ * 
+ */
+export function getCombinationBannerList(data) {
+	return request.get('combination/banner_list', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 拼团人数
+ * 
+ */
+export function getPink(data) {
+	return request.get('pink', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 
+ * 砍价列表(已参与)
+ * @param object data
+ */
+export function getBargainUserList(data) {
+	return request.get('bargain/user/list', data);
+}
+
+
+/**
+ * 砍价产品详情
+ */
+export function getBargainDetail(id) {
+	return request.get("bargain/detail/" + id, {},{
+		noAuth: true
+	});
+}
+
+/**
+ * 砍价 开启砍价用户信息
+ */
+export function postBargainStartUser(data) {
+	return request.post("bargain/start/user", data);
+}
+
+/**
+ * 砍价开启
+ */
+export function postBargainStart(bargainId) {
+	return request.post("bargain/start", {
+		bargainId: bargainId
+	});
+}
+
+/**
+ * 砍价 帮助好友砍价
+ */
+export function postBargainHelp(data) {
+	return request.post("bargain/help", data);
+}
+
+/**
+ * 砍价 砍掉金额
+ */
+export function postBargainHelpPrice(data) {
+	return request.post("bargain/help/price", data);
+}
+
+/**
+ * 砍价 砍价帮
+ */
+export function postBargainHelpList(data) {
+	return request.post("bargain/help/list", data);
+}
+
+/**
+ * 砍价 砍价帮总人数、剩余金额、进度条、已经砍掉的价格
+ */
+export function postBargainHelpCount(data) {
+	return request.post("bargain/help/count", data);
+}
+
+/**
+ * 砍价 观看/分享/参与次数
+ */
+export function postBargainShare(bargainId) {
+	return request.post("bargain/share", {
+		bargainId: bargainId
+	});
+}
+
+/**
+ * 秒杀产品时间区间
+ * 
+ */
+export function getSeckillIndexTime() {
+	return request.get('seckill/index', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 秒杀产品列表
+ * @param int time
+ * @param object data
+ */
+export function getSeckillList(time, data) {
+	return request.get('seckill/list/' + time, data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 秒杀产品详情
+ * @param int id
+ */
+export function getSeckillDetail(id, data) {
+	return request.get('seckill/detail/' + id,{},{
+		noAuth: true
+	});
+}
+
+/**
+ * 砍价海报
+ * @param object data
+ * 
+ */
+export function getBargainPoster(data) {
+	return request.post('bargain/poster', data)
+}
+
+/**
+ * 拼团海报
+ * @param object data
+ * 
+ */
+export function getCombinationPoster(data) {
+	return request.post('combination/poster', data)
+}
+
+/**
+ * 砍价取消
+ */
+export function getBargainUserCancel(data) {
+	return request.post("bargain/user/cancel", data);
+}
+
+/**
+ * 获取秒杀小程序二维码
+ */
+export function seckillCode(id, data) {
+	return request.get("seckill/code/" + id, data);
+}
+
+/**
+ * 获取拼团小程序二维码
+ */
+export function scombinationCode(id) {
+	return request.get("combination/code/" + id);
+}
+
+/**
+ * 获取砍价海报详细信息
+ */
+export function getCombinationPosterData(id) {
+	return request.get("combination/poster_info/" + id);
+}
+
+
+/**
+ * 获取砍价海报详细信息
+ */
+export function getBargainPosterData(id) {
+	return request.get("bargain/poster_info/" + id);
+}
+
+/**
+ * 获取积分订单详细信息
+ */
+export function integralOrderConfirm(data) {
+	return request.post('store_integral/order/confirm', data);
+}
+
+/**
+ * 获取积分订单创建
+ */
+export function integralOrderCreate(data) {
+	return request.post('store_integral/order/create', data);
+}
+/**
+ * 获取积分订单详情
+ * @param string cartId
+ */
+export function integralOrderDetails(order) {
+	return request.get(`store_integral/order/detail/${order}`);
+}
+
+/**
+ * 积分产品详情
+ * @param int id
+ * 
+ */
+export function getIntegralProductDetail(id) {
+	return request.get('store_integral/detail/' + id, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 积分商城商品列表
+ * @param object data
+ */
+export function getStoreIntegralList(data) {
+	return request.get('store_integral/list', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 积分兑换列表
+ * @param object data
+ */
+export function getIntegralOrderList(data) {
+	return request.get('store_integral/order/list', data);
+}
+
+/**
+ * 积分兑换详情
+ */
+export function getLogisticsDetails(orderId) {
+	return request.get(`store_integral/order/express/${orderId}`);
+}
+
+/**
+ * 积分兑换订单确认收货
+ * @param object data
+ */
+export function orderTake(data) {
+	return request.post(`store_integral/order/take`, data);
+}
+
+/**
+ * 积分兑换订单删除
+ * @param object data
+ */
+export function orderDel(data) {
+	return request.post(`store_integral/order/del`, data);
+}
+
+/**
+ * 预售商品列表
+ */
+export function getAdvancellList(data) {
+  return request.get("presale/list", data);
+}
+
+/**
+ * 限时折扣商品列表
+ */
+export function promotionsList(type,data) {
+  return request.get("v2/promotions/productList/"+type, data);
+}
+
+/**
+ * 活动赠送商品
+ */
+export function giveInfo(id) {
+  return request.get("v2/promotions/give_info/"+id);
+}
+

+ 442 - 0
api/admin.js

@@ -0,0 +1,442 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+import request from "@/utils/request.js";
+
+/**
+ * 统计数据
+ */
+export function getStatisticsInfo() {
+	return request.get("admin/order/statistics", {}, {
+		login: true
+	});
+}
+/**
+ * 订单月统计
+ */
+export function getStatisticsMonth(where) {
+	return request.get("admin/order/data", where, {
+		login: true
+	});
+}
+/**
+ * 订单月统计
+ */
+export function getAdminOrderList(where) {
+	return request.get("admin/order/list", where, {
+		login: true
+	});
+}
+/**
+ * 订单改价
+ */
+export function setAdminOrderPrice(data) {
+	return request.post("admin/order/price", data, {
+		login: true
+	});
+}
+/**
+ * 订单备注
+ */
+export function setAdminOrderRemark(data) {
+	return request.post("admin/order/remark", data, {
+		login: true
+	});
+}
+/**
+ * 订单备注(退款)
+ */
+export function setAdminRefundRemark(data) {
+	return request.post("admin/refund_order/remark", data, {
+		login: true
+	});
+}
+/**
+ * 订单详情
+ */
+export function getAdminOrderDetail(orderId) {
+	return request.get("admin/order/detail/" + orderId, {}, {
+		login: true
+	});
+}
+/**
+ * 订单详情(退款)
+ */
+export function getAdminRefundDetail(orderId) {
+	return request.get("admin/refund_order/detail/" + orderId, {}, {
+		login: true
+	});
+}
+
+/**
+ * 订单发货信息获取
+ */
+export function getAdminOrderDelivery(orderId) {
+	return request.get(
+		"admin/order/delivery/gain/" + orderId, {}, {
+			login: true
+		}
+	);
+}
+
+/**
+ * 订单发货保存
+ */
+export function setAdminOrderDelivery(id, data) {
+	return request.post("admin/order/delivery/keep/" + id, data, {
+		login: true
+	});
+}
+/**
+ * 订单统计图
+ */
+export function getStatisticsTime(data) {
+	return request.get("admin/order/time", data, {
+		login: true
+	});
+}
+/**
+ * 线下付款订单确认付款
+ */
+export function setOfflinePay(data) {
+	return request.post("admin/order/offline", data, {
+		login: true
+	});
+}
+/**
+ * 订单确认退款
+ */
+export function setOrderRefund(data) {
+	return request.post("admin/order/refund", data, {
+		login: true
+	});
+}
+
+/**
+ * 获取快递公司
+ * @returns {*}
+ */
+export function getLogistics(data) {
+	return request.get("logistics", data, {
+		login: false
+	});
+}
+
+/**
+ * 订单核销
+ * @returns {*}
+ */
+export function orderVerific(verify_code, is_confirm) {
+	return request.post("order/order_verific", {
+		verify_code,
+		is_confirm
+	});
+}
+
+/**
+ * 获取物流公司模板
+ * @returns {*}
+ */
+export function orderExportTemp(data) {
+	return request.get("admin/order/export_temp", data);
+}
+
+/**
+ * 获取订单打印默认配置
+ * @returns {*}
+ */
+export function orderDeliveryInfo() {
+	return request.get("admin/order/delivery_info");
+}
+
+/**
+ * 配送员列表
+ * @returns {*}
+ */
+export function orderOrderDelivery() {
+	return request.get("admin/order/delivery");
+}
+
+
+// 门店
+
+/**
+ * 用户信息
+ */
+export function userInfo() {
+	return request.get("store/staff/info");
+}
+
+
+/**
+ * 门店中心-订单统计
+ */
+export function orderInfo(data) {
+	return request.get("store/order/statistics",data);
+}
+
+
+
+/**
+ * 门店中心-统计菜单
+ */
+export function statisticsMenuApi(data) {
+	return request.get("store/staff/statistics",data);
+}
+
+
+
+/**
+ * 门店中心-详细数据列表
+ */
+export function getListApi(data) {
+	return request.get("store/order/data",data);
+}
+
+
+/**
+ * 门店中心-数据详情-列表
+ */
+export function getStatisticsListApi(type,data) {
+	return request.get("store/staff/data/"+type,data);
+}
+
+
+/**
+ * 门店中心-订单管理列表
+ */
+export function getOrderlistApi(data) {
+	return request.get("store/order/list",data);
+}
+
+/**
+ * 门店中心-订单管理列表(退款)
+ */
+export function getRefundlistApi(data) {
+	return request.get("store/refund/list",data);
+}
+
+/**
+ * 门店中心-订单管理备注
+ */
+export function getOrderreMarkApi(data) {
+	return request.post("store/order/remark",data);
+}
+
+/**
+ * 门店中心-订单管理备注(退款)
+ */
+export function getRefundMarkApi(data) {
+	return request.post("store/refund/remark",data);
+}
+
+/**
+ * 门店中心-订单管理改价
+ */
+export function getOrderPriceApi(data) {
+	return request.post("store/order/price",data);
+}
+
+/**
+ * 门店中心-订单管理确定付款
+ */
+export function getOrderOfflineApi(data) {
+	return request.post("store/order/offline",data);
+}
+
+
+/**
+ * 门店中心-去发货-用户
+ */
+export function getOrderDeliveryinfoApi(id) {
+	return request.get("store/order/delivery_info/"+id);
+}
+
+/**
+ * 门店中心-去发货-获取快递公司
+ */
+export function getOrderExportApi(data) {
+	return request.get("store/order/export_all", data, {
+		login: false
+	});
+}
+/**
+ * 门店中心-去发货-获取物流公司模板
+ * @returns {*}
+ */
+export function getOrderExportTemp(data) {
+	return request.get("store/order/export_temp", data);
+}
+
+/**
+ * 门店中心-去发货-订单发货保存
+ */
+export function setOrderDelivery(id, data) {
+	return request.post("store/order/delivery/" + id, data, {
+		login: true
+	});
+}
+/**
+ * 门店中心-去发货-获取配送员列表
+ * @returns {*}
+ */
+export function getOrderDelivery() {
+	return request.get("store/delivery/list");
+}
+/**
+ * 门店中心-订单确认退款
+ */
+export function OrderRefund(data) {
+	return request.post("store/order/refund", data, {
+		login: true
+	});
+}
+
+/**
+ * 门店中心-订单详情
+ */
+export function OrderDetail(id) {
+	return request.get("store/order/detail/"+id);
+}
+
+/**
+ * 门店中心-订单详情(退款)
+ */
+export function refundDetail(id) {
+	return request.get("store/refund/detail/"+id);
+}
+
+
+/**
+ * 配送员-获取用户信息
+ */
+export function deliveryInfo(id) {
+	return request.get("store/delivery/info");
+}
+
+
+/**
+ * 配送员-获取配送统计数据
+ */
+export function deliveryStatistics(data) {
+	return request.get("store/delivery/statistics",data);
+}
+
+
+/**
+ * 配送员-获取配送统计数据列表
+ */
+export function deliveryList(data) {
+	return request.get("store/delivery/data",data);
+}
+
+
+
+/**
+ * 配送员-获取订单列表数据列表
+ */
+export function deliveryOrderList(data) {
+	return request.get("store/delivery/order",data);
+}
+
+
+/**
+ * 门店中心-订单取消、删除
+ */
+export function OrderDel(id) {
+	return request.delete("store/order/del/"+id);
+}
+
+
+/**
+ * 门店中心-订单取消、取消
+ */
+export function OrderCancel(id) {
+	return request.post("store/order/cancel/"+id);
+}
+
+
+/**
+ * 配送员-扫码核销获取订单信息
+ */
+export function orderWriteoffInfo(type,data) {
+	return request.get("store/order/writeoff_info/"+type,data);
+}
+
+
+
+
+/**
+ * 配送员-核销订单获取商品信息
+ */
+export function orderCartInfo(type,data) {
+	return request.get("store/order/cart_info/"+type,data);
+}
+
+
+/**
+ * 配送员-订单核销
+ */
+export function orderWriteoff(type,data) {
+	return request.post("store/order/writeoff/"+type,data);
+}
+
+/**
+ * 统计管理-获取订单可拆分商品列表
+ */
+export function orderSplitInfo(id) {
+	return request.get("admin/order/split_cart_info/"+id);
+}
+
+/**
+ * 统计管理-提交
+ */
+export function orderSplitDelivery(id,data) {
+	return request.put("admin/order/split_delivery/"+id,data);
+}
+
+/**
+ * 统计管理-退货退款
+ */
+export function orderRefundAgree(id) {
+	return request.post("admin/order/refund_agree/"+id);
+}
+
+/**
+ * 门店中心-获取订单可拆分商品列表
+ */
+export function storeSplitInfo(id) {
+	return request.get("store/order/split_cart_info/"+id);
+}
+
+/**
+ * 门店中心-提交
+ */
+export function storeSplitDelivery(id,data) {
+	return request.put("store/order/split_delivery/"+id,data);
+}
+
+/**
+ * 门店中心-退货退款
+ */
+export function storeRefundAgree(id) {
+	return request.post("store/order/refund_agree/"+id);
+}
+
+/**
+ * 平台-退款列表
+ */
+export function adminRefundList(data) {
+	return request.get("admin/refund_order/list",data);
+}
+
+
+

+ 461 - 0
api/api.js

@@ -0,0 +1,461 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+/**
+ * 公共接口 ,优惠券接口 , 行业此讯 , 手机号码注册
+ * 
+ */
+export function getAjcaptcha(data) {
+	return request.get("ajcaptcha", data, {
+		noAuth: true
+	});
+}
+
+export function ajcaptchaCheck(data) {
+	return request.post("ajcheck", data, {
+		noAuth: true
+	});
+}
+/**
+ * 获取主页数据 无需授权
+ * 
+ */
+export function getIndexData() {
+	return request.get("v2/index", {}, {
+		noAuth: true
+	});
+}
+/**
+ * 获取服务器类型
+ * 
+ */
+export function getServerType() {
+	return request.get("v2/site_serve", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取登录授权login
+ * 
+ */
+export function getLogo() {
+	return request.get('wechat/get_logo', {}, {
+		noAuth: true
+	});
+}
+
+
+/**
+ * 保存form_id
+ * @param string formId 
+ */
+export function setFormId(formId) {
+	return request.post("wechat/set_form_id", {
+		formId: formId
+	});
+}
+
+/**
+ * 领取优惠卷
+ * @param int couponId
+ * 
+ */
+export function setCouponReceive(couponId) {
+	return request.post('coupon/receive', {
+		couponId: couponId
+	});
+}
+/**
+ * 优惠券列表
+ * @param object data
+ */
+export function getCoupons(data) {
+	return request.get('v2/coupons', data, {
+		noAuth: true
+	})
+}
+
+/**
+ * 我的优惠券
+ * @param int types 0全部  1未使用 2已使用
+ */
+export function getUserCoupons(types, data) {
+	return request.get('coupons/user/' + types, data)
+}
+
+/**
+ * 首页新人优惠券
+ * 
+ */
+export function getNewCoupon() {
+	return request.get('v2/new_coupon')
+}
+
+/**
+ * 文章分类列表
+ * 
+ */
+export function getArticleCategoryList() {
+	return request.get('article/category/list', {}, {
+		noAuth: true
+	})
+}
+
+/**
+ * 文章列表
+ * @param int cid
+ * 
+ */
+export function getArticleList(cid, data) {
+	return request.get('article/list/' + cid, data, {
+		noAuth: true
+	})
+}
+
+/**
+ * 文章 热门列表
+ * 
+ */
+export function getArticleHotList() {
+	return request.get('article/hot/list', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 文章 轮播列表
+ * 
+ */
+export function getArticleBannerList() {
+	return request.get('article/banner/list', {}, {
+		noAuth: true
+	})
+}
+
+/**
+ * 文章详情
+ * @param int id 
+ * 
+ */
+export function getArticleDetails(id) {
+	return request.get('article/details/' + id, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 手机号+验证码登录接口
+ * @param object data
+ */
+export function loginMobile(data) {
+	return request.post('login/mobile', data, {
+		noAuth: true
+	})
+}
+
+/**
+ * 获取短信KEY
+ * @param object phone
+ */
+export function verifyCode() {
+	return request.get('verify_code', {}, {
+		noAuth: true
+	})
+}
+
+/**
+ * 验证码发送
+ * @param object phone
+ */
+export function registerVerify(data) {
+	return request.post('register/verify',data, {
+		noAuth: true
+	})
+}
+
+/**
+ * 手机号注册
+ * @param object data
+ * 
+ */
+export function phoneRegister(data) {
+	return request.post('register', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 手机号修改密码
+ * @param object data
+ * 
+ */
+export function phoneRegisterReset(data) {
+	return request.post('register/reset', data, {
+		noAuth: true
+	})
+}
+
+/**
+ * 手机号+密码登录
+ * @param object data
+ * 
+ */
+export function phoneLogin(data) {
+	return request.post('login', data, {
+		noAuth: true
+	})
+}
+
+/**
+ * 切换H5登录
+ * @param object data
+ */
+// #ifdef MP
+export function switchH5Login() {
+	return request.post('switch_h5', {
+		'from': 'routine'
+	});
+}
+// #endif
+
+/*
+ * h5切换公众号登陆
+ * */
+// #ifdef H5
+export function switchH5Login() {
+	return request.post("switch_h5", {
+		'from': "wechat"
+	});
+}
+// #endif
+
+/**
+ * 绑定手机号
+ * 
+ */
+export function bindingPhone(data) {
+	return request.post('binding', data, {
+		noAuth: true
+	});
+}
+
+
+
+/**
+ * 绑定手机号
+ * 
+ */
+export function bindingUserPhone(data) {
+	return request.post('user/binding', data);
+}
+
+/**
+ * 退出登錄
+ * 
+ */
+export function logout() {
+	return request.get('logout');
+}
+
+/**
+ * 获取订阅消息id
+ */
+export function getTemlIds() {
+	return request.get('wechat/teml_ids', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 首页拼团数据
+ */
+export function pink() {
+	return request.get('pink', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取城市信息
+ */
+export function getCity() {
+	return request.get('city_list', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取省市区街道
+ */
+export function getCityData(pid) {
+	return request.get('city', {'pid':pid}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取小程序观看列表
+ */
+export function getLiveList(page, limit) {
+	return request.get('wechat/live', {
+		page,
+		limit
+	}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取首页DIY;
+ */
+export function getDiy(id) {
+	return request.get('diy/get_diy/' + id, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 一键换色;
+ */
+export function colorChange(name) {
+	return request.get('v2/diy/color_change/' + name, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取公众号关注
+ * @returns {*}
+ */
+export function follow() {
+	return request.get("wechat/follow", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 更换手机号码
+ * @returns {*}
+ */
+export function updatePhone(data) {
+	return request.post("user/updatePhone", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 首页优惠券弹窗
+ * @returns {*}
+ */
+export function getCouponV2() {
+	return request.get("v2/get_today_coupon", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 新用户优惠券弹窗
+ * @returns {*}
+ */
+export function getCouponNewUser() {
+	return request.get("v2/new_coupon", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 首页快速选择数据
+ * @param {Object} data
+ */
+export function category(data) {
+	return request.get("category", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 个人搜索历史
+ * @param {Object} data
+ */
+export function searchList(data) {
+	return request.get('v2/user/search_list', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 删除搜索历史
+ */
+export function clearSearch() {
+	return request.get('v2/user/clean_search');
+}
+
+/**
+ * App微信登录
+ * @returns {*}
+ */
+export function wechatAppAuth(data) {
+	return request.post("wechat/app_auth", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 客服配置
+ */
+export function customerType() {
+	return request.get('get_customer_type',{},{
+		noAuth: true
+	});
+}
+
+/**
+ * 获取开屏广告
+ * @returns {*}
+ */
+export function getOpenAdv(data) {
+	return request.get("get_open_adv", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取版权
+ * 
+ */
+export function copyRight() {
+	return request.get('get_copyright', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取用户信息
+ * 
+ */
+export function diyUserInfo() {
+	return request.get('diy/user_info', {});
+}
+
+/**
+ * 新人专享
+ * 
+ */
+export function newcomerList(data) {
+	return request.get('diy/newcomer_list', data,{
+		noAuth: true
+	});
+}
+
+
+
+

+ 19 - 0
api/esp.js

@@ -0,0 +1,19 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * erp设置
+ * 
+ */
+export function erpConfig(id,data) {
+	return request.get('admin/erp/config');
+}

+ 123 - 0
api/kefu.js

@@ -0,0 +1,123 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 客服登录
+ * @param data object 用户账号密码
+ */
+export function kefuLogin(data) {
+  return request.post("login", data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 获取左侧客服聊天用户列表
+ * @constructor
+ */
+export function record (data) {
+  return request.get("user/record", data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 客服话术
+ * @constructor
+ */
+export function speeChcraft (data) {
+  return request.get("service/speechcraft", data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 客服转接列表
+ * @constructor
+ */
+export function transferList (data) {
+  return request.get("service/transfer_list", data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 商品购买记录
+ * @constructor
+ */
+export function productCart (id,data) {
+  return request.get("product/cart/"+id,data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 热销商品
+ * @constructor
+ */
+export function productHot (id,data) {
+  return request.get("product/hot/"+id,data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 商品足记
+ * @constructor
+ */
+export function productVisit (id,data) {
+  return request.get("product/visit/"+id,data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 客服用户聊天列表
+ * @constructor
+ */
+export function serviceList (data) { 
+  return request.get("service/list",data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 客服转接
+ * @constructor
+ */
+export function serviceTransfer (data) { 
+  return request.post("service/transfer",data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 客服详细信息
+ * @constructor
+ */
+export function serviceInfo (data) { 
+  return request.get("service/info",data, { noAuth : true,kefu:true });
+}
+
+/**
+ * 客服反馈头部信息
+ * @constructor
+ */
+export function serviceFeedBack () { 
+  return request.get("user/service/feedback");
+}
+
+/**
+ * 客服反馈
+ * @constructor
+ */
+export function feedBackPost (data) { 
+  return request.post("user/service/feedback", data);
+}
+
+/**
+ * 检测登录code
+ * @constructor
+ */
+export function codeStauts (data) { 
+  return request.get("user/code",data);
+}
+
+/**
+ * 客服扫码登录code
+ * @constructor
+ */
+export function kefuScanLogin (data) { 
+  return request.post("user/code",data);
+}

+ 43 - 0
api/lottery.js

@@ -0,0 +1,43 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 获取抽奖详情信息
+ * 
+ */
+export function getLotteryData(type) {
+	return request.get(`v2/lottery/info/${type}`);
+}
+
+/**
+ * 参与抽奖
+ * 
+ */
+export function startLottery(data) {
+	return request.post(`v2/lottery`, data);
+}
+
+/**
+ * 领奖
+ * 
+ */
+export function receiveLottery(data) {
+	return request.post(`v2/lottery/receive`, data);
+}
+
+/**
+ * 获取中奖记录
+ * 
+ */
+export function getLotteryList(data) {
+	return request.get(`v2/lottery/record`, data);
+}

+ 305 - 0
api/new_store.js

@@ -0,0 +1,305 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 获取附近门店
+ * @param int id
+ * 
+ */
+export function getnearbyStore(data) {
+	return request.get('nearby_store',data, {
+		noAuth: true
+	});
+}
+
+
+/**
+ * 门店商品列表
+ * @param int id
+ * 
+ */
+export function getProducts(data) {
+	return request.get('store/products' ,data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取门店客服列表
+ * @param int id
+ * 
+ */
+export function getCustomerList(store_id) {
+	return request.get('store/customer/list/' + store_id, {},{
+		noAuth: true
+	});
+}
+
+/**
+ * 获取门店客服详情
+ * @param int id
+ * 
+ */
+export function getCustomerInfo(store_id) {
+	return request.get('store/customer/info/' + store_id, {},{
+		noAuth: true
+	});
+}
+
+/**
+ * 门店商品分类
+ * @param int id
+ */
+export function getStoreCategory(data) {
+	return request.get('store/category', data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 门店商品品牌
+ * @param int id
+ */
+export function getStoreBrand(data) {
+	return request.get('store/brand', data,{
+		noAuth: true
+	});
+}
+
+
+/**
+ * 附近门店列表
+ * @param int data
+ */
+export function getList( data) {
+	return request.get('store/list',data, {
+	noAuth: true
+	
+	});
+}
+
+/**
+ * 删除收藏产品
+ * @param int id
+ * @param string category product=普通产品,product_seckill=秒杀产品
+ */
+export function collectDel(id, category) {
+	return request.post('collect/del', {
+		id: id,
+		category: category === undefined ? 'product' : category
+	});
+}
+
+/**
+ * 购车添加
+ * 
+ */
+export function postCartAdd(data) {
+	return request.post('cart/add', data);
+}
+
+/**
+ * 获取分类列表
+ * 
+ */
+export function getCategoryList() {
+	return request.get('category', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取产品列表
+ * @param object data
+ */
+export function getProductslist(data) {
+	return request.get('products', data, {
+		noAuth: true
+	});
+}
+
+
+
+/**
+ * 获取推荐产品
+ * 
+ */
+export function getProductHot(page, limit) {
+	return request.get("product/hot", {
+		page: page === undefined ? 1 : page,
+		limit: limit === undefined ? 4 : limit
+	}, {
+		noAuth: true
+	});
+}
+/**
+ * 批量收藏
+ * 
+ * @param object id  产品编号 join(',') 切割成字符串
+ * @param string category 
+ */
+export function collectAll(id, category) {
+	return request.post('collect/all', {
+		id: id,
+		category: category === undefined ? 'product' : category
+	});
+}
+
+/**
+ * 首页产品的轮播图和产品信息
+ * @param int type 
+ * 
+ */
+export function getGroomList(type, data) {
+	return request.get('groom/list/' + type, data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取收藏列表
+ * @param object data
+ */
+export function getCollectUserList(data) {
+	return request.get('collect/user', data)
+}
+
+/**
+ * 获取浏览记录列表
+ * @param object data
+ */
+export function getVisitList(data) {
+	return request.get('user/visit_list', data)
+}
+
+/**
+ * 获取浏览记录列表-删除
+ * @param object data
+ */
+export function deleteVisitList(data) {
+	return request.delete('user/visit', data)
+}
+
+/**
+ * 获取产品评论
+ * @param int id
+ * @param object data
+ * 
+ */
+export function getReplyList(id, data) {
+	return request.get('v2/reply/list/' + id, data,{noAuth: true})
+}
+
+/**
+ * 产品评价数量和好评度
+ * @param int id
+ */
+export function getReplyConfig(id) {
+	return request.get('reply/config/' + id,{},{noAuth: true});
+}
+
+/**
+ * 评论点赞
+ * @param int id
+ */
+export function getReplyPraise(id) {
+	return request.post('reply/reply_praise/' + id);
+}
+
+/**
+ * 取消评论点赞
+ * @param int id
+ */
+export function getUnReplyPraise(id) {
+	return request.post('reply/un_reply_praise/' + id);
+}
+
+/**
+ * 获取评论详情
+ * @param int id
+ */
+export function getReplyInfo(id) {
+	return request.get('reply/info/' + id);
+}
+
+/**
+ * 获取评论回复列表
+ * @param int id
+ */
+export function getReplyComment(id,data) {
+	return request.get('reply/comment/' + id,data);
+}
+
+/**
+ * 评论回复点赞
+ * @param int id
+ */
+export function postReplyPraise(id) {
+	return request.post('reply/praise/' + id);
+}
+
+/**
+ * 取消评论回复点赞
+ * @param int id
+ */
+export function postUnReplyPraise(id) {
+	return request.post('reply/un_praise/' + id);
+}
+
+/**
+ * 保存商品评价回复
+ * @param int id
+ */
+export function replyComment(id,data) {
+	return request.post('reply/comment/' + id,data);
+}
+
+/**
+ * 获取搜索关键字获取
+ * 
+ */
+export function getSearchKeyword() {
+	return request.get('search/keyword', {}, {
+		noAuth: true
+	});
+}
+
+
+/**
+ * 获取新人礼信息
+ * 
+ */
+export function newcomerInfo() {
+	return request.get('marketing/newcomer/info', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 新人专享商品
+ * 
+ */
+export function newcomerList(data) {
+	return request.get('marketing/newcomer/product_list', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 新人大礼包弹窗
+ * 
+ */
+export function newcomerGift(data) {
+	return request.get('marketing/newcomer/gift');
+}
+
+

+ 387 - 0
api/order.js

@@ -0,0 +1,387 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 获取购物车列表
+ * @param numType boolean true 购物车数量,false=购物车产品数量
+ */
+export function getCartCounts(numType,storeId) {
+	return request.get("cart/count", {
+		numType: numType === undefined ? 0 : numType,
+		store_id:storeId
+	});
+}
+/**
+ * 获取购物车列表
+ * 
+ */
+export function getCartList(data) {
+	return request.get("cart/list", data);
+}
+
+/**
+ * 购物车计算
+ * 
+ */
+export function cartCompute(data) {
+	return request.post("cart/compute", data);
+}
+
+/**
+ * 修改购物车
+ * 
+ */
+export function getResetCart(data) {
+	return request.post("v2/reset_cart", data);
+}
+
+/**
+ * 修改购物车数量
+ * @param int cartId  购物车id
+ * @param int number 修改数量
+ */
+export function changeCartNum(cartId, number) {
+	return request.post("cart/num", {
+		id: cartId,
+		number: number
+	});
+}
+/**
+ * 清除购物车
+ * @param object ids join(',') 切割成字符串
+ */
+export function cartDel(ids,storeId) {
+	if (typeof ids === 'object')
+		ids = ids.join(',');
+	return request.post('cart/del', {
+		ids: ids,
+		store_id: storeId
+	});
+}
+/**
+ * 订单列表
+ * @param object data
+ */
+export function getOrderList(data) {
+	return request.get('order/list', data);
+}
+
+/**
+ * 新订单列表 2.1版本
+ * @param object data
+ */
+export function getNewOrderList(data) {
+	return request.get('order/refund/list', data);
+}
+
+/**
+ * 订单产品信息
+ * @param string unique 
+ */
+export function orderProduct(unique) {
+	return request.post('order/product', {
+		unique: unique
+	});
+}
+
+/**
+ * 订单评价
+ * @param object data
+ * 
+ */
+export function orderComment(data) {
+	return request.post('order/comment', data);
+}
+
+/**
+ * 订单支付
+ * @param object data
+ */
+export function orderPay(data) {
+	return request.post('order/pay', data);
+}
+
+/**
+ * 订单统计数据
+ */
+export function orderData() {
+	return request.get('order/data')
+}
+
+/**
+ * 订单取消
+ * @param string id
+ * 
+ */
+export function orderCancel(id) {
+	return request.post('order/cancel', {
+		id: id
+	});
+}
+
+/**
+ * 删除已完成订单
+ * @param string uni
+ * 
+ */
+export function orderDel(uni) {
+	return request.post('order/del', {
+		uni: uni
+	});
+}
+
+/**
+ * 删除已退款和拒绝退款的订单
+ * @param string uni
+ * 
+ */
+export function refundOrderDel(uni) {
+	return request.get('order/refund/del/' + uni, {});
+}
+
+
+/**
+ * 订单详情
+ * @param string uni 
+ */
+export function getOrderDetail(uni) {
+	return request.get('order/detail/' + uni);
+}
+
+/**
+ * 退款订单详情
+ * @param string uni 
+ */
+export function getRefundOrderDetail(uni) {
+	return request.get('order/refund/detail/' + uni);
+}
+
+/**
+ * 放弃申请退款
+ * @param string uni 
+ */
+export function cancelRefundOrder(uni) {
+	return request.post('order/refund/cancel/' + uni);
+}
+
+/**
+ * 再次下单
+ * @param string uni
+ * 
+ */
+export function orderAgain(uni) {
+	return request.post('order/again', {
+		uni: uni
+	});
+}
+
+/**
+ * 订单收货
+ * @param string uni
+ * 
+ */
+export function orderTake(uni) {
+	return request.post('order/take', {
+		uni: uni
+	});
+}
+
+/**
+ * 订单查询物流信息
+ * @returns {*}
+ */
+export function express(uni, type) {
+	return request.get("order/express/" + uni + (type ? '/' + type : ''));
+}
+
+/**
+ * 获取退款理由
+ * 
+ */
+export function ordeRefundReason() {
+	return request.get('order/refund/reason');
+}
+
+/**
+ * 订单退款审核
+ * @param object data
+ */
+export function orderRefundVerify(data) {
+	return request.post('order/refund/verify', data);
+}
+
+/**
+ * 订单确认获取订单详细信息
+ * @param string cartId
+ */
+export function orderConfirm(cartId, news, addressId, shippingType, store_id, couponId) {
+	return request.post('order/confirm', {
+		cartId,
+		'new': news,
+		addressId,
+		'shipping_type': shippingType,
+		store_id,
+		'couponId':couponId
+	});
+}
+
+/**
+ * 获取当前金额能使用的优惠卷
+ * @param string price
+ * 
+ */
+export function getCouponsOrderPrice(price, data) {
+	return request.get('coupons/order/' + price, data)
+}
+
+/**
+ * 订单创建
+ * @param string key
+ * @param object data
+ * 
+ */
+export function orderCreate(key, data) {
+	return request.post('order/create/' + key, data);
+}
+
+/**
+ * 计算订单金额
+ * @param key
+ * @param data
+ * @returns {*}
+ */
+export function postOrderComputed(key, data) {
+	return request.post("order/computed/" + key, data);
+}
+
+/**
+ * 订单优惠券
+ * @param key
+ * @param data
+ * @returns {*}
+ */
+export function orderCoupon(orderId) {
+	return request.post("v2/order/product_coupon/" + orderId);
+}
+
+/**
+ * 计算会员线下付款金额
+ * @param {Object} data
+ */
+export function offlineCheckPrice(data) {
+	return request.post("order/offline/check/price", data);
+}
+
+/**
+ * 线下扫码付款
+ * @param {Object} data
+ */
+export function offlineCreate(data) {
+	return request.post("order/offline/create", data);
+}
+
+/**
+ * 支付方式开关
+ */
+export function orderOfflinePayType() {
+	return request.get('order/offline/pay/type');
+}
+
+/**
+ * 开票记录
+ */
+export function orderInvoiceList(data) {
+	return request.get('v2/order/invoice_list', data);
+}
+
+/**
+ * 开票订单详情
+ * @param {Object} id
+ */
+export function orderInvoiceDetail(id) {
+	return request.get(`v2/order/invoice_detail/${id}`);
+}
+
+
+/**
+ * 支付宝支付
+ * @param {Object} key
+ * @param {Object} quitUrl
+ */
+export function aliPay(key, quitUrl) {
+	return request.get('ali_pay', {
+		key,
+		quitUrl
+	}, {
+		noAuth: true
+	});
+}
+
+
+/**
+ * 退货物流单号提交
+ * @param {Object} data
+ */
+export function refundExpress(data) {
+	return request.post("order/refund/express", data);
+}
+
+/**
+ * 分类购物车列表
+ */
+export function vcartList(data) {
+	return request.get("v2/cart_list",data);
+}
+
+/**
+ * 支付订单
+ */
+export function payCashier(storeId) {
+	return request.get(`order/pay_cashier?store_id=${storeId}`);
+}
+
+/**
+ * 退款商品列表
+ */
+export function refundGoodsList(orderId) {
+	return request.get(`order/refund/cart_info/${orderId}`);
+}
+
+/**
+ * 申请退款商品列表
+ */
+export function postRefundGoods(data) {
+	return request.post(`order/refund/cart_info`, data);
+}
+
+/**
+ * 退款商品提交
+ */
+export function returnGoodsSubmit(id, data) {
+	return request.post(`order/refund/apply/${id}`, data);
+}
+
+/**
+ * 确认订单详情(是否显示快递配送)
+ */
+export function checkShipping(data) {
+	return request.post(`order/check_shipping`, data);
+}
+
+/**
+ * 配送订单详情
+ */
+export function deliveryDetail(id) {
+	return request.get(`delivery_order/detail/${id}`);
+}
+
+

+ 20 - 0
api/points_mall.js

@@ -0,0 +1,20 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 积分商城
+ */
+export function getStoreIntegral(data) {
+	return request.get("store_integral/index", data, {
+		noAuth: true
+	});
+}

+ 167 - 0
api/public.js

@@ -0,0 +1,167 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+import wechat from "@/libs/wechat.js";
+
+/**
+ * 获取微信sdk配置
+ * @returns {*}
+ */
+export function getWechatConfig() {
+  return request.get(
+    "wechat/config",
+    { url: wechat.signLink() },
+    { noAuth: true }
+  );
+}
+
+/**
+ * 获取微信sdk配置
+ * @returns {*}
+ */
+export function wechatAuth(code, spread, login_type) {
+  return request.get(
+    "wechat/auth",
+    { code, spread, login_type },
+    { noAuth: true }
+  );
+}
+
+/**
+ * 获取登录授权login
+ * 
+*/
+export function getLogo()
+{
+  return request.get('wechat/get_logo', {}, { noAuth : true});
+}
+
+/**
+ * 小程序用户登录
+ * @param data object 小程序用户登陆信息
+ */
+export function login(data) {
+  return request.post("wechat/mp_auth", data, { noAuth : true });
+}
+
+/**
+ * 静默授权
+ * @param {Object} data
+ */
+export function silenceAuth(data) {
+	//#ifdef MP
+  return request.get("v2/wechat/silence_auth", data, { noAuth : true });
+  //#endif
+  //#ifdef H5
+  return request.get("v2/wechat/wx_silence_auth", data, { noAuth : true });
+  //#endif
+}
+
+/**
+ * 分享
+ * @returns {*}
+ */
+export function getShare() {
+  return request.get("share", {}, { noAuth: true });
+}
+
+/**
+ * 获取关注海报
+ * @returns {*}
+ */
+export function follow() {
+  return request.get("wechat/follow", {}, { noAuth: true });
+}
+
+/**
+ * code生成用户
+ * @returns {*}
+ */
+export function authLogin(data) {
+	return request.get("v2/wechat/silence_auth_login", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取图片base64
+ * @retins {*}
+ * */
+export function imageBase64(image, code) {
+  return request.post(
+    "image_base64",
+    { image: image, code: code },
+    { noAuth: true }
+  );
+}
+
+/**
+ * 自动复制口令功能
+ * @returns {*}
+ */
+export function copyWords() {
+  return request.get("copy_words", {}, { noAuth: true });
+}
+
+/**
+ * 获取商城是否强制绑定手机号
+ */
+export function getShopConfig() {
+	return request.get('v2/bind_status' ,{} ,{noAuth : true});
+}
+
+/**
+ * 小程序绑定手机号
+ * @param {Object} data
+ */
+export function getUserPhone(data){
+	return request.post('v2/auth_bindind_phone',data,{noAuth : true});
+}
+
+/**
+ * 小程序用户登录
+ * @param data object 小程序用户登陆信息
+ */
+export function routineLogin(data) {
+	return request.get("v2/wechat/routine_auth", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取微信sdk配置
+ * @returns {*}
+ */
+export function wechatAuthV2(code, spread) {
+	return request.get(
+		"v2/wechat/auth", {
+			code,
+			spread
+		}, {
+			noAuth: true
+		}
+	);
+}
+
+/**
+ * 获取组件底部菜单
+ * @param data object 获取组件底部菜单
+ */
+export function getNavigation(data) {
+	return request.get("navigation", data, {
+		noAuth: true
+	});
+}
+export function getSubscribe(){
+	return request.get("subscribe", {}, {
+		noAuth: true
+	});
+}

+ 93 - 0
api/short-video.js

@@ -0,0 +1,93 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 短视频列表
+ * 
+ */
+export function videoList(data) {
+  return request.get(
+    "marketing/short_video",data,{ noAuth: true }
+  );
+}
+
+/**
+ * diy短视频列表
+ * 
+ */
+export function diyVideoList(data) {
+  return request.get(
+    "diy/video_list",data,{ noAuth: true }
+  );
+}
+
+/**
+ * 短视频点赞、收藏、分享
+ * 
+ */
+export function markeVideo(type,id) {
+  return request.get(
+    `marketing/short_video/${type}/${id}`
+  );
+}
+
+/**
+ * 短视频评论列表
+ * 
+ */
+export function commentList(id,data) {
+  return request.get(
+    `marketing/short_video/comment/${id}`,data
+  );
+}
+
+/**
+ * 短视频评价、评价回复
+ * 
+ */
+export function markeComment(data) {
+  return request.post(
+    `marketing/short_video/comment/${data.id}/${data.pid}`,{content:data.content}
+  );
+}
+
+/**
+ * 短视频评价回复列表
+ * 
+ */
+export function replyCommentList(pid,data) {
+  return request.get(
+    `marketing/short_video/comment_reply/${pid}`,data
+  );
+}
+
+/**
+ * 视频评论点赞
+ * 
+ */
+export function replyCommentLike(type,id) {
+  return request.get(
+    `marketing/short_video/comment/${type}/${id}`
+  );
+}
+
+/**
+ * 短视频关联商品列表
+ * 
+ */
+export function videoProduct(id,data) {
+  return request.get(
+    `marketing/short_video/product/${id}`,data
+  );
+}
+
+

+ 331 - 0
api/store.js

@@ -0,0 +1,331 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 获取产品详情
+ * @param int id
+ * 
+ */
+export function getProductDetail(id,data) {
+	return request.get('product/detail/' + id, data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取产品活动相关详情
+ * @param int id
+ * 
+ */
+export function getProductCtivity(id,data) {
+	return request.get('product/detail/activity/' + id, data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取产品详情中推荐商品列表
+ * @param int id
+ * 
+ */
+export function getProductRecommend(id) {
+	return request.get('product/detail/recommend/' + id, {},{
+		noAuth: true
+	});
+}
+
+/**
+ * 产品分享二维码 推广员
+ * @param int id
+ */
+// #ifdef H5  || APP-PLUS
+export function getProductCode(id) {
+	return request.get('product/code/' + id, {});
+}
+// #endif
+// #ifdef MP
+export function getProductCode(id) {
+	return request.get('product/code/' + id, {
+		user_type: 'routine'
+	});
+}
+// #endif
+
+/**
+ * 添加收藏
+ * @param int id
+ * @param string category product=普通产品,product_seckill=秒杀产品
+ */
+export function collectAdd(id, category) {
+	return request.post('collect/add', {
+		id: id,
+		'category': category === undefined ? 'product' : category
+	});
+}
+
+/**
+ * 删除收藏产品
+ * @param int id
+ * @param string category product=普通产品,product_seckill=秒杀产品
+ */
+export function collectDel(id, category) {
+	return request.post('collect/del', {
+		id: id,
+		category: category === undefined ? 'product' : category
+	});
+}
+
+/**
+ * 购车添加
+ * 
+ */
+export function postCartAdd(data) {
+	return request.post('cart/add', data);
+}
+
+/**
+ * 获取分类列表
+ * 
+ */
+export function getCategoryList() {
+	return request.get('category', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 商品详情diy
+ * @param {*} data 
+ */
+export function diyProduct() {
+	return request.get('v2/diy/product_detail', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取产品列表
+ * @param object data
+ */
+export function getProductslist(data) {
+	return request.get('products', data, {
+		noAuth: true
+	});
+}
+
+
+
+/**
+ * 获取推荐产品
+ * 
+ */
+export function getProductHot(page, limit) {
+	return request.get("product/hot", {
+		page: page === undefined ? 1 : page,
+		limit: limit === undefined ? 4 : limit
+	}, {
+		noAuth: true
+	});
+}
+/**
+ * 批量收藏
+ * 
+ * @param object id  产品编号 join(',') 切割成字符串
+ * @param string category 
+ */
+export function collectAll(id, category) {
+	return request.post('collect/all', {
+		id: id,
+		category: category === undefined ? 'product' : category
+	});
+}
+
+/**
+ * 首页产品的轮播图和产品信息
+ * @param int type 
+ * 
+ */
+export function getGroomList(type, data) {
+	return request.get('groom/list/' + type, data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取收藏列表
+ * @param object data
+ */
+export function getCollectUserList(data) {
+	return request.get('collect/user', data)
+}
+
+/**
+ * 获取浏览记录列表
+ * @param object data
+ */
+export function getVisitList(data) {
+	return request.get('user/visit_list', data)
+}
+
+/**
+ * 获取浏览记录列表-删除
+ * @param object data
+ */
+export function deleteVisitList(data) {
+	return request.delete('user/visit', data)
+}
+
+/**
+ * 获取产品评论
+ * @param int id
+ * @param object data
+ * 
+ */
+export function getReplyList(id, data) {
+	return request.get('v2/reply/list/' + id, data,{noAuth: true})
+}
+
+/**
+ * 产品评价数量和好评度
+ * @param int id
+ */
+export function getReplyConfig(id) {
+	return request.get('reply/config/' + id,{},{noAuth: true});
+}
+
+/**
+ * 评论点赞
+ * @param int id
+ */
+export function getReplyPraise(id) {
+	return request.post('reply/reply_praise/' + id);
+}
+
+/**
+ * 取消评论点赞
+ * @param int id
+ */
+export function getUnReplyPraise(id) {
+	return request.post('reply/un_reply_praise/' + id);
+}
+
+/**
+ * 获取评论详情
+ * @param int id
+ */
+export function getReplyInfo(id) {
+	return request.get('reply/info/' + id);
+}
+
+/**
+ * 获取评论回复列表
+ * @param int id
+ */
+export function getReplyComment(id,data) {
+	return request.get('reply/comment/' + id,data);
+}
+
+/**
+ * 评论回复点赞
+ * @param int id
+ */
+export function postReplyPraise(id) {
+	return request.post('reply/praise/' + id);
+}
+
+/**
+ * 取消评论回复点赞
+ * @param int id
+ */
+export function postUnReplyPraise(id) {
+	return request.post('reply/un_praise/' + id);
+}
+
+/**
+ * 保存商品评价回复
+ * @param int id
+ */
+export function replyComment(id,data) {
+	return request.post('reply/comment/' + id,data);
+}
+
+/**
+ * 获取搜索关键字获取
+ * 
+ */
+export function getSearchKeyword() {
+	return request.get('search/keyword', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 门店列表
+ * @returns {*}
+ */
+export function storeListApi(data) {
+	return request.get("store_list", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 套餐列表
+ * @param int id
+ * 
+ */
+export function storeDiscountsList(id) {
+	return request.get('store_discounts/list/' + id, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 购车添加、减少、修改
+ * 
+*/
+export function postCartNum(data) {
+  return request.post('v2/set_cart_num', data);
+}
+
+/**
+ * 获取首页的属性
+ * @returns {*}
+ */
+export function getAttr(id,type) {
+  return request.get("v2/get_attr/"+id+"/"+type);
+}
+
+/**
+ * 获取店员推广微信会员卡二维码
+ */
+export function storeCardApi() {
+	return request.get("store/staff/card/code");
+}
+
+/**
+ * 分类列表-品牌列表
+ */
+export function brand(data) {
+	return request.get("brand",data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 新人专享商品详情
+ */
+export function newcomerDetail(id) {
+	return request.get("marketing/newcomer/product_detail/"+id,{},{
+		noAuth: true
+	});
+}

+ 731 - 0
api/user.js

@@ -0,0 +1,731 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 获取用户信息
+ * 
+ */
+export function getUserInfo() {
+	return request.get('user');
+}
+
+/**
+ * 登录成功后更新公众号用户信息
+ */
+export function updateWechatInfo(data) {
+	return request.get('v2/user/wechat', data);
+}
+
+/**
+ * 设置用户分享
+ * 
+ */
+export function userShare() {
+	return request.post('user/share');
+}
+
+/**
+ * h5用户登录
+ * @param data object 用户账号密码
+ */
+export function loginH5(data) {
+	return request.post("login", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户手机号登录
+ * @param data object 用户手机号 也只能
+ */
+export function loginMobile(data) {
+	return request.post("login/mobile", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 验证码key
+ */
+export function getCodeApi() {
+	return request.get("verify_code", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户发送验证码
+ * @param data object 用户手机号
+ */
+export function registerVerify(data) {
+	return request.post("register/verify", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户手机号注册
+ * @param data object 用户手机号 验证码 密码
+ */
+export function register(data) {
+	return request.post("register", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户手机号修改密码
+ * @param data object 用户手机号 验证码 密码
+ */
+export function registerReset(data) {
+	return request.post("register/reset", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取用户中心菜单
+ *
+ */
+export function getMenuList() {
+	return request.get("menu/user", {}, {
+		noAuth: true
+	});
+}
+
+/*
+ * 签到用户信息
+ * */
+export function postSignUser(sign) {
+	return request.post("sign/user", sign);
+}
+
+/**
+ * 获取签到配置
+ * 
+ */
+export function getSignConfig() {
+	return request.get('sign/config')
+}
+
+/**
+ * 获取签到列表
+ * @param object data
+ */
+export function getSignList(data) {
+	return request.get('sign/list', data);
+}
+
+/**
+ * 用户签到
+ */
+export function setSignIntegral() {
+	return request.post('sign/integral')
+}
+
+/**
+ * 签到列表(年月)
+ * @param object data
+ * 
+ */
+export function getSignMonthList(data) {
+	return request.get('sign/month', data)
+}
+
+/**
+ * 活动状态
+ * 
+ */
+export function userActivity() {
+	return request.get('user/activity');
+}
+
+/*
+ * 资金明细(types|0=全部,1=消费,2=充值,3=返佣,4=提现)这个接口暂时废弃
+ * */
+export function getCommissionInfo(q, types) {
+	return request.get("spread/commission/" + types, q);
+}
+
+// 资金明细(types|0=全部,1=消费,2=充值,3=返佣,4=提现)
+export function moneyList(q, types) {
+	return request.get("v2/user/money_list/" + types, q);
+}
+
+/*
+ * 积分记录
+ * */
+export function getIntegralList(q) {
+	return request.get("integral/list", q);
+}
+
+/**
+ * 获取分销海报图片
+ * 
+ */
+export function spreadBanner() {
+	//#ifdef H5 || APP-PLUS
+	return request.get('spread/banner', {
+		type: 2
+	});
+	//#endif
+	//#ifdef MP
+	return request.get('spread/banner', {
+		type: 1
+	});
+	//#endif
+
+}
+
+/**
+ *
+ * 获取推广用户一级和二级
+ * @param object data
+ */
+export function spreadPeople(data) {
+	return request.post('spread/people', data);
+}
+
+/**
+ * 
+ * 推广佣金/提现总和
+ * @param int type
+ */
+export function spreadCount(type) {
+	return request.get('spread/count/' + type);
+}
+
+/*
+ * 推广数据
+ * */
+export function getSpreadInfo() {
+	return request.get("commission");
+}
+
+
+/**
+ * 
+ * 推广订单
+ * @param object data
+ */
+export function spreadOrder(data) {
+	return request.post('spread/order', data);
+}
+
+/*
+ * 获取推广人排行
+ * */
+export function getRankList(q) {
+	return request.get("rank", q);
+}
+
+/*
+ * 获取佣金排名
+ * */
+export function getBrokerageRank(q) {
+	return request.get("brokerage_rank", q);
+}
+
+/**
+ * 提现申请
+ * @param object data
+ */
+export function extractCash(data) {
+	return request.post('extract/cash', data)
+}
+
+/**
+ * 提现银行/提现最低金额
+ * 
+ */
+export function extractBank() {
+	return request.get('extract/bank');
+}
+
+/**
+ * 会员等级列表
+ * 
+ */
+export function userLevelGrade() {
+	return request.get('user/level/grade');
+}
+
+/**
+ * 获取某个等级任务
+ * @param int id 任务id
+ */
+export function userLevelTask(id) {
+	return request.get('user/level/task/' + id);
+}
+
+
+/**
+ * 检查用户是否可以成为会员
+ * 
+ */
+export function userLevelDetection() {
+	return request.get('user/level/detection');
+}
+
+/**
+ * 
+ * 地址列表
+ * @param object data
+ */
+export function getAddressList(data) {
+	return request.get('address/list', data);
+}
+
+/**
+ * 设置默认地址
+ * @param int id
+ */
+export function setAddressDefault(id) {
+	return request.post('address/default/set', {
+		id: id
+	})
+}
+
+/**
+ * 修改 添加地址
+ * @param object data
+ */
+export function editAddress(data) {
+	return request.post('address/edit', data);
+}
+
+/**
+ * 删除地址
+ * @param int id
+ * 
+ */
+export function delAddress(id) {
+	return request.post('address/del', {
+		id: id
+	})
+}
+
+/**
+ * 获取单个地址
+ * @param int id 
+ */
+export function getAddressDetail(id) {
+	return request.get('address/detail/' + id);
+}
+
+/**
+ * 修改用户信息
+ * @param object
+ */
+export function userEdit(data) {
+	return request.post('user/edit', data);
+}
+
+/*
+ * 退出登录
+ * */
+export function getLogout() {
+	return request.get("logout");
+}
+/**
+ * 小程序充值
+ * 
+ */
+export function rechargeRoutine(data) {
+	return request.post('recharge/routine', data)
+}
+
+/**
+ * 充值
+ * 
+ */
+export function rechargeRecharge(data) {
+	return request.post('recharge/recharge', data)
+}
+
+/*
+ * 公众号充值
+ * */
+export function rechargeWechat(data) {
+	return request.post("recharge/wechat", data);
+}
+/**
+ * 获取默认地址
+ * 
+ */
+export function getAddressDefault() {
+	return request.get('address/default');
+}
+
+/**
+ * 充值金额选择
+ */
+export function getRechargeApi() {
+	return request.get("recharge/index");
+}
+
+/**
+ * 登陆记录
+ */
+export function setVisit(data) {
+	return request.post('user/set_visit', {
+		...data
+	}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 客服列表
+ */
+export function serviceList() {
+	return request.get("user/service/list");
+}
+/**
+ * 客服详情
+ */
+export function getChatRecord(data) {
+	return request.get("v2/user/service/record", data);
+}
+
+/**
+ * 静默绑定推广人
+ * @param {Object} puid
+ */
+export function spread(puid) {
+	return request.post("user/spread", puid);
+}
+
+/**
+ * 会员详情
+ */
+export function getlevelInfo() {
+	return request.get("user/level/info");
+}
+
+/**
+ * 会员经验列表
+ */
+export function getlevelExpList(data) {
+	return request.get("user/level/expList", data);
+}
+
+/**
+ * 修改用户信息
+ * @param {Object} data
+ */
+export function updateUserInfo(data) {
+	return request.post('v2/user/user_update', data);
+}
+
+/**
+ * 微信直接手机号登录
+ */
+export function phoneWxSilenceAuth(data) {
+	return request.post('v2/phone_wx_silence_auth', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 小程序直接手机号登录
+ */
+export function phoneSilenceAuth(data) {
+	return request.post('v2/phone_silence_auth', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户发票列表
+ * @param {Object} data
+ */
+export function invoiceList(data) {
+	return request.get('v2/invoice', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户添加|修改发票
+ * @param {Object} data
+ */
+export function invoiceSave(data) {
+	return request.post('v2/invoice/save', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户删除发票
+ * @param {Object} data
+ */
+export function invoiceDelete(id) {
+	return request.get('v2/invoice/del/' + id);
+}
+
+/**
+ * 获取用户默认发票
+ * @param {Object} type
+ */
+export function invoiceDefault(type) {
+	return request.get('v2/invoice/get_default/' + type);
+}
+
+/**
+ * 用户单个发票详情
+ * @param {Object} id
+ */
+export function invoiceDetail(id) {
+	return request.get('v2/invoice/detail/' + id);
+}
+
+/**
+ * 订单申请开票
+ * @param {Object} id
+ */
+export function invoiceOrder(data) {
+	return request.post('v2/order/make_up_invoice', data);
+}
+
+/**
+ * 订单详情中申请开票
+ * @param {Object} id
+ */
+export function makeUpinvoice(data) {
+	return request.post('v2/order/make_up_invoice', data);
+}
+
+/**
+ * 会员卡主界面
+ */
+export function memberCard() {
+	return request.get('user/member/card/index');
+}
+
+/**
+ * 卡密领取会员卡
+ * @param {Object} data
+ */
+export function memberCardDraw(data) {
+	return request.post('user/member/card/draw', data);
+}
+
+/**
+ * 购买会员卡
+ * @param {Object} data
+ */
+export function memberCardCreate(data) {
+	return request.post('user/member/card/create', data);
+}
+
+/**
+ * 会员优惠券
+ */
+export function memberCouponsList() {
+	return request.get('user/member/coupons/list');
+}
+
+/**
+ * svip推荐商品
+ * @param {Object} id
+ */
+export function groomList(id, data) {
+	return request.get(`groom/list/${id}`, data);
+}
+
+/**
+ * 付费会员结束
+ * @param {Object} data
+ */
+export function memberOverdueTime(data) {
+	return request.get('user/member/overdue/time', data);
+}
+
+/**
+ * 新版分享海报信息获取
+ * 
+ */
+export function spreadMsg() {
+	return request.get('user/spread_info');
+}
+
+/**
+ * 已邀请/已下单好友
+ * 
+ */
+export function agentUserList(type, page, limit) {
+	return request.get(`v2/agent/agent_user_list/${type}?page=${page}&limit=${limit}`);
+}
+
+/**
+ * 获取用户推广获得收益,佣金轮播,分销规则
+
+ * 
+ */
+export function agentInfo() {
+	return request.get(`v2/agent/agent_info`);
+}
+
+/**
+ * 图片链接转base64
+ * 
+ */
+export function imgToBase(data) {
+	return request.post('image_base64', data);
+}
+
+/**
+ * 获取小程序二维码
+ * 
+ */
+export function routineCode(data) {
+	return request.get('user/routine_code', data);
+}
+
+/**
+ * 消息中心
+ */
+export function serviceRecord(data) {
+	return request.get('user/record', data);
+}
+
+/**
+ * 消息中心-站内信列表
+ */
+export function messageSystem(data) {
+	return request.get('user/message_system/list', data);
+}
+
+/**
+ * 消息中心-站内信列表详情
+ */
+export function getMsgDetails(id) {
+	return request.get('user/message_system/detail/' + id);
+}
+
+/**
+ * 苹果账号登录
+ * @param {Object} data
+ */
+export function appleLogin(data) {
+	return request.post('apple_login', data, {
+		noAuth: true
+	});
+}
+
+/*
+ * 获取隐私协议
+ * */
+export function getUserAgreement(type) {
+	return request.get(`user_agreement/${type}`, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取分销等级列表
+ * @param int id 任务id
+ */
+export function agentLevelList() {
+	return request.get('v2/agent/level_list');
+}
+
+/**
+ * 获取分销任务列表
+ * @param int id 任务id
+ */
+export function agentLevelTaskList(id) {
+	return request.get('v2/agent/level_task_list?id=' + id);
+}
+
+/**
+ * 获取定位详细地址
+ * @param int id
+ * 
+ */
+export function getGeocoder(data) {
+	return request.get(`geoLbscoder?location=${data.lat},${data.long}`, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取当前定位选中的地址
+ * @param int id
+ * 
+ */
+export function getCityList(address) {
+	return request.get('v2/cityList', {
+		address
+	}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取版权
+ * 
+ */
+export function getCopyRight() {
+	return request.get('get_copyright', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取code码
+ * @param int id
+ * 
+ */
+export function getRandCode() {
+	return request.get('user/rand_code');
+}
+
+/**
+ * 注销用户
+ * @param int id
+ * 
+ */
+export function cancelUser() {
+	return request.get('cancel/user');
+}
+
+/**
+ * 获取激活会员卡需要的信息
+ * @param int id
+ * 
+ */
+export function levelInfo() {
+	return request.get('user/level/activate_info');
+}
+
+/**
+ * 用户激活会员卡
+ * @param int id
+ * 
+ */
+export function levelActivate(data) {
+	return request.post('user/level/activate',data);
+}
+
+/**
+ * 小程序审核
+ * 
+ */
+export function getGs(data) {
+	return request.get('pass',data);
+}
+
+
+
+

+ 101 - 0
api/work.js

@@ -0,0 +1,101 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from "@/utils/request.js";
+
+/**
+ * 获取企业微信基础配置
+ * 
+ */
+export function getWorkConfig(url) {
+	return request.get('work/config?url=' + url,{},{
+		noAuth: true
+	});
+}
+
+/**
+ * 获取企业微信配置
+ * 
+ */
+export function getWorkAgentConfig(url) {
+	return request.get('work/agentConfig?url=' + url,{},{
+		noAuth: true
+	});
+}
+
+/**
+ * 获取客户信息详情
+ * 
+ */
+export function getWorkAgentInfo(data) {
+	return request.get('work/client/info',data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 获取客户订单列表
+ * 
+ */
+export function getWorkOrderList(data) {
+	return request.get('work/order/list',data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 获取客户订单详情
+ * 
+ */
+export function getWorkOrderInfo(id,data) {
+	return request.get(`work/order/info/${id}`,data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 购买商品记录
+ * 
+ */
+export function getWorkCartList(data) {
+	return request.get(`work/product/cart_list`,data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 浏览记录商品记录
+ * 
+ */
+export function getWorkVisitInfo(data) {
+	return request.get(`work/product/visit_list`,data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 获取客户群详情
+ * 
+ */
+export function getWorkGroupInfo(data) {
+	return request.get(`work/groupInfo`,data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 获取群成员列表
+ * 
+ */
+export function getWorkGroupMember(id,data) {
+	return request.get(`work/groupMember/${id}`,data,{
+		noAuth: true
+	});
+}

+ 60 - 0
components/Loading/index.vue

@@ -0,0 +1,60 @@
+<template>
+	<!-- 上拉加载 -->
+	<view>
+		<view class="Loads acea-row row-center-wrapper" v-if="loading && !loaded" style="margin-top: .2rem;">
+			<view v-if="loading">
+				<view class="iconfont icon-jiazai loading acea-row row-center-wrapper"></view>
+				<slot name="loading"></slot>
+				正在加载中
+			</view>
+			<view v-else>
+				<slot name="load"></slot>
+				上拉加载更多
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "Loading",
+		props: {
+			loaded: {
+				type: Boolean,
+				default: false
+			},
+			loading: {
+				type: Boolean,
+				default: false
+			}
+		}
+	};
+</script>
+<style>
+	.Loads {
+	  height: 80upx;
+	  font-size: 25upx;
+	  color: #999;
+	}
+	.Loads .iconfont {
+	  font-size: 30upx;
+	  margin-right: 10upx;
+	  height: 32upx;
+	  line-height: 32upx;
+	}
+	/*加载动画*/
+	@keyframes load {
+	  from {
+	    transform: rotate(0deg);
+	  }
+	  to {
+	    transform: rotate(360deg);
+	  }
+	}
+	.loadingpic {
+	  animation: load 3s linear 1s infinite;
+	}
+	.loading {
+	  animation: load linear 1s infinite;
+	}
+</style>

+ 202 - 0
components/addressWindow/index.vue

@@ -0,0 +1,202 @@
+<template>
+	<view>
+		<!-- 下拉选择地址 -->
+		<view class="address-window" :class="address.address==true?'on':''">
+			<view class='title'>选择地址<text class='iconfont icon-guanbi' @tap='close'></text></view>
+			<view class='list'>
+				<view class='item acea-row row-between-wrapper' :class='active==index?"font-num":""' v-for="(item,index) in addressList"
+				 @tap='tapAddress(index,item.id,item)' :key='index'>
+					<text class='iconfont icon-ditu' :class='active==index?"font-num":""'></text>
+					<view class='address'>
+						<view class='name' :class='active==index?"font-num":""'>{{item.real_name}}<text class='phone'>{{item.phone}}</text></view>
+						<view class='line1'>{{item.province}}{{item.city}}{{item.district}}{{item.street}}{{item.detail}}</view>
+						<!-- #ifdef H5 || APP-PLUS -->
+						<slot name="bottom" :item="item"></slot>
+						<!-- #endif -->
+						<!-- #ifdef MP -->
+						<slot name="bottom{{item.id}}"></slot>
+						<!-- #endif -->
+					</view>
+					<text class='iconfont icon-complete' :class='active==index?"font-num":""'></text>
+				</view>
+			</view>
+			<!-- 无地址 -->
+			<view class='pictrue' v-if="!is_loading && !addressList.length">
+				<image :src="imgHost + '/statics/images/noAddress.png'"></image>
+			</view>
+			<view class='addressBnt bg-color' :class="fromType?'on':''" @tap='goAddressPages'>选择其它地址</view>
+		</view>
+		<view class='mask' catchtouchmove="true" :hidden='address.address==false' @tap='close'></view>
+	</view>
+</template>
+
+<script>
+	import {
+		getAddressList
+	} from '@/api/user.js';
+	import {HTTP_REQUEST_URL} from '@/config/app'; 
+	export default {
+		props: {
+			fromType:{
+				type: Number,
+				default: 0,
+			},
+			pagesUrl: {
+				type: String,
+				default: '',
+			},
+			address: {
+				type: Object,
+				default: function() {
+					return {
+						address: true,
+						addressId: 0,
+					};
+				}
+			},
+			isLog: {
+				type: Boolean,
+				default: false,
+			},
+		},
+		data() {
+			return {
+				active: 0,
+				//地址列表
+				addressList: [],
+				is_loading: true,
+				imgHost:HTTP_REQUEST_URL
+			};
+		},
+		methods: {
+			tapAddress: function(e, addressid,row) {
+				this.active = e;
+				this.$emit('OnChangeAddress', addressid,row);
+			},
+			close: function() {
+				this.$emit('changeClose');
+				this.$emit('changeTextareaStatus');
+			},
+			goAddressPages: function() {
+				this.$emit('changeClose');
+				this.$emit('changeTextareaStatus');
+				uni.navigateTo({
+					url: this.pagesUrl
+				});
+			},
+			getAddressList: function() {
+				let that = this;
+				getAddressList({
+					page: 1,
+					limit: 5
+				}).then(res => {
+					let addressList = res.data;
+					//处理默认选中项
+					for (let i = 0, leng = addressList.length; i < leng; i++) {
+						if (addressList[i].id == that.address.addressId) {
+							that.active = i;
+						}
+					}
+					that.$set(that, 'addressList', addressList);
+					that.is_loading = false;
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.mask{
+		z-index: 100 !important;
+	}
+	.address-window {
+		background-color: #fff;
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		width: 100%;
+		z-index: 101;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+	}
+
+	.address-window.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.address-window .title {
+		font-size: 32rpx;
+		font-weight: bold;
+		text-align: center;
+		height: 123rpx;
+		line-height: 123rpx;
+		position: relative;
+	}
+
+	.address-window .title .iconfont {
+		position: absolute;
+		right: 30rpx;
+		color: #8a8a8a;
+		font-size: 35rpx;
+	}
+
+	.address-window .list .item {
+		margin-left: 30rpx;
+		padding-right: 30rpx;
+		border-bottom: 1px solid #eee;
+		height: 129rpx;
+		font-size: 25rpx;
+		color: #333;
+	}
+
+	.address-window .list .item .iconfont {
+		font-size: 37rpx;
+		color: #2c2c2c;
+	}
+
+	.address-window .list .item .iconfont.icon-complete {
+		font-size: 30rpx;
+		color: #fff;
+	}
+
+	.address-window .list .item .address {
+		width: 560rpx;
+	}
+
+	.address-window .list .item .address .name {
+		font-size: 28rpx;
+		font-weight: bold;
+		color: #282828;
+		margin-bottom: 4rpx;
+	}
+
+	.address-window .list .item .address .name .phone {
+		margin-left: 18rpx;
+	}
+
+	.address-window .addressBnt {
+		font-size: 30rpx;
+		font-weight: bold;
+		color: #fff;
+		width: 690rpx;
+		height: 86rpx;
+		border-radius: 43rpx;
+		text-align: center;
+		line-height: 86rpx;
+		margin: 85rpx auto;
+		&.on{
+			margin-bottom: 150rpx;
+		}
+	}
+
+	.address-window .pictrue {
+		width: 414rpx;
+		height: 336rpx;
+		margin: 0 auto;
+	}
+
+	.address-window .pictrue image {
+		width: 100%;
+		height: 100%;
+	}
+</style>

+ 345 - 0
components/authorize/index.vue

@@ -0,0 +1,345 @@
+<template>
+	<view :style="colorStyle">
+		<view class="authorize">
+			<view class="pictrue">
+				<image :src="logoUrl"></image>
+				<view class="iconfont icon-guanbi4" @click='close'></view>
+			</view>
+			<view class="title">账号登录</view>
+			<view class="info">登录注册即同意商城<text class="agree" @click="privacy('user')">《用户协议》</text>与<text class="agree" @click="privacy('privacy')">《隐私协议》</text></view>
+			<button hover-class="none" v-if="mp_is_new" @tap="userLogin"
+				class="btn1">微信授权登录</button>
+			<button v-else-if="canUseGetUserProfile && code" hover-class="none" @tap="getUserProfile"
+					class="btn1">微信授权登录</button>
+			<button v-else hover-class="none" open-type="getUserInfo" @getuserinfo="setUserInfo"
+				class="btn1">微信授权登录</button>
+			<button hover-class="none" @click="isUp = true" class="btn2 acea-row row-center-wrapper">手机一键登录</button>
+		</view>
+		<block v-if="isUp">
+			<mobileLogin :isUp="isUp" @close="maskClose" :authKey="authKey" @wechatPhone="wechatPhone"></mobileLogin>
+		</block>
+		<block v-if="isPhoneBox">
+			<routinePhone :logoUrl="logoUrl" :isPhoneBox="isPhoneBox" @close="bindPhoneClose" :authKey="authKey">
+			</routinePhone>
+		</block>
+		<view class="mask" @click='close'></view>
+	</view>
+</template>
+
+<script>
+	const app = getApp();
+	import mobileLogin from '../loginMobile/index.vue';
+	import routinePhone from '../loginMobile/routine_phone.vue';
+	import {
+		getLogo,
+		silenceAuth,
+		wechatAuthV2,
+		authLogin
+	} from '@/api/public';
+	import {
+		LOGO_URL,
+		EXPIRES_TIME,
+		USER_INFO,
+		STATE_R_KEY
+	} from '@/config/cache';
+	import {
+		getUserInfo
+	} from '@/api/user.js';
+	import Routine from '@/libs/routine';
+	import wechat from '@/libs/wechat';
+	import colors from '@/mixins/color.js';
+	export default {
+		mixins:[colors],
+		props: {
+			isShowAuth: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				isUp: false,
+				phone: '',
+				isPhoneBox: false,
+				logoUrl: '',
+				code: '',
+				authKey: '',
+				options: '',
+				userInfo: {},
+				codeNum: 0,
+				canUseGetUserProfile: false,
+				mp_is_new: this.$Cache.get('MP_VERSION_ISNEW') || false
+			};
+		},
+		components: {
+			mobileLogin,
+			routinePhone
+		},
+		mounted(options) {
+			if (uni.getUserProfile) {
+				this.canUseGetUserProfile = true
+			}
+			getLogo().then(res => {
+				this.logoUrl = res.data.logo_url;
+			});
+			let that = this;
+			// #ifdef MP
+			Routine.getCode()
+				.then(code => {
+					this.code = code
+				})
+			// #endif
+		},
+		methods: {
+			close(){
+				this.$emit('authColse', false);
+			},
+			privacy(type) {
+				uni.navigateTo({
+					url: "/pages/users/privacy/index?type=" + type
+				})
+			},
+			// 小程序 22.11.8日删除getUserProfile 接口获取用户昵称头像
+			userLogin() {
+				Routine.getCode()
+					.then(code => {
+						uni.showLoading({
+							title: '正在登录中'
+						});
+						authLogin({
+							code,
+							spread_spid: app.globalData.spid,
+							spread_code: app.globalData.code
+						}).then(res => {
+							if (res.data.key !== undefined && res.data.key) {
+								uni.hideLoading();
+								this.authKey = res.data.key;
+								this.isPhoneBox = true;
+							} else {
+								uni.hideLoading();
+								let time = res.data.expires_time - this.$Cache.time();
+								this.$store.commit('LOGIN', {
+									token: res.data.token,
+									time: time
+								});
+								this.getUserInfo()
+							}
+			
+						})
+					})
+					.catch(err => {
+						console.log(err)
+					});
+			},
+			// 弹窗关闭
+			maskClose() {
+				this.isUp = false;
+				this.$emit('onLoadFun');
+			},
+			bindPhoneClose(data) {
+				if (data.isStatus) {
+					this.isPhoneBox = false;
+					this.$emit('onLoadFun');
+					// this.$util.Tips({
+					// 	title: '登录成功',
+					// 	icon: 'success'
+					// }, {
+					// 	tab: 3
+					// });
+				} else {
+					this.isPhoneBox = false;
+				}
+			},
+			// #ifdef MP
+			/**
+			 * 获取个人用户信息
+			 */
+			getUserInfo: function() {
+				let that = this;
+				getUserInfo().then(res => {
+					uni.hideLoading();
+					that.userInfo = res.data;
+					that.$store.commit('SETUID', res.data.uid);
+					that.$store.commit('UPDATE_USERINFO', res.data);
+					that.$emit('onLoadFun');
+					that.$util.Tips({
+						title: '登录成功',
+						icon: 'success'
+					});
+				});
+			},
+			setUserInfo(e) {
+				uni.showLoading({
+					title: '正在登录中'
+				});
+				Routine.getCode()
+					.then(code => {
+						this.getWxUser(code);
+					})
+					.catch(res => {
+						uni.hideLoading();
+					});
+			},
+			//小程序授权api替换 getUserInfo
+			getUserProfile() {
+				uni.showLoading({
+					title: '正在登录中'
+				});
+				let self = this;
+				Routine.getUserProfile()
+					.then(res => {
+						let userInfo = res.userInfo;
+						userInfo.code = this.code;
+						userInfo.spread_spid = app.globalData.spid || this.$Cache.get('spread'); //获取推广人ID
+						userInfo.spread_code = app.globalData.code; //获取推广人分享二维码ID
+						Routine.authUserInfo(userInfo)
+							.then(res => {
+								if (res.data.key !== undefined && res.data.key) {
+									uni.hideLoading();
+									self.authKey = res.data.key;
+									self.isPhoneBox = true;
+								} else {
+									uni.hideLoading();
+									let time = res.data.expires_time - self.$Cache.time();
+									self.$store.commit('LOGIN', {
+										token: res.data.token,
+										time: time
+									});
+									this.getUserInfo()
+								}
+							})
+							.catch(res => {
+								uni.hideLoading();
+								uni.showToast({
+									title: res.msg,
+									icon: 'none',
+									duration: 2000
+								});
+							});
+					})
+					.catch(res => {
+						uni.hideLoading();
+					});
+			},
+			getWxUser(code) {
+				let self = this;
+				Routine.getUserInfo()
+					.then(res => {
+						let userInfo = res.userInfo;
+						userInfo.code = code;
+						userInfo.spread_spid = app.globalData.spid; //获取推广人ID
+						userInfo.spread_code = app.globalData.code; //获取推广人分享二维码ID
+						Routine.authUserInfo(userInfo)
+							.then(res => {
+								if (res.data.key !== undefined && res.data.key) {
+									uni.hideLoading();
+									self.authKey = res.data.key;
+									self.isPhoneBox = true;
+								} else {
+									uni.hideLoading();
+									let time = res.data.expires_time - self.$Cache.time();
+									self.$store.commit('LOGIN', {
+										token: res.data.token,
+										time: time
+									});
+									self.$emit('onLoadFun');
+									self.$util.Tips({
+										title: res.msg,
+										icon: 'success'
+									});
+								}
+							})
+							.catch(res => {
+								uni.hideLoading();
+								uni.showToast({
+									title: res.msg,
+									icon: 'none',
+									duration: 2000
+								});
+							});
+					})
+					.catch(res => {
+						uni.hideLoading();
+					});
+			},
+			// #endif
+		}
+	};
+</script>
+
+<style lang="scss">
+	.mask{
+		z-index: 99;
+	}
+	.authorize{
+		width: 100%;
+		height: 680rpx;
+		background-color: #fff;
+		border-radius: 48rpx 48rpx 0 0;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		z-index: 667;
+		padding-top: 50rpx;
+		text-align: center;
+		.pictrue{
+			width: 152rpx;
+			height: 152rpx;
+			border-radius: 50%;
+			margin: 0 auto;
+			position: relative;
+			image{
+				width: 100%;
+				height: 100%;
+				border-radius: 50%;
+				border:1px solid #eee;
+			}
+			.iconfont{
+				position: absolute;
+				width: 52rpx;
+				height: 52rpx;
+				background: #EEE;
+				border-radius: 50%;
+				color: #888;
+				font-size: 30rpx;
+				text-align: center;
+				line-height: 52rpx;
+				right: -267rpx;
+				top: -20rpx;
+			}
+		}
+		.title{
+			margin-top: 28rpx;
+			font-size: 36rpx;
+			color: #333333;
+		}
+		.info{
+			color: #9E9E9E;
+			font-size: 28rpx;
+			margin-top: 14rpx;
+			.agree{
+				color: #333;
+			}
+		}
+		.btn1{
+			width: 536rpx;
+			height: 86rpx;
+			border-radius: 43rpx;
+			color: #fff;
+			text-align: center;
+			line-height: 86rpx;
+			margin: 50rpx auto 0 auto;
+			background-color: #2BA245;
+			font-size: 30rpx;
+		}
+		.btn2{
+			width: 536rpx;
+			height: 86rpx;
+			border-radius: 43rpx;
+			border: 2rpx solid #2BA245;
+			color: #2BA245;
+			font-size: 30rpx;
+			margin: 40rpx auto 0 auto;
+		}
+	}
+</style>

+ 142 - 0
components/cartDiscount/index.vue

@@ -0,0 +1,142 @@
+<template>
+	<view>
+		<!-- 购物车优惠明细 -->
+		<view class="cartDiscount" :class="discountInfo.discount === true ? 'on' : ''">
+			<view class="title">优惠明细<text class="iconfont icon-guanbi5" @click="closeDiscount"></text></view>
+			<view class="list">
+				<view class="item acea-row row-between-wrapper">
+					<view>商品总价:</view>
+					<view>¥{{discountInfo.deduction.sum_price}}</view>
+				</view>
+				<view class="item acea-row row-between-wrapper">
+					<view>优惠抵扣:</view>
+					<view class="font-color">-¥{{$util.$h.Sub(discountInfo.deduction.sum_price,discountInfo.deduction.pay_price)}}</view>
+				</view>
+				<view class="discountList">
+					<view class="coupon acea-row row-between-wrapper" v-if="discountInfo.deduction.coupon_price">
+						<view>{{discountInfo.coupon.coupon_title}}</view>
+						<view>-¥{{discountInfo.deduction.coupon_price}}</view>
+					</view>
+					<view class="coupon acea-row row-between-wrapper" v-if="discountInfo.deduction.first_order_price">
+						<view>新人首单优惠</view>
+						<view>-¥{{discountInfo.deduction.first_order_price}}</view>
+					</view>
+					<view class="coupon acea-row row-between-wrapper" v-if="discountInfo.deduction.promotions_price">
+						<view>优惠活动</view>
+						<view>-¥{{discountInfo.deduction.promotions_price}}</view>
+					</view>
+					<view class="coupon acea-row row-between-wrapper" v-if="discountInfo.deduction.vip_price">
+						<view>会员优惠</view>
+						<view>-¥{{discountInfo.deduction.vip_price}}</view>
+					</view>
+				</view>
+				<div class="item">
+					<slot name="bottom"></slot>
+				</div>
+				<view class="bottom">
+					<view class="item acea-row row-between-wrapper">
+						<view>共优惠:</view>
+						<view class="font-color">-¥{{$util.$h.Sub(discountInfo.deduction.sum_price,discountInfo.deduction.pay_price)}}</view>
+					</view>
+					<view class="item acea-row row-between-wrapper">
+						<view class="total">合计:</view>
+						<view class="money">¥{{discountInfo.deduction.pay_price}}</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="mask" @touchmove.prevent :hidden="discountInfo.discount === false" @click="closeDiscount"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			discountInfo: {
+				type: Object,
+				default: () => {}
+			}
+		},
+		data() {
+			return {};
+		},
+		mounted() {},
+		methods: {
+			closeDiscount(){
+				this.$emit('myevent');
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.discountList{
+		background: #F5F5F5;
+	}
+	.cartDiscount{
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		background-color: #fff;
+		z-index: 9;
+		border-radius: 24rpx 24rpx 0 0;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		padding-bottom: 200rpx;
+		padding-bottom: calc(200rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(200rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		.title{
+			font-size: 32rpx;
+			color: #282828;
+			text-align: center;
+			position: relative;
+			background-color: #F5F5F5;
+			height: 120rpx;
+			line-height: 120rpx;
+			border-radius: 24rpx 24rpx 0 0;
+			.iconfont{
+				position: absolute;
+				right: 30rpx;
+				top:0;
+				font-size: 36rpx;
+			}
+		}
+		.list{
+			max-height: 600rpx;
+			overflow-x: hidden;
+			overflow-y: auto;
+			padding-top: 40rpx;
+			.discountList{
+				width: 692rpx;
+				background: #F5F5F5;
+				margin: 0 auto;
+				border-radius: 12rpx;
+				padding: 0 24rpx;
+			}
+			.coupon{
+				height: 70rpx;
+				font-size: 24rpx;
+			}
+			.bottom{
+				border-top: 2rpx dotted #EEEEEE;
+				margin-top: 30rpx;
+				padding-top: 30rpx;
+				.total{
+					font-size: 30rpx;
+					font-weight: 600;
+				}
+				.money{
+					font-size: 36rpx;
+					font-weight: 600;
+				}
+			}
+			.item{
+				margin: 0 30rpx 30rpx 30rpx;
+			}
+		}
+	}
+	.cartDiscount.on{
+		transform: translate3d(0, 0, 0);
+	}
+</style>

+ 218 - 0
components/cartList/index.vue

@@ -0,0 +1,218 @@
+<template>
+	<view>
+		<!-- 分类购物车下拉列表 -->
+		<view class="cartList" :class="cartData.iScart?'on':''">
+			<view class="title acea-row row-between-wrapper">
+				<view class="name">已选商品</view>
+				<view class="del acea-row row-middle" @click="subDel"><view class="iconfont icon-shanchu1"></view>清空</view>
+			</view>
+			<view class="list">
+				<view class="item acea-row row-between-wrapper" v-for="(item,index) in cartData.cartList" :key="index">
+					<view class="pictrue">
+						<image v-if="item.productInfo.attrInfo" :src='item.productInfo.attrInfo.image'></image>
+						<image v-else :src='item.productInfo.image'></image>
+						<view class="mantle" v-if="!item.status || !item.attrStatus"></view>
+					</view>
+					<view class="txtPic">
+						<view class="name line2" :class="(item.attrStatus && item.status)?'':'on'">{{item.productInfo.store_name}}</view>
+						<view v-if="item.attrStatus && item.status">
+							<view class="info" v-if="item.productInfo.attrInfo">{{item.productInfo.attrInfo.suk}}</view>
+							<!-- #ifdef H5 || APP-PLUS -->
+							<slot name="center" :item="item"></slot>
+							<!-- #endif -->
+							<!-- #ifdef MP -->
+							<slot name="center{{index}}"></slot>
+							<!-- #endif -->
+							<view class="bottom acea-row row-between-wrapper">
+								<view class="money">¥<text class="num">{{item.truePrice}}</text></view>
+								<view class="cartNum acea-row row-middle">
+									<view class="reduce iconfont icon-jianhao1" @click="leaveCart(index)"></view>
+									<view class="num">{{item.cart_num}}</view>
+									<view class="plus iconfont icon-jiahao1" @click="joinCart(index)"></view>
+								</view>
+							</view>
+						</view>
+						<view class="noBnt" v-else-if="!item.attrStatus">已售罄</view>
+						<view class="noBnt" v-else-if="!item.status">已下架</view>
+						<view class="delTxt acea-row row-right" v-if="!item.status || !item.attrStatus"><text @click="oneDel(item.id,index)">删除</text></view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="mask" v-if="cartData.iScart" @click="closeList"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props:{
+			cartData: {
+				type: Object,
+				default: () => {}
+			}
+		},
+		data() {
+			return {};
+		},
+		mounted(){
+		},
+		methods: {
+			closeList(){
+				this.$emit('closeList', false);
+			},
+			leaveCart(index){
+				this.$emit('ChangeCartNumDan', false,index);
+			},
+			joinCart(index){
+				this.$emit('ChangeCartNumDan', true,index);
+			},
+			subDel(){
+				this.$emit('ChangeSubDel');
+			},
+			oneDel(id,index){
+				this.$emit('ChangeOneDel',id,index);
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.mask{
+		z-index: 99;
+	}
+	.cartList{
+		position: fixed;
+		left:0;
+		bottom: 0;
+		width: 100%;
+		background-color: #fff;
+		z-index:100;
+		padding: 0 30rpx 200rpx 30rpx;
+		padding-bottom: calc(200rpx + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(200rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		box-sizing: border-box;
+		border-radius:16rpx 16rpx 0 0;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		&.on{
+			transform: translate3d(0, 0, 0);
+		}
+		.title{
+			height: 108rpx;
+			.name{
+				font-size:28rpx;
+				color: #282828;
+				font-weight:bold;
+			}
+			.del{
+				font-size: 26rpx;
+				color: var(--view-theme);
+				.iconfont{
+					margin-right: 5rpx;
+					font-size: 34rpx;
+				}
+			}
+		}
+		.list{
+			max-height: 720rpx;
+			overflow-x: hidden;
+			overflow-y: auto;
+			.item{
+				margin-bottom: 40rpx;
+				.pictrue{
+					width: 176rpx;
+					height: 176rpx;
+					border-radius: 16rpx;
+					position: relative;
+					image{
+						width: 100%;
+						height: 100%;
+						border-radius: 16rpx;
+					}
+					.mantle{
+						position: absolute;
+						top:0;
+						left:0;
+						width: 100%;
+						height: 100%;
+						background:rgba(255,255,255,0.65);
+						border-radius:16rpx;
+					}
+				}
+				.txtPic{
+					width: 486rpx;
+					.name{
+						font-size:28rpx;
+						color: #282828;
+						&.on{
+							color: #A3A3A3;
+						}
+					}
+					.noBnt{
+						width:126rpx;
+						height:44rpx;
+						background:rgba(242,242,242,1);
+						border-radius:22rpx;
+						text-align: center;
+						line-height: 44rpx;
+						font-size: 24rpx;
+						color: #A3A3A3;
+						margin-top: 10rpx;
+					}
+					.delTxt{
+						margin-top: 48rpx;
+						font-size: 24rpx;
+						color: #E93323;
+						text{
+							width: 70rpx;
+							height: 50rpx;
+							text-align: center;
+							line-height: 50rpx;
+						}
+					}
+					.info{
+						font-size: 23rpx;
+						color: #989898;
+						margin-top: 5rpx;
+					}
+					.bottom{
+						margin-top: 11rpx;
+						.money{
+							font-weight:bold;
+							font-size: 26rpx;
+							color: var(--view-priceColor);
+							.num{
+								font-size: 34rpx;
+							}
+						}
+						.cartNum{
+							font-weight:bold;
+						    .num{
+								font-size: 34rpx;
+								color: #282828;
+								width: 120rpx;
+								text-align: center;
+							}
+							.reduce{
+								color: #282828;
+								font-size: 24rpx;
+								width: 60rpx;
+								height: 60rpx;
+								text-align: center;
+								line-height: 60rpx;
+							}
+							.plus{
+								color: #282828;
+								font-size: 24rpx;
+								width: 60rpx;
+								height: 60rpx;
+								text-align: center;
+								line-height: 60rpx;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 134 - 0
components/countDown/index.vue

@@ -0,0 +1,134 @@
+<template>
+	<view class="time" :style="justifyLeft">
+		<!-- 倒计时 -->
+		<text class="red" v-if="tipText.trim()">{{ tipText }}</text>
+		<text class="styleAll" :style="'background-color:'+ bgColor +';color:'+ colors +';'" v-if="isDay === true">{{ day }}</text>
+		<text class="timeTxt red" :style="'color:'+colors" v-if="dayText">{{ dayText }}</text>
+		<text class="styleAll" :style="'background-color:'+ bgColor +';color:'+ colors +';'">{{ hour }}</text>
+		<text class="timeTxt red" :style="'color:'+colors" v-if="hourText">{{ hourText }}</text>
+		<text class="styleAll" :style="'background-color:'+ bgColor +';color:'+ colors +';'">{{ minute }}</text>
+		<text class="timeTxt red" :style="'color:'+colors" v-if="minuteText">{{ minuteText }}</text>
+		<text class="styleAll" :style="'background-color:'+ bgColor +';color:'+ colors +';'" v-if="isSecond === true">{{ second }}</text>
+		<text class="timeTxt red" :style="'color:'+colors" v-if="secondText">{{ secondText }}</text>
+		<slot name="bottom"></slot>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "countDown",
+		props: {
+			justifyLeft: {
+				type: String,
+				default: ""
+			},
+			//距离开始提示文字
+			tipText: {
+				type: String,
+				default: "倒计时"
+			},
+			dayText: {
+				type: String,
+				default: "天"
+			},
+			hourText: {
+				type: String,
+				default: "时"
+			},
+			minuteText: {
+				type: String,
+				default: "分"
+			},
+			secondText: {
+				type: String,
+				default: "秒"
+			},
+			datatime: {
+				type: Number,
+				default: 0
+			},
+			isDay: {
+				type: Boolean,
+				default: true
+			},
+			isSecond: {
+				type: Boolean,
+				default: true
+			},
+			bgColor:{
+				type: String,
+				default: ""
+			},
+			colors:{
+				type: String,
+				default: ""
+			}
+		},
+		data: function() {
+			return {
+				day: "00",
+				hour: "00",
+				minute: "00",
+				second: "00"
+			};
+		},
+		created: function() {
+			this.show_time();
+		},
+		mounted: function() {},
+		methods: {
+			show_time: function() {
+				let that = this;
+
+				function runTime() {
+					//时间函数
+					let intDiff = that.datatime - Date.parse(new Date()) / 1000; //获取数据中的时间戳的时间差;
+					let day = 0,
+						hour = 0,
+						minute = 0,
+						second = 0;
+					if (intDiff > 0) {
+						//转换时间
+						if (that.isDay === true) {
+							day = Math.floor(intDiff / (60 * 60 * 24));
+						} else {
+							day = 0;
+						}
+						hour = Math.floor(intDiff / (60 * 60)) - day * 24;
+						minute = Math.floor(intDiff / 60) - day * 24 * 60 - hour * 60;
+						second =
+							Math.floor(intDiff) -
+							day * 24 * 60 * 60 -
+							hour * 60 * 60 -
+							minute * 60;
+						if (hour <= 9) hour = "0" + hour;
+						if (minute <= 9) minute = "0" + minute;
+						if (second <= 9) second = "0" + second;
+						that.day = day;
+						that.hour = hour;
+						that.minute = minute;
+						that.second = second;
+					} else {
+						that.day = "00";
+						that.hour = "00";
+						that.minute = "00";
+						that.second = "00";
+					}
+				}
+				runTime();
+				setInterval(runTime, 1000);
+			}
+		}
+	};
+</script>
+
+<style>
+	.time{
+		display: flex;
+		justify-content: center;
+	} 
+	.red{
+		color: var(--view-theme);
+		margin: 0 4rpx;
+	}
+</style>

+ 282 - 0
components/couponListWindow/index.vue

@@ -0,0 +1,282 @@
+<template>
+	<view>
+		<!-- 优惠券下拉列表 -->
+		<view class='coupon-list-window' :class='[coupon.coupon==true?"on":"",coupon.goFrom==1?"cart":""]'>
+			<view v-if="coupon.count" class="nav acea-row row-around">
+				<view v-if="coupon.count[2]" :class="['acea-row', 'row-middle', coupon.type === 2 ? 'on' : '']" @click="setType(2)">商品券</view>
+				<view v-if="coupon.count[1]" :class="['acea-row', 'row-middle', coupon.type === 1 ? 'on' : '']" @click="setType(1)">品类券</view>
+				<view v-if="coupon.count[0]" :class="['acea-row', 'row-middle', coupon.type === 0 ? 'on' : '']" @click="setType(0)">通用券</view>
+			</view>
+			<view class='title' v-else>优惠券<text class='iconfont icon-guanbi' @click='close'></text></view>
+			<view v-if="coupon.count" class="occupy"></view>
+			<view class='coupon-list' v-if="coupon.list.length">
+				<view class='item acea-row row-center-wrapper' v-for="(item,index) in coupon.list" @click="getCouponUser(index,item.id)"
+				 :key='index' :class="{svip: item.receive_type === 4}">
+				  <view class="moneyCon acea-row row-center-wrapper">
+						<view class='money acea-row row-column row-center-wrapper' :class='item.is_use && coupon.count?"moneyGray":""'>
+							<view><text v-if="item.coupon_type==1">¥</text><text class='num'>{{item.coupon_type==1?item.coupon_price:parseFloat(item.coupon_price)/10}}</text><text v-if="item.coupon_type==2">折</text></view>
+							<view class="pic-num" v-if="item.use_min_price > 0">满{{item.use_min_price}}元可用</view>
+							<view class="pic-num" v-else>无门槛券</view>
+						</view>
+					</view>
+					<view class='text'>
+						<view class='condition line2' :class="coupon.count?'':'order'">
+							<span class='line-title' :class='item.is_use && coupon.count?"gray":""' v-if='item.type===0'>通用劵</span>
+							<span class='line-title' :class='item.is_use && coupon.count?"gray":""' v-else-if='item.type===1'>品类券</span>
+							<span class='line-title' :class='item.is_use && coupon.count?"gray":""' v-else>商品券</span>
+							<image src='../../static/images/fvip.png' class="pic" v-if="item.receive_type===4"></image>
+							<span class='name'>{{item.title}}</span>
+						</view>
+						<!-- #ifdef H5 || APP-PLUS -->
+						<slot name="center" :item="item"></slot>
+						<!-- #endif -->
+						<!-- #ifdef MP -->
+						<slot name="center{{index}}"></slot>
+						<!-- #endif -->
+						<view class='data acea-row row-between-wrapper'>
+							<view v-if="item.coupon_time && !openType">领取后{{item.coupon_time}}天内可用</view>
+							<view v-else>{{ item.start_time ? item.start_time + "-" : ""}}{{ item.end_time }}</view>
+							<view v-if="coupon.count">
+								<view class='bnt gray' v-if="item.is_use">{{item.use_title || '已领取'}}</view>
+								<view class='bnt bg-color' v-else>{{coupon.statusTile || '立即领取'}}</view>
+							</view>
+							<view v-else class="orderCou">
+								<view class="iconfont icon-xuanzhong11" :class="item.receive_type === 4?'svip':'font-num'" v-if="item.is_use"></view>
+								<view class="iconfont icon-weixuan" v-else></view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<!-- 无优惠券 -->
+			<view class='pictrue' v-else>
+				<image :src="imgHost + '/statics/images/noCoupon.png'"></image>
+			</view>
+		</view>
+		<view class='mask' catchtouchmove="true" :hidden='coupon.coupon==false' @click='close'></view>
+	</view>
+</template>
+
+<script>
+	import {
+		setCouponReceive
+	} from '@/api/api.js';
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default {
+		props: {
+			//打开状态 0=领取优惠券,1=使用优惠券
+			openType: {
+				type: Number,
+				default: 0,
+			},
+			coupon: {
+				type: Object,
+				default: function() {
+					return {};
+				}
+			}
+		},
+		data() {
+			return {
+				type: 0,
+				imgHost:HTTP_REQUEST_URL
+			};
+		},
+		methods: {
+			close: function() {
+				this.$emit('ChangCouponsClone');
+				this.type = 0;
+			},
+			getCouponUser: function(index, id) {
+				let that = this;
+				let list = that.coupon.list;
+				if (list[index].is_use == true && this.openType == 0) return true;
+				switch (this.openType) {
+					case 0:
+						//领取优惠券
+						setCouponReceive(id).then(res => {
+							that.$emit('ChangCouponsUseState', index);
+							that.$util.Tips({
+								title: "领取成功"
+							});
+							// that.$emit('ChangCoupons', list[index]);
+						}).catch(err => {
+							uni.showToast({
+								title: err,
+								icon: 'none'
+							});
+						})
+						break;
+					case 1:
+						that.$emit('ChangCoupons', index);
+						break;
+				}
+			},
+			setType: function(type) {
+				this.type = type;
+				this.$emit('tabCouponType', type);
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.orderCou{
+		position: absolute;
+		right: 20rpx;
+		top:50%;
+		margin-top: -20rpx;
+	}
+	.orderCou .iconfont{
+		font-size: 40rpx;
+	}
+	.orderCou .svip{
+		color:#EDBB75;
+	}
+	.coupon-list .item .text{
+		position: relative;
+	}
+	.coupon-list .item .text .condition.order{
+		width: 350rpx;
+	}
+	.coupon-list-window .coupon-list .text .condition .pic {
+		width: 30rpx;
+		height: 30rpx;
+		margin-right: 10rpx;
+		vertical-align: middle;
+	}
+
+	.coupon-list-window .coupon-list .text .condition .name {
+		vertical-align: middle;
+		font-size: 26rpx;
+		font-weight: 500;
+	}
+
+	.coupon-list-window {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		width: 100%;
+		background-color: #FFFFFF;
+		border-radius: 16rpx 16rpx 0 0;
+		z-index: 555;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+	}
+
+	.coupon-list-window.on {
+		transform: translate3d(0, 0, 0);
+	}
+	
+	.coupon-list-window.cart{
+		padding-bottom: 150rpx;
+		padding-bottom: calc(150rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(150rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+	}
+
+	.coupon-list-window .title {
+		height: 124rpx;
+		width: 100%;
+		text-align: center;
+		line-height: 124rpx;
+		font-size: 32rpx;
+		font-weight: bold;
+		position: relative;
+	}
+
+	.coupon-list-window .title .iconfont {
+		position: absolute;
+		right: 30rpx;
+		top: 50%;
+		transform: translateY(-50%);
+		font-size: 35rpx;
+		color: #8a8a8a;
+		font-weight: normal;
+	}
+
+	.coupon-list-window .coupon-list {
+		margin: 0 0 50rpx 0;
+		height: 721rpx;
+		padding-top: 28rpx;
+		overflow: auto;
+	}
+
+	.coupon-list-window .pictrue {
+		width: 414rpx;
+		height: 336rpx;
+		margin: 192rpx auto 243rpx auto;
+	}
+
+	.coupon-list-window .pictrue image {
+		width: 100%;
+		height: 100%;
+	}
+
+	.pic-num {
+		color: #fff;
+		font-size: 24rpx;
+	}
+
+	.line-title {
+		width: 70rpx;
+		height: 32rpx !important;
+		padding: 0 10rpx;
+		line-height: 30rpx;
+		text-align: center;
+		background: var(--view-minorColorT);
+		border: 1px solid var(--view-theme);
+		opacity: 1;
+		border-radius: 20rpx;
+		font-size: 18rpx;
+		color: var(--view-theme);
+		margin-right: 12rpx;
+		box-sizing: border-box;
+	}
+
+	.line-title.gray {
+		border-color: #C1C1C1!important;
+		color: #C1C1C1!important;
+		background-color: #F7F7F7!important;
+	}
+
+	.nav {
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 106rpx;
+		border-bottom: 2rpx solid #F5F5F5;
+		border-top-left-radius: 16rpx;
+		border-top-right-radius: 16rpx;
+		background-color: #FFFFFF;
+		font-size: 30rpx;
+		color: #999999;
+	}
+
+	.nav .acea-row {
+		border-top: 5rpx solid transparent;
+		border-bottom: 5rpx solid transparent;
+	}
+
+	.nav .acea-row.on {
+		border-bottom-color: var(--view-theme);
+		color: #282828;
+	}
+
+	.nav .acea-row:only-child {
+		border-bottom-color: transparent;
+	}
+
+	.occupy {
+		height: 106rpx;
+	}
+
+	.coupon-list .item {
+		margin-bottom: 18rpx;
+		box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.06);
+	}
+
+	.coupon-list .item .money {
+		font-weight: normal;
+	}
+</style>

+ 248 - 0
components/couponWindow/index.vue

@@ -0,0 +1,248 @@
+<template>
+	<view :style="colorStyle">
+		<!-- 优惠券弹窗 -->
+		<view class='coupon-window' :class='window==true?"on":""'>
+			<image class="co-bag" :src="imgHost + '/statics/images/co-bag.png'" mode=""></image>
+			<view class='couponWinList'>
+				<view class='item acea-row row-between-wrapper' v-for="(item,index) in couponList" :key="index">
+					<view class='money font-color'><text v-if="item.coupon_type==1">¥</text><text class='num'>{{item.coupon_type==1?item.coupon_price:parseFloat(item.coupon_price)/10}}</text><text v-if="item.coupon_type==2">折</text></view>
+					<view class='text'>
+						<view v-if="item.coupon_type==1" class='name'>购物满{{item.use_min_price}}元减{{item.coupon_price}}元</view>
+						<view v-else class='name'>购物满{{item.use_min_price}}元打{{parseFloat(item.coupon_price)/10}}折</view>
+						<view v-if="item.coupon_time">领取后{{item.coupon_time}}天内可用</view>
+						<view v-else>{{item.start_time ? item.start_time+'-' : ''}}{{item.end_time === 0 ? '不限时': item.end_time}}</view>
+						<!-- #ifdef H5 || APP-PLUS -->
+						<slot name="bottom" :item="item"></slot>
+						<!-- #endif -->
+						<!-- #ifdef MP -->
+						<slot name="bottom{{index}}"></slot>
+						<!-- #endif -->
+					</view>
+				</view>
+			</view>
+			<view class='lid'>
+				<navigator hover-class='none' url='/pages/users/user_get_coupon/index' class='bnt'>立即领取</navigator>
+				<view class='iconfont icon-guanbi3' @click="close"></view>
+			</view>
+		</view>
+		<view class='mask' catchtouchmove="true" :hidden="window==false"></view>
+	</view>
+</template>
+
+<script>
+	import colors from "@/mixins/color";
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default {
+		props: {
+			window: {
+				type: Boolean | String | Number,
+				default: false,
+			},
+			couponList: {
+				type: Array,
+				default: function() {
+					return []
+				},
+			},
+			couponImage: {
+				type: String,
+				default: '',
+			},
+		},
+		mixins: [colors],
+		data() {
+			return {
+				imgHost:HTTP_REQUEST_URL
+			};
+		},
+		methods: {
+			close:function(){
+			      this.$emit('onColse');
+			    }
+		}
+	}
+</script>
+
+
+<style scoped lang="scss">
+	.mask {
+		z-index: 9999;
+	}
+
+	.coupon-window {
+		width: 572rpx;
+		height: 760rpx;
+		position: fixed;
+		top: 20%;
+		z-index: 10000;
+		left: 50%;
+		margin-left: -286rpx;
+		transform: translate3d(0, -200%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		border-radius: 30rpx 30rpx 0 0;
+		overflow-x: hidden;
+	}
+
+	.co-bag {
+		width: 100%;
+		height: 250rpx;
+		z-index: 33333;
+		top: -40rpx;
+		position: absolute;
+	}
+
+	.coupon-window:after {
+		width: 900rpx;
+		height: 650rpx;
+		position: absolute;
+		top: 0%;
+		left: 50%;
+		z-index: 11111;
+		margin-left: -450rpx;
+		content: '';
+		border-radius: 50% 50% 0 0;
+		background: var(--view-theme);
+	}
+
+	.coupon-window.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.coupon-window .couponWinList {
+		width: 480rpx;
+		margin: 157rpx 0 0 50rpx;
+		height: 340rpx;
+		overflow: auto;
+	}
+
+	.coupon-window .couponWinList .item {
+		width: 100%;
+		height: 120rpx;
+		background-color: #fff;
+		position: relative;
+		margin-bottom: 17rpx;
+		position: relative;
+		z-index: 99999;
+	}
+
+	.coupon-window .couponWinList .item .left {
+		border-right: 1px dashed #ccc;
+	}
+
+	.coupon-window .couponWinList .label {
+		width: 28rpx;
+		height: 64rpx;
+		display: block;
+		position: absolute;
+		top: 0;
+		right: 12rpx;
+	}
+
+	.coupon-window .couponWinList .item::after {
+		content: '';
+		position: absolute;
+		width: 18rpx;
+		height: 18rpx;
+		border-radius: 50%;
+		background-color: var(--view-theme);
+		left: 25.5%;
+		bottom: 0;
+		margin-bottom: -9rpx;
+	}
+
+	.coupon-window .couponWinList .item::before {
+		content: '';
+		position: absolute;
+		width: 18rpx;
+		height: 18rpx;
+		border-radius: 50%;
+		background-color: var(--view-theme);
+		left: 25.5%;
+		top: 0;
+		margin-top: -9rpx;
+	}
+
+	.coupon-window .couponWinList .item .money {
+		width: 130rpx;
+		text-align: center;
+		font-size: 26rpx;
+		font-weight: bold;
+	}
+
+	.coupon-window .couponWinList .item .min_money {
+		color: #ccc;
+		font-size: 18rpx;
+		text-align: center;
+	}
+
+	.coupon-window .couponWinList .item .money .num {
+		font-size: 40rpx;
+	}
+
+	.coupon-window .couponWinList .item .text {
+		width: 349rpx;
+		font-size: 22rpx;
+		color: #ccc;
+		padding: 0 29rpx;
+		box-sizing: border-box;
+	}
+
+	.coupon-window .couponWinList .item .text .image {
+		width: 32rpx;
+		height: 32rpx;
+		display: inline-block;
+		vertical-align: bottom;
+		margin-right: 10rpx;
+	}
+
+	.coupon-window .couponWinList .item .text .name {
+		font-size: 26rpx;
+		color: var(--view-priceColor);
+		font-weight: bold;
+		margin-bottom: 9rpx;
+		width: 250rpx;
+	}
+	.coupon-window .lid {
+		background: rgba(255,255,255,0.2);
+		width: 582rpx;
+		height: 224rpx;
+		position: fixed;
+		z-index: 22222;
+		left: 50%;
+		top: 0%;
+		margin: 424rpx 0 0 -296rpx;
+	}
+	
+	.coupon-window .lid:after {
+		width: 920rpx;
+		height: 280rpx;
+		position: absolute;
+		top: -100%;
+		left: 50%;
+		z-index: 22222;
+		margin-left: -460rpx;
+		content: '';
+		border-radius: 0 0 50% 50%;
+		background: var(--view-theme);
+	}
+	
+	.coupon-window .lid .bnt {
+		font-size: 29rpx;
+		width: 440rpx;
+		height: 80rpx;
+		border-radius: 40rpx;
+		background: linear-gradient(90deg, #FFCA52 0%, #FE960F 100%);
+		text-align: center;
+		line-height: 80rpx;
+		font-weight: bold;
+		margin: 98rpx auto 0 auto;
+		color: #fff;
+	}
+	
+	.coupon-window .lid .iconfont {
+		color: #fff;
+		font-size: 60rpx;
+		text-align: center;
+		margin-top: 87rpx;
+	}
+</style>

+ 150 - 0
components/cusPreviewImg/index.vue

@@ -0,0 +1,150 @@
+<template>
+	<!-- 属性规格放大图轮播 -->
+	<view class="previewImg" v-if="showBox" @touchmove.stop.prevent>
+		<view class="mask" @click="close">
+			<swiper @change="changeSwiper" class="mask-swiper" :current="currentIndex" :circular="circular" :duration="duration">
+				<swiper-item v-for="(src, i) in list" :key="i" class="flex flex-column justify-center align-center">
+					<image class="mask-swiper-img" :src="src.image" mode="widthFix" />
+					<view class="mask_sku">
+						<text class="sku_name">{{src.suk}}</text>
+						<text class="sku_price">¥{{src.price}}</text>
+						<!-- #ifdef H5 || APP-PLUS -->
+						<slot name="info" :item="src"></slot>
+						<!-- #endif -->
+						<!-- #ifdef MP -->
+						<slot name="info{{i}}"></slot>
+						<!-- #endif -->
+					</view>
+				</swiper-item>
+			</swiper>
+		</view>
+		<view class="pagebox" v-if="list.length>0">{{ Number(currentIndex) + 1 }} / {{ list.length }}</view>
+		<!-- #ifndef MP -->
+		<!-- <text class="iconfont icon-fenxiang share_btn" @click="shareFriend()"></text> -->
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'cus-previewImg',
+		props: {
+			list: {
+				type: Array,
+				required: true,
+				default: () => {
+					return [];
+				}
+			},
+			circular: {
+				type: Boolean,
+				default: true
+			},
+			duration: {
+				type: Number,
+				default: 500
+			}
+		},
+		data() {
+			return {
+				currentIndex: 0,
+				showBox: false
+			};
+		},
+		watch: {
+			list(val) {
+				// console.log('图片预览', val)
+			}
+		},
+		methods: {
+			// 左右切换
+			changeSwiper(e) {
+				this.currentIndex = e.target.current;
+				this.$emit('changeSwitch',e.target.current)
+			},
+			open(current) {
+				if (!current || !this.list.length) return;
+				this.currentIndex = this.list.map((item)=>item.suk).indexOf(current);
+				this.showBox = true;
+			},
+			close() {
+				this.showBox = false;
+			}
+			// shareFriend(){
+			// 	this.$emit('shareFriend')
+			// }
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+@mixin full {
+	width: 100%;
+	height: 100%;
+}
+
+.previewImg {
+	position: fixed;
+	top: 0;
+	left: 0;
+	z-index: 300;
+	@include full;
+	.mask {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background-color: #000;
+		opacity: 1;
+		z-index: 8;
+		@include full;
+		&-swiper {
+			@include full;
+			&-img {
+				width: 100%;
+			}
+		}
+	}
+	.pagebox{
+		position: absolute;
+		width: 100%;
+		bottom: 20rpx;
+		z-index: 300;
+		color: #fff;
+		text-align: center;
+	}
+}
+.mask_sku{
+	color: #fff;
+	max-width: 80%;
+	z-index: 300;
+	text-align: center;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	margin-top: 30rpx;
+	.sku_name{
+		font-size: 12px;
+		border: 1px solid #fff;
+		padding: 10rpx 30rpx 10rpx;
+		border-radius: 40px;
+		box-sizing: border-box;
+	}
+	.sku_price{
+		padding-top: 10px;
+	}
+}
+.font12{
+	font-size: 24rpx;
+}
+.share_btn{
+	position: absolute;
+	top:70rpx;
+	right:50rpx;
+	font-size: 40rpx;
+	color:#fff;
+	z-index: 300;
+}
+.flex-column{flex-direction: column;}
+.justify-center {justify-content: center;}
+.align-center {align-items: center;}
+</style>

+ 91 - 0
components/customForm/index.vue

@@ -0,0 +1,91 @@
+<template>
+	<!-- 自定义组件 -->
+	<view class='wrapper card' v-if="customForm && customForm.length && isShow">
+		<view class='item acea-row row-between' v-for="(item,index) in customForm" :key="index" v-if="item.value">
+			<view>{{item.title}}:</view>
+			<view v-if="item.label == 'img'" class='conter'>
+				<view class='pictrue' v-for="(img,indexn) in item.value" :key="indexn">
+					<image :src='img' mode="aspectFill" @click='getCustomForm(index,indexn)'></image>
+				</view>
+			</view>
+			<view v-if="item.label != 'img'" class='conter'>{{item.value}}</view>
+		</view>
+		<slot name="bottom"></slot>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'customForm',
+		props: {
+			customForm:{
+				type: Array,
+				default: () => []
+			}
+		},
+		data() {
+			return {
+				isShow:0
+			};
+		},
+		watch: {
+			customForm (value) {
+				if(value && value.length){
+					value.forEach((item)=>{
+						if(item.value){
+							return this.isShow = 1
+						}
+					})
+				}
+			}
+		},
+		created() {},
+		mounted() {},
+		methods: {
+			getCustomForm: function(index,indexn) {
+				uni.previewImage({
+					urls: this.customForm[index].value,
+					current: this.customForm[index].value[indexn]
+				});
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	.wrapper{
+		    background-color: #fff;
+		    margin-top: 6px;
+		    padding: 15px;
+	}
+	.wrapper .item {
+		font-size: 28rpx;
+		color: #282828;
+	}
+	
+	.wrapper .item~.item {
+		margin-top: 20rpx;
+		white-space: normal;
+		word-break: break-all;
+		word-wrap: break-word;
+	}
+	
+	.wrapper .item .conter {
+		color: #868686;
+		width: 460rpx;
+		display: flex;
+		flex-wrap: nowrap;
+		justify-content: flex-end;
+		text-align: right;
+		.pictrue{
+			width: 80rpx;
+			height: 80rpx;
+			margin-left: 6rpx;
+			image{
+				width: 100%;
+				height: 100%;
+				border-radius: 6rpx;
+			}
+		}
+	}
+</style>

+ 187 - 0
components/d_goodList/index.vue

@@ -0,0 +1,187 @@
+<template>
+	<!-- 分类二商品列表 -->
+	<view class="goodsList">
+		<view class="item" v-for="(item,index) in tempArr" :key='index' @click="goDetail(item)">
+			<view class="pictrue">
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '1'">秒杀</span>
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '2'">砍价</span>
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '3'">拼团</span>
+				<image :src="item.recommend_image" mode="aspectFill" v-if="item.recommend_image"></image>
+				<image :src="item.image" mode="aspectFill" v-else></image>
+			</view>
+			<view class="text line2">{{item.store_name}}</view>
+			<!-- #ifdef H5 || APP-PLUS -->
+			<slot name="center" :item="item"></slot>
+			<!-- #endif -->
+			<!-- #ifdef MP -->
+			<slot name="center{{index}}"></slot>
+			<!-- #endif -->
+			<view class="bottom acea-row row-between-wrapper">
+				<view class="sales acea-row row-middle">
+					<view class="money font-color"><text>¥</text>{{item.price}}</view>
+					<view>已售 {{item.sales}}</view>
+				</view>
+				<view v-if="item.stock>0">
+				    <view class="bnt acea-row row-center-wrapper" v-if="(item.activity && (item.activity.type === '1' || item.activity.type === '2' || item.activity.type === '3')) || item.product_type!=0 || item.custom_form.length">立即购买</view>
+					<view v-else>
+						<!-- 多规格 -->
+						<view class="bnt acea-row row-center-wrapper" @click.stop="goCartDuo(item)" v-if="item.spec_type">
+							加入购物车
+							<text class="num" v-if="isLogin && item.cart_num">{{item.cart_num}}</text>
+						</view>
+						<!-- 单规格 -->
+						<view v-if="!item.spec_type && !item.cart_num">
+							<view v-if="item.cart_button">
+								<view class="bnt acea-row row-center-wrapper end" v-if="item.is_presale_product && (item.presale_pay_status == 1 || item.presale_pay_status == 3)">>
+									{{item.presale_pay_status === 1?'未开始':'已结束'}}
+								</view>
+								<view v-else class="bnt acea-row row-center-wrapper" @click.stop="goCartDan(item,index)">加入购物车</view>
+							</view>
+							<view v-else class="bnt acea-row row-center-wrapper">立即购买</view>
+						</view>
+						<view class="cart acea-row row-middle" v-if="!item.spec_type && item.cart_num">
+							<view class="pictrue iconfont icon-jianhao" @click.stop="CartNumDes(index,item)"></view>
+							<view class="num">{{item.cart_num}}</view>
+							<view class="pictrue iconfont icon-jiahao" @click.stop="CartNumAdd(index,item)"></view>
+						</view>
+					</view>
+				</view>
+				<view class="bnt end acea-row row-center-wrapper" v-else>已售罄</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'd_goodList',
+		props: {
+			dataConfig: {
+				type: Object,
+				default: () => {}
+			},
+			tempArr:{
+				type: Array,
+				default: () => []
+			},
+			isLogin:{
+				type: Boolean,
+				default:false
+			}
+		},
+		data() {
+			return {
+			};
+		},
+		created() {},
+		mounted() {},
+		methods: {
+			goDetail(item){
+				this.$emit('detail',item);
+			},
+			goCartDuo(item){
+				this.$emit('gocartduo',item);
+			},
+			goCartDan(item,index){
+				this.$emit('gocartdan',item,index);
+			},
+			CartNumDes(index,item){
+				this.$emit('ChangeCartNumDan', false,index,item);
+			},
+			CartNumAdd(index,item){
+				if(item.is_limit && item.cart_num>=item.limit_num){
+					this.$util.Tips({
+					  title: "购买最多不能超过"+item.limit_num
+					});
+				}else{
+					this.$emit('ChangeCartNumDan', true,index,item);
+				}
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	.goodsList{
+		padding: 0 30rpx;
+		.item{
+			width: 100%;
+			box-sizing: border-box;
+			margin-bottom: 63rpx;
+			.pictrue{
+				width: 100%;
+				height: 290rpx;
+				border-radius: 16rpx;
+				position: relative;
+				image{
+					width: 100%;
+					height: 100%;
+					border-radius: 16rpx;
+				}
+			}
+			.text{
+				font-size:30rpx;
+				font-family:PingFang SC;
+				font-weight:bold;
+				color: #282828;
+				margin: 20rpx 0;
+			}
+			.bottom{
+				.sales{
+					font-size: 22rpx;
+					color: #8E8E8E;
+					.money{
+						font-size: 42rpx;
+						font-weight: bold;
+						margin-right: 16rpx;
+						text{
+							font-size: 28rpx;
+						}
+					}
+				}
+				.cart{
+					height: 56rpx;
+					.pictrue{
+						color: var(--view-theme);
+						font-size:46rpx;
+						width: 50rpx;
+						height: 50rpx;
+						text-align: center;
+						line-height: 50rpx;
+					}
+					.num{
+						font-size: 30rpx;
+						color: #282828;
+						font-weight: bold;
+						width: 80rpx;
+						text-align: center;
+					}
+				}
+				.bnt{
+					padding: 0 30rpx;
+					height: 55rpx;
+					background:var(--view-theme);
+					border-radius:42rpx;
+					font-size: 26rpx;
+					color: #fff;
+					position: relative;
+					&.end{
+						background:rgba(203,203,203,1);
+					}
+					.num{
+						min-width: 14rpx;
+						background-color: #fff;
+						color: var(--view-theme);
+						border-radius: 15px;
+						position: absolute;
+						right: -14rpx;
+						top: -15rpx;
+						font-size: 20rpx;
+						padding: 0 10rpx;
+						border: 1px solid var(--view-theme);
+					}
+				}
+			}
+		}
+	}
+</style>

+ 49 - 0
components/emptyPage.vue

@@ -0,0 +1,49 @@
+<template>
+	<!-- 无数据时显示 -->
+	<view class="empty-box">
+		<image :src="imgHost + '/statics/images/empty-box.png'"></image>
+		<view class="txt">{{title}}</view>
+		<slot name="bottom"></slot>
+	</view>
+</template>
+
+<script>
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default{
+		props: {
+			title: {
+				type: String,
+				default: '暂无记录',
+			},
+		},
+		data(){
+			return{
+				imgHost:HTTP_REQUEST_URL
+			}
+		}
+	}
+	
+</script>
+
+<style lang="scss">
+	.empty-box{
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		width: 690rpx;
+		height: 760rpx;
+		margin: 30rpx auto;
+		background: #FFFFFF;
+		border-radius: 14rpx;
+		background: #fff;
+		image{
+			width: 414rpx;
+			height: 240rpx;
+		}
+		.txt{
+			font-size: 26rpx;
+			color: #999;
+		}
+	}
+</style>

+ 185 - 0
components/ewcomerPop/index.vue

@@ -0,0 +1,185 @@
+<template>
+	<view :style="colorStyle">
+		<image :src="imgHost+'/statics/images/header.png'" mode="" class="img"></image>
+		<view class="tipaddress">
+			<view class="title">{{fromActive == 1?'激活送好礼':'新人大礼包'}}</view>
+			<view class="list">
+				<view class="list-img acea-row row-between-wrapper" :style="{backgroundImage:'url('+imgHost+'/statics/images/box1.png'+')'}" v-if="comerGift.product_count>0 && fromActive == 0">
+				  <view class="left acea-row row-center-wrapper">
+						<image :src="imgHost+'/statics/images/vip.png'" mode=""></image>
+					</view>
+					<view class="right">新人专享价商品</view>
+				</view>
+				<view class="list-img acea-row row-between-wrapper" :style="{backgroundImage:'url('+imgHost+'/statics/images/box1.png'+')'}" v-if="comerGift.first_order_discount>0 && fromActive == 0">
+          <view class="left">
+            {{parseFloat(comerGift.first_order_discount)/10 || 10}}<text class="text">折</text>
+          </view>
+          <view class="right">新人首单优惠</view>
+        </view>
+				<view class="list-img acea-row row-between-wrapper" :style="{backgroundImage:'url('+imgHost+'/statics/images/box1.png'+')'}" v-if="comerGift.register_give_integral>0">
+				  <view class="left">{{comerGift.register_give_integral}}</view>
+				  <view class="right">新人赠送积分</view>
+				</view>
+				<view class="list-img acea-row row-between-wrapper" :style="{backgroundImage:'url('+imgHost+'/statics/images/box1.png'+')'}" v-if="comerGift.register_give_money>0">
+				  <view class="left">{{comerGift.register_give_money}}<text class="text">元</text></view>
+				  <view class="right">新人赠送余额</view>
+				</view>
+				<view class="list-img acea-row row-between-wrapper" :style="{backgroundImage:'url('+imgHost+'/statics/images/box1.png'+')'}" v-if="comerGift.coupon_count>0" v-for="(item,index) in comerGift.register_give_coupon" :key="index">
+				   <view class="left">
+						 <text v-if="item.coupon_type==1">{{item.coupon_price.toString().split(".")[0]}}</text>
+						 <text class="nums"
+						 	v-if="item.coupon_price.toString().split('.').length>1 && item.coupon_type==1">.{{item.coupon_price.toString().split(".")[1]}}</text>
+						 <text v-if="item.coupon_type==2">{{parseFloat(item.coupon_price)/10}}</text>
+						 <text class="text">{{item.coupon_type==1?'元':'折'}}</text>
+				   </view>
+				   <view class="right">优惠券</view>
+				</view>
+			</view>
+			<view class="btn" @click="accept">
+				立即收下
+			</view>
+		</view>
+		<view class="mark"></view>
+	</view>
+</template>
+
+<script>
+	import {
+		HTTP_REQUEST_URL
+	} from '@/config/app';
+	import colors from '@/mixins/color';
+	export default {
+		mixins: [colors],
+		props:{
+			comerGift: {
+				type: Object,
+				default: function() {
+					return {}
+				},
+			},
+			fromActive: {
+				type: Number,
+				default: 0
+			}
+		},
+		data() {
+			return {
+				imgHost: HTTP_REQUEST_URL,
+			};
+		},
+		methods:{
+			accept(){
+				this.$emit('comerPop')
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.img {
+		position: fixed;
+		top: 162rpx;
+		left: 9%;
+		width: 590rpx;
+		height: 294rpx;
+		z-index: 100;
+
+	}
+
+	.tipaddress {
+		position: fixed;
+		left: 13%;
+		top: 25%;
+		width: 538rpx;
+		height: 650rpx;
+		background-color: var(--view-theme);
+		border-radius: 10rpx;
+		z-index: 100;
+		text-align: center;
+		
+		.title{
+			color: #fff;
+			font-size: 50rpx;
+			margin-top: 32rpx;
+			margin-bottom: 18rpx;
+		}
+
+		.goods-img {
+			width: 258rpx;
+			height: 52rpx;
+			margin-top: 50rpx;
+
+		}
+
+		.list {
+			height: 370rpx;
+			overflow-x: hidden;
+			overflow-y: auto;
+
+			.list-img {
+				margin-top: 14rpx;
+				margin-left: 32rpx;
+				width: 474rpx;
+				height: 124rpx;
+				background-repeat: no-repeat;
+				background-size: 100% 100%;
+
+				.left {
+					width: 144rpx;
+					font-size: 48rpx;
+					font-weight: 500;
+					color: var(--view-theme);
+					
+					image{
+						width: 72rpx;
+						height: 72rpx;
+						display: block;
+					}
+
+					.text {
+						font-size: 24rpx;
+					}
+					
+					.nums{
+						font-size: 30rpx;
+					}
+				}
+
+				.right {
+					width: 328rpx;
+					font-size: 28rpx;
+					font-weight: 500;
+					color: var(--view-theme);
+					text-align: left;
+					padding-left: 50rpx;
+				}
+			}
+		}
+
+
+		.btn {
+			width: 474rpx;
+			height: 78rpx;
+			background: linear-gradient(90deg, #FFCA52 0%, #FE960F 100%);
+			border-radius: 39rpx;
+			font-size: 30rpx;
+			font-weight: 500;
+			color: #FFFFFF;
+			line-height: 78rpx;
+			text-align: center;
+			margin-left: 32rpx;
+			margin-top: 48rpx;
+		}
+
+	}
+
+	.mark {
+		position: fixed;
+		top: 0;
+		left: 0;
+		bottom: 0;
+		right: 0;
+		background: rgba(0, 0, 0, 0.5);
+		z-index: 99;
+	}
+</style>

+ 310 - 0
components/filterPopup/index.vue

@@ -0,0 +1,310 @@
+<template>
+  <view :style="colorStyle">
+    <tui-drawer :mode="mode" :visible="visible" @close="closeDrawer">
+			<!-- #ifdef MP  -->
+			<view :style="'height:'+(statusBarHeight+43)+'px'"></view>
+      <scroll-view scroll-y="true" class="scroll-Y" :style="'height: calc(100vh - '+(statusBarHeight+214)+'rpx)'">
+			<!-- #endif -->
+			<!-- #ifndef MP  -->
+			<scroll-view scroll-y="true" class="scroll-Y" :style="'height: calc(100vh - 128rpx)'">
+			<!-- #endif -->	
+      <view class="d-container">
+        <!-- 品牌 -->
+        <view class="box">
+          <view class="title">
+            <view class="font">品牌</view>
+            <view class="font-right" @click="openFn(1)" v-if="open==1">展开 <text
+                class="iconfont icon-xialazhankai"></text>
+            </view>
+            <view class="font-right" v-if="open==2" @click="openFn(2)">收起 <text class="iconfont icon-xiangshang"></text>
+            </view>
+          </view>
+          <!-- 品牌显示十个 -->
+          <view class="box-list">
+            <view class="list acea-row row-center-wrapper" :class="{'bgcolor':spanIndex.indexOf(index)>-1}" v-for="(item,index) in list"
+              :key="index" @click="changeSpan(index,item)">
+              {{item.brand_name}}
+            </view>
+          </view>
+
+        </view>
+
+        <!-- 分类 -->
+        <view class="box">
+          <view class="font">分类</view>
+          <template v-for="(item,indexw) in storeArr">
+            <tui-collapse :index="indexw" :current="item.current" :disabled="item.disabled" @click="change">
+              <template v-slot:title>
+                <view class="title" :key="item.id">
+                  <view class="font-live">
+
+                    <tui-list-cell :hover="!item.disabled">{{item.cate_name}}</tui-list-cell>
+
+                  </view>
+
+                </view>
+              </template>
+              <template v-slot:content>
+                <view class="box-list">
+                  <view class="list acea-row row-center-wrapper" v-for="(data,indexn) in item.children" :key="indexn"
+                    @click="categoryFn(data,item)">
+                    <view class="acea-row row-center-wrapper" :class="{bgcolor:sortIndex===data.id}">
+                      {{data.cate_name}}
+                    </view>
+
+                  </view>
+                </view>
+              </template>
+            </tui-collapse>
+          </template>
+        </view>
+      </view>
+      </scroll-view>
+      <!-- 底部按钮 -->
+      <view class="footer">
+        <view class="btn" @click="submit(2)">
+          重置
+        </view>
+        <view class="btn btnColor" @click="submit(1)">
+          确认
+        </view>
+      </view>
+    </tui-drawer>
+    <!-- 确认 -->
+  </view>
+</template>
+
+<script>
+  import colors from "@/mixins/color";
+  import tuiDrawer from "@/components/thorui/tui-drawer"
+  import tuiCollapse from "@/components/thorui/tui-collapse"
+  import tuiListCell from "@/components/thorui/tui-list-cell"
+	let statusBarHeight = uni.getSystemInfoSync().statusBarHeight;
+
+  export default {
+    components: {
+      tuiDrawer,
+      tuiCollapse,
+      tuiListCell
+    },
+    props: {
+      storeCategory: {
+        type: Array, // 分类数据
+        default: []
+      },
+      storeBrand: {
+        type: Array, //品牌数据
+     
+      }
+    },
+    mixins: [colors],
+    data() {
+      return {
+				statusBarHeight:statusBarHeight,
+        visible: false,
+        mode: "right",
+        sortIndex: 0,
+        spanIndex: [],
+        newList: [],
+        open: 1,
+        forArr: [],
+        serchData: {
+          sort: '', //new 最新, sales价值
+          sort_type: '', // DESC 倒序 ASC 正序
+          send: '',
+          cate_id: [],
+        }
+      }
+    },
+    computed: {
+      storeArr() {
+        return this.storeCategory
+      },
+      list() {
+        if(this.open===1) {
+           return this.storeBrand.slice(0, 10)
+        } else if( this.open===2) {
+          return this.storeBrand
+        }
+      }
+    },
+    onLoad() {
+    },
+    mounted() {
+          console.log(2,'父组件传过来的值')
+          // this.newListArr()
+      // this.openFn()
+    },
+
+    methods: {
+      // newListArr() {
+      //      // this.forArr = this.list
+      //   if (this.open == 1) {
+      //  console.log('进入')
+      //     this.$set(this.forArr,this.forArr.length,...this.list.slice(0, 10))
+      //      console.log(this.forArr)
+        
+      //   } else {
+      //     console.log('全部')
+      //     this.forArr = this.list
+      //   }
+      // },
+      closeDrawer() {
+        this.visible = false
+      },
+      // 点击展开
+      openFn(num) {
+        switch (num) {
+          case 1:
+            this.open = 2
+       
+            break;
+          case 2:
+            this.open = 1
+
+            break;
+        }
+             // this.newListArr()
+      },
+      // 单选
+      categoryFn(row,item) {
+        console.log(row,item)
+        this.sortIndex = row.id
+        let data ={
+          cid:item.id,
+          sid:row.id
+        }
+        console.log(data)
+        this.$emit('categoryChange',data)
+      },
+      change(e) {
+        let index = e.index;
+        let item = this.storeArr[index];
+        item.current = item.current == index ? -1 : index
+
+      },
+      // 多选
+      changeSpan(index, row) {
+        let arrIndex = this.spanIndex.indexOf(index);
+        if (arrIndex > -1) {
+          this.spanIndex.splice(arrIndex, 1);
+					this.newList.splice(arrIndex, 1);
+        } else {
+          this.spanIndex.push(index);
+					this.newList.push(row.id);
+        }
+        let result = this.newList.join(",")
+        this.$emit('brandChange', result)
+      },
+      // 确认提交
+      submit(val) {
+        if(val==2) {
+           this.sortIndex =0
+           this.spanIndex=[]
+        }
+         this.$emit('submitFn',val)
+      }
+    }
+  }
+</script>
+
+<style lang="scss">
+  .bgcolor {
+    background: var(--view-minorColorT) !important;
+    border: 1px solid var(--view-theme);
+    border-radius: 34rpx;
+    color: var(--view-theme) !important;
+		height: 100%;
+		width: 100%;
+  }
+
+  .font {
+    margin-top: 30rpx;
+    font-size: 28rpx;
+    font-weight: 500;
+    color: #333333;
+  }
+
+  .font-live {
+    font-size: 24rpx;
+    font-weight: 400;
+    color: #666666;
+  }
+
+  .font-right {
+    margin-top: 30rpx;
+    font-size: 20rpx;
+    font-weight: 400;
+    color: #666666;
+  }
+
+  .icon-xialazhankai {
+    font-size: 20rpx;
+    color: #666666;
+		margin-left: 6rpx;
+  }
+
+  .icon-xiangshang {
+    font-size: 20rpx;
+    color: #666666;
+		margin-left: 6rpx;
+  }
+
+  .d-container {
+    width:600rpx;
+    padding: 0 34rpx 20rpx 34rpx;
+
+    .box {
+      .title {
+				/* #ifndef MP */
+				margin-top: 30rpx;
+				/* #endif */
+        display: flex;
+        justify-content: space-between;
+      }
+
+      .box-list {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+        margin-bottom: 20rpx;
+
+        .list {
+          width: 240rpx;
+          height: 68rpx;
+          background: #F5F5F5;
+          border-radius: 34rpx;
+          font-size: 24rpx;
+          font-weight: 400;
+          color: #666666;
+          margin-top: 30rpx;
+        }
+      }
+    }
+  }
+
+  .footer {
+   
+    // position: fixed;
+    // bottom: 10rpx;
+    margin: 20rpx 30rpx 38rpx 30rpx;
+    display: flex;
+    justify-content: space-between;
+
+    .btn {
+      width: 240rpx;
+      height: 68rpx;
+      background: #F5F5F5;
+      border-radius: 34rpx;
+      font-size: 24rpx;
+      font-weight: 400;
+      text-align: center;
+      line-height: 68rpx;
+    }
+
+    .btnColor {
+      background: var(--view-theme);
+      color: #fff;
+    }
+  }
+</style>

+ 221 - 0
components/goodClass/index.vue

@@ -0,0 +1,221 @@
+<template>
+	<!-- 分类三商品列表 -->
+	<view class="goodsList">
+		<view class="item acea-row row-between-wrapper" v-for="(item,index) in tempArr" :key='index' @click="goDetail(item)">
+			<view class="pictrue">
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '1'">秒杀</span>
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '2'">砍价</span>
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '3'">拼团</span>
+				<image :src="item.image" mode="aspectFill"></image>
+			</view>
+			<view class="pictxt">
+				<view class="text line2">{{item.store_name}}</view>
+				<!-- #ifdef H5 || APP-PLUS -->
+				<slot name="center" :item="item"></slot>
+				<!-- #endif -->
+				<!-- #ifdef MP -->
+				<slot name="center{{index}}"></slot>
+				<!-- #endif -->
+				<view class="bottom acea-row row-between-wrapper">
+					<view class="money font-color">
+						<text class="sign">¥</text>{{item.price}}
+						<!-- <span class="vip" v-if="item.vip_price">
+							<image src="../../static/images/vip01.png"></image>
+							¥{{item.vip_price}}
+						</span>
+						<text class="y_money" v-else>¥{{item.ot_price}}</text> -->
+					</view>
+					<view v-if="item.stock>0">
+					    <view class="iconfont icon-gouwuche6 acea-row row-center-wrapper" v-if="(item.activity && (item.activity.type === '1' || item.activity.type === '2' || item.activity.type === '3')) || item.product_type!=0 || item.custom_form.length"></view>
+						<view v-else>
+							<!-- 多规格 -->
+							<view class="bnt acea-row row-center-wrapper" @click.stop="goCartDuo(item)" v-if="item.spec_type">
+								选规格
+								<text class="num" v-if="isLogin && item.cart_num">{{item.cart_num}}</text>
+							</view>
+							<!-- 单规格 -->
+							<view v-if="!item.spec_type && !item.cart_num">
+								<view v-if="item.cart_button">
+									<view class="bnt acea-row row-center-wrapper end" v-if="item.is_presale_product && (item.presale_pay_status == 1 || item.presale_pay_status == 3)">
+										{{item.presale_pay_status === 1?'未开始':'已结束'}}
+									</view>
+									<view v-else class="iconfont icon-gouwuche6 acea-row row-center-wrapper" @click.stop="goCartDan(item,index)"></view>
+								</view>
+								<view v-else class="bnt acea-row row-center-wrapper">立即购买</view>
+							</view>
+							<view class="cart acea-row row-middle" v-if="!item.spec_type && item.cart_num">
+								<view class="pictrue iconfont icon-jianhao acea-row row-center-wrapper" @click.stop="CartNumDes(index,item)"></view>
+								<view class="num">{{item.cart_num}}</view>
+								<view class="pictrue iconfont icon-jiahao acea-row row-center-wrapper" @click.stop="CartNumAdd(index,item)"></view>
+							</view>
+						</view>
+					</view>
+					<view class="bnt acea-row row-center-wrapper end" v-else>已售罄</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'd_goodList',
+		props: {
+			dataConfig: {
+				type: Object,
+				default: () => {}
+			},
+			tempArr:{
+				type: Array,
+				default: () => []
+			},
+			isLogin:{
+				type: Boolean,
+				default:false
+			}
+		},
+		data() {
+			return {
+			};
+		},
+		created() {},
+		mounted() {},
+		methods: {
+			goDetail(item){
+				this.$emit('detail',item);
+			},
+			goCartDuo(item){
+				this.$emit('gocartduo',item);
+			},
+			goCartDan(item,index){
+				this.$emit('gocartdan',item,index);
+			},
+			CartNumDes(index,item){
+				this.$emit('ChangeCartNumDan', false,index,item);
+			},
+			CartNumAdd(index,item){
+				if(item.is_limit && item.cart_num>=item.limit_num){
+					this.$util.Tips({
+					  title: "购买最多不能超过"+item.limit_num
+					});
+				}else{
+					this.$emit('ChangeCartNumDan', true,index,item);
+				}
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	.goodsList{
+		padding: 0 30rpx;
+		.item{
+			width: 100%;
+			box-sizing: border-box;
+			margin-bottom: 63rpx;
+			.pictrue{
+				width: 140rpx;
+				height: 140rpx;
+				border-radius: 10rpx;
+				position: relative;
+				border-radius: 22rpx;
+				image{
+					width: 100%;
+					height: 100%;
+					border-radius: 22rpx;
+				}
+			}
+			.pictxt{
+				width: 372rpx;
+				.text{
+					font-size:26rpx;
+					font-family:PingFang SC;
+					font-weight:500;
+					color: #333333;
+				}
+				.bottom{
+					margin-top: 22rpx;
+					.money{
+						font-size: 34rpx;
+						font-weight: 800;
+						width: 212rpx;
+						.sign{
+							font-size: 24rpx;
+						}
+						.y_money{
+							font-size: 20rpx;
+							color: #999999;
+							margin-left: 14rpx;
+							font-weight: normal;
+							text-decoration: line-through;
+						}
+						.vip{
+							font-size: 22rpx;
+							color: #333333;
+							font-weight: normal;
+							margin-left: 14rpx;
+							image{
+								width: 38rpx;
+								height: 18rpx;
+								margin-right: 6rpx;
+							}
+						}
+					}
+					.cart{
+						height: 46rpx;
+						.pictrue{
+							color: var(--view-theme);
+							font-size:46rpx;
+							width: 46rpx;
+							height: 46rpx;
+							text-align: center;
+							line-height: 46rpx;
+							&.icon-jiahao{
+								 color: var(--view-theme);
+							}
+						}
+						.num{
+							font-size: 30rpx;
+							color: #333333;
+							font-weight: bold;
+							width: 60rpx;
+							text-align: center;
+						}
+					}
+					.icon-gouwuche6{
+						width: 46rpx;
+						height: 46rpx;
+						background-color: var(--view-theme);
+						border-radius: 50%;
+						color: #fff;
+						font-size: 30rpx;
+					}
+					.bnt{
+						padding: 0 20rpx;
+						height: 45rpx;
+						background:var(--view-theme);
+						border-radius:23rpx;
+						font-size: 22rpx;
+						color: #fff;
+						position: relative;
+						&.end{
+							background:#cccccc;
+						}
+						.num{
+							min-width: 14rpx;
+							background-color: #fff;
+							color: var(--view-theme);
+							border-radius: 15px;
+							position: absolute;
+							right: -13rpx;
+							top: -11rpx;
+							font-size: 16rpx;
+							padding: 0 10rpx;
+							border: 1px solid var(--view-theme);
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 158 - 0
components/goodList/index.vue

@@ -0,0 +1,158 @@
+<template>
+	<!-- 商品列表 -->
+	<view class='goodList'>
+		<block v-for="(item,index) in bastList" :key="index">
+			<view @click="goDetail(item)" class='item acea-row row-between-wrapper' hover-class="none">
+				<view class='pictrue'>
+					<image :src='item.image' mode="aspectFill"></image>
+					<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '1'">秒杀</span>
+					<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '2'">砍价</span>
+					<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '3'">拼团</span>
+				</view>
+				<view class='underline'>
+					<view class='text'>
+						<view class='line1'>{{item.store_name}}</view>
+						<!-- #ifdef H5 || APP-PLUS -->
+						<slot name="center" :item="item"></slot>
+						<!-- #endif -->
+						<!-- #ifdef MP -->
+						<slot name="center{{index}}"></slot>
+						<!-- #endif -->
+						<view class='money font-color'>¥<text class='num'>{{item.price}}</text></view>
+						<view class='vip-money acea-row row-middle' v-if="item.is_vip && item.vip_price && item.vip_price > 0">¥{{item.vip_price || 0}}
+							<image src='../../static/images/vip.png'></image><text class='num'>已售{{item.sales}}{{item.unit_name}}</text>
+						</view>
+						<view class='vip-money acea-row row-middle' v-else><text class='num'>已售{{item.sales}}{{item.unit_name}}</text></view>
+					</view>
+				</view>
+				<!-- <view class='iconfont icon-gouwuche cart-color acea-row row-center-wrapper'></view> -->
+			</view>
+		</block>
+	</view>
+</template>
+
+<script>
+	import {mapGetters} from "vuex";
+	import { goShopDetail,goPage } from '@/libs/order.js'
+	export default {
+		computed: mapGetters(['uid']),
+		props: {
+			status: {
+				type: Number,
+				default: 0,
+			},
+			bastList: {
+				type: Array,
+				default: function() {
+					return [];
+				}
+			}
+		},
+		data() {
+			return {
+
+			};
+		},
+		methods: {
+			goDetail(item){
+				goPage().then(res=>{
+					goShopDetail(item,this.uid).then(res=>{
+						uni.navigateTo({
+							url:`/pages/goods_details/index?id=${item.id}`
+						})
+					})
+				})
+				
+			}
+			
+		}
+	}
+</script>
+
+<style scoped lang='scss'>
+	.goodList .item {
+		position: relative;
+		padding-left: 30rpx;
+	}
+
+	.goodList .item .pictrue {
+		width: 180rpx;
+		height: 180rpx;
+		position: relative;
+	}
+
+	.goodList .item .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 20rpx;
+	}
+
+	.goodList .item .pictrue .numPic {
+		position: absolute;
+		left: 7rpx;
+		top: 7rpx;
+		width: 50rpx;
+		height: 50rpx;
+		border-radius: 50%;
+	}
+
+	.goodList .item .underline {
+		padding: 30rpx 30rpx 30rpx 0;
+		border-bottom: 1px solid #f5f5f5;
+	}
+
+	.goodList .item:nth-last-child(1) .underline {
+		border-bottom: 0;
+	}
+
+	.goodList .item .text {
+		font-size: 30rpx;
+		color: #222;
+		width: 489rpx;
+	}
+
+	.goodList .item .text .money {
+		font-size: 26rpx;
+		font-weight: bold;
+		margin-top: 50rpx;
+	}
+
+	.goodList .item .text .money .num {
+		font-size: 34rpx;
+	}
+
+	.goodList .item .text .vip-money {
+		font-size: 24rpx;
+		color: #282828;
+		font-weight: bold;
+		margin-top: 15rpx;
+	}
+
+	.goodList .item .text .vip-money image {
+		width: 56rpx;
+		height: 20rpx;
+		margin-right: 8rpx;
+		margin-left: 8rpx;
+	}
+
+	.goodList .item .text .vip-money .num {
+		font-size: 22rpx;
+		color: #aaa;
+		font-weight: normal;
+		margin-top: -2rpx;
+		
+		~.num {
+			margin-left: 22rpx;
+		}
+	}
+
+	.goodList .item .iconfont {
+		position: absolute;
+		right: 30rpx;
+		width: 50rpx;
+		height: 50rpx;
+		border-radius: 50%;
+		font-size: 30rpx;
+		bottom: 38rpx;
+	}
+</style>

+ 157 - 0
components/guide/index.vue

@@ -0,0 +1,157 @@
+<template>
+	<!-- 开屏广告 -->
+	<view class="content">
+		<swiper class="swiper" :autoplay="autoplay" :duration="duration"
+			v-if="advData.type == 'pic' && advData.value.length">
+			<swiper-item v-for="(item,index) in advData.value" :key="index" @click="jump(item.link)">
+				<view class="swiper-item">
+					<view class="swiper-item-img">
+						<image :src="item.img" mode="aspectFill"></image>
+					</view>
+				</view>
+			</swiper-item>
+		</swiper>
+		<view class="video-box" v-else-if="advData.type == 'video' && advData.video_link">
+			<video class="vid" :src="advData.video_link" :autoplay="true" :loop="true" :muted="true"
+				:controls="false"></video>
+		</view>
+		<view class="jump-over"  :style="{ top: navH + 'rpx' }" @tap="launchFlag()">跳过<text v-if="closeType == 1">{{time}}</text><slot name="bottom"></slot></view>
+	</view>
+</template>
+
+<script>
+	let app = getApp();
+	export default {
+		data() {
+			return {
+				autoplay: false,
+				duration: 500,
+				jumpover: '跳过',
+				experience: '立即体验',
+				time: this.advData.time,
+				timecount: undefined,
+				navH: 0
+			}
+		},
+		props: {
+			advData: {
+				type: Object,
+				default: () => {}
+			},
+			// 1 倒计时 2 手动关闭(预留)
+			closeType: {
+				type: Number,
+				default: 1
+			}
+		},
+		mounted() {
+			this.timer()
+			// #ifdef MP
+			this.navH = app.globalData.navHeight;
+			// #endif
+			// #ifndef MP
+			this.navH = 80;
+			// #endif
+		},
+		methods: {
+			timer() {
+				var t = this.advData.time || 5
+				this.timecount = setInterval(() => {
+					t--
+					this.time = t
+					if (t <= 0) {
+						clearInterval(this.timecount)
+						this.launchFlag()
+					}
+				}, 1000)
+			},
+			launchFlag() {
+				clearInterval(this.timecount)
+				uni.switchTab({
+					url: '/pages/index/index'
+				});
+			},
+			jump(url) {
+				if(url){
+					clearInterval(this.timecount)
+					if (url.indexOf("http") != -1) {
+						uni.navigateTo({
+							url: `/pages/annex/web_view/index?url=${url}`
+						});
+					} else {
+						if (['/pages/goods_cate/goods_cate', '/pages/order_addcart/order_addcart', '/pages/user/index', '/pages/index/index', '/pages/store_cate/store_cate']
+							.indexOf(url) == -1) {
+							uni.navigateTo({
+								url: url
+							})
+						} else {
+							uni.reLaunch({
+								url: url
+							})
+						}
+					}
+				}
+			},
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	page,
+	.content {
+		width: 100%;
+		height: 100%;
+		background-size: 100% auto;
+		padding: 0;
+	}
+
+	.swiper {
+		width: 100%;
+		height: 100vh;
+		background: #FFFFFF;
+	}
+
+	.swiper-item {
+		width: 100%;
+		height: 100%;
+		text-align: center;
+		position: relative;
+		display: flex;
+		/* justify-content: center; */
+		align-items: flex-end;
+		flex-direction: column-reverse
+	}
+
+	.swiper-item-img {
+		width: 100vw;
+		height: 100vh;
+		margin: 0 auto;
+	}
+
+	.swiper-item-img image {
+		width: 100%;
+		height: 100%;
+	}
+
+	.jump-over {
+		position: absolute;
+		height: 45rpx;
+		line-height: 45rpx;
+		padding: 0 15rpx;
+		border-radius: 30rpx;
+		font-size: 24rpx;
+		color: #b09e9a;
+		border: 1px solid #b09e9a;
+		z-index: 999;
+		right: 30rpx;
+	}
+
+	.video-box {
+		width: 100vw;
+		height: 100vh;
+
+		.vid {
+			width: 100%;
+			height: 100%;
+		}
+	}
+</style>

+ 131 - 0
components/home/index.vue

@@ -0,0 +1,131 @@
+<template>
+	<!-- 悬浮导航按钮 -->
+	<view :style="colorStyle">
+		<view style="touch-action: none;">
+			<view class="home" style="position:fixed;" :style="{ top: top + 'px'}" id="right-nav"
+				@touchmove.stop.prevent="setTouchMove">
+				<view class="homeCon bg-color" :class="homeActive === true ? 'on' : ''" v-if="homeActive">
+					<navigator hover-class='none' open-type="switchTab" url='/pages/index/index'
+						class='iconfont icon-shouye-xianxing'>
+					</navigator>
+					<navigator hover-class='none' open-type="switchTab" url='/pages/order_addcart/order_addcart'
+						class='iconfont icon-caigou-xianxing'></navigator>
+					<navigator hover-class='none' open-type="switchTab" url='/pages/user/index'
+						class='iconfont icon-yonghu1'></navigator>
+					<slot name="bottom"></slot>
+				</view>
+				<view @click="open" class="pictrueBox">
+					<view class="pictrue">
+						<image :src="
+		          homeActive === true
+		            ? imgHost + '/statics/images/close.gif'
+		            : imgHost + '/statics/images/open.gif'
+		        " class="image" />
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+	import {
+		mapGetters
+	} from "vuex";
+	import colors from '@/mixins/color.js';
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default {
+		name: "Home",
+		props: {},
+		mixins:[colors],
+		data: function() {
+			return {
+				top: "545",
+				imgHost:HTTP_REQUEST_URL
+			};
+		},
+		computed: mapGetters(["homeActive"]),
+		methods: {
+			setTouchMove(e) {
+				var that = this;
+				if (e.touches[0].clientY < 545 && e.touches[0].clientY > 66) {
+					that.top = e.touches[0].clientY
+					// that.setData({
+					// 	top: e.touches[0].clientY
+					// })
+				}
+			},
+			open: function() {
+				this.homeActive ?
+					this.$store.commit("CLOSE_HOME") :
+					this.$store.commit("OPEN_HOME");
+			}
+		},
+		created() {},
+		beforeDestroy() {
+			this.$store.commit("CLOSE_HOME")
+		}
+	};
+</script>
+
+<style scoped>
+	.pictrueBox {
+		width: 130rpx;
+		height: 120rpx;
+	}
+
+	/*返回主页按钮*/
+	.home {
+		position: fixed;
+		color: white;
+		text-align: center;
+		z-index: 9999;
+		right: 15rpx;
+		display: flex;
+	}
+
+	.home .homeCon {
+		border-radius: 50rpx;
+		opacity: 0;
+		height: 0;
+		width: 0;
+	}
+
+	.home .homeCon.on {
+		opacity: 1;
+		animation: bounceInRight 0.5s cubic-bezier(0.215, 0.610, 0.355, 1.000);
+		width: 300rpx;
+		height: 86rpx;
+		margin-bottom: 20rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background: var(--view-theme) !important;
+	}
+
+	.home .homeCon .iconfont {
+		font-size: 48rpx;
+		color: #fff;
+		display: inline-block;
+		margin: 0 auto;
+	}
+
+	.home .pictrue {
+		width: 86rpx;
+		height: 86rpx;
+		border-radius: 50%;
+		margin: 0 auto;
+		background-color: var(--view-theme);
+    border: 1px solid #fff;
+	}
+
+	.home .pictrue .image {
+		width: 100%;
+		height: 100%;
+		border-radius: 50%;
+		transform: rotate(90deg);
+		ms-transform: rotate(90deg);
+		moz-transform: rotate(90deg);
+		webkit-transform: rotate(90deg);
+		o-transform: rotate(90deg);
+	}
+</style>

+ 152 - 0
components/homeList/index.vue

@@ -0,0 +1,152 @@
+<template>
+	<!-- 顶部下拉导航 -->
+	<!-- #ifdef APP-PLUS -->
+	<view class="animated dialog_nav" :style="{ top: (navH+15) + 'rpx', marginTop: sysHeight}" :class="[goodList?'dialogIndex':'',currentPage?'':'']" v-show="currentPage">
+	<!-- #endif -->
+	<!-- #ifndef APP-PLUS -->
+	<view class="animated dialog_nav" :style="{ top: (navH+15) + 'rpx' }" :class="[goodList?'dialogIndex':'',goodsShow?'dialogGoods':'',currentPage?'':'']" v-show="currentPage">
+	<!-- #endif -->
+		<view class="dialog_nav_item" :class="item.after" v-for="(item,index) in selectNavList" :key="index" @click="linkPage(item.url)">
+			<text class="iconfont" :class="item.icon"></text>
+			<text class="pl-20">{{item.name}}</text>
+			<!-- #ifdef H5 || APP-PLUS -->
+			<slot name="bottom" :item="item"></slot>
+			<!-- #endif -->
+			<!-- #ifdef MP -->
+			<slot name="bottom{{index}}"></slot>
+			<!-- #endif -->
+		</view>
+	</view>
+</template>
+<script>
+	export default {
+		name: "homeIdex",
+		props: {
+			navH: {
+				type: String|Number,
+				default: ""
+			},
+			returnShow: {
+				type: Boolean,
+				default: true
+			},
+			goodList: {
+				type: Boolean,
+				default: false
+			},
+			currentPage: {
+				type: Boolean,
+				default: false
+			},
+			goodsShow: {
+				type: Boolean,
+				default: false
+			},
+			sysHeight: {
+				type: String|Number,
+				default: ""
+			}
+		},
+		data: function() {
+			return {
+				selectNavList:[
+					{name:'首页',icon:'icon-shouye8',url:'/pages/index/index',after:'dialog_after'},
+					{name:'搜索',icon:'icon-sousuo6',url:'/pages/goods/goods_search/index',after:'dialog_after'},
+					{name:'购物车',icon:'icon-gouwuche7',url:'/pages/order_addcart/order_addcart',after:'dialog_after'},
+					{name:'我的收藏',icon:'icon-shoucang3',url:'/pages/users/user_goods_collection/index',after:'dialog_after'},
+					{name:'个人中心',icon:'icon-gerenzhongxin1',url:'/pages/user/index'},
+				]
+			};
+		},
+		methods: {
+			linkPage(url){
+				if (['/pages/goods_cate/goods_cate', '/pages/order_addcart/order_addcart', '/pages/user/index', '/pages/index/index']
+					.indexOf(url) == -1) {
+					uni.navigateTo({
+						url: url
+					})
+				} else {
+					uni.switchTab({
+						url: url
+					})
+				}
+			}
+		},
+		created() {},
+		beforeDestroy() {
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	.dialog_nav{
+		position: absolute;
+		/* #ifdef MP */
+		left: 14rpx;
+		/* #endif */
+		/* #ifndef MP */
+		right: 14rpx;
+		/* #endif */
+		width: 240rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 0px 16rpx rgba(0, 0, 0, 0.08);
+		z-index: 310;
+		border-radius: 14rpx;
+		&::before{
+			content: '';
+			width: 0;
+			height: 0;
+			position: absolute;
+			/* #ifdef MP */
+			left: -26rpx;
+			/* #endif */
+			/* #ifndef MP */
+			left: 150rpx;
+			/* #endif */
+			right: 0;
+			margin:auto;
+			top:-9px;
+			border-bottom: 10px solid #F5F5F5;
+			border-left: 10px solid transparent;    /*transparent 表示透明*/
+			border-right: 10px solid transparent;
+		}
+		&.dialogIndex{
+			left: 14rpx;
+			&::before{
+				left: -160rpx!important;
+			}
+		}
+		&.dialogGoods{
+			&::before{
+				left: -170rpx;
+			}
+		}
+	}
+	.dialog_nav_item{
+		width: 100%;
+		height: 84rpx;
+		line-height: 84rpx;
+		padding: 0 20rpx 0;
+		box-sizing: border-box;
+		border-bottom: #eee;
+		font-size: 28rpx;
+		color: #333;
+		position: relative;
+		display: flex;
+		.iconfont{
+			font-size: 32rpx;
+			margin-right: 26rpx;
+		}
+	}
+	.dialog_after{
+		::after{
+			content: '';
+			position: absolute;
+			width:90px;
+			height: 1px;
+			background-color: #EEEEEE;
+			bottom: 0;
+			right: 0;
+		}
+	}
+</style>

+ 814 - 0
components/jyf-parser/jyf-parser.vue

@@ -0,0 +1,814 @@
+<!--
+  parser 主模块组件
+  github:https://github.com/jin-yufeng/Parser 
+  docs:https://jin-yufeng.github.io/Parser
+  插件市场:https://ext.dcloud.net.cn/plugin?id=805
+  author:JinYufeng
+  update:2020/04/14
+-->
+<template>
+	<view>
+		<slot v-if="!nodes.length" />
+		<!--#ifdef APP-PLUS-NVUE-->
+		<web-view id="top" ref="web" :src="src" :style="'margin-top:-2px;height:'+height+'px'" @onPostMessage="_message" />
+		<!--#endif-->
+		<!--#ifndef APP-PLUS-NVUE-->
+		<view id="top" :style="showAm+(selectable?';user-select:text;-webkit-user-select:text':'')" :animation="scaleAm" @tap="_tap"
+		 @touchstart="_touchstart" @touchmove="_touchmove">
+			<!--#ifdef H5-->
+			<div :id="'rtf'+uid"></div>
+			<!--#endif-->
+			<!--#ifndef H5-->
+			<trees :nodes="nodes" :lazy-load="lazyLoad" :loadVideo="loadVideo" />
+			<image v-for="(item, index) in imgs" v-bind:key="index" :id="index" :src="item" hidden @load="_load" />
+			<!--#endif-->
+		</view>
+		<!--#endif-->
+	</view>
+</template>
+
+<script>
+	// #ifndef H5 || APP-PLUS-NVUE
+	import trees from './libs/trees';
+	var cache = {},
+		// #ifdef MP-WEIXIN || MP-TOUTIAO
+		fs = uni.getFileSystemManager ? uni.getFileSystemManager() : null,
+		// #endif
+		Parser = require('./libs/MpHtmlParser.js');
+	var document; // document 补丁包 https://jin-yufeng.github.io/Parser/#/instructions?id=document
+	// 计算 cache 的 key
+	function hash(str) {
+		for (var i = str.length, val = 5381; i--;)
+			val += (val << 5) + str.charCodeAt(i);
+		return val;
+	}
+	// #endif
+	// #ifdef H5 || APP-PLUS-NVUE
+	var rpx = uni.getSystemInfoSync().screenWidth / 750,
+		cfg = require('./libs/config.js');
+	// #endif
+	// #ifdef APP-PLUS-NVUE
+	var dom = weex.requireModule('dom');
+	// #endif
+	export default {
+		name: 'parser',
+		data() {
+			return {
+				// #ifdef APP-PLUS
+				loadVideo: false,
+				// #endif
+				// #ifdef H5
+				uid: this._uid,
+				// #endif
+				// #ifdef APP-PLUS-NVUE
+				src: '',
+				height: 1,
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				scaleAm: '',
+				showAm: '',
+				imgs: [],
+				// #endif
+				nodes: []
+			}
+		},
+		// #ifndef H5 || APP-PLUS-NVUE
+		components: {
+			trees
+		},
+		// #endif
+		props: {
+			'html': null,
+			// #ifndef MP-ALIPAY
+			'autopause': {
+				type: Boolean,
+				default: true
+			},
+			// #endif
+			'autosetTitle': {
+				type: Boolean,
+				default: true
+			},
+			// #ifndef H5 || APP-PLUS-NVUE
+			'compress': Number,
+			'useCache': Boolean,
+			'xml': Boolean,
+			// #endif
+			'domain': String,
+			// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+			'gestureZoom': Boolean,
+			// #endif
+			// #ifdef MP-WEIXIN || MP-QQ || H5 || APP-PLUS
+			'lazyLoad': Boolean,
+			// #endif
+			'selectable': Boolean,
+			'tagStyle': Object,
+			'showWithAnimation': Boolean,
+			'useAnchor': Boolean
+		},
+		watch: {
+			html(html) {
+				this.setContent(html);
+			}
+		},
+		mounted() {
+			// 图片数组
+			this.imgList = [];
+			this.imgList.each = function(f) {
+				for (var i = 0, len = this.length; i < len; i++)
+					this.setItem(i, f(this[i], i, this));
+			}
+			this.imgList.setItem = function(i, src) {
+				if (i == void 0 || !src) return;
+				// #ifndef MP-ALIPAY || APP-PLUS
+				// 去重
+				if (src.indexOf('http') == 0 && this.includes(src)) {
+					var newSrc = '';
+					for (var j = 0, c; c = src[j]; j++) {
+						if (c == '/' && src[j - 1] != '/' && src[j + 1] != '/') break;
+						newSrc += Math.random() > 0.5 ? c.toUpperCase() : c;
+					}
+					newSrc += src.substr(j);
+					return this[i] = newSrc;
+				}
+				// #endif
+				this[i] = src;
+				// 暂存 data src
+				if (src.includes('data:image')) {
+					var filePath, info = src.match(/data:image\/(\S+?);(\S+?),(.+)/);
+					if (!info) return;
+					// #ifdef MP-WEIXIN || MP-TOUTIAO
+					filePath = `${wx.env.USER_DATA_PATH}/${Date.now()}.${info[1]}`;
+					fs && fs.writeFile({
+						filePath,
+						data: info[3],
+						encoding: info[2],
+						success: () => this[i] = filePath
+					})
+					// #endif
+					// #ifdef APP-PLUS
+					filePath = `_doc/parser_tmp/${Date.now()}.${info[1]}`;
+					var bitmap = new plus.nativeObj.Bitmap();
+					bitmap.loadBase64Data(src, () => {
+						bitmap.save(filePath, {}, () => {
+							bitmap.clear()
+							this[i] = filePath;
+						})
+					})
+					// #endif
+				}
+			}
+			if (this.html) this.setContent(this.html);
+		},
+		beforeDestroy() {
+			// #ifdef H5
+			if (this._observer) this._observer.disconnect();
+			// #endif
+			this.imgList.each(src => {
+				// #ifdef APP-PLUS
+				if (src && src.includes('_doc')) {
+					plus.io.resolveLocalFileSystemURL(src, entry => {
+						entry.remove();
+					});
+				}
+				// #endif
+				// #ifdef MP-WEIXIN || MP-TOUTIAO
+				if (src && src.includes(uni.env.USER_DATA_PATH))
+					fs && fs.unlink({
+						filePath: src
+					})
+				// #endif
+			})
+			clearInterval(this._timer);
+		},
+		methods: {
+			// #ifdef H5 || APP-PLUS-NVUE
+			_Dom2Str(nodes) {
+				var str = '';
+				for (var node of nodes) {
+					if (node.type == 'text')
+						str += node.text;
+					else {
+						str += ('<' + node.name);
+						for (var attr in node.attrs || {})
+							str += (' ' + attr + '="' + node.attrs[attr] + '"');
+						if (!node.children || !node.children.length) str += '>';
+						else str += ('>' + this._Dom2Str(node.children) + '</' + node.name + '>');
+					}
+				}
+				return str;
+			},
+			_handleHtml(html, append) {
+				if (typeof html != 'string') html = this._Dom2Str(html.nodes || html);
+				// 处理 rpx
+				if (html.includes('rpx'))
+					html = html.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * rpx + 'px');
+				if (!append) {
+					// 处理 tag-style 和 userAgentStyles
+					var style = '<style>@keyframes show{0%{opacity:0}100%{opacity:1}}';
+					for (var item in cfg.userAgentStyles)
+						style += `${item}{${cfg.userAgentStyles[item]}}`;
+					for (item in this.tagStyle)
+						style += `${item}{${this.tagStyle[item]}}`;
+					style += '</style>';
+					html = style + html;
+				}
+				return html;
+			},
+			// #endif
+			setContent(html, append) {
+				// #ifdef APP-PLUS-NVUE
+				if (!html) {
+					this.src = '';
+					this.height = 1;
+					return;
+				}
+				if (append) return;
+				plus.io.resolveLocalFileSystemURL('_doc', entry => {
+					entry.getDirectory('parser_tmp', {
+						create: true
+					}, entry => {
+						var fileName = Date.now() + '.html';
+						entry.getFile(fileName, {
+							create: true
+						}, entry => {
+							entry.createWriter(writer => {
+								writer.onwriteend = () => {
+									this.nodes = [1];
+									this.src = '_doc/parser_tmp/' + fileName;
+									this.$nextTick(function() {
+										entry.remove();
+									})
+								}
+								html =
+									'<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1' +
+									(this.selectable ? '' : ',user-scalable=no') +
+									'"><script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></' +
+									'script><base href="' + this.domain + '">' + this._handleHtml(html) +
+									'<script>"use strict";function post(t){uni.postMessage({data:t})}' +
+									(this.showWithAnimation ? 'document.body.style.animation="show .5s",' : '') +
+									'document.addEventListener("UniAppJSBridgeReady",function(){post({action:"load",text:document.body.innerText});var t=document.getElementsByTagName("title");t.length&&post({action:"getTitle",title:t[0].innerText});for(var e,o=document.getElementsByTagName("img"),n=[],i=0,r=0;e=o[i];i++)e.onerror=function(){post({action:"error",source:"img",target:this})},e.hasAttribute("ignore")||"A"==e.parentElement.nodeName||(e.i=r++,n.push(e.src),e.onclick=function(){post({action:"preview",img:{i:this.i,src:this.src}})});post({action:"getImgList",imgList:n});for(var a,s=document.getElementsByTagName("a"),c=0;a=s[c];c++)a.onclick=function(){var t,e=this.getAttribute("href");if("#"==e[0]){var r=document.getElementById(e.substr(1));r&&(t=r.offsetTop)}return post({action:"linkpress",href:e,offset:t}),!1};;for(var u,m=document.getElementsByTagName("video"),d=0;u=m[d];d++)u.style.maxWidth="100%",u.onerror=function(){post({action:"error",source:"video",target:this})}' +
+									(this.autopause ? ',u.onplay=function(){for(var t,e=0;t=m[e];e++)t!=this&&t.pause()}' : '') +
+									';for(var g,l=document.getElementsByTagName("audio"),p=0;g=l[p];p++)g.onerror=function(){post({action:"error",source:"audio",target:this})};window.onload=function(){post({action:"ready",height:document.body.scrollHeight})}});</' +
+									'script>';
+								writer.write(html);
+							});
+						})
+					})
+				})
+				// #endif
+				// #ifdef H5
+				if (!html) {
+					if (this.rtf && !append) this.rtf.parentNode.removeChild(this.rtf);
+					return;
+				}
+				var div = document.createElement('div');
+				if (!append) {
+					if (this.rtf) this.rtf.parentNode.removeChild(this.rtf);
+					this.rtf = div;
+				} else {
+					if (!this.rtf) this.rtf = div;
+					else this.rtf.appendChild(div);
+				}
+				div.innerHTML = this._handleHtml(html, append);
+				for (var styles = this.rtf.getElementsByTagName('style'), i = 0, style; style = styles[i++];) {
+					style.innerHTML = style.innerHTML.replace(/body/g, '#rtf' + this._uid);
+					style.setAttribute('scoped', 'true');
+				}
+				// 懒加载
+				if (!this._observer && this.lazyLoad && IntersectionObserver) {
+					this._observer = new IntersectionObserver(changes => {
+						for (let item, i = 0; item = changes[i++];) {
+							if (item.isIntersecting) {
+								item.target.src = item.target.getAttribute('data-src');
+								item.target.removeAttribute('data-src');
+								this._observer.unobserve(item.target);
+							}
+						}
+					}, {
+						rootMargin: '900px 0px 900px 0px'
+					})
+				}
+				var _ts = this;
+				// 获取标题
+				var title = this.rtf.getElementsByTagName('title');
+				if (title.length && this.autosetTitle)
+					uni.setNavigationBarTitle({
+						title: title[0].innerText
+					})
+				// 图片处理
+				this.imgList.length = 0;
+				var imgs = this.rtf.getElementsByTagName('img');
+				for (let i = 0, j = 0, img; img = imgs[i]; i++) {
+					img.style.maxWidth = '100%';
+					var src = img.getAttribute('src');
+					if (this.domain && src) {
+						if (src[0] == '/') {
+							if (src[1] == '/')
+								img.src = (this.domain.includes('://') ? this.domain.split('://')[0] : '') + ':' + src;
+							else img.src = this.domain + src;
+						} else if (!src.includes('://')) img.src = this.domain + '/' + src;
+					}
+					if (!img.hasAttribute('ignore') && img.parentElement.nodeName != 'A') {
+						img.i = j++;
+						_ts.imgList.push(img.src || img.getAttribute('data-src'));
+						img.onclick = function() {
+							var preview = true;
+							this.ignore = () => preview = false;
+							_ts.$emit('imgtap', this);
+							if (preview) {
+								uni.previewImage({
+									current: this.i,
+									urls: _ts.imgList
+								});
+							}
+						}
+					}
+					img.onerror = function() {
+						_ts.$emit('error', {
+							source: 'img',
+							target: this
+						});
+					}
+					if (_ts.lazyLoad && this._observer && img.src && img.i != 0) {
+						img.setAttribute('data-src', img.src);
+						img.removeAttribute('src');
+						this._observer.observe(img);
+					}
+				}
+				// 链接处理
+				var links = this.rtf.getElementsByTagName('a');
+				for (var link of links) {
+					link.onclick = function() {
+						var jump = true,
+							href = this.getAttribute('href');
+						_ts.$emit('linkpress', {
+							href,
+							ignore: () => jump = false
+						});
+						if (jump && href) {
+							if (href[0] == '#') {
+								if (_ts.useAnchor) {
+									_ts.navigateTo({
+										id: href.substr(1)
+									})
+								}
+							} else if (href.indexOf('http') == 0 || href.indexOf('//') == 0)
+								return true;
+							else {
+								uni.navigateTo({
+									url: href
+								})
+							}
+						}
+						return false;
+					}
+				}
+				// 视频处理
+				var videos = this.rtf.getElementsByTagName('video');
+				_ts.videoContexts = videos;
+				for (let video, i = 0; video = videos[i++];) {
+					video.style.maxWidth = '100%';
+					video.onerror = function() {
+						_ts.$emit('error', {
+							source: 'video',
+							target: this
+						});
+					}
+					video.onplay = function() {
+						if (_ts.autopause)
+							for (let item, i = 0; item = _ts.videoContexts[i++];)
+								if (item != this) item.pause();
+					}
+				}
+				// 音频处理
+				var audios = this.rtf.getElementsByTagName('audios');
+				for (var audio of audios)
+					audio.onerror = function() {
+						_ts.$emit('error', {
+							source: 'audio',
+							target: this
+						});
+					}
+				this.document = this.rtf;
+				if (!append) document.getElementById('rtf' + this._uid).appendChild(this.rtf);
+				this.$nextTick(() => {
+					this.nodes = [1];
+					this.$emit('load');
+				})
+				setTimeout(() => this.showAm = '', 500);
+				// #endif
+				// #ifndef H5 || APP-PLUS-NVUE
+				var nodes;
+				if (!html)
+					return this.nodes = [];
+				else if (typeof html == 'string') {
+					let parser = new Parser(html, this);
+					// 缓存读取
+					if (this.useCache) {
+						var hashVal = hash(html);
+						if (cache[hashVal])
+							nodes = cache[hashVal];
+						else {
+							nodes = parser.parse();
+							cache[hashVal] = nodes;
+						}
+					} else nodes = parser.parse();
+					this.$emit('parse', nodes);
+				} else if (Object.prototype.toString.call(html) == '[object Array]') {
+					// 非本插件产生的 array 需要进行一些转换
+					if (html.length && html[0].PoweredBy != 'Parser') {
+						let parser = new Parser(html, this);
+						(function f(ns) {
+							for (var i = 0, n; n = ns[i]; i++) {
+								if (n.type == 'text') continue;
+								n.attrs = n.attrs || {};
+								for (var item in n.attrs)
+									if (typeof n.attrs[item] != 'string') n.attrs[item] = n.attrs[item].toString();
+								parser.matchAttr(n, parser);
+								if (n.children && n.children.length) {
+									parser.STACK.push(n);
+									f(n.children);
+									parser.popNode(parser.STACK.pop());
+								} else n.children = void 0;
+							}
+						})(html);
+					}
+					nodes = html;
+				} else if (typeof html == 'object' && html.nodes) {
+					nodes = html.nodes;
+					console.warn('错误的 html 类型:object 类型已废弃');
+				} else
+					return console.warn('错误的 html 类型:' + typeof html);
+				// #ifdef APP-PLUS
+				this.loadVideo = false;
+				// #endif
+				if (document) this.document = new document(this.nodes, 'nodes', this);
+				if (append) this.nodes = this.nodes.concat(nodes);
+				else this.nodes = nodes;
+				if (nodes.length && nodes[0].title && this.autosetTitle)
+					uni.setNavigationBarTitle({
+						title: nodes[0].title
+					})
+				this.$nextTick(() => {
+					this.imgList.length = 0;
+					this.videoContexts = [];
+					// #ifdef MP-TOUTIAO
+					setTimeout(() => {
+						// #endif
+						var f = (cs) => {
+							for (let i = 0, c; c = cs[i++];) {
+								if (c.$options.name == 'trees') {
+									for (var j = c.nodes.length, item; item = c.nodes[--j];) {
+										if (item.c) continue;
+										if (item.name == 'img') {
+											this.imgList.setItem(item.attrs.i, item.attrs.src);
+											// #ifndef MP-ALIPAY
+											if (!c.observer && !c.imgLoad && item.attrs.i != '0') {
+												if (this.lazyLoad && uni.createIntersectionObserver) {
+													c.observer = uni.createIntersectionObserver(c);
+													c.observer.relativeToViewport({
+														top: 900,
+														bottom: 900
+													}).observe('._img', () => {
+														c.imgLoad = true;
+														c.observer.disconnect();
+													})
+												} else
+													c.imgLoad = true;
+											}
+											// #endif
+										}
+										// #ifndef MP-ALIPAY
+										else if (item.name == 'video') {
+											var ctx = uni.createVideoContext(item.attrs.id, c);
+											ctx.id = item.attrs.id;
+											this.videoContexts.push(ctx);
+										}
+										// #endif
+										// #ifdef MP-BAIDU || MP-ALIPAY || APP-PLUS
+										if (item.attrs && item.attrs.id) {
+											this.anchors = this.anchors || [];
+											this.anchors.push({
+												id: item.attrs.id,
+												node: c
+											})
+										}
+										// #endif
+									}
+								}
+								if (c.$children.length)
+									f(c.$children)
+							}
+						}
+						f(this.$children);
+						// #ifdef MP-TOUTIAO
+					}, 200)
+					this.$emit('load');
+					// #endif
+					// #ifdef APP-PLUS
+					setTimeout(() => {
+						this.loadVideo = true;
+					}, 3000);
+					// #endif
+				})
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				var height;
+				clearInterval(this._timer);
+				this._timer = setInterval(() => {
+					// #ifdef H5
+					var res = [this.rtf.getBoundingClientRect()];
+					// #endif
+					// #ifndef H5
+					// #ifdef APP-PLUS
+					uni.createSelectorQuery().in(this)
+					// #endif
+					// #ifndef APP-PLUS
+					this.createSelectorQuery()
+						// #endif
+						.select('#top').boundingClientRect().exec(res => {
+							// #endif
+							this.width = res[0].width;
+							if (res[0].height == height) {
+								this.$emit('ready', res[0])
+								clearInterval(this._timer);
+							}
+							height = res[0].height;
+							// #ifndef H5
+						});
+					// #endif
+				}, 350)
+				if (this.showWithAnimation && !append) this.showAm = 'animation:show .5s';
+				// #endif
+			},
+			getText(ns = this.nodes) {
+				// #ifdef APP-PLUS-NVUE
+				return this._text;
+				// #endif
+				// #ifdef H5
+				return this.rtf.innerText;
+				// #endif
+				// #ifndef H5 || APP-PLUS-NVUE
+				var txt = '';
+				for (var i = 0, n; n = ns[i++];) {
+					if (n.type == 'text') txt += n.text.replace(/&nbsp;/g, '\u00A0').replace(/&lt;/g, '<').replace(/&gt;/g, '>')
+						.replace(/&amp;/g, '&');
+					else if (n.type == 'br') txt += '\n';
+					else {
+						// 块级标签前后加换行
+						var block = n.name == 'p' || n.name == 'div' || n.name == 'tr' || n.name == 'li' || (n.name[0] == 'h' && n.name[1] >
+							'0' && n.name[1] < '7');
+						if (block && txt && txt[txt.length - 1] != '\n') txt += '\n';
+						if (n.children) txt += this.getText(n.children);
+						if (block && txt[txt.length - 1] != '\n') txt += '\n';
+						else if (n.name == 'td' || n.name == 'th') txt += '\t';
+					}
+				}
+				return txt;
+				// #endif
+			},
+			navigateTo(obj) {
+				if (!this.useAnchor)
+					return obj.fail && obj.fail({
+						errMsg: 'Anchor is disabled'
+					})
+				// #ifdef APP-PLUS-NVUE
+				if (!obj.id)
+					dom.scrollToElement(this.$refs.web);
+				else
+					this.$refs.web.evalJs('var pos=document.getElementById("' + obj.id +
+						'");if(pos)post({action:"linkpress",href:"#",offset:pos.offsetTop})');
+				return obj.success && obj.success({
+					errMsg: 'pageScrollTo:ok'
+				});
+				// #endif
+				// #ifdef H5
+				if (!obj.id) {
+					window.scrollTo(0, this.rtf.offsetTop);
+					return obj.success && obj.success({
+						errMsg: 'pageScrollTo:ok'
+					});
+				}
+				var target = document.getElementById(obj.id);
+				if (!target) return obj.fail && obj.fail({
+					errMsg: 'Label not found'
+				});
+				obj.scrollTop = this.rtf.offsetTop + target.offsetTop;
+				uni.pageScrollTo(obj);
+				// #endif
+				// #ifndef H5
+				var Scroll = (selector, component) => {
+					uni.createSelectorQuery().in(component ? component : this).select(selector).boundingClientRect().selectViewport()
+						.scrollOffset()
+						.exec(res => {
+							if (!res || !res[0])
+								return obj.fail && obj.fail({
+									errMsg: 'Label not found'
+								});
+							obj.scrollTop = res[1].scrollTop + res[0].top;
+							uni.pageScrollTo(obj);
+						})
+				}
+				if (!obj.id) Scroll('#top');
+				else {
+					// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+					Scroll('#top >>> #' + obj.id + ', #top >>> .' + obj.id);
+					// #endif
+					// #ifdef MP-BAIDU || MP-ALIPAY || APP-PLUS
+					for (var anchor of this.anchors)
+						if (anchor.id == obj.id)
+							Scroll('#' + obj.id + ', .' + obj.id, anchor.node);
+					// #endif
+				}
+				// #endif
+			},
+			getVideoContext(id) {
+				// #ifndef APP-PLUS-NVUE
+				if (!id) return this.videoContexts;
+				else
+					for (var i = this.videoContexts.length; i--;)
+						if (this.videoContexts[i].id == id) return this.videoContexts[i];
+				// #endif
+			},
+			// 预加载
+			preLoad(html, num) {
+				// #ifdef H5 || APP-PLUS-NVUE
+				if (html.constructor == Array)
+					html = this._Dom2Str(html);
+				var script = "var contain=document.createElement('div');contain.innerHTML='" + html.replace(/'/g, "\\'") +
+					"';for(var imgs=contain.querySelectorAll('img'),i=imgs.length-1;i>=" + num +
+					";i--)imgs[i].removeAttribute('src');";
+				// #endif
+				// #ifdef APP-PLUS-NVUE
+				this.$refs.web.evalJs(script);
+				// #endif
+				// #ifdef H5
+				eval(script);
+				// #endif
+				// #ifndef H5 || APP-PLUS-NVUE
+				if (typeof html == 'string') {
+					var id = hash(html);
+					html = new Parser(html, this).parse();
+					cache[id] = html;
+				}
+				var wait = [];
+				(function f(ns) {
+					for (var i = 0, n; n = ns[i++];) {
+						if (n.name == 'img' && n.attrs.src && !wait.includes(n.attrs.src))
+							wait.push(n.attrs.src);
+						f(n.children || []);
+					}
+				})(html);
+				if (num) wait = wait.slice(0, num);
+				this._wait = (this._wait || []).concat(wait);
+				if (!this.imgs) this.imgs = this._wait.splice(0, 15);
+				else if (this.imgs.length < 15)
+					this.imgs = this.imgs.concat(this._wait.splice(0, 15 - this.imgs.length));
+				// #endif
+			},
+			// #ifdef APP-PLUS-NVUE
+			_message(e) {
+				// 接收 web-view 消息
+				var data = e.detail.data[0];
+				if (data.action == 'load') {
+					this.$emit('load');
+					this._text = data.text;
+				} else if (data.action == 'getTitle') {
+					if (this.autosetTitle)
+						uni.setNavigationBarTitle({
+							title: data.title
+						})
+				} else if (data.action == 'getImgList') {
+					this.imgList.length = 0;
+					for (var i = data.imgList.length; i--;)
+						this.imgList.setItem(i, data.imgList[i]);
+				} else if (data.action == 'preview') {
+					var preview = true;
+					data.img.ignore = () => preview = false;
+					this.$emit('imgtap', data.img);
+					if (preview)
+						uni.previewImage({
+							current: data.img.i,
+							urls: this.imgList
+						})
+				} else if (data.action == 'linkpress') {
+					var jump = true,
+						href = data.href;
+					this.$emit('linkpress', {
+						href,
+						ignore: () => jump = false
+					})
+					if (jump && href) {
+						if (href[0] == '#') {
+							if (this.useAnchor)
+								dom.scrollToElement(this.$refs.web, {
+									offset: data.offset
+								})
+						} else if (href.includes('://'))
+							plus.runtime.openWeb(href);
+						else
+							uni.navigateTo({
+								url: href
+							})
+					}
+				} else if (data.action == 'error')
+					this.$emit('error', {
+						source: data.source,
+						target: data.target
+					})
+				else if (data.action == 'ready') {
+					this.height = data.height;
+					this.$nextTick(() => {
+						uni.createSelectorQuery().in(this).select('#top').boundingClientRect().exec(res => {
+							this.rect = res[0];
+							this.$emit('ready', res[0]);
+						})
+					})
+				}
+			},
+			// #endif
+			// #ifndef APP-PLUS-NVUE
+			// #ifndef H5
+			_load(e) {
+				if (this._wait.length)
+					this.$set(this.imgs, e.target.id, this._wait.shift());
+			},
+			// #endif
+			_tap(e) {
+				// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+				if (this.gestureZoom && e.timeStamp - this._lastT < 300) {
+					var initY = e.touches[0].pageY - e.currentTarget.offsetTop;
+					if (this._zoom) {
+						this._scaleAm.translateX(0).scale(1).step();
+						uni.pageScrollTo({
+							scrollTop: (initY + this._initY) / 2 - e.touches[0].clientY,
+							duration: 400
+						})
+					} else {
+						var initX = e.touches[0].pageX - e.currentTarget.offsetLeft;
+						this._initY = initY;
+						this._scaleAm = uni.createAnimation({
+							transformOrigin: `${initX}px ${this._initY}px 0`,
+							timingFunction: 'ease-in-out'
+						});
+						// #ifdef MP-TOUTIAO
+						this._scaleAm.opacity(1);
+						// #endif
+						this._scaleAm.scale(2).step();
+						this._tMax = initX / 2;
+						this._tMin = (initX - this.width) / 2;
+						this._tX = 0;
+					}
+					this._zoom = !this._zoom;
+					this.scaleAm = this._scaleAm.export();
+				}
+				this._lastT = e.timeStamp;
+				// #endif
+			},
+			_touchstart(e) {
+				// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+				if (e.touches.length == 1)
+					this._initX = this._lastX = e.touches[0].pageX;
+				// #endif
+			},
+			_touchmove(e) {
+				// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+				var diff = e.touches[0].pageX - this._lastX;
+				if (this._zoom && e.touches.length == 1 && Math.abs(diff) > 20) {
+					this._lastX = e.touches[0].pageX;
+					if ((this._tX <= this._tMin && diff < 0) || (this._tX >= this._tMax && diff > 0))
+						return;
+					this._tX += (diff * Math.abs(this._lastX - this._initX) * 0.05);
+					if (this._tX < this._tMin) this._tX = this._tMin;
+					if (this._tX > this._tMax) this._tX = this._tMax;
+					this._scaleAm.translateX(this._tX).step();
+					this.scaleAm = this._scaleAm.export();
+				}
+				// #endif
+			}
+			// #endif
+		}
+	}
+</script>
+
+<style>
+	@keyframes show {
+		0% {
+			opacity: 0
+		}
+
+		100% {
+			opacity: 1;
+		}
+	}
+
+	/* #ifdef MP-WEIXIN */
+	:host {
+		display: block;
+		overflow: scroll;
+		-webkit-overflow-scrolling: touch;
+	}
+
+	/* #endif */
+</style>

+ 102 - 0
components/jyf-parser/libs/CssHandler.js

@@ -0,0 +1,102 @@
+/*
+  解析和匹配 Css 的选择器
+  github:https://github.com/jin-yufeng/Parser
+  docs:https://jin-yufeng.github.io/Parser
+  author:JinYufeng
+  update:2020/03/15
+*/
+var cfg = require('./config.js');
+class CssHandler {
+	constructor(tagStyle) {
+		var styles = Object.assign({}, cfg.userAgentStyles);
+		for (var item in tagStyle)
+			styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item];
+		this.styles = styles;
+	}
+	getStyle = data => this.styles = new CssParser(data, this.styles).parse();
+	match(name, attrs) {
+		var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : '';
+		if (attrs.class) {
+			var items = attrs.class.split(' ');
+			for (var i = 0, item; item = items[i]; i++)
+				if (tmp = this.styles['.' + item])
+					matched += tmp + ';';
+		}
+		if (tmp = this.styles['#' + attrs.id])
+			matched += tmp + ';';
+		return matched;
+	}
+}
+module.exports = CssHandler;
+class CssParser {
+	constructor(data, init) {
+		this.data = data;
+		this.floor = 0;
+		this.i = 0;
+		this.list = [];
+		this.res = init;
+		this.state = this.Space;
+	}
+	parse() {
+		for (var c; c = this.data[this.i]; this.i++)
+			this.state(c);
+		return this.res;
+	}
+	section = () => this.data.substring(this.start, this.i);
+	isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+	// 状态机
+	Space(c) {
+		if (c == '.' || c == '#' || this.isLetter(c)) {
+			this.start = this.i;
+			this.state = this.Name;
+		} else if (c == '/' && this.data[this.i + 1] == '*')
+			this.Comment();
+		else if (!cfg.blankChar[c] && c != ';')
+			this.state = this.Ignore;
+	}
+	Comment() {
+		this.i = this.data.indexOf('*/', this.i) + 1;
+		if (!this.i) this.i = this.data.length;
+		this.state = this.Space;
+	}
+	Ignore(c) {
+		if (c == '{') this.floor++;
+		else if (c == '}' && !--this.floor) this.state = this.Space;
+	}
+	Name(c) {
+		if (cfg.blankChar[c]) {
+			this.list.push(this.section());
+			this.state = this.NameSpace;
+		} else if (c == '{') {
+			this.list.push(this.section());
+			this.Content();
+		} else if (c == ',') {
+			this.list.push(this.section());
+			this.Comma();
+		} else if (!this.isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_')
+			this.state = this.Ignore;
+	}
+	NameSpace(c) {
+		if (c == '{') this.Content();
+		else if (c == ',') this.Comma();
+		else if (!cfg.blankChar[c]) this.state = this.Ignore;
+	}
+	Comma() {
+		while (cfg.blankChar[this.data[++this.i]]);
+		if (this.data[this.i] == '{') this.Content();
+		else {
+			this.start = this.i--;
+			this.state = this.Name;
+		}
+	}
+	Content() {
+		this.start = ++this.i;
+		if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length;
+		var content = this.section();
+		for (var i = 0, item; item = this.list[i++];)
+			if (this.res[item]) this.res[item] += ';' + content;
+			else this.res[item] = content;
+		this.list = [];
+		this.state = this.Space;
+	}
+}

+ 577 - 0
components/jyf-parser/libs/MpHtmlParser.js

@@ -0,0 +1,577 @@
+/*
+  将 html 解析为适用于小程序 rich-text 的 DOM 结构
+  github:https://github.com/jin-yufeng/Parser
+  docs:https://jin-yufeng.github.io/Parser
+  author:JinYufeng
+  update:2020/04/13
+*/
+var cfg = require('./config.js'),
+	blankChar = cfg.blankChar,
+	CssHandler = require('./CssHandler.js'),
+	{
+		screenWidth,
+		system
+	} = wx.getSystemInfoSync();
+// #ifdef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO
+var entities = {
+	lt: '<',
+	gt: '>',
+	amp: '&',
+	quot: '"',
+	apos: "'",
+	nbsp: '\xA0',
+	ensp: '\u2002',
+	emsp: '\u2003',
+	ndash: '–',
+	mdash: '—',
+	middot: '·',
+	lsquo: '‘',
+	rsquo: '’',
+	ldquo: '“',
+	rdquo: '”',
+	bull: '•',
+	hellip: '…',
+	permil: '‰',
+	copy: '©',
+	reg: '®',
+	trade: '™',
+	times: '×',
+	divide: '÷',
+	cent: '¢',
+	pound: '£',
+	yen: '¥',
+	euro: '€',
+	sect: '§'
+};
+// #endif
+var emoji; // emoji 补丁包 https://jin-yufeng.github.io/Parser/#/instructions?id=emoji
+class MpHtmlParser {
+	constructor(data, options = {}) {
+		this.attrs = {};
+		this.compress = options.compress;
+		this.CssHandler = new CssHandler(options.tagStyle, screenWidth);
+		this.data = data;
+		this.domain = options.domain;
+		this.DOM = [];
+		this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0;
+		this.protocol = this.domain && this.domain.includes('://') ? this.domain.split('://')[0] : '';
+		this.state = this.Text;
+		this.STACK = [];
+		this.useAnchor = options.useAnchor;
+		this.xml = options.xml;
+	}
+	parse() {
+		if (emoji) this.data = emoji.parseEmoji(this.data);
+		for (var c; c = this.data[this.i]; this.i++)
+			this.state(c);
+		if (this.state == this.Text) this.setText();
+		while (this.STACK.length) this.popNode(this.STACK.pop());
+		// #ifdef MP-BAIDU || MP-TOUTIAO
+		// 将顶层标签的一些样式提取出来给 rich-text
+		(function f(ns) {
+			for (var i = ns.length, n; n = ns[--i];) {
+				if (n.type == 'text') continue;
+				if (!n.c) {
+					var style = n.attrs.style;
+					if (style) {
+						var j, k, res;
+						if ((j = style.indexOf('display')) != -1)
+							res = style.substring(j, (k = style.indexOf(';', j)) == -1 ? style.length : k);
+						if ((j = style.indexOf('float')) != -1)
+							res += ';' + style.substring(j, (k = style.indexOf(';', j)) == -1 ? style.length : k);
+						n.attrs.contain = res;
+					}
+				} else f(n.children);
+			}
+		})(this.DOM);
+		// #endif
+		if (this.DOM.length) {
+			this.DOM[0].PoweredBy = 'Parser';
+			if (this.title) this.DOM[0].title = this.title;
+		}
+		return this.DOM;
+	}
+	// 设置属性
+	setAttr() {
+		var name = this.getName(this.attrName);
+		if (cfg.trustAttrs[name]) {
+			if (!this.attrVal) {
+				if (cfg.boolAttrs[name]) this.attrs[name] = 'T';
+			} else if (name == 'src') this.attrs[name] = this.getUrl(this.attrVal.replace(/&amp;/g, '&'));
+			else this.attrs[name] = this.attrVal;
+		}
+		this.attrVal = '';
+		while (blankChar[this.data[this.i]]) this.i++;
+		if (this.isClose()) this.setNode();
+		else {
+			this.start = this.i;
+			this.state = this.AttrName;
+		}
+	}
+	// 设置文本节点
+	setText() {
+		var back, text = this.section();
+		if (!text) return;
+		text = (cfg.onText && cfg.onText(text, () => back = true)) || text;
+		if (back) {
+			this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i);
+			let j = this.start + text.length;
+			for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]);
+			return;
+		}
+		if (!this.pre) {
+			// 合并空白符
+			var tmp = [];
+			for (let i = text.length, c; c = text[--i];)
+				if (!blankChar[c] || (!blankChar[tmp[0]] && (c = ' '))) tmp.unshift(c);
+			text = tmp.join('');
+			if (text == ' ') return;
+		}
+		// 处理实体
+		var siblings = this.siblings(),
+			i = -1,
+			j, en;
+		while (1) {
+			if ((i = text.indexOf('&', i + 1)) == -1) break;
+			if ((j = text.indexOf(';', i + 2)) == -1) break;
+			if (text[i + 1] == '#') {
+				en = parseInt((text[i + 2] == 'x' ? '0' : '') + text.substring(i + 2, j));
+				if (!isNaN(en)) text = text.substr(0, i) + String.fromCharCode(en) + text.substring(j + 1);
+			} else {
+				en = text.substring(i + 1, j);
+				// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
+				if (en == 'nbsp') text = text.substr(0, i) + '\xA0' + text.substr(j + 1); // 解决 &nbsp; 失效
+				else if (en != 'lt' && en != 'gt' && en != 'amp' && en != 'ensp' && en != 'emsp' && en != 'quot' && en != 'apos') {
+					i && siblings.push({
+						type: 'text',
+						text: text.substr(0, i)
+					})
+					siblings.push({
+						type: 'text',
+						text: `&${en};`,
+						en: 1
+					})
+					text = text.substr(j + 1);
+					i = -1;
+				}
+				// #endif
+				// #ifdef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO
+				if (entities[en]) text = text.substr(0, i) + entities[en] + text.substr(j + 1);
+				// #endif
+			}
+		}
+		text && siblings.push({
+			type: 'text',
+			text
+		})
+	}
+	// 设置元素节点
+	setNode() {
+		var node = {
+				name: this.tagName.toLowerCase(),
+				attrs: this.attrs
+			},
+			close = cfg.selfClosingTags[node.name] || (this.xml && this.data[this.i] == '/');
+		this.attrs = {};
+		if (!cfg.ignoreTags[node.name]) {
+			this.matchAttr(node);
+			if (!close) {
+				node.children = [];
+				if (node.name == 'pre' && cfg.highlight) {
+					this.remove(node);
+					this.pre = node.pre = true;
+				}
+				this.siblings().push(node);
+				this.STACK.push(node);
+			} else if (!cfg.filter || cfg.filter(node, this) != false)
+				this.siblings().push(node);
+		} else {
+			if (!close) this.remove(node);
+			else if (node.name == 'source') {
+				var parent = this.STACK[this.STACK.length - 1],
+					attrs = node.attrs;
+				if (parent && attrs.src)
+					if (parent.name == 'video' || parent.name == 'audio')
+						parent.attrs.source.push(attrs.src);
+					else {
+						var i, media = attrs.media;
+						if (parent.name == 'picture' && !parent.attrs.src && !(attrs.src.indexOf('.webp') && system.includes('iOS')) &&
+							(!media || (media.includes('px') &&
+								(((i = media.indexOf('min-width')) != -1 && (i = media.indexOf(':', i + 8)) != -1 && screenWidth > parseInt(
+										media.substr(i + 1))) ||
+									((i = media.indexOf('max-width')) != -1 && (i = media.indexOf(':', i + 8)) != -1 && screenWidth < parseInt(
+										media.substr(i + 1)))))))
+							parent.attrs.src = attrs.src;
+					}
+			} else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href;
+		}
+		if (this.data[this.i] == '/') this.i++;
+		this.start = this.i + 1;
+		this.state = this.Text;
+	}
+	// 移除标签
+	remove(node) {
+		var name = node.name,
+			j = this.i;
+		while (1) {
+			if ((this.i = this.data.indexOf('</', this.i + 1)) == -1) {
+				if (name == 'pre' || name == 'svg') this.i = j;
+				else this.i = this.data.length;
+				return;
+			}
+			this.start = (this.i += 2);
+			while (!blankChar[this.data[this.i]] && !this.isClose()) this.i++;
+			if (this.getName(this.section()) == name) {
+				// 代码块高亮
+				if (name == 'pre') {
+					this.data = this.data.substr(0, j + 1) + cfg.highlight(this.data.substring(j + 1, this.i - 5), node.attrs) +
+						this.data.substr(this.i - 5);
+					return this.i = j;
+				} else if (name == 'style')
+					this.CssHandler.getStyle(this.data.substring(j + 1, this.i - 7));
+				else if (name == 'title')
+					this.title = this.data.substring(j + 1, this.i - 7);
+				if ((this.i = this.data.indexOf('>', this.i)) == -1) this.i = this.data.length;
+				// 处理 svg
+				if (name == 'svg') {
+					var src = this.data.substring(j, this.i + 1);
+					if (!node.attrs.xmlns) src = ' xmlns="http://www.w3.org/2000/svg"' + src;
+					var i = j;
+					while (this.data[j] != '<') j--;
+					src = this.data.substring(j, i) + src;
+					var parent = this.STACK[this.STACK.length - 1];
+					if (node.attrs.width == '100%' && parent && (parent.attrs.style || '').includes('inline'))
+						parent.attrs.style = 'width:300px;max-width:100%;' + parent.attrs.style;
+					this.siblings().push({
+						name: 'img',
+						attrs: {
+							src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
+							ignore: 'T'
+						}
+					})
+				}
+				return;
+			}
+		}
+	}
+	// 处理属性
+	matchAttr(node) {
+		var attrs = node.attrs,
+			style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''),
+			styleObj = {};
+		if (attrs.id) {
+			if (this.compress & 1) attrs.id = void 0;
+			else if (this.useAnchor) this.bubble();
+		}
+		if ((this.compress & 2) && attrs.class) attrs.class = void 0;
+		switch (node.name) {
+			case 'img':
+				if (attrs['data-src']) {
+					attrs.src = attrs.src || attrs['data-src'];
+					attrs['data-src'] = void 0;
+				}
+				if (attrs.src && !attrs.ignore) {
+					if (this.bubble()) attrs.i = (this.imgNum++).toString();
+					else attrs.ignore = 'T';
+				}
+				break;
+			case 'a':
+			case 'ad':
+			// #ifdef APP-PLUS
+			case 'iframe':
+			case 'embed':
+			// #endif
+				this.bubble();
+				break;
+			case 'font':
+				if (attrs.color) {
+					styleObj['color'] = attrs.color;
+					attrs.color = void 0;
+				}
+				if (attrs.face) {
+					styleObj['font-family'] = attrs.face;
+					attrs.face = void 0;
+				}
+				if (attrs.size) {
+					var size = parseInt(attrs.size);
+					if (size < 1) size = 1;
+					else if (size > 7) size = 7;
+					var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
+					styleObj['font-size'] = map[size - 1];
+					attrs.size = void 0;
+				}
+				break;
+			case 'video':
+			case 'audio':
+				if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]);
+				else this[`${node.name}Num`]++;
+				if (node.name == 'video') {
+					if (attrs.width) {
+						style = `width:${parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')};${style}`;
+						attrs.width = void 0;
+					}
+					if (attrs.height) {
+						style = `height:${parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')};${style}`;
+						attrs.height = void 0;
+					}
+					if (this.videoNum > 3) node.lazyLoad = true;
+				}
+				attrs.source = [];
+				if (attrs.src) attrs.source.push(attrs.src);
+				if (!attrs.controls && !attrs.autoplay)
+					console.warn(`存在没有 controls 属性的 ${node.name} 标签,可能导致无法播放`, node);
+				this.bubble();
+				break;
+			case 'td':
+			case 'th':
+				if (attrs.colspan || attrs.rowspan)
+					for (var k = this.STACK.length, item; item = this.STACK[--k];)
+						if (item.name == 'table') {
+							item.c = void 0;
+							break;
+						}
+		}
+		if (attrs.align) {
+			styleObj['text-align'] = attrs.align;
+			attrs.align = void 0;
+		}
+		// 压缩 style
+		var styles = style.replace(/&quot;/g, '"').replace(/&amp;/g, '&').split(';');
+		style = '';
+		for (var i = 0, len = styles.length; i < len; i++) {
+			var info = styles[i].split(':');
+			if (info.length < 2) continue;
+			let key = info[0].trim().toLowerCase(),
+				value = info.slice(1).join(':').trim();
+			if (value.includes('-webkit') || value.includes('-moz') || value.includes('-ms') || value.includes('-o') || value
+				.includes(
+					'safe'))
+				style += `;${key}:${value}`;
+			else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
+				styleObj[key] = value;
+		}
+		if (node.name == 'img' && parseInt(styleObj.width || attrs.width) > screenWidth)
+			styleObj.height = 'auto';
+		for (var key in styleObj) {
+			var value = styleObj[key];
+			if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1;
+			// 填充链接
+			if (value.includes('url')) {
+				var j = value.indexOf('(');
+				if (j++ != -1) {
+					while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++;
+					value = value.substr(0, j) + this.getUrl(value.substr(j));
+				}
+			}
+			// 转换 rpx
+			else if (value.includes('rpx'))
+				value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * screenWidth / 750 + 'px');
+			else if (key == 'white-space' && value.includes('pre'))
+				this.pre = node.pre = true;
+			style += `;${key}:${value}`;
+		}
+		style = style.substr(1);
+		if (style) attrs.style = style;
+	}
+	// 节点出栈处理
+	popNode(node) {
+		// 空白符处理
+		if (node.pre) {
+			node.pre = this.pre = void 0;
+			for (let i = this.STACK.length; i--;)
+				if (this.STACK[i].pre)
+					this.pre = true;
+		}
+		if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false))
+			return this.siblings().pop();
+		var attrs = node.attrs;
+		// 替换一些标签名
+		if (node.name == 'picture') {
+			node.name = 'img';
+			if (!attrs.src && (node.children[0] || '').name == 'img')
+				attrs.src = node.children[0].attrs.src;
+			if (attrs.src && !attrs.ignore)
+				attrs.i = (this.imgNum++).toString();
+			return node.children = void 0;
+		}
+		if (cfg.blockTags[node.name]) node.name = 'div';
+		else if (!cfg.trustTags[node.name]) node.name = 'span';
+		// 处理列表
+		if (node.c) {
+			if (node.name == 'ul') {
+				var floor = 1;
+				for (let i = this.STACK.length; i--;)
+					if (this.STACK[i].name == 'ul') floor++;
+				if (floor != 1)
+					for (let i = node.children.length; i--;)
+						node.children[i].floor = floor;
+			} else if (node.name == 'ol') {
+				for (let i = 0, num = 1, child; child = node.children[i++];)
+					if (child.name == 'li') {
+						child.type = 'ol';
+						child.num = ((num, type) => {
+							if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26);
+							if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26);
+							if (type == 'i' || type == 'I') {
+								num = (num - 1) % 99 + 1;
+								var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
+									ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
+									res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || '');
+								if (type == 'i') return res.toLowerCase();
+								return res;
+							}
+							return num;
+						})(num++, attrs.type) + '.';
+					}
+			}
+		}
+		// 处理表格的边框
+		if (node.name == 'table') {
+			var padding = attrs.cellpadding,
+				spacing = attrs.cellspacing,
+				border = attrs.border;
+			if (node.c) {
+				this.bubble();
+				if (!padding) padding = 2;
+				if (!spacing) spacing = 2;
+			}
+			if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`;
+			if (spacing) attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`;
+			if (border || padding)
+				(function f(ns) {
+					for (var i = 0, n; n = ns[i]; i++) {
+						if (n.name == 'th' || n.name == 'td') {
+							if (border) n.attrs.style = `border:${border}px solid gray;${n.attrs.style}`;
+							if (padding) n.attrs.style = `padding:${padding}px;${n.attrs.style}`;
+						} else f(n.children || []);
+					}
+				})(node.children)
+		}
+		this.CssHandler.pop && this.CssHandler.pop(node);
+		// 自动压缩
+		if (node.name == 'div' && !Object.keys(attrs).length) {
+			var siblings = this.siblings();
+			if (node.children.length == 1 && node.children[0].name == 'div')
+				siblings[siblings.length - 1] = node.children[0];
+		}
+	}
+	// 工具函数
+	bubble() {
+		for (var i = this.STACK.length, item; item = this.STACK[--i];) {
+			if (cfg.richOnlyTags[item.name]) {
+				if (item.name == 'table' && !Object.hasOwnProperty.call(item, 'c')) item.c = 1;
+				return false;
+			}
+			item.c = 1;
+		}
+		return true;
+	}
+	getName = val => this.xml ? val : val.toLowerCase();
+	getUrl(url) {
+		if (url[0] == '/') {
+			if (url[1] == '/') url = this.protocol + ':' + url;
+			else if (this.domain) url = this.domain + url;
+		} else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://'))
+			url = this.domain + '/' + url;
+		return url;
+	}
+	isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>');
+	section = () => this.data.substring(this.start, this.i);
+	siblings = () => this.STACK.length ? this.STACK[this.STACK.length - 1].children : this.DOM;
+	// 状态机
+	Text(c) {
+		if (c == '<') {
+			var next = this.data[this.i + 1],
+				isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+			if (isLetter(next)) {
+				this.setText();
+				this.start = this.i + 1;
+				this.state = this.TagName;
+			} else if (next == '/') {
+				this.setText();
+				if (isLetter(this.data[++this.i + 1])) {
+					this.start = this.i + 1;
+					this.state = this.EndTag;
+				} else
+					this.Comment();
+			} else if (next == '!') {
+				this.setText();
+				this.Comment();
+			}
+		}
+	}
+	Comment() {
+		var key;
+		if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->';
+		else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>';
+		else key = '>';
+		if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length;
+		else this.i += key.length - 1;
+		this.start = this.i + 1;
+		this.state = this.Text;
+	}
+	TagName(c) {
+		if (blankChar[c]) {
+			this.tagName = this.section();
+			while (blankChar[this.data[this.i]]) this.i++;
+			if (this.isClose()) this.setNode();
+			else {
+				this.start = this.i;
+				this.state = this.AttrName;
+			}
+		} else if (this.isClose()) {
+			this.tagName = this.section();
+			this.setNode();
+		}
+	}
+	AttrName(c) {
+		var blank = blankChar[c];
+		if (blank) {
+			this.attrName = this.section();
+			c = this.data[this.i];
+		}
+		if (c == '=') {
+			if (!blank) this.attrName = this.section();
+			while (blankChar[this.data[++this.i]]);
+			this.start = this.i--;
+			this.state = this.AttrValue;
+		} else if (blank) this.setAttr();
+		else if (this.isClose()) {
+			this.attrName = this.section();
+			this.setAttr();
+		}
+	}
+	AttrValue(c) {
+		if (c == '"' || c == "'") {
+			this.start++;
+			if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length;
+			this.attrVal = this.section();
+			this.i++;
+		} else {
+			for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++);
+			this.attrVal = this.section();
+		}
+		this.setAttr();
+	}
+	EndTag(c) {
+		if (blankChar[c] || c == '>' || c == '/') {
+			var name = this.getName(this.section());
+			for (var i = this.STACK.length; i--;)
+				if (this.STACK[i].name == name) break;
+			if (i != -1) {
+				var node;
+				while ((node = this.STACK.pop()).name != name);
+				this.popNode(node);
+			} else if (name == 'p' || name == 'br')
+				this.siblings().push({
+					name,
+					attrs: {}
+				});
+			this.i = this.data.indexOf('>', this.i);
+			this.start = this.i + 1;
+			if (this.i == -1) this.i = this.data.length;
+			else this.state = this.Text;
+		}
+	}
+}
+module.exports = MpHtmlParser;

+ 80 - 0
components/jyf-parser/libs/config.js

@@ -0,0 +1,80 @@
+/* 配置文件 */
+// #ifdef MP-WEIXIN
+const canIUse = wx.canIUse('editor'); // 高基础库标识,用于兼容
+// #endif
+module.exports = {
+	// 过滤器函数
+	filter: null,
+	// 代码高亮函数
+	highlight: null,
+	// 文本处理函数
+	onText: null,
+	blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
+	// 块级标签,将被转为 div
+	blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,section' + (
+		// #ifdef MP-WEIXIN
+		canIUse ? '' :
+		// #endif
+		',pre')),
+	// 将被移除的标签
+	ignoreTags: makeMap(
+		'area,base,basefont,canvas,command,frame,input,isindex,keygen,link,map,meta,param,script,source,style,svg,textarea,title,track,use,wbr'
+		// #ifdef MP-WEIXIN
+		+ (canIUse ? ',rp' : '')
+		// #endif
+		// #ifndef APP-PLUS
+		+ ',embed,iframe'
+		// #endif
+	),
+	// 只能被 rich-text 显示的标签
+	richOnlyTags: makeMap('a,colgroup,fieldset,legend,picture,table'
+		// #ifdef MP-WEIXIN
+		+ (canIUse ? ',bdi,bdo,caption,rt,ruby' : '')
+		// #endif
+	),
+	// 自闭合的标签
+	selfClosingTags: makeMap(
+		'area,base,basefont,br,col,circle,ellipse,embed,frame,hr,img,input,isindex,keygen,line,link,meta,param,path,polygon,rect,source,track,use,wbr'
+	),
+	// 信任的属性
+	trustAttrs: makeMap(
+		'align,alt,app-id,author,autoplay,border,cellpadding,cellspacing,class,color,colspan,controls,data-src,dir,face,height,href,id,ignore,loop,media,muted,name,path,poster,rowspan,size,span,src,start,style,type,unit-id,width,xmlns'
+	),
+	// bool 型的属性
+	boolAttrs: makeMap('autoplay,controls,ignore,loop,muted'),
+	// 信任的标签
+	trustTags: makeMap(
+		'a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'
+		// #ifdef MP-WEIXIN
+		+ (canIUse ? ',bdi,bdo,caption,pre,rt,ruby' : '')
+		// #endif
+		// #ifdef APP-PLUS
+		+ ',embed,iframe'
+		// #endif
+	),
+	// 默认的标签样式
+	userAgentStyles: {
+		address: 'font-style:italic',
+		big: 'display:inline;font-size:1.2em',
+		blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px',
+		caption: 'display:table-caption;text-align:center',
+		center: 'text-align:center',
+		cite: 'font-style:italic',
+		dd: 'margin-left:40px',
+		img: 'max-width:100%',
+		mark: 'background-color:yellow',
+		picture: 'max-width:100%',
+		pre: 'font-family:monospace;white-space:pre;overflow:scroll',
+		s: 'text-decoration:line-through',
+		small: 'display:inline;font-size:0.8em',
+		u: 'text-decoration:underline'
+	}
+}
+
+function makeMap(maprichee55text9oppplugin) {
+	var map = {},
+		list = maprichee55text9oppplugin.split(',');
+	for (var i = list.length; i--;)
+		map[list[i]] = true;
+	return map;
+}

+ 35 - 0
components/jyf-parser/libs/handler.sjs

@@ -0,0 +1,35 @@
+var inlineTags = {
+	abbr: 1,
+	b: 1,
+	big: 1,
+	code: 1,
+	del: 1,
+	em: 1,
+	i: 1,
+	ins: 1,
+	label: 1,
+	q: 1,
+	small: 1,
+	span: 1,
+	strong: 1
+}
+export default {
+	// 从顶层标签的样式中取出一些给 rich-text
+	getStyle: function(style) {
+		if (style) {
+			var i, j, res = '';
+			if ((i = style.indexOf('display')) != -1)
+				res = style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
+			if ((i = style.indexOf('float')) != -1)
+				res += ';' + style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
+			return res;
+		}
+	},
+	getNode: function(item) {
+		return [item];
+	},
+	// 是否通过 rich-text 显示
+	useRichText: function(item) {
+		return !item.c && !inlineTags[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1;
+	}
+}

+ 44 - 0
components/jyf-parser/libs/handler.wxs

@@ -0,0 +1,44 @@
+var inlineTags = {
+	abbr: 1,
+	b: 1,
+	big: 1,
+	code: 1,
+	del: 1,
+	em: 1,
+	i: 1,
+	ins: 1,
+	label: 1,
+	q: 1,
+	small: 1,
+	span: 1,
+	strong: 1
+}
+module.exports = {
+	// 从顶层标签的样式中取出一些给 rich-text
+	getStyle: function(style) {
+		if (style) {
+			var i, j, res = '';
+			if ((i = style.indexOf('display')) != -1)
+				res = style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
+			if ((i = style.indexOf('float')) != -1)
+				res += ';' + style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
+			return res;
+		}
+	},
+	// 处理懒加载
+	getNode: function(item, imgLoad) {
+		if (!imgLoad && item.attrs.i != '0') {
+			var img = {
+				name: 'img',
+				attrs: JSON.parse(JSON.stringify(item.attrs))
+			}
+			delete img.attrs.src;
+			img.attrs.style += ';width:20px;height:20px';
+			return [img];
+		} else return [item];
+	},
+	// 是否通过 rich-text 显示
+	useRichText: function(item) {
+		return !item.c && !inlineTags[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1;
+	}
+}

+ 476 - 0
components/jyf-parser/libs/trees.vue

@@ -0,0 +1,476 @@
+<!--
+  trees 递归显示组件
+  github:https://github.com/jin-yufeng/Parser 
+  docs:https://jin-yufeng.github.io/Parser
+  插件市场:https://ext.dcloud.net.cn/plugin?id=805
+  author:JinYufeng
+  update:2020/04/13
+-->
+<template>
+	<view class="interlayer">
+		<block v-for="(n, index) in nodes" v-bind:key="index">
+			<!--图片-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
+			<rich-text v-if="n.name=='img'" :id="n.attrs.id" class="_img" :style="''+handler.getStyle(n.attrs.style)" :nodes="handler.getNode(n,!lazyLoad||imgLoad)"
+			 :data-attrs="n.attrs" @tap="imgtap" @longpress="imglongtap" />
+			<!--#endif-->
+			<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
+			<rich-text v-if="n.name=='img'" :id="n.attrs.id" class="_img" :style="n.attrs.contain" :nodes='[n]' :data-attrs="n.attrs"
+			 @tap="imgtap" @longpress="imglongtap" />
+			<!--#endif-->
+			<!--文本-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
+			<rich-text v-else-if="n.decode" class="_entity" :nodes="[n]"></rich-text>
+			<!--#endif-->
+			<text v-else-if="n.type=='text'" decode>{{n.text}}</text>
+			<text v-else-if="n.name=='br'">\n</text>
+			<!--视频-->
+			<view v-else-if="n.name=='video'">
+				<view v-if="(!loadVideo||n.lazyLoad)&&!(controls[n.attrs.id]&&controls[n.attrs.id].play)" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')"
+				 :style="n.attrs.style" @tap="_loadVideo" />
+				<video v-else :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||(controls[n.attrs.id]&&controls[n.attrs.id].play)"
+				 :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[(controls[n.attrs.id]&&controls[n.attrs.id].index)||0]"
+				 :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" data-from="video" data-source="source" @error="error" @play="play" />
+			</view>
+			<!--音频-->
+			<audio v-else-if="n.name=='audio'" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :autoplay="n.attrs.autoplay"
+			 :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.attrs.source[(controls[n.attrs.id]&&controls[n.attrs.id].index)||0]"
+			 :data-id="n.attrs.id" data-from="audio" data-source="source" @error="error" @play="play" />
+			<!--链接-->
+			<view v-else-if="n.name=='a'" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style"
+			 :data-attrs="n.attrs" @tap="linkpress">
+				<trees class="_span" :nodes="n.children" />
+			</view>
+			<!--广告(按需打开注释)-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO-->
+			<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']"
+			 data-from="ad" @error="error" />-->
+			<!--#endif-->
+			<!--#ifdef MP-BAIDU-->
+			<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :appid="n.attrs.appid"
+			 :apid="n.attrs.apid" :type="n.attrs.type" data-from="ad" @error="error" />-->
+			<!--#endif-->
+			<!--#ifdef APP-PLUS-->
+			<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :adpid="n.attrs.adpid"
+			 data-from="ad" @error="error" />-->
+			<!--#endif-->
+			<!--列表-->
+			<view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex'">
+				<view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view>
+				<view v-else class="_ul-bef">
+					<view v-if="n.floor%3==0" class="_ul-p1">█</view>
+					<view v-else-if="n.floor%3==2" class="_ul-p2" />
+					<view v-else class="_ul-p1" style="border-radius:50%">█</view>
+				</view>
+				<!--#ifdef MP-ALIPAY-->
+				<view class="_li">
+					<trees :nodes="n.children" />
+				</view>
+				<!--#endif-->
+				<!--#ifndef MP-ALIPAY-->
+				<trees class="_li" :nodes="n.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
+				<!--#endif-->
+			</view>
+			<!--表格-->
+			<view v-else-if="n.name=='table'&&n.c" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:table'">
+				<view v-for="(tbody, i) in n.children" v-bind:key="i" :class="tbody.attrs.class" :style="(tbody.attrs.style||'')+(tbody.name[0]=='t'?';display:table-'+(tbody.name=='tr'?'row':'row-group'):'')">
+					<view v-for="(tr, j) in tbody.children" v-bind:key="j" :class="tr.attrs.class" :style="(tr.attrs.style||'')+(tr.name[0]=='t'?';display:table-'+(tr.name=='tr'?'row':'cell'):'')">
+						<trees v-if="tr.name=='td'" :nodes="tr.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
+						<block v-else>
+							<!--#ifdef MP-ALIPAY-->
+							<view v-for="(td, k) in tr.children" v-bind:key="k" :class="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')">
+								<trees :nodes="td.children" />
+							</view>
+							<!--#endif-->
+							<!--#ifndef MP-ALIPAY-->
+							<trees v-for="(td, k) in tr.children" v-bind:key="k" :class="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')"
+							 :nodes="td.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
+							<!--#endif-->
+						</block>
+					</view>
+				</view>
+			</view>
+			<!--#ifdef APP-PLUS-->
+			<iframe v-else-if="n.name=='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder"
+			 :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
+			<embed v-else-if="n.name=='embed'" :style="n.attrs.style" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
+			<!--#endif-->
+			<!--富文本-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
+			<rich-text v-else-if="handler.useRichText(n)" :id="n.attrs.id" :class="'_p __'+n.name" :nodes="[n]" />
+			<!--#endif-->
+			<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
+			<rich-text v-else-if="!(n.c||n.continue)" :id="n.attrs.id" :class="_p" :style="n.attrs.contain" :nodes="[n]" />
+			<!--#endif-->
+			<!--#ifdef MP-ALIPAY-->
+			<view v-else :id="n.attrs.id" :class="'_'+n.name+' '+(n.attrs.class||'')" :style="n.attrs.style">
+				<trees :nodes="n.children" />
+			</view>
+			<!--#endif-->
+			<!--#ifndef MP-ALIPAY-->
+			<trees v-else :class="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :style="n.attrs.style" :nodes="n.children"
+			 :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
+			<!--#endif-->
+		</block>
+	</view>
+</template>
+<script module="handler" lang="wxs" src="./handler.wxs"></script>
+<script module="handler" lang="sjs" src="./handler.sjs"></script>
+<script>
+	global.Parser = {};
+	import trees from './trees'
+	export default {
+		components: {
+			trees
+		},
+		name: 'trees',
+		data() {
+			return {
+				controls: {},
+				// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
+				imgLoad: false,
+				// #endif
+				// #ifndef APP-PLUS
+				loadVideo: true
+				// #endif
+			}
+		},
+		props: {
+			nodes: Array,
+			// #ifdef MP-WEIXIN || MP-QQ || H5 || APP-PLUS
+			lazyLoad: Boolean,
+			// #endif
+			// #ifdef APP-PLUS
+			loadVideo: Boolean
+			// #endif
+		},
+		mounted() {
+			// 获取顶层组件
+			this.top = this.$parent;
+			while (this.top.$options.name != 'parser') {
+				if (this.top.top) {
+					this.top = this.top.top;
+					break;
+				}
+				this.top = this.top.$parent;
+			}
+		},
+		// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
+		beforeDestroy() {
+			if (this.observer)
+				this.observer.disconnect();
+		},
+		// #endif
+		methods: {
+			// #ifndef MP-ALIPAY
+			play(e) {
+				if (this.top.videoContexts.length > 1 && this.top.autopause)
+					for (var i = this.top.videoContexts.length; i--;)
+						if (this.top.videoContexts[i].id != e.currentTarget.dataset.id)
+							this.top.videoContexts[i].pause();
+			},
+			// #endif
+			imgtap(e) {
+				var attrs = e.currentTarget.dataset.attrs;
+				if (!attrs.ignore) {
+					var preview = true, data = {
+						id: e.target.id,
+						src: attrs.src,
+						ignore: () => preview = false
+					};
+					global.Parser.onImgtap && global.Parser.onImgtap(data);
+					this.top.$emit('imgtap', data);
+					if (preview) {
+						var urls = this.top.imgList,
+							current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0);
+						uni.previewImage({
+							current,
+							urls
+						})
+					}
+				}
+			},
+			imglongtap(e) {
+				var attrs = e.item.dataset.attrs;
+				if (!attrs.ignore)
+					this.top.$emit('imglongtap', {
+						id: e.target.id,
+						src: attrs.src
+					})
+			},
+			linkpress(e) {
+				var jump = true,
+					attrs = e.currentTarget.dataset.attrs;
+				attrs.ignore = () => jump = false;
+				global.Parser.onLinkpress && global.Parser.onLinkpress(attrs);
+				this.top.$emit('linkpress', attrs);
+				if (jump) {
+					// #ifdef MP
+					if (attrs['app-id']) {
+						return uni.navigateToMiniProgram({
+							appId: attrs['app-id'],
+							path: attrs.path
+						})
+					}
+					// #endif
+					if (attrs.href) {
+						if (attrs.href[0] == '#') {
+							if (this.top.useAnchor)
+								this.top.navigateTo({
+									id: attrs.href.substring(1)
+								})
+						} else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0) {
+							// #ifdef APP-PLUS
+							plus.runtime.openWeb(attrs.href);
+							// #endif
+							// #ifndef APP-PLUS
+							uni.setClipboardData({
+								data: attrs.href,
+								success: () =>
+									uni.showToast({
+										title: '链接已复制'
+									})
+							})
+							// #endif
+						} else
+							uni.navigateTo({
+								url: attrs.href
+							})
+					}
+				}
+			},
+			error(e) {
+				var context, target = e.currentTarget,
+					source = target.dataset.from;
+				if (source == 'video' || source == 'audio') {
+					// 加载其他 source
+					var index = this.controls[target.id] ? this.controls[target.id].index + 1 : 1;
+					if (index < target.dataset.source.length)
+						this.$set(this.controls, target.id + '.index', index);
+					if (source == 'video') context = uni.createVideoContext(target.id, this);
+				}
+				this.top && this.top.$emit('error', {
+					source,
+					target,
+					errMsg: e.detail.errMsg,
+					errCode: e.detail.errCode,
+					context
+				});
+			},
+			_loadVideo(e) {
+				this.$set(this.controls, e.currentTarget.id, {
+					play: true,
+					index: 0
+				})
+			}
+		}
+	}
+</script>
+
+<style>
+	/* 在这里引入自定义样式 */
+
+	/* 链接和图片效果 */
+	._a {
+		display: inline;
+		color: #366092;
+		word-break: break-all;
+		padding: 1.5px 0 1.5px 0;
+	}
+
+	._hover {
+		opacity: 0.7;
+		text-decoration: underline;
+	}
+
+	._img {
+		display: inline-block;
+		text-indent: 0;
+	}
+
+	/* #ifdef MP-WEIXIN */
+	:host {
+		display: inline;
+	}
+
+	/* #endif */
+
+	/* #ifdef MP */
+	.interlayer {
+		align-content: inherit;
+		align-items: inherit;
+		display: inherit;
+		flex-direction: inherit;
+		flex-wrap: inherit;
+		justify-content: inherit;
+		width: 100%;
+		white-space: inherit;
+	}
+
+	/* #endif */
+
+	._b,
+	._strong {
+		font-weight: bold;
+	}
+
+	._blockquote,
+	._div,
+	._p,
+	._ol,
+	._ul,
+	._li {
+		display: block;
+	}
+
+	._code {
+		font-family: monospace;
+	}
+
+	._del {
+		text-decoration: line-through;
+	}
+
+	._em,
+	._i {
+		font-style: italic;
+	}
+
+	._h1 {
+		font-size: 2em;
+	}
+
+	._h2 {
+		font-size: 1.5em;
+	}
+
+	._h3 {
+		font-size: 1.17em;
+	}
+
+	._h5 {
+		font-size: 0.83em;
+	}
+
+	._h6 {
+		font-size: 0.67em;
+	}
+
+	._h1,
+	._h2,
+	._h3,
+	._h4,
+	._h5,
+	._h6 {
+		display: block;
+		font-weight: bold;
+	}
+
+	._ins {
+		text-decoration: underline;
+	}
+
+	._li {
+		flex: 1;
+		width: 0;
+	}
+
+	._ol-bef {
+		margin-right: 5px;
+		text-align: right;
+		width: 36px;
+	}
+
+	._ul-bef {
+		line-height: normal;
+		margin: 0 12px 0 23px;
+	}
+
+	._ol-bef,
+	._ul_bef {
+		flex: none;
+		user-select: none;
+	}
+
+	._ul-p1 {
+		display: inline-block;
+		height: 0.3em;
+		line-height: 0.3em;
+		overflow: hidden;
+		width: 0.3em;
+	}
+
+	._ul-p2 {
+		border: 0.05em solid black;
+		border-radius: 50%;
+		display: inline-block;
+		height: 0.23em;
+		width: 0.23em;
+	}
+
+	._q::before {
+		content: '"';
+	}
+
+	._q::after {
+		content: '"';
+	}
+
+	._sub {
+		font-size: smaller;
+		vertical-align: sub;
+	}
+
+	._sup {
+		font-size: smaller;
+		vertical-align: super;
+	}
+
+	/* #ifndef MP-WEIXIN */
+	._abbr,
+	._b,
+	._code,
+	._del,
+	._em,
+	._i,
+	._ins,
+	._label,
+	._q,
+	._span,
+	._strong,
+	._sub,
+	._sup {
+		display: inline;
+	}
+
+	/* #endif */
+
+	/* #ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY */
+	.__bdo,
+	.__bdi,
+	.__ruby,
+	.__rt,
+	._entity {
+		display: inline-block;
+	}
+
+	/* #endif */
+	._video {
+		background-color: black;
+		display: inline-block;
+		height: 225px;
+		position: relative;
+		width: 300px;
+	}
+
+	._video::after {
+		border-color: transparent transparent transparent white;
+		border-style: solid;
+		border-width: 15px 0 15px 30px;
+		content: '';
+		left: 50%;
+		margin: -15px 0 0 -15px;
+		position: absolute;
+		top: 50%;
+	}
+</style>

+ 143 - 0
components/kefu/index.vue

@@ -0,0 +1,143 @@
+<template>
+  <!-- 客服列表 -->
+  <view v-if="show" :style="colorStyle">
+    <view class="discountInfo on">
+      <view class="title">客服列表<text class="iconfont icon-guanbi5" @click="closeDiscount"></text></view>
+      <view class="list">
+        <view class="item" v-for="(item,index) in customerList" :key="index">
+          <image :src="item.avatar" mode="" class="img"></image>
+          <view class="text">{{item.staff_name}}</view>
+          <view class="contact" @click="callPhone(item)">
+            联系客服
+          </view>
+        </view>
+      </view>
+      <slot name="bottom"></slot>
+    </view>
+    <view class="mask" @touchmove.prevent :hidden="false" @click="closeDiscount"></view>
+  </view>
+</template>
+
+<script>
+   import colors from "@/mixins/color";
+  export default {
+    props: {
+      customerList: {
+        type: Array,
+        default: []
+      },
+			customerType:{
+				type:Number,
+				default:1
+			}
+    },
+    mixins:[colors],
+    data() {
+      return {
+        show: false,
+      };
+    },
+    mounted() {},
+    methods: {
+      closeDiscount() {
+        this.$emit('closeKefu')
+      },
+      callPhone(item) {
+				if(this.customerType == 1){
+					uni.makePhoneCall({
+						phoneNumber: item.customer_phone //仅为示例
+					});
+				}else{
+					uni.navigateTo({
+					  url: '/pages/store/service/index?id='+item.id
+					})
+				}
+      }
+    }
+  }
+</script>
+
+<style scoped lang="scss">
+  .discountInfo {
+    position: fixed;
+    bottom: 0;
+    width: 100%;
+    left: 0;
+    background-color: #fff;
+    z-index: 300;
+    border-radius: 16rpx 16rpx 0 0;
+    transform: translate3d(0, 100%, 0);
+    transition: all .3s cubic-bezier(.25, .5, .5, .9);
+    padding-bottom: 22rpx;
+    padding-bottom: calc(22rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+    padding-bottom: calc(22rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+
+    .title {
+      font-size: 32rpx;
+      color: #282828;
+      text-align: center;
+      margin: 38rpx 0 36rpx 0;
+      position: relative;
+
+      .iconfont {
+        position: absolute;
+        right: 30rpx;
+        top: 0;
+        font-size: 36rpx;
+      }
+    }
+
+    .list {
+
+      height: 750rpx;
+      margin: 30rpx 30rpx 0 30rpx;
+      overflow-x: hidden;
+      overflow-y: auto;
+
+      .item {
+        height: 120rpx;
+        width: 100%;
+        border-bottom: 1px solid #eee;
+        background-color: #fff;
+        padding: 30rpx 30rpx;
+        position: relative;
+        display: flex;
+        align-items: center;
+
+        .img {
+          margin-left: 6rpx;
+          width: 80rpx;
+          height: 80rpx;
+          border-radius: 50%;
+          border: 1px solid #EEEEEE;
+        }
+
+        .text {
+          margin-left: 20rpx;
+          font-size: 28rpx;
+          font-weight: 400;
+          color: #333333;
+
+        }
+
+        .contact {
+          position: absolute;
+          right: 30rpx;
+          width: 140rpx;
+          height: 48rpx;
+          text-align: center;
+          line-height: 48rpx;
+          background-color: var(--view-minorColorT);
+          font-size: 24rpx;
+          font-weight: 400;
+          border-radius: 24rpx;
+          color: var(--view-theme);
+        }
+      }
+    }
+  }
+
+  .on {
+    transform: translate3d(0, 0, 0);
+  }
+</style>

+ 89 - 0
components/kefuIcon/index.vue

@@ -0,0 +1,89 @@
+<template>
+	<!-- 客服跳转 -->
+	<!-- #ifdef APP-PLUS || H5 -->
+	<view class="acea-row row-center-wrapper cartf iconfont icon-kefu3" :style="{ top: top + 'px'}" @touchmove.stop.prevent="setTouchMove" @click="licks"></view>
+	<!-- #endif -->
+	<!-- #ifdef MP -->
+	<view v-if="routineContact == 0">
+		<view class="acea-row row-center-wrapper cartf iconfont icon-kefu3" :style="{ top: top + 'px'}" @touchmove.stop.prevent="setTouchMove" @click="licks"></view>
+	</view>
+	<button class="acea-row row-center-wrapper cartf iconfont icon-kefu3" open-type='contact' :style="{ top: top + 'px'}" @touchmove.stop.prevent="setTouchMove" v-else-if="routineContact==1 && !goodsCon"></button>
+	<button class="acea-row row-center-wrapper cartf iconfont icon-kefu3" open-type='contact' :send-message-title="storeInfo.store_name" :send-message-img="storeInfo.image" :send-message-path="`/pages/goods_details/index?id=${storeInfo.id}`" show-message-card :style="{ top: top + 'px'}" @touchmove.stop.prevent="setTouchMove" v-else-if="routineContact==1 && goodsCon"></button>
+	<!-- #endif -->
+</template>
+
+<script>
+	let app = getApp();
+	import {
+		mapGetters
+	} from "vuex";
+	export default {
+		name: "kefuIcon", 
+		props: {
+			ids: {
+				type: Number,
+				default: 0
+			},
+			routineContact: {
+				type: Number,
+				default: 0
+			},
+			storeInfo: {
+				type: Object,
+				default () {
+					return {};
+				}
+			},
+			goodsCon: {
+				type: Number,
+				default: 0
+			}
+		},
+		computed: mapGetters(['userInfo']),
+		data: function() {
+			return {
+				top: "480"
+			};
+		},
+		mounted() {
+			// #ifdef H5
+			this.top =  parseFloat(window.innerHeight) -200
+			// #endif
+		},
+		methods: {
+			setTouchMove(e) {
+				let that = this;
+				if (e.touches[0].clientY < 480 && e.touches[0].clientY > 66) {
+					that.top = e.touches[0].clientY
+				}
+			},
+			licks(){
+				let userInfo = {}
+				if(typeof this.userInfo === 'string'){
+					userInfo = JSON.parse(this.userInfo)
+				}else{
+					userInfo = this.userInfo
+				}
+				let url = `/pages/extension/customer_list/chat?productId=${this.ids}`
+				this.$util.getCustomer(userInfo,url)
+			}
+		},
+		created() {
+		}
+	};
+</script>
+
+<style lang="scss">
+	.cartf{
+		width: 96rpx;
+		height: 96rpx;
+		background: #FFFFFF;
+		box-shadow: 0 3rpx 16rpx rgba(0, 0, 0, 0.08);
+		border-radius: 50%;
+		font-size: 47rpx;
+		color: #666;
+		position: fixed;
+		right: 15rpx;
+		z-index: 9;
+	}
+</style>

+ 330 - 0
components/loginMobile/index.vue

@@ -0,0 +1,330 @@
+<template>
+	<!-- 手机号登录弹窗 -->
+	<view v-if="isUp">
+		<view class="mobile-bg" @click="close"></view>
+		<view class="mobile-mask animated" :class="{slideInUp:isUp}">
+			<view class="input-item">
+				<input type="text" v-model="account" placeholder="输入手机号" maxlength="11" />
+			</view>
+			<view class="input-item">
+				<input type="text" v-model="codeNum" placeholder="输入验证码" maxlength="6" />
+				<button class="code" :disabled="disabled" @click="code">{{text}}</button>
+			</view>
+			<view class="sub_btn" @click="loginBtn">立即登录</view>
+		</view>
+		<Verify @success="success" :captchaType="'blockPuzzle'" :imgSize="{ width: '330px', height: '155px' }"
+			ref="verify"></Verify>
+	</view>
+</template>
+
+<script>
+	const app = getApp();
+	import sendVerifyCode from "@/mixins/SendVerifyCode";
+	import Routine from '@/libs/routine';
+	import Verify from './../verify/verify.vue';
+	import {
+		loginMobile,
+		registerVerify,
+		getCodeApi,
+		getUserInfo,
+		phoneSilenceAuth,
+		phoneWxSilenceAuth
+	} from "@/api/user";
+	import {
+		bindingPhone
+	} from '@/api/api.js'
+	export default {
+		name: 'login_mobile',
+		components: {
+			Verify
+		},
+		props: {
+			isUp: {
+				type: Boolean,
+				default: false,
+			},
+			authKey: {
+				type: String,
+				default: '',
+			}
+		},
+		data() {
+			return {
+				keyCode: '',
+				account: '',
+				codeNum: ''
+			}
+		},
+		mixins: [sendVerifyCode],
+		mounted() {
+			this.getCode();
+		},
+		methods: {
+			success(data) {
+				let that = this;
+				this.$refs.verify.hide()
+				getCodeApi().then(res => {
+					registerVerify({
+						phone: that.account,
+						key: res.data.key,
+						captchaType: 'blockPuzzle',
+						captchaVerification: data.captchaVerification
+					}).then(res => {
+						that.$util.Tips({
+							title: res.msg
+						});
+						that.sendCode();
+					}).catch(err => {
+						return that.$util.Tips({
+							title: err
+						})
+					})
+				})
+			},
+			// 获取验证码
+			code() {
+				let that = this;
+				if (!that.account) return that.$util.Tips({
+					title: '请填写手机号码'
+				});
+				if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
+					title: '请输入正确的手机号码'
+				});
+				// await registerVerify({
+				// 	phone: that.account,
+				// 	key: that.keyCode,
+				// }).then(res => {
+				// 	that.$util.Tips({
+				// 		title: res.msg
+				// 	});
+				// 	that.sendCode();
+				// }).catch(err => {
+				// 	return that.$util.Tips({
+				// 		title: err
+				// 	})
+				// })
+				this.$refs.verify.show();
+			},
+			// 获取验证码api
+			getCode() {
+				let that = this
+				getCodeApi().then(res => {
+					that.keyCode = res.data.key;
+				}).catch(res => {
+					that.$util.Tips({
+						title: res
+					});
+				});
+			},
+			close() {
+				this.$emit('close', false)
+			},
+			// 登录
+			loginBtn() {
+				let that = this
+				// #ifdef MP
+				if (!that.account) return that.$util.Tips({
+					title: '请填写手机号码'
+				});
+				if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
+					title: '请输入正确的手机号码'
+				});
+				if (!that.codeNum) return that.$util.Tips({
+					title: '请填写验证码'
+				});
+				if (!/^[\w\d]+$/i.test(that.codeNum)) return that.$util.Tips({
+					title: '请输入正确的验证码'
+				});
+				uni.showLoading({
+					title: '正在登录中'
+				});
+				Routine.getCode()
+					.then(code => {
+						this.phoneSilenceAuth(code);
+					})
+					.catch(error => {
+						uni.hideLoading();
+					});
+				// #endif
+				// #ifdef H5
+				if (!that.account) return that.$util.Tips({
+					title: '请填写手机号码'
+				});
+				if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
+					title: '请输入正确的手机号码'
+				});
+				if (!that.codeNum) return that.$util.Tips({
+					title: '请填写验证码'
+				});
+				if (!/^[\w\d]+$/i.test(that.codeNum)) return that.$util.Tips({
+					title: '请输入正确的验证码'
+				});
+				uni.showLoading({
+					title: '正在登录中'
+				});
+				if (this.authKey) {
+					phoneWxSilenceAuth({
+						spid: app.globalData.spid,
+						spread: app.globalData.code,
+						phone: this.account,
+						captcha: this.codeNum,
+						key: this.authKey
+					}).then(res => {
+						let time = res.data.expires_time - this.$Cache.time();
+						this.$store.commit('LOGIN', {
+							token: res.data.token,
+							time: time
+						});
+						this.getUserInfo();
+					}).catch(error => {
+						uni.hideLoading()
+						this.$util.Tips({
+							title: error
+						})
+					})
+				} else {
+					bindingPhone({
+						phone: this.account,
+						captcha: this.codeNum,
+						key: this.$Cache.get('snsapiKey')
+					}).then(res => {
+						let time = res.data.expires_time - this.$Cache.time();
+						this.$store.commit('LOGIN', {
+							token: res.data.token,
+							time: time
+						});
+						this.$Cache.clear('snsapiKey');
+						this.getUserInfo();
+					}).catch(error => {
+						uni.hideLoading()
+						this.$util.Tips({
+							title: error
+						})
+					})
+				}
+
+				// #endif
+			},
+			// #ifdef MP
+			phoneSilenceAuth(code) {
+				let self = this
+				phoneSilenceAuth({
+					code: code,
+					spread_spid: app.globalData.spid,
+					spread_code: app.globalData.code,
+					phone: this.account,
+					captcha: this.codeNum
+				}).then(res => {
+					let time = res.data.expires_time - this.$Cache.time();
+					this.$store.commit('LOGIN', {
+						token: res.data.token,
+						time: time
+					});
+					this.getUserInfo();
+				}).catch(error => {
+					self.$util.Tips({
+						title: error
+					})
+				})
+			},
+			// #endif
+			/**
+			 * 获取个人用户信息
+			 */
+			getUserInfo: function() {
+				let that = this;
+				getUserInfo().then(res => {
+					uni.hideLoading();
+					that.userInfo = res.data
+					that.$store.commit("SETUID", res.data.uid);
+					that.$store.commit("UPDATE_USERINFO", res.data);
+					// #ifdef MP
+					that.$util.Tips({
+						title: '登录成功',
+						icon: 'success'
+					}, {
+						tab: 3
+					})
+					that.close()
+					// #endif
+					// #ifdef H5
+					that.$emit('wechatPhone', true)
+					// #endif
+				});
+			},
+		}
+	}
+</script>
+
+<style lang="stylus">
+	.mobile-bg {
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+		background: rgba(0, 0, 0, 0.5);
+		z-index: 667;
+	}
+
+	.mobile-mask {
+		z-index: 668;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		width: 100%;
+		padding: 67rpx 30rpx;
+		background: #fff;
+
+		.input-item {
+			display: flex;
+			justify-content: space-between;
+			width: 100%;
+			height: 86rpx;
+			margin-bottom: 38rpx;
+
+			input {
+				flex: 1;
+				display: block;
+				height: 100%;
+				padding-left: 40rpx;
+				border-radius: 43rpx;
+				border: 1px solid #DCDCDC;
+			}
+
+			.code {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 220rpx;
+				height: 86rpx;
+				margin-left: 30rpx;
+				background: var(--view-minorColorT);
+				font-size: 28rpx;
+				color: var(--view-theme);
+				border-radius: 43rpx;
+
+				&[disabled] {
+					background: rgba(0, 0, 0, 0.05);
+					color: #999;
+				}
+			}
+		}
+
+		.sub_btn {
+			width: 690rpx;
+			height: 86rpx;
+			line-height: 86rpx;
+			margin-top: 60rpx;
+			background: var(--view-theme);
+			border-radius: 43rpx;
+			color: #fff;
+			font-size: 28rpx;
+			text-align: center;
+		}
+	}
+
+	.animated {
+		animation-duration: .4s
+	}
+</style>

+ 163 - 0
components/loginMobile/routine_phone.vue

@@ -0,0 +1,163 @@
+<template>
+	<!-- 授权弹窗 -->
+	<view v-if="isPhoneBox">
+		<view class="mobile-bg" @click="close"></view>
+		<view class="mobile-mask animated" :class="{slideInUp:isUp}">
+			<view class="info-box">
+				<image :src="logoUrl"></image>
+				<view class="title">获取授权</view>
+				<view class="txt">获取微信的手机号授权</view>
+			</view>
+			<button class="sub_btn" open-type="getPhoneNumber" @getphonenumber="getphonenumber">获取微信手机号</button>
+			<slot name="bottom"></slot>
+		</view>
+	</view>
+</template>
+<script>
+	const app = getApp();
+	import Routine from '@/libs/routine';
+	import {
+		loginMobile,
+		registerVerify,
+		getCodeApi,
+		getUserInfo
+	} from "@/api/user";
+	import { getLogo, silenceAuth, getUserPhone } from '@/api/public';
+	export default{
+		name:'routine_phone',
+		props:{
+			isPhoneBox:{
+				type:Boolean,
+				default:false,
+			},
+			logoUrl:{
+				type:String,
+				default:'',
+			},
+			authKey:{
+				type:String,
+				default:'',
+			}
+		},
+		data(){
+			return {
+				keyCode:'',
+				account:'',
+				codeNum:'',
+				isStatus:false
+			}
+		},
+		mounted() {
+		},
+		methods:{
+			// #ifdef MP
+			// 小程序获取手机号码
+			getphonenumber(e){
+				uni.showLoading({ title: '正在登录中' });
+				Routine.getCode()
+					.then(code => {
+						this.getUserPhoneNumber(e.detail.encryptedData, e.detail.iv, code);
+					})
+					.catch(error => {
+						uni.hideLoading();
+					});
+			},
+			// 小程序获取手机号码回调
+			getUserPhoneNumber(encryptedData, iv, code) {
+				getUserPhone({
+					encryptedData: encryptedData,
+					iv: iv,
+					code: code,
+					spread_spid: app.globalData.spid,
+					spread_code: app.globalData.code,
+					key:this.authKey
+				})
+					.then(res => {
+						let time = res.data.expires_time - this.$Cache.time();
+						this.$store.commit('LOGIN', {
+							token: res.data.token,
+							time: time
+						});
+						this.getUserInfo();
+					})
+					.catch(res => {
+						uni.hideLoading();
+					});
+			},
+			/**
+			 * 获取个人用户信息
+			 */
+			getUserInfo: function() {
+				let that = this;
+				getUserInfo().then(res => {
+					uni.hideLoading();
+					that.userInfo = res.data
+					that.$store.commit("SETUID", res.data.uid);
+					that.$store.commit("UPDATE_USERINFO", res.data);
+					that.isStatus = true
+					this.close()
+				});
+			},
+			// #endif
+			close(){
+				this.$emit('close',{isStatus:this.isStatus})
+			}
+		}
+	}
+	
+</script>
+
+<style lang="scss">
+	.mobile-bg{
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+		background: rgba(0,0,0,0.5);
+		z-index: 667;
+	}
+	.mobile-mask {
+		z-index: 668;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		width: 100%;
+		padding: 67rpx 30rpx;
+		background: #fff;
+		.info-box{
+			display:flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			image{
+				width: 150rpx;
+				height: 150rpx;
+				border-radius: 10rpx;
+			}
+			.title{
+				margin-top: 30rpx;
+				margin-bottom: 20rpx;
+				font-size: 36rpx;
+			}
+			.txt{
+				font-size: 30rpx;
+				color: #868686;
+			}
+		}
+		.sub_btn{
+			width: 690rpx;
+			height: 86rpx;
+			line-height: 86rpx;
+			margin-top: 60rpx;
+			background: var(--view-theme);
+			border-radius: 43rpx;
+			color: #fff;
+			font-size: 28rpx;
+			text-align: center;
+		}
+	}
+	.animated{
+		animation-duration:.4s
+	}
+</style>

+ 215 - 0
components/maramlee-waterfalls-flow/maramlee-waterfalls-flow.vue

@@ -0,0 +1,215 @@
+<template>
+  <view class="waterfalls-box" :style="{ height: height + 'px' }">
+    <!--  #ifdef  MP-WEIXIN -->
+    <view
+      v-for="(item, index) of list"
+      class="waterfalls-list"
+      :key="item[idKey]"
+      :id="'waterfalls-list-id-' + item[idKey]"
+      :ref="'waterfalls-list-id-' + item[idKey]"
+      :style="{
+        '--offset': offset + 'px',
+        '--cols': cols,
+        top: allPositionArr[index].top || 0,
+        left: allPositionArr[index].left || 0,
+      }"
+      @click="$emit('wapper-lick', item)"
+    >
+		  <view class="pictrue">
+				<image
+				  class="waterfalls-list-image"
+				  mode="widthFix"
+				  :class="{ single }"
+          :style="imageStyle"
+				  :src="item[imageSrcKey] || ' '"
+				  @load="imageLoadHandle(index)"
+				  @error="imageLoadHandle(index)"
+				  @click="$emit('image-click', item)"
+				/>
+				<view class="masks acea-row row-center-wrapper" v-if="item.stock<=0">
+					<view class="bg">
+						<view>暂时</view>
+						<view>售罄</view>
+					</view>
+				</view>
+			</view>
+      <slot name="slot{{index}}" />
+    </view>
+    <!--  #endif -->
+    <!--  #ifndef  MP-WEIXIN -->
+    <view
+      v-for="(item, index) of list"
+      class="waterfalls-list"
+      :key="item[idKey]"
+      :id="'waterfalls-list-id-' + item[idKey]"
+      :ref="'waterfalls-list-id-' + item[idKey]"
+      :style="{
+        '--offset': offset + 'px',
+        '--cols': cols,
+        ...listStyle,
+        ...(allPositionArr[index] || {}),
+      }"
+      @click="$emit('wapper-lick', item)"
+    >
+	  <view class="pictrue">
+		  <image
+		    class="waterfalls-list-image"
+		    :class="{ single }"
+		    mode="widthFix"
+		    :style="imageStyle"
+		    :src="item[imageSrcKey] || ' '"
+		    @load="imageLoadHandle(index)"
+		    @error="imageLoadHandle(index)"
+		    @click="$emit('image-click', item)"
+		  />
+			<view class="masks acea-row row-center-wrapper" v-if="item.stock<=0">
+				<view class="bg">
+					<view>暂时</view>
+					<view>售罄</view>
+				</view>
+			</view>
+	  </view>
+      <slot v-bind="item" />
+    </view>
+    <!--  #endif -->
+  </view>
+</template>
+<script>
+export default {
+  props: {
+    list: { type: Array, required: true },
+    // offset 间距,单位为 px
+    offset: { type: Number, default: 10 },
+    // 列表渲染的 key 的键名,值必须唯一,默认为 id
+    idKey: { type: String, default: "id" },
+    // 图片 src 的键名
+    imageSrcKey: { type: String, default: "image" },
+    // 列数
+    cols: { type: Number, default: 2, validator: (num) => num >= 2 },
+    imageStyle: { type: Object },
+
+    // 是否是单独的渲染图片的样子,只控制图片圆角而已
+    single: { type: Boolean, default: false },
+
+    // #ifndef MP-WEIXIN
+    listStyle: { type: Object },
+    // #endif
+  },
+  data() {
+    return {
+      topArr: [], // left, right 多个时依次表示第几列的数据
+      allPositionArr: [], // 保存所有的位置信息
+      allHeightArr: [], // 保存所有的 height 信息
+      height: 0, // 外层包裹高度
+      oldNum: 0,
+      num: 0,
+    };
+  },
+  created() {
+    this.refresh();
+  },
+  methods: {
+    imageLoadHandle(index) {
+			if(!this.list.length){
+				return
+			}
+      const id = "waterfalls-list-id-" + this.list[index][this.idKey],
+        query = uni.createSelectorQuery().in(this);
+      query
+        .select("#" + id)
+        .fields({ size: true }, (data) => {
+          this.num++;
+          this.$set(this.allHeightArr, index, data.height);
+          if (this.num === this.list.length) {
+            for (let i = this.oldNum; i < this.num; i++) {
+              const getTopArrMsg = () => {
+                let arrtmp = [...this.topArr].sort((a, b) => a - b);
+                return {
+                  shorterIndex: this.topArr.indexOf(arrtmp[0]),
+                  shorterValue: arrtmp[0],
+                  longerIndex: this.topArr.indexOf(arrtmp[this.cols - 1]),
+                  longerValue: arrtmp[this.cols - 1],
+                };
+              };
+
+              const { shorterIndex, shorterValue } = getTopArrMsg();
+              const position = {
+                top: shorterValue + "px",
+                left: (data.width + this.offset) * shorterIndex + "px",
+              };
+              this.$set(this.allPositionArr, i, position);
+              this.topArr[shorterIndex] =
+                shorterValue + this.allHeightArr[i] + this.offset;
+              this.height = getTopArrMsg().longerValue - this.offset;
+            }
+            this.oldNum = this.num;
+            // 完成渲染 emit `image-load` 事件
+            this.$emit("image-load");
+          }
+        })
+        .exec();
+    },
+    refresh() {
+      let arr = [];
+      for (let i = 0; i < this.cols; i++) {
+        arr.push(0);
+      }
+      this.topArr = arr;
+      this.num = 0;
+      this.oldNum = 0;
+      this.height = 0;
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+// 这里可以自行配置
+$border-radius: 10px;
+
+.waterfalls-box {
+  position: relative;
+  width: 100%;
+  overflow: hidden;
+  .waterfalls-list {
+    width: calc((100% - var(--offset) * (var(--cols) - 1)) / var(--cols));
+    position: absolute;
+    background-color: #fff;
+    border-radius: $border-radius;
+    // 防止刚开始渲染时堆叠在第一幅图的地方
+    left: calc(-50% - var(--offset));
+	.pictrue{
+		position: relative;
+		.masks{
+			position: absolute;
+			top: 0;
+			left: 0;
+			right: 0;
+			bottom: 0;
+			background: rgba(0, 0, 0, 0.2);
+			border-radius: 20rpx 20rpx 0 0;
+			.bg{
+				width: 152rpx;
+				height: 152rpx;
+				background: #000000;
+				opacity: 0.6;
+				color: #fff;
+				font-size: 32rpx;
+				border-radius: 50%;
+				padding: 34rpx 0;
+				text-align: center;
+			}
+		}
+	}
+    .waterfalls-list-image {
+      width: 100%;
+			height: 382rpx!important;
+      will-change: transform;
+      border-radius: $border-radius $border-radius 0 0;
+      display: block;
+      &.single {
+        border-radius: $border-radius;
+      }
+    }
+  }
+}
+</style>

+ 476 - 0
components/orderGoods/index.vue

@@ -0,0 +1,476 @@
+<template>
+	<!-- 订单商品 -->
+	<view class="orderGoods" :class="product_type?'on':''">
+		<view class='total' v-if="!split && totalNmu>0">共{{totalNmu}}件商品</view>
+		<view class='total' v-if="split">
+			<text>订单包裹{{index + 1}}</text>
+			<view class="rig-btn" v-if="status_type === 2">
+				<view class="logistics sure" @click="confirmOrder(orderId)">确认收货</view>
+				<view v-if="delivery_type === 'express'" class="logistics" @click="logistics(orderId)">查看物流</view>
+			</view>
+			<view class="rig-btn" v-else-if="status_type === -1">
+				<view class="refund">申请退款中</view>
+			</view>
+			<view class="rig-btn" v-else-if="status_type === -2">
+				<view class="refund">已退款</view>
+			</view>
+			<view class="rig-btn" v-else-if="status_type === 4">
+				<view class="done">已完成</view>
+			</view>
+		</view>
+		<view class='goodWrapper'>
+			<view class='list' :class="{op:!item.is_valid}"
+				v-for="(item,index) in cartInfo" :key="index" @click="jumpCon(item.product_id)">
+				<view class="item acea-row row-between-wrapper">
+					<view class='pictrue'>
+						<image :src='item.productInfo.attrInfo.image' v-if="item.productInfo.attrInfo"></image>
+						<image :src='item.productInfo.image' v-else></image>
+					</view>
+					<view class='text'>
+						<view class='acea-row row-between-wrapper'>
+							<view class='name line1'>{{item.productInfo.store_name}}</view>
+							<view class='num'>x {{item.cart_num}}</view>
+						</view>
+						<view class='attr line1' v-if="item.productInfo.attrInfo">{{item.productInfo.attrInfo.suk}}</view>
+						<view class='money font-color pic'>
+							<text>
+								¥{{item.productInfo.attrInfo?item.productInfo.attrInfo.price:item.productInfo.price}}
+							</text>
+							<text class="valid" v-if="!item.is_valid">{{shippingType==0?'不送达':'不支持自提'}}</text>
+						</view>
+						<view class="posBnt acea-row row-middle">
+							<view class="evaluate writeOff" v-if="(statusType==5 || statusType==1 || statusType==2 || statusType==3) && (deliveryType==2 || sendType=='send')">
+								<text class="on" v-if="item.is_writeoff">已核销</text>
+								<text class="on" v-if="!item.is_writeoff && item.surplus_num<item.cart_num">已核销{{parseInt(item.cart_num)-parseInt(item.surplus_num)}}件</text>
+								<text v-if="!item.is_writeoff && item.surplus_num==item.cart_num">未核销</text>
+							</view>
+							<!-- #ifdef H5 || APP-PLUS -->
+							<slot name="bottom" :item="item"></slot>
+							<!-- #endif -->
+							<!-- #ifdef MP -->
+							<slot name="bottom{{index}}"></slot>
+							<!-- #endif -->
+							<text class="refund" v-if="item.refund_num && statusType !=-2">{{item.refund_num}}件退款中</text>
+						</view>
+					</view>
+				</view>
+				<view class="button acea-row row-right">
+					<view class="bnt acea-row row-center-wrapper" v-if="refund_status === 0 && item.refund_num !=item.cart_num && paid && item.is_support_refund" @click.stop="openSubcribe(item,productType)">申请退款</view>
+					<view class='bnt acea-row row-center-wrapper' v-if='evaluate==3 && item.is_reply==0 && pid != -1'
+						@click.stop="evaluateTap(item.unique,orderId)">评价</view>
+					<view class='bnt acea-row row-center-wrapper' v-else-if="evaluate==3 && item.is_reply==1">已评价</view>
+				</view>
+				<!-- #ifdef H5 || APP-PLUS -->
+				<slot name="footer" :item="item"></slot>
+				<!-- #endif -->
+				<!-- #ifdef MP -->
+				<slot name="footer{{index}}"></slot>
+				<!-- #endif -->
+			</view>
+			<view class="giveGoods">
+				<view class="item acea-row row-between-wrapper" v-for="(item,index) in giveCartInfo" :key="item.id">
+					<view class="picTxt acea-row row-middle">
+						<view class="pictrue">
+							<image :src="item.productInfo.attrInfo.image" v-if="item.productInfo.attrInfo"></image>
+							<image :src="item.productInfo.image" v-else></image>
+						</view>
+						<view class="texts">
+							<view class="name line1">[赠品]{{item.productInfo.store_name}}</view>
+							<view class="limit line1" v-if="item.productInfo.attrInfo">{{item.productInfo.attrInfo.suk}}</view>
+						</view>
+					</view>
+					<view class="num">x{{item.cart_num}}</view>
+				</view>
+				<view class="item acea-row row-between-wrapper" v-for="(item,index) in giveData.give_coupon" :key="item.id" v-if="giveData.give_coupon.length">
+					<view class="picTxt acea-row row-middle">
+						<view class="pictrue acea-row row-center-wrapper">
+							<text class="iconfont icon-pc-youhuiquan"></text>
+						</view>
+						<view class="texts">
+							<view class="line1">[赠品]{{item.coupon_title}}</view>
+						</view>
+					</view>
+				</view>
+				<view class="item acea-row row-between-wrapper" v-if="giveData.give_integral>0">
+					<view class="picTxt acea-row row-middle">
+						<view class="pictrue acea-row row-center-wrapper">
+							<text class="iconfont icon-pc-jifen"></text>
+						</view>
+						<view class="texts">
+							<view class="line1">[赠品]{{giveData.give_integral}}积分</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="more-operation" v-if="split && refund_status === 0" @click="changeOperation">
+				{{operationModel?'关闭':'更多操作'}}
+			</view>
+			<transition name="fade" mode="out-in" v-if="split && operationModel && refund_status === 0">
+				<!-- #ifdef MP -->
+				<view>
+					<view class="more-operation b-top" @click="openSubcribe">
+						申请退款
+					</view>
+				</view>
+				<!-- #endif -->
+				<!-- #ifndef MP -->
+				<navigator hover-class="none" :url="'/pages/goods/goods_return/index?orderId='+ orderId"
+					class='more-operation b-top'>申请退款
+				</navigator>
+				<!-- #endif -->
+			</transition>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		openOrderRefundSubscribe
+	} from '@/utils/SubscribeMessage.js';
+	export default {
+		props: {
+			productType:{
+				type: Number,
+				default: 0,
+			},
+			product_type:{
+				type: Number,
+				default: 0,
+			},
+			evaluate: {
+				type: Number,
+				default: 0,
+			},
+			paid: {
+				type: Number,
+				default: 0
+			},
+			// 订单状态
+			statusType: {
+				type: Number,
+				default: 0,
+			},
+			// 配送方式
+			deliveryType: {
+				type: Number,
+				default: 0,
+			},
+			// 送货方式
+			sendType: {
+				type: String,
+				default: '',
+			},
+			cartInfo: {
+				type: Array,
+				default: function() {
+					return [];
+				}
+			},
+			giveData:{
+				type:Object,
+				default: function() {
+					return [];
+				}
+			},
+			giveCartInfo:{
+				type: Array,
+				default: function() {
+					return [];
+				}
+			},
+			orderId: {
+				type: String,
+				default: '',
+			},
+			delivery_type: {
+				type: String,
+				default: '',
+			},
+			shippingType: {
+				type: Number,
+				default: 0,
+			},
+			id:{
+				type: Number,
+				default: 0,
+			},
+			oid:{
+				type: Number,
+				default: 0,
+			},
+			jump: {
+				type: Boolean,
+				default: false,
+			},
+			split: {
+				type: Boolean,
+				default: false,
+			},
+			jumpDetail: {
+				type: Boolean,
+				default: false,
+			},
+			index: {
+				type: Number,
+				default: 0,
+			},
+			pid: {
+				type: Number,
+				default: 0,
+			},
+			refund_status: {
+				type: Number,
+				default: -1,
+			},
+			status_type: {
+				type: Number,
+				default: 0,
+			}
+		},
+		data() {
+			return {
+				totalNmu: '',
+				operationModel: false,
+				status: ""
+			};
+		},
+		watch: {
+			cartInfo: function(nVal, oVal) {
+				let num = 0
+				nVal.forEach((item, index) => {
+					num += item.cart_num
+				})
+				this.totalNmu = num
+			}
+		},
+		methods: {
+			evaluateTap: function(unique, orderId) {
+				uni.navigateTo({
+					url: "/pages/goods/goods_comment_con/index?unique=" + unique + "&uni=" + orderId
+				})
+			},
+			jumpCon: function(id) {
+				if (this.jump) {
+					uni.navigateTo({
+						url: `/pages/goods_details/index?id=${id}`
+					})
+				} else if (this.jumpDetail) {
+					uni.navigateTo({
+						url: `/pages/goods/order_details/index?order_id=${this.orderId}`
+					})
+				}
+			},
+			logistics(order_id) {
+				uni.navigateTo({
+					url: '/pages/goods/goods_logistics/index?orderId=' + order_id
+				})
+			},
+			confirmOrder(orderId) {
+				this.$emit('confirmOrder', orderId)
+			},
+			changeOperation() {
+				this.operationModel = !this.operationModel
+			},
+			openSubcribe: function(item,productType) {
+				let cartIds = [
+						{
+							cart_id:item.id,
+							cart_num:parseInt(item.cart_num) - parseInt(item.refund_num)
+						}
+				]
+				cartIds = JSON.stringify(cartIds);
+				let page = `/pages/goods/goods_return/index?orderId=`+this.orderId+ '&id=' + this.oid+ '&cartIds='+ cartIds+'&productType='+this.productType;
+				// #ifdef MP
+				uni.showLoading({
+					title: '正在加载',
+				})
+				openOrderRefundSubscribe().then(res => {
+					uni.hideLoading();
+					uni.navigateTo({
+						url: page,
+					});
+				}).catch(() => {
+					uni.hideLoading();
+				});
+				// #endif
+				// #ifndef MP
+				uni.navigateTo({
+					url: page
+				})
+				// #endif
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.giveGoods{
+		.item{
+			padding: 14rpx 30rpx 14rpx 0;
+			margin-left: 30rpx;
+			border-bottom: 1px solid #eee;
+			.picTxt{
+				.pictrue{
+					width: 76rpx;
+					height: 76rpx;
+					border-radius: 6rpx;
+					background-color: #F5F5F5;
+					color: var(--view-theme);
+					.iconfont{
+						font-size: 34rpx;
+					}
+					image{
+						width: 100%;
+						height: 100%;
+						border-radius: 6rpx;
+					}
+					margin-right: 16rpx;
+				}
+				.texts{
+					width: 360rpx;
+					color: #999999;
+					font-size: 20rpx;
+					.name{
+						color: #333;
+					}
+					.limit{
+						font-size: 20rpx;
+						margin-top: 4rpx;
+					}
+				}
+			}
+			.num{
+				color: #999999;
+				font-size: 20rpx;
+			}
+		}
+	}
+	.goodWrapper .list .button{
+		margin-bottom: 16rpx;
+		.bnt{
+			font-size: 24rpx;
+			color: #666;
+			width: 140rpx;
+			height: 48rpx;
+			border-radius: 23rpx;
+			border: 1rpx solid #CCCCCC;
+			margin-left: 20rpx;
+		}
+	}
+	.goodWrapper .item .text .posBnt{
+		position: absolute;
+		right: 0;
+		bottom: -5rpx
+	}
+	.goodWrapper .item .text .refund{
+		font-size: 24rpx;
+		color: #E93323;
+		margin-left: 20rpx;
+	}
+	.goodWrapper .item .text .writeOff{
+		border: 0;
+		width: unset;
+		font-size: 20rpx;
+		color: #1890FF;
+	}
+	.goodWrapper .item .text .writeOff .on{
+		color: #999;
+	}
+	.fontcolor {
+		color: var(--view-theme);
+	}
+
+	.orderGoods {
+		background-color: #fff;
+		margin-top: 12rpx;
+		&.on{
+			margin-top: 0;
+		}
+	}
+
+	.orderGoods .total {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		width: 100%;
+		// height: 86rpx;
+		padding: 0 30rpx;
+		border-bottom: 2rpx solid #f0f0f0;
+		font-size: 30rpx;
+		color: #282828;
+		line-height: 86rpx;
+		box-sizing: border-box;
+
+		.rig-btn {
+			display: flex;
+			align-items: center;
+
+			.refund {
+				font-size: 26rpx;
+				color: var(--view-theme);
+			}
+
+			.done {
+				font-size: 26rpx;
+				color: #F19D2F;
+			}
+		}
+
+		.logistics {
+			// height: 46rpx;
+			line-height: 30rpx;
+			color: #999999;
+			font-size: 20rpx;
+			border: 1px solid;
+			border-radius: 30rpx;
+			padding: 6rpx 12rpx;
+			margin-left: 10rpx;
+		}
+
+		.sure {
+			color: var(--view-theme);
+			border: 1px solid var(--view-theme);
+		}
+	}
+
+	.more-operation {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		padding: 10rpx 0;
+		color: #bbb;
+	}
+
+	.b-top {
+		margin-left: 30rpx;
+		margin-right: 30rpx;
+		border-top: 1px solid #f0f0f0
+	}
+
+	.fade-enter-active,
+	.fade-leave-active {
+		transition: all 0.1s;
+	}
+
+	.fade-enter,
+	.fade-leave-to
+
+	/* .fade-leave-active below version 2.1.8 */
+		{
+		opacity: 0;
+		transform: translateY(-10px);
+	}
+
+	.op {
+		opacity: 0.5;
+	}
+
+	.pic {
+		display: flex;
+		justify-content: space-between;
+	}
+
+	.valid {
+		font-size: 24rpx;
+	}
+</style>

+ 149 - 0
components/pageFooter/index.vue

@@ -0,0 +1,149 @@
+<template>
+	<!-- 底部导航 -->
+	<view v-if="newData.status && newData.status.status">
+		<view v-if="newData.bgColor">
+			<view class="page-footer" id="target" :style="{'background-color':newData.bgColor.color[0].item}">
+				<view class="foot-item" v-for="(item,index) in newData.menuList" :key="index" @click="goRouter(item)">
+					<block v-if="item.link.split('?')[0] == activeRouter">
+						<image :src="item.imgList[0]"></image>
+						<view class="txt" :style="{color:newData.activeTxtColor.color[0].item}">{{item.name}}</view>
+					</block>
+					<block v-else>
+						<image :src="item.imgList[1]"></image>
+						<view class="txt" :style="{color:newData.txtColor.color[0].item}">{{item.name}}</view>
+					</block>
+					<div class="count-num"
+						v-if="item.link === '/pages/order_addcart/order_addcart' && cartNum>0">
+						{{cartNum}}
+					</div>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapGetters
+	} from "vuex"
+	import {
+		getNavigation
+	} from '@/api/public.js'
+	import {
+		getCartCounts,
+	} from '@/api/order.js';
+	export default {
+		name: 'pageFooter',
+		props: {},
+		computed: mapGetters(['isLogin', 'cartNum']),
+		created() {
+			let routes = getCurrentPages(); //获取当前打开过的页面路由数组
+			let curRoute = routes[routes.length - 1].route //获取当前页面路由
+			this.activeRouter = '/' + curRoute
+		},
+		mounted() {
+			this.navigationInfo();
+			if (this.isLogin) {
+				this.getCartNum()
+			}
+		},
+		data() {
+			return {
+				newData: {},
+				activeRouter:''
+			}
+		},
+		methods: {
+			navigationInfo(){
+				getNavigation().then(res => {
+					this.newData = res.data
+					this.$emit('newDataStatus', this.newData.status?this.newData.status.status:false)
+					if (this.newData.status && this.newData.status.status) {
+						uni.hideTabBar()
+					} else {
+						uni.showTabBar()
+					}
+				})
+			},
+			goRouter(item) {
+				var pages = getCurrentPages();
+				var page = (pages[pages.length - 1]).$page.fullPath;
+				if (item.link == page) return
+				uni.switchTab({
+					url: item.link,
+					fail(err) {
+						uni.redirectTo({
+							url: item.link
+						})
+					}
+				})
+			},
+			getCartNum: function() {
+				let id = uni.getStorageSync('user_store_id') || 0;
+				getCartCounts(0,id).then(res => {
+					this.$store.commit('indexData/setCartNum', res.data.count > 99 ? '..' : res.data.count + '')
+				});
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.page-footer {
+		position: fixed;
+		bottom: 0;
+		z-index: 666;
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		width: 100%;
+		height: calc(98rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		height: calc(98rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		box-sizing: border-box;
+		border-top: solid 1rpx #F3F3F3;
+		background-color: #fff;
+		box-shadow: 0px 0px 17rpx 1rpx rgba(206, 206, 206, 0.32);
+		padding-bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/
+		padding-bottom: env(safe-area-inset-bottom); ///兼容 IOS>11.2/
+
+		.foot-item {
+			display: flex;
+			width: max-content;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+			position: relative;
+
+			.count-num {
+				position: absolute;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				width: 40rpx;
+				height: 40rpx;
+				top: 0rpx;
+				right: -15rpx;
+				color: #fff;
+				font-size: 20rpx;
+				background-color: #FD502F;
+				border-radius: 50%;
+				padding: 4rpx;
+			}
+		}
+
+		.foot-item image {
+			height: 50rpx;
+			width: 50rpx;
+			text-align: center;
+			margin: 0 auto;
+		}
+
+		.foot-item .txt {
+			font-size: 24rpx;
+
+
+			&.active {}
+		}
+	}
+</style>

+ 472 - 0
components/payment/index.vue

@@ -0,0 +1,472 @@
+<template>
+	<!-- 支付弹窗 -->
+	<view :style="colorStyle">
+		<view class="payment" :class="pay_close ? 'on' : ''">
+			<view class="title acea-row row-center-wrapper">
+				选择付款方式<text class="iconfont icon-guanbi" @click='close'></text>
+			</view>
+			<view class="item acea-row row-between-wrapper" v-for="(item,index) in payMode" :key="index"
+				v-if='item.payStatus' @click="payType(item.number || 0 , item.value,index)">
+				<view class="left acea-row row-between-wrapper">
+					<view class="iconfont" :class="item.icon"></view>
+					<view class="text">
+						<view class="name">{{item.name}}</view>
+						<view class="info" v-if="item.value == 'yue'">
+							{{item.title}} <span class="money">¥{{ item.number }}</span>
+						</view>
+						<view class="info" v-else>{{item.title}}</view>
+					</view>
+				</view>
+				<view class="iconfont" :class="active==index?'icon-xuanzhong11 font-num':'icon-weixuan'"></view>
+			</view>
+			<view class="payMoney">支付<span class="font-color">¥<span class="money">{{totalPrice}}</span></span></view>
+			<view class="button bg-color acea-row row-center-wrapper" @click='goPay(number, paytype)'>去付款</view>
+			<slot name="buttom"></slot>
+		</view>
+		<view class="mask" @click='close' v-if="pay_close"></view>
+		<view v-show="false" v-html="formContent"></view>
+	</view>
+</template>
+
+<script>
+	import {
+		orderPay
+	} from '@/api/order.js';
+	import colors from '@/mixins/color.js';
+	export default {
+		props: {
+			payMode: {
+				type: Array,
+				default: function() {
+					return [];
+				}
+			},
+			pay_close: {
+				type: Boolean,
+				default: false,
+			},
+			order_id: {
+				type: String,
+				default: ''
+			},
+			totalPrice: {
+				type: String,
+				default: '0'
+			},
+			isCall: {
+				type: Boolean,
+				default: false
+			}
+		},
+		mixins:[colors],
+		data() {
+			return {
+				formContent: '',
+				active: 0,
+				paytype: '',
+				number: 0
+			};
+		},
+		watch: {
+			payMode: {
+				handler(newV, oldValue) {
+					let newPayList = [];
+					newV.forEach((item, index) => {
+						if (item.payStatus) {
+							item.index = index;
+							newPayList.push(item)
+						}
+					});
+					this.active = newPayList[0].index;
+					this.paytype = newPayList[0].value;
+					this.number = newPayList[0].number || 0;
+				},
+				immediate: true,
+				deep: true
+			}
+		},
+		methods: {
+			payType(number, paytype, index) {
+				this.active = index;
+				console.log(this.active,'this.active');
+				this.paytype = paytype;
+				this.number = number;
+				this.$emit('changePayType', paytype)
+			},
+			close: function() {
+				this.$emit('onChangeFun', {
+					action: 'payClose'
+				});
+			},
+			goPay: function(number, paytype) {
+				if (this.isCall) {
+					return this.$emit('onChangeFun', {
+						action: 'payCheck',
+						value: paytype
+					});
+				}
+				let that = this;
+				if (!that.order_id) return that.$util.Tips({
+					title: '请选择要支付的订单'
+				});
+				if (paytype == 'yue' && parseFloat(number) < parseFloat(that.totalPrice)) return that.$util.Tips({
+					title: '余额不足!'
+				});
+				uni.showLoading({
+					title: '支付中'
+				});
+
+				orderPay({
+					uni: that.order_id,
+					paytype: paytype,
+					// #ifdef MP 
+					'from': 'routine',
+					// #endif
+					// #ifdef H5
+					'from': this.$wechat.isWeixin() ? 'weixin' : 'weixinh5',
+					// #endif
+					// #ifdef H5
+					quitUrl: location.port ? location.protocol + '//' + location.hostname + ':' + location
+						.port +
+						'/pages/goods/order_details/index?order_id=' + this.order_id : location.protocol +
+						'//' + location.hostname +
+						'/pages/goods/order_details/index?order_id=' + this.order_id
+					// #endif
+					// #ifdef APP-PLUS
+					quitUrl: '/pages/goods/order_details/index?order_id=' + this.order_id
+					// #endif
+				}).then(res => {
+					let jsConfig = res.data.result.jsConfig;
+					switch (paytype) {
+						case 'weixin':
+							if (res.data.result === undefined) return that.$util.Tips({
+								title: '缺少支付参数'
+							});
+
+							// #ifdef MP
+							let mp_pay_name=''
+							if(uni.requestOrderPayment){
+								mp_pay_name='requestOrderPayment'
+							}else{
+								mp_pay_name='requestPayment'
+							}
+							uni[mp_pay_name]({
+								timeStamp: jsConfig.timestamp,
+								nonceStr: jsConfig.nonceStr,
+								package: jsConfig.package,
+								signType: jsConfig.signType,
+								paySign: jsConfig.paySign,
+								success: function(res) {
+									uni.hideLoading();
+									return that.$util.Tips({
+										title: res.msg,
+										icon: 'success'
+									}, () => {
+										that.$emit('onChangeFun', {
+											action: 'pay_complete'
+										});
+									});
+								},
+								fail: function(e) {
+									uni.hideLoading();
+									return that.$util.Tips({
+										title: '取消支付'
+									}, () => {
+										that.$emit('onChangeFun', {
+											action: 'pay_fail'
+										});
+									});
+								},
+								complete: function(e) {
+									uni.hideLoading();
+									if (e.errMsg == 'requestPayment:cancel') return that.$util
+										.Tips({
+											title: '取消支付'
+										}, () => {
+											that.$emit('onChangeFun', {
+												action: 'pay_fail'
+											});
+										});
+								},
+							});
+							// #endif
+							// #ifdef H5
+							let data = res.data;
+							if (data.status == "WECHAT_H5_PAY") {
+								uni.hideLoading();
+								location.replace(data.result.jsConfig.mweb_url);
+								return that.$util.Tips({
+									title: "支付成功",
+									icon: 'success'
+								}, () => {
+									that.$emit('onChangeFun', {
+										action: 'pay_complete'
+									});
+								});
+							} else {
+								that.$wechat.pay(data.result.jsConfig)
+									.then(() => {
+										return that.$util.Tips({
+											title: "支付成功",
+											icon: 'success'
+										}, () => {
+											that.$emit('onChangeFun', {
+												action: 'pay_complete'
+											});
+										});
+									})
+									.catch(function(res) {
+										if (res.errMsg == 'chooseWXPay:cancel') return that.$util.Tips({
+											title: '取消支付'
+										},() => {
+											that.$emit('onChangeFun', {
+												action: 'pay_fail'
+											});
+										});
+									});
+							}
+							// #endif
+							// #ifdef APP-PLUS
+							uni.requestPayment({
+								provider: 'wxpay',
+								orderInfo: jsConfig,
+								success: (e) => {
+									let url = '/pages/goods/order_pay_status/index?order_id=' + orderId +
+										'&msg=支付成功';
+									uni.showToast({
+										title: "支付成功"
+									})
+									setTimeout(res => {
+										that.$emit('onChangeFun', {
+											action: 'pay_complete'
+										});
+									}, 2000)
+								},
+								fail: (e) => {
+									uni.showModal({
+										content: "支付失败",
+										showCancel: false,
+										success: function(res) {
+											if (res.confirm) {
+												that.$emit('onChangeFun', {
+													action: 'pay_fail'
+												});
+											} else if (res.cancel) {}
+										}
+									})
+								},
+								complete: () => {
+									uni.hideLoading();
+								},
+							});
+							// #endif
+							break;
+						case 'yue':
+							uni.hideLoading();
+							return that.$util.Tips({
+								title: res.msg,
+								icon: 'success'
+							}, () => {
+								that.$emit('onChangeFun', {
+									action: 'pay_complete'
+								});
+							});
+							break;
+						case 'offline':
+							uni.hideLoading();
+							return that.$util.Tips({
+								title: res.msg,
+								icon: 'success'
+							}, () => {
+								that.$emit('onChangeFun', {
+									action: 'pay_complete'
+								});
+							});
+							break;
+						case 'alipay':
+							uni.hideLoading();
+							//#ifdef H5
+							if (this.$wechat.isWeixin()) {
+								uni.redirectTo({
+									url: `/pages/users/alipay_invoke/index?id=${res.data.result.order_id}&pay_key=${res.data.result.pay_key}`
+								});
+							} else {
+								uni.hideLoading();
+								that.formContent = res.data.result.jsConfig;
+								that.$nextTick(() => {
+									document.getElementById('alipaysubmit').submit();
+								});
+							}
+							//#endif
+							// #ifdef MP
+							uni.navigateTo({
+								url: `/pages/users/alipay_invoke/index?id=${res.data.result.order_id}&link=${res.data.result.jsConfig.qrCode}`
+							});
+							// #endif
+							// #ifdef APP-PLUS
+							uni.requestPayment({
+								provider: 'alipay',
+								orderInfo: jsConfig,
+								success: (e) => {
+									uni.showToast({
+										title: "支付成功"
+									})
+									setTimeout(res => {
+										that.$emit('onChangeFun', {
+											action: 'pay_complete'
+										});
+									}, 2000)
+
+								},
+								fail: (e) => {
+									uni.showModal({
+										content: "支付失败",
+										showCancel: false,
+										success: function(res) {
+											if (res.confirm) {
+												that.$emit('onChangeFun', {
+													action: 'pay_fail'
+												});
+											} else if (res.cancel) {}
+										}
+									})
+								},
+								complete: () => {
+									uni.hideLoading();
+								},
+							});
+							// #endif
+							break;
+					}
+				}).catch(err => {
+					uni.hideLoading();
+					return that.$util.Tips({
+						title: err
+					}, () => {
+						that.$emit('onChangeFun', {
+							action: 'pay_fail'
+						});
+					});
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.bgcolor{
+		background-color: var(--view-theme)
+	}
+	.payment {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		width: 100%;
+		border-radius: 16rpx 16rpx 0 0;
+		background-color: #fff;
+		padding-bottom: 60rpx;
+		z-index: 999;
+		transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
+		transform: translate3d(0, 100%, 0);
+
+		.payMoney {
+			font-size: 28rpx;
+			color: #333333;
+			text-align: center;
+			margin-top: 50rpx;
+
+			.font-color {
+				margin-left: 10rpx;
+
+				.money {
+					font-size: 40rpx;
+				}
+			}
+		}
+
+		.button {
+			width: 690rpx;
+			height: 90rpx;
+			border-radius: 45rpx;
+			color: #FFFFFF;
+			margin: 20rpx auto 0 auto;
+		}
+	}
+
+	.payment.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.payment .title {
+		text-align: center;
+		height: 123rpx;
+		font-size: 32rpx;
+		color: #282828;
+		font-weight: bold;
+		padding-right: 30rpx;
+		margin-left: 30rpx;
+		position: relative;
+		border-bottom: 1rpx solid #eee;
+	}
+
+	.payment .title .iconfont {
+		position: absolute;
+		right: 30rpx;
+		top: 50%;
+		transform: translateY(-50%);
+		font-size: 38rpx;
+		color: #8a8a8a;
+		font-weight: normal;
+	}
+
+	.payment .item {
+		border-bottom: 1rpx solid #eee;
+		height: 130rpx;
+		margin-left: 30rpx;
+		padding-right: 30rpx;
+	}
+
+	.payment .item .left {
+		width: 610rpx;
+	}
+
+	.payment .item .left .text {
+		width: 540rpx;
+	}
+
+	.payment .item .left .text .name {
+		font-size: 32rpx;
+		color: #282828;
+	}
+
+	.payment .item .left .text .info {
+		font-size: 24rpx;
+		color: #999;
+	}
+
+	.payment .item .left .text .info .money {
+		color: #ff9900;
+	}
+
+	.payment .item .left .iconfont {
+		font-size: 45rpx;
+		color: #09bb07;
+	}
+
+	.payment .item .left .iconfont.icon-zhifubao {
+		color: #00aaea;
+	}
+
+	.payment .item .left .iconfont.icon-yuezhifu {
+		color: #ff9900;
+	}
+
+	.payment .item .left .iconfont.icon-yuezhifu1 {
+		color: #eb6623;
+	}
+
+	.payment .item .iconfont {
+		font-size: 40rpx;
+		color: #ccc;
+	}
+</style>

+ 186 - 0
components/productConSwiper/index.vue

@@ -0,0 +1,186 @@
+<template>
+	<!-- 商品详情轮播图 -->
+	<view class='product-bg'>
+		<swiper :indicator-dots="indicatorDots" indicator-active-color="var(--view-theme)" :autoplay="autoplay" :circular="circular"
+		 :interval="interval" :duration="duration" @change="change" v-if="isPlay">
+		 <!-- #ifndef APP-PLUS -->
+			<swiper-item v-if="videoline">
+				<view class="item">
+					<view v-show="!controls" class="item-box">
+						<video id="myVideo" :src='videoline' objectFit="cover" controls style="width:100%;height:100% "
+						 show-center-play-btn show-mute-btn="true" auto-pause-if-navigate :custom-cache="false" :enable-progress-gesture="false" :poster="imgUrls[0]" @pause="videoPause"></video>
+					</view>
+					<view class="poster" v-show="controls">
+						<image class="image" :src="imgUrls[0]"></image>
+					</view>
+					<view class="stop" v-show="controls" @tap="bindPause">
+						<image class="image" src="../../static/images/stop.png"></image>
+					</view>
+				</view>
+			</swiper-item>
+			<!-- #endif -->
+			<!-- #ifdef APP-PLUS -->
+			<swiper-item v-if="videoline">
+				<view class="item">
+					<view class="poster" v-show="controls">
+						<image class="image" :src="imgUrls[0]"></image>
+					</view>
+					<view class="stop" v-show="controls" @tap="bindPause">
+						<image class="image" src="../../static/images/stop.png"></image>
+					</view>
+				</view>
+			</swiper-item>
+			<!-- #endif -->
+			<block v-for="(item,index) in imgUrls" :key='index'>
+				<swiper-item v-if="videoline?index>=1:index>=0">
+					<image :src="item" class="slide-image" />
+				</swiper-item>
+			</block>
+		</swiper>
+		<!-- #ifdef APP-PLUS -->
+		<view v-if="!isPlay" style="width: 100%; height: 750rpx;">
+			<video id="myVideo" :src='videoline' objectFit="cover" controls style="width:100%;height:100% "
+			 show-center-play-btn show-mute-btn="true" autoplay="true" auto-pause-if-navigate :custom-cache="false" :enable-progress-gesture="false" :poster="imgUrls[0]" @pause="videoPause"></video>
+		</view>
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			imgUrls: {
+				type: Array,
+				default: function() {
+					return [];
+				}
+			},
+			videoline: {
+				type: String,
+				value: ""
+			}
+		},
+		data() {
+			return {
+				indicatorDots: true,
+				circular: true,
+				autoplay: true,
+				interval: 3000,
+				duration: 500,
+				currents: "1",
+				controls: true,
+				isPlay:true,
+				videoContext:''
+			};
+		},
+		mounted() {
+			if(this.videoline){
+				this.imgUrls.shift()
+			}
+			// #ifndef APP-PLUS
+			this.videoContext = uni.createVideoContext('myVideo', this);
+			// #endif
+		},
+		methods: {
+			videoPause(e){
+				// #ifdef APP-PLUS
+				this.isPlay= true
+				this.autoplay = true
+				// #endif
+			},
+			bindPause: function() {
+				
+				// #ifndef APP-PLUS
+				this.videoContext.play();
+				this.$set(this, 'controls', false)
+				this.autoplay = false
+				// #endif
+				// #ifdef APP-PLUS
+				this.isPlay= false
+				this.videoContext = uni.createVideoContext('myVideo', this);
+				this.videoContext.play();
+				// #endif
+			},
+			change: function(e) {
+				this.$set(this, 'currents', e.detail.current + 1);
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss"> 
+  .item-box {
+    width:100%;
+    height:100% 
+  }
+	.product-bg {
+		width: 100%;
+		height: 750rpx;
+		position: relative;
+	}
+
+	.product-bg swiper {
+		width: 100%;
+		height: 100%;
+		position: relative;
+	}
+
+	.product-bg .slide-image {
+		width: 100%;
+		height: 100%;
+	}
+
+	.product-bg .pages {
+		position: absolute;
+		background-color: #fff;
+		height: 34rpx;
+		padding: 0 10rpx;
+		border-radius: 3rpx;
+		right: 30rpx;
+		bottom: 30rpx;
+		line-height: 34rpx;
+		font-size: 24rpx;
+		color: #050505;
+	}
+
+	#myVideo {
+		width: 100%;
+		height: 100%
+	}
+
+	.product-bg .item {
+		position: relative;
+		width: 100%;
+		height: 100%;
+	}
+
+	.product-bg .item .poster {
+		position: absolute;
+		top: 0;
+		left: 0;
+		height: 750rpx;
+		width: 100%;
+		z-index: 9;
+	}
+
+	.product-bg .item .poster .image {
+		width: 100%;
+		height: 100%;
+	}
+
+	.product-bg .item .stop {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		width: 136rpx;
+		height: 136rpx;
+		margin-top: -68rpx;
+		margin-left: -68rpx;
+		z-index: 9;
+	}
+
+	.product-bg .item .stop .image {
+		width: 100%;
+		height: 100%;
+	}
+</style>

+ 781 - 0
components/productWindow/index.vue

@@ -0,0 +1,781 @@
+<template>
+	<!-- 商品属性规格弹窗 -->
+	<view>
+		<view class="product-window"
+			:class="(attr.cartAttr === true ? 'on' : '') + ' ' + (iSbnt?'join':'') + ' ' + (iScart?'joinCart':'')">
+			<view class="textpic acea-row row-between-wrapper">
+				<view class="pictrue" @click="showImg()">
+					<image :src="attr.productSelect.image"></image>
+					<view class="icon acea-row row-center-wrapper" v-if="cusPreviewImg">
+						<view class="iconfont icon-fangda1"></view>
+					</view>
+				</view>
+				<view class="text">
+					<view class="line1">
+						{{ type == 'setMeal'?title : attr.productSelect.store_name }}
+					</view>
+					<view class="money font-color">
+						<view class="acea-row row-middle">
+							<text v-if="type != 'points'">¥</text><text class="num">{{ attr.productSelect.price }}</text><text v-if="type == 'points'" class="num">积分</text>
+							<text class='vip-money'
+								v-if="is_vip>0 && attr.productSelect.vip_price && storeInfo && storeInfo.price_type == 'member'">¥{{attr.productSelect.vip_price}}</text>
+							<view class="vipImg" v-if="is_vip>0 && attr.productSelect.vip_price && storeInfo && storeInfo.price_type == 'member'">
+								<image src="../../static/images/vip.png"></image>
+							</view>
+							
+							<view class="icon" v-if="is_vip>0 && attr.productSelect.vip_price && storeInfo && storeInfo.price_type == 'level'"><text class="iconfont icon-dengjitubiao"></text>{{storeInfo.level_name}}</view>
+							
+						</view>
+						<text class="stock" v-if='isShow'>库存: {{ attr.productSelect.stock }}</text>
+						<text class='stock' v-if="limitNum">{{type == 'seckill' ? '限量' : type == 'points'?'剩余':'库存'}}: {{attr.productSelect.quota}}</text>
+						<slot name="bottom" :attr="attr"></slot>
+					</view>
+				</view>
+				<view class="iconfont icon-guanbi" @click="closeAttr"></view>
+			</view>
+			<view class="rollTop">
+				<view class="productWinList">
+					<view class="item" v-for="(item, indexw) in attr.productAttr" :key="indexw">
+						<view class="title">{{ item.attr_name }}</view>
+						<view class="listn acea-row row-middle">
+							<view class="itemn" :class="item.index === itemn.attr ? 'on' : ''"
+								v-for="(itemn, indexn) in item.attr_value" @click="tapAttr(indexw, indexn)"
+								:key="indexn">
+								{{ itemn.attr }}
+							</view>
+						</view>
+					</view>
+					<view class="item" v-if="isDelivery">
+						 <view class="title">配送方式</view>
+						 <view class="listn acea-row row-middle">
+							 <view class="itemn" v-if="attr.deliveryType.includes('1')" @click="getstoreInfo('1')" :class="flag==1?'on':''">商城配送</view>
+							 <view class="itemn" v-if="attr.deliveryType.includes('2') && attr.store_self_mention && selfStoreList.length" @click="getstoreInfo('2')" :class="flag==2?'on':''">门店自提</view>
+							 <view class="itemn" v-if="attr.deliveryType.includes('3') && storeList.length" @click="getstoreInfo('3')" :class="flag==3?'on':''">门店配送</view>
+						 </view>
+					</view>
+					<view class="address acea-row row-middle" v-if="flag ==1 && isDelivery" @click="openAddress">
+						<view class="adsInfo">{{addressInfo}}</view>
+						<view class="iconfont icon-gengduo3"></view>
+					</view>
+					<view class="address acea-row row-middle" v-if="flag ==3 && isDelivery" @click="openStore">
+						<view class="adsInfo">{{deliveryName}}{{deliveryAddress}}{{distance}}</view>
+						<view class="iconfont icon-gengduo3" v-if="attr.isType == 0"></view>
+					</view>
+					<view class="address" v-if="flag ==2 && isDelivery"  @click="openStore">
+						<view>{{deliveryName}}</view>
+						<view class="info acea-row row-between-wrapper">
+							<view class="con">{{deliveryAddress}}</view>
+							<view>{{distance}}<text class="iconfont icon-gengduo3" v-if="attr.isType == 0"></text></view>
+						</view>
+					</view>
+				</view>
+				<view class="cart acea-row row-between-wrapper" v-if="type != 'setMeal'">
+				  <view class="title">数量</view>
+					<view class="carnum acea-row row-left">
+						<view class="item reduce acea-row row-center-wrapper"
+							:class="attr.productSelect.cart_num <= 1 ? 'on' : ''" v-if="attr.productSelect.cart_num <= 1">
+							<text class="iconfont icon-shangpinshuliang-jian"></text>
+						</view>
+						<view class="item reduce acea-row row-center-wrapper"
+							:class="attr.productSelect.cart_num <= 1 ? 'on' : ''" @click="CartNumDes" v-else>
+							<text class="iconfont icon-shangpinshuliang-jian"></text>
+						</view>
+						<view class='item num acea-row row-middle'>
+							<input type="number" v-model="attr.productSelect.cart_num"
+								data-name="productSelect.cart_num"
+								@input="bindCode(attr.productSelect.cart_num)"></input>
+						</view>
+						<view v-if="iSplus" class="item plus acea-row row-center-wrapper" :class="
+				      attr.productSelect.cart_num >= attr.productSelect.stock
+				        ? 'on'
+				        : ''
+				    " @click="CartNumAdd">
+							<text class="iconfont icon-shangpinshuliang-jia"></text>
+						</view>
+						<view v-else class='item plus'
+							:class='(attr.productSelect.cart_num >= attr.productSelect.quota) || (attr.productSelect.cart_num >= attr.productSelect.product_stock) || (attr.productSelect.cart_num >= attr.productSelect.num) || (type=="seckill" && attr.productSelect.cart_num >= attr.productSelect.once_num)? "on":""'
+							@click='CartNumAdd'>+</view>
+					</view>
+				</view>
+			</view>
+			<view class="joinBnt bg-color"
+				v-if="iSbnt && attr.productSelect.product_stock>0 &&attr.productSelect.quota>0" @click="goCat">我要参团
+			</view>
+			<view class="joinBnt on"
+				v-else-if="(iSbnt && attr.productSelect.quota<=0)||(iSbnt &&attr.productSelect.product_stock<=0)">已售罄
+			</view>
+			<view class="joinBnt bg-color" v-if="iScart && attr.productSelect.stock" @click="goCat">确定</view>
+			<view class="joinBnt on" v-else-if="iScart && !attr.productSelect.stock">已售罄</view>
+		</view>
+		<!-- 选择门店 -->
+    <view class="product-window" :class="isStore?'store':''">
+			<view class="storeTitle">选择门店<text class="iconfont icon-guanbi5" @click="closeStore"></text></view>
+			<view class="storeList">
+				<view class="item" :class="active == index?'on':''" v-for="(item,index) in storeList" :key="index" @click="tapStore(index,item)">
+					<view class="name line1">{{item.name}}</view>
+					<view class="address acea-row row-between">
+						<view class="iconfont icon-dingwei2"></view>
+						<view class="info">{{item.address}}</view>
+					</view>
+					<view class="time acea-row row-middle">
+						<view class="iconfont icon-yingyeshijian2"></view>
+						<view>营业时间:{{item.day_time}}</view>
+					</view>
+					<view class="iconfont icon-xuanzhong6" v-if="active == index"></view>
+				</view>
+			</view>
+    </view>
+    <addressWindow ref="addressWindow" :pagesUrl="pagesUrl" :fromType="1" :address="address" @changeClose="changeClose" @OnChangeAddress="OnChangeAddress">
+    </addressWindow>
+		<view class="mask" @touchmove.prevent :hidden="attr.cartAttr === false" @click="closeAttr"></view>
+		<view class="mask on" @touchmove.prevent :hidden="isStore === false" @click="closeStore"></view>
+	</view>
+</template>
+
+<script>
+  import addressWindow from '@/components/addressWindow';
+  import {getAddressList} from '@/api/user.js'
+  import {storeListApi} from '@/api/store.js'
+	import {
+		mapGetters
+	} from 'vuex';
+	export default {
+		computed: mapGetters(['isLogin']),
+    components:{
+      addressWindow
+    },
+		props: {
+			cusPreviewImg: {
+				type: Number,
+				value: 0
+			},
+			title: {
+				type: String,
+				default: ''
+			},
+			attr: {
+				type: Object,
+				default: () => {}
+			},
+			storeInfo: {
+				type: Object,
+				default: () => {}
+			},
+			limitNum: {
+				type: Number,
+				value: 0
+			},
+			isShow: {
+				type: Number,
+				value: 0
+			},
+			iSbnt: {
+				type: Number,
+				value: 0
+			},
+			iSplus: {
+				type: Number,
+				value: 0
+			},
+			iScart: {
+				type: Number,
+				value: 0
+			},
+			is_vip: {
+				type: Number,
+				value: 0
+			},
+			type: {
+				type: String,
+				default: ''
+			},
+		},
+		data() {
+			return {
+        flag:1,
+        addressInfo:'', // 商城快递
+        deliveryName:'', // 门店配送
+				distance:'',
+				deliveryAddress:'',
+				address: {
+					address: false
+				},
+				pagesUrl:'',
+			 user_latitude: 0,
+			 user_longitude: 0,
+			 isDelivery: false,
+			 storeList: [],
+			 deliveryStoreList: [],
+			 selfStoreList: [],
+			 active:0,
+			 isStore: false
+      }
+		},
+    
+		mounted() {
+		 try {
+		 	this.user_latitude = uni.getStorageSync('user_latitude');
+		 	this.user_longitude = uni.getStorageSync('user_longitude');
+		 } catch (e) {}
+    },
+		watch: {
+			'attr.deliveryType': {
+				handler(newV) {
+					if(newV){
+						if(this.active<1){
+							if (this.user_latitude && this.user_longitude) {
+								this.getList();
+							} else {
+								this.selfLocation();
+							}
+						}
+						this.flag = newV[0];
+						this.$emit('deliveryFun',newV[0]);
+					}
+				},
+				deep: true
+			}
+		},
+		methods: {
+			closeStore(){
+				this.isStore = false;
+			},
+			openStore(){
+				if(this.attr.isType == 0){
+					this.isStore = true;
+				}
+			},
+			// 切换门店
+				tapStore(index,item){
+					this.active = index;
+					this.deliveryName = item.name;
+					this.deliveryAddress = item.detailed_address+'\xa0';
+					this.distance = '距您'+item.range+'km';
+					this.isStore = false;
+					this.$emit('onstoreId',item);
+				},
+				// 切换地址
+				OnChangeAddress: function(e,row) {
+				  this.address.address = false;
+					this.addressInfo = row.province+'省'+'\xa0'+row.city+'\xa0'+row.district+'\xa0'+row.street+'\xa0'+row.detail
+					this.$emit('onAddressId',row)
+				},
+				// 打开弹窗
+			openAddress(){
+				this.$refs.addressWindow.getAddressList();
+				this.address.address = true;
+				this.pagesUrl = '/pages/users/user_address/index'
+			},
+			goCat: function() {
+				this.$emit('goCat');
+			},
+      // 配送地址
+      getAddressList() {
+        getAddressList({
+					page: 1,
+					limit: 1
+				}).then(res=>{
+					let data = res.data[0];
+					if(res.data.length){
+						 this.addressInfo = data.province+'省'+'\xa0'+data.city+'\xa0'+data.district+'\xa0'+data.street+'\xa0'+data.detail
+						 this.$emit('onAddressId',data)
+					}else{
+						this.addressInfo = '点击添加地址'
+					}
+        })
+      },
+			// 关闭地址弹窗;
+			changeClose: function() {
+			  this.$set(this.address, 'address', false);
+			},
+			selfLocation() {
+				let self = this
+				// #ifdef H5
+				if (self.$wechat.isWeixin()) {
+					self.$wechat.location().then(res => {
+						this.user_latitude = res.latitude;
+						this.user_longitude = res.longitude;
+						uni.setStorageSync('user_latitude', res.latitude);
+						uni.setStorageSync('user_longitude', res.longitude);
+						self.getList();
+					})
+				} else {
+					// #endif	
+					uni.getLocation({
+						type: 'wgs84',
+						success: (res) => {
+							try {
+								this.user_latitude = res.latitude;
+								this.user_longitude = res.longitude;
+								uni.setStorageSync('user_latitude', res.latitude);
+								uni.setStorageSync('user_longitude', res.longitude);
+							} catch {}
+							self.getList();
+						},
+						complete: function() {
+							self.getList();
+						}
+					});
+					// #ifdef H5	
+				}
+				// #endif
+			},
+			getList: function() {
+				let data = {
+					latitude: this.user_latitude || "", //纬度
+					longitude: this.user_longitude || "", //经度
+					page: 1,
+					limit: 100,
+					product_id: this.storeInfo ? this.storeInfo.id : '',
+					is_store:''   //查找所有门店列表
+				};
+				storeListApi(data)
+					.then(res => {
+						let list = res.data.list.list;
+						if(list.length && this.attr && ((this.attr.deliveryType.indexOf('2') != -1 && this.attr.store_self_mention) || this.attr.deliveryType.indexOf('3') != -1)){
+							this.isDelivery = true;
+							if(this.isLogin){
+								this.getAddressList()
+							}
+						}
+						// 拆分自提门店列表和配送门店列表
+						let selfStoreList = [];
+						list.forEach(function(item,index){
+							if(item.is_store === 1) selfStoreList.push(item);
+						});
+						this.storeList = this.flag==2?selfStoreList:list;
+						this.selfStoreList = selfStoreList;//门店自提
+						this.deliveryStoreList = list;//门店配送
+						this.active = 0;
+						this.deliveryName = list[0].name;
+						this.deliveryAddress = list[0].detailed_address+'\xa0';
+						this.distance = '距您'+list[0].range+'km';
+						this.$emit('onstoreId',list[0]);
+					})
+					.catch(err => {
+						this.$util.Tips({
+							title: err
+						})
+					});
+			},
+			/**
+			 * 购物车手动输入数量
+			 * 
+			 */
+			bindCode: function(e) {
+				this.$emit('iptCartNum', this.attr.productSelect.cart_num);
+			},
+			closeAttr: function() {
+				this.$emit('myevent');
+			},
+			CartNumDes: function() {
+				this.$emit('ChangeCartNum', false);
+			},
+			CartNumAdd: function() {
+				this.$emit('ChangeCartNum', true);
+			},
+			tapAttr: function(indexw, indexn) {
+				let that = this;
+				that.$emit("attrVal", {
+					indexw: indexw,
+					indexn: indexn
+				});
+				this.$set(this.attr.productAttr[indexw], 'index', this.attr.productAttr[indexw].attr_values[indexn]);
+				let value = that
+					.getCheckedValue()
+					.join(",");
+				that.$emit("ChangeAttr", value);
+
+			},
+			//获取被选中属性;
+			getCheckedValue: function() {
+				let productAttr = this.attr.productAttr;
+				let value = [];
+				for (let i = 0; i < productAttr.length; i++) {
+					for (let j = 0; j < productAttr[i].attr_values.length; j++) {
+						if (productAttr[i].index === productAttr[i].attr_values[j]) {
+							value.push(productAttr[i].attr_values[j]);
+						}
+					}
+				}
+				return value;
+			},
+      // 选择配送方式
+      getstoreInfo(index) {
+				if(index === '2') this.storeList = this.selfStoreList; //门店自提
+				if(index === '3') this.storeList = this.deliveryStoreList; //门店配送
+        this.flag = index;
+				this.active = 0;
+				this.deliveryName = this.storeList[0].name;
+				this.deliveryAddress = this.storeList[0].detailed_address+'\xa0';
+				this.distance = '距您'+this.storeList[0].range+'km';
+				this.$emit('deliveryFun',index);
+				if(index === '2' || index === '3'){
+					this.$emit('onstoreId',this.storeList[0]);
+				}
+      },
+			showImg() {
+				this.$emit('getImg');
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.mask.on{
+		z-index: 100 !important;
+	}
+	.product-window{
+		 .productWinList{
+			 .address{
+				 width: 690rpx;
+				 background: #F5F5F5;
+				 padding: 30rpx 24rpx;
+				 margin: 0 auto;
+				 margin-top: 20rpx;
+				 font-weight: 400;
+				 color: #333333;
+				 font-size: 26rpx;
+				 border-radius: 10rpx;
+				 .adsInfo{
+					 max-width: 594rpx;
+				 }
+				 .iconfont{
+					 font-size: 18rpx;
+					 margin-left: 12rpx;
+				 }
+				 .info{
+					 font-weight: 400;
+					 color: #999999;
+					 margin-top: 12rpx;
+					 .con{
+						 width: 416rpx;
+					 }
+				 }
+			 }
+		 }
+	}
+  .active {
+    position: relative;
+    border: 1px solid var(--view-theme);
+    .icon-xuanzhong6 {
+      font-size: 46rpx;
+      position: absolute;
+      bottom: -4rpx;
+      right: -6rpx;
+      color: var(--view-theme);
+    }
+  }
+	.vip-money {
+		color: #282828;
+		font-size: 28rpx;
+		font-weight: 700;
+		margin-left: 6rpx;
+	}
+	.vipImg {
+		width: 56rpx;
+		height: 20rpx;
+		margin-left: 6rpx;
+
+		image {
+			width: 100%;
+			height: 100%;
+			display: block;
+		}
+	}
+	
+	.product-window{
+		&.store{
+			background-color: #F5F5F5;
+			border-radius: 20rpx 20rpx 0 0;
+			transform: translate3d(0, 0, 0);
+			z-index: 102;
+			margin: 0;
+		}
+		.storeTitle{
+			text-align: center;
+			height: 100rpx;
+			line-height: 100rpx;
+			font-size: 32rpx;
+			font-weight: 500;
+			color: #282828;
+			position: relative;
+			.iconfont{
+				position: absolute;
+				font-size: 35rpx;
+				right: 30rpx;
+			}
+		}
+		.storeList{
+			max-height: 690rpx;
+			overflow: auto;
+			.item{
+				width: 690rpx;
+				background: #FFFFFF;
+				border-radius: 12rpx;
+				margin: 0 auto 20rpx auto;
+				padding: 28rpx 30rpx;
+				border: 1px solid #fff;
+				position: relative;
+				&.on{
+					border-color: var(--view-theme);
+				}
+				.icon-xuanzhong6{
+					position: absolute;
+					right: -6rpx;
+					bottom: -6rpx;
+					color: var(--view-theme);
+					font-size: 54rpx;
+				}
+				.name{
+					font-weight: 500;
+					color: #333333;
+					font-size: 28rpx;
+				}
+				.time{
+					font-weight: 400;
+					color: #888888;
+					font-size: 22rpx;
+					margin-top: 15rpx;
+					.iconfont{
+						font-size: 20rpx;
+						margin-right: 8rpx;
+					}
+				}
+				.address{
+					font-weight: 400;
+					color: #888888;
+					font-size: 22rpx;
+					margin-top: 13rpx;
+					.iconfont{
+						font-size: 20rpx;
+						margin-right: 8rpx;
+						margin-top: 6rpx;
+					}
+					.info{
+						width: 590rpx;
+						line-height: 1.5;
+					}
+				}
+			}
+		}
+	}
+
+	.product-window {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		background-color: #fff;
+		z-index: 100;
+		border-radius: 16rpx 16rpx 0 0;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		padding-bottom: 140rpx;
+		padding-bottom: calc(140rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(140rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+	}
+
+	.product-window.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.product-window.join {
+		padding-bottom: 30rpx;
+	}
+
+	.product-window.joinCart {
+		padding-bottom: 30rpx;
+		z-index: 10000;
+	}
+
+	.product-window .textpic {
+		padding: 0 130rpx 0 30rpx;
+		margin-top: 29rpx;
+		position: relative;
+	}
+
+	.product-window .textpic .pictrue {
+		width: 150rpx;
+		height: 150rpx;
+		position: relative;
+		.icon{
+			width: 30rpx;
+			height: 30rpx;
+			background-color: rgba(0,0,0,0.4);
+			border-radius: 4rpx;
+			position: absolute;
+			bottom: 8rpx;
+			right: 8rpx;
+			text-align: center;
+			line-height: 23rpx;
+			.iconfont{
+				color: #fff;
+				font-size: 20rpx;
+			}
+		}
+	}
+
+	.product-window .textpic .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 10rpx;
+	}
+
+	.product-window .textpic .text {
+		width: 410rpx;
+		font-size: 32rpx;
+		color: #202020;
+	}
+
+	.product-window .textpic .text .money {
+		font-size: 24rpx;
+		margin-top: 40rpx;
+		.icon{
+			display: inline-block;
+			font-size: 16rpx;
+			font-weight: normal;
+			background: #FF9500;
+      color: #fff;
+			border-radius: 18rpx;
+			padding: 2rpx 6rpx;
+			margin-left: 10rpx;
+			.iconfont{
+				font-size: 16rpx;
+				margin-right: 4rpx;
+				color: #fff;
+			}
+		}
+	}
+
+	.product-window .textpic .text .money .num {
+		font-size: 36rpx;
+	}
+
+	.product-window .textpic .text .money .stock {
+		color: #999;
+		margin-left: 6rpx;
+	}
+
+	.product-window .textpic .icon-guanbi {
+		position: absolute;
+		right: 30rpx;
+		top: -5rpx;
+		font-size: 35rpx;
+		color: #8a8a8a;
+	}
+
+	.product-window .rollTop {
+		max-height: 535rpx;
+		overflow: auto;
+		margin-top: 36rpx;
+	}
+
+	.product-window .productWinList .item~.item {
+		margin-top: 36rpx;
+	}
+
+	.product-window .productWinList .item .title {
+		font-size: 30rpx;
+		color: #999;
+		padding: 0 30rpx;
+	}
+
+	.product-window .productWinList .item .listn {
+		padding: 0 30rpx 0 16rpx;
+	}
+
+	.product-window .productWinList .item .listn .itemn {
+		border: 1px solid #F2F2F2;
+		font-size: 26rpx;
+		color: #282828;
+		padding: 7rpx 33rpx;
+		border-radius: 25rpx;
+		margin: 20rpx 0 0 14rpx;
+		background-color: #F2F2F2;
+		word-break: break-all;
+	}
+
+	.product-window .productWinList .item .listn .itemn.on {
+		color: var(--view-theme);
+		background: var(--view-minorColorT);
+		border-color: var(--view-theme);
+	}
+	.product-window .productWinList .item .listn .itemn.limit {
+		color: #999;
+		text-decoration: line-through;
+	}
+
+	.product-window .cart {
+		margin-top: 36rpx;
+		padding: 0 30rpx;
+    
+	}
+	.product-window .cart .title {
+		font-size: 30rpx;
+		color: #999;
+	}
+
+	.product-window .cart .carnum {
+		height: 54rpx;
+		margin-top: 24rpx;
+	}
+
+	.product-window .cart .carnum .iconfont {
+		font-size: 25rpx;
+	}
+
+	.product-window .cart .carnum view {
+		// border: 1px solid #a4a4a4;
+		width: 84rpx;
+		text-align: center;
+		height: 100%;
+		line-height: 54rpx;
+		color: #282828;
+		font-size: 45rpx;
+	}
+
+	.product-window .cart .carnum .reduce {
+		border-right: 0;
+		border-radius: 6rpx 0 0 6rpx;
+		line-height: 48rpx;
+		font-size: 60rpx;
+	}
+
+	.product-window .cart .carnum .reduce.on {
+		color: #DEDEDE;
+	}
+
+	.product-window .cart .carnum .plus {
+		border-left: 0;
+		border-radius: 0 6rpx 6rpx 0;
+		line-height: 46rpx;
+	}
+
+	.product-window .cart .carnum .plus.on {
+		// border-color: #e3e3e3;
+		color: #dedede;
+	}
+
+	.product-window .cart .carnum .num {
+		background: rgba(242, 242, 242, 1);
+		color: #282828;
+		font-size: 28rpx;
+	}
+
+	.product-window .joinBnt {
+		font-size: 30rpx;
+		width: 620rpx;
+		height: 86rpx;
+		border-radius: 50rpx;
+		text-align: center;
+		line-height: 86rpx;
+		color: #fff;
+		margin: 21rpx auto 0 auto;
+	}
+
+	.product-window .joinBnt.on {
+		background-color: #bbb;
+		color: #fff;
+	}
+</style>

+ 121 - 0
components/recommend/index.vue

@@ -0,0 +1,121 @@
+<template>
+	<!-- 热门推荐 -->
+	<view class='recommend' :style="colorStyle">
+		<view class='title acea-row row-center-wrapper'>
+			<text class='iconfont icon-zhuangshixian'></text>
+			<text class='name'>热门推荐</text>
+			<text class='iconfont icon-zhuangshixian lefticon'></text>
+		</view>
+		<view class='recommendList acea-row row-between-wrapper'>
+			<view class='item' v-for="(item,index) in hostProduct" :key="index" hover-class='none' @tap="goDetail(item)">
+				<view class='pictrue'>
+					<image :src='item.image' mode="aspectFill"></image>
+					<span class="pictrue_log_big pictrue_log_class" v-if="item.activity && item.activity.type === '1'">秒杀</span>
+					<span class="pictrue_log_big pictrue_log_class" v-if="item.activity && item.activity.type === '2'">砍价</span>
+					<span class="pictrue_log_big pictrue_log_class" v-if="item.activity && item.activity.type === '3'">拼团</span>
+				</view>
+				<view class='name line1'>{{item.store_name}}</view>
+				<!-- #ifdef H5 || APP-PLUS -->
+				<slot name="center" :item="item"></slot>
+				<!-- #endif -->
+				<!-- #ifdef MP -->
+				<slot name="center{{index}}"></slot>
+				<!-- #endif -->
+				<view class='money font-color'>¥<text class='num'>{{item.price}}</text></view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {mapGetters} from "vuex";
+	import { goShopDetail } from '@/libs/order.js'
+	import colors from "@/mixins/color";
+	export default {
+	computed: mapGetters(['uid']),
+		props: {
+			hostProduct: {
+				type: Array,
+				default: function() {
+					return [];
+				}
+			}
+		},
+		mixins: [colors],
+		data() {
+			return {
+
+			};
+		},
+		methods: {
+			goDetail(item){
+				goShopDetail(item,this.uid).then(res=>{
+					uni.navigateTo({
+						url:`/pages/goods_details/index?id=${item.id}`
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.recommend {
+		background-color: #fff;
+	}
+
+	.recommend .title {
+		height: 135rpx;
+		font-size: 28rpx;
+		color: #282828;
+	}
+
+	.recommend .title .name {
+		margin: 0 28rpx;
+	}
+
+	.recommend .title .iconfont {
+		font-size: 170rpx;
+		color: #454545;
+	}
+
+	.recommend .title .iconfont.lefticon {
+		transform: rotate(180deg);
+	}
+
+	.recommend .recommendList {
+		padding: 0 30rpx;
+	}
+
+	.recommend .recommendList .item {
+		width: 335rpx;
+		margin-bottom: 30rpx;
+	}
+
+	.recommend .recommendList .item .pictrue {
+		position: relative;
+		width: 100%;
+		height: 335rpx;
+	}
+
+	.recommend .recommendList .item .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 20rpx;
+	}
+
+	.recommend .recommendList .item .name {
+		font-size: 28rpx;
+		color: #282828;
+		margin-top: 20rpx;
+	}
+
+	.recommend .recommendList .item .money {
+		font-size: 20rpx;
+		margin-top: 8rpx;
+	}
+
+	.recommend .recommendList .item .money .num {
+		font-size: 28rpx;
+	}
+</style>

+ 198 - 0
components/skeleton/index.vue

@@ -0,0 +1,198 @@
+<template>
+	<view v-if="show"
+		:style="{width: systemInfo.width + 'px', height: systemInfo.height + 'px', backgroundColor: bgcolor, position: 'absolute', left: 0, top: 0, zIndex: 9998}">
+		<view v-for="(item,rect_idx) in skeletonRectLists" :key="item.rect"
+			:class="[loading == 'chiaroscuro' ? 'chiaroscuro' : '']"
+			:style="{width: item.width + 'px', height: item.height + 'px', backgroundColor: 'rgb(194, 207, 214,.3)', position: 'absolute', left: item.left + 'px', top: item.top + 'px'}">
+		</view>
+		<view v-for="(item,circle_idx) in skeletonCircleLists" :key="item.circle"
+			:class="loading == 'chiaroscuro' ? 'chiaroscuro' : ''"
+			:style="{width: item.width + 'px', height: item.height + 'px', backgroundColor: 'rgb(194, 207, 214,.3)', borderRadius: item.width + 'px', position: 'absolute', left: item.left + 'px', top: item.top + 'px'}">
+		</view>
+		<view class="spinbox" v-if="loading == 'spin'">
+			<view class="spin"></view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "skeleton",
+		props: {
+			bgcolor: {
+				type: String,
+				value: '#FFF'
+			},
+			selector: {
+				type: String,
+				value: 'skeleton'
+			},
+			loading: {
+				type: String,
+				value: 'spin'
+			},
+			show: {
+				type: Boolean,
+				value: false
+			},
+			isNodes: {
+				type: Number,
+				value: false
+			} //控制什么时候开始抓取元素节点,只要数值改变就重新抓取
+		},
+		data() {
+			return {
+				loadingAni: ['spin', 'chiaroscuro'],
+				systemInfo: {},
+				skeletonRectLists: [],
+				skeletonCircleLists: []
+			}
+		},
+		watch: {
+			isNodes(val) {
+				this.readyAction();
+			}
+		},
+		mounted() {
+			this.attachedAction();
+		},
+		methods: {
+			attachedAction: function() {
+				//默认的首屏宽高,防止内容闪现
+				const systemInfo = uni.getSystemInfoSync();
+				this.systemInfo = {
+					width: systemInfo.windowWidth,
+					height: systemInfo.windowHeight
+				};
+				this.loading = this.loadingAni.includes(this.loading) ? this.loading : 'spin';
+			},
+			readyAction: function() {
+				const that = this;
+				//绘制背景
+				uni.createSelectorQuery().selectAll(`.${this.selector}`).boundingClientRect().exec(function(res) {
+					if(res[0].length>0)
+					that.systemInfo.height = res[0][0].height + res[0][0].top;
+				});
+
+				//绘制矩形
+				this.rectHandle();
+
+				//绘制圆形
+				this.radiusHandle();
+			},
+			rectHandle: function() {
+				const that = this;
+
+				//绘制不带样式的节点
+				uni.createSelectorQuery().selectAll(`.${this.selector}-rect`).boundingClientRect().exec(function(res) {
+					let obj = res[0];
+					obj.forEach((item,index)=>{
+						item.rect = 'rect'+index
+					})
+					that.skeletonRectLists = obj;
+				});
+
+			},
+			radiusHandle() {
+				const that = this;
+
+				uni.createSelectorQuery().selectAll(`.${this.selector}-radius`).boundingClientRect().exec(function(res) {
+					let obj = res[0];
+					obj.forEach((item,index)=>{
+						item.circle = 'circle'+index
+					})
+					that.skeletonCircleLists = obj;
+				});
+			}
+		}
+	}
+</script>
+
+<style>
+	.spinbox {
+		position: fixed;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		height: 100%;
+		width: 100%;
+		z-index: 9999
+	}
+
+	.spin {
+		display: inline-block;
+		width: 64rpx;
+		height: 64rpx;
+	}
+
+	.spin:after {
+		content: " ";
+		display: block;
+		width: 46rpx;
+		height: 46rpx;
+		margin: 1rpx;
+		border-radius: 50%;
+		border: 5rpx solid #409eff;
+		border-color: #409eff transparent #409eff transparent;
+		animation: spin 1.2s linear infinite;
+	}
+
+	@keyframes spin {
+		0% {
+			transform: rotate(0deg);
+		}
+
+		100% {
+			transform: rotate(360deg);
+		}
+	}
+
+	.chiaroscuro {
+		width: 100%;
+		height: 100%;
+		background: rgb(194, 207, 214);
+		animation-duration: 2s;
+		animation-name: blink;
+		animation-iteration-count: infinite;
+	}
+
+	@keyframes blink {
+		0% {
+			opacity: .4;
+		}
+
+		50% {
+			opacity: 1;
+		}
+
+		100% {
+			opacity: .4;
+		}
+	}
+
+	@keyframes flush {
+		0% {
+			left: -100%;
+		}
+
+		50% {
+			left: 0;
+		}
+
+		100% {
+			left: 100%;
+		}
+	}
+
+	.shine {
+		animation: flush 2s linear infinite;
+		position: absolute;
+		top: 0;
+		bottom: 0;
+		width: 100%;
+		background: linear-gradient(to left,
+				rgba(255, 255, 255, 0) 0%,
+				rgba(255, 255, 255, .85) 50%,
+				rgba(255, 255, 255, 0) 100%)
+	}
+</style>

+ 246 - 0
components/splitOrder/index.vue

@@ -0,0 +1,246 @@
+<template>
+	<!-- 拆单订单 -->
+	<view class='splitOrder' v-if="splitGoods.length">
+		<view class="all" v-if="select_all">
+			<checkbox-group @change="checkboxAllChange">
+				<checkbox value="all" :checked="isAllSelect" />
+				<text class='checkAll'>全选</text>
+			</checkbox-group>
+		</view>
+		<checkbox-group @change="checkboxChange">
+			<block v-for="(item,index) in splitGoods" :key="index">
+				<view class='items acea-row row-between-wrapper'>
+					<!-- #ifndef MP -->
+					<checkbox :value="(item.id).toString()" :checked="item.checked" />
+					<!-- #endif -->
+					<!-- #ifdef MP -->
+					<checkbox :value="item.id" :checked="item.checked"/>
+					<!-- #endif -->
+					<view class='picTxt acea-row row-between-wrapper'>
+						<view class='pictrue'>
+							<image :src='item.cart_info.productInfo.image'></image>
+						</view>
+						<view class='text'>
+							<view class="acea-row row-between-wrapper">
+								<view class='name line1'>{{item.cart_info.productInfo.store_name}}</view>
+								<view>×{{item.cart_num}}</view>
+							</view>
+							<view class='infor line1'>
+								属性:{{item.cart_info.productInfo.attrInfo.suk || '默认'}}</view>
+							<view class='money'>¥{{item.cart_info.truePrice}}</view>
+						</view>
+						<view class='carnum acea-row row-center-wrapper'>
+							<view class="reduce" :class="item.surplus_num == 1 ? 'on' : ''"
+								@click.stop='subCart(item)'>-</view>
+							<view class='num'>{{item.surplus_num}}</view>
+							<view class="plus" :class="item.surplus_num == item.numShow ? 'on' : ''"
+								@click.stop='addCart(item)'>+</view>
+						</view>
+					</view>
+				</view>
+			</block>
+		</checkbox-group>
+	</view>
+</template>
+
+<script>
+	export default {
+		props:{
+			splitGoods: {
+				type: Array,
+				default: () => []
+			},
+			select_all: {
+				type: Boolean,
+				default: true
+			}
+		},
+		data() {
+			return {
+				isAllSelect:false
+			};
+		},
+		mounted(){
+			
+		},
+		methods: {
+			subCart(item){
+				item.surplus_num = Number(item.surplus_num) - 1;
+				if(item.surplus_num<=1){
+					item.surplus_num = 1
+				}
+				this.$emit('getList',this.splitGoods);
+			},
+			addCart(item){
+				item.surplus_num = Number(item.surplus_num) + 1;
+				if(item.surplus_num>=item.numShow){
+					item.surplus_num = item.numShow
+				}
+				this.$emit('getList',this.splitGoods);
+			},
+			inArray: function(search, array) {
+				for (let i in array) {
+					if (array[i] == search) {
+						return true;
+					}
+				}
+				return false;
+			},
+			checkboxChange(event){
+				let idList = event.detail.value;
+				this.splitGoods.forEach((item)=>{
+					if(this.inArray(item.id, idList)){
+						item.checked = true;
+					}else{
+						item.checked = false;
+					}
+				})
+				this.$emit('getList',this.splitGoods);
+				if(idList.length == this.splitGoods.length){
+					this.isAllSelect = true;
+				}else{
+					this.isAllSelect = false;
+				}
+			},
+			forGoods(val){
+				let that = this;
+				if(!that.splitGoods.length) return
+				that.splitGoods.forEach((item)=>{
+					if(val){
+						item.checked = true;
+					}else{
+						item.checked = false;
+					}
+				})
+				that.$emit('getList',that.splitGoods);
+			},
+			checkboxAllChange(event){
+				let value = event.detail.value;
+				if(value.length){
+					this.forGoods(1)
+				}else{
+					this.forGoods(0)
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	
+	.splitOrder {
+		border-bottom: 1px solid #f0f0f0;
+	}
+	
+	.splitOrder .all{
+		padding: 20rpx 30rpx;
+	}
+	
+	.splitOrder .all .checkAll{
+		margin-left: 20rpx;
+	}
+	
+	.splitOrder .items {
+		padding: 25rpx 30rpx;
+		background-color: #fff;
+		margin-bottom: 15rpx;
+	}
+	
+	.splitOrder .items .picTxt {
+		width: 627rpx;
+		position: relative;
+	}
+	
+	.splitOrder .items .picTxt .name{
+		width: 360rpx;
+	}
+	
+	.splitOrder .items .picTxt .pictrue {
+		width: 160rpx;
+		height: 160rpx;
+	}
+	
+	.splitOrder .items .picTxt .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 6rpx;
+	}
+	
+	.splitOrder .items .picTxt .text {
+		width: 444rpx;
+		font-size: 28rpx;
+		color: #282828;
+	}
+	
+	.splitOrder .items .picTxt .text .reColor {
+		color: #999;
+	}
+	
+	.splitOrder .items .picTxt .text .reElection {
+		margin-top: 20rpx;
+	}
+	
+	.splitOrder .items .picTxt .text .reElection .title {
+		font-size: 24rpx;
+	}
+	
+	.splitOrder .items .picTxt .text .reElection .reBnt {
+		width: 120rpx;
+		height: 46rpx;
+		border-radius: 23rpx;
+		font-size: 26rpx;
+	}
+	
+	.splitOrder .items .picTxt .text .infor {
+		font-size: 24rpx;
+		color: #868686;
+		margin-top: 16rpx;
+	}
+	
+	.splitOrder .items .picTxt .text .money {
+		font-size: 32rpx;
+		color: #282828;
+		margin-top: 28rpx;
+	}
+	
+	.splitOrder .items .picTxt .carnum {
+		height: 47rpx;
+		position: absolute;
+		bottom: 7rpx;
+		right: 0;
+	}
+	
+	.splitOrder .items .picTxt .carnum view {
+		border: 1rpx solid #a4a4a4;
+		width: 66rpx;
+		text-align: center;
+		height: 100%;
+		line-height: 40rpx;
+		font-size: 28rpx;
+		color: #a4a4a4;
+	}
+	
+	.splitOrder .items .picTxt .carnum .reduce {
+		border-right: 0;
+		border-radius: 3rpx 0 0 3rpx;
+	}
+	
+	.splitOrder .items .picTxt .carnum .reduce.on {
+		border-color: #e3e3e3;
+		color: #dedede;
+	}
+	
+	.splitOrder .items .picTxt .carnum .plus {
+		border-left: 0;
+		border-radius: 0 3rpx 3rpx 0;
+	}
+	
+	.splitOrder .items .picTxt .carnum .plus.on {
+		border-color: #e3e3e3;
+		color: #dedede;
+	}
+	
+	.splitOrder .items .picTxt .carnum .num {
+		color: #282828;
+	}
+</style>

+ 197 - 0
components/storeLis/index.vue

@@ -0,0 +1,197 @@
+<template>
+	<!-- 门店列表 -->
+	<view class="list">
+		<view class="item" v-for="(item, index) in storeList" :key="index" v-if="index<num">
+			<view class="name line1"><text class="iconfont icon-shangjiadingdan"></text>{{item.name}}</view>
+			<view class="address line1"><text class="font-num" v-if="item.range">距您{{ item.range }}km</text><text class="spot" v-if="item.range">·</text>{{ item.address }}{{ ", " + item.detailed_address }}</view>
+			<!-- #ifdef H5 || APP-PLUS -->
+			<slot name="bottom" :item="item"></slot>
+			<!-- #endif -->
+			<!-- #ifdef MP -->
+			<slot name="bottom{{index}}"></slot>
+			<!-- #endif -->
+		</view>
+	</view>
+</template>
+<script>
+	import {
+		storeListApi
+	} from "@/api/store";
+	import {
+		isWeixin
+	} from "@/utils/index";
+	// #ifdef H5
+	import {
+		wechatEvevt,
+		wxShowLocation
+	} from "@/libs/wechat";
+	// #endif
+	import {
+		mapGetters
+	} from "vuex";
+	const LONGITUDE = "user_longitude";
+	const LATITUDE = "user_latitude";
+	const MAPKEY = "mapKey";
+	export default {
+		name: "storeList",
+		props: {
+			num : {
+				type: Number,
+				default: 1,
+			},
+			ids: {
+				type: Number,
+				default: 0,
+			}
+		},
+		data() {
+			return {
+				page: 1,
+				limit: 20,
+				loaded: false,
+				loading: false,
+				storeList: [],
+				system_store: {},
+				user_latitude: 0,
+				user_longitude: 0
+			};
+		},
+		created() {
+			try {
+				this.user_latitude = uni.getStorageSync('user_latitude');
+				this.user_longitude = uni.getStorageSync('user_longitude');
+			} catch (e) {}
+		},
+		mounted() {
+			// if (this.user_latitude && this.user_longitude) {
+			// 	this.getList();
+			// } else {
+			// 	this.selfLocation();
+			// }
+			this.selfLocation();
+			if(!this.$util.checkOpenGPSServiceByAndroidIOS()){
+				this.getList();
+			}
+		},
+		methods: {
+			call(phone) {
+				uni.makePhoneCall({
+					phoneNumber: phone,
+				});
+			},
+			selfLocation() {
+				let self = this
+				// #ifdef H5
+				if (self.$wechat.isWeixin()) {
+					self.$wechat.location().then(res => {
+						this.user_latitude = res.latitude;
+						this.user_longitude = res.longitude;
+						uni.setStorageSync('user_latitude', res.latitude);
+						uni.setStorageSync('user_longitude', res.longitude);
+						self.getList();
+					}).catch(err=>{
+						self.getList();
+					})
+				} else {
+					// #endif	
+					uni.getLocation({
+						type: 'wgs84',
+						success: (res) => {
+							try {
+								this.user_latitude = res.latitude;
+								this.user_longitude = res.longitude;
+								uni.setStorageSync('user_latitude', res.latitude);
+								uni.setStorageSync('user_longitude', res.longitude);
+							} catch {}
+							self.getList();
+						},
+						complete: function() {
+							self.getList();
+						}
+					});
+					// #ifdef H5	
+				}
+				// #endif
+			},
+			showMaoLocation(e) {
+				let self = this;
+				// #ifdef H5
+				if (self.$wechat.isWeixin()) {
+					self.$wechat.seeLocation({
+						latitude: Number(e.latitude),
+						longitude: Number(e.longitude),
+						name: e.name,
+						address: `${e.address}-${e.detailed_address}`,
+					}).then(res => {
+					})
+				} else {
+					// #endif	
+					uni.openLocation({
+						latitude: Number(e.latitude),
+						longitude: Number(e.longitude),
+						name: e.name,
+						address: `${e.address}-${e.detailed_address}`,
+						success: function() {
+							Number
+						}
+					});
+					// #ifdef H5	
+				}
+				// #endif
+			},
+			// 获取门店列表数据
+			getList: function() {
+				if (this.loading || this.loaded) return;
+				this.loading = true;
+				let data = {
+					latitude: this.user_latitude || "", //纬度
+					longitude: this.user_longitude || "", //经度
+					page: this.page,
+					limit: this.limit,
+					product_id: this.ids
+				};
+				storeListApi(data)
+					.then(res => {
+						this.loading = false;
+						this.loaded = res.data.list.length < this.limit;
+						this.storeList.push.apply(this.storeList, res.data.list.list);
+						if(this.page == 1){
+							this.$emit('getStoreList',this.storeList.length)
+						}
+						this.page = this.page + 1;
+					})
+					.catch(err => {
+						this.$util.Tips({
+							title: err
+						})
+					});
+			}
+		},
+		onReachBottom() {
+			this.getList();
+		}
+	};
+</script>
+
+<style lang="scss">
+	.list{
+		width: 508rpx;
+		margin-left: 28rpx;
+		.item{
+			font-size: 26rpx;
+			color: #333;
+			.iconfont{
+				font-size: 30rpx;
+				margin-right: 10rpx;
+				color: #333;
+			}
+			.address{
+				font-size: 22rpx;
+				margin-top: 10rpx;
+				.spot{
+					margin: 0 20rpx;
+				}
+			}
+		}
+	}
+</style>

+ 181 - 0
components/thorui/tui-collapse.vue

@@ -0,0 +1,181 @@
+<template>
+	<view class="tui-collapse" :style="{backgroundColor:bgColor}">
+		<view class="tui-collapse-head" :style="{backgroundColor:hdBgColor}" @tap.stop="handleClick">
+			<view class="tui-header" :class="{'tui-opacity':disabled}">
+				<slot name="title"></slot>
+        <view class="open" v-if="!isOpen">
+          展开
+        </view> 
+         <view class="open" v-else>
+          收起
+        </view>
+				<view class="tui-collapse-icon tui-icon-arrow" :class="{'tui-icon-active':isOpen}" :style="{color:arrowColor}" v-if="arrow"></view>
+			</view>
+		</view>
+		<view class="tui-collapse-body_box" :style="{backgroundColor:bdBgColor,height:isOpen?height:'0rpx'}">
+			<view class="tui-collapse-body" :class="{'tui-collapse-transform':height=='auto','tui-collapse-body_show':isOpen && height=='auto'}">
+				<slot name="content"></slot>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "tuiCollapse",
+		emits: ['click'],
+		props: {
+			//collapse背景颜色
+			bgColor: {
+				type: String,
+				default: 'transparent'
+			},
+			//collapse-head 背景颜色
+			hdBgColor: {
+				type: String,
+				default: '#fff'
+			},
+			//collapse-body 背景颜色
+			bdBgColor: {
+				type: String,
+				default: 'transparent'
+			},
+			//collapse-body实际高度 open时使用
+			height: {
+				type: String,
+				default: 'auto'
+			},
+			//索引
+			index: {
+				type: Number,
+				default: 0
+			},
+			//当前索引,index==current时展开
+			current: {
+				type: Number,
+				default: -1
+			},
+			// 是否禁用
+			disabled: {
+				type: [Boolean, String],
+				default: false
+			},
+			//是否带箭头
+			arrow: {
+				type: [Boolean, String],
+				default: true
+			},
+			//箭头颜色
+			arrowColor: {
+				type: String,
+				default: "#666666"
+			}
+		},
+		watch: {
+			current() {
+				this.updateCurrentChange()
+			}
+		},
+		created() {
+			this.updateCurrentChange()
+		},
+		data() {
+			return {
+				isOpen: false
+			};
+		},
+		methods: {
+			updateCurrentChange() {
+				this.isOpen = this.index == this.current
+			},
+			handleClick() {
+				if (this.disabled) return;
+				this.$emit("click", {
+					index: Number(this.index)
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped>
+	@font-face {
+		font-family: 'tuiCollapse';
+		src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAQ4AA0AAAAABlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEHAAAABoAAAAciRx3B0dERUYAAAP8AAAAHgAAAB4AKQAKT1MvMgAAAaAAAABCAAAAVjxuR/JjbWFwAAAB9AAAAD4AAAFCAA/pq2dhc3AAAAP0AAAACAAAAAj//wADZ2x5ZgAAAkAAAABEAAAARCs1U/toZWFkAAABMAAAADAAAAA2FpaT+mhoZWEAAAFgAAAAHQAAACQHngOFaG10eAAAAeQAAAAPAAAAEAwAAEBsb2NhAAACNAAAAAoAAAAKACIAAG1heHAAAAGAAAAAHwAAACABDwAdbmFtZQAAAoQAAAFJAAACiCnmEVVwb3N0AAAD0AAAACMAAAA1DunpUnjaY2BkYGAAYja/oO54fpuvDNwsDCBwc4/6fzjtwNDNfICpBMjlYGACiQIAGVAKZnjaY2BkYGBu+N/AEMPCAALMBxgYGVABCwBVNgMsAAAAeNpjYGRgYGBhEGQA0QwMTEDMBYQMDP/BfAYACnYBLQB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ4xMDf8b2CIYW5gaAAKM4LkANq9C9sAAHjaY2GAABYIdgAAAMAATQB42mNgYGBmgGAZBkYGELAB8hjBfBYGBSDNAoRA/jOG//8hpBQzVCUDIxsDjMnAyAQkmBhQASPDsAcAMCAGoQAAAAAAAAAAAAAAIgAAAAEAQACLA8ACdAAQAAAlASYiBhQXARYyNwE2NCYiBwIA/oYNIBkMAZcNIA0BlwwZIA3uAXoMGSAN/mkMDAGXDSAZDAB42n2QPU4DMRCFn/MHJBJCIKhdUQDa/JQpEyn0CKWjSDbekGjXXnmdSDkBLRUHoOUYHIAbINFyCl6WSZMia+3o85uZ57EBnOMbCv/fJe6EFY7xKFzBETLhKvUX4Rr5XbiOFj6FG9R/hJu4VQPhFi7UGx1U7YS7m9JtywpnGAhXcIon4Sr1lXCN/CpcxxU+hBvUv4SbGONXuIVrZakM4WEwQWCcQWOKDeMCMRwskjIG1qE59GYSzExPN3oRO5s4GyjvV2KXAx5oOeeAKe09t2a+Sif+YMuB1JhuHgVLtimNLiJ0KBtfLJzV3ahzsP2e7ba02L9rgTXH7FENbNT8Pdsz0khsDK+QkjXyMrekElOPaGus8btnKdbzXgiJTrzL9IjHmjR1OvduaeLA4ufyjBx9tLmSPfeoHD5jWQh5v91OxCCKXYY/k9hxGQAAAHjaY2BigAAuMMnIgA5YwKJMjExciUVF+eW6KfnleQAZ0wQyAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAMAAQAEAAAAAgAAAAB42mNgYGBkAIKrS9Q5QPTNPer/YTQAQ+0HIAAA) format('woff');
+		font-weight: normal;
+		font-style: normal;
+	}
+
+	.tui-collapse-icon {
+		font-family: "tuiCollapse" !important;
+		font-style: normal;
+		-webkit-font-smoothing: antialiased;
+		-moz-osx-font-smoothing: grayscale;
+	}
+
+	.tui-icon-arrow:before {
+		content: "\e600";
+	}
+.open {
+  position: absolute;
+  top: 22rpx;
+  right: 50rpx;
+  font-size: 20rpx;
+  font-weight: 400;
+  color: #666666;
+	margin-right: 10rpx;
+}
+	.tui-icon-arrow {
+		font-size: 16rpx;
+		transform: rotate(0);
+		transform-origin: center center;
+		transition: all 0.3s;
+		position: absolute;
+		top: 50%;
+		margin-top: -8px;
+		right: 30rpx;
+	}
+
+	.tui-arrow-padding {
+		padding-right: 62rpx;
+		box-sizing: border-box;
+	}
+
+	.tui-icon-active {
+		transform: rotate(180deg);
+		transform-origin: center center;
+	}
+
+	.tui-header {
+		position: relative;
+		z-index: 2;
+	}
+   .tui-collapse-body_box{
+	   transition: all 0.25s;
+	   overflow: hidden;
+   }
+	.tui-collapse-body {
+		transition: all 0.25s;
+		overflow: hidden;
+		position: relative;
+		z-index: 1;
+	}
+
+	.tui-collapse-transform {
+		opacity: 0;
+		visibility: hidden;
+		-webkit-transform: translateY(-40%);
+		transform: translateY(-40%);
+	}
+
+	.tui-collapse-body_show {
+		opacity: 1;
+		visibility: visible;
+		-webkit-transform: translateY(0);
+		transform: translateY(0);
+	}
+
+	.tui-opacity {
+		opacity: 0.6;
+	}
+</style>

+ 140 - 0
components/thorui/tui-drawer.vue

@@ -0,0 +1,140 @@
+<template>
+	<!-- @touchmove.stop.prevent -->
+	<view>
+		<view v-if="mask" class="tui-drawer-mask" :class="{ 'tui-drawer-mask_show': visible }" :style="{ zIndex: maskZIndex }" @tap="handleMaskClick"></view>
+		<view
+			class="tui-drawer-container"
+			:class="[`tui-drawer-container_${mode}`, visible ? `tui-drawer-${mode}__show` : '']"
+			:style="{ zIndex: zIndex, backgroundColor: backgroundColor }"
+		>
+			<slot></slot>
+		</view>
+	</view>
+</template>
+
+<script>
+/**
+ * 超过一屏时插槽使用scroll-view
+ **/
+export default {
+	name: 'tuiDrawer',
+	emits: ['close'],
+	props: {
+		visible: {
+			type: Boolean,
+			default: false
+		},
+		mask: {
+			type: Boolean,
+			default: true
+		},
+		maskClosable: {
+			type: Boolean,
+			default: true
+		},
+		// left right bottom top
+		mode: {
+			type: String,
+			default: 'right'
+		},
+		//drawer z-index
+		zIndex: {
+			type: [Number, String],
+			default: 9999
+		},
+		//mask z-index
+		maskZIndex: {
+			type: [Number, String],
+			default: 9998
+		},
+		backgroundColor: {
+			type: String,
+			default: '#fff'
+		}
+	},
+	methods: {
+		handleMaskClick() {
+			if (!this.maskClosable) {
+				return;
+			}
+			this.$emit('close', {});
+		}
+	}
+};
+</script>
+
+<style scoped>
+.tui-drawer-mask {
+	opacity: 0;
+	visibility: hidden;
+	position: fixed;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	background-color: rgba(0, 0, 0, 0.6);
+	transition: all 0.3s ease-in-out;
+}
+.tui-drawer-mask_show {
+	display: block;
+	visibility: visible;
+	opacity: 1;
+}
+
+.tui-drawer-container {
+	position: fixed;
+	left: 50%;
+	height: 100.2%;
+	top: 0;
+	transform: translate3d(-50%, -50%, 0);
+	transform-origin: center;
+	transition: all 0.3s ease-in-out;
+	opacity: 0;
+	overflow-y: scroll;
+	-webkit-overflow-scrolling: touch;
+	-ms-touch-action: pan-y cross-slide-y;
+	-ms-scroll-chaining: none;
+	-ms-scroll-limit: 0 50 0 50;
+}
+.tui-drawer-container_left {
+	left: 0;
+	top: 50%;
+	transform: translate3d(-100%, -50%, 0);
+}
+
+.tui-drawer-container_right {
+	right: 0;
+	top: 50%;
+	left: auto;
+	transform: translate3d(100%, -50%, 0);
+}
+
+.tui-drawer-container_bottom,
+.tui-drawer-container_top {
+	width: 100%;
+	height: auto !important;
+	min-height: 20rpx;
+	left: 0;
+	right: 0;
+	transform-origin: center;
+	transition: all 0.3s ease-in-out;
+}
+.tui-drawer-container_bottom {
+	bottom: 0;
+	top: auto;
+	transform: translate3d(0, 100%, 0);
+}
+.tui-drawer-container_top {
+	transform: translate3d(0, -100%, 0);
+}
+.tui-drawer-left__show,
+.tui-drawer-right__show {
+	opacity: 1;
+	transform: translate3d(0, -50%, 0);
+}
+.tui-drawer-top__show,
+.tui-drawer-bottom__show {
+	opacity: 1;
+	transform: translate3d(0, 0, 0);
+}
+</style>

+ 178 - 0
components/thorui/tui-list-cell.vue

@@ -0,0 +1,178 @@
+<template>
+	<view
+		class="tui-list-class tui-list-cell"
+		:class="[
+			arrow ? 'tui-cell-arrow' : '',
+			arrow && arrowRight ? '' : 'tui-arrow-right',
+			unlined ? 'tui-cell-unlined' : '',
+			lineLeft ? 'tui-line-left' : '',
+			lineRight ? 'tui-line-right' : '',
+			arrow && arrowColor ? 'tui-arrow-' + arrowColor : '',
+			radius ? 'tui-radius' : ''
+		]"
+		:hover-class="hover ? 'tui-cell-hover' : ''"
+		:style="{ backgroundColor: backgroundColor, fontSize: size + 'rpx', color: color, padding: padding }"
+		:hover-stay-time="150"
+		@tap="handleClick"
+	>
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+export default {
+	name: 'tuiListCell',
+	emits: ['click'],
+	props: {
+		//是否有箭头
+		arrow: {
+			type: Boolean,
+			default: false
+		},
+		//箭头颜色 传值: white,gray,warning,danger
+		arrowColor: {
+			type: String,
+			default: ''
+		},
+		//是否有点击效果
+		hover: {
+			type: Boolean,
+			default: true
+		},
+		//隐藏线条
+		unlined: {
+			type: Boolean,
+			default: false
+		},
+		//线条是否有左偏移距离
+		lineLeft: {
+			type: Boolean,
+			default: true
+		},
+		//线条是否有右偏移距离
+		lineRight: {
+			type: Boolean,
+			default: false
+		},
+		padding: {
+			type: String,
+			default: '26rpx 30rpx'
+		},
+		//背景颜色
+		backgroundColor: {
+			type: String,
+			default: '#fff'
+		},
+		//字体大小
+		size: {
+			type: Number,
+			default: 28
+		},
+		//字体颜色
+		color: {
+			type: String,
+			default: '#333'
+		},
+		//是否加圆角
+		radius: {
+			type: Boolean,
+			default: false
+		},
+		//箭头是否有偏移距离
+		arrowRight: {
+			type: Boolean,
+			default: true
+		},
+		index: {
+			type: Number,
+			default: 0
+		}
+	},
+	methods: {
+		handleClick() {
+			this.$emit('click', {
+				index: this.index
+			});
+		}
+	}
+};
+</script>
+
+<style scoped>
+.tui-list-cell {
+	position: relative;
+	width: 100%;
+	box-sizing: border-box;
+}
+.tui-radius {
+	border-radius: 6rpx;
+	overflow: hidden;
+}
+
+.tui-cell-hover {
+	background-color: #f1f1f1 !important;
+}
+/* #ifdef MP-BAIDU */
+.tui-list-cell:active {
+	background-color: #f1f1f1 !important;
+}
+/* #endif */
+
+.tui-list-cell::after {
+	content: '';
+	position: absolute;
+	border-bottom: 1px solid #eaeef1;
+	-webkit-transform: scaleY(0.5) translateZ(0);
+	transform: scaleY(0.5) translateZ(0);
+	transform-origin: 0 100%;
+	bottom: 0;
+	right: 0;
+	left: 0;
+	pointer-events: none;
+}
+
+.tui-line-left::after {
+	left: 30rpx !important;
+}
+
+.tui-line-right::after {
+	right: 30rpx !important;
+}
+
+.tui-cell-unlined::after {
+	border-bottom: 0 !important;
+}
+
+.tui-cell-arrow::before {
+	content: ' ';
+	height: 10px;
+	width: 10px;
+	border-width: 2px 2px 0 0;
+	border-color: #c0c0c0;
+	border-style: solid;
+	-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
+	transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
+	position: absolute;
+	top: 50%;
+	margin-top: -6px;
+	right: 30rpx;
+}
+.tui-arrow-right::before {
+	right: 0 !important;
+}
+.tui-arrow-gray::before {
+	border-color: #666666 !important;
+}
+.tui-arrow-white::before {
+	border-color: #ffffff !important;
+}
+.tui-arrow-warning::before {
+	border-color: #ff7900 !important;
+}
+.tui-arrow-success::before {
+	border-color: #19be6b !important;
+}
+.tui-arrow-danger::before {
+	border-color: #eb0909 !important;
+}
+</style>

+ 195 - 0
components/timeSlot/index.vue

@@ -0,0 +1,195 @@
+<template>
+	<!-- 日期组件 -->
+	<view>
+		<view class="list">
+			<view class="times">
+				<view class="item" :class="time == 'all' ? 'on' : ''" @click="setTime('all')">全部</view>
+				<view class="item" :class="time == 'today' ? 'on' : ''" @click="setTime('today')">今天</view>
+				<view class="item" :class="time == 'yesterday' ? 'on' : ''" @click="setTime('yesterday')">昨天</view>
+				<view class="item" :class="time == 'seven' ? 'on' : ''" @click="setTime('seven')">近7天</view>
+			</view>
+			<view class="item" :class="time == 'date' ? 'on' : ''" @click="dateTitle">自定义时间 <text
+					class="iconfont icon-xiangxia aaa"></text></view>
+		</view>
+		<uni-calendar ref="calendar" :date="info.date" :insert="info.insert" :lunar="info.lunar"
+			:startDate="info.startDate" :endDate="info.endDate" :range="info.range" @confirm="confirm"
+			:showMonth="info.showMonth" />
+		<view class="mask" @touchmove.prevent v-show="current === true" @click="close"></view>
+		<Loading :loaded="loaded" :loading="loading"></Loading>
+	</view>
+
+</template>
+
+<script>
+	import Loading from '@/components/Loading/index.vue'
+	import uniCalendar from '@/components/uni-calendar/uni-calendar.vue'
+	const year = new Date().getFullYear();
+	const month = new Date().getMonth() + 1;
+	const day = new Date().getDate();
+	export default {
+		components: {
+			uniCalendar,
+			Loading
+		},
+		data() {
+			return {
+				time:'all',
+				current: false,
+				loaded: false,
+				loading: false,
+				info: {
+					startDate: '',
+					endDate: '',
+					lunar: false,
+					range: true,
+					insert: false,
+					selected: [],
+					showMonth: false
+				},
+				where: {
+					start: "",
+					stop: "",
+				},
+			}
+		},
+		methods: {
+			close() {
+				this.current = false;
+			},
+			// 日历确定
+			confirm(e) {
+				console.log(e)
+				let self = this
+				let star, stop;
+				if (e.range.after && e.range.before) {
+					if (e.range.before > e.range.after) {
+						star = new Date(e.range.after + ' 00:00:00').getTime() / 1000
+						stop = new Date(e.range.before + ' 23:59:59').getTime() / 1000
+					} else {
+						star = new Date(e.range.before + ' 00:00:00').getTime() / 1000
+						stop = new Date(e.range.after + ' 23:59:59').getTime() / 1000
+					}
+					self.where.start = star
+					self.where.stop = stop
+					self.loaded = false;
+					self.loading = false;
+					// Promise.all();
+					this.$emit('changeTime', this.where)
+				}
+			},
+			dateTitle() {
+				this.$refs.calendar.open()
+				this.time = 'date'
+			},
+			setTime(time) {
+				let self = this
+				this.time = time;
+				var year = new Date().getFullYear(),
+					month = new Date().getMonth() + 1,
+					day = new Date().getDate();
+				this.tip = 1
+				this.loaded = false;
+				this.loading = false;
+				switch (time) {
+					case "all":
+						this.where.start = 0
+						this.where.stop = 0
+						this.title = "全部";
+						this.$emit('changeTime', this.where)
+						break;
+					case "today":
+						this.where.start =
+							new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
+							1000;
+						this.where.stop =
+							new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
+							1000 +
+							24 * 60 * 60 -
+							1;
+						this.title = "今日";
+						this.$emit('changeTime', this.where)
+						break;
+					case "yesterday":
+						this.where.start =
+							new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
+							1000 -
+							24 * 60 * 60;
+						this.where.stop =
+							new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
+							1000 -
+							1;
+						this.title = "昨日";
+						this.$emit('changeTime', this.where)
+						break;
+					case "month":
+						this.where.start =
+							new Date(year, new Date().getMonth(), 1).getTime() / 1000;
+						this.where.stop = new Date(year, month, 1).getTime() / 1000 - 1;
+						this.title = "本月";
+						this.$emit('changeTime', this.where)
+						break;
+					case "seven":
+						this.where.start =
+							new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
+							1000 +
+							24 * 60 * 60 -
+							7 * 3600 * 24;
+						this.where.stop =
+							new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
+							1000 +
+							24 * 60 * 60 -
+							1;
+						this.title = "七日";
+						this.$emit('changeTime', this.where)
+						break;
+						// #ifdef MP
+					case "date":
+						let star = new Date(self.before).getTime() / 1000
+						let stop = new Date(self.after).getTime() / 1000
+						self.where.start = star
+						self.where.stop = stop
+						Promise.all([self.getList()]);
+						this.$emit('changeTime', this.where)
+						break;
+						// #endif
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.list {
+		display: flex;
+		justify-content: space-between;
+		padding: 24rpx 30rpx;
+		background-color: #fff;
+		color: #666666;
+		font-size: 26rpx;
+
+		.times {
+			display: flex;
+
+			.item {
+				margin-right: 20rpx;
+				background: #F5F5F5;
+				padding: 10rpx 20rpx;
+				border-radius: 30rpx;
+
+			}
+
+			.item.on {
+				color: var(--view-theme);
+				background-color: var(--view-minorColorT);
+			}
+		}
+		.item{
+			padding: 10rpx 0rpx;
+		}
+	}
+
+	.aaa {
+		padding-left: 10rpx;
+		font-size: 20rpx !important;
+	}
+</style>

+ 546 - 0
components/uni-calendar/calendar.js

@@ -0,0 +1,546 @@
+/**
+* @1900-2100区间内的公历、农历互转
+* @charset UTF-8
+* @github  https://github.com/jjonline/calendar.js
+* @Author  Jea杨(JJonline@JJonline.Cn)
+* @Time    2014-7-21
+* @Time    2016-8-13 Fixed 2033hex、Attribution Annals
+* @Time    2016-9-25 Fixed lunar LeapMonth Param Bug
+* @Time    2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
+* @Version 1.0.3
+* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
+* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
+*/
+/* eslint-disable */
+var calendar = {
+
+  /**
+      * 农历1900-2100的润大小信息表
+      * @Array Of Property
+      * @return Hex
+      */
+  lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
+    0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
+    0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
+    0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
+    0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
+    0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
+    0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
+    0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
+    0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
+    0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
+    0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
+    0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
+    0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
+    0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
+    0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
+    /** Add By JJonline@JJonline.Cn**/
+    0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
+    0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
+    0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
+    0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
+    0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
+    0x0d520], // 2100
+
+  /**
+      * 公历每个月份的天数普通表
+      * @Array Of Property
+      * @return Number
+      */
+  solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+
+  /**
+      * 天干地支之天干速查表
+      * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
+      * @return Cn string
+      */
+  Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
+
+  /**
+      * 天干地支之地支速查表
+      * @Array Of Property
+      * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
+      * @return Cn string
+      */
+  Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
+
+  /**
+      * 天干地支之地支速查表<=>生肖
+      * @Array Of Property
+      * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
+      * @return Cn string
+      */
+  Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
+
+  /**
+      * 24节气速查表
+      * @Array Of Property
+      * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
+      * @return Cn string
+      */
+  solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
+
+  /**
+      * 1900-2100各年的24节气日期速查表
+      * @Array Of Property
+      * @return 0x string For splice
+      */
+  sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
+    '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
+    'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
+    '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
+    '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
+    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
+    '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
+    '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
+    '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
+    '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+    '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
+    '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
+    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+    '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
+    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+    '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+    '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+    '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+    '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+    '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
+    '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+    '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+    '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
+    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+    '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
+    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
+    '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+    '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
+    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
+    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
+    '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
+    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
+    '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+    '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
+    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
+
+  /**
+      * 数字转中文速查表
+      * @Array Of Property
+      * @trans ['日','一','二','三','四','五','六','七','八','九','十']
+      * @return Cn string
+      */
+  nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
+
+  /**
+      * 日期转农历称呼速查表
+      * @Array Of Property
+      * @trans ['初','十','廿','卅']
+      * @return Cn string
+      */
+  nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
+
+  /**
+      * 月份转农历称呼速查表
+      * @Array Of Property
+      * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
+      * @return Cn string
+      */
+  nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
+
+  /**
+      * 返回农历y年一整年的总天数
+      * @param lunar Year
+      * @return Number
+      * @eg:var count = calendar.lYearDays(1987) ;//count=387
+      */
+  lYearDays: function (y) {
+    var i; var sum = 348
+    for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
+    return (sum + this.leapDays(y))
+  },
+
+  /**
+      * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
+      * @param lunar Year
+      * @return Number (0-12)
+      * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
+      */
+  leapMonth: function (y) { // 闰字编码 \u95f0
+    return (this.lunarInfo[y - 1900] & 0xf)
+  },
+
+  /**
+      * 返回农历y年闰月的天数 若该年没有闰月则返回0
+      * @param lunar Year
+      * @return Number (0、29、30)
+      * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
+      */
+  leapDays: function (y) {
+    if (this.leapMonth(y)) {
+      return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
+    }
+    return (0)
+  },
+
+  /**
+      * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
+      * @param lunar Year
+      * @return Number (-1、29、30)
+      * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
+      */
+  monthDays: function (y, m) {
+    if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
+    return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
+  },
+
+  /**
+      * 返回公历(!)y年m月的天数
+      * @param solar Year
+      * @return Number (-1、28、29、30、31)
+      * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
+      */
+  solarDays: function (y, m) {
+    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+    var ms = m - 1
+    if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
+      return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
+    } else {
+      return (this.solarMonth[ms])
+    }
+  },
+
+  /**
+     * 农历年份转换为干支纪年
+     * @param  lYear 农历年的年份数
+     * @return Cn string
+     */
+  toGanZhiYear: function (lYear) {
+    var ganKey = (lYear - 3) % 10
+    var zhiKey = (lYear - 3) % 12
+    if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
+    if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
+    return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
+  },
+
+  /**
+     * 公历月、日判断所属星座
+     * @param  cMonth [description]
+     * @param  cDay [description]
+     * @return Cn string
+     */
+  toAstro: function (cMonth, cDay) {
+    var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
+    var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
+    return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
+  },
+
+  /**
+      * 传入offset偏移量返回干支
+      * @param offset 相对甲子的偏移量
+      * @return Cn string
+      */
+  toGanZhi: function (offset) {
+    return this.Gan[offset % 10] + this.Zhi[offset % 12]
+  },
+
+  /**
+      * 传入公历(!)y年获得该年第n个节气的公历日期
+      * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
+      * @return day Number
+      * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
+      */
+  getTerm: function (y, n) {
+    if (y < 1900 || y > 2100) { return -1 }
+    if (n < 1 || n > 24) { return -1 }
+    var _table = this.sTermInfo[y - 1900]
+    var _info = [
+      parseInt('0x' + _table.substr(0, 5)).toString(),
+      parseInt('0x' + _table.substr(5, 5)).toString(),
+      parseInt('0x' + _table.substr(10, 5)).toString(),
+      parseInt('0x' + _table.substr(15, 5)).toString(),
+      parseInt('0x' + _table.substr(20, 5)).toString(),
+      parseInt('0x' + _table.substr(25, 5)).toString()
+    ]
+    var _calday = [
+      _info[0].substr(0, 1),
+      _info[0].substr(1, 2),
+      _info[0].substr(3, 1),
+      _info[0].substr(4, 2),
+
+      _info[1].substr(0, 1),
+      _info[1].substr(1, 2),
+      _info[1].substr(3, 1),
+      _info[1].substr(4, 2),
+
+      _info[2].substr(0, 1),
+      _info[2].substr(1, 2),
+      _info[2].substr(3, 1),
+      _info[2].substr(4, 2),
+
+      _info[3].substr(0, 1),
+      _info[3].substr(1, 2),
+      _info[3].substr(3, 1),
+      _info[3].substr(4, 2),
+
+      _info[4].substr(0, 1),
+      _info[4].substr(1, 2),
+      _info[4].substr(3, 1),
+      _info[4].substr(4, 2),
+
+      _info[5].substr(0, 1),
+      _info[5].substr(1, 2),
+      _info[5].substr(3, 1),
+      _info[5].substr(4, 2)
+    ]
+    return parseInt(_calday[n - 1])
+  },
+
+  /**
+      * 传入农历数字月份返回汉语通俗表示法
+      * @param lunar month
+      * @return Cn string
+      * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
+      */
+  toChinaMonth: function (m) { // 月 => \u6708
+    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+    var s = this.nStr3[m - 1]
+    s += '\u6708'// 加上月字
+    return s
+  },
+
+  /**
+      * 传入农历日期数字返回汉字表示法
+      * @param lunar day
+      * @return Cn string
+      * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
+      */
+  toChinaDay: function (d) { // 日 => \u65e5
+    var s
+    switch (d) {
+      case 10:
+        s = '\u521d\u5341'; break
+      case 20:
+        s = '\u4e8c\u5341'; break
+        break
+      case 30:
+        s = '\u4e09\u5341'; break
+        break
+      default :
+        s = this.nStr2[Math.floor(d / 10)]
+        s += this.nStr1[d % 10]
+    }
+    return (s)
+  },
+
+  /**
+      * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
+      * @param y year
+      * @return Cn string
+      * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
+      */
+  getAnimal: function (y) {
+    return this.Animals[(y - 4) % 12]
+  },
+
+  /**
+      * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
+      * @param y  solar year
+      * @param m  solar month
+      * @param d  solar day
+      * @return JSON object
+      * @eg:console.log(calendar.solar2lunar(1987,11,01));
+      */
+  solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
+    // 年份限定、上限
+    if (y < 1900 || y > 2100) {
+      return -1// undefined转换为数字变为NaN
+    }
+    // 公历传参最下限
+    if (y == 1900 && m == 1 && d < 31) {
+      return -1
+    }
+    // 未传参  获得当天
+    if (!y) {
+      var objDate = new Date()
+    } else {
+      var objDate = new Date(y, parseInt(m) - 1, d)
+    }
+    var i; var leap = 0; var temp = 0
+    // 修正ymd参数
+    var y = objDate.getFullYear()
+    var m = objDate.getMonth() + 1
+    var d = objDate.getDate()
+    var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
+    for (i = 1900; i < 2101 && offset > 0; i++) {
+      temp = this.lYearDays(i)
+      offset -= temp
+    }
+    if (offset < 0) {
+      offset += temp; i--
+    }
+
+    // 是否今天
+    var isTodayObj = new Date()
+    var isToday = false
+    if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
+      isToday = true
+    }
+    // 星期几
+    var nWeek = objDate.getDay()
+    var cWeek = this.nStr1[nWeek]
+    // 数字表示周几顺应天朝周一开始的惯例
+    if (nWeek == 0) {
+      nWeek = 7
+    }
+    // 农历年
+    var year = i
+    var leap = this.leapMonth(i) // 闰哪个月
+    var isLeap = false
+
+    // 效验闰月
+    for (i = 1; i < 13 && offset > 0; i++) {
+      // 闰月
+      if (leap > 0 && i == (leap + 1) && isLeap == false) {
+        --i
+        isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
+      } else {
+        temp = this.monthDays(year, i)// 计算农历普通月天数
+      }
+      // 解除闰月
+      if (isLeap == true && i == (leap + 1)) { isLeap = false }
+      offset -= temp
+    }
+    // 闰月导致数组下标重叠取反
+    if (offset == 0 && leap > 0 && i == leap + 1) {
+      if (isLeap) {
+        isLeap = false
+      } else {
+        isLeap = true; --i
+      }
+    }
+    if (offset < 0) {
+      offset += temp; --i
+    }
+    // 农历月
+    var month = i
+    // 农历日
+    var day = offset + 1
+    // 天干地支处理
+    var sm = m - 1
+    var gzY = this.toGanZhiYear(year)
+
+    // 当月的两个节气
+    // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
+    var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
+    var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
+
+    // 依据12节气修正干支月
+    var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
+    if (d >= firstNode) {
+      gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
+    }
+
+    // 传入的日期的节气与否
+    var isTerm = false
+    var Term = null
+    if (firstNode == d) {
+      isTerm = true
+      Term = this.solarTerm[m * 2 - 2]
+    }
+    if (secondNode == d) {
+      isTerm = true
+      Term = this.solarTerm[m * 2 - 1]
+    }
+    // 日柱 当月一日与 1900/1/1 相差天数
+    var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
+    var gzD = this.toGanZhi(dayCyclical + d - 1)
+    // 该日期所属的星座
+    var astro = this.toAstro(m, d)
+
+    return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
+  },
+
+  /**
+      * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
+      * @param y  lunar year
+      * @param m  lunar month
+      * @param d  lunar day
+      * @param isLeapMonth  lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
+      * @return JSON object
+      * @eg:console.log(calendar.lunar2solar(1987,9,10));
+      */
+  lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
+    var isLeapMonth = !!isLeapMonth
+    var leapOffset = 0
+    var leapMonth = this.leapMonth(y)
+    var leapDay = this.leapDays(y)
+    if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
+    if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
+    var day = this.monthDays(y, m)
+    var _day = day
+    // bugFix 2016-9-25
+    // if month is leap, _day use leapDays method
+    if (isLeapMonth) {
+      _day = this.leapDays(y, m)
+    }
+    if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
+
+    // 计算农历的时间差
+    var offset = 0
+    for (var i = 1900; i < y; i++) {
+      offset += this.lYearDays(i)
+    }
+    var leap = 0; var isAdd = false
+    for (var i = 1; i < m; i++) {
+      leap = this.leapMonth(y)
+      if (!isAdd) { // 处理闰月
+        if (leap <= i && leap > 0) {
+          offset += this.leapDays(y); isAdd = true
+        }
+      }
+      offset += this.monthDays(y, i)
+    }
+    // 转换闰月农历 需补充该年闰月的前一个月的时差
+    if (isLeapMonth) { offset += day }
+    // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
+    var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
+    var calObj = new Date((offset + d - 31) * 86400000 + stmap)
+    var cY = calObj.getUTCFullYear()
+    var cM = calObj.getUTCMonth() + 1
+    var cD = calObj.getUTCDate()
+
+    return this.solar2lunar(cY, cM, cD)
+  }
+}
+
+export default calendar

+ 152 - 0
components/uni-calendar/uni-calendar-item.vue

@@ -0,0 +1,152 @@
+<template>
+	<view class="uni-calendar-item__weeks-box" :class="{
+		'uni-calendar-item--disable':weeks.disable,
+		'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+		'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) ,
+		'uni-calendar-item--multiple': weeks.multiple
+		}"
+	 @click="choiceDate(weeks)">
+		<view class="uni-calendar-item__weeks-box-item">
+			<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
+			<text class="uni-calendar-item__weeks-box-text" :class="{
+				'uni-calendar-item--isDay-text': weeks.isDay,
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
+				'uni-calendar-item--multiple': weeks.multiple,
+				'uni-calendar-item--disable':weeks.disable,
+				}">{{weeks.date}}</text>
+			<text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{
+				'uni-calendar-item--isDay-text':weeks.isDay,
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
+				'uni-calendar-item--multiple': weeks.multiple,
+				}">今天</text>
+			<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{
+				'uni-calendar-item--isDay-text':weeks.isDay,
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
+				'uni-calendar-item--multiple': weeks.multiple,
+				'uni-calendar-item--disable':weeks.disable,
+				}">{{weeks.isDay?'今天': (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
+			<text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{
+				'uni-calendar-item--extra':weeks.extraInfo.info,
+				'uni-calendar-item--isDay-text':weeks.isDay,
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
+				'uni-calendar-item--multiple': weeks.multiple,
+				'uni-calendar-item--disable':weeks.disable,
+				}">{{weeks.extraInfo.info}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			weeks: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			calendar: {
+				type: Object,
+				default: () => {
+					return {}
+				}
+			},
+			selected: {
+				type: Array,
+				default: () => {
+					return []
+				}
+			},
+			lunar: {
+				type: Boolean,
+				default: false
+			}
+		},
+		methods: {
+			choiceDate(weeks) {
+				this.$emit('change', weeks)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-calendar-item__weeks-box {
+		flex: 1;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.uni-calendar-item__weeks-box-text {
+		font-size: $uni-font-size-base;
+		color: $uni-text-color;
+	}
+
+	.uni-calendar-item__weeks-lunar-text {
+		font-size: $uni-font-size-sm;
+		color: $uni-text-color;
+	}
+
+	.uni-calendar-item__weeks-box-item {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		width: 100rpx;
+		height: 100rpx;
+	}
+
+	.uni-calendar-item__weeks-box-circle {
+		position: absolute;
+		top: 5px;
+		right: 5px;
+		width: 8px;
+		height: 8px;
+		border-radius: 8px;
+		background-color: $uni-color-error;
+
+	}
+
+	.uni-calendar-item--disable {
+		background-color: rgba(249, 249, 249, $uni-opacity-disabled);
+		color: $uni-text-color-disable;
+	}
+
+	.uni-calendar-item--isDay-text {
+		color: $uni-color-primary;
+	}
+
+	.uni-calendar-item--isDay {
+		background-color: $uni-color-primary;
+		opacity: 0.8;
+		color: #fff;
+	}
+
+	.uni-calendar-item--extra {
+		color: $uni-color-error;
+		opacity: 0.8;
+	}
+
+	.uni-calendar-item--checked {
+		background-color: $uni-color-primary;
+		color: #fff;
+		opacity: 0.8;
+	}
+
+	.uni-calendar-item--multiple {
+		background-color: $uni-color-primary;
+		color: #fff;
+		opacity: 0.8;
+	}
+</style>

+ 434 - 0
components/uni-calendar/uni-calendar.vue

@@ -0,0 +1,434 @@
+<template>
+	<view class="uni-calendar" @touchmove.stop.prevent="clean">
+		<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="close"></view>
+		<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
+			<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
+				<view class="uni-calendar__header-btn-box" @click="close">
+					<text class="uni-calendar__header-text uni-calendar--fixed-width">取消</text>
+				</view>
+				<view class="uni-calendar__header-btn-box" @click="confirm">
+					<text class="uni-calendar__header-text uni-calendar--fixed-width">确定</text>
+				</view>
+			</view>
+			<view class="uni-calendar__header">
+				<view class="uni-calendar__header-btn-box" @click="pre">
+					<view class="uni-calendar__header-btn uni-calendar--left"></view>
+				</view>
+				<text class="uni-calendar__header-text">{{ (nowDate.year||'') +'年'+( nowDate.month||'') +'月'}}</text>
+				<view class="uni-calendar__header-btn-box" @click="next">
+					<view class="uni-calendar__header-btn uni-calendar--right"></view>
+				</view>
+				<text class="uni-calendar__backtoday" @click="backtoday">回到今天</text>
+			</view>
+			<view class="uni-calendar__box">
+				<view v-if="showMonth" class="uni-calendar__box-bg">
+					<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
+				</view>
+				<view class="uni-calendar__weeks">
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">日</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">一</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">二</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">三</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">四</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">五</text>
+					</view>
+					<view class="uni-calendar__weeks-day">
+						<text class="uni-calendar__weeks-day-text">六</text>
+					</view>
+				</view>
+				<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
+					<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
+						<uni-calendar-item :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></uni-calendar-item>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import Calendar from './util.js';
+	import uniCalendarItem from './uni-calendar-item.vue'
+	export default {
+		components: {
+			uniCalendarItem
+		},
+		props: {
+			/**
+			 * 当前日期
+			 */
+			date: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 打点日期
+			 */
+			selected: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			/**
+			 * 是否开启阴历日期
+			 */
+			lunar: {
+				type: Boolean,
+				default: false
+			},
+			/**
+			 * 开始时间
+			 */
+			startDate: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 结束时间
+			 */
+			endDate: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 范围
+			 */
+			range: {
+				type: Boolean,
+				default: false
+			},
+			/**
+			 * 插入
+			 */
+			insert: {
+				type: Boolean,
+				default: true
+			},
+			/**
+			 * 是否显示月份背景
+			 */
+			showMonth: {
+				type: Boolean,
+				default: true
+			}
+		},
+		data() {
+			return {
+				show: false,
+				weeks: [],
+				calendar: {},
+				nowDate: '',
+				aniMaskShow: false
+			}
+		},
+		watch: {
+			selected(newVal) {
+				this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
+				this.weeks = this.cale.weeks
+			}
+		},
+		created() {
+			// 获取日历方法实例
+			this.cale = new Calendar({
+				date: this.date,
+				selected: this.selected,
+				startDate: this.startDate,
+				endDate: this.endDate,
+				range: this.range,
+			})
+			this.init(this.cale.date.fullDate)
+		},
+		methods: {
+			// 取消穿透
+			clean() {},
+			init(date) {
+				this.weeks = this.cale.weeks
+				this.nowDate = this.calendar = this.cale.getInfo(date)
+			},
+			open() {
+				this.show = true
+				this.$nextTick(() => {
+					setTimeout(()=>{
+						this.aniMaskShow = true
+					},50)
+				})
+			},
+			close() {
+				this.aniMaskShow = false
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.show = false
+					}, 300)
+				})
+			},
+			confirm() {
+				this.setEmit('confirm')
+				this.close()
+			},
+			change() {
+				if (!this.insert) return
+				this.setEmit('change')
+			},
+			monthSwitch() {
+				let {
+					year,
+					month
+				} = this.nowDate
+				this.$emit('monthSwitch', {
+					year,
+					month: Number(month)
+				})
+			},
+			setEmit(name) {
+				let {
+					year,
+					month,
+					date,
+					fullDate,
+					lunar,
+					extraInfo
+				} = this.calendar
+				this.$emit(name, {
+					range: this.cale.multipleStatus,
+					year,
+					month,
+					date,
+					fulldate: fullDate,
+					lunar,
+					extraInfo: extraInfo || {}
+				})
+			},
+			choiceDate(weeks) {
+				if (weeks.disable) return
+				this.calendar = weeks
+				// 设置多选
+				this.cale.setMultiple(this.calendar.fullDate)
+				this.weeks = this.cale.weeks
+				this.change()
+			},
+			backtoday() {
+				this.cale.setDate(this.date)
+				this.weeks = this.cale.weeks
+				this.nowDate = this.calendar = this.cale.getInfo(this.date)
+				this.change()
+			},
+			pre() {
+				const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
+				this.setDate(preDate)
+				this.monthSwitch()
+
+			},
+			next() {
+				const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
+				this.setDate(nextDate)
+				this.monthSwitch()
+			},
+			setDate(date) {
+				this.cale.setDate(date)
+				this.weeks = this.cale.weeks
+				this.nowDate = this.cale.getInfo(date)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-calendar {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+	}
+
+	.uni-calendar__mask {
+		position: fixed;
+		bottom: 0;
+		top: 0;
+		left: 0;
+		right: 0;
+		background-color: $uni-bg-color-mask;
+		transition-property: opacity;
+		transition-duration: 0.3s;
+		opacity: 0;
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+	.uni-calendar--mask-show {
+		opacity: 1
+	}
+
+	.uni-calendar--fixed {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		transition-property: transform;
+		transition-duration: 0.3s;
+		transform: translateY(460px);
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+	.uni-calendar--ani-show {
+		transform: translateY(0);
+	}
+
+	.uni-calendar__content {
+		background-color: #fff;
+	}
+
+	.uni-calendar__header {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 50px;
+		border-bottom-color: $uni-border-color;
+		border-bottom-style: solid;
+		border-bottom-width: 1px;
+	}
+
+	.uni-calendar--fixed-top {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: space-between;
+		border-top-color: $uni-border-color;
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-calendar--fixed-width {
+		width: 50px;
+		// padding: 0 15px;
+	}
+
+	.uni-calendar__backtoday {
+		position: absolute;
+		right: 0;
+		top: 25rpx;
+		padding: 0 5px;
+		padding-left: 10px;
+		height: 25px;
+		line-height: 25px;
+		font-size: 12px;
+		border-top-left-radius: 25px;
+		border-bottom-left-radius: 25px;
+		color: $uni-text-color;
+		background-color: $uni-bg-color-hover;
+	}
+
+	.uni-calendar__header-text {
+		text-align: center;
+		width: 100px;
+		font-size: $uni-font-size-base;
+		color: $uni-text-color;
+	}
+
+	.uni-calendar__header-btn-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		width: 50px;
+		height: 50px;
+	}
+
+	.uni-calendar__header-btn {
+		width: 10px;
+		height: 10px;
+		border-left-color: $uni-text-color-placeholder;
+		border-left-style: solid;
+		border-left-width: 2px;
+		border-top-color: $uni-color-subtitle;
+		border-top-style: solid;
+		border-top-width: 2px;
+	}
+
+	.uni-calendar--left {
+		transform: rotate(-45deg);
+	}
+
+	.uni-calendar--right {
+		transform: rotate(135deg);
+	}
+
+
+	.uni-calendar__weeks {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+	}
+
+	.uni-calendar__weeks-item {
+		flex: 1;
+	}
+
+	.uni-calendar__weeks-day {
+		flex: 1;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		height: 45px;
+		border-bottom-color: #F5F5F5;
+		border-bottom-style: solid;
+		border-bottom-width: 1px;
+	}
+	.uni-calendar__weeks-day-text {
+		font-size: 14px;
+	}
+
+	.uni-calendar__box {
+		position: relative;
+	}
+
+	.uni-calendar__box-bg {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		position: absolute;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+	}
+
+	.uni-calendar__box-bg-text {
+		font-size: 200px;
+		font-weight: bold;
+		color: $uni-text-color-grey;
+		opacity: 0.1;
+		text-align: center;
+		/* #ifndef APP-NVUE */
+		line-height: 1;
+		/* #endif */
+	}
+</style>

+ 327 - 0
components/uni-calendar/util.js

@@ -0,0 +1,327 @@
+import CALENDAR from './calendar.js'
+
+class Calendar {
+	constructor({
+		date,
+		selected,
+		startDate,
+		endDate,
+		range
+	} = {}) {
+		// 当前日期
+		this.date = this.getDate(date) // 当前初入日期
+		// 打点信息
+		this.selected = selected || [];
+		// 范围开始
+		this.startDate = startDate
+		// 范围结束
+		this.endDate = endDate
+		this.range = range
+		// 多选状态
+		this.multipleStatus = {
+			before: '',
+			after: '',
+			data: []
+		}
+		// 每周日期
+		this.weeks = {}
+
+		this._getWeek(this.date.fullDate)
+	}
+
+	/**
+	 * 获取任意时间
+	 */
+	getDate(date, AddDayCount = 0, str = 'day') {
+		if (!date) {
+			date = new Date()
+		}
+		if (typeof date !== 'object') {
+			date = date.replace(/-/g, '/')
+		}
+		const dd = new Date(date)
+		switch (str) {
+			case 'day':
+				dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
+				break
+			case 'month':
+				if (dd.getDate() === 31) {
+					dd.setDate(dd.getDate() + AddDayCount)
+				} else {
+					dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
+				}
+				break
+			case 'year':
+				dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
+				break
+		}
+		const y = dd.getFullYear()
+		const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
+		const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
+		return {
+			fullDate: y + '-' + m + '-' + d,
+			year: y,
+			month: m,
+			date: d,
+			day: dd.getDay()
+		}
+	}
+
+
+	/**
+	 * 获取上月剩余天数
+	 */
+	_getLastMonthDays(firstDay, full) {
+		let dateArr = []
+		for (let i = firstDay; i > 0; i--) {
+			const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
+			dateArr.push({
+				date: beforeDate,
+				month: full.month - 1,
+				lunar: this.getlunar(full.year, full.month - 1, beforeDate),
+				disable: true
+			})
+		}
+		return dateArr
+	}
+	/**
+	 * 获取本月天数
+	 */
+	_currentMonthDys(dateData, full) {
+		let dateArr = []
+		let fullDate = this.date.fullDate
+		for (let i = 1; i <= dateData; i++) {
+			let isinfo = false
+			let nowDate = full.year + '-' + (full.month < 10 ?
+				full.month : full.month) + '-' + (i < 10 ?
+				'0' + i : i)
+			// 是否今天
+			let isDay = fullDate === nowDate
+			// 获取打点信息
+			let info = this.selected && this.selected.find((item) => {
+				if (this.dateEqual(nowDate, item.date)) {
+					return item
+				}
+			})
+
+			// 日期禁用
+			let disableBefore = true
+			let disableAfter = true
+			if (this.startDate) {
+				let dateCompBefore = this.dateCompare(this.startDate, fullDate)
+				disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
+			}
+
+			if (this.endDate) {
+				let dateCompAfter = this.dateCompare(fullDate, this.endDate)
+				disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
+			}
+
+			let multiples = this.multipleStatus.data
+			let checked = false
+			let multiplesStatus = -1
+			if (this.range) {
+				if (multiples) {
+					multiplesStatus = multiples.findIndex((item) => {
+						return this.dateEqual(item, nowDate)
+					})
+				}
+				if (multiplesStatus !== -1) {
+					checked = true
+				}
+			}
+
+			let data = {
+				fullDate: nowDate,
+				year: full.year,
+				date: i,
+				multiple: this.range ? checked : false,
+				month: full.month,
+				lunar: this.getlunar(full.year, full.month, i),
+				disable: !disableBefore || !disableAfter,
+				isDay
+			}
+			if (info) {
+				data.extraInfo = info
+			}
+
+			dateArr.push(data)
+		}
+		return dateArr
+	}
+	/**
+	 * 获取下月天数
+	 */
+	_getNextMonthDays(surplus, full) {
+		let dateArr = []
+		for (let i = 1; i < surplus + 1; i++) {
+			dateArr.push({
+				date: i,
+				month: Number(full.month) + 1,
+				lunar: this.getlunar(full.year, Number(full.month) + 1, i),
+				disable: true
+			})
+		}
+		return dateArr
+	}
+	/**
+	 * 设置日期
+	 * @param {Object} date
+	 */
+	setDate(date) {
+		this._getWeek(date)
+	}
+	/**
+	 * 获取当前日期详情
+	 * @param {Object} date
+	 */
+	getInfo(date) {
+		if (!date) {
+			date = new Date()
+		}
+		const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
+		return dateInfo
+	}
+
+	/**
+	 * 比较时间大小
+	 */
+	dateCompare(startDate, endDate) {
+		// 计算截止时间
+		startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+		// 计算详细项的截止时间
+		endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+		if (startDate <= endDate) {
+			return true
+		} else {
+			return false
+		}
+	}
+
+	/**
+	 * 比较时间是否相等
+	 */
+	dateEqual(before, after) {
+		// 计算截止时间
+		before = new Date(before.replace('-', '/').replace('-', '/'))
+		// 计算详细项的截止时间
+		after = new Date(after.replace('-', '/').replace('-', '/'))
+		if (before.getTime() - after.getTime() === 0) {
+			return true
+		} else {
+			return false
+		}
+	}
+
+
+	/**
+	 * 获取日期范围内所有日期
+	 * @param {Object} begin
+	 * @param {Object} end
+	 */
+	geDateAll(begin, end) {
+		var arr = []
+		var ab = begin.split('-')
+		var ae = end.split('-')
+		var db = new Date()
+		db.setFullYear(ab[0], ab[1] - 1, ab[2])
+		var de = new Date()
+		de.setFullYear(ae[0], ae[1] - 1, ae[2])
+		var unixDb = db.getTime() - 24 * 60 * 60 * 1000
+		var unixDe = de.getTime() - 24 * 60 * 60 * 1000
+		for (var k = unixDb; k <= unixDe;) {
+			k = k + 24 * 60 * 60 * 1000
+			arr.push(this.getDate(new Date(parseInt(k))).fullDate)
+		}
+		return arr
+	}
+	/**
+	 * 计算阴历日期显示
+	 */
+	getlunar(year, month, date) {
+		return CALENDAR.solar2lunar(year, month, date)
+	}
+	/**
+	 * 设置打点
+	 */
+	setSelectInfo(data, value) {
+		this.selected = value
+		this._getWeek(data)
+	}
+
+	/**
+	 *  获取多选状态
+	 */
+	setMultiple(fullDate) {
+		let {
+			before,
+			after
+		} = this.multipleStatus
+		if (!this.range) return
+		if (before && after) {
+			this.multipleStatus.before = ''
+			this.multipleStatus.after = ''
+			this.multipleStatus.data = []
+			this._getWeek(fullDate)
+		} else {
+			if (!before) {
+				this.multipleStatus.before = fullDate
+			} else {
+				this.multipleStatus.after = fullDate
+				if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
+				} else {
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
+				}
+				this._getWeek(fullDate)
+			}
+		}
+	}
+
+	/**
+	 * 获取每周数据
+	 * @param {Object} dateData
+	 */
+	_getWeek(dateData) {
+		const {
+			fullDate,
+			year,
+			month,
+			date,
+			day
+		} = this.getDate(dateData)
+		let firstDay = new Date(year, month - 1, 1).getDay()
+		let currentDay = new Date(year, month, 0).getDate()
+		let dates = {
+			lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
+			currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
+			nextMonthDays: [], // 下个月开始几天
+			weeks: []
+		}
+		let canlender = []
+		const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
+		dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
+		canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
+		let weeks = {}
+		// 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
+		for (let i = 0; i < canlender.length; i++) {
+			if (i % 7 === 0) {
+				weeks[parseInt(i / 7)] = new Array(7)
+			}
+			weeks[parseInt(i / 7)][i % 7] = canlender[i]
+		}
+		this.canlender = canlender
+		this.weeks = weeks
+	}
+
+	//静态方法
+	// static init(date) {
+	// 	if (!this.instance) {
+	// 		this.instance = new Calendar(date);
+	// 	}
+	// 	return this.instance;
+	// }
+}
+
+
+export default Calendar

+ 398 - 0
components/uniNoticeBar/uni-notice-bar.vue

@@ -0,0 +1,398 @@
+<template>
+	<view v-if="show" class="uni-noticebar" :style="'background-color:'+backgroundColor+';width:'+(250-prConfig*2)*2+'rpx;'" @click="onClick">
+<!-- 		<uni-icons v-if="showIcon === true || showIcon === 'true'" class="uni-noticebar-icon" type="sound"
+			:color="color" size="22" /> -->
+		<view ref="textBox" class="uni-noticebar__content-wrapper"
+			:class="{'uni-noticebar__content-wrapper--scrollable':scrollable, 'uni-noticebar__content-wrapper--single':!scrollable && (single || moreText)}">
+			<view :id="elIdBox" class="uni-noticebar__content"
+				:class="{'uni-noticebar__content--scrollable':scrollable, 'uni-noticebar__content--single':!scrollable && (single || moreText)}">
+				<text :id="elId" ref="animationEle" class="uni-noticebar__content-text"
+					:class="{'uni-noticebar__content-text--scrollable':scrollable,'uni-noticebar__content-text--single':!scrollable && (single || showGetMore)}"
+					:style="{color:color, width:wrapWidth+'px', 'animationDuration': animationDuration, '-webkit-animationDuration': animationDuration ,animationPlayState: webviewHide?'paused':animationPlayState,'-webkit-animationPlayState':webviewHide?'paused':animationPlayState, animationDelay: animationDelay, '-webkit-animationDelay':animationDelay}">{{text}}</text>
+			</view>
+		</view>
+		<view v-if="showGetMore === true || showGetMore === 'true'" class="uni-noticebar__more uni-cursor-point"
+			@click="clickMore">
+			<text v-if="moreText.length > 0" :style="{ color: moreColor }" class="uni-noticebar__more-text">{{ moreText }}</text>
+			<!-- <uni-icons v-else type="right" :color="moreColor" size="16" /> -->
+		</view>
+		<view class="uni-noticebar-close uni-cursor-point" v-if="(showClose === true || showClose === 'true') && (showGetMore === false || showGetMore === 'false')">
+<!-- 			<uni-icons
+				type="closeempty" :color="color" size="16" @click="close" /> -->
+		</view>
+	</view>
+</template>
+
+<script>
+	// #ifdef APP-NVUE
+	const dom = weex.requireModule('dom');
+	const animation = weex.requireModule('animation');
+	// #endif
+
+	/**
+	 * NoticeBar 自定义导航栏
+	 * @description 通告栏组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=30
+	 * @property {Number} speed 文字滚动的速度,默认100px/秒
+	 * @property {String} text 显示文字
+	 * @property {String} backgroundColor 背景颜色
+	 * @property {String} color 文字颜色
+	 * @property {String} moreColor 查看更多文字的颜色
+	 * @property {String} moreText 设置“查看更多”的文本
+	 * @property {Boolean} single = [true|false] 是否单行
+	 * @property {Boolean} scrollable = [true|false] 是否滚动,为true时,NoticeBar为单行
+	 * @property {Boolean} showIcon = [true|false] 是否显示左侧喇叭图标
+	 * @property {Boolean} showClose = [true|false] 是否显示左侧关闭按钮
+	 * @property {Boolean} showGetMore = [true|false] 是否显示右侧查看更多图标,为true时,NoticeBar为单行
+	 * @event {Function} click 点击 NoticeBar 触发事件
+	 * @event {Function} close 关闭 NoticeBar 触发事件
+	 * @event {Function} getmore 点击”查看更多“时触发事件
+	 */
+
+	export default {
+		name: 'UniNoticeBar',
+		emits: ['click', 'getmore', 'close'],
+		props: {
+			prConfig: {
+				type: Number,
+				default: 0
+			},
+			text: {
+				type: String,
+				default: ''
+			},
+			moreText: {
+				type: String,
+				default: ''
+			},
+			backgroundColor: {
+				type: String,
+				default: '#FFF9EA'
+			},
+			speed: {
+				// 默认1s滚动100px
+				type: Number,
+				default: 100
+			},
+			color: {
+				type: String,
+				default: '#FF9A43'
+			},
+			moreColor: {
+				type: String,
+				default: '#FF9A43'
+			},
+			single: {
+				// 是否单行
+				type: [Boolean, String],
+				default: false
+			},
+			scrollable: {
+				// 是否滚动,添加后控制单行效果取消
+				type: [Boolean, String],
+				default: false
+			},
+			showIcon: {
+				// 是否显示左侧icon
+				type: [Boolean, String],
+				default: false
+			},
+			showGetMore: {
+				// 是否显示右侧查看更多
+				type: [Boolean, String],
+				default: false
+			},
+			showClose: {
+				// 是否显示左侧关闭按钮
+				type: [Boolean, String],
+				default: false
+			}
+		},
+		data() {
+			const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
+			const elIdBox = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
+			return {
+				textWidth: 0,
+				boxWidth: 0,
+				wrapWidth: '',
+				webviewHide: false,
+				// #ifdef APP-NVUE
+				stopAnimation: false,
+				// #endif
+				elId: elId,
+				elIdBox: elIdBox,
+				show: true,
+				animationDuration: 'none',
+				animationPlayState: 'paused',
+				animationDelay: '0s'
+			}
+		},
+		mounted() {
+			// #ifdef APP-PLUS
+			var pages = getCurrentPages();
+			var page = pages[pages.length - 1];
+			var currentWebview = page.$getAppWebview();
+			currentWebview.addEventListener('hide', () => {
+				this.webviewHide = true
+			})
+			currentWebview.addEventListener('show', () => {
+				this.webviewHide = false
+			})
+			// #endif
+			this.$nextTick(() => {
+				this.initSize()
+			})
+		},
+		// #ifdef APP-NVUE
+		beforeDestroy() {
+			this.stopAnimation = true
+		},
+		// #endif
+		methods: {
+			initSize() {
+				if (this.scrollable) {
+					// #ifndef APP-NVUE
+					let query = [],
+						boxWidth = 0,
+						textWidth = 0;
+					let textQuery = new Promise((resolve, reject) => {
+						uni.createSelectorQuery()
+							// #ifndef MP-ALIPAY
+							.in(this)
+							// #endif
+							.select(`#${this.elId}`)
+							.boundingClientRect()
+							.exec(ret => {
+								this.textWidth = ret[0].width
+								resolve()
+							})
+					})
+					let boxQuery = new Promise((resolve, reject) => {
+						uni.createSelectorQuery()
+							// #ifndef MP-ALIPAY
+							.in(this)
+							// #endif
+							.select(`#${this.elIdBox}`)
+							.boundingClientRect()
+							.exec(ret => {
+								this.boxWidth = ret[0].width
+								resolve()
+							})
+					})
+					query.push(textQuery)
+					query.push(boxQuery)
+					Promise.all(query).then(() => {
+						this.animationDuration = `${this.textWidth / this.speed}s`
+						this.animationDelay = `-${this.boxWidth / this.speed}s`
+						setTimeout(() => {
+							this.animationPlayState = 'running'
+						}, 1000)
+					})
+					// #endif
+					// #ifdef APP-NVUE
+					dom.getComponentRect(this.$refs['animationEle'], (res) => {
+						let winWidth = uni.getSystemInfoSync().windowWidth
+						this.textWidth = res.size.width
+						animation.transition(this.$refs['animationEle'], {
+							styles: {
+								transform: `translateX(-${winWidth}px)`
+							},
+							duration: 0,
+							timingFunction: 'linear',
+							delay: 0
+						}, () => {
+							if (!this.stopAnimation) {
+								animation.transition(this.$refs['animationEle'], {
+									styles: {
+										transform: `translateX(-${this.textWidth}px)`
+									},
+									timingFunction: 'linear',
+									duration: (this.textWidth - winWidth) / this.speed * 1000,
+									delay: 1000
+								}, () => {
+									if (!this.stopAnimation) {
+										this.loopAnimation()
+									}
+								});
+							}
+						});
+					})
+					// #endif
+				}
+				// #ifdef APP-NVUE
+				if (!this.scrollable && (this.single || this.moreText)) {
+					dom.getComponentRect(this.$refs['textBox'], (res) => {
+						this.wrapWidth = res.size.width
+					})
+				}
+				// #endif
+			},
+			loopAnimation() {
+				// #ifdef APP-NVUE
+				animation.transition(this.$refs['animationEle'], {
+					styles: {
+						transform: `translateX(0px)`
+					},
+					duration: 0
+				}, () => {
+					if (!this.stopAnimation) {
+						animation.transition(this.$refs['animationEle'], {
+							styles: {
+								transform: `translateX(-${this.textWidth}px)`
+							},
+							duration: this.textWidth / this.speed * 1000,
+							timingFunction: 'linear',
+							delay: 0
+						}, () => {
+							if (!this.stopAnimation) {
+								this.loopAnimation()
+							}
+						});
+					}
+				});
+				// #endif
+			},
+			clickMore() {
+				this.$emit('getmore')
+			},
+			close() {
+				this.show = false;
+				this.$emit('close')
+			},
+			onClick() {
+				this.$emit('click')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-noticebar {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		width: 100%;
+		box-sizing: border-box;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		width: 500rpx;
+	}
+
+	.uni-cursor-point {
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+	}
+
+	.uni-noticebar-close {
+		margin-left: 8px;
+		margin-right: 5px;
+	}
+
+	.uni-noticebar-icon {
+		margin-right: 5px;
+	}
+
+	.uni-noticebar__content-wrapper {
+		flex: 1;
+		flex-direction: column;
+		overflow: hidden;
+	}
+
+	.uni-noticebar__content-wrapper--single {
+		/* #ifndef APP-NVUE */
+		line-height: 18px;
+		/* #endif */
+	}
+
+	.uni-noticebar__content-wrapper--single,
+	.uni-noticebar__content-wrapper--scrollable {
+		flex-direction: row;
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-noticebar__content-wrapper--scrollable {
+		position: relative;
+		height: 18px;
+	}
+
+	/* #endif */
+
+	.uni-noticebar__content--scrollable {
+		/* #ifdef APP-NVUE */
+		flex: 0;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		flex: 1;
+		display: block;
+		overflow: hidden;
+		/* #endif */
+	}
+
+	.uni-noticebar__content--single {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		flex: none;
+		width: 100%;
+		justify-content: center;
+		/* #endif */
+	}
+
+	.uni-noticebar__content-text {
+		font-size: 14px;
+		line-height: 18px;
+		/* #ifndef APP-NVUE */
+		word-break: break-all;
+		/* #endif */
+	}
+
+	.uni-noticebar__content-text--single {
+		/* #ifdef APP-NVUE */
+		lines: 1;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		display: block;
+		width: 100%;
+		white-space: nowrap;
+		/* #endif */
+		overflow: hidden;
+		text-overflow: ellipsis;
+	}
+
+	.uni-noticebar__content-text--scrollable {
+		/* #ifdef APP-NVUE */
+		lines: 1;
+		padding-left: 750rpx;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		position: absolute;
+		display: block;
+		height: 18px;
+		line-height: 18px;
+		white-space: nowrap;
+		padding-left: 100%;
+		animation: notice 10s 0s linear infinite both;
+		animation-play-state: paused;
+		/* #endif */
+	}
+
+	.uni-noticebar__more {
+		/* #ifndef APP-NVUE */
+		display: inline-flex;
+		/* #endif */
+		flex-direction: row;
+		flex-wrap: nowrap;
+		align-items: center;
+		padding-left: 5px;
+	}
+
+	.uni-noticebar__more-text {
+		font-size: 14px;
+	}
+
+	@keyframes notice {
+		100% {
+			transform: translate3d(-100%, 0, 0);
+		}
+	}
+</style>

+ 253 - 0
components/userEvaluation/index.vue

@@ -0,0 +1,253 @@
+<template>
+	<!-- 评价列表 -->
+	<view class="evaluateWtapper">
+		<view class="evaluateItem" v-for="(item, indexw) in reply" :key="indexw" @click.stop="details(item)">
+			<view class="pic-text acea-row row-between-wrapper">
+				<view class="acea-row row-middle">
+					<view class="pictrue">
+						<image :src="item.avatar" mode="aspectFill"></image>
+					</view>
+					<view class="acea-row row-middle">
+						<view class="acea-row row-middle" style="margin-right: 15rpx;">
+							<view class="name line1">{{ item.nickname }}</view>
+							<view class="vipImg" v-if="item.is_money_level>0"><image src="../../static/images/vip.png"></image></view>
+						</view>
+					</view>
+				</view>
+				<view class="start" :class="'star' + item.star"></view>
+			</view>
+			<view class="time">{{ item.add_time }} {{ item.suk }}</view>
+			<view class="evaluate-infor">{{ item.comment }}</view>
+			<view class="imgList acea-row">
+				<view class="pictrue" :class="item.pics.length==1?'one':item.pics.length==2?'two':item.pics.length==3?'three':''" v-for="(itemn, indexn) in item.pics" :key="indexn">
+					<image :src="itemn" class="image" @click.stop='getpreviewImage(indexw, indexn)' mode="aspectFill"></image>
+				</view>
+			</view>
+			<view class="census acea-row row-between-wrapper" v-if="!fromTo">
+				<view>浏览{{item.views_num}}次</view>
+				<view class="icons acea-row row-middle">
+					<view>
+						<text class="iconfont icon-pinglun1"></text>{{item.replyComment?item.replyComment.sum:0}}
+					</view>
+					<view @click.stop="praise(item)">
+						<text class="icon iconfont" :class="item.is_praise?'icon-weizan font-num':'icon-zan'"></text>{{item.praise}}
+					</view>
+					<!-- #ifdef H5 || APP-PLUS -->
+					<slot name="bottom" :item="item"></slot>
+					<!-- #endif -->
+					<!-- #ifdef MP -->
+					<slot name="bottom{{indexw}}"></slot>
+					<!-- #endif -->
+				</view>
+			</view>
+			<view class="reply" v-if="item.replyComment && !fromTo">
+				<text :class="item.replyComment.uid?'':'font-num'">{{item.replyComment.user?item.replyComment.user.nickname:''}}</text><text class="store" v-if="!item.replyComment.uid">商家</text>:{{
+          item.replyComment.content
+        }}
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+	import {
+		mapGetters
+	} from 'vuex';
+	import {
+		getReplyPraise,
+		getUnReplyPraise
+	} from '@/api/store.js';
+	export default {
+		computed: mapGetters(['isLogin']),
+		props: {
+			reply: {
+				type: Array,
+				default: () => []
+			},
+			fromTo: {
+				type: Number,
+				default: 0
+			}
+		},
+		data: function() {
+			return {};
+		},
+		methods: {
+			details(item){
+				if(this.isLogin){
+					uni.navigateTo({
+						url: '/pages/goods/goods_comment_con/comment_con?id=' + item.id
+					})
+				}else{
+					this.$emit('changeLogin');
+				}
+			},
+			getpreviewImage: function(indexw, indexn) {
+				uni.previewImage({
+					urls: this.reply[indexw].pics,
+					current: this.reply[indexw].pics[indexn]
+				});
+			},
+			praise(item){
+				if(this.isLogin){
+					if (item.is_praise) {
+						getUnReplyPraise(item.id).then(res => {
+							item.is_praise = !item.is_praise
+							item.praise = item.praise - 1
+							return this.$util.Tips({
+								title: res.msg
+							});
+						});
+					} else {
+						getReplyPraise(item.id).then(res => {
+							item.is_praise = !item.is_praise
+							item.praise = item.praise + 1
+							return this.$util.Tips({
+								title: res.msg
+							});
+						});
+					}
+				}else{
+					this.$emit('changeLogin');
+				}
+			}
+		}
+	}
+</script>
+<style scoped lang='scss'>
+	.vipImg{
+		width: 56rpx;
+		height: 20rpx;
+		margin-left: 10rpx;
+		image{
+			width: 100%;
+			height: 100%;
+			display: block;
+		}
+	}
+	.evaluateWtapper .census{
+		padding: 0 20rpx;
+		font-size: 22rpx;
+		color: #999;
+	}
+	.evaluateWtapper .census .iconfont{
+		margin-right: 6rpx;
+	}
+	.evaluateWtapper .census .icons{
+		color: #333;
+	}
+	.evaluateWtapper .census .icon{
+		margin-left: 40rpx;
+	}
+	.evaluateWtapper .evaluateItem {
+		background-color: #fff;
+		padding-bottom: 25rpx;
+		margin: 0 20rpx 20rpx 20rpx;
+		border-radius: 12rpx;
+	}
+
+	.evaluateWtapper .evaluateItem~.evaluateItem {
+		/* border-top: 1rpx solid #f5f5f5; */
+	}
+
+	.evaluateWtapper .evaluateItem .pic-text {
+		font-size: 26rpx;
+		color: #282828;
+		height: 95rpx;
+		padding: 0 20rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .pic-text .pictrue {
+		width: 56rpx;
+		height: 56rpx;
+		margin-right: 20rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .pic-text .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 50%;
+	}
+
+	.evaluateWtapper .evaluateItem .pic-text .name {
+		max-width: 450rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .time {
+		font-size: 24rpx;
+		color: #82848f;
+		padding: 0 20rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .evaluate-infor {
+		font-size: 28rpx;
+		color: #282828;
+		margin-top: 19rpx;
+		padding: 0 20rpx;
+		word-break: break-all;
+	}
+
+	.evaluateWtapper .evaluateItem .imgList {
+		padding: 0 20rpx 0 6rpx;
+		margin-top: 25rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .imgList .pictrue {
+		width: 156rpx;
+		height: 156rpx;
+		margin: 0 0 15rpx 15rpx;
+		border-radius: 12rpx;
+	}
+	
+	.evaluateWtapper .evaluateItem .imgList .pictrue.one{
+		width: 400rpx;
+		height: 400rpx;
+	}
+	
+	.evaluateWtapper .evaluateItem .imgList .pictrue.two{
+		width: 324rpx;
+		height: 324rpx;
+	}
+	
+	.evaluateWtapper .evaluateItem .imgList .pictrue.three{
+		width: 214rpx;
+		height: 214rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .imgList .pictrue image {
+		width: 100%;
+		height: 100%;
+		background-color: #f7f7f7;
+		border-radius: 12rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .reply {
+		font-size: 26rpx;
+		color: #454545;
+		background-color: #f7f7f7;
+		border-radius: 5rpx;
+		margin: 20rpx 30rpx 0 30rpx;
+		padding: 20rpx;
+		position: relative;
+		word-break: break-all;
+		.store{
+			background-color: var(--view-theme);
+			font-size: 12rpx;
+			color: #fff;
+			border-radius: 15rpx;
+			padding: 2rpx 5rpx;
+			margin-left: 10rpx;
+		}
+	}
+
+	.evaluateWtapper .evaluateItem .reply::before {
+		content: "";
+		width: 0;
+		height: 0;
+		border-left: 20rpx solid transparent;
+		border-right: 20rpx solid transparent;
+		border-bottom: 30rpx solid #f7f7f7;
+		position: absolute;
+		top: -14rpx;
+		left: 40rpx;
+	}
+</style>

+ 11 - 0
components/verify/utils/ase.js

@@ -0,0 +1,11 @@
+import CryptoJS from './crypto-js.js'
+/**
+ * @word 要加密的内容
+ * @keyWord String  服务器随机返回的关键字
+ *  */
+export function aesEncrypt(word,keyWord="XwKsGlMcdPMEhR1B"){
+  var key = CryptoJS.enc.Utf8.parse(keyWord);
+  var srcs = CryptoJS.enc.Utf8.parse(word);
+  var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
+  return encrypted.toString();
+}

+ 6191 - 0
components/verify/utils/crypto-js.js

@@ -0,0 +1,6191 @@
+;(function (root, factory) {
+	if (typeof exports === "object") {
+		// CommonJS
+		module.exports = exports = factory();
+	}
+	else if (typeof define === "function" && define.amd) {
+		// AMD
+		define([], factory);
+	}
+	else {
+		// Global (browser)
+		root.CryptoJS = factory();
+	}
+}(this, function () {
+
+	/*globals window, global, require*/
+
+	/**
+	 * CryptoJS core components.
+	 */
+	var CryptoJS = CryptoJS || (function (Math, undefined) {
+
+	    var crypto;
+
+	    // Native crypto from window (Browser)
+	    if (typeof window !== 'undefined' && window.crypto) {
+	        crypto = window.crypto;
+	    }
+
+	    // Native crypto in web worker (Browser)
+	    if (typeof self !== 'undefined' && self.crypto) {
+	        crypto = self.crypto;
+	    }
+
+	    // Native crypto from worker
+	    if (typeof globalThis !== 'undefined' && globalThis.crypto) {
+	        crypto = globalThis.crypto;
+	    }
+
+	    // Native (experimental IE 11) crypto from window (Browser)
+	    if (!crypto && typeof window !== 'undefined' && window.msCrypto) {
+	        crypto = window.msCrypto;
+	    }
+
+	    // Native crypto from global (NodeJS)
+	    if (!crypto && typeof global !== 'undefined' && global.crypto) {
+	        crypto = global.crypto;
+	    }
+
+	    // Native crypto import via require (NodeJS)
+	    if (!crypto && typeof require === 'function') {
+	        try {
+	            crypto = require('crypto');
+	        } catch (err) {}
+	    }
+
+	    /*
+	     * Cryptographically secure pseudorandom number generator
+	     *
+	     * As Math.random() is cryptographically not safe to use
+	     */
+	    var cryptoSecureRandomInt = function () {
+	        if (crypto) {
+	            // Use getRandomValues method (Browser)
+	            if (typeof crypto.getRandomValues === 'function') {
+	                try {
+	                    return crypto.getRandomValues(new Uint32Array(1))[0];
+	                } catch (err) {}
+	            }
+
+	            // Use randomBytes method (NodeJS)
+	            if (typeof crypto.randomBytes === 'function') {
+	                try {
+	                    return crypto.randomBytes(4).readInt32LE();
+	                } catch (err) {}
+	            }
+	        }
+
+	        throw new Error('Native crypto module could not be used to get secure random number.');
+	    };
+
+	    /*
+	     * Local polyfill of Object.create
+
+	     */
+	    var create = Object.create || (function () {
+	        function F() {}
+
+	        return function (obj) {
+	            var subtype;
+
+	            F.prototype = obj;
+
+	            subtype = new F();
+
+	            F.prototype = null;
+
+	            return subtype;
+	        };
+	    }());
+
+	    /**
+	     * CryptoJS namespace.
+	     */
+	    var C = {};
+
+	    /**
+	     * Library namespace.
+	     */
+	    var C_lib = C.lib = {};
+
+	    /**
+	     * Base object for prototypal inheritance.
+	     */
+	    var Base = C_lib.Base = (function () {
+
+
+	        return {
+	            /**
+	             * Creates a new object that inherits from this object.
+	             *
+	             * @param {Object} overrides Properties to copy into the new object.
+	             *
+	             * @return {Object} The new object.
+	             *
+	             * @static
+	             *
+	             * @example
+	             *
+	             *     var MyType = CryptoJS.lib.Base.extend({
+	             *         field: 'value',
+	             *
+	             *         method: function () {
+	             *         }
+	             *     });
+	             */
+	            extend: function (overrides) {
+	                // Spawn
+	                var subtype = create(this);
+
+	                // Augment
+	                if (overrides) {
+	                    subtype.mixIn(overrides);
+	                }
+
+	                // Create default initializer
+	                if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
+	                    subtype.init = function () {
+	                        subtype.$super.init.apply(this, arguments);
+	                    };
+	                }
+
+	                // Initializer's prototype is the subtype object
+	                subtype.init.prototype = subtype;
+
+	                // Reference supertype
+	                subtype.$super = this;
+
+	                return subtype;
+	            },
+
+	            /**
+	             * Extends this object and runs the init method.
+	             * Arguments to create() will be passed to init().
+	             *
+	             * @return {Object} The new object.
+	             *
+	             * @static
+	             *
+	             * @example
+	             *
+	             *     var instance = MyType.create();
+	             */
+	            create: function () {
+	                var instance = this.extend();
+	                instance.init.apply(instance, arguments);
+
+	                return instance;
+	            },
+
+	            /**
+	             * Initializes a newly created object.
+	             * Override this method to add some logic when your objects are created.
+	             *
+	             * @example
+	             *
+	             *     var MyType = CryptoJS.lib.Base.extend({
+	             *         init: function () {
+	             *             // ...
+	             *         }
+	             *     });
+	             */
+	            init: function () {
+	            },
+
+	            /**
+	             * Copies properties into this object.
+	             *
+	             * @param {Object} properties The properties to mix in.
+	             *
+	             * @example
+	             *
+	             *     MyType.mixIn({
+	             *         field: 'value'
+	             *     });
+	             */
+	            mixIn: function (properties) {
+	                for (var propertyName in properties) {
+	                    if (properties.hasOwnProperty(propertyName)) {
+	                        this[propertyName] = properties[propertyName];
+	                    }
+	                }
+
+	                // IE won't copy toString using the loop above
+	                if (properties.hasOwnProperty('toString')) {
+	                    this.toString = properties.toString;
+	                }
+	            },
+
+	            /**
+	             * Creates a copy of this object.
+	             *
+	             * @return {Object} The clone.
+	             *
+	             * @example
+	             *
+	             *     var clone = instance.clone();
+	             */
+	            clone: function () {
+	                return this.init.prototype.extend(this);
+	            }
+	        };
+	    }());
+
+	    /**
+	     * An array of 32-bit words.
+	     *
+	     * @property {Array} words The array of 32-bit words.
+	     * @property {number} sigBytes The number of significant bytes in this word array.
+	     */
+	    var WordArray = C_lib.WordArray = Base.extend({
+	        /**
+	         * Initializes a newly created word array.
+	         *
+	         * @param {Array} words (Optional) An array of 32-bit words.
+	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.lib.WordArray.create();
+	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
+	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
+	         */
+	        init: function (words, sigBytes) {
+	            words = this.words = words || [];
+
+	            if (sigBytes != undefined) {
+	                this.sigBytes = sigBytes;
+	            } else {
+	                this.sigBytes = words.length * 4;
+	            }
+	        },
+
+	        /**
+	         * Converts this word array to a string.
+	         *
+	         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
+	         *
+	         * @return {string} The stringified word array.
+	         *
+	         * @example
+	         *
+	         *     var string = wordArray + '';
+	         *     var string = wordArray.toString();
+	         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
+	         */
+	        toString: function (encoder) {
+	            return (encoder || Hex).stringify(this);
+	        },
+
+	        /**
+	         * Concatenates a word array to this word array.
+	         *
+	         * @param {WordArray} wordArray The word array to append.
+	         *
+	         * @return {WordArray} This word array.
+	         *
+	         * @example
+	         *
+	         *     wordArray1.concat(wordArray2);
+	         */
+	        concat: function (wordArray) {
+	            // Shortcuts
+	            var thisWords = this.words;
+	            var thatWords = wordArray.words;
+	            var thisSigBytes = this.sigBytes;
+	            var thatSigBytes = wordArray.sigBytes;
+
+	            // Clamp excess bits
+	            this.clamp();
+
+	            // Concat
+	            if (thisSigBytes % 4) {
+	                // Copy one byte at a time
+	                for (var i = 0; i < thatSigBytes; i++) {
+	                    var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                    thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
+	                }
+	            } else {
+	                // Copy one word at a time
+	                for (var j = 0; j < thatSigBytes; j += 4) {
+	                    thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2];
+	                }
+	            }
+	            this.sigBytes += thatSigBytes;
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Removes insignificant bits.
+	         *
+	         * @example
+	         *
+	         *     wordArray.clamp();
+	         */
+	        clamp: function () {
+	            // Shortcuts
+	            var words = this.words;
+	            var sigBytes = this.sigBytes;
+
+	            // Clamp
+	            words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
+	            words.length = Math.ceil(sigBytes / 4);
+	        },
+
+	        /**
+	         * Creates a copy of this word array.
+	         *
+	         * @return {WordArray} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = wordArray.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+	            clone.words = this.words.slice(0);
+
+	            return clone;
+	        },
+
+	        /**
+	         * Creates a word array filled with random bytes.
+	         *
+	         * @param {number} nBytes The number of random bytes to generate.
+	         *
+	         * @return {WordArray} The random word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.lib.WordArray.random(16);
+	         */
+	        random: function (nBytes) {
+	            var words = [];
+
+	            for (var i = 0; i < nBytes; i += 4) {
+	                words.push(cryptoSecureRandomInt());
+	            }
+
+	            return new WordArray.init(words, nBytes);
+	        }
+	    });
+
+	    /**
+	     * Encoder namespace.
+	     */
+	    var C_enc = C.enc = {};
+
+	    /**
+	     * Hex encoding strategy.
+	     */
+	    var Hex = C_enc.Hex = {
+	        /**
+	         * Converts a word array to a hex string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The hex string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var hexChars = [];
+	            for (var i = 0; i < sigBytes; i++) {
+	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                hexChars.push((bite >>> 4).toString(16));
+	                hexChars.push((bite & 0x0f).toString(16));
+	            }
+
+	            return hexChars.join('');
+	        },
+
+	        /**
+	         * Converts a hex string to a word array.
+	         *
+	         * @param {string} hexStr The hex string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
+	         */
+	        parse: function (hexStr) {
+	            // Shortcut
+	            var hexStrLength = hexStr.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < hexStrLength; i += 2) {
+	                words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
+	            }
+
+	            return new WordArray.init(words, hexStrLength / 2);
+	        }
+	    };
+
+	    /**
+	     * Latin1 encoding strategy.
+	     */
+	    var Latin1 = C_enc.Latin1 = {
+	        /**
+	         * Converts a word array to a Latin1 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The Latin1 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var latin1Chars = [];
+	            for (var i = 0; i < sigBytes; i++) {
+	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                latin1Chars.push(String.fromCharCode(bite));
+	            }
+
+	            return latin1Chars.join('');
+	        },
+
+	        /**
+	         * Converts a Latin1 string to a word array.
+	         *
+	         * @param {string} latin1Str The Latin1 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
+	         */
+	        parse: function (latin1Str) {
+	            // Shortcut
+	            var latin1StrLength = latin1Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < latin1StrLength; i++) {
+	                words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
+	            }
+
+	            return new WordArray.init(words, latin1StrLength);
+	        }
+	    };
+
+	    /**
+	     * UTF-8 encoding strategy.
+	     */
+	    var Utf8 = C_enc.Utf8 = {
+	        /**
+	         * Converts a word array to a UTF-8 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-8 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            try {
+	                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
+	            } catch (e) {
+	                throw new Error('Malformed UTF-8 data');
+	            }
+	        },
+
+	        /**
+	         * Converts a UTF-8 string to a word array.
+	         *
+	         * @param {string} utf8Str The UTF-8 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
+	         */
+	        parse: function (utf8Str) {
+	            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
+	        }
+	    };
+
+	    /**
+	     * Abstract buffered block algorithm template.
+	     *
+	     * The property blockSize must be implemented in a concrete subtype.
+	     *
+	     * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
+	     */
+	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
+	        /**
+	         * Resets this block algorithm's data buffer to its initial state.
+	         *
+	         * @example
+	         *
+	         *     bufferedBlockAlgorithm.reset();
+	         */
+	        reset: function () {
+	            // Initial values
+	            this._data = new WordArray.init();
+	            this._nDataBytes = 0;
+	        },
+
+	        /**
+	         * Adds new data to this block algorithm's buffer.
+	         *
+	         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
+	         *
+	         * @example
+	         *
+	         *     bufferedBlockAlgorithm._append('data');
+	         *     bufferedBlockAlgorithm._append(wordArray);
+	         */
+	        _append: function (data) {
+	            // Convert string to WordArray, else assume WordArray already
+	            if (typeof data == 'string') {
+	                data = Utf8.parse(data);
+	            }
+
+	            // Append
+	            this._data.concat(data);
+	            this._nDataBytes += data.sigBytes;
+	        },
+
+	        /**
+	         * Processes available data blocks.
+	         *
+	         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
+	         *
+	         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
+	         *
+	         * @return {WordArray} The processed data.
+	         *
+	         * @example
+	         *
+	         *     var processedData = bufferedBlockAlgorithm._process();
+	         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
+	         */
+	        _process: function (doFlush) {
+	            var processedWords;
+
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+	            var dataSigBytes = data.sigBytes;
+	            var blockSize = this.blockSize;
+	            var blockSizeBytes = blockSize * 4;
+
+	            // Count blocks ready
+	            var nBlocksReady = dataSigBytes / blockSizeBytes;
+	            if (doFlush) {
+	                // Round up to include partial blocks
+	                nBlocksReady = Math.ceil(nBlocksReady);
+	            } else {
+	                // Round down to include only full blocks,
+	                // less the number of blocks that must remain in the buffer
+	                nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
+	            }
+
+	            // Count words ready
+	            var nWordsReady = nBlocksReady * blockSize;
+
+	            // Count bytes ready
+	            var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
+
+	            // Process blocks
+	            if (nWordsReady) {
+	                for (var offset = 0; offset < nWordsReady; offset += blockSize) {
+	                    // Perform concrete-algorithm logic
+	                    this._doProcessBlock(dataWords, offset);
+	                }
+
+	                // Remove processed words
+	                processedWords = dataWords.splice(0, nWordsReady);
+	                data.sigBytes -= nBytesReady;
+	            }
+
+	            // Return processed words
+	            return new WordArray.init(processedWords, nBytesReady);
+	        },
+
+	        /**
+	         * Creates a copy of this object.
+	         *
+	         * @return {Object} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = bufferedBlockAlgorithm.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+	            clone._data = this._data.clone();
+
+	            return clone;
+	        },
+
+	        _minBufferSize: 0
+	    });
+
+	    /**
+	     * Abstract hasher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
+	     */
+	    var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
+	        /**
+	         * Configuration options.
+	         */
+	        cfg: Base.extend(),
+
+	        /**
+	         * Initializes a newly created hasher.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
+	         *
+	         * @example
+	         *
+	         *     var hasher = CryptoJS.algo.SHA256.create();
+	         */
+	        init: function (cfg) {
+	            // Apply config defaults
+	            this.cfg = this.cfg.extend(cfg);
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this hasher to its initial state.
+	         *
+	         * @example
+	         *
+	         *     hasher.reset();
+	         */
+	        reset: function () {
+	            // Reset data buffer
+	            BufferedBlockAlgorithm.reset.call(this);
+
+	            // Perform concrete-hasher logic
+	            this._doReset();
+	        },
+
+	        /**
+	         * Updates this hasher with a message.
+	         *
+	         * @param {WordArray|string} messageUpdate The message to append.
+	         *
+	         * @return {Hasher} This hasher.
+	         *
+	         * @example
+	         *
+	         *     hasher.update('message');
+	         *     hasher.update(wordArray);
+	         */
+	        update: function (messageUpdate) {
+	            // Append
+	            this._append(messageUpdate);
+
+	            // Update the hash
+	            this._process();
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Finalizes the hash computation.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
+	         *
+	         * @return {WordArray} The hash.
+	         *
+	         * @example
+	         *
+	         *     var hash = hasher.finalize();
+	         *     var hash = hasher.finalize('message');
+	         *     var hash = hasher.finalize(wordArray);
+	         */
+	        finalize: function (messageUpdate) {
+	            // Final message update
+	            if (messageUpdate) {
+	                this._append(messageUpdate);
+	            }
+
+	            // Perform concrete-hasher logic
+	            var hash = this._doFinalize();
+
+	            return hash;
+	        },
+
+	        blockSize: 512/32,
+
+	        /**
+	         * Creates a shortcut function to a hasher's object interface.
+	         *
+	         * @param {Hasher} hasher The hasher to create a helper for.
+	         *
+	         * @return {Function} The shortcut function.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
+	         */
+	        _createHelper: function (hasher) {
+	            return function (message, cfg) {
+	                return new hasher.init(cfg).finalize(message);
+	            };
+	        },
+
+	        /**
+	         * Creates a shortcut function to the HMAC's object interface.
+	         *
+	         * @param {Hasher} hasher The hasher to use in this HMAC helper.
+	         *
+	         * @return {Function} The shortcut function.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
+	         */
+	        _createHmacHelper: function (hasher) {
+	            return function (message, key) {
+	                return new C_algo.HMAC.init(hasher, key).finalize(message);
+	            };
+	        }
+	    });
+
+	    /**
+	     * Algorithm namespace.
+	     */
+	    var C_algo = C.algo = {};
+
+	    return C;
+	}(Math));
+
+
+	(function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var X32WordArray = C_lib.WordArray;
+
+	    /**
+	     * x64 namespace.
+	     */
+	    var C_x64 = C.x64 = {};
+
+	    /**
+	     * A 64-bit word.
+	     */
+	    var X64Word = C_x64.Word = Base.extend({
+	        /**
+	         * Initializes a newly created 64-bit word.
+	         *
+	         * @param {number} high The high 32 bits.
+	         * @param {number} low The low 32 bits.
+	         *
+	         * @example
+	         *
+	         *     var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607);
+	         */
+	        init: function (high, low) {
+	            this.high = high;
+	            this.low = low;
+	        }
+
+	        /**
+	         * Bitwise NOTs this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after negating.
+	         *
+	         * @example
+	         *
+	         *     var negated = x64Word.not();
+	         */
+	        // not: function () {
+	            // var high = ~this.high;
+	            // var low = ~this.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise ANDs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to AND with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after ANDing.
+	         *
+	         * @example
+	         *
+	         *     var anded = x64Word.and(anotherX64Word);
+	         */
+	        // and: function (word) {
+	            // var high = this.high & word.high;
+	            // var low = this.low & word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise ORs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to OR with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after ORing.
+	         *
+	         * @example
+	         *
+	         *     var ored = x64Word.or(anotherX64Word);
+	         */
+	        // or: function (word) {
+	            // var high = this.high | word.high;
+	            // var low = this.low | word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise XORs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to XOR with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after XORing.
+	         *
+	         * @example
+	         *
+	         *     var xored = x64Word.xor(anotherX64Word);
+	         */
+	        // xor: function (word) {
+	            // var high = this.high ^ word.high;
+	            // var low = this.low ^ word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Shifts this word n bits to the left.
+	         *
+	         * @param {number} n The number of bits to shift.
+	         *
+	         * @return {X64Word} A new x64-Word object after shifting.
+	         *
+	         * @example
+	         *
+	         *     var shifted = x64Word.shiftL(25);
+	         */
+	        // shiftL: function (n) {
+	            // if (n < 32) {
+	                // var high = (this.high << n) | (this.low >>> (32 - n));
+	                // var low = this.low << n;
+	            // } else {
+	                // var high = this.low << (n - 32);
+	                // var low = 0;
+	            // }
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Shifts this word n bits to the right.
+	         *
+	         * @param {number} n The number of bits to shift.
+	         *
+	         * @return {X64Word} A new x64-Word object after shifting.
+	         *
+	         * @example
+	         *
+	         *     var shifted = x64Word.shiftR(7);
+	         */
+	        // shiftR: function (n) {
+	            // if (n < 32) {
+	                // var low = (this.low >>> n) | (this.high << (32 - n));
+	                // var high = this.high >>> n;
+	            // } else {
+	                // var low = this.high >>> (n - 32);
+	                // var high = 0;
+	            // }
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Rotates this word n bits to the left.
+	         *
+	         * @param {number} n The number of bits to rotate.
+	         *
+	         * @return {X64Word} A new x64-Word object after rotating.
+	         *
+	         * @example
+	         *
+	         *     var rotated = x64Word.rotL(25);
+	         */
+	        // rotL: function (n) {
+	            // return this.shiftL(n).or(this.shiftR(64 - n));
+	        // },
+
+	        /**
+	         * Rotates this word n bits to the right.
+	         *
+	         * @param {number} n The number of bits to rotate.
+	         *
+	         * @return {X64Word} A new x64-Word object after rotating.
+	         *
+	         * @example
+	         *
+	         *     var rotated = x64Word.rotR(7);
+	         */
+	        // rotR: function (n) {
+	            // return this.shiftR(n).or(this.shiftL(64 - n));
+	        // },
+
+	        /**
+	         * Adds this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to add with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after adding.
+	         *
+	         * @example
+	         *
+	         *     var added = x64Word.add(anotherX64Word);
+	         */
+	        // add: function (word) {
+	            // var low = (this.low + word.low) | 0;
+	            // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0;
+	            // var high = (this.high + word.high + carry) | 0;
+
+	            // return X64Word.create(high, low);
+	        // }
+	    });
+
+	    /**
+	     * An array of 64-bit words.
+	     *
+	     * @property {Array} words The array of CryptoJS.x64.Word objects.
+	     * @property {number} sigBytes The number of significant bytes in this word array.
+	     */
+	    var X64WordArray = C_x64.WordArray = Base.extend({
+	        /**
+	         * Initializes a newly created word array.
+	         *
+	         * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects.
+	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create();
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create([
+	         *         CryptoJS.x64.Word.create(0x00010203, 0x04050607),
+	         *         CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
+	         *     ]);
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create([
+	         *         CryptoJS.x64.Word.create(0x00010203, 0x04050607),
+	         *         CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
+	         *     ], 10);
+	         */
+	        init: function (words, sigBytes) {
+	            words = this.words = words || [];
+
+	            if (sigBytes != undefined) {
+	                this.sigBytes = sigBytes;
+	            } else {
+	                this.sigBytes = words.length * 8;
+	            }
+	        },
+
+	        /**
+	         * Converts this 64-bit word array to a 32-bit word array.
+	         *
+	         * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array.
+	         *
+	         * @example
+	         *
+	         *     var x32WordArray = x64WordArray.toX32();
+	         */
+	        toX32: function () {
+	            // Shortcuts
+	            var x64Words = this.words;
+	            var x64WordsLength = x64Words.length;
+
+	            // Convert
+	            var x32Words = [];
+	            for (var i = 0; i < x64WordsLength; i++) {
+	                var x64Word = x64Words[i];
+	                x32Words.push(x64Word.high);
+	                x32Words.push(x64Word.low);
+	            }
+
+	            return X32WordArray.create(x32Words, this.sigBytes);
+	        },
+
+	        /**
+	         * Creates a copy of this word array.
+	         *
+	         * @return {X64WordArray} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = x64WordArray.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+
+	            // Clone "words" array
+	            var words = clone.words = this.words.slice(0);
+
+	            // Clone each X64Word object
+	            var wordsLength = words.length;
+	            for (var i = 0; i < wordsLength; i++) {
+	                words[i] = words[i].clone();
+	            }
+
+	            return clone;
+	        }
+	    });
+	}());
+
+
+	(function () {
+	    // Check if typed arrays are supported
+	    if (typeof ArrayBuffer != 'function') {
+	        return;
+	    }
+
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+
+	    // Reference original init
+	    var superInit = WordArray.init;
+
+	    // Augment WordArray.init to handle typed arrays
+	    var subInit = WordArray.init = function (typedArray) {
+	        // Convert buffers to uint8
+	        if (typedArray instanceof ArrayBuffer) {
+	            typedArray = new Uint8Array(typedArray);
+	        }
+
+	        // Convert other array views to uint8
+	        if (
+	            typedArray instanceof Int8Array ||
+	            (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) ||
+	            typedArray instanceof Int16Array ||
+	            typedArray instanceof Uint16Array ||
+	            typedArray instanceof Int32Array ||
+	            typedArray instanceof Uint32Array ||
+	            typedArray instanceof Float32Array ||
+	            typedArray instanceof Float64Array
+	        ) {
+	            typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);
+	        }
+
+	        // Handle Uint8Array
+	        if (typedArray instanceof Uint8Array) {
+	            // Shortcut
+	            var typedArrayByteLength = typedArray.byteLength;
+
+	            // Extract bytes
+	            var words = [];
+	            for (var i = 0; i < typedArrayByteLength; i++) {
+	                words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);
+	            }
+
+	            // Initialize this word array
+	            superInit.call(this, words, typedArrayByteLength);
+	        } else {
+	            // Else call normal init
+	            superInit.apply(this, arguments);
+	        }
+	    };
+
+	    subInit.prototype = WordArray;
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_enc = C.enc;
+
+	    /**
+	     * UTF-16 BE encoding strategy.
+	     */
+	    var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = {
+	        /**
+	         * Converts a word array to a UTF-16 BE string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-16 BE string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf16String = CryptoJS.enc.Utf16.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var utf16Chars = [];
+	            for (var i = 0; i < sigBytes; i += 2) {
+	                var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff;
+	                utf16Chars.push(String.fromCharCode(codePoint));
+	            }
+
+	            return utf16Chars.join('');
+	        },
+
+	        /**
+	         * Converts a UTF-16 BE string to a word array.
+	         *
+	         * @param {string} utf16Str The UTF-16 BE string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf16.parse(utf16String);
+	         */
+	        parse: function (utf16Str) {
+	            // Shortcut
+	            var utf16StrLength = utf16Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < utf16StrLength; i++) {
+	                words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16);
+	            }
+
+	            return WordArray.create(words, utf16StrLength * 2);
+	        }
+	    };
+
+	    /**
+	     * UTF-16 LE encoding strategy.
+	     */
+	    C_enc.Utf16LE = {
+	        /**
+	         * Converts a word array to a UTF-16 LE string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-16 LE string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var utf16Chars = [];
+	            for (var i = 0; i < sigBytes; i += 2) {
+	                var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff);
+	                utf16Chars.push(String.fromCharCode(codePoint));
+	            }
+
+	            return utf16Chars.join('');
+	        },
+
+	        /**
+	         * Converts a UTF-16 LE string to a word array.
+	         *
+	         * @param {string} utf16Str The UTF-16 LE string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str);
+	         */
+	        parse: function (utf16Str) {
+	            // Shortcut
+	            var utf16StrLength = utf16Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < utf16StrLength; i++) {
+	                words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16));
+	            }
+
+	            return WordArray.create(words, utf16StrLength * 2);
+	        }
+	    };
+
+	    function swapEndian(word) {
+	        return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff);
+	    }
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_enc = C.enc;
+
+	    /**
+	     * Base64 encoding strategy.
+	     */
+	    var Base64 = C_enc.Base64 = {
+	        /**
+	         * Converts a word array to a Base64 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The Base64 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var base64String = CryptoJS.enc.Base64.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+	            var map = this._map;
+
+	            // Clamp excess bits
+	            wordArray.clamp();
+
+	            // Convert
+	            var base64Chars = [];
+	            for (var i = 0; i < sigBytes; i += 3) {
+	                var byte1 = (words[i >>> 2]       >>> (24 - (i % 4) * 8))       & 0xff;
+	                var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;
+	                var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;
+
+	                var triplet = (byte1 << 16) | (byte2 << 8) | byte3;
+
+	                for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {
+	                    base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));
+	                }
+	            }
+
+	            // Add padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                while (base64Chars.length % 4) {
+	                    base64Chars.push(paddingChar);
+	                }
+	            }
+
+	            return base64Chars.join('');
+	        },
+
+	        /**
+	         * Converts a Base64 string to a word array.
+	         *
+	         * @param {string} base64Str The Base64 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Base64.parse(base64String);
+	         */
+	        parse: function (base64Str) {
+	            // Shortcuts
+	            var base64StrLength = base64Str.length;
+	            var map = this._map;
+	            var reverseMap = this._reverseMap;
+
+	            if (!reverseMap) {
+	                    reverseMap = this._reverseMap = [];
+	                    for (var j = 0; j < map.length; j++) {
+	                        reverseMap[map.charCodeAt(j)] = j;
+	                    }
+	            }
+
+	            // Ignore padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                var paddingIndex = base64Str.indexOf(paddingChar);
+	                if (paddingIndex !== -1) {
+	                    base64StrLength = paddingIndex;
+	                }
+	            }
+
+	            // Convert
+	            return parseLoop(base64Str, base64StrLength, reverseMap);
+
+	        },
+
+	        _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
+	    };
+
+	    function parseLoop(base64Str, base64StrLength, reverseMap) {
+	      var words = [];
+	      var nBytes = 0;
+	      for (var i = 0; i < base64StrLength; i++) {
+	          if (i % 4) {
+	              var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);
+	              var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);
+	              var bitsCombined = bits1 | bits2;
+	              words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8);
+	              nBytes++;
+	          }
+	      }
+	      return WordArray.create(words, nBytes);
+	    }
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_enc = C.enc;
+
+	    /**
+	     * Base64url encoding strategy.
+	     */
+	    var Base64url = C_enc.Base64url = {
+	        /**
+	         * Converts a word array to a Base64url string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @param {boolean} urlSafe Whether to use url safe
+	         *
+	         * @return {string} The Base64url string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var base64String = CryptoJS.enc.Base64url.stringify(wordArray);
+	         */
+	        stringify: function (wordArray, urlSafe=true) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+	            var map = urlSafe ? this._safe_map : this._map;
+
+	            // Clamp excess bits
+	            wordArray.clamp();
+
+	            // Convert
+	            var base64Chars = [];
+	            for (var i = 0; i < sigBytes; i += 3) {
+	                var byte1 = (words[i >>> 2]       >>> (24 - (i % 4) * 8))       & 0xff;
+	                var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;
+	                var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;
+
+	                var triplet = (byte1 << 16) | (byte2 << 8) | byte3;
+
+	                for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {
+	                    base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));
+	                }
+	            }
+
+	            // Add padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                while (base64Chars.length % 4) {
+	                    base64Chars.push(paddingChar);
+	                }
+	            }
+
+	            return base64Chars.join('');
+	        },
+
+	        /**
+	         * Converts a Base64url string to a word array.
+	         *
+	         * @param {string} base64Str The Base64url string.
+	         *
+	         * @param {boolean} urlSafe Whether to use url safe
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Base64url.parse(base64String);
+	         */
+	        parse: function (base64Str, urlSafe=true) {
+	            // Shortcuts
+	            var base64StrLength = base64Str.length;
+	            var map = urlSafe ? this._safe_map : this._map;
+	            var reverseMap = this._reverseMap;
+
+	            if (!reverseMap) {
+	                reverseMap = this._reverseMap = [];
+	                for (var j = 0; j < map.length; j++) {
+	                    reverseMap[map.charCodeAt(j)] = j;
+	                }
+	            }
+
+	            // Ignore padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                var paddingIndex = base64Str.indexOf(paddingChar);
+	                if (paddingIndex !== -1) {
+	                    base64StrLength = paddingIndex;
+	                }
+	            }
+
+	            // Convert
+	            return parseLoop(base64Str, base64StrLength, reverseMap);
+
+	        },
+
+	        _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
+	        _safe_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
+	    };
+
+	    function parseLoop(base64Str, base64StrLength, reverseMap) {
+	        var words = [];
+	        var nBytes = 0;
+	        for (var i = 0; i < base64StrLength; i++) {
+	            if (i % 4) {
+	                var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);
+	                var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);
+	                var bitsCombined = bits1 | bits2;
+	                words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8);
+	                nBytes++;
+	            }
+	        }
+	        return WordArray.create(words, nBytes);
+	    }
+	}());
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Constants table
+	    var T = [];
+
+	    // Compute constants
+	    (function () {
+	        for (var i = 0; i < 64; i++) {
+	            T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
+	        }
+	    }());
+
+	    /**
+	     * MD5 hash algorithm.
+	     */
+	    var MD5 = C_algo.MD5 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0x67452301, 0xefcdab89,
+	                0x98badcfe, 0x10325476
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Swap endian
+	            for (var i = 0; i < 16; i++) {
+	                // Shortcuts
+	                var offset_i = offset + i;
+	                var M_offset_i = M[offset_i];
+
+	                M[offset_i] = (
+	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
+	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
+	                );
+	            }
+
+	            // Shortcuts
+	            var H = this._hash.words;
+
+	            var M_offset_0  = M[offset + 0];
+	            var M_offset_1  = M[offset + 1];
+	            var M_offset_2  = M[offset + 2];
+	            var M_offset_3  = M[offset + 3];
+	            var M_offset_4  = M[offset + 4];
+	            var M_offset_5  = M[offset + 5];
+	            var M_offset_6  = M[offset + 6];
+	            var M_offset_7  = M[offset + 7];
+	            var M_offset_8  = M[offset + 8];
+	            var M_offset_9  = M[offset + 9];
+	            var M_offset_10 = M[offset + 10];
+	            var M_offset_11 = M[offset + 11];
+	            var M_offset_12 = M[offset + 12];
+	            var M_offset_13 = M[offset + 13];
+	            var M_offset_14 = M[offset + 14];
+	            var M_offset_15 = M[offset + 15];
+
+	            // Working varialbes
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+
+	            // Computation
+	            a = FF(a, b, c, d, M_offset_0,  7,  T[0]);
+	            d = FF(d, a, b, c, M_offset_1,  12, T[1]);
+	            c = FF(c, d, a, b, M_offset_2,  17, T[2]);
+	            b = FF(b, c, d, a, M_offset_3,  22, T[3]);
+	            a = FF(a, b, c, d, M_offset_4,  7,  T[4]);
+	            d = FF(d, a, b, c, M_offset_5,  12, T[5]);
+	            c = FF(c, d, a, b, M_offset_6,  17, T[6]);
+	            b = FF(b, c, d, a, M_offset_7,  22, T[7]);
+	            a = FF(a, b, c, d, M_offset_8,  7,  T[8]);
+	            d = FF(d, a, b, c, M_offset_9,  12, T[9]);
+	            c = FF(c, d, a, b, M_offset_10, 17, T[10]);
+	            b = FF(b, c, d, a, M_offset_11, 22, T[11]);
+	            a = FF(a, b, c, d, M_offset_12, 7,  T[12]);
+	            d = FF(d, a, b, c, M_offset_13, 12, T[13]);
+	            c = FF(c, d, a, b, M_offset_14, 17, T[14]);
+	            b = FF(b, c, d, a, M_offset_15, 22, T[15]);
+
+	            a = GG(a, b, c, d, M_offset_1,  5,  T[16]);
+	            d = GG(d, a, b, c, M_offset_6,  9,  T[17]);
+	            c = GG(c, d, a, b, M_offset_11, 14, T[18]);
+	            b = GG(b, c, d, a, M_offset_0,  20, T[19]);
+	            a = GG(a, b, c, d, M_offset_5,  5,  T[20]);
+	            d = GG(d, a, b, c, M_offset_10, 9,  T[21]);
+	            c = GG(c, d, a, b, M_offset_15, 14, T[22]);
+	            b = GG(b, c, d, a, M_offset_4,  20, T[23]);
+	            a = GG(a, b, c, d, M_offset_9,  5,  T[24]);
+	            d = GG(d, a, b, c, M_offset_14, 9,  T[25]);
+	            c = GG(c, d, a, b, M_offset_3,  14, T[26]);
+	            b = GG(b, c, d, a, M_offset_8,  20, T[27]);
+	            a = GG(a, b, c, d, M_offset_13, 5,  T[28]);
+	            d = GG(d, a, b, c, M_offset_2,  9,  T[29]);
+	            c = GG(c, d, a, b, M_offset_7,  14, T[30]);
+	            b = GG(b, c, d, a, M_offset_12, 20, T[31]);
+
+	            a = HH(a, b, c, d, M_offset_5,  4,  T[32]);
+	            d = HH(d, a, b, c, M_offset_8,  11, T[33]);
+	            c = HH(c, d, a, b, M_offset_11, 16, T[34]);
+	            b = HH(b, c, d, a, M_offset_14, 23, T[35]);
+	            a = HH(a, b, c, d, M_offset_1,  4,  T[36]);
+	            d = HH(d, a, b, c, M_offset_4,  11, T[37]);
+	            c = HH(c, d, a, b, M_offset_7,  16, T[38]);
+	            b = HH(b, c, d, a, M_offset_10, 23, T[39]);
+	            a = HH(a, b, c, d, M_offset_13, 4,  T[40]);
+	            d = HH(d, a, b, c, M_offset_0,  11, T[41]);
+	            c = HH(c, d, a, b, M_offset_3,  16, T[42]);
+	            b = HH(b, c, d, a, M_offset_6,  23, T[43]);
+	            a = HH(a, b, c, d, M_offset_9,  4,  T[44]);
+	            d = HH(d, a, b, c, M_offset_12, 11, T[45]);
+	            c = HH(c, d, a, b, M_offset_15, 16, T[46]);
+	            b = HH(b, c, d, a, M_offset_2,  23, T[47]);
+
+	            a = II(a, b, c, d, M_offset_0,  6,  T[48]);
+	            d = II(d, a, b, c, M_offset_7,  10, T[49]);
+	            c = II(c, d, a, b, M_offset_14, 15, T[50]);
+	            b = II(b, c, d, a, M_offset_5,  21, T[51]);
+	            a = II(a, b, c, d, M_offset_12, 6,  T[52]);
+	            d = II(d, a, b, c, M_offset_3,  10, T[53]);
+	            c = II(c, d, a, b, M_offset_10, 15, T[54]);
+	            b = II(b, c, d, a, M_offset_1,  21, T[55]);
+	            a = II(a, b, c, d, M_offset_8,  6,  T[56]);
+	            d = II(d, a, b, c, M_offset_15, 10, T[57]);
+	            c = II(c, d, a, b, M_offset_6,  15, T[58]);
+	            b = II(b, c, d, a, M_offset_13, 21, T[59]);
+	            a = II(a, b, c, d, M_offset_4,  6,  T[60]);
+	            d = II(d, a, b, c, M_offset_11, 10, T[61]);
+	            c = II(c, d, a, b, M_offset_2,  15, T[62]);
+	            b = II(b, c, d, a, M_offset_9,  21, T[63]);
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+
+	            var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
+	            var nBitsTotalL = nBitsTotal;
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
+	                (((nBitsTotalH << 8)  | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotalH << 24) | (nBitsTotalH >>> 8))  & 0xff00ff00)
+	            );
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
+	                (((nBitsTotalL << 8)  | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotalL << 24) | (nBitsTotalL >>> 8))  & 0xff00ff00)
+	            );
+
+	            data.sigBytes = (dataWords.length + 1) * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var hash = this._hash;
+	            var H = hash.words;
+
+	            // Swap endian
+	            for (var i = 0; i < 4; i++) {
+	                // Shortcut
+	                var H_i = H[i];
+
+	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
+	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    function FF(a, b, c, d, x, s, t) {
+	        var n = a + ((b & c) | (~b & d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function GG(a, b, c, d, x, s, t) {
+	        var n = a + ((b & d) | (c & ~d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function HH(a, b, c, d, x, s, t) {
+	        var n = a + (b ^ c ^ d) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function II(a, b, c, d, x, s, t) {
+	        var n = a + (c ^ (b | ~d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.MD5('message');
+	     *     var hash = CryptoJS.MD5(wordArray);
+	     */
+	    C.MD5 = Hasher._createHelper(MD5);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacMD5(message, key);
+	     */
+	    C.HmacMD5 = Hasher._createHmacHelper(MD5);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Reusable object
+	    var W = [];
+
+	    /**
+	     * SHA-1 hash algorithm.
+	     */
+	    var SHA1 = C_algo.SHA1 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0x67452301, 0xefcdab89,
+	                0x98badcfe, 0x10325476,
+	                0xc3d2e1f0
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var H = this._hash.words;
+
+	            // Working variables
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+	            var e = H[4];
+
+	            // Computation
+	            for (var i = 0; i < 80; i++) {
+	                if (i < 16) {
+	                    W[i] = M[offset + i] | 0;
+	                } else {
+	                    var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
+	                    W[i] = (n << 1) | (n >>> 31);
+	                }
+
+	                var t = ((a << 5) | (a >>> 27)) + e + W[i];
+	                if (i < 20) {
+	                    t += ((b & c) | (~b & d)) + 0x5a827999;
+	                } else if (i < 40) {
+	                    t += (b ^ c ^ d) + 0x6ed9eba1;
+	                } else if (i < 60) {
+	                    t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;
+	                } else /* if (i < 80) */ {
+	                    t += (b ^ c ^ d) - 0x359d3e2a;
+	                }
+
+	                e = d;
+	                d = c;
+	                c = (b << 30) | (b >>> 2);
+	                b = a;
+	                a = t;
+	            }
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	            H[4] = (H[4] + e) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Return final computed hash
+	            return this._hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA1('message');
+	     *     var hash = CryptoJS.SHA1(wordArray);
+	     */
+	    C.SHA1 = Hasher._createHelper(SHA1);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA1(message, key);
+	     */
+	    C.HmacSHA1 = Hasher._createHmacHelper(SHA1);
+	}());
+
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Initialization and round constants tables
+	    var H = [];
+	    var K = [];
+
+	    // Compute constants
+	    (function () {
+	        function isPrime(n) {
+	            var sqrtN = Math.sqrt(n);
+	            for (var factor = 2; factor <= sqrtN; factor++) {
+	                if (!(n % factor)) {
+	                    return false;
+	                }
+	            }
+
+	            return true;
+	        }
+
+	        function getFractionalBits(n) {
+	            return ((n - (n | 0)) * 0x100000000) | 0;
+	        }
+
+	        var n = 2;
+	        var nPrime = 0;
+	        while (nPrime < 64) {
+	            if (isPrime(n)) {
+	                if (nPrime < 8) {
+	                    H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
+	                }
+	                K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));
+
+	                nPrime++;
+	            }
+
+	            n++;
+	        }
+	    }());
+
+	    // Reusable object
+	    var W = [];
+
+	    /**
+	     * SHA-256 hash algorithm.
+	     */
+	    var SHA256 = C_algo.SHA256 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init(H.slice(0));
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var H = this._hash.words;
+
+	            // Working variables
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+	            var e = H[4];
+	            var f = H[5];
+	            var g = H[6];
+	            var h = H[7];
+
+	            // Computation
+	            for (var i = 0; i < 64; i++) {
+	                if (i < 16) {
+	                    W[i] = M[offset + i] | 0;
+	                } else {
+	                    var gamma0x = W[i - 15];
+	                    var gamma0  = ((gamma0x << 25) | (gamma0x >>> 7))  ^
+	                                  ((gamma0x << 14) | (gamma0x >>> 18)) ^
+	                                   (gamma0x >>> 3);
+
+	                    var gamma1x = W[i - 2];
+	                    var gamma1  = ((gamma1x << 15) | (gamma1x >>> 17)) ^
+	                                  ((gamma1x << 13) | (gamma1x >>> 19)) ^
+	                                   (gamma1x >>> 10);
+
+	                    W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
+	                }
+
+	                var ch  = (e & f) ^ (~e & g);
+	                var maj = (a & b) ^ (a & c) ^ (b & c);
+
+	                var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
+	                var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7)  | (e >>> 25));
+
+	                var t1 = h + sigma1 + ch + K[i] + W[i];
+	                var t2 = sigma0 + maj;
+
+	                h = g;
+	                g = f;
+	                f = e;
+	                e = (d + t1) | 0;
+	                d = c;
+	                c = b;
+	                b = a;
+	                a = (t1 + t2) | 0;
+	            }
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	            H[4] = (H[4] + e) | 0;
+	            H[5] = (H[5] + f) | 0;
+	            H[6] = (H[6] + g) | 0;
+	            H[7] = (H[7] + h) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Return final computed hash
+	            return this._hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA256('message');
+	     *     var hash = CryptoJS.SHA256(wordArray);
+	     */
+	    C.SHA256 = Hasher._createHelper(SHA256);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA256(message, key);
+	     */
+	    C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var SHA256 = C_algo.SHA256;
+
+	    /**
+	     * SHA-224 hash algorithm.
+	     */
+	    var SHA224 = C_algo.SHA224 = SHA256.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+	                0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
+	            ]);
+	        },
+
+	        _doFinalize: function () {
+	            var hash = SHA256._doFinalize.call(this);
+
+	            hash.sigBytes -= 4;
+
+	            return hash;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA224('message');
+	     *     var hash = CryptoJS.SHA224(wordArray);
+	     */
+	    C.SHA224 = SHA256._createHelper(SHA224);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA224(message, key);
+	     */
+	    C.HmacSHA224 = SHA256._createHmacHelper(SHA224);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Hasher = C_lib.Hasher;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var X64WordArray = C_x64.WordArray;
+	    var C_algo = C.algo;
+
+	    function X64Word_create() {
+	        return X64Word.create.apply(X64Word, arguments);
+	    }
+
+	    // Constants
+	    var K = [
+	        X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd),
+	        X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc),
+	        X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019),
+	        X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118),
+	        X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe),
+	        X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2),
+	        X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1),
+	        X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694),
+	        X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3),
+	        X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65),
+	        X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483),
+	        X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5),
+	        X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210),
+	        X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4),
+	        X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725),
+	        X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70),
+	        X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926),
+	        X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df),
+	        X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8),
+	        X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b),
+	        X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001),
+	        X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30),
+	        X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910),
+	        X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8),
+	        X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53),
+	        X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8),
+	        X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb),
+	        X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3),
+	        X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60),
+	        X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec),
+	        X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9),
+	        X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b),
+	        X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207),
+	        X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178),
+	        X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6),
+	        X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b),
+	        X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493),
+	        X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c),
+	        X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a),
+	        X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817)
+	    ];
+
+	    // Reusable objects
+	    var W = [];
+	    (function () {
+	        for (var i = 0; i < 80; i++) {
+	            W[i] = X64Word_create();
+	        }
+	    }());
+
+	    /**
+	     * SHA-512 hash algorithm.
+	     */
+	    var SHA512 = C_algo.SHA512 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new X64WordArray.init([
+	                new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b),
+	                new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1),
+	                new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f),
+	                new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179)
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcuts
+	            var H = this._hash.words;
+
+	            var H0 = H[0];
+	            var H1 = H[1];
+	            var H2 = H[2];
+	            var H3 = H[3];
+	            var H4 = H[4];
+	            var H5 = H[5];
+	            var H6 = H[6];
+	            var H7 = H[7];
+
+	            var H0h = H0.high;
+	            var H0l = H0.low;
+	            var H1h = H1.high;
+	            var H1l = H1.low;
+	            var H2h = H2.high;
+	            var H2l = H2.low;
+	            var H3h = H3.high;
+	            var H3l = H3.low;
+	            var H4h = H4.high;
+	            var H4l = H4.low;
+	            var H5h = H5.high;
+	            var H5l = H5.low;
+	            var H6h = H6.high;
+	            var H6l = H6.low;
+	            var H7h = H7.high;
+	            var H7l = H7.low;
+
+	            // Working variables
+	            var ah = H0h;
+	            var al = H0l;
+	            var bh = H1h;
+	            var bl = H1l;
+	            var ch = H2h;
+	            var cl = H2l;
+	            var dh = H3h;
+	            var dl = H3l;
+	            var eh = H4h;
+	            var el = H4l;
+	            var fh = H5h;
+	            var fl = H5l;
+	            var gh = H6h;
+	            var gl = H6l;
+	            var hh = H7h;
+	            var hl = H7l;
+
+	            // Rounds
+	            for (var i = 0; i < 80; i++) {
+	                var Wil;
+	                var Wih;
+
+	                // Shortcut
+	                var Wi = W[i];
+
+	                // Extend message
+	                if (i < 16) {
+	                    Wih = Wi.high = M[offset + i * 2]     | 0;
+	                    Wil = Wi.low  = M[offset + i * 2 + 1] | 0;
+	                } else {
+	                    // Gamma0
+	                    var gamma0x  = W[i - 15];
+	                    var gamma0xh = gamma0x.high;
+	                    var gamma0xl = gamma0x.low;
+	                    var gamma0h  = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7);
+	                    var gamma0l  = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25));
+
+	                    // Gamma1
+	                    var gamma1x  = W[i - 2];
+	                    var gamma1xh = gamma1x.high;
+	                    var gamma1xl = gamma1x.low;
+	                    var gamma1h  = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6);
+	                    var gamma1l  = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26));
+
+	                    // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]
+	                    var Wi7  = W[i - 7];
+	                    var Wi7h = Wi7.high;
+	                    var Wi7l = Wi7.low;
+
+	                    var Wi16  = W[i - 16];
+	                    var Wi16h = Wi16.high;
+	                    var Wi16l = Wi16.low;
+
+	                    Wil = gamma0l + Wi7l;
+	                    Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0);
+	                    Wil = Wil + gamma1l;
+	                    Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0);
+	                    Wil = Wil + Wi16l;
+	                    Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0);
+
+	                    Wi.high = Wih;
+	                    Wi.low  = Wil;
+	                }
+
+	                var chh  = (eh & fh) ^ (~eh & gh);
+	                var chl  = (el & fl) ^ (~el & gl);
+	                var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);
+	                var majl = (al & bl) ^ (al & cl) ^ (bl & cl);
+
+	                var sigma0h = ((ah >>> 28) | (al << 4))  ^ ((ah << 30)  | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));
+	                var sigma0l = ((al >>> 28) | (ah << 4))  ^ ((al << 30)  | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));
+	                var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9));
+	                var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9));
+
+	                // t1 = h + sigma1 + ch + K[i] + W[i]
+	                var Ki  = K[i];
+	                var Kih = Ki.high;
+	                var Kil = Ki.low;
+
+	                var t1l = hl + sigma1l;
+	                var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);
+	                var t1l = t1l + chl;
+	                var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
+	                var t1l = t1l + Kil;
+	                var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0);
+	                var t1l = t1l + Wil;
+	                var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0);
+
+	                // t2 = sigma0 + maj
+	                var t2l = sigma0l + majl;
+	                var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);
+
+	                // Update working variables
+	                hh = gh;
+	                hl = gl;
+	                gh = fh;
+	                gl = fl;
+	                fh = eh;
+	                fl = el;
+	                el = (dl + t1l) | 0;
+	                eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+	                dh = ch;
+	                dl = cl;
+	                ch = bh;
+	                cl = bl;
+	                bh = ah;
+	                bl = al;
+	                al = (t1l + t2l) | 0;
+	                ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;
+	            }
+
+	            // Intermediate hash value
+	            H0l = H0.low  = (H0l + al);
+	            H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0));
+	            H1l = H1.low  = (H1l + bl);
+	            H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0));
+	            H2l = H2.low  = (H2l + cl);
+	            H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0));
+	            H3l = H3.low  = (H3l + dl);
+	            H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0));
+	            H4l = H4.low  = (H4l + el);
+	            H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0));
+	            H5l = H5.low  = (H5l + fl);
+	            H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0));
+	            H6l = H6.low  = (H6l + gl);
+	            H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0));
+	            H7l = H7.low  = (H7l + hl);
+	            H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0));
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Convert hash to 32-bit word array before returning
+	            var hash = this._hash.toX32();
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        },
+
+	        blockSize: 1024/32
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA512('message');
+	     *     var hash = CryptoJS.SHA512(wordArray);
+	     */
+	    C.SHA512 = Hasher._createHelper(SHA512);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA512(message, key);
+	     */
+	    C.HmacSHA512 = Hasher._createHmacHelper(SHA512);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var X64WordArray = C_x64.WordArray;
+	    var C_algo = C.algo;
+	    var SHA512 = C_algo.SHA512;
+
+	    /**
+	     * SHA-384 hash algorithm.
+	     */
+	    var SHA384 = C_algo.SHA384 = SHA512.extend({
+	        _doReset: function () {
+	            this._hash = new X64WordArray.init([
+	                new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507),
+	                new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939),
+	                new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511),
+	                new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4)
+	            ]);
+	        },
+
+	        _doFinalize: function () {
+	            var hash = SHA512._doFinalize.call(this);
+
+	            hash.sigBytes -= 16;
+
+	            return hash;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA384('message');
+	     *     var hash = CryptoJS.SHA384(wordArray);
+	     */
+	    C.SHA384 = SHA512._createHelper(SHA384);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA384(message, key);
+	     */
+	    C.HmacSHA384 = SHA512._createHmacHelper(SHA384);
+	}());
+
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var C_algo = C.algo;
+
+	    // Constants tables
+	    var RHO_OFFSETS = [];
+	    var PI_INDEXES  = [];
+	    var ROUND_CONSTANTS = [];
+
+	    // Compute Constants
+	    (function () {
+	        // Compute rho offset constants
+	        var x = 1, y = 0;
+	        for (var t = 0; t < 24; t++) {
+	            RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64;
+
+	            var newX = y % 5;
+	            var newY = (2 * x + 3 * y) % 5;
+	            x = newX;
+	            y = newY;
+	        }
+
+	        // Compute pi index constants
+	        for (var x = 0; x < 5; x++) {
+	            for (var y = 0; y < 5; y++) {
+	                PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5;
+	            }
+	        }
+
+	        // Compute round constants
+	        var LFSR = 0x01;
+	        for (var i = 0; i < 24; i++) {
+	            var roundConstantMsw = 0;
+	            var roundConstantLsw = 0;
+
+	            for (var j = 0; j < 7; j++) {
+	                if (LFSR & 0x01) {
+	                    var bitPosition = (1 << j) - 1;
+	                    if (bitPosition < 32) {
+	                        roundConstantLsw ^= 1 << bitPosition;
+	                    } else /* if (bitPosition >= 32) */ {
+	                        roundConstantMsw ^= 1 << (bitPosition - 32);
+	                    }
+	                }
+
+	                // Compute next LFSR
+	                if (LFSR & 0x80) {
+	                    // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1
+	                    LFSR = (LFSR << 1) ^ 0x71;
+	                } else {
+	                    LFSR <<= 1;
+	                }
+	            }
+
+	            ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw);
+	        }
+	    }());
+
+	    // Reusable objects for temporary values
+	    var T = [];
+	    (function () {
+	        for (var i = 0; i < 25; i++) {
+	            T[i] = X64Word.create();
+	        }
+	    }());
+
+	    /**
+	     * SHA-3 hash algorithm.
+	     */
+	    var SHA3 = C_algo.SHA3 = Hasher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} outputLength
+	         *   The desired number of bits in the output hash.
+	         *   Only values permitted are: 224, 256, 384, 512.
+	         *   Default: 512
+	         */
+	        cfg: Hasher.cfg.extend({
+	            outputLength: 512
+	        }),
+
+	        _doReset: function () {
+	            var state = this._state = []
+	            for (var i = 0; i < 25; i++) {
+	                state[i] = new X64Word.init();
+	            }
+
+	            this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32;
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcuts
+	            var state = this._state;
+	            var nBlockSizeLanes = this.blockSize / 2;
+
+	            // Absorb
+	            for (var i = 0; i < nBlockSizeLanes; i++) {
+	                // Shortcuts
+	                var M2i  = M[offset + 2 * i];
+	                var M2i1 = M[offset + 2 * i + 1];
+
+	                // Swap endian
+	                M2i = (
+	                    (((M2i << 8)  | (M2i >>> 24)) & 0x00ff00ff) |
+	                    (((M2i << 24) | (M2i >>> 8))  & 0xff00ff00)
+	                );
+	                M2i1 = (
+	                    (((M2i1 << 8)  | (M2i1 >>> 24)) & 0x00ff00ff) |
+	                    (((M2i1 << 24) | (M2i1 >>> 8))  & 0xff00ff00)
+	                );
+
+	                // Absorb message into state
+	                var lane = state[i];
+	                lane.high ^= M2i1;
+	                lane.low  ^= M2i;
+	            }
+
+	            // Rounds
+	            for (var round = 0; round < 24; round++) {
+	                // Theta
+	                for (var x = 0; x < 5; x++) {
+	                    // Mix column lanes
+	                    var tMsw = 0, tLsw = 0;
+	                    for (var y = 0; y < 5; y++) {
+	                        var lane = state[x + 5 * y];
+	                        tMsw ^= lane.high;
+	                        tLsw ^= lane.low;
+	                    }
+
+	                    // Temporary values
+	                    var Tx = T[x];
+	                    Tx.high = tMsw;
+	                    Tx.low  = tLsw;
+	                }
+	                for (var x = 0; x < 5; x++) {
+	                    // Shortcuts
+	                    var Tx4 = T[(x + 4) % 5];
+	                    var Tx1 = T[(x + 1) % 5];
+	                    var Tx1Msw = Tx1.high;
+	                    var Tx1Lsw = Tx1.low;
+
+	                    // Mix surrounding columns
+	                    var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));
+	                    var tLsw = Tx4.low  ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));
+	                    for (var y = 0; y < 5; y++) {
+	                        var lane = state[x + 5 * y];
+	                        lane.high ^= tMsw;
+	                        lane.low  ^= tLsw;
+	                    }
+	                }
+
+	                // Rho Pi
+	                for (var laneIndex = 1; laneIndex < 25; laneIndex++) {
+	                    var tMsw;
+	                    var tLsw;
+
+	                    // Shortcuts
+	                    var lane = state[laneIndex];
+	                    var laneMsw = lane.high;
+	                    var laneLsw = lane.low;
+	                    var rhoOffset = RHO_OFFSETS[laneIndex];
+
+	                    // Rotate lanes
+	                    if (rhoOffset < 32) {
+	                        tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));
+	                        tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));
+	                    } else /* if (rhoOffset >= 32) */ {
+	                        tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));
+	                        tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));
+	                    }
+
+	                    // Transpose lanes
+	                    var TPiLane = T[PI_INDEXES[laneIndex]];
+	                    TPiLane.high = tMsw;
+	                    TPiLane.low  = tLsw;
+	                }
+
+	                // Rho pi at x = y = 0
+	                var T0 = T[0];
+	                var state0 = state[0];
+	                T0.high = state0.high;
+	                T0.low  = state0.low;
+
+	                // Chi
+	                for (var x = 0; x < 5; x++) {
+	                    for (var y = 0; y < 5; y++) {
+	                        // Shortcuts
+	                        var laneIndex = x + 5 * y;
+	                        var lane = state[laneIndex];
+	                        var TLane = T[laneIndex];
+	                        var Tx1Lane = T[((x + 1) % 5) + 5 * y];
+	                        var Tx2Lane = T[((x + 2) % 5) + 5 * y];
+
+	                        // Mix rows
+	                        lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);
+	                        lane.low  = TLane.low  ^ (~Tx1Lane.low  & Tx2Lane.low);
+	                    }
+	                }
+
+	                // Iota
+	                var lane = state[0];
+	                var roundConstant = ROUND_CONSTANTS[round];
+	                lane.high ^= roundConstant.high;
+	                lane.low  ^= roundConstant.low;
+	            }
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+	            var blockSizeBits = this.blockSize * 32;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32);
+	            dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var state = this._state;
+	            var outputLengthBytes = this.cfg.outputLength / 8;
+	            var outputLengthLanes = outputLengthBytes / 8;
+
+	            // Squeeze
+	            var hashWords = [];
+	            for (var i = 0; i < outputLengthLanes; i++) {
+	                // Shortcuts
+	                var lane = state[i];
+	                var laneMsw = lane.high;
+	                var laneLsw = lane.low;
+
+	                // Swap endian
+	                laneMsw = (
+	                    (((laneMsw << 8)  | (laneMsw >>> 24)) & 0x00ff00ff) |
+	                    (((laneMsw << 24) | (laneMsw >>> 8))  & 0xff00ff00)
+	                );
+	                laneLsw = (
+	                    (((laneLsw << 8)  | (laneLsw >>> 24)) & 0x00ff00ff) |
+	                    (((laneLsw << 24) | (laneLsw >>> 8))  & 0xff00ff00)
+	                );
+
+	                // Squeeze state to retrieve hash
+	                hashWords.push(laneLsw);
+	                hashWords.push(laneMsw);
+	            }
+
+	            // Return final computed hash
+	            return new WordArray.init(hashWords, outputLengthBytes);
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+
+	            var state = clone._state = this._state.slice(0);
+	            for (var i = 0; i < 25; i++) {
+	                state[i] = state[i].clone();
+	            }
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA3('message');
+	     *     var hash = CryptoJS.SHA3(wordArray);
+	     */
+	    C.SHA3 = Hasher._createHelper(SHA3);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA3(message, key);
+	     */
+	    C.HmacSHA3 = Hasher._createHmacHelper(SHA3);
+	}(Math));
+
+
+	/** @preserve
+	(c) 2012 by Cédric Mesnil. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+	    - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+	    - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+	*/
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Constants table
+	    var _zl = WordArray.create([
+	        0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	        7,  4, 13,  1, 10,  6, 15,  3, 12,  0,  9,  5,  2, 14, 11,  8,
+	        3, 10, 14,  4,  9, 15,  8,  1,  2,  7,  0,  6, 13, 11,  5, 12,
+	        1,  9, 11, 10,  0,  8, 12,  4, 13,  3,  7, 15, 14,  5,  6,  2,
+	        4,  0,  5,  9,  7, 12,  2, 10, 14,  1,  3,  8, 11,  6, 15, 13]);
+	    var _zr = WordArray.create([
+	        5, 14,  7,  0,  9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
+	        6, 11,  3,  7,  0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
+	        15,  5,  1,  3,  7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
+	        8,  6,  4,  1,  3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
+	        12, 15, 10,  4,  1,  5,  8,  7,  6,  2, 13, 14,  0,  3,  9, 11]);
+	    var _sl = WordArray.create([
+	         11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
+	        7, 6,   8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
+	        11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
+	          11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
+	        9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6 ]);
+	    var _sr = WordArray.create([
+	        8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
+	        9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
+	        9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
+	        15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
+	        8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11 ]);
+
+	    var _hl =  WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]);
+	    var _hr =  WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]);
+
+	    /**
+	     * RIPEMD160 hash algorithm.
+	     */
+	    var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash  = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+
+	            // Swap endian
+	            for (var i = 0; i < 16; i++) {
+	                // Shortcuts
+	                var offset_i = offset + i;
+	                var M_offset_i = M[offset_i];
+
+	                // Swap
+	                M[offset_i] = (
+	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
+	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
+	                );
+	            }
+	            // Shortcut
+	            var H  = this._hash.words;
+	            var hl = _hl.words;
+	            var hr = _hr.words;
+	            var zl = _zl.words;
+	            var zr = _zr.words;
+	            var sl = _sl.words;
+	            var sr = _sr.words;
+
+	            // Working variables
+	            var al, bl, cl, dl, el;
+	            var ar, br, cr, dr, er;
+
+	            ar = al = H[0];
+	            br = bl = H[1];
+	            cr = cl = H[2];
+	            dr = dl = H[3];
+	            er = el = H[4];
+	            // Computation
+	            var t;
+	            for (var i = 0; i < 80; i += 1) {
+	                t = (al +  M[offset+zl[i]])|0;
+	                if (i<16){
+		            t +=  f1(bl,cl,dl) + hl[0];
+	                } else if (i<32) {
+		            t +=  f2(bl,cl,dl) + hl[1];
+	                } else if (i<48) {
+		            t +=  f3(bl,cl,dl) + hl[2];
+	                } else if (i<64) {
+		            t +=  f4(bl,cl,dl) + hl[3];
+	                } else {// if (i<80) {
+		            t +=  f5(bl,cl,dl) + hl[4];
+	                }
+	                t = t|0;
+	                t =  rotl(t,sl[i]);
+	                t = (t+el)|0;
+	                al = el;
+	                el = dl;
+	                dl = rotl(cl, 10);
+	                cl = bl;
+	                bl = t;
+
+	                t = (ar + M[offset+zr[i]])|0;
+	                if (i<16){
+		            t +=  f5(br,cr,dr) + hr[0];
+	                } else if (i<32) {
+		            t +=  f4(br,cr,dr) + hr[1];
+	                } else if (i<48) {
+		            t +=  f3(br,cr,dr) + hr[2];
+	                } else if (i<64) {
+		            t +=  f2(br,cr,dr) + hr[3];
+	                } else {// if (i<80) {
+		            t +=  f1(br,cr,dr) + hr[4];
+	                }
+	                t = t|0;
+	                t =  rotl(t,sr[i]) ;
+	                t = (t+er)|0;
+	                ar = er;
+	                er = dr;
+	                dr = rotl(cr, 10);
+	                cr = br;
+	                br = t;
+	            }
+	            // Intermediate hash value
+	            t    = (H[1] + cl + dr)|0;
+	            H[1] = (H[2] + dl + er)|0;
+	            H[2] = (H[3] + el + ar)|0;
+	            H[3] = (H[4] + al + br)|0;
+	            H[4] = (H[0] + bl + cr)|0;
+	            H[0] =  t;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
+	                (((nBitsTotal << 8)  | (nBitsTotal >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotal << 24) | (nBitsTotal >>> 8))  & 0xff00ff00)
+	            );
+	            data.sigBytes = (dataWords.length + 1) * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var hash = this._hash;
+	            var H = hash.words;
+
+	            // Swap endian
+	            for (var i = 0; i < 5; i++) {
+	                // Shortcut
+	                var H_i = H[i];
+
+	                // Swap
+	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
+	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+
+	    function f1(x, y, z) {
+	        return ((x) ^ (y) ^ (z));
+
+	    }
+
+	    function f2(x, y, z) {
+	        return (((x)&(y)) | ((~x)&(z)));
+	    }
+
+	    function f3(x, y, z) {
+	        return (((x) | (~(y))) ^ (z));
+	    }
+
+	    function f4(x, y, z) {
+	        return (((x) & (z)) | ((y)&(~(z))));
+	    }
+
+	    function f5(x, y, z) {
+	        return ((x) ^ ((y) |(~(z))));
+
+	    }
+
+	    function rotl(x,n) {
+	        return (x<<n) | (x>>>(32-n));
+	    }
+
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.RIPEMD160('message');
+	     *     var hash = CryptoJS.RIPEMD160(wordArray);
+	     */
+	    C.RIPEMD160 = Hasher._createHelper(RIPEMD160);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacRIPEMD160(message, key);
+	     */
+	    C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var C_enc = C.enc;
+	    var Utf8 = C_enc.Utf8;
+	    var C_algo = C.algo;
+
+	    /**
+	     * HMAC algorithm.
+	     */
+	    var HMAC = C_algo.HMAC = Base.extend({
+	        /**
+	         * Initializes a newly created HMAC.
+	         *
+	         * @param {Hasher} hasher The hash algorithm to use.
+	         * @param {WordArray|string} key The secret key.
+	         *
+	         * @example
+	         *
+	         *     var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
+	         */
+	        init: function (hasher, key) {
+	            // Init hasher
+	            hasher = this._hasher = new hasher.init();
+
+	            // Convert string to WordArray, else assume WordArray already
+	            if (typeof key == 'string') {
+	                key = Utf8.parse(key);
+	            }
+
+	            // Shortcuts
+	            var hasherBlockSize = hasher.blockSize;
+	            var hasherBlockSizeBytes = hasherBlockSize * 4;
+
+	            // Allow arbitrary length keys
+	            if (key.sigBytes > hasherBlockSizeBytes) {
+	                key = hasher.finalize(key);
+	            }
+
+	            // Clamp excess bits
+	            key.clamp();
+
+	            // Clone key for inner and outer pads
+	            var oKey = this._oKey = key.clone();
+	            var iKey = this._iKey = key.clone();
+
+	            // Shortcuts
+	            var oKeyWords = oKey.words;
+	            var iKeyWords = iKey.words;
+
+	            // XOR keys with pad constants
+	            for (var i = 0; i < hasherBlockSize; i++) {
+	                oKeyWords[i] ^= 0x5c5c5c5c;
+	                iKeyWords[i] ^= 0x36363636;
+	            }
+	            oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this HMAC to its initial state.
+	         *
+	         * @example
+	         *
+	         *     hmacHasher.reset();
+	         */
+	        reset: function () {
+	            // Shortcut
+	            var hasher = this._hasher;
+
+	            // Reset
+	            hasher.reset();
+	            hasher.update(this._iKey);
+	        },
+
+	        /**
+	         * Updates this HMAC with a message.
+	         *
+	         * @param {WordArray|string} messageUpdate The message to append.
+	         *
+	         * @return {HMAC} This HMAC instance.
+	         *
+	         * @example
+	         *
+	         *     hmacHasher.update('message');
+	         *     hmacHasher.update(wordArray);
+	         */
+	        update: function (messageUpdate) {
+	            this._hasher.update(messageUpdate);
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Finalizes the HMAC computation.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
+	         *
+	         * @return {WordArray} The HMAC.
+	         *
+	         * @example
+	         *
+	         *     var hmac = hmacHasher.finalize();
+	         *     var hmac = hmacHasher.finalize('message');
+	         *     var hmac = hmacHasher.finalize(wordArray);
+	         */
+	        finalize: function (messageUpdate) {
+	            // Shortcut
+	            var hasher = this._hasher;
+
+	            // Compute HMAC
+	            var innerHash = hasher.finalize(messageUpdate);
+	            hasher.reset();
+	            var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));
+
+	            return hmac;
+	        }
+	    });
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var SHA1 = C_algo.SHA1;
+	    var HMAC = C_algo.HMAC;
+
+	    /**
+	     * Password-Based Key Derivation Function 2 algorithm.
+	     */
+	    var PBKDF2 = C_algo.PBKDF2 = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)
+	         * @property {Hasher} hasher The hasher to use. Default: SHA1
+	         * @property {number} iterations The number of iterations to perform. Default: 1
+	         */
+	        cfg: Base.extend({
+	            keySize: 128/32,
+	            hasher: SHA1,
+	            iterations: 1
+	        }),
+
+	        /**
+	         * Initializes a newly created key derivation function.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for the derivation.
+	         *
+	         * @example
+	         *
+	         *     var kdf = CryptoJS.algo.PBKDF2.create();
+	         *     var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 });
+	         *     var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 });
+	         */
+	        init: function (cfg) {
+	            this.cfg = this.cfg.extend(cfg);
+	        },
+
+	        /**
+	         * Computes the Password-Based Key Derivation Function 2.
+	         *
+	         * @param {WordArray|string} password The password.
+	         * @param {WordArray|string} salt A salt.
+	         *
+	         * @return {WordArray} The derived key.
+	         *
+	         * @example
+	         *
+	         *     var key = kdf.compute(password, salt);
+	         */
+	        compute: function (password, salt) {
+	            // Shortcut
+	            var cfg = this.cfg;
+
+	            // Init HMAC
+	            var hmac = HMAC.create(cfg.hasher, password);
+
+	            // Initial values
+	            var derivedKey = WordArray.create();
+	            var blockIndex = WordArray.create([0x00000001]);
+
+	            // Shortcuts
+	            var derivedKeyWords = derivedKey.words;
+	            var blockIndexWords = blockIndex.words;
+	            var keySize = cfg.keySize;
+	            var iterations = cfg.iterations;
+
+	            // Generate key
+	            while (derivedKeyWords.length < keySize) {
+	                var block = hmac.update(salt).finalize(blockIndex);
+	                hmac.reset();
+
+	                // Shortcuts
+	                var blockWords = block.words;
+	                var blockWordsLength = blockWords.length;
+
+	                // Iterations
+	                var intermediate = block;
+	                for (var i = 1; i < iterations; i++) {
+	                    intermediate = hmac.finalize(intermediate);
+	                    hmac.reset();
+
+	                    // Shortcut
+	                    var intermediateWords = intermediate.words;
+
+	                    // XOR intermediate with block
+	                    for (var j = 0; j < blockWordsLength; j++) {
+	                        blockWords[j] ^= intermediateWords[j];
+	                    }
+	                }
+
+	                derivedKey.concat(block);
+	                blockIndexWords[0]++;
+	            }
+	            derivedKey.sigBytes = keySize * 4;
+
+	            return derivedKey;
+	        }
+	    });
+
+	    /**
+	     * Computes the Password-Based Key Derivation Function 2.
+	     *
+	     * @param {WordArray|string} password The password.
+	     * @param {WordArray|string} salt A salt.
+	     * @param {Object} cfg (Optional) The configuration options to use for this computation.
+	     *
+	     * @return {WordArray} The derived key.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var key = CryptoJS.PBKDF2(password, salt);
+	     *     var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 });
+	     *     var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 });
+	     */
+	    C.PBKDF2 = function (password, salt, cfg) {
+	        return PBKDF2.create(cfg).compute(password, salt);
+	    };
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var MD5 = C_algo.MD5;
+
+	    /**
+	     * This key derivation function is meant to conform with EVP_BytesToKey.
+	     * www.openssl.org/docs/crypto/EVP_BytesToKey.html
+	     */
+	    var EvpKDF = C_algo.EvpKDF = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)
+	         * @property {Hasher} hasher The hash algorithm to use. Default: MD5
+	         * @property {number} iterations The number of iterations to perform. Default: 1
+	         */
+	        cfg: Base.extend({
+	            keySize: 128/32,
+	            hasher: MD5,
+	            iterations: 1
+	        }),
+
+	        /**
+	         * Initializes a newly created key derivation function.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for the derivation.
+	         *
+	         * @example
+	         *
+	         *     var kdf = CryptoJS.algo.EvpKDF.create();
+	         *     var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 });
+	         *     var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 });
+	         */
+	        init: function (cfg) {
+	            this.cfg = this.cfg.extend(cfg);
+	        },
+
+	        /**
+	         * Derives a key from a password.
+	         *
+	         * @param {WordArray|string} password The password.
+	         * @param {WordArray|string} salt A salt.
+	         *
+	         * @return {WordArray} The derived key.
+	         *
+	         * @example
+	         *
+	         *     var key = kdf.compute(password, salt);
+	         */
+	        compute: function (password, salt) {
+	            var block;
+
+	            // Shortcut
+	            var cfg = this.cfg;
+
+	            // Init hasher
+	            var hasher = cfg.hasher.create();
+
+	            // Initial values
+	            var derivedKey = WordArray.create();
+
+	            // Shortcuts
+	            var derivedKeyWords = derivedKey.words;
+	            var keySize = cfg.keySize;
+	            var iterations = cfg.iterations;
+
+	            // Generate key
+	            while (derivedKeyWords.length < keySize) {
+	                if (block) {
+	                    hasher.update(block);
+	                }
+	                block = hasher.update(password).finalize(salt);
+	                hasher.reset();
+
+	                // Iterations
+	                for (var i = 1; i < iterations; i++) {
+	                    block = hasher.finalize(block);
+	                    hasher.reset();
+	                }
+
+	                derivedKey.concat(block);
+	            }
+	            derivedKey.sigBytes = keySize * 4;
+
+	            return derivedKey;
+	        }
+	    });
+
+	    /**
+	     * Derives a key from a password.
+	     *
+	     * @param {WordArray|string} password The password.
+	     * @param {WordArray|string} salt A salt.
+	     * @param {Object} cfg (Optional) The configuration options to use for this computation.
+	     *
+	     * @return {WordArray} The derived key.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var key = CryptoJS.EvpKDF(password, salt);
+	     *     var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 });
+	     *     var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 });
+	     */
+	    C.EvpKDF = function (password, salt, cfg) {
+	        return EvpKDF.create(cfg).compute(password, salt);
+	    };
+	}());
+
+
+	/**
+	 * Cipher core components.
+	 */
+	CryptoJS.lib.Cipher || (function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm;
+	    var C_enc = C.enc;
+	    var Utf8 = C_enc.Utf8;
+	    var Base64 = C_enc.Base64;
+	    var C_algo = C.algo;
+	    var EvpKDF = C_algo.EvpKDF;
+
+	    /**
+	     * Abstract base cipher template.
+	     *
+	     * @property {number} keySize This cipher's key size. Default: 4 (128 bits)
+	     * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits)
+	     * @property {number} _ENC_XFORM_MODE A constant representing encryption mode.
+	     * @property {number} _DEC_XFORM_MODE A constant representing decryption mode.
+	     */
+	    var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {WordArray} iv The IV to use for this operation.
+	         */
+	        cfg: Base.extend(),
+
+	        /**
+	         * Creates this cipher in encryption mode.
+	         *
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {Cipher} A cipher instance.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });
+	         */
+	        createEncryptor: function (key, cfg) {
+	            return this.create(this._ENC_XFORM_MODE, key, cfg);
+	        },
+
+	        /**
+	         * Creates this cipher in decryption mode.
+	         *
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {Cipher} A cipher instance.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });
+	         */
+	        createDecryptor: function (key, cfg) {
+	            return this.create(this._DEC_XFORM_MODE, key, cfg);
+	        },
+
+	        /**
+	         * Initializes a newly created cipher.
+	         *
+	         * @param {number} xformMode Either the encryption or decryption transormation mode constant.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray });
+	         */
+	        init: function (xformMode, key, cfg) {
+	            // Apply config defaults
+	            this.cfg = this.cfg.extend(cfg);
+
+	            // Store transform mode and key
+	            this._xformMode = xformMode;
+	            this._key = key;
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this cipher to its initial state.
+	         *
+	         * @example
+	         *
+	         *     cipher.reset();
+	         */
+	        reset: function () {
+	            // Reset data buffer
+	            BufferedBlockAlgorithm.reset.call(this);
+
+	            // Perform concrete-cipher logic
+	            this._doReset();
+	        },
+
+	        /**
+	         * Adds data to be encrypted or decrypted.
+	         *
+	         * @param {WordArray|string} dataUpdate The data to encrypt or decrypt.
+	         *
+	         * @return {WordArray} The data after processing.
+	         *
+	         * @example
+	         *
+	         *     var encrypted = cipher.process('data');
+	         *     var encrypted = cipher.process(wordArray);
+	         */
+	        process: function (dataUpdate) {
+	            // Append
+	            this._append(dataUpdate);
+
+	            // Process available blocks
+	            return this._process();
+	        },
+
+	        /**
+	         * Finalizes the encryption or decryption process.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt.
+	         *
+	         * @return {WordArray} The data after final processing.
+	         *
+	         * @example
+	         *
+	         *     var encrypted = cipher.finalize();
+	         *     var encrypted = cipher.finalize('data');
+	         *     var encrypted = cipher.finalize(wordArray);
+	         */
+	        finalize: function (dataUpdate) {
+	            // Final data update
+	            if (dataUpdate) {
+	                this._append(dataUpdate);
+	            }
+
+	            // Perform concrete-cipher logic
+	            var finalProcessedData = this._doFinalize();
+
+	            return finalProcessedData;
+	        },
+
+	        keySize: 128/32,
+
+	        ivSize: 128/32,
+
+	        _ENC_XFORM_MODE: 1,
+
+	        _DEC_XFORM_MODE: 2,
+
+	        /**
+	         * Creates shortcut functions to a cipher's object interface.
+	         *
+	         * @param {Cipher} cipher The cipher to create a helper for.
+	         *
+	         * @return {Object} An object with encrypt and decrypt shortcut functions.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);
+	         */
+	        _createHelper: (function () {
+	            function selectCipherStrategy(key) {
+	                if (typeof key == 'string') {
+	                    return PasswordBasedCipher;
+	                } else {
+	                    return SerializableCipher;
+	                }
+	            }
+
+	            return function (cipher) {
+	                return {
+	                    encrypt: function (message, key, cfg) {
+	                        return selectCipherStrategy(key).encrypt(cipher, message, key, cfg);
+	                    },
+
+	                    decrypt: function (ciphertext, key, cfg) {
+	                        return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg);
+	                    }
+	                };
+	            };
+	        }())
+	    });
+
+	    /**
+	     * Abstract base stream cipher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits)
+	     */
+	    var StreamCipher = C_lib.StreamCipher = Cipher.extend({
+	        _doFinalize: function () {
+	            // Process partial blocks
+	            var finalProcessedBlocks = this._process(!!'flush');
+
+	            return finalProcessedBlocks;
+	        },
+
+	        blockSize: 1
+	    });
+
+	    /**
+	     * Mode namespace.
+	     */
+	    var C_mode = C.mode = {};
+
+	    /**
+	     * Abstract base block cipher mode template.
+	     */
+	    var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({
+	        /**
+	         * Creates this mode for encryption.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);
+	         */
+	        createEncryptor: function (cipher, iv) {
+	            return this.Encryptor.create(cipher, iv);
+	        },
+
+	        /**
+	         * Creates this mode for decryption.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);
+	         */
+	        createDecryptor: function (cipher, iv) {
+	            return this.Decryptor.create(cipher, iv);
+	        },
+
+	        /**
+	         * Initializes a newly created mode.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);
+	         */
+	        init: function (cipher, iv) {
+	            this._cipher = cipher;
+	            this._iv = iv;
+	        }
+	    });
+
+	    /**
+	     * Cipher Block Chaining mode.
+	     */
+	    var CBC = C_mode.CBC = (function () {
+	        /**
+	         * Abstract base CBC mode.
+	         */
+	        var CBC = BlockCipherMode.extend();
+
+	        /**
+	         * CBC encryptor.
+	         */
+	        CBC.Encryptor = CBC.extend({
+	            /**
+	             * Processes the data block at offset.
+	             *
+	             * @param {Array} words The data words to operate on.
+	             * @param {number} offset The offset where the block starts.
+	             *
+	             * @example
+	             *
+	             *     mode.processBlock(data.words, offset);
+	             */
+	            processBlock: function (words, offset) {
+	                // Shortcuts
+	                var cipher = this._cipher;
+	                var blockSize = cipher.blockSize;
+
+	                // XOR and encrypt
+	                xorBlock.call(this, words, offset, blockSize);
+	                cipher.encryptBlock(words, offset);
+
+	                // Remember this block to use with next block
+	                this._prevBlock = words.slice(offset, offset + blockSize);
+	            }
+	        });
+
+	        /**
+	         * CBC decryptor.
+	         */
+	        CBC.Decryptor = CBC.extend({
+	            /**
+	             * Processes the data block at offset.
+	             *
+	             * @param {Array} words The data words to operate on.
+	             * @param {number} offset The offset where the block starts.
+	             *
+	             * @example
+	             *
+	             *     mode.processBlock(data.words, offset);
+	             */
+	            processBlock: function (words, offset) {
+	                // Shortcuts
+	                var cipher = this._cipher;
+	                var blockSize = cipher.blockSize;
+
+	                // Remember this block to use with next block
+	                var thisBlock = words.slice(offset, offset + blockSize);
+
+	                // Decrypt and XOR
+	                cipher.decryptBlock(words, offset);
+	                xorBlock.call(this, words, offset, blockSize);
+
+	                // This block becomes the previous block
+	                this._prevBlock = thisBlock;
+	            }
+	        });
+
+	        function xorBlock(words, offset, blockSize) {
+	            var block;
+
+	            // Shortcut
+	            var iv = this._iv;
+
+	            // Choose mixing block
+	            if (iv) {
+	                block = iv;
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            } else {
+	                block = this._prevBlock;
+	            }
+
+	            // XOR blocks
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= block[i];
+	            }
+	        }
+
+	        return CBC;
+	    }());
+
+	    /**
+	     * Padding namespace.
+	     */
+	    var C_pad = C.pad = {};
+
+	    /**
+	     * PKCS #5/7 padding strategy.
+	     */
+	    var Pkcs7 = C_pad.Pkcs7 = {
+	        /**
+	         * Pads data using the algorithm defined in PKCS #5/7.
+	         *
+	         * @param {WordArray} data The data to pad.
+	         * @param {number} blockSize The multiple that the data should be padded to.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     CryptoJS.pad.Pkcs7.pad(wordArray, 4);
+	         */
+	        pad: function (data, blockSize) {
+	            // Shortcut
+	            var blockSizeBytes = blockSize * 4;
+
+	            // Count padding bytes
+	            var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
+
+	            // Create padding word
+	            var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes;
+
+	            // Create padding
+	            var paddingWords = [];
+	            for (var i = 0; i < nPaddingBytes; i += 4) {
+	                paddingWords.push(paddingWord);
+	            }
+	            var padding = WordArray.create(paddingWords, nPaddingBytes);
+
+	            // Add padding
+	            data.concat(padding);
+	        },
+
+	        /**
+	         * Unpads data that had been padded using the algorithm defined in PKCS #5/7.
+	         *
+	         * @param {WordArray} data The data to unpad.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     CryptoJS.pad.Pkcs7.unpad(wordArray);
+	         */
+	        unpad: function (data) {
+	            // Get number of padding bytes from last byte
+	            var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	            // Remove padding
+	            data.sigBytes -= nPaddingBytes;
+	        }
+	    };
+
+	    /**
+	     * Abstract base block cipher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits)
+	     */
+	    var BlockCipher = C_lib.BlockCipher = Cipher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {Mode} mode The block mode to use. Default: CBC
+	         * @property {Padding} padding The padding strategy to use. Default: Pkcs7
+	         */
+	        cfg: Cipher.cfg.extend({
+	            mode: CBC,
+	            padding: Pkcs7
+	        }),
+
+	        reset: function () {
+	            var modeCreator;
+
+	            // Reset cipher
+	            Cipher.reset.call(this);
+
+	            // Shortcuts
+	            var cfg = this.cfg;
+	            var iv = cfg.iv;
+	            var mode = cfg.mode;
+
+	            // Reset block mode
+	            if (this._xformMode == this._ENC_XFORM_MODE) {
+	                modeCreator = mode.createEncryptor;
+	            } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
+	                modeCreator = mode.createDecryptor;
+	                // Keep at least one block in the buffer for unpadding
+	                this._minBufferSize = 1;
+	            }
+
+	            if (this._mode && this._mode.__creator == modeCreator) {
+	                this._mode.init(this, iv && iv.words);
+	            } else {
+	                this._mode = modeCreator.call(mode, this, iv && iv.words);
+	                this._mode.__creator = modeCreator;
+	            }
+	        },
+
+	        _doProcessBlock: function (words, offset) {
+	            this._mode.processBlock(words, offset);
+	        },
+
+	        _doFinalize: function () {
+	            var finalProcessedBlocks;
+
+	            // Shortcut
+	            var padding = this.cfg.padding;
+
+	            // Finalize
+	            if (this._xformMode == this._ENC_XFORM_MODE) {
+	                // Pad data
+	                padding.pad(this._data, this.blockSize);
+
+	                // Process final blocks
+	                finalProcessedBlocks = this._process(!!'flush');
+	            } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
+	                // Process final blocks
+	                finalProcessedBlocks = this._process(!!'flush');
+
+	                // Unpad data
+	                padding.unpad(finalProcessedBlocks);
+	            }
+
+	            return finalProcessedBlocks;
+	        },
+
+	        blockSize: 128/32
+	    });
+
+	    /**
+	     * A collection of cipher parameters.
+	     *
+	     * @property {WordArray} ciphertext The raw ciphertext.
+	     * @property {WordArray} key The key to this ciphertext.
+	     * @property {WordArray} iv The IV used in the ciphering operation.
+	     * @property {WordArray} salt The salt used with a key derivation function.
+	     * @property {Cipher} algorithm The cipher algorithm.
+	     * @property {Mode} mode The block mode used in the ciphering operation.
+	     * @property {Padding} padding The padding scheme used in the ciphering operation.
+	     * @property {number} blockSize The block size of the cipher.
+	     * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string.
+	     */
+	    var CipherParams = C_lib.CipherParams = Base.extend({
+	        /**
+	         * Initializes a newly created cipher params object.
+	         *
+	         * @param {Object} cipherParams An object with any of the possible cipher parameters.
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.lib.CipherParams.create({
+	         *         ciphertext: ciphertextWordArray,
+	         *         key: keyWordArray,
+	         *         iv: ivWordArray,
+	         *         salt: saltWordArray,
+	         *         algorithm: CryptoJS.algo.AES,
+	         *         mode: CryptoJS.mode.CBC,
+	         *         padding: CryptoJS.pad.PKCS7,
+	         *         blockSize: 4,
+	         *         formatter: CryptoJS.format.OpenSSL
+	         *     });
+	         */
+	        init: function (cipherParams) {
+	            this.mixIn(cipherParams);
+	        },
+
+	        /**
+	         * Converts this cipher params object to a string.
+	         *
+	         * @param {Format} formatter (Optional) The formatting strategy to use.
+	         *
+	         * @return {string} The stringified cipher params.
+	         *
+	         * @throws Error If neither the formatter nor the default formatter is set.
+	         *
+	         * @example
+	         *
+	         *     var string = cipherParams + '';
+	         *     var string = cipherParams.toString();
+	         *     var string = cipherParams.toString(CryptoJS.format.OpenSSL);
+	         */
+	        toString: function (formatter) {
+	            return (formatter || this.formatter).stringify(this);
+	        }
+	    });
+
+	    /**
+	     * Format namespace.
+	     */
+	    var C_format = C.format = {};
+
+	    /**
+	     * OpenSSL formatting strategy.
+	     */
+	    var OpenSSLFormatter = C_format.OpenSSL = {
+	        /**
+	         * Converts a cipher params object to an OpenSSL-compatible string.
+	         *
+	         * @param {CipherParams} cipherParams The cipher params object.
+	         *
+	         * @return {string} The OpenSSL-compatible string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);
+	         */
+	        stringify: function (cipherParams) {
+	            var wordArray;
+
+	            // Shortcuts
+	            var ciphertext = cipherParams.ciphertext;
+	            var salt = cipherParams.salt;
+
+	            // Format
+	            if (salt) {
+	                wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
+	            } else {
+	                wordArray = ciphertext;
+	            }
+
+	            return wordArray.toString(Base64);
+	        },
+
+	        /**
+	         * Converts an OpenSSL-compatible string to a cipher params object.
+	         *
+	         * @param {string} openSSLStr The OpenSSL-compatible string.
+	         *
+	         * @return {CipherParams} The cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);
+	         */
+	        parse: function (openSSLStr) {
+	            var salt;
+
+	            // Parse base64
+	            var ciphertext = Base64.parse(openSSLStr);
+
+	            // Shortcut
+	            var ciphertextWords = ciphertext.words;
+
+	            // Test for salt
+	            if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) {
+	                // Extract salt
+	                salt = WordArray.create(ciphertextWords.slice(2, 4));
+
+	                // Remove salt from ciphertext
+	                ciphertextWords.splice(0, 4);
+	                ciphertext.sigBytes -= 16;
+	            }
+
+	            return CipherParams.create({ ciphertext: ciphertext, salt: salt });
+	        }
+	    };
+
+	    /**
+	     * A cipher wrapper that returns ciphertext as a serializable cipher params object.
+	     */
+	    var SerializableCipher = C_lib.SerializableCipher = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL
+	         */
+	        cfg: Base.extend({
+	            format: OpenSSLFormatter
+	        }),
+
+	        /**
+	         * Encrypts a message.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {WordArray|string} message The message to encrypt.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {CipherParams} A cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key);
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv });
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         */
+	        encrypt: function (cipher, message, key, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Encrypt
+	            var encryptor = cipher.createEncryptor(key, cfg);
+	            var ciphertext = encryptor.finalize(message);
+
+	            // Shortcut
+	            var cipherCfg = encryptor.cfg;
+
+	            // Create and return serializable cipher params
+	            return CipherParams.create({
+	                ciphertext: ciphertext,
+	                key: key,
+	                iv: cipherCfg.iv,
+	                algorithm: cipher,
+	                mode: cipherCfg.mode,
+	                padding: cipherCfg.padding,
+	                blockSize: cipher.blockSize,
+	                formatter: cfg.format
+	            });
+	        },
+
+	        /**
+	         * Decrypts serialized ciphertext.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {WordArray} The plaintext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         *     var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         */
+	        decrypt: function (cipher, ciphertext, key, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Convert string to CipherParams
+	            ciphertext = this._parse(ciphertext, cfg.format);
+
+	            // Decrypt
+	            var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext);
+
+	            return plaintext;
+	        },
+
+	        /**
+	         * Converts serialized ciphertext to CipherParams,
+	         * else assumed CipherParams already and returns ciphertext unchanged.
+	         *
+	         * @param {CipherParams|string} ciphertext The ciphertext.
+	         * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext.
+	         *
+	         * @return {CipherParams} The unserialized ciphertext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);
+	         */
+	        _parse: function (ciphertext, format) {
+	            if (typeof ciphertext == 'string') {
+	                return format.parse(ciphertext, this);
+	            } else {
+	                return ciphertext;
+	            }
+	        }
+	    });
+
+	    /**
+	     * Key derivation function namespace.
+	     */
+	    var C_kdf = C.kdf = {};
+
+	    /**
+	     * OpenSSL key derivation function.
+	     */
+	    var OpenSSLKdf = C_kdf.OpenSSL = {
+	        /**
+	         * Derives a key and IV from a password.
+	         *
+	         * @param {string} password The password to derive from.
+	         * @param {number} keySize The size in words of the key to generate.
+	         * @param {number} ivSize The size in words of the IV to generate.
+	         * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.
+	         *
+	         * @return {CipherParams} A cipher params object with the key, IV, and salt.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
+	         *     var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
+	         */
+	        execute: function (password, keySize, ivSize, salt) {
+	            // Generate random salt
+	            if (!salt) {
+	                salt = WordArray.random(64/8);
+	            }
+
+	            // Derive key and IV
+	            var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
+
+	            // Separate key and IV
+	            var iv = WordArray.create(key.words.slice(keySize), ivSize * 4);
+	            key.sigBytes = keySize * 4;
+
+	            // Return params
+	            return CipherParams.create({ key: key, iv: iv, salt: salt });
+	        }
+	    };
+
+	    /**
+	     * A serializable cipher wrapper that derives the key from a password,
+	     * and returns ciphertext as a serializable cipher params object.
+	     */
+	    var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL
+	         */
+	        cfg: SerializableCipher.cfg.extend({
+	            kdf: OpenSSLKdf
+	        }),
+
+	        /**
+	         * Encrypts a message using a password.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {WordArray|string} message The message to encrypt.
+	         * @param {string} password The password.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {CipherParams} A cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password');
+	         *     var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });
+	         */
+	        encrypt: function (cipher, message, password, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Derive key and other params
+	            var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize);
+
+	            // Add IV to config
+	            cfg.iv = derivedParams.iv;
+
+	            // Encrypt
+	            var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg);
+
+	            // Mix in derived params
+	            ciphertext.mixIn(derivedParams);
+
+	            return ciphertext;
+	        },
+
+	        /**
+	         * Decrypts serialized ciphertext using a password.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
+	         * @param {string} password The password.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {WordArray} The plaintext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL });
+	         *     var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL });
+	         */
+	        decrypt: function (cipher, ciphertext, password, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Convert string to CipherParams
+	            ciphertext = this._parse(ciphertext, cfg.format);
+
+	            // Derive key and other params
+	            var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt);
+
+	            // Add IV to config
+	            cfg.iv = derivedParams.iv;
+
+	            // Decrypt
+	            var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg);
+
+	            return plaintext;
+	        }
+	    });
+	}());
+
+
+	/**
+	 * Cipher Feedback block mode.
+	 */
+	CryptoJS.mode.CFB = (function () {
+	    var CFB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    CFB.Encryptor = CFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher;
+	            var blockSize = cipher.blockSize;
+
+	            generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher);
+
+	            // Remember this block to use with next block
+	            this._prevBlock = words.slice(offset, offset + blockSize);
+	        }
+	    });
+
+	    CFB.Decryptor = CFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher;
+	            var blockSize = cipher.blockSize;
+
+	            // Remember this block to use with next block
+	            var thisBlock = words.slice(offset, offset + blockSize);
+
+	            generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher);
+
+	            // This block becomes the previous block
+	            this._prevBlock = thisBlock;
+	        }
+	    });
+
+	    function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) {
+	        var keystream;
+
+	        // Shortcut
+	        var iv = this._iv;
+
+	        // Generate keystream
+	        if (iv) {
+	            keystream = iv.slice(0);
+
+	            // Remove IV for subsequent blocks
+	            this._iv = undefined;
+	        } else {
+	            keystream = this._prevBlock;
+	        }
+	        cipher.encryptBlock(keystream, 0);
+
+	        // Encrypt
+	        for (var i = 0; i < blockSize; i++) {
+	            words[offset + i] ^= keystream[i];
+	        }
+	    }
+
+	    return CFB;
+	}());
+
+
+	/**
+	 * Counter block mode.
+	 */
+	CryptoJS.mode.CTR = (function () {
+	    var CTR = CryptoJS.lib.BlockCipherMode.extend();
+
+	    var Encryptor = CTR.Encryptor = CTR.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var counter = this._counter;
+
+	            // Generate keystream
+	            if (iv) {
+	                counter = this._counter = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+	            var keystream = counter.slice(0);
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Increment counter
+	            counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    CTR.Decryptor = Encryptor;
+
+	    return CTR;
+	}());
+
+
+	/** @preserve
+	 * Counter block mode compatible with  Dr Brian Gladman fileenc.c
+	 * derived from CryptoJS.mode.CTR
+	 * Jan Hruby jhruby.web@gmail.com
+	 */
+	CryptoJS.mode.CTRGladman = (function () {
+	    var CTRGladman = CryptoJS.lib.BlockCipherMode.extend();
+
+		function incWord(word)
+		{
+			if (((word >> 24) & 0xff) === 0xff) { //overflow
+			var b1 = (word >> 16)&0xff;
+			var b2 = (word >> 8)&0xff;
+			var b3 = word & 0xff;
+
+			if (b1 === 0xff) // overflow b1
+			{
+			b1 = 0;
+			if (b2 === 0xff)
+			{
+				b2 = 0;
+				if (b3 === 0xff)
+				{
+					b3 = 0;
+				}
+				else
+				{
+					++b3;
+				}
+			}
+			else
+			{
+				++b2;
+			}
+			}
+			else
+			{
+			++b1;
+			}
+
+			word = 0;
+			word += (b1 << 16);
+			word += (b2 << 8);
+			word += b3;
+			}
+			else
+			{
+			word += (0x01 << 24);
+			}
+			return word;
+		}
+
+		function incCounter(counter)
+		{
+			if ((counter[0] = incWord(counter[0])) === 0)
+			{
+				// encr_data in fileenc.c from  Dr Brian Gladman's counts only with DWORD j < 8
+				counter[1] = incWord(counter[1]);
+			}
+			return counter;
+		}
+
+	    var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var counter = this._counter;
+
+	            // Generate keystream
+	            if (iv) {
+	                counter = this._counter = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+
+				incCounter(counter);
+
+				var keystream = counter.slice(0);
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    CTRGladman.Decryptor = Encryptor;
+
+	    return CTRGladman;
+	}());
+
+
+
+
+	/**
+	 * Output Feedback block mode.
+	 */
+	CryptoJS.mode.OFB = (function () {
+	    var OFB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    var Encryptor = OFB.Encryptor = OFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var keystream = this._keystream;
+
+	            // Generate keystream
+	            if (iv) {
+	                keystream = this._keystream = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    OFB.Decryptor = Encryptor;
+
+	    return OFB;
+	}());
+
+
+	/**
+	 * Electronic Codebook block mode.
+	 */
+	CryptoJS.mode.ECB = (function () {
+	    var ECB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    ECB.Encryptor = ECB.extend({
+	        processBlock: function (words, offset) {
+	            this._cipher.encryptBlock(words, offset);
+	        }
+	    });
+
+	    ECB.Decryptor = ECB.extend({
+	        processBlock: function (words, offset) {
+	            this._cipher.decryptBlock(words, offset);
+	        }
+	    });
+
+	    return ECB;
+	}());
+
+
+	/**
+	 * ANSI X.923 padding strategy.
+	 */
+	CryptoJS.pad.AnsiX923 = {
+	    pad: function (data, blockSize) {
+	        // Shortcuts
+	        var dataSigBytes = data.sigBytes;
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Count padding bytes
+	        var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes;
+
+	        // Compute last byte position
+	        var lastBytePos = dataSigBytes + nPaddingBytes - 1;
+
+	        // Pad
+	        data.clamp();
+	        data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8);
+	        data.sigBytes += nPaddingBytes;
+	    },
+
+	    unpad: function (data) {
+	        // Get number of padding bytes from last byte
+	        var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	        // Remove padding
+	        data.sigBytes -= nPaddingBytes;
+	    }
+	};
+
+
+	/**
+	 * ISO 10126 padding strategy.
+	 */
+	CryptoJS.pad.Iso10126 = {
+	    pad: function (data, blockSize) {
+	        // Shortcut
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Count padding bytes
+	        var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
+
+	        // Pad
+	        data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)).
+	             concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1));
+	    },
+
+	    unpad: function (data) {
+	        // Get number of padding bytes from last byte
+	        var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	        // Remove padding
+	        data.sigBytes -= nPaddingBytes;
+	    }
+	};
+
+
+	/**
+	 * ISO/IEC 9797-1 Padding Method 2.
+	 */
+	CryptoJS.pad.Iso97971 = {
+	    pad: function (data, blockSize) {
+	        // Add 0x80 byte
+	        data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1));
+
+	        // Zero pad the rest
+	        CryptoJS.pad.ZeroPadding.pad(data, blockSize);
+	    },
+
+	    unpad: function (data) {
+	        // Remove zero padding
+	        CryptoJS.pad.ZeroPadding.unpad(data);
+
+	        // Remove one more byte -- the 0x80 byte
+	        data.sigBytes--;
+	    }
+	};
+
+
+	/**
+	 * Zero padding strategy.
+	 */
+	CryptoJS.pad.ZeroPadding = {
+	    pad: function (data, blockSize) {
+	        // Shortcut
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Pad
+	        data.clamp();
+	        data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes);
+	    },
+
+	    unpad: function (data) {
+	        // Shortcut
+	        var dataWords = data.words;
+
+	        // Unpad
+	        var i = data.sigBytes - 1;
+	        for (var i = data.sigBytes - 1; i >= 0; i--) {
+	            if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) {
+	                data.sigBytes = i + 1;
+	                break;
+	            }
+	        }
+	    }
+	};
+
+
+	/**
+	 * A noop padding strategy.
+	 */
+	CryptoJS.pad.NoPadding = {
+	    pad: function () {
+	    },
+
+	    unpad: function () {
+	    }
+	};
+
+
+	(function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var CipherParams = C_lib.CipherParams;
+	    var C_enc = C.enc;
+	    var Hex = C_enc.Hex;
+	    var C_format = C.format;
+
+	    var HexFormatter = C_format.Hex = {
+	        /**
+	         * Converts the ciphertext of a cipher params object to a hexadecimally encoded string.
+	         *
+	         * @param {CipherParams} cipherParams The cipher params object.
+	         *
+	         * @return {string} The hexadecimally encoded string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var hexString = CryptoJS.format.Hex.stringify(cipherParams);
+	         */
+	        stringify: function (cipherParams) {
+	            return cipherParams.ciphertext.toString(Hex);
+	        },
+
+	        /**
+	         * Converts a hexadecimally encoded ciphertext string to a cipher params object.
+	         *
+	         * @param {string} input The hexadecimally encoded string.
+	         *
+	         * @return {CipherParams} The cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.format.Hex.parse(hexString);
+	         */
+	        parse: function (input) {
+	            var ciphertext = Hex.parse(input);
+	            return CipherParams.create({ ciphertext: ciphertext });
+	        }
+	    };
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var BlockCipher = C_lib.BlockCipher;
+	    var C_algo = C.algo;
+
+	    // Lookup tables
+	    var SBOX = [];
+	    var INV_SBOX = [];
+	    var SUB_MIX_0 = [];
+	    var SUB_MIX_1 = [];
+	    var SUB_MIX_2 = [];
+	    var SUB_MIX_3 = [];
+	    var INV_SUB_MIX_0 = [];
+	    var INV_SUB_MIX_1 = [];
+	    var INV_SUB_MIX_2 = [];
+	    var INV_SUB_MIX_3 = [];
+
+	    // Compute lookup tables
+	    (function () {
+	        // Compute double table
+	        var d = [];
+	        for (var i = 0; i < 256; i++) {
+	            if (i < 128) {
+	                d[i] = i << 1;
+	            } else {
+	                d[i] = (i << 1) ^ 0x11b;
+	            }
+	        }
+
+	        // Walk GF(2^8)
+	        var x = 0;
+	        var xi = 0;
+	        for (var i = 0; i < 256; i++) {
+	            // Compute sbox
+	            var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4);
+	            sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63;
+	            SBOX[x] = sx;
+	            INV_SBOX[sx] = x;
+
+	            // Compute multiplication
+	            var x2 = d[x];
+	            var x4 = d[x2];
+	            var x8 = d[x4];
+
+	            // Compute sub bytes, mix columns tables
+	            var t = (d[sx] * 0x101) ^ (sx * 0x1010100);
+	            SUB_MIX_0[x] = (t << 24) | (t >>> 8);
+	            SUB_MIX_1[x] = (t << 16) | (t >>> 16);
+	            SUB_MIX_2[x] = (t << 8)  | (t >>> 24);
+	            SUB_MIX_3[x] = t;
+
+	            // Compute inv sub bytes, inv mix columns tables
+	            var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100);
+	            INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8);
+	            INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16);
+	            INV_SUB_MIX_2[sx] = (t << 8)  | (t >>> 24);
+	            INV_SUB_MIX_3[sx] = t;
+
+	            // Compute next counter
+	            if (!x) {
+	                x = xi = 1;
+	            } else {
+	                x = x2 ^ d[d[d[x8 ^ x2]]];
+	                xi ^= d[d[xi]];
+	            }
+	        }
+	    }());
+
+	    // Precomputed Rcon lookup
+	    var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
+
+	    /**
+	     * AES block cipher algorithm.
+	     */
+	    var AES = C_algo.AES = BlockCipher.extend({
+	        _doReset: function () {
+	            var t;
+
+	            // Skip reset of nRounds has been set before and key did not change
+	            if (this._nRounds && this._keyPriorReset === this._key) {
+	                return;
+	            }
+
+	            // Shortcuts
+	            var key = this._keyPriorReset = this._key;
+	            var keyWords = key.words;
+	            var keySize = key.sigBytes / 4;
+
+	            // Compute number of rounds
+	            var nRounds = this._nRounds = keySize + 6;
+
+	            // Compute number of key schedule rows
+	            var ksRows = (nRounds + 1) * 4;
+
+	            // Compute key schedule
+	            var keySchedule = this._keySchedule = [];
+	            for (var ksRow = 0; ksRow < ksRows; ksRow++) {
+	                if (ksRow < keySize) {
+	                    keySchedule[ksRow] = keyWords[ksRow];
+	                } else {
+	                    t = keySchedule[ksRow - 1];
+
+	                    if (!(ksRow % keySize)) {
+	                        // Rot word
+	                        t = (t << 8) | (t >>> 24);
+
+	                        // Sub word
+	                        t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
+
+	                        // Mix Rcon
+	                        t ^= RCON[(ksRow / keySize) | 0] << 24;
+	                    } else if (keySize > 6 && ksRow % keySize == 4) {
+	                        // Sub word
+	                        t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
+	                    }
+
+	                    keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t;
+	                }
+	            }
+
+	            // Compute inv key schedule
+	            var invKeySchedule = this._invKeySchedule = [];
+	            for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) {
+	                var ksRow = ksRows - invKsRow;
+
+	                if (invKsRow % 4) {
+	                    var t = keySchedule[ksRow];
+	                } else {
+	                    var t = keySchedule[ksRow - 4];
+	                }
+
+	                if (invKsRow < 4 || ksRow <= 4) {
+	                    invKeySchedule[invKsRow] = t;
+	                } else {
+	                    invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^
+	                                               INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]];
+	                }
+	            }
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            // Swap 2nd and 4th rows
+	            var t = M[offset + 1];
+	            M[offset + 1] = M[offset + 3];
+	            M[offset + 3] = t;
+
+	            this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX);
+
+	            // Inv swap 2nd and 4th rows
+	            var t = M[offset + 1];
+	            M[offset + 1] = M[offset + 3];
+	            M[offset + 3] = t;
+	        },
+
+	        _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) {
+	            // Shortcut
+	            var nRounds = this._nRounds;
+
+	            // Get input, add round key
+	            var s0 = M[offset]     ^ keySchedule[0];
+	            var s1 = M[offset + 1] ^ keySchedule[1];
+	            var s2 = M[offset + 2] ^ keySchedule[2];
+	            var s3 = M[offset + 3] ^ keySchedule[3];
+
+	            // Key schedule row counter
+	            var ksRow = 4;
+
+	            // Rounds
+	            for (var round = 1; round < nRounds; round++) {
+	                // Shift rows, sub bytes, mix columns, add round key
+	                var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++];
+	                var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++];
+	                var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++];
+	                var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++];
+
+	                // Update state
+	                s0 = t0;
+	                s1 = t1;
+	                s2 = t2;
+	                s3 = t3;
+	            }
+
+	            // Shift rows, sub bytes, add round key
+	            var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++];
+	            var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++];
+	            var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++];
+	            var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++];
+
+	            // Set output
+	            M[offset]     = t0;
+	            M[offset + 1] = t1;
+	            M[offset + 2] = t2;
+	            M[offset + 3] = t3;
+	        },
+
+	        keySize: 256/32
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.AES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.AES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.AES = BlockCipher._createHelper(AES);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var BlockCipher = C_lib.BlockCipher;
+	    var C_algo = C.algo;
+
+	    // Permuted Choice 1 constants
+	    var PC1 = [
+	        57, 49, 41, 33, 25, 17, 9,  1,
+	        58, 50, 42, 34, 26, 18, 10, 2,
+	        59, 51, 43, 35, 27, 19, 11, 3,
+	        60, 52, 44, 36, 63, 55, 47, 39,
+	        31, 23, 15, 7,  62, 54, 46, 38,
+	        30, 22, 14, 6,  61, 53, 45, 37,
+	        29, 21, 13, 5,  28, 20, 12, 4
+	    ];
+
+	    // Permuted Choice 2 constants
+	    var PC2 = [
+	        14, 17, 11, 24, 1,  5,
+	        3,  28, 15, 6,  21, 10,
+	        23, 19, 12, 4,  26, 8,
+	        16, 7,  27, 20, 13, 2,
+	        41, 52, 31, 37, 47, 55,
+	        30, 40, 51, 45, 33, 48,
+	        44, 49, 39, 56, 34, 53,
+	        46, 42, 50, 36, 29, 32
+	    ];
+
+	    // Cumulative bit shift constants
+	    var BIT_SHIFTS = [1,  2,  4,  6,  8,  10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28];
+
+	    // SBOXes and round permutation constants
+	    var SBOX_P = [
+	        {
+	            0x0: 0x808200,
+	            0x10000000: 0x8000,
+	            0x20000000: 0x808002,
+	            0x30000000: 0x2,
+	            0x40000000: 0x200,
+	            0x50000000: 0x808202,
+	            0x60000000: 0x800202,
+	            0x70000000: 0x800000,
+	            0x80000000: 0x202,
+	            0x90000000: 0x800200,
+	            0xa0000000: 0x8200,
+	            0xb0000000: 0x808000,
+	            0xc0000000: 0x8002,
+	            0xd0000000: 0x800002,
+	            0xe0000000: 0x0,
+	            0xf0000000: 0x8202,
+	            0x8000000: 0x0,
+	            0x18000000: 0x808202,
+	            0x28000000: 0x8202,
+	            0x38000000: 0x8000,
+	            0x48000000: 0x808200,
+	            0x58000000: 0x200,
+	            0x68000000: 0x808002,
+	            0x78000000: 0x2,
+	            0x88000000: 0x800200,
+	            0x98000000: 0x8200,
+	            0xa8000000: 0x808000,
+	            0xb8000000: 0x800202,
+	            0xc8000000: 0x800002,
+	            0xd8000000: 0x8002,
+	            0xe8000000: 0x202,
+	            0xf8000000: 0x800000,
+	            0x1: 0x8000,
+	            0x10000001: 0x2,
+	            0x20000001: 0x808200,
+	            0x30000001: 0x800000,
+	            0x40000001: 0x808002,
+	            0x50000001: 0x8200,
+	            0x60000001: 0x200,
+	            0x70000001: 0x800202,
+	            0x80000001: 0x808202,
+	            0x90000001: 0x808000,
+	            0xa0000001: 0x800002,
+	            0xb0000001: 0x8202,
+	            0xc0000001: 0x202,
+	            0xd0000001: 0x800200,
+	            0xe0000001: 0x8002,
+	            0xf0000001: 0x0,
+	            0x8000001: 0x808202,
+	            0x18000001: 0x808000,
+	            0x28000001: 0x800000,
+	            0x38000001: 0x200,
+	            0x48000001: 0x8000,
+	            0x58000001: 0x800002,
+	            0x68000001: 0x2,
+	            0x78000001: 0x8202,
+	            0x88000001: 0x8002,
+	            0x98000001: 0x800202,
+	            0xa8000001: 0x202,
+	            0xb8000001: 0x808200,
+	            0xc8000001: 0x800200,
+	            0xd8000001: 0x0,
+	            0xe8000001: 0x8200,
+	            0xf8000001: 0x808002
+	        },
+	        {
+	            0x0: 0x40084010,
+	            0x1000000: 0x4000,
+	            0x2000000: 0x80000,
+	            0x3000000: 0x40080010,
+	            0x4000000: 0x40000010,
+	            0x5000000: 0x40084000,
+	            0x6000000: 0x40004000,
+	            0x7000000: 0x10,
+	            0x8000000: 0x84000,
+	            0x9000000: 0x40004010,
+	            0xa000000: 0x40000000,
+	            0xb000000: 0x84010,
+	            0xc000000: 0x80010,
+	            0xd000000: 0x0,
+	            0xe000000: 0x4010,
+	            0xf000000: 0x40080000,
+	            0x800000: 0x40004000,
+	            0x1800000: 0x84010,
+	            0x2800000: 0x10,
+	            0x3800000: 0x40004010,
+	            0x4800000: 0x40084010,
+	            0x5800000: 0x40000000,
+	            0x6800000: 0x80000,
+	            0x7800000: 0x40080010,
+	            0x8800000: 0x80010,
+	            0x9800000: 0x0,
+	            0xa800000: 0x4000,
+	            0xb800000: 0x40080000,
+	            0xc800000: 0x40000010,
+	            0xd800000: 0x84000,
+	            0xe800000: 0x40084000,
+	            0xf800000: 0x4010,
+	            0x10000000: 0x0,
+	            0x11000000: 0x40080010,
+	            0x12000000: 0x40004010,
+	            0x13000000: 0x40084000,
+	            0x14000000: 0x40080000,
+	            0x15000000: 0x10,
+	            0x16000000: 0x84010,
+	            0x17000000: 0x4000,
+	            0x18000000: 0x4010,
+	            0x19000000: 0x80000,
+	            0x1a000000: 0x80010,
+	            0x1b000000: 0x40000010,
+	            0x1c000000: 0x84000,
+	            0x1d000000: 0x40004000,
+	            0x1e000000: 0x40000000,
+	            0x1f000000: 0x40084010,
+	            0x10800000: 0x84010,
+	            0x11800000: 0x80000,
+	            0x12800000: 0x40080000,
+	            0x13800000: 0x4000,
+	            0x14800000: 0x40004000,
+	            0x15800000: 0x40084010,
+	            0x16800000: 0x10,
+	            0x17800000: 0x40000000,
+	            0x18800000: 0x40084000,
+	            0x19800000: 0x40000010,
+	            0x1a800000: 0x40004010,
+	            0x1b800000: 0x80010,
+	            0x1c800000: 0x0,
+	            0x1d800000: 0x4010,
+	            0x1e800000: 0x40080010,
+	            0x1f800000: 0x84000
+	        },
+	        {
+	            0x0: 0x104,
+	            0x100000: 0x0,
+	            0x200000: 0x4000100,
+	            0x300000: 0x10104,
+	            0x400000: 0x10004,
+	            0x500000: 0x4000004,
+	            0x600000: 0x4010104,
+	            0x700000: 0x4010000,
+	            0x800000: 0x4000000,
+	            0x900000: 0x4010100,
+	            0xa00000: 0x10100,
+	            0xb00000: 0x4010004,
+	            0xc00000: 0x4000104,
+	            0xd00000: 0x10000,
+	            0xe00000: 0x4,
+	            0xf00000: 0x100,
+	            0x80000: 0x4010100,
+	            0x180000: 0x4010004,
+	            0x280000: 0x0,
+	            0x380000: 0x4000100,
+	            0x480000: 0x4000004,
+	            0x580000: 0x10000,
+	            0x680000: 0x10004,
+	            0x780000: 0x104,
+	            0x880000: 0x4,
+	            0x980000: 0x100,
+	            0xa80000: 0x4010000,
+	            0xb80000: 0x10104,
+	            0xc80000: 0x10100,
+	            0xd80000: 0x4000104,
+	            0xe80000: 0x4010104,
+	            0xf80000: 0x4000000,
+	            0x1000000: 0x4010100,
+	            0x1100000: 0x10004,
+	            0x1200000: 0x10000,
+	            0x1300000: 0x4000100,
+	            0x1400000: 0x100,
+	            0x1500000: 0x4010104,
+	            0x1600000: 0x4000004,
+	            0x1700000: 0x0,
+	            0x1800000: 0x4000104,
+	            0x1900000: 0x4000000,
+	            0x1a00000: 0x4,
+	            0x1b00000: 0x10100,
+	            0x1c00000: 0x4010000,
+	            0x1d00000: 0x104,
+	            0x1e00000: 0x10104,
+	            0x1f00000: 0x4010004,
+	            0x1080000: 0x4000000,
+	            0x1180000: 0x104,
+	            0x1280000: 0x4010100,
+	            0x1380000: 0x0,
+	            0x1480000: 0x10004,
+	            0x1580000: 0x4000100,
+	            0x1680000: 0x100,
+	            0x1780000: 0x4010004,
+	            0x1880000: 0x10000,
+	            0x1980000: 0x4010104,
+	            0x1a80000: 0x10104,
+	            0x1b80000: 0x4000004,
+	            0x1c80000: 0x4000104,
+	            0x1d80000: 0x4010000,
+	            0x1e80000: 0x4,
+	            0x1f80000: 0x10100
+	        },
+	        {
+	            0x0: 0x80401000,
+	            0x10000: 0x80001040,
+	            0x20000: 0x401040,
+	            0x30000: 0x80400000,
+	            0x40000: 0x0,
+	            0x50000: 0x401000,
+	            0x60000: 0x80000040,
+	            0x70000: 0x400040,
+	            0x80000: 0x80000000,
+	            0x90000: 0x400000,
+	            0xa0000: 0x40,
+	            0xb0000: 0x80001000,
+	            0xc0000: 0x80400040,
+	            0xd0000: 0x1040,
+	            0xe0000: 0x1000,
+	            0xf0000: 0x80401040,
+	            0x8000: 0x80001040,
+	            0x18000: 0x40,
+	            0x28000: 0x80400040,
+	            0x38000: 0x80001000,
+	            0x48000: 0x401000,
+	            0x58000: 0x80401040,
+	            0x68000: 0x0,
+	            0x78000: 0x80400000,
+	            0x88000: 0x1000,
+	            0x98000: 0x80401000,
+	            0xa8000: 0x400000,
+	            0xb8000: 0x1040,
+	            0xc8000: 0x80000000,
+	            0xd8000: 0x400040,
+	            0xe8000: 0x401040,
+	            0xf8000: 0x80000040,
+	            0x100000: 0x400040,
+	            0x110000: 0x401000,
+	            0x120000: 0x80000040,
+	            0x130000: 0x0,
+	            0x140000: 0x1040,
+	            0x150000: 0x80400040,
+	            0x160000: 0x80401000,
+	            0x170000: 0x80001040,
+	            0x180000: 0x80401040,
+	            0x190000: 0x80000000,
+	            0x1a0000: 0x80400000,
+	            0x1b0000: 0x401040,
+	            0x1c0000: 0x80001000,
+	            0x1d0000: 0x400000,
+	            0x1e0000: 0x40,
+	            0x1f0000: 0x1000,
+	            0x108000: 0x80400000,
+	            0x118000: 0x80401040,
+	            0x128000: 0x0,
+	            0x138000: 0x401000,
+	            0x148000: 0x400040,
+	            0x158000: 0x80000000,
+	            0x168000: 0x80001040,
+	            0x178000: 0x40,
+	            0x188000: 0x80000040,
+	            0x198000: 0x1000,
+	            0x1a8000: 0x80001000,
+	            0x1b8000: 0x80400040,
+	            0x1c8000: 0x1040,
+	            0x1d8000: 0x80401000,
+	            0x1e8000: 0x400000,
+	            0x1f8000: 0x401040
+	        },
+	        {
+	            0x0: 0x80,
+	            0x1000: 0x1040000,
+	            0x2000: 0x40000,
+	            0x3000: 0x20000000,
+	            0x4000: 0x20040080,
+	            0x5000: 0x1000080,
+	            0x6000: 0x21000080,
+	            0x7000: 0x40080,
+	            0x8000: 0x1000000,
+	            0x9000: 0x20040000,
+	            0xa000: 0x20000080,
+	            0xb000: 0x21040080,
+	            0xc000: 0x21040000,
+	            0xd000: 0x0,
+	            0xe000: 0x1040080,
+	            0xf000: 0x21000000,
+	            0x800: 0x1040080,
+	            0x1800: 0x21000080,
+	            0x2800: 0x80,
+	            0x3800: 0x1040000,
+	            0x4800: 0x40000,
+	            0x5800: 0x20040080,
+	            0x6800: 0x21040000,
+	            0x7800: 0x20000000,
+	            0x8800: 0x20040000,
+	            0x9800: 0x0,
+	            0xa800: 0x21040080,
+	            0xb800: 0x1000080,
+	            0xc800: 0x20000080,
+	            0xd800: 0x21000000,
+	            0xe800: 0x1000000,
+	            0xf800: 0x40080,
+	            0x10000: 0x40000,
+	            0x11000: 0x80,
+	            0x12000: 0x20000000,
+	            0x13000: 0x21000080,
+	            0x14000: 0x1000080,
+	            0x15000: 0x21040000,
+	            0x16000: 0x20040080,
+	            0x17000: 0x1000000,
+	            0x18000: 0x21040080,
+	            0x19000: 0x21000000,
+	            0x1a000: 0x1040000,
+	            0x1b000: 0x20040000,
+	            0x1c000: 0x40080,
+	            0x1d000: 0x20000080,
+	            0x1e000: 0x0,
+	            0x1f000: 0x1040080,
+	            0x10800: 0x21000080,
+	            0x11800: 0x1000000,
+	            0x12800: 0x1040000,
+	            0x13800: 0x20040080,
+	            0x14800: 0x20000000,
+	            0x15800: 0x1040080,
+	            0x16800: 0x80,
+	            0x17800: 0x21040000,
+	            0x18800: 0x40080,
+	            0x19800: 0x21040080,
+	            0x1a800: 0x0,
+	            0x1b800: 0x21000000,
+	            0x1c800: 0x1000080,
+	            0x1d800: 0x40000,
+	            0x1e800: 0x20040000,
+	            0x1f800: 0x20000080
+	        },
+	        {
+	            0x0: 0x10000008,
+	            0x100: 0x2000,
+	            0x200: 0x10200000,
+	            0x300: 0x10202008,
+	            0x400: 0x10002000,
+	            0x500: 0x200000,
+	            0x600: 0x200008,
+	            0x700: 0x10000000,
+	            0x800: 0x0,
+	            0x900: 0x10002008,
+	            0xa00: 0x202000,
+	            0xb00: 0x8,
+	            0xc00: 0x10200008,
+	            0xd00: 0x202008,
+	            0xe00: 0x2008,
+	            0xf00: 0x10202000,
+	            0x80: 0x10200000,
+	            0x180: 0x10202008,
+	            0x280: 0x8,
+	            0x380: 0x200000,
+	            0x480: 0x202008,
+	            0x580: 0x10000008,
+	            0x680: 0x10002000,
+	            0x780: 0x2008,
+	            0x880: 0x200008,
+	            0x980: 0x2000,
+	            0xa80: 0x10002008,
+	            0xb80: 0x10200008,
+	            0xc80: 0x0,
+	            0xd80: 0x10202000,
+	            0xe80: 0x202000,
+	            0xf80: 0x10000000,
+	            0x1000: 0x10002000,
+	            0x1100: 0x10200008,
+	            0x1200: 0x10202008,
+	            0x1300: 0x2008,
+	            0x1400: 0x200000,
+	            0x1500: 0x10000000,
+	            0x1600: 0x10000008,
+	            0x1700: 0x202000,
+	            0x1800: 0x202008,
+	            0x1900: 0x0,
+	            0x1a00: 0x8,
+	            0x1b00: 0x10200000,
+	            0x1c00: 0x2000,
+	            0x1d00: 0x10002008,
+	            0x1e00: 0x10202000,
+	            0x1f00: 0x200008,
+	            0x1080: 0x8,
+	            0x1180: 0x202000,
+	            0x1280: 0x200000,
+	            0x1380: 0x10000008,
+	            0x1480: 0x10002000,
+	            0x1580: 0x2008,
+	            0x1680: 0x10202008,
+	            0x1780: 0x10200000,
+	            0x1880: 0x10202000,
+	            0x1980: 0x10200008,
+	            0x1a80: 0x2000,
+	            0x1b80: 0x202008,
+	            0x1c80: 0x200008,
+	            0x1d80: 0x0,
+	            0x1e80: 0x10000000,
+	            0x1f80: 0x10002008
+	        },
+	        {
+	            0x0: 0x100000,
+	            0x10: 0x2000401,
+	            0x20: 0x400,
+	            0x30: 0x100401,
+	            0x40: 0x2100401,
+	            0x50: 0x0,
+	            0x60: 0x1,
+	            0x70: 0x2100001,
+	            0x80: 0x2000400,
+	            0x90: 0x100001,
+	            0xa0: 0x2000001,
+	            0xb0: 0x2100400,
+	            0xc0: 0x2100000,
+	            0xd0: 0x401,
+	            0xe0: 0x100400,
+	            0xf0: 0x2000000,
+	            0x8: 0x2100001,
+	            0x18: 0x0,
+	            0x28: 0x2000401,
+	            0x38: 0x2100400,
+	            0x48: 0x100000,
+	            0x58: 0x2000001,
+	            0x68: 0x2000000,
+	            0x78: 0x401,
+	            0x88: 0x100401,
+	            0x98: 0x2000400,
+	            0xa8: 0x2100000,
+	            0xb8: 0x100001,
+	            0xc8: 0x400,
+	            0xd8: 0x2100401,
+	            0xe8: 0x1,
+	            0xf8: 0x100400,
+	            0x100: 0x2000000,
+	            0x110: 0x100000,
+	            0x120: 0x2000401,
+	            0x130: 0x2100001,
+	            0x140: 0x100001,
+	            0x150: 0x2000400,
+	            0x160: 0x2100400,
+	            0x170: 0x100401,
+	            0x180: 0x401,
+	            0x190: 0x2100401,
+	            0x1a0: 0x100400,
+	            0x1b0: 0x1,
+	            0x1c0: 0x0,
+	            0x1d0: 0x2100000,
+	            0x1e0: 0x2000001,
+	            0x1f0: 0x400,
+	            0x108: 0x100400,
+	            0x118: 0x2000401,
+	            0x128: 0x2100001,
+	            0x138: 0x1,
+	            0x148: 0x2000000,
+	            0x158: 0x100000,
+	            0x168: 0x401,
+	            0x178: 0x2100400,
+	            0x188: 0x2000001,
+	            0x198: 0x2100000,
+	            0x1a8: 0x0,
+	            0x1b8: 0x2100401,
+	            0x1c8: 0x100401,
+	            0x1d8: 0x400,
+	            0x1e8: 0x2000400,
+	            0x1f8: 0x100001
+	        },
+	        {
+	            0x0: 0x8000820,
+	            0x1: 0x20000,
+	            0x2: 0x8000000,
+	            0x3: 0x20,
+	            0x4: 0x20020,
+	            0x5: 0x8020820,
+	            0x6: 0x8020800,
+	            0x7: 0x800,
+	            0x8: 0x8020000,
+	            0x9: 0x8000800,
+	            0xa: 0x20800,
+	            0xb: 0x8020020,
+	            0xc: 0x820,
+	            0xd: 0x0,
+	            0xe: 0x8000020,
+	            0xf: 0x20820,
+	            0x80000000: 0x800,
+	            0x80000001: 0x8020820,
+	            0x80000002: 0x8000820,
+	            0x80000003: 0x8000000,
+	            0x80000004: 0x8020000,
+	            0x80000005: 0x20800,
+	            0x80000006: 0x20820,
+	            0x80000007: 0x20,
+	            0x80000008: 0x8000020,
+	            0x80000009: 0x820,
+	            0x8000000a: 0x20020,
+	            0x8000000b: 0x8020800,
+	            0x8000000c: 0x0,
+	            0x8000000d: 0x8020020,
+	            0x8000000e: 0x8000800,
+	            0x8000000f: 0x20000,
+	            0x10: 0x20820,
+	            0x11: 0x8020800,
+	            0x12: 0x20,
+	            0x13: 0x800,
+	            0x14: 0x8000800,
+	            0x15: 0x8000020,
+	            0x16: 0x8020020,
+	            0x17: 0x20000,
+	            0x18: 0x0,
+	            0x19: 0x20020,
+	            0x1a: 0x8020000,
+	            0x1b: 0x8000820,
+	            0x1c: 0x8020820,
+	            0x1d: 0x20800,
+	            0x1e: 0x820,
+	            0x1f: 0x8000000,
+	            0x80000010: 0x20000,
+	            0x80000011: 0x800,
+	            0x80000012: 0x8020020,
+	            0x80000013: 0x20820,
+	            0x80000014: 0x20,
+	            0x80000015: 0x8020000,
+	            0x80000016: 0x8000000,
+	            0x80000017: 0x8000820,
+	            0x80000018: 0x8020820,
+	            0x80000019: 0x8000020,
+	            0x8000001a: 0x8000800,
+	            0x8000001b: 0x0,
+	            0x8000001c: 0x20800,
+	            0x8000001d: 0x820,
+	            0x8000001e: 0x20020,
+	            0x8000001f: 0x8020800
+	        }
+	    ];
+
+	    // Masks that select the SBOX input
+	    var SBOX_MASK = [
+	        0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000,
+	        0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f
+	    ];
+
+	    /**
+	     * DES block cipher algorithm.
+	     */
+	    var DES = C_algo.DES = BlockCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+
+	            // Select 56 bits according to PC1
+	            var keyBits = [];
+	            for (var i = 0; i < 56; i++) {
+	                var keyBitPos = PC1[i] - 1;
+	                keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1;
+	            }
+
+	            // Assemble 16 subkeys
+	            var subKeys = this._subKeys = [];
+	            for (var nSubKey = 0; nSubKey < 16; nSubKey++) {
+	                // Create subkey
+	                var subKey = subKeys[nSubKey] = [];
+
+	                // Shortcut
+	                var bitShift = BIT_SHIFTS[nSubKey];
+
+	                // Select 48 bits according to PC2
+	                for (var i = 0; i < 24; i++) {
+	                    // Select from the left 28 key bits
+	                    subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6);
+
+	                    // Select from the right 28 key bits
+	                    subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6);
+	                }
+
+	                // Since each subkey is applied to an expanded 32-bit input,
+	                // the subkey can be broken into 8 values scaled to 32-bits,
+	                // which allows the key to be used without expansion
+	                subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31);
+	                for (var i = 1; i < 7; i++) {
+	                    subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3);
+	                }
+	                subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27);
+	            }
+
+	            // Compute inverse subkeys
+	            var invSubKeys = this._invSubKeys = [];
+	            for (var i = 0; i < 16; i++) {
+	                invSubKeys[i] = subKeys[15 - i];
+	            }
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._subKeys);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._invSubKeys);
+	        },
+
+	        _doCryptBlock: function (M, offset, subKeys) {
+	            // Get input
+	            this._lBlock = M[offset];
+	            this._rBlock = M[offset + 1];
+
+	            // Initial permutation
+	            exchangeLR.call(this, 4,  0x0f0f0f0f);
+	            exchangeLR.call(this, 16, 0x0000ffff);
+	            exchangeRL.call(this, 2,  0x33333333);
+	            exchangeRL.call(this, 8,  0x00ff00ff);
+	            exchangeLR.call(this, 1,  0x55555555);
+
+	            // Rounds
+	            for (var round = 0; round < 16; round++) {
+	                // Shortcuts
+	                var subKey = subKeys[round];
+	                var lBlock = this._lBlock;
+	                var rBlock = this._rBlock;
+
+	                // Feistel function
+	                var f = 0;
+	                for (var i = 0; i < 8; i++) {
+	                    f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0];
+	                }
+	                this._lBlock = rBlock;
+	                this._rBlock = lBlock ^ f;
+	            }
+
+	            // Undo swap from last round
+	            var t = this._lBlock;
+	            this._lBlock = this._rBlock;
+	            this._rBlock = t;
+
+	            // Final permutation
+	            exchangeLR.call(this, 1,  0x55555555);
+	            exchangeRL.call(this, 8,  0x00ff00ff);
+	            exchangeRL.call(this, 2,  0x33333333);
+	            exchangeLR.call(this, 16, 0x0000ffff);
+	            exchangeLR.call(this, 4,  0x0f0f0f0f);
+
+	            // Set output
+	            M[offset] = this._lBlock;
+	            M[offset + 1] = this._rBlock;
+	        },
+
+	        keySize: 64/32,
+
+	        ivSize: 64/32,
+
+	        blockSize: 64/32
+	    });
+
+	    // Swap bits across the left and right words
+	    function exchangeLR(offset, mask) {
+	        var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask;
+	        this._rBlock ^= t;
+	        this._lBlock ^= t << offset;
+	    }
+
+	    function exchangeRL(offset, mask) {
+	        var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask;
+	        this._lBlock ^= t;
+	        this._rBlock ^= t << offset;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.DES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.DES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.DES = BlockCipher._createHelper(DES);
+
+	    /**
+	     * Triple-DES block cipher algorithm.
+	     */
+	    var TripleDES = C_algo.TripleDES = BlockCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+	            // Make sure the key length is valid (64, 128 or >= 192 bit)
+	            if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) {
+	                throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.');
+	            }
+
+	            // Extend the key according to the keying options defined in 3DES standard
+	            var key1 = keyWords.slice(0, 2);
+	            var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4);
+	            var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6);
+
+	            // Create DES instances
+	            this._des1 = DES.createEncryptor(WordArray.create(key1));
+	            this._des2 = DES.createEncryptor(WordArray.create(key2));
+	            this._des3 = DES.createEncryptor(WordArray.create(key3));
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._des1.encryptBlock(M, offset);
+	            this._des2.decryptBlock(M, offset);
+	            this._des3.encryptBlock(M, offset);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            this._des3.decryptBlock(M, offset);
+	            this._des2.encryptBlock(M, offset);
+	            this._des1.decryptBlock(M, offset);
+	        },
+
+	        keySize: 192/32,
+
+	        ivSize: 64/32,
+
+	        blockSize: 64/32
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.TripleDES = BlockCipher._createHelper(TripleDES);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    /**
+	     * RC4 stream cipher algorithm.
+	     */
+	    var RC4 = C_algo.RC4 = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+	            var keySigBytes = key.sigBytes;
+
+	            // Init sbox
+	            var S = this._S = [];
+	            for (var i = 0; i < 256; i++) {
+	                S[i] = i;
+	            }
+
+	            // Key setup
+	            for (var i = 0, j = 0; i < 256; i++) {
+	                var keyByteIndex = i % keySigBytes;
+	                var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff;
+
+	                j = (j + S[i] + keyByte) % 256;
+
+	                // Swap
+	                var t = S[i];
+	                S[i] = S[j];
+	                S[j] = t;
+	            }
+
+	            // Counters
+	            this._i = this._j = 0;
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            M[offset] ^= generateKeystreamWord.call(this);
+	        },
+
+	        keySize: 256/32,
+
+	        ivSize: 0
+	    });
+
+	    function generateKeystreamWord() {
+	        // Shortcuts
+	        var S = this._S;
+	        var i = this._i;
+	        var j = this._j;
+
+	        // Generate keystream word
+	        var keystreamWord = 0;
+	        for (var n = 0; n < 4; n++) {
+	            i = (i + 1) % 256;
+	            j = (j + S[i]) % 256;
+
+	            // Swap
+	            var t = S[i];
+	            S[i] = S[j];
+	            S[j] = t;
+
+	            keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8);
+	        }
+
+	        // Update counters
+	        this._i = i;
+	        this._j = j;
+
+	        return keystreamWord;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RC4.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RC4 = StreamCipher._createHelper(RC4);
+
+	    /**
+	     * Modified RC4 stream cipher algorithm.
+	     */
+	    var RC4Drop = C_algo.RC4Drop = RC4.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} drop The number of keystream words to drop. Default 192
+	         */
+	        cfg: RC4.cfg.extend({
+	            drop: 192
+	        }),
+
+	        _doReset: function () {
+	            RC4._doReset.call(this);
+
+	            // Drop
+	            for (var i = this.cfg.drop; i > 0; i--) {
+	                generateKeystreamWord.call(this);
+	            }
+	        }
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RC4Drop = StreamCipher._createHelper(RC4Drop);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    // Reusable objects
+	    var S  = [];
+	    var C_ = [];
+	    var G  = [];
+
+	    /**
+	     * Rabbit stream cipher algorithm
+	     */
+	    var Rabbit = C_algo.Rabbit = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var K = this._key.words;
+	            var iv = this.cfg.iv;
+
+	            // Swap endian
+	            for (var i = 0; i < 4; i++) {
+	                K[i] = (((K[i] << 8)  | (K[i] >>> 24)) & 0x00ff00ff) |
+	                       (((K[i] << 24) | (K[i] >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Generate initial state values
+	            var X = this._X = [
+	                K[0], (K[3] << 16) | (K[2] >>> 16),
+	                K[1], (K[0] << 16) | (K[3] >>> 16),
+	                K[2], (K[1] << 16) | (K[0] >>> 16),
+	                K[3], (K[2] << 16) | (K[1] >>> 16)
+	            ];
+
+	            // Generate initial counter values
+	            var C = this._C = [
+	                (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff),
+	                (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff),
+	                (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff),
+	                (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff)
+	            ];
+
+	            // Carry bit
+	            this._b = 0;
+
+	            // Iterate the system four times
+	            for (var i = 0; i < 4; i++) {
+	                nextState.call(this);
+	            }
+
+	            // Modify the counters
+	            for (var i = 0; i < 8; i++) {
+	                C[i] ^= X[(i + 4) & 7];
+	            }
+
+	            // IV setup
+	            if (iv) {
+	                // Shortcuts
+	                var IV = iv.words;
+	                var IV_0 = IV[0];
+	                var IV_1 = IV[1];
+
+	                // Generate four subvectors
+	                var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00);
+	                var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00);
+	                var i1 = (i0 >>> 16) | (i2 & 0xffff0000);
+	                var i3 = (i2 << 16)  | (i0 & 0x0000ffff);
+
+	                // Modify counter values
+	                C[0] ^= i0;
+	                C[1] ^= i1;
+	                C[2] ^= i2;
+	                C[3] ^= i3;
+	                C[4] ^= i0;
+	                C[5] ^= i1;
+	                C[6] ^= i2;
+	                C[7] ^= i3;
+
+	                // Iterate the system four times
+	                for (var i = 0; i < 4; i++) {
+	                    nextState.call(this);
+	                }
+	            }
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var X = this._X;
+
+	            // Iterate the system
+	            nextState.call(this);
+
+	            // Generate four keystream words
+	            S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16);
+	            S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16);
+	            S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16);
+	            S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16);
+
+	            for (var i = 0; i < 4; i++) {
+	                // Swap endian
+	                S[i] = (((S[i] << 8)  | (S[i] >>> 24)) & 0x00ff00ff) |
+	                       (((S[i] << 24) | (S[i] >>> 8))  & 0xff00ff00);
+
+	                // Encrypt
+	                M[offset + i] ^= S[i];
+	            }
+	        },
+
+	        blockSize: 128/32,
+
+	        ivSize: 64/32
+	    });
+
+	    function nextState() {
+	        // Shortcuts
+	        var X = this._X;
+	        var C = this._C;
+
+	        // Save old counter values
+	        for (var i = 0; i < 8; i++) {
+	            C_[i] = C[i];
+	        }
+
+	        // Calculate new counter values
+	        C[0] = (C[0] + 0x4d34d34d + this._b) | 0;
+	        C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0;
+	        C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0;
+	        C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0;
+	        C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0;
+	        C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0;
+	        C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0;
+	        C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0;
+	        this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0;
+
+	        // Calculate the g-values
+	        for (var i = 0; i < 8; i++) {
+	            var gx = X[i] + C[i];
+
+	            // Construct high and low argument for squaring
+	            var ga = gx & 0xffff;
+	            var gb = gx >>> 16;
+
+	            // Calculate high and low result of squaring
+	            var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb;
+	            var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0);
+
+	            // High XOR low
+	            G[i] = gh ^ gl;
+	        }
+
+	        // Calculate new state values
+	        X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0;
+	        X[1] = (G[1] + ((G[0] << 8)  | (G[0] >>> 24)) + G[7]) | 0;
+	        X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0;
+	        X[3] = (G[3] + ((G[2] << 8)  | (G[2] >>> 24)) + G[1]) | 0;
+	        X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0;
+	        X[5] = (G[5] + ((G[4] << 8)  | (G[4] >>> 24)) + G[3]) | 0;
+	        X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0;
+	        X[7] = (G[7] + ((G[6] << 8)  | (G[6] >>> 24)) + G[5]) | 0;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg);
+	     */
+	    C.Rabbit = StreamCipher._createHelper(Rabbit);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    // Reusable objects
+	    var S  = [];
+	    var C_ = [];
+	    var G  = [];
+
+	    /**
+	     * Rabbit stream cipher algorithm.
+	     *
+	     * This is a legacy version that neglected to convert the key to little-endian.
+	     * This error doesn't affect the cipher's security,
+	     * but it does affect its compatibility with other implementations.
+	     */
+	    var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var K = this._key.words;
+	            var iv = this.cfg.iv;
+
+	            // Generate initial state values
+	            var X = this._X = [
+	                K[0], (K[3] << 16) | (K[2] >>> 16),
+	                K[1], (K[0] << 16) | (K[3] >>> 16),
+	                K[2], (K[1] << 16) | (K[0] >>> 16),
+	                K[3], (K[2] << 16) | (K[1] >>> 16)
+	            ];
+
+	            // Generate initial counter values
+	            var C = this._C = [
+	                (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff),
+	                (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff),
+	                (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff),
+	                (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff)
+	            ];
+
+	            // Carry bit
+	            this._b = 0;
+
+	            // Iterate the system four times
+	            for (var i = 0; i < 4; i++) {
+	                nextState.call(this);
+	            }
+
+	            // Modify the counters
+	            for (var i = 0; i < 8; i++) {
+	                C[i] ^= X[(i + 4) & 7];
+	            }
+
+	            // IV setup
+	            if (iv) {
+	                // Shortcuts
+	                var IV = iv.words;
+	                var IV_0 = IV[0];
+	                var IV_1 = IV[1];
+
+	                // Generate four subvectors
+	                var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00);
+	                var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00);
+	                var i1 = (i0 >>> 16) | (i2 & 0xffff0000);
+	                var i3 = (i2 << 16)  | (i0 & 0x0000ffff);
+
+	                // Modify counter values
+	                C[0] ^= i0;
+	                C[1] ^= i1;
+	                C[2] ^= i2;
+	                C[3] ^= i3;
+	                C[4] ^= i0;
+	                C[5] ^= i1;
+	                C[6] ^= i2;
+	                C[7] ^= i3;
+
+	                // Iterate the system four times
+	                for (var i = 0; i < 4; i++) {
+	                    nextState.call(this);
+	                }
+	            }
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var X = this._X;
+
+	            // Iterate the system
+	            nextState.call(this);
+
+	            // Generate four keystream words
+	            S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16);
+	            S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16);
+	            S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16);
+	            S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16);
+
+	            for (var i = 0; i < 4; i++) {
+	                // Swap endian
+	                S[i] = (((S[i] << 8)  | (S[i] >>> 24)) & 0x00ff00ff) |
+	                       (((S[i] << 24) | (S[i] >>> 8))  & 0xff00ff00);
+
+	                // Encrypt
+	                M[offset + i] ^= S[i];
+	            }
+	        },
+
+	        blockSize: 128/32,
+
+	        ivSize: 64/32
+	    });
+
+	    function nextState() {
+	        // Shortcuts
+	        var X = this._X;
+	        var C = this._C;
+
+	        // Save old counter values
+	        for (var i = 0; i < 8; i++) {
+	            C_[i] = C[i];
+	        }
+
+	        // Calculate new counter values
+	        C[0] = (C[0] + 0x4d34d34d + this._b) | 0;
+	        C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0;
+	        C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0;
+	        C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0;
+	        C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0;
+	        C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0;
+	        C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0;
+	        C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0;
+	        this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0;
+
+	        // Calculate the g-values
+	        for (var i = 0; i < 8; i++) {
+	            var gx = X[i] + C[i];
+
+	            // Construct high and low argument for squaring
+	            var ga = gx & 0xffff;
+	            var gb = gx >>> 16;
+
+	            // Calculate high and low result of squaring
+	            var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb;
+	            var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0);
+
+	            // High XOR low
+	            G[i] = gh ^ gl;
+	        }
+
+	        // Calculate new state values
+	        X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0;
+	        X[1] = (G[1] + ((G[0] << 8)  | (G[0] >>> 24)) + G[7]) | 0;
+	        X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0;
+	        X[3] = (G[3] + ((G[2] << 8)  | (G[2] >>> 24)) + G[1]) | 0;
+	        X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0;
+	        X[5] = (G[5] + ((G[4] << 8)  | (G[4] >>> 24)) + G[3]) | 0;
+	        X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0;
+	        X[7] = (G[7] + ((G[6] << 8)  | (G[6] >>> 24)) + G[5]) | 0;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy);
+	}());
+
+
+	return CryptoJS;
+
+}));

File diff suppressed because it is too large
+ 432 - 0
components/verify/verify.vue


File diff suppressed because it is too large
+ 467 - 0
components/verify/verifyPoint/verifyPoint.vue


File diff suppressed because it is too large
+ 582 - 0
components/verify/verifySlider/verifySlider.vue


+ 1201 - 0
components/zb-code/qrcode.js

@@ -0,0 +1,1201 @@
+let QRCode = {};
+(function () {
+    /**
+     * 获取单个字符的utf8编码
+     * unicode BMP平面约65535个字符
+     * @param {num} code
+     * return {array}
+     */
+    function unicodeFormat8(code) {
+        // 1 byte
+        var c0, c1, c2;
+        if (code < 128) {
+            return [code];
+            // 2 bytes
+        } else if (code < 2048) {
+            c0 = 192 + (code >> 6);
+            c1 = 128 + (code & 63);
+            return [c0, c1];
+            // 3 bytes
+        } else {
+            c0 = 224 + (code >> 12);
+            c1 = 128 + (code >> 6 & 63);
+            c2 = 128 + (code & 63);
+            return [c0, c1, c2];
+        }
+    }
+    /**
+     * 获取字符串的utf8编码字节串
+     * @param {string} string
+     * @return {array}
+     */
+    function getUTF8Bytes(string) {
+        var utf8codes = [];
+        for (var i = 0; i < string.length; i++) {
+            var code = string.charCodeAt(i);
+            var utf8 = unicodeFormat8(code);
+            for (var j = 0; j < utf8.length; j++) {
+                utf8codes.push(utf8[j]);
+            }
+        }
+        return utf8codes;
+    }
+    /**
+     * 二维码算法实现
+     * @param {string} data              要编码的信息字符串
+     * @param {num} errorCorrectLevel 纠错等级
+     */
+    function QRCodeAlg(data, twodimensionalcodeee5conversionmethod) {
+        this.typeNumber = -1; //版本
+        this.errorCorrectLevel = twodimensionalcodeee5conversionmethod;
+        this.modules = null; //二维矩阵,存放最终结果
+        this.moduleCount = 0; //矩阵大小
+        this.dataCache = null; //数据缓存
+        this.rsBlocks = null; //版本数据信息
+        this.totalDataCount = -1; //可使用的数据量
+        this.data = data;
+        this.utf8bytes = getUTF8Bytes(data);
+        this.make();
+    }
+    QRCodeAlg.prototype = {
+        constructor: QRCodeAlg,
+        /**
+         * 获取二维码矩阵大小
+         * @return {num} 矩阵大小
+         */
+        getModuleCount: function () {
+            return this.moduleCount;
+        },
+        /**
+         * 编码
+         */
+        make: function () {
+            this.getRightType();
+            this.dataCache = this.createData();
+            this.createQrcode();
+        },
+        /**
+         * 设置二位矩阵功能图形
+         * @param  {bool} test 表示是否在寻找最好掩膜阶段
+         * @param  {num} maskPattern 掩膜的版本
+         */
+        makeImpl: function (maskPattern) {
+            this.moduleCount = this.typeNumber * 4 + 17;
+            this.modules = new Array(this.moduleCount);
+            for (var row = 0; row < this.moduleCount; row++) {
+                this.modules[row] = new Array(this.moduleCount);
+            }
+            this.setupPositionProbePattern(0, 0);
+            this.setupPositionProbePattern(this.moduleCount - 7, 0);
+            this.setupPositionProbePattern(0, this.moduleCount - 7);
+            this.setupPositionAdjustPattern();
+            this.setupTimingPattern();
+            this.setupTypeInfo(true, maskPattern);
+            if (this.typeNumber >= 7) {
+                this.setupTypeNumber(true);
+            }
+            this.mapData(this.dataCache, maskPattern);
+        },
+        /**
+         * 设置二维码的位置探测图形
+         * @param  {num} row 探测图形的中心横坐标
+         * @param  {num} col 探测图形的中心纵坐标
+         */
+        setupPositionProbePattern: function (row, col) {
+            for (var r = -1; r <= 7; r++) {
+                if (row + r <= -1 || this.moduleCount <= row + r) continue;
+                for (var c = -1; c <= 7; c++) {
+                    if (col + c <= -1 || this.moduleCount <= col + c) continue;
+                    if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c && c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+                        this.modules[row + r][col + c] = true;
+                    } else {
+                        this.modules[row + r][col + c] = false;
+                    }
+                }
+            }
+        },
+        /**
+         * 创建二维码
+         * @return {[type]} [description]
+         */
+        createQrcode: function () {
+            var minLostPoint = 0;
+            var pattern = 0;
+            var bestModules = null;
+            for (var i = 0; i < 8; i++) {
+                this.makeImpl(i);
+                var lostPoint = QRUtil.getLostPoint(this);
+                if (i == 0 || minLostPoint > lostPoint) {
+                    minLostPoint = lostPoint;
+                    pattern = i;
+                    bestModules = this.modules;
+                }
+            }
+            this.modules = bestModules;
+            this.setupTypeInfo(false, pattern);
+            if (this.typeNumber >= 7) {
+                this.setupTypeNumber(false);
+            }
+        },
+        /**
+         * 设置定位图形
+         * @return {[type]} [description]
+         */
+        setupTimingPattern: function () {
+            for (var r = 8; r < this.moduleCount - 8; r++) {
+                if (this.modules[r][6] != null) {
+                    continue;
+                }
+                this.modules[r][6] = (r % 2 == 0);
+                if (this.modules[6][r] != null) {
+                    continue;
+                }
+                this.modules[6][r] = (r % 2 == 0);
+            }
+        },
+        /**
+         * 设置矫正图形
+         * @return {[type]} [description]
+         */
+        setupPositionAdjustPattern: function () {
+            var pos = QRUtil.getPatternPosition(this.typeNumber);
+            for (var i = 0; i < pos.length; i++) {
+                for (var j = 0; j < pos.length; j++) {
+                    var row = pos[i];
+                    var col = pos[j];
+                    if (this.modules[row][col] != null) {
+                        continue;
+                    }
+                    for (var r = -2; r <= 2; r++) {
+                        for (var c = -2; c <= 2; c++) {
+                            if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) {
+                                this.modules[row + r][col + c] = true;
+                            } else {
+                                this.modules[row + r][col + c] = false;
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        /**
+         * 设置版本信息(7以上版本才有)
+         * @param  {bool} test 是否处于判断最佳掩膜阶段
+         * @return {[type]}      [description]
+         */
+        setupTypeNumber: function (test) {
+            var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+            for (var i = 0; i < 18; i++) {
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+                this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+            }
+        },
+        /**
+         * 设置格式信息(纠错等级和掩膜版本)
+         * @param  {bool} test
+         * @param  {num} maskPattern 掩膜版本
+         * @return {}
+         */
+        setupTypeInfo: function (test, maskPattern) {
+            var data = (QRErrorCorrectLevel[this.errorCorrectLevel] << 3) | maskPattern;
+            var bits = QRUtil.getBCHTypeInfo(data);
+            // vertical
+            for (var i = 0; i < 15; i++) {
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                if (i < 6) {
+                    this.modules[i][8] = mod;
+                } else if (i < 8) {
+                    this.modules[i + 1][8] = mod;
+                } else {
+                    this.modules[this.moduleCount - 15 + i][8] = mod;
+                }
+                // horizontal
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                if (i < 8) {
+                    this.modules[8][this.moduleCount - i - 1] = mod;
+                } else if (i < 9) {
+                    this.modules[8][15 - i - 1 + 1] = mod;
+                } else {
+                    this.modules[8][15 - i - 1] = mod;
+                }
+            }
+            // fixed module
+            this.modules[this.moduleCount - 8][8] = (!test);
+        },
+        /**
+         * 数据编码
+         * @return {[type]} [description]
+         */
+        createData: function () {
+            var buffer = new QRBitBuffer();
+            var lengthBits = this.typeNumber > 9 ? 16 : 8;
+            buffer.put(4, 4); //添加模式
+            buffer.put(this.utf8bytes.length, lengthBits);
+            for (var i = 0, l = this.utf8bytes.length; i < l; i++) {
+                buffer.put(this.utf8bytes[i], 8);
+            }
+            if (buffer.length + 4 <= this.totalDataCount * 8) {
+                buffer.put(0, 4);
+            }
+            // padding
+            while (buffer.length % 8 != 0) {
+                buffer.putBit(false);
+            }
+            // padding
+            while (true) {
+                if (buffer.length >= this.totalDataCount * 8) {
+                    break;
+                }
+                buffer.put(QRCodeAlg.PAD0, 8);
+                if (buffer.length >= this.totalDataCount * 8) {
+                    break;
+                }
+                buffer.put(QRCodeAlg.PAD1, 8);
+            }
+            return this.createBytes(buffer);
+        },
+        /**
+         * 纠错码编码
+         * @param  {buffer} buffer 数据编码
+         * @return {[type]}
+         */
+        createBytes: function (buffer) {
+            var offset = 0;
+            var maxDcCount = 0;
+            var maxEcCount = 0;
+            var length = this.rsBlock.length / 3;
+            var rsBlocks = new Array();
+            for (var i = 0; i < length; i++) {
+                var count = this.rsBlock[i * 3 + 0];
+                var totalCount = this.rsBlock[i * 3 + 1];
+                var dataCount = this.rsBlock[i * 3 + 2];
+                for (var j = 0; j < count; j++) {
+                    rsBlocks.push([dataCount, totalCount]);
+                }
+            }
+            var dcdata = new Array(rsBlocks.length);
+            var ecdata = new Array(rsBlocks.length);
+            for (var r = 0; r < rsBlocks.length; r++) {
+                var dcCount = rsBlocks[r][0];
+                var ecCount = rsBlocks[r][1] - dcCount;
+                maxDcCount = Math.max(maxDcCount, dcCount);
+                maxEcCount = Math.max(maxEcCount, ecCount);
+                dcdata[r] = new Array(dcCount);
+                for (var i = 0; i < dcdata[r].length; i++) {
+                    dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+                }
+                offset += dcCount;
+                var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+                var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+                var modPoly = rawPoly.mod(rsPoly);
+                ecdata[r] = new Array(rsPoly.getLength() - 1);
+                for (var i = 0; i < ecdata[r].length; i++) {
+                    var modIndex = i + modPoly.getLength() - ecdata[r].length;
+                    ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+                }
+            }
+            var data = new Array(this.totalDataCount);
+            var index = 0;
+            for (var i = 0; i < maxDcCount; i++) {
+                for (var r = 0; r < rsBlocks.length; r++) {
+                    if (i < dcdata[r].length) {
+                        data[index++] = dcdata[r][i];
+                    }
+                }
+            }
+            for (var i = 0; i < maxEcCount; i++) {
+                for (var r = 0; r < rsBlocks.length; r++) {
+                    if (i < ecdata[r].length) {
+                        data[index++] = ecdata[r][i];
+                    }
+                }
+            }
+            return data;
+
+        },
+        /**
+         * 布置模块,构建最终信息
+         * @param  {} data
+         * @param  {} maskPattern
+         * @return {}
+         */
+        mapData: function (data, maskPattern) {
+            var inc = -1;
+            var row = this.moduleCount - 1;
+            var bitIndex = 7;
+            var byteIndex = 0;
+            for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+                if (col == 6) col--;
+                while (true) {
+                    for (var c = 0; c < 2; c++) {
+                        if (this.modules[row][col - c] == null) {
+                            var dark = false;
+                            if (byteIndex < data.length) {
+                                dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+                            }
+                            var mask = QRUtil.getMask(maskPattern, row, col - c);
+                            if (mask) {
+                                dark = !dark;
+                            }
+                            this.modules[row][col - c] = dark;
+                            bitIndex--;
+                            if (bitIndex == -1) {
+                                byteIndex++;
+                                bitIndex = 7;
+                            }
+                        }
+                    }
+                    row += inc;
+                    if (row < 0 || this.moduleCount <= row) {
+                        row -= inc;
+                        inc = -inc;
+                        break;
+                    }
+                }
+            }
+        }
+    };
+    /**
+     * 填充字段
+     */
+    QRCodeAlg.PAD0 = 0xEC;
+    QRCodeAlg.PAD1 = 0x11;
+    //---------------------------------------------------------------------
+    // 纠错等级对应的编码
+    //---------------------------------------------------------------------
+    var QRErrorCorrectLevel = [1, 0, 3, 2];
+    //---------------------------------------------------------------------
+    // 掩膜版本
+    //---------------------------------------------------------------------
+    var QRMaskPattern = {
+        PATTERN000: 0,
+        PATTERN001: 1,
+        PATTERN010: 2,
+        PATTERN011: 3,
+        PATTERN100: 4,
+        PATTERN101: 5,
+        PATTERN110: 6,
+        PATTERN111: 7
+    };
+    //---------------------------------------------------------------------
+    // 工具类
+    //---------------------------------------------------------------------
+    var QRUtil = {
+        /*
+        每个版本矫正图形的位置
+         */
+        PATTERN_POSITION_TABLE: [
+            [],
+            [6, 18],
+            [6, 22],
+            [6, 26],
+            [6, 30],
+            [6, 34],
+            [6, 22, 38],
+            [6, 24, 42],
+            [6, 26, 46],
+            [6, 28, 50],
+            [6, 30, 54],
+            [6, 32, 58],
+            [6, 34, 62],
+            [6, 26, 46, 66],
+            [6, 26, 48, 70],
+            [6, 26, 50, 74],
+            [6, 30, 54, 78],
+            [6, 30, 56, 82],
+            [6, 30, 58, 86],
+            [6, 34, 62, 90],
+            [6, 28, 50, 72, 94],
+            [6, 26, 50, 74, 98],
+            [6, 30, 54, 78, 102],
+            [6, 28, 54, 80, 106],
+            [6, 32, 58, 84, 110],
+            [6, 30, 58, 86, 114],
+            [6, 34, 62, 90, 118],
+            [6, 26, 50, 74, 98, 122],
+            [6, 30, 54, 78, 102, 126],
+            [6, 26, 52, 78, 104, 130],
+            [6, 30, 56, 82, 108, 134],
+            [6, 34, 60, 86, 112, 138],
+            [6, 30, 58, 86, 114, 142],
+            [6, 34, 62, 90, 118, 146],
+            [6, 30, 54, 78, 102, 126, 150],
+            [6, 24, 50, 76, 102, 128, 154],
+            [6, 28, 54, 80, 106, 132, 158],
+            [6, 32, 58, 84, 110, 136, 162],
+            [6, 26, 54, 82, 110, 138, 166],
+            [6, 30, 58, 86, 114, 142, 170]
+        ],
+        G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+        G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+        G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+        /*
+        BCH编码格式信息
+         */
+        getBCHTypeInfo: function (data) {
+            var d = data << 10;
+            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+                d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+            }
+            return ((data << 10) | d) ^ QRUtil.G15_MASK;
+        },
+        /*
+        BCH编码版本信息
+         */
+        getBCHTypeNumber: function (data) {
+            var d = data << 12;
+            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+                d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+            }
+            return (data << 12) | d;
+        },
+        /*
+        获取BCH位信息
+         */
+        getBCHDigit: function (data) {
+            var digit = 0;
+            while (data != 0) {
+                digit++;
+                data >>>= 1;
+            }
+            return digit;
+        },
+        /*
+        获取版本对应的矫正图形位置
+         */
+        getPatternPosition: function (typeNumber) {
+            return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+        },
+        /*
+        掩膜算法
+         */
+        getMask: function (maskPattern, i, j) {
+            switch (maskPattern) {
+                case QRMaskPattern.PATTERN000:
+                    return (i + j) % 2 == 0;
+                case QRMaskPattern.PATTERN001:
+                    return i % 2 == 0;
+                case QRMaskPattern.PATTERN010:
+                    return j % 3 == 0;
+                case QRMaskPattern.PATTERN011:
+                    return (i + j) % 3 == 0;
+                case QRMaskPattern.PATTERN100:
+                    return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+                case QRMaskPattern.PATTERN101:
+                    return (i * j) % 2 + (i * j) % 3 == 0;
+                case QRMaskPattern.PATTERN110:
+                    return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+                case QRMaskPattern.PATTERN111:
+                    return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+                default:
+                    throw new Error("bad maskPattern:" + maskPattern);
+            }
+        },
+        /*
+        获取RS的纠错多项式
+         */
+        getErrorCorrectPolynomial: function (errorCorrectLength) {
+            var a = new QRPolynomial([1], 0);
+            for (var i = 0; i < errorCorrectLength; i++) {
+                a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+            }
+            return a;
+        },
+        /*
+        获取评价
+         */
+        getLostPoint: function (qrCode) {
+            var moduleCount = qrCode.getModuleCount(),
+                lostPoint = 0,
+                darkCount = 0;
+            for (var row = 0; row < moduleCount; row++) {
+                var sameCount = 0;
+                var head = qrCode.modules[row][0];
+                for (var col = 0; col < moduleCount; col++) {
+                    var current = qrCode.modules[row][col];
+                    //level 3 评价
+                    if (col < moduleCount - 6) {
+                        if (current && !qrCode.modules[row][col + 1] && qrCode.modules[row][col + 2] && qrCode.modules[row][col + 3] && qrCode.modules[row][col + 4] && !qrCode.modules[row][col + 5] && qrCode.modules[row][col + 6]) {
+                            if (col < moduleCount - 10) {
+                                if (qrCode.modules[row][col + 7] && qrCode.modules[row][col + 8] && qrCode.modules[row][col + 9] && qrCode.modules[row][col + 10]) {
+                                    lostPoint += 40;
+                                }
+                            } else if (col > 3) {
+                                if (qrCode.modules[row][col - 1] && qrCode.modules[row][col - 2] && qrCode.modules[row][col - 3] && qrCode.modules[row][col - 4]) {
+                                    lostPoint += 40;
+                                }
+                            }
+                        }
+                    }
+                    //level 2 评价
+                    if ((row < moduleCount - 1) && (col < moduleCount - 1)) {
+                        var count = 0;
+                        if (current) count++;
+                        if (qrCode.modules[row + 1][col]) count++;
+                        if (qrCode.modules[row][col + 1]) count++;
+                        if (qrCode.modules[row + 1][col + 1]) count++;
+                        if (count == 0 || count == 4) {
+                            lostPoint += 3;
+                        }
+                    }
+                    //level 1 评价
+                    if (head ^ current) {
+                        sameCount++;
+                    } else {
+                        head = current;
+                        if (sameCount >= 5) {
+                            lostPoint += (3 + sameCount - 5);
+                        }
+                        sameCount = 1;
+                    }
+                    //level 4 评价
+                    if (current) {
+                        darkCount++;
+                    }
+                }
+            }
+            for (var col = 0; col < moduleCount; col++) {
+                var sameCount = 0;
+                var head = qrCode.modules[0][col];
+                for (var row = 0; row < moduleCount; row++) {
+                    var current = qrCode.modules[row][col];
+                    //level 3 评价
+                    if (row < moduleCount - 6) {
+                        if (current && !qrCode.modules[row + 1][col] && qrCode.modules[row + 2][col] && qrCode.modules[row + 3][col] && qrCode.modules[row + 4][col] && !qrCode.modules[row + 5][col] && qrCode.modules[row + 6][col]) {
+                            if (row < moduleCount - 10) {
+                                if (qrCode.modules[row + 7][col] && qrCode.modules[row + 8][col] && qrCode.modules[row + 9][col] && qrCode.modules[row + 10][col]) {
+                                    lostPoint += 40;
+                                }
+                            } else if (row > 3) {
+                                if (qrCode.modules[row - 1][col] && qrCode.modules[row - 2][col] && qrCode.modules[row - 3][col] && qrCode.modules[row - 4][col]) {
+                                    lostPoint += 40;
+                                }
+                            }
+                        }
+                    }
+                    //level 1 评价
+                    if (head ^ current) {
+                        sameCount++;
+                    } else {
+                        head = current;
+                        if (sameCount >= 5) {
+                            lostPoint += (3 + sameCount - 5);
+                        }
+                        sameCount = 1;
+                    }
+                }
+            }
+            // LEVEL4
+            var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+            lostPoint += ratio * 10;
+            return lostPoint;
+        }
+
+    };
+    //---------------------------------------------------------------------
+    // QRMath使用的数学工具
+    //---------------------------------------------------------------------
+    var QRMath = {
+        /*
+        将n转化为a^m
+         */
+        glog: function (n) {
+            if (n < 1) {
+                throw new Error("glog(" + n + ")");
+            }
+            return QRMath.LOG_TABLE[n];
+        },
+        /*
+        将a^m转化为n
+         */
+        gexp: function (n) {
+            while (n < 0) {
+                n += 255;
+            }
+            while (n >= 256) {
+                n -= 255;
+            }
+            return QRMath.EXP_TABLE[n];
+        },
+        EXP_TABLE: new Array(256),
+        LOG_TABLE: new Array(256)
+
+    };
+    for (var i = 0; i < 8; i++) {
+        QRMath.EXP_TABLE[i] = 1 << i;
+    }
+    for (var i = 8; i < 256; i++) {
+        QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
+    }
+    for (var i = 0; i < 255; i++) {
+        QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+    }
+    //---------------------------------------------------------------------
+    // QRPolynomial 多项式
+    //---------------------------------------------------------------------
+    /**
+     * 多项式类
+     * @param {Array} num   系数
+     * @param {num} shift a^shift
+     */
+    function QRPolynomial(num, shift) {
+        if (num.length == undefined) {
+            throw new Error(num.length + "/" + shift);
+        }
+        var offset = 0;
+        while (offset < num.length && num[offset] == 0) {
+            offset++;
+        }
+        this.num = new Array(num.length - offset + shift);
+        for (var i = 0; i < num.length - offset; i++) {
+            this.num[i] = num[i + offset];
+        }
+    }
+    QRPolynomial.prototype = {
+        get: function (index) {
+            return this.num[index];
+        },
+        getLength: function () {
+            return this.num.length;
+        },
+        /**
+         * 多项式乘法
+         * @param  {QRPolynomial} e 被乘多项式
+         * @return {[type]}   [description]
+         */
+        multiply: function (e) {
+            var num = new Array(this.getLength() + e.getLength() - 1);
+            for (var i = 0; i < this.getLength(); i++) {
+                for (var j = 0; j < e.getLength(); j++) {
+                    num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+                }
+            }
+            return new QRPolynomial(num, 0);
+        },
+        /**
+         * 多项式模运算
+         * @param  {QRPolynomial} e 模多项式
+         * @return {}
+         */
+        mod: function (e) {
+            var tl = this.getLength(),
+                el = e.getLength();
+            if (tl - el < 0) {
+                return this;
+            }
+            var num = new Array(tl);
+            for (var i = 0; i < tl; i++) {
+                num[i] = this.get(i);
+            }
+            while (num.length >= el) {
+                var ratio = QRMath.glog(num[0]) - QRMath.glog(e.get(0));
+
+                for (var i = 0; i < e.getLength(); i++) {
+                    num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+                }
+                while (num[0] == 0) {
+                    num.shift();
+                }
+            }
+            return new QRPolynomial(num, 0);
+        }
+    };
+
+    //---------------------------------------------------------------------
+    // RS_BLOCK_TABLE
+    //---------------------------------------------------------------------
+    /*
+    二维码各个版本信息[块数, 每块中的数据块数, 每块中的信息块数]
+     */
+    var RS_BLOCK_TABLE = [
+        // L
+        // M
+        // Q
+        // H
+        // 1
+        [1, 26, 19],
+        [1, 26, 16],
+        [1, 26, 13],
+        [1, 26, 9],
+
+        // 2
+        [1, 44, 34],
+        [1, 44, 28],
+        [1, 44, 22],
+        [1, 44, 16],
+
+        // 3
+        [1, 70, 55],
+        [1, 70, 44],
+        [2, 35, 17],
+        [2, 35, 13],
+
+        // 4
+        [1, 100, 80],
+        [2, 50, 32],
+        [2, 50, 24],
+        [4, 25, 9],
+
+        // 5
+        [1, 134, 108],
+        [2, 67, 43],
+        [2, 33, 15, 2, 34, 16],
+        [2, 33, 11, 2, 34, 12],
+
+        // 6
+        [2, 86, 68],
+        [4, 43, 27],
+        [4, 43, 19],
+        [4, 43, 15],
+
+        // 7
+        [2, 98, 78],
+        [4, 49, 31],
+        [2, 32, 14, 4, 33, 15],
+        [4, 39, 13, 1, 40, 14],
+
+        // 8
+        [2, 121, 97],
+        [2, 60, 38, 2, 61, 39],
+        [4, 40, 18, 2, 41, 19],
+        [4, 40, 14, 2, 41, 15],
+
+        // 9
+        [2, 146, 116],
+        [3, 58, 36, 2, 59, 37],
+        [4, 36, 16, 4, 37, 17],
+        [4, 36, 12, 4, 37, 13],
+
+        // 10
+        [2, 86, 68, 2, 87, 69],
+        [4, 69, 43, 1, 70, 44],
+        [6, 43, 19, 2, 44, 20],
+        [6, 43, 15, 2, 44, 16],
+
+        // 11
+        [4, 101, 81],
+        [1, 80, 50, 4, 81, 51],
+        [4, 50, 22, 4, 51, 23],
+        [3, 36, 12, 8, 37, 13],
+
+        // 12
+        [2, 116, 92, 2, 117, 93],
+        [6, 58, 36, 2, 59, 37],
+        [4, 46, 20, 6, 47, 21],
+        [7, 42, 14, 4, 43, 15],
+
+        // 13
+        [4, 133, 107],
+        [8, 59, 37, 1, 60, 38],
+        [8, 44, 20, 4, 45, 21],
+        [12, 33, 11, 4, 34, 12],
+
+        // 14
+        [3, 145, 115, 1, 146, 116],
+        [4, 64, 40, 5, 65, 41],
+        [11, 36, 16, 5, 37, 17],
+        [11, 36, 12, 5, 37, 13],
+
+        // 15
+        [5, 109, 87, 1, 110, 88],
+        [5, 65, 41, 5, 66, 42],
+        [5, 54, 24, 7, 55, 25],
+        [11, 36, 12],
+
+        // 16
+        [5, 122, 98, 1, 123, 99],
+        [7, 73, 45, 3, 74, 46],
+        [15, 43, 19, 2, 44, 20],
+        [3, 45, 15, 13, 46, 16],
+
+        // 17
+        [1, 135, 107, 5, 136, 108],
+        [10, 74, 46, 1, 75, 47],
+        [1, 50, 22, 15, 51, 23],
+        [2, 42, 14, 17, 43, 15],
+
+        // 18
+        [5, 150, 120, 1, 151, 121],
+        [9, 69, 43, 4, 70, 44],
+        [17, 50, 22, 1, 51, 23],
+        [2, 42, 14, 19, 43, 15],
+
+        // 19
+        [3, 141, 113, 4, 142, 114],
+        [3, 70, 44, 11, 71, 45],
+        [17, 47, 21, 4, 48, 22],
+        [9, 39, 13, 16, 40, 14],
+
+        // 20
+        [3, 135, 107, 5, 136, 108],
+        [3, 67, 41, 13, 68, 42],
+        [15, 54, 24, 5, 55, 25],
+        [15, 43, 15, 10, 44, 16],
+
+        // 21
+        [4, 144, 116, 4, 145, 117],
+        [17, 68, 42],
+        [17, 50, 22, 6, 51, 23],
+        [19, 46, 16, 6, 47, 17],
+
+        // 22
+        [2, 139, 111, 7, 140, 112],
+        [17, 74, 46],
+        [7, 54, 24, 16, 55, 25],
+        [34, 37, 13],
+
+        // 23
+        [4, 151, 121, 5, 152, 122],
+        [4, 75, 47, 14, 76, 48],
+        [11, 54, 24, 14, 55, 25],
+        [16, 45, 15, 14, 46, 16],
+
+        // 24
+        [6, 147, 117, 4, 148, 118],
+        [6, 73, 45, 14, 74, 46],
+        [11, 54, 24, 16, 55, 25],
+        [30, 46, 16, 2, 47, 17],
+
+        // 25
+        [8, 132, 106, 4, 133, 107],
+        [8, 75, 47, 13, 76, 48],
+        [7, 54, 24, 22, 55, 25],
+        [22, 45, 15, 13, 46, 16],
+
+        // 26
+        [10, 142, 114, 2, 143, 115],
+        [19, 74, 46, 4, 75, 47],
+        [28, 50, 22, 6, 51, 23],
+        [33, 46, 16, 4, 47, 17],
+
+        // 27
+        [8, 152, 122, 4, 153, 123],
+        [22, 73, 45, 3, 74, 46],
+        [8, 53, 23, 26, 54, 24],
+        [12, 45, 15, 28, 46, 16],
+
+        // 28
+        [3, 147, 117, 10, 148, 118],
+        [3, 73, 45, 23, 74, 46],
+        [4, 54, 24, 31, 55, 25],
+        [11, 45, 15, 31, 46, 16],
+
+        // 29
+        [7, 146, 116, 7, 147, 117],
+        [21, 73, 45, 7, 74, 46],
+        [1, 53, 23, 37, 54, 24],
+        [19, 45, 15, 26, 46, 16],
+
+        // 30
+        [5, 145, 115, 10, 146, 116],
+        [19, 75, 47, 10, 76, 48],
+        [15, 54, 24, 25, 55, 25],
+        [23, 45, 15, 25, 46, 16],
+
+        // 31
+        [13, 145, 115, 3, 146, 116],
+        [2, 74, 46, 29, 75, 47],
+        [42, 54, 24, 1, 55, 25],
+        [23, 45, 15, 28, 46, 16],
+
+        // 32
+        [17, 145, 115],
+        [10, 74, 46, 23, 75, 47],
+        [10, 54, 24, 35, 55, 25],
+        [19, 45, 15, 35, 46, 16],
+
+        // 33
+        [17, 145, 115, 1, 146, 116],
+        [14, 74, 46, 21, 75, 47],
+        [29, 54, 24, 19, 55, 25],
+        [11, 45, 15, 46, 46, 16],
+
+        // 34
+        [13, 145, 115, 6, 146, 116],
+        [14, 74, 46, 23, 75, 47],
+        [44, 54, 24, 7, 55, 25],
+        [59, 46, 16, 1, 47, 17],
+
+        // 35
+        [12, 151, 121, 7, 152, 122],
+        [12, 75, 47, 26, 76, 48],
+        [39, 54, 24, 14, 55, 25],
+        [22, 45, 15, 41, 46, 16],
+
+        // 36
+        [6, 151, 121, 14, 152, 122],
+        [6, 75, 47, 34, 76, 48],
+        [46, 54, 24, 10, 55, 25],
+        [2, 45, 15, 64, 46, 16],
+
+        // 37
+        [17, 152, 122, 4, 153, 123],
+        [29, 74, 46, 14, 75, 47],
+        [49, 54, 24, 10, 55, 25],
+        [24, 45, 15, 46, 46, 16],
+
+        // 38
+        [4, 152, 122, 18, 153, 123],
+        [13, 74, 46, 32, 75, 47],
+        [48, 54, 24, 14, 55, 25],
+        [42, 45, 15, 32, 46, 16],
+
+        // 39
+        [20, 147, 117, 4, 148, 118],
+        [40, 75, 47, 7, 76, 48],
+        [43, 54, 24, 22, 55, 25],
+        [10, 45, 15, 67, 46, 16],
+
+        // 40
+        [19, 148, 118, 6, 149, 119],
+        [18, 75, 47, 31, 76, 48],
+        [34, 54, 24, 34, 55, 25],
+        [20, 45, 15, 61, 46, 16]
+    ];
+
+    /**
+     * 根据数据获取对应版本
+     * @return {[type]} [description]
+     */
+    QRCodeAlg.prototype.getRightType = function () {
+        for (var typeNumber = 1; typeNumber < 41; typeNumber++) {
+            var rsBlock = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + this.errorCorrectLevel];
+            if (rsBlock == undefined) {
+                throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + this.errorCorrectLevel);
+            }
+            var length = rsBlock.length / 3;
+            var totalDataCount = 0;
+            for (var i = 0; i < length; i++) {
+                var count = rsBlock[i * 3 + 0];
+                var dataCount = rsBlock[i * 3 + 2];
+                totalDataCount += dataCount * count;
+            }
+            var lengthBytes = typeNumber > 9 ? 2 : 1;
+            if (this.utf8bytes.length + lengthBytes < totalDataCount || typeNumber == 40) {
+                this.typeNumber = typeNumber;
+                this.rsBlock = rsBlock;
+                this.totalDataCount = totalDataCount;
+                break;
+            }
+        }
+    };
+
+    //---------------------------------------------------------------------
+    // QRBitBuffer
+    //---------------------------------------------------------------------
+    function QRBitBuffer() {
+        this.buffer = new Array();
+        this.length = 0;
+    }
+    QRBitBuffer.prototype = {
+        get: function (index) {
+            var bufIndex = Math.floor(index / 8);
+            return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1);
+        },
+        put: function (num, length) {
+            for (var i = 0; i < length; i++) {
+                this.putBit(((num >>> (length - i - 1)) & 1));
+            }
+        },
+        putBit: function (bit) {
+            var bufIndex = Math.floor(this.length / 8);
+            if (this.buffer.length <= bufIndex) {
+                this.buffer.push(0);
+            }
+            if (bit) {
+                this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+            }
+            this.length++;
+        }
+    };
+
+
+
+    // xzedit
+    let qrcodeAlgObjCache = [];
+    /**
+     * 二维码构造函数,主要用于绘制
+     * @param  {参数列表} opt 传递参数
+     * @return {}
+     */
+    QRCode = function (opt) {
+        //设置默认参数
+        this.options = {
+            text: '',
+            size: 256,
+            correctLevel: 3,
+            background: '#ffffff',
+            foreground: '#000000',
+            pdground: '#000000',
+            image: '',
+            imageSize: 30,
+            canvasId: opt.canvasId,
+            context: opt.context,
+            usingComponents: opt.usingComponents,
+            showLoading: opt.showLoading,
+            loadingText: opt.loadingText,
+        };
+        if (typeof opt === 'string') { // 只编码ASCII字符串
+            opt = {
+                text: opt
+            };
+        }
+        if (opt) {
+            for (var i in opt) {
+                this.options[i] = opt[i];
+            }
+        }
+        //使用QRCodeAlg创建二维码结构
+        var qrCodeAlg = null;
+        for (var i = 0, l = qrcodeAlgObjCache.length; i < l; i++) {
+            if (qrcodeAlgObjCache[i].text == this.options.text && qrcodeAlgObjCache[i].text.correctLevel == this.options.correctLevel) {
+                qrCodeAlg = qrcodeAlgObjCache[i].obj;
+                break;
+            }
+        }
+        if (i == l) {
+            qrCodeAlg = new QRCodeAlg(this.options.text, this.options.correctLevel);
+            qrcodeAlgObjCache.push({
+                text: this.options.text,
+                correctLevel: this.options.correctLevel,
+                obj: qrCodeAlg
+            });
+        }
+        /**
+         * 计算矩阵点的前景色
+         * @param {Obj} config
+         * @param {Number} config.row 点x坐标
+         * @param {Number} config.col 点y坐标
+         * @param {Number} config.count 矩阵大小
+         * @param {Number} config.options 组件的options
+         * @return {String}
+         */
+        let getForeGround = function (config) {
+            var options = config.options;
+            if (options.pdground && (
+                (config.row > 1 && config.row < 5 && config.col > 1 && config.col < 5) ||
+                (config.row > (config.count - 6) && config.row < (config.count - 2) && config.col > 1 && config.col < 5) ||
+                (config.row > 1 && config.row < 5 && config.col > (config.count - 6) && config.col < (config.count - 2))
+            )) {
+                return options.pdground;
+            }
+            return options.foreground;
+        }
+        // 创建canvas
+        let createCanvas = function (options) {
+            if (options.showLoading) {
+                // uni.showLoading({
+                //     title: options.loadingText,
+                //     mask: true
+                // });
+            }
+            var ctx = uni.createCanvasContext(options.canvasId, options.context);
+            var count = qrCodeAlg.getModuleCount();
+            var ratioSize = options.size;
+            var ratioImgSize = options.imageSize;
+            //计算每个点的长宽
+            var tileW = (ratioSize / count).toPrecision(4);
+            var tileH = (ratioSize / count).toPrecision(4);
+            //绘制
+            for (var row = 0; row < count; row++) {
+                for (var col = 0; col < count; col++) {
+                    var w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW));
+                    var h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW));
+                    var foreground = getForeGround({
+                        row: row,
+                        col: col,
+                        count: count,
+                        options: options
+                    });
+                    ctx.setFillStyle(qrCodeAlg.modules[row][col] ? foreground : options.background);
+                    ctx.fillRect(Math.round(col * tileW), Math.round(row * tileH), w, h);
+                }
+            }
+            if (options.image) {
+                var x = Number(((ratioSize - ratioImgSize) / 2).toFixed(2));
+                var y = Number(((ratioSize - ratioImgSize) / 2).toFixed(2));
+                drawRoundedRect(ctx, x, y, ratioImgSize, ratioImgSize, 2, 6, true, true)
+                ctx.drawImage(options.image, x, y, ratioImgSize, ratioImgSize);
+                // 画圆角矩形
+                function drawRoundedRect(ctxi, x, y, width, height, r, lineWidth, fill, stroke) {
+                    ctxi.setLineWidth(lineWidth);
+                    ctxi.setFillStyle(options.background);
+                    ctxi.setStrokeStyle(options.background);
+                    ctxi.beginPath(); // draw top and top right corner 
+                    ctxi.moveTo(x + r, y);
+                    ctxi.arcTo(x + width, y, x + width, y + r, r); // draw right side and bottom right corner 
+                    ctxi.arcTo(x + width, y + height, x + width - r, y + height, r); // draw bottom and bottom left corner 
+                    ctxi.arcTo(x, y + height, x, y + height - r, r); // draw left and top left corner 
+                    ctxi.arcTo(x, y, x + r, y, r);
+                    ctxi.closePath();
+                    if (fill) {
+                        ctxi.fill();
+                    }
+                    if (stroke) {
+                        ctxi.stroke();
+                    }
+                }
+            }
+            setTimeout(() => {
+                ctx.draw(true, () => {
+                    // 保存到临时区域
+                    setTimeout(() => {
+                        uni.canvasToTempFilePath({
+                            width: options.width,
+                            height: options.height,
+                            destWidth: options.width,
+                            destHeight: options.height,
+                            canvasId: options.canvasId,
+                            quality: Number(1),
+                            success: function (res) {
+                                if (options.cbResult) {
+                                    options.cbResult(res.tempFilePath)
+                                }
+                            },
+                            fail: function (res) {
+                                if (options.cbResult) {
+                                    options.cbResult(res)
+                                }
+                            },
+                            complete: function () {
+                                if (options.showLoading){
+                                    // uni.hideLoading();
+                                }
+                            },
+                        }, options.context);
+                    }, options.text.length + 100);
+                });
+            }, options.usingComponents ? 0 : 150);
+        }
+        createCanvas(this.options);
+        // 空判定
+        let empty = function (v) {
+            let tp = typeof v,
+                rt = false;
+            if (tp == "number" && String(v) == "") {
+                rt = true
+            } else if (tp == "undefined") {
+                rt = true
+            } else if (tp == "object") {
+                if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
+            } else if (tp == "string") {
+                if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
+            } else if (tp == "function") {
+                rt = false
+            }
+            return rt
+        }
+    };
+    QRCode.prototype.clear = function (fn) {
+        var ctx = uni.createCanvasContext(this.options.canvasId, this.options.context)
+        ctx.clearRect(0, 0, this.options.size, this.options.size)
+        ctx.draw(false, () => {
+            if (fn) {
+                fn()
+            }
+        })
+    };
+})()
+
+export default QRCode

+ 210 - 0
components/zb-code/zb-code.vue

@@ -0,0 +1,210 @@
+<template xlang="wxml" minapp="mpvue">
+	<view class="zb-code">
+		<!-- #ifndef MP-ALIPAY -->
+		<canvas class="zb-code-canvas" :canvas-id="cid" :style="{width:cpSize+'px',height:cpSize+'px'}" />
+		<!-- #endif -->
+		<!-- #ifdef MP-ALIPAY -->
+		<canvas :id="cid" :width="cpSize" :height="cpSize" class="zb-code-canvas" />
+		<!-- #endif -->
+		<image v-show="show" :src="result" :style="{width:cpSize+'px',height:cpSize+'px'}" />
+	</view>
+</template>
+
+<script>
+import QRCode from "./qrcode.js"
+let qrcode
+export default {
+	name: "zb-code",
+	props: {
+		cid: {
+			type: String,
+			default: 'zb-code-canvas'
+		},
+		size: {
+			type: Number,
+			default: 200
+		},
+		unit: {
+			type: String,
+			default: 'upx'
+		},
+		show: {
+			type: Boolean,
+			default: true
+		},
+		val: {
+			type: String,
+			default: ''
+		},
+		background: {
+			type: String,
+			default: '#ffffff'
+		},
+		foreground: {
+			type: String,
+			default: '#000000'
+		},
+		pdground: {
+			type: String,
+			default: '#000000'
+		},
+		icon: {
+			type: String,
+			default: ''
+		},
+		iconSize: {
+			type: Number,
+			default: 40
+		},
+		lv: {
+			type: Number,
+			default: 3
+		},
+		onval: {
+			type: Boolean,
+			default: false
+		},
+		loadMake: {
+			type: Boolean,
+			default: false
+		},
+		usingComponents: {
+			type: Boolean,
+			default: true
+		},
+		showLoading: {
+			type: Boolean,
+			default: true
+		},
+		loadingText: {
+			type: String,
+			default: '二维码生成中'
+		},
+	},
+	data() {
+		return {
+			result: '',
+		}
+	},
+	methods: {
+		_makeCode() {
+			let that = this
+			if (!this._empty(this.val)) {
+				qrcode = new QRCode({
+					context: that, // 上下文环境
+					canvasId:that.cid, // canvas-id
+					usingComponents: that.usingComponents, // 是否是自定义组件
+					showLoading: that.showLoading, // 是否显示loading
+					loadingText: that.loadingText, // loading文字
+					text: that.val, // 生成内容
+					size: that.cpSize, // 二维码大小
+					background: that.background, // 背景色
+					foreground: that.foreground, // 前景色
+					pdground: that.pdground, // 定位角点颜色
+					correctLevel: that.lv, // 容错级别
+					image: that.icon, // 二维码图标
+					imageSize: that.iconSize,// 二维码图标大小
+					cbResult: function (res) { // 生成二维码的回调
+						that._result(res)
+					},
+				});
+			} else {
+				uni.showToast({
+					title: '二维码内容不能为空',
+					icon: 'none',
+					duration: 2000
+				});
+			}
+		},
+		_clearCode() {
+			this._result('')
+			qrcode.clear()
+		},
+		_saveCode() {
+			let that = this;
+			if (this.result != "") {
+				uni.saveImageToPhotosAlbum({
+					filePath: that.result,
+					success: function () {
+						uni.showToast({
+							title: '二维码保存成功',
+							icon: 'success',
+							duration: 2000
+						});
+					}
+				});
+			}
+		},
+		_result(res) {
+			this.result = res;
+			this.$emit('result', res)
+		},
+		_empty(v) {
+			let tp = typeof v,
+				rt = false;
+			if (tp == "number" && String(v) == "") {
+				rt = true
+			} else if (tp == "undefined") {
+				rt = true
+			} else if (tp == "object") {
+				if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
+			} else if (tp == "string") {
+				if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
+			} else if (tp == "function") {
+				rt = false
+			}
+			return rt
+		}
+	},
+	watch: {
+		size: function (n, o) {
+			if (n != o && !this._empty(n)) {
+				this.cSize = n
+				if (!this._empty(this.val)) {
+					setTimeout(() => {
+						this._makeCode()
+					}, 100);
+				}
+			}
+		},
+		val: function (n, o) {
+			if (this.onval) {
+				if (n != o && !this._empty(n)) {
+					setTimeout(() => {
+						this._makeCode()
+					}, 0);
+				}
+			}
+		}
+	},
+	computed: {
+		cpSize() {
+			if(this.unit == "upx"){
+				return uni.upx2px(this.size)
+			}else{
+				return this.size
+			}
+		}
+	},
+	mounted: function () {
+		if (this.loadMake) {
+			if (!this._empty(this.val)) {
+				setTimeout(() => {
+					this._makeCode()
+				}, 0);
+			}
+		}
+	},
+}
+</script>
+<style>
+.zb-code {
+  position: relative;
+}
+.zb-code-canvas {
+  position: fixed;
+  top: -99999upx;
+  left: -99999upx;
+  z-index: -99999;
+}
+</style>

+ 49 - 0
config/app.js

@@ -0,0 +1,49 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+module.exports = {
+
+	// 小程序配置
+	// #ifdef MP || APP-PLUS
+	// 请求域名 格式: https://您的域名
+	HTTP_REQUEST_URL: `https://ygs.hqgjsmc.com`,
+	// 长连接 格式:wss://您的域名 
+	VUE_APP_WS_URL: `wss://ygs.hqgjsmc.com/ws`,
+	// #endif
+	// H5配置
+	// #ifdef H5
+	//H5接口是浏览器地址,非单独部署不用修改
+	// HTTP_REQUEST_URL:  window.location.protocol + "//" + window.location.host,
+		HTTP_REQUEST_URL: `https://ygs.hqgjsmc.com`,
+	// 长连接地址,非单独部署不用修改
+	VUE_APP_WS_URL: `ws://${window.location.host}/ws`,
+	// #endif
+
+
+	// 以下配置在不做二开的前提下,不需要做任何的修改
+	HEADER: {
+		'content-type': 'application/json',
+		//#ifdef H5
+		'Form-type': navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1 ? 'wechat' : 'h5',
+		//#endif
+		//#ifdef MP
+		'Form-type': 'routine',
+		//#endif
+		//#ifdef APP-PLUS
+		'Form-type': 'app',
+		//#endif
+	},
+	// 回话密钥名称 请勿修改此配置
+	TOKENNAME: 'Authori-zation',
+	// 缓存时间 0 永久
+	EXPIRE: 0,
+	//分页最多显示条数
+	LIMIT: 10
+}

+ 42 - 0
config/cache.js

@@ -0,0 +1,42 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+module.exports = {
+	//token
+	LOGIN_STATUS: 'LOGIN_STATUS_TOKEN',
+	//uid
+	UID:'UID',
+	//用户信息
+	USER_INFO: 'USER_INFO',
+	//token过期时间
+	EXPIRES_TIME: 'EXPIRES_TIME',
+	//微信登录
+	WX_AUTH: 'WX_AUTH',
+	//公众号登录code
+	STATE_KEY: 'wx_authorize_state',
+	//登录类型
+	LOGINTYPE: 'loginType',
+	//登录跳转地址
+	BACK_URL: 'login_back_url',
+	//小程序登录状态code
+	STATE_R_KEY: 'roution_authorize_state',
+	//logo 地址
+	LOGO_URL: 'LOGO_URL',
+	//模板缓存
+	SUBSCRIBE_MESSAGE: 'SUBSCRIBE_MESSAGE',
+
+	TIPS_KEY: 'TIPS_KEY',
+
+	SPREAD: 'spread',
+	//缓存经度
+	CACHE_LONGITUDE: 'LONGITUDE',
+	//缓存纬度
+	CACHE_LATITUDE: 'LATITUDE',
+}

+ 18 - 0
config/socket.js

@@ -0,0 +1,18 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+module.exports = {
+  // Socket链接 暂不做配置
+  WSS_SERVER_URL:'',
+  // Socket调试模式
+  SERVER_DEBUG:true,
+  // 心跳间隔
+  PINGINTERVAL:3000
+}

+ 33 - 0
index.html

@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+	<head>
+		<meta charset="utf-8">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge">
+		<title>
+			易博优购
+		</title>
+		<!-- Open Graph data -->
+		<!-- <meta property="og:title" content="Title Here" /> -->
+		<!-- <meta property="og:url" content="http://www.example.com/" /> -->
+		<!-- <meta property="og:image" content="http://example.com/image.jpg" /> -->
+		<!-- <meta property="og:description" content="Description Here" /> -->
+		<script>
+		window.wx = null;
+		//uniapp默认的wx重置
+		</script>
+		<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
+		<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+		<script>
+			var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
+			document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+		</script>
+		<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
+	</head>
+	<body>
+		<noscript>
+			<strong>Please enable JavaScript to continue.</strong>
+		</noscript>
+		<div id="app"></div>
+		<!-- built files will be auto injected -->
+	</body>
+</html>

+ 272 - 0
js_sdk/wa-permission/permission.js

@@ -0,0 +1,272 @@
+/**
+ * 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启
+ */
+
+var isIos
+// #ifdef APP-PLUS
+isIos = (plus.os.name == "iOS")
+// #endif
+
+// 判断推送权限是否开启
+function judgeIosPermissionPush() {
+	var result = false;
+	var UIApplication = plus.ios.import("UIApplication");
+	var app = UIApplication.sharedApplication();
+	var enabledTypes = 0;
+	if (app.currentUserNotificationSettings) {
+		var settings = app.currentUserNotificationSettings();
+		enabledTypes = settings.plusGetAttribute("types");
+		console.log("enabledTypes1:" + enabledTypes);
+		if (enabledTypes == 0) {
+			console.log("推送权限没有开启");
+		} else {
+			result = true;
+			console.log("已经开启推送功能!")
+		}
+		plus.ios.deleteObject(settings);
+	} else {
+		enabledTypes = app.enabledRemoteNotificationTypes();
+		if (enabledTypes == 0) {
+			console.log("推送权限没有开启!");
+		} else {
+			result = true;
+			console.log("已经开启推送功能!")
+		}
+		console.log("enabledTypes2:" + enabledTypes);
+	}
+	plus.ios.deleteObject(app);
+	plus.ios.deleteObject(UIApplication);
+	return result;
+}
+
+// 判断定位权限是否开启
+function judgeIosPermissionLocation() {
+	var result = false;
+	var cllocationManger = plus.ios.import("CLLocationManager");
+	var status = cllocationManger.authorizationStatus();
+	result = (status != 2)
+	console.log("定位权限开启:" + result);
+	// 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation
+	/* var enable = cllocationManger.locationServicesEnabled();
+	var status = cllocationManger.authorizationStatus();
+	console.log("enable:" + enable);
+	console.log("status:" + status);
+	if (enable && status != 2) {
+		result = true;
+		console.log("手机定位服务已开启且已授予定位权限");
+	} else {
+		console.log("手机系统的定位没有打开或未给予定位权限");
+	} */
+	plus.ios.deleteObject(cllocationManger);
+	return result;
+}
+
+// 判断麦克风权限是否开启
+function judgeIosPermissionRecord() {
+	var result = false;
+	var avaudiosession = plus.ios.import("AVAudioSession");
+	var avaudio = avaudiosession.sharedInstance();
+	var permissionStatus = avaudio.recordPermission();
+	console.log("permissionStatus:" + permissionStatus);
+	if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
+		console.log("麦克风权限没有开启");
+	} else {
+		result = true;
+		console.log("麦克风权限已经开启");
+	}
+	plus.ios.deleteObject(avaudiosession);
+	return result;
+}
+
+// 判断相机权限是否开启
+function judgeIosPermissionCamera() {
+	var result = false;
+	var AVCaptureDevice = plus.ios.import("AVCaptureDevice");
+	var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
+	console.log("authStatus:" + authStatus);
+	if (authStatus == 3) {
+		result = true;
+		console.log("相机权限已经开启");
+	} else {
+		console.log("相机权限没有开启");
+	}
+	plus.ios.deleteObject(AVCaptureDevice);
+	return result;
+}
+
+// 判断相册权限是否开启
+function judgeIosPermissionPhotoLibrary() {
+	var result = false;
+	var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
+	var authStatus = PHPhotoLibrary.authorizationStatus();
+	console.log("authStatus:" + authStatus);
+	if (authStatus == 3) {
+		result = true;
+		console.log("相册权限已经开启");
+	} else {
+		console.log("相册权限没有开启");
+	}
+	plus.ios.deleteObject(PHPhotoLibrary);
+	return result;
+}
+
+// 判断通讯录权限是否开启
+function judgeIosPermissionContact() {
+	var result = false;
+	var CNContactStore = plus.ios.import("CNContactStore");
+	var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
+	if (cnAuthStatus == 3) {
+		result = true;
+		console.log("通讯录权限已经开启");
+	} else {
+		console.log("通讯录权限没有开启");
+	}
+	plus.ios.deleteObject(CNContactStore);
+	return result;
+}
+
+// 判断日历权限是否开启
+function judgeIosPermissionCalendar() {
+	var result = false;
+	var EKEventStore = plus.ios.import("EKEventStore");
+	var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
+	if (ekAuthStatus == 3) {
+		result = true;
+		console.log("日历权限已经开启");
+	} else {
+		console.log("日历权限没有开启");
+	}
+	plus.ios.deleteObject(EKEventStore);
+	return result;
+}
+
+// 判断备忘录权限是否开启
+function judgeIosPermissionMemo() {
+	var result = false;
+	var EKEventStore = plus.ios.import("EKEventStore");
+	var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
+	if (ekAuthStatus == 3) {
+		result = true;
+		console.log("备忘录权限已经开启");
+	} else {
+		console.log("备忘录权限没有开启");
+	}
+	plus.ios.deleteObject(EKEventStore);
+	return result;
+}
+
+// Android权限查询
+function requestAndroidPermission(permissionID) {
+	return new Promise((resolve, reject) => {
+		plus.android.requestPermissions(
+			[permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装
+			function(resultObj) {
+				var result = 0;
+				for (var i = 0; i < resultObj.granted.length; i++) {
+					var grantedPermission = resultObj.granted[i];
+					console.log('已获取的权限:' + grantedPermission);
+					result = 1
+				}
+				for (var i = 0; i < resultObj.deniedPresent.length; i++) {
+					var deniedPresentPermission = resultObj.deniedPresent[i];
+					console.log('拒绝本次申请的权限:' + deniedPresentPermission);
+					result = 0
+				}
+				for (var i = 0; i < resultObj.deniedAlways.length; i++) {
+					var deniedAlwaysPermission = resultObj.deniedAlways[i];
+					console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
+					result = -1
+				}
+				resolve(result);
+				// 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
+				// if (result != 1) {
+				// gotoAppPermissionSetting()
+				// }
+			},
+			function(error) {
+				console.log('申请权限错误:' + error.code + " = " + error.message);
+				resolve({
+					code: error.code,
+					message: error.message
+				});
+			}
+		);
+	});
+}
+
+// 使用一个方法,根据参数判断权限
+function judgeIosPermission(permissionID) {
+	if (permissionID == "location") {
+		return judgeIosPermissionLocation()
+	} else if (permissionID == "camera") {
+		return judgeIosPermissionCamera()
+	} else if (permissionID == "photoLibrary") {
+		return judgeIosPermissionPhotoLibrary()
+	} else if (permissionID == "record") {
+		return judgeIosPermissionRecord()
+	} else if (permissionID == "push") {
+		return judgeIosPermissionPush()
+	} else if (permissionID == "contact") {
+		return judgeIosPermissionContact()
+	} else if (permissionID == "calendar") {
+		return judgeIosPermissionCalendar()
+	} else if (permissionID == "memo") {
+		return judgeIosPermissionMemo()
+	}
+	return false;
+}
+
+// 跳转到**应用**的权限页面
+function gotoAppPermissionSetting() {
+	if (isIos) {
+		var UIApplication = plus.ios.import("UIApplication");
+		var application2 = UIApplication.sharedApplication();
+		var NSURL2 = plus.ios.import("NSURL");
+		// var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");		
+		var setting2 = NSURL2.URLWithString("app-settings:");
+		application2.openURL(setting2);
+
+		plus.ios.deleteObject(setting2);
+		plus.ios.deleteObject(NSURL2);
+		plus.ios.deleteObject(application2);
+	} else {
+		// console.log(plus.device.vendor);
+		var Intent = plus.android.importClass("android.content.Intent");
+		var Settings = plus.android.importClass("android.provider.Settings");
+		var Uri = plus.android.importClass("android.net.Uri");
+		var mainActivity = plus.android.runtimeMainActivity();
+		var intent = new Intent();
+		intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+		var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
+		intent.setData(uri);
+		mainActivity.startActivity(intent);
+	}
+}
+
+// 检查系统的设备服务是否开启
+// var checkSystemEnableLocation = async function () {
+function checkSystemEnableLocation() {
+	if (isIos) {
+		var result = false;
+		var cllocationManger = plus.ios.import("CLLocationManager");
+		var result = cllocationManger.locationServicesEnabled();
+		console.log("系统定位开启:" + result);
+		plus.ios.deleteObject(cllocationManger);
+		return result;
+	} else {
+		var context = plus.android.importClass("android.content.Context");
+		var locationManager = plus.android.importClass("android.location.LocationManager");
+		var main = plus.android.runtimeMainActivity();
+		var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
+		var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
+		console.log("系统定位开启:" + result);
+		return result
+	}
+}
+
+module.exports = {
+	judgeIosPermission: judgeIosPermission,
+	requestAndroidPermission: requestAndroidPermission,
+	checkSystemEnableLocation: checkSystemEnableLocation,
+	gotoAppPermissionSetting: gotoAppPermissionSetting
+}

+ 138 - 0
libs/login.js

@@ -0,0 +1,138 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import store from "../store";
+import Cache from '../utils/cache';
+import {
+	Debounce
+} from '@/utils/validate.js'
+// #ifdef H5 || APP-PLUS
+import {
+	isWeixin
+} from "../utils";
+import auth from './wechat';
+// #endif
+
+import {
+	LOGIN_STATUS,
+	USER_INFO,
+	EXPIRES_TIME,
+	STATE_R_KEY
+} from './../config/cache';
+import Routine from '@/libs/routine';
+
+function prePage() {
+	let pages = getCurrentPages();
+	let prePage = pages[pages.length - 1];
+	// #ifndef APP-PLUS
+	return prePage.route;
+	// #endif
+	// #ifdef APP-PLUS
+	return prePage.$page.fullPath;
+	// #endif
+
+}
+
+
+
+
+export const toLogin = Debounce(_toLogin, 800)
+
+function _toLogin(push, pathLogin) {
+	// #ifdef H5
+	if (isWeixin()) {
+		if (!uni.getStorageSync('authIng')) {
+			store.commit("LOGOUT");
+		}
+	} else {
+		store.commit("LOGOUT");
+	}
+	// #endif
+	// #ifndef H5
+	store.commit("LOGOUT");
+	// #endif
+	let path = prePage();
+
+	// #ifdef H5
+	path = location.pathname + location.search;
+	// #endif
+
+	if (!pathLogin)
+		pathLogin = '/page/users/login/index'
+	Cache.set('login_back_url', path);
+	// #ifdef H5
+	if (isWeixin()) {
+		let urlData = location.pathname + location.search
+		if (urlData.indexOf('?') !== -1) {
+			urlData += '&go_longin=1';
+		} else {
+			urlData += '?go_longin=1';
+		}
+		if (!Cache.has('snsapiKey')) {
+			auth.oAuth('snsapi_base', urlData);
+		} else {
+			uni.navigateTo({
+				url: '/pages/users/wechat_login/index',
+			});
+		}
+
+	} else {
+		uni.navigateTo({
+			url: '/pages/users/login/index'
+		})
+	}
+	// #endif
+
+	// #ifdef MP 
+	// uni.navigateTo({
+	// 	url: '/pages/users/wechat_login/index'
+	// })
+	// Routine.getCode()
+	// 	.then(code => {
+	// 		console.log(code)
+	// 		Routine.silenceAuth(code).then(res => {
+	// 			console.log(res)
+	// 		})
+	// 	})
+	// 	.catch(err => {
+	// 		uni.hideLoading();
+	// 	});
+	// #endif
+
+	// #ifdef APP-PLUS
+	uni.navigateTo({
+		url: '/pages/users/login/index'
+	})
+	// #endif
+
+}
+
+
+export function checkLogin() {
+	let token = Cache.get(LOGIN_STATUS);
+	let expiresTime = Cache.get(EXPIRES_TIME);
+	let newTime = Math.round(new Date() / 1000);
+	if (expiresTime < newTime || !token) {
+		uni.setStorageSync('authIng', false)
+		Cache.clear(LOGIN_STATUS);
+		Cache.clear(EXPIRES_TIME);
+		Cache.clear(USER_INFO);
+		Cache.clear(STATE_R_KEY);
+		return false;
+	} else {
+		store.commit('UPDATE_LOGIN', token);
+		let userInfo = Cache.get(USER_INFO, true);
+		if (userInfo) {
+			store.commit('UPDATE_USERINFO', userInfo);
+		}
+		return true;
+	}
+
+}

+ 9 - 0
libs/network.js

@@ -0,0 +1,9 @@
+export function onNetworkStatusChange(onlineFun, offlineFun) {
+	uni.onNetworkStatusChange(res => {
+		if(res.networkType !== 'none') { 
+			onlineFun && onlineFun(res);
+		} else{
+			offlineFun && offlineFun(res);
+		}
+	});
+}

+ 259 - 0
libs/new_chat.js

@@ -0,0 +1,259 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import $store from "@/store";
+import wechat from "@/libs/wechat";
+import {
+	HTTP_REQUEST_URL,
+	VUE_APP_WS_URL
+} from "@/config/app.js";
+import {
+	getServerType
+} from '@/api/api.js';
+import {
+	onNetworkStatusChange
+} from '@/libs/network.js';
+
+
+function wss(wsSocketUrl) {
+	if (wsSocketUrl.indexOf('wss:') !== -1) {
+		return wsSocketUrl;
+	}
+	// #ifdef H5
+	let ishttps = document.location.protocol == 'https:';
+	if (ishttps) {
+		return wsSocketUrl.replace('ws:', 'wss:');
+	} else {
+		return wsSocketUrl.replace('wss:', 'ws:');
+	}
+	// #endif
+	// #ifndef H5
+	return wsSocketUrl.replace('ws:', 'wss:');
+	//#endif
+}
+
+class Socket {
+	constructor() {
+		this.socketTask = null; //socket 任务
+		this.timer = null; //心跳定时器
+		this.connectStatus = false; //连接状态
+		this.wsUrl = ''; //ws地址
+		this.reconnectTimer = 2000; //重连
+		this.handClse = false; //手动关闭
+		this.reconnetime = null; //重连 定时器
+		this.networkStatus = true;
+		this.connectLing = false; //连接是否进行中
+		this.defaultEvenv(); //执行默认事件
+		this.networkEvent();
+	}
+	//网络状态变化监听
+	networkEvent() {
+		onNetworkStatusChange((res) => {
+			console.log('有网了',res)
+			this.networkStatus = true;
+			if (this.socketTask) {
+				this.socketTask.close();	
+			}
+			uni.$on('timeout', this.timeoutEvent.bind(this))
+		}, () => {
+			console.log('断网了')
+			this.networkStatus = false;
+			this.connectStatus = false;
+			clearInterval(this.timer);
+			this.timer = null;
+			uni.$off('timeout', this.timeoutEvent)
+		});
+	}
+	//开始连接
+	startConnect() {
+		console.log('开始链接')
+		this.handClse = false;
+		if (!this.connectStatus) {
+			this.init();
+			this.connect();
+		}
+	}
+	//默认事件
+	defaultEvenv() {
+
+		uni.$off('success', this.successEvent);
+		uni.$off('timeout', this.timeoutEvent);
+
+		uni.$on('success', this.successEvent.bind(this));
+		uni.$on('timeout', this.timeoutEvent.bind(this));
+	}
+
+	timeoutEvent() {
+		console.log('timeoutEvent')
+		this.reconne();
+	}
+	successEvent() {
+		console.log('success默认事件');
+		// this.changOnline();
+	}
+	//发送用户状态
+	changOnline() {
+		let online = cache.get('kefu_online')
+		if (online !== undefined && online !== '') {
+			this.send({
+				data: {
+					online: online
+				},
+				type: 'online'
+			});
+		}
+	}
+
+	//连接websocket
+	connect() {
+		this.connectLing = true;
+		this.socketTask = uni.connectSocket({
+			url: this.wsUrl,
+			complete: () => {}
+		});
+
+		this.socketTask.onOpen(this.onOpen.bind(this))
+		this.socketTask.onError(this.onError.bind(this));
+		this.socketTask.onMessage(this.onMessage.bind(this))
+		this.socketTask.onClose(this.onClose.bind(this));
+
+	}
+
+	init() {
+		let wsUrl = wss(`${VUE_APP_WS_URL}?type=user`),
+			form_type = 3;
+
+		//#ifdef MP || APP-PLUS
+		form_type = 2
+		//#endif
+		//#ifdef H5
+		form_type = wechat.isWeixin() ? 1 : 3
+		//#endif
+		this.wsUrl = `${wsUrl}&token=${$store.state.app.token}&form_type=${form_type}`
+	}
+
+	//断线重连
+	reconne() {
+		if (this.reconnetime || this.connectStatus) {
+			return;
+		}
+		this.reconnetime = setInterval(() => {
+			if (this.connectStatus) {
+				return;
+			}
+			this.connectLing || this.connect();
+		}, this.reconnectTimer);
+	}
+
+	onOpen() {
+		clearInterval(this.reconnetime);
+		this.reconnetime = null;
+		this.connectLing = false;
+		this.connectStatus = true;
+		this.ping();
+	}
+
+	onError(error) {
+		console.log('连接发生错误', error)
+		this.connectStatus = false;
+		this.connectLing = false;
+		this.reconne();
+	}
+
+	onClose(err) {
+		console.log(this.socketTask, err, '关闭连接')
+		uni.$emit('close');
+		//手动关闭不用重新连接
+		if (this.handClse) {
+			return;
+		}
+		clearInterval(this.timer);
+		this.timer = null;
+		this.connectStatus = false;
+		this.connectLing = false;
+		this.reconne();
+	}
+
+	ping() {
+		this.timer = setInterval(() => {
+			this.send({
+				type: 'ping'
+			})
+		}, 10000)
+	}
+
+	onMessage(response) {
+		let {
+			type,
+			data
+		} = JSON.parse(response.data);
+		uni.$emit(type, data);
+	}
+
+
+	send(data) {
+		let that = this;
+		//没有网络,或者没有连接
+		if (!this.connectStatus || !this.networkStatus) {
+			this.reconne();
+		}
+		return new Promise((reslove, reject) => {
+			this.socketTask.send({
+				data: JSON.stringify(data),
+				success() {
+					reslove();
+				},
+				fail(res) {
+					console.log(res)
+					if (res.errMsg ==
+						'sendSocketMessage:fail WebSocket is not connected' ||
+						res.errMsg ==
+						'sendSocketMessage:fail Error: SocketTask.readyState is not OPEN'
+					) {
+						that.reconne();
+					}
+					reject(res);
+				},
+				complete(res) {
+					console.log(res)
+				}
+			})
+		});
+	}
+
+	guid() {
+		return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+			var r = Math.random() * 16 | 0,
+				v = c == 'x' ? r : (r & 0x3 | 0x8);
+			return v.toString(16);
+		});
+	}
+
+	clearPing() {
+		clearInterval(this.timer);
+		this.timer = null;
+		if (this.connectStatus) {
+			this.socketTask.close();
+		}
+		this.handClse = true;
+		this.connectStatus = false;
+		this.connectLing = false;
+	}
+
+	setBadgeNumber(count) {
+		//#ifdef APP-PLUS
+		plus.runtime.setBadgeNumber(Number(count));
+		//#endif
+	}
+
+}
+
+
+export default Socket;

+ 38 - 0
libs/order.js

@@ -0,0 +1,38 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+let app = getApp()
+
+export function goShopDetail(item, uid) {
+	return new Promise(resolve => {
+		if (item.activity && item.activity.type === "1") {
+			uni.navigateTo({
+				url: `/pages/activity/goods_seckill_details/index?id=${item.activity.id}&time=${item.activity.time}&status=1`
+			})
+		} else if (item.activity && item.activity.type === "2") {
+			uni.navigateTo({
+				url: `/pages/activity/goods_bargain_details/index?id=${item.activity.id}&bargain=${uid}`
+			})
+		} else if (item.activity && item.activity.type === "3") {
+			uni.navigateTo({
+				url: `/pages/activity/goods_combination_details/index?id=${item.activity.id}`
+			})
+		} else {
+			resolve(item);
+		}
+	});
+}
+
+
+export function goPage() {
+	return new Promise(resolve => {
+		resolve(true);
+	});
+}

+ 252 - 0
libs/routine.js

@@ -0,0 +1,252 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import store from '../store';
+import {
+	checkLogin
+} from './login';
+import {
+	login,
+	routineLogin,
+	silenceAuth
+} from '../api/public';
+import Cache from '../utils/cache';
+import {
+	STATE_R_KEY,
+	USER_INFO,
+	EXPIRES_TIME,
+	LOGIN_STATUS
+} from './../config/cache';
+import {
+	mapGetters
+} from "vuex";
+class Routine {
+
+	constructor() {
+		this.scopeUserInfo = 'scope.userInfo';
+	}
+
+	async getUserCode() {
+		let isAuth = await this.isAuth(),
+			code = '';
+		if (isAuth)
+			code = await this.getCode();
+		return code;
+	}
+	// 小程序静默授权
+	// silenceAuth(code) {
+	// 	const app = getApp();
+	// 	let that = this;
+	// 	let spread = app.globalData.spid ? app.globalData.spid : '';
+	// 	return new Promise((resolve, reject) => {
+	// 		silenceAuth({
+	// 				code: code,
+	// 				spread_spid: spread,
+	// 				spread_code: app.globalData.code
+	// 			})
+	// 			.then(res => {
+	// 				if (res.data && res.data.token !== undefined) {
+	// 					uni.hideLoading();
+	// 					let time = res.data.expires_time - Math.round(new Date() / 1000);
+	// 					store.commit('LOGIN', {
+	// 						token: res.data.token,
+	// 						time: time
+	// 					});
+	// 					store.commit('SETUID', res.data.userInfo.uid);
+	// 					store.commit('UPDATE_USERINFO', res.data.userInfo);
+	// 					resolve(res)
+	// 				} else {
+	// 					reject()
+	// 					uni.navigateTo({
+	// 						url: '/pages/users/wechat_login/index'
+	// 					})
+	// 				}
+	// 			})
+	// 			.catch(err => {
+	// 				reject(err)
+	// 			});
+	// 	})
+	// }
+	/**
+	 * 获取用户信息
+	 */
+	getUserInfo() {
+		let that = this,
+			code = this.getUserCode();
+		return new Promise((resolve, reject) => {
+			uni.getUserInfo({
+				lang: 'zh_CN',
+				success(user) {
+					if (code) user.code = code;
+					resolve({
+						userInfo: user,
+						islogin: false
+					});
+				},
+				fail(res) {
+					reject(res);
+				}
+			})
+		})
+	}
+
+	/**
+	 * 新版小程序获取用户信息 2021 4.13微信小程序开始正式启用
+	 */
+	getUserProfile(code) {
+		return new Promise((resolve, reject) => {
+			uni.getUserProfile({
+				lang: 'zh_CN',
+				desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
+				success(user) {
+					if (code) user.code = code;
+					resolve({
+						userInfo: user,
+						islogin: false
+					});
+				},
+				fail(res) {
+					reject(res);
+				}
+			})
+		})
+	}
+
+	/**
+	 * 获取用户信息
+	 */
+	authorize() {
+		let that = this;
+		return new Promise((resolve, reject) => {
+			if (checkLogin())
+				return resolve({
+					userInfo: Cache.get(USER_INFO, true),
+					islogin: true,
+				});
+			uni.authorize({
+				scope: that.scopeUserInfo,
+				success() {
+					resolve({
+						islogin: false
+					});
+				},
+				fail(res) {
+					reject(res);
+				}
+			})
+		})
+	}
+
+	async getCode() {
+		let provider = await this.getProvider();
+		return new Promise((resolve, reject) => {
+			// if(Cache.has(STATE_R_KEY)){
+			// 	return resolve(Cache.get(STATE_R_KEY));
+			// }
+			uni.login({
+				provider: provider,
+				success(res) {
+					if (res.code) Cache.set(STATE_R_KEY, res.code, 10800);
+					return resolve(res.code);
+				},
+				fail() {
+					return reject(null);
+				}
+			})
+		})
+	}
+
+	/**
+	 * 获取服务供应商
+	 */
+	getProvider() {
+		return new Promise((resolve, reject) => {
+			uni.getProvider({
+				service: 'oauth',
+				success(res) {
+					resolve(res.provider);
+				},
+				fail() {
+					resolve(false);
+				}
+			});
+		});
+	}
+
+	/**
+	 * 是否授权
+	 */
+	isAuth() {
+		let that = this;
+		return new Promise((resolve, reject) => {
+			uni.getSetting({
+				success(res) {
+					if (!res.authSetting[that.scopeUserInfo]) {
+						resolve(true)
+					} else {
+						resolve(true);
+					}
+				},
+				fail() {
+					resolve(false);
+				}
+			});
+		});
+	}
+	
+	/**
+	 * 小程序比较版本信息
+	 * @param v1 当前版本
+	 * @param v2 进行比较的版本 
+	 * @return boolen
+	 * 
+	 */
+	compareVersion(v1, v2) {
+		v1 = v1.split('.')
+		v2 = v2.split('.')
+		const len = Math.max(v1.length, v2.length)
+
+		while (v1.length < len) {
+			v1.push('0')
+		}
+		while (v2.length < len) {
+			v2.push('0')
+		}
+
+		for (let i = 0; i < len; i++) {
+			const num1 = parseInt(v1[i])
+			const num2 = parseInt(v2[i])
+
+			if (num1 > num2) {
+				return 1
+			} else if (num1 < num2) {
+				return -1
+			}
+		}
+
+		return 0
+	}
+	authUserInfo(data) {
+		return new Promise((resolve, reject) => {
+			routineLogin(data).then(res => {
+				if (res.data.key !== undefined && res.data.key) {} else {
+					store.commit('UPDATE_USERINFO', res.data.userInfo);
+					store.commit('SETUID', res.data.userInfo.uid);
+					Cache.set(USER_INFO, res.data.userInfo);
+				}
+				return resolve(res);
+			}).catch(res => {
+				return reject(res);
+			})
+		})
+	}
+}
+
+export default new Routine();

+ 334 - 0
libs/wechat.js

@@ -0,0 +1,334 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+// #ifdef H5
+import {
+	getWechatConfig,
+	wechatAuth,
+	getShopConfig,
+	wechatAuthV2
+} from "@/api/public";
+import {
+	WX_AUTH,
+	STATE_KEY,
+	LOGINTYPE,
+	BACK_URL
+} from '@/config/cache';
+import {
+	parseQuery
+} from '@/utils';
+import store from '@/store';
+import Cache from '@/utils/cache';
+
+class AuthWechat {
+
+	constructor() {
+		this.instance = jWeixin;
+		//是否实例化
+		this.status = false;
+
+		this.initConfig = {};
+
+	}
+	
+	isAndroid(){
+		let u = navigator.userAgent;
+		return u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
+	}
+	
+	signLink() {
+		if (typeof window.entryUrl === 'undefined' || window.entryUrl === '') {
+			  window.entryUrl = location.href
+		}
+		return  /(Android)/i.test(navigator.userAgent) ? location.href : window.entryUrl;
+	}
+
+	/**
+	 * 初始化wechat(分享配置)
+	 */
+	wechat() {
+		return new Promise((resolve, reject) => {
+			// if (this.status && !this.isAndroid()) return resolve(this.instance);
+			getWechatConfig()
+				.then(res => {
+					this.instance.config(res.data);
+					this.initConfig = res.data;
+					this.status = true;
+					this.instance.ready(() => {
+						resolve(this.instance);
+					})
+				}).catch(err => {
+					this.status = false;
+					reject(err);
+				});
+		});
+	}
+	
+	/**
+	 * 验证是否初始化
+	 */
+	verifyInstance() {
+		let that = this;
+		return new Promise((resolve, reject) => {
+			if (that.instance === null && !that.status) {
+				that.wechat().then(res => {
+					resolve(that.instance);
+				}).catch(() => {
+					return reject();
+				})
+			} else {
+				return resolve(that.instance);
+			}
+		})
+	}
+	// 微信公众号的共享地址
+	openAddress() {
+		return new Promise((resolve, reject) => {
+			this.wechat().then(wx => {
+				this.toPromise(wx.openAddress).then(res => {
+					resolve(res);
+				}).catch(err => {
+					reject(err);
+				});
+			}).catch(err => {
+				reject(err);
+			})
+		});
+	}
+	
+	// 获取经纬度;
+	location(){
+		return new Promise((resolve, reject) => {
+			this.wechat().then(wx => {
+				this.toPromise(wx.getLocation,{type: 'wgs84'}).then(res => {
+					resolve(res);
+				}).catch(err => {
+					reject(err);
+				});
+			}).catch(err => {
+				reject(err);
+			})
+		});
+	}
+	
+	// 使用微信内置地图查看位置接口;
+	seeLocation(config){
+		return new Promise((resolve, reject) => {
+			this.wechat().then(wx => {
+				this.toPromise(wx.openLocation, config).then(res => {
+					resolve(res);
+				}).catch(err => {
+					reject(err);
+				});
+			}).catch(err => {
+				reject(err);
+			})
+		});
+	}
+
+	/**
+	 * 微信支付
+	 * @param {Object} config
+	 */
+	pay(config) {
+		return new Promise((resolve, reject) => {
+			this.wechat().then((wx) => {
+				this.toPromise(wx.chooseWXPay, config).then(res => {
+					resolve(res);
+				}).catch(res => {
+					reject(res);
+				});
+			}).catch(res => {
+				reject(res);
+			});
+		});
+	}
+
+	toPromise(fn, config = {}) {
+		return new Promise((resolve, reject) => {
+			fn({
+				...config,
+				success(res) {
+					resolve(res);
+				},
+				fail(err) {
+					reject(err);
+				},
+				complete(err) {
+					reject(err);
+				},
+				cancel(err) {
+					reject(err);
+				}
+			});
+		});
+	}
+	
+	/**
+	 * 自动去授权
+	 */
+	oAuth(snsapiBase,url) {
+		if(uni.getStorageSync('authIng'))return
+		
+		if (uni.getStorageSync(WX_AUTH) && store.state.app.token && snsapiBase == 'snsapi_base') return;
+		let {
+			code
+		} = parseQuery();
+		let snsapiCode = uni.getStorageSync('snsapiCode')
+		if(code instanceof Array){
+			code = code[code.length-1]
+		}
+		if(snsapiCode instanceof Array){
+			snsapiCode = snsapiCode[snsapiCode.length-1]
+		}
+		if (!code || code == snsapiCode){
+			uni.setStorageSync('authIng',true)
+			return this.toAuth(snsapiBase,url);
+		}else{
+			if(Cache.has('snsapiKey'))
+				return this.auth(code).catch(error=>{
+					uni.showToast({
+						title:error,
+						icon:'none'
+					})
+				})
+		}
+	}
+
+	clearAuthStatus() {
+
+	}
+
+	/**
+	 * 授权登陆获取token
+	 * @param {Object} code
+	 */
+	auth(code) {
+		return new Promise((resolve, reject) => {
+			let loginType = Cache.get(LOGINTYPE);
+			wechatAuthV2(code, parseInt(Cache.get("spread")))
+				.then(({
+					data
+				}) => {
+					// store.commit("LOGIN", {
+					// 	token: data.token,
+					// 	time: Cache.strTotime(data.expires_time) - Cache.time()
+					// });
+					// store.commit("SETUID", data.userInfo.uid);
+					Cache.set(WX_AUTH, code);
+					Cache.clear(STATE_KEY);
+					resolve(data);
+				})
+				.catch(reject);
+		});
+	}
+
+	/**
+	 * 获取跳转授权后的地址
+	 * @param {Object} appId
+	 */
+	getAuthUrl(appId,snsapiBase,backUrl) {
+		if (backUrl) {
+			let backUrlArr = backUrl.split('&');
+			let newUrlArr = backUrlArr.filter(item => {
+				if (item.indexOf('code=') === -1 || item.indexOf('back_url=') === -1 || item.indexOf('scope=') === -1) {
+					return item;
+				}
+			});
+			backUrl = newUrlArr.join('&');
+		}
+		
+		let url = `${location.origin}${backUrl}`
+		
+		if(url.indexOf('?') == -1){
+					url = url+'?'
+				}else{
+					url = url+'&'
+				}
+		const redirect_uri = encodeURIComponent(
+			`${url}scope=${snsapiBase}&back_url=` +
+			encodeURIComponent(
+				encodeURIComponent(
+					uni.getStorageSync(BACK_URL) ?
+					uni.getStorageSync(BACK_URL) :
+					location.pathname + location.search
+				)
+			)
+		);
+		uni.removeStorageSync(BACK_URL);
+		const state = encodeURIComponent(
+			("" + Math.random()).split(".")[1] + "authorizestate"
+		);
+		uni.setStorageSync(STATE_KEY, state);
+		if(snsapiBase==='snsapi_base'){
+			return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_base&state=${state}&connect_redirect=1#wechat_redirect`;
+		}else{
+			return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=${state}&connect_redirect=1#wechat_redirect`;
+		}
+		
+	}
+
+	/**
+	 * 跳转自动登陆
+	 */
+	toAuth(snsapiBase,backUrl) {
+		let that = this;
+		this.wechat().then(wx => {
+			location.href = this.getAuthUrl(that.initConfig.appId,snsapiBase,backUrl);
+		})
+	}
+
+	/**
+	 * 绑定事件
+	 * @param {Object} name 事件名
+	 * @param {Object} config 参数
+	 */
+	wechatEvevt(name, config) {
+		let that = this;
+		return new Promise((resolve, reject) => {
+			let configDefault = {
+				fail(res) {
+					if (that.instance) return reject({
+						is_ready: true,
+						wx: that.instance
+					});
+					that.verifyInstance().then(wx => {
+						return reject({
+							is_ready: true,
+							wx: wx
+						});
+					})
+				},
+				success(res) {
+					return resolve(res,2222);
+				}
+			};
+			Object.assign(configDefault, config);
+			that.wechat().then(wx => {
+				if (typeof name === 'object') {
+					name.forEach(item => {
+						wx[item] && wx[item](configDefault)
+					})
+				} else {
+					wx[name] && wx[name](configDefault)
+				}
+			})
+		});
+	}
+	
+
+	isWeixin() {
+		return navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1;
+	}
+
+}
+
+export default new AuthWechat();
+// #endif

+ 117 - 0
libs/work.js

@@ -0,0 +1,117 @@
+import {getWorkConfig,getWorkAgentConfig} from "@/api/work.js"
+// import {wx} from "@/utils/agent.js"
+export function initWxConfig() {
+    return getTicket;
+}
+
+export function initAgentConfig() {
+    return agentConfig;
+};
+
+
+    
+const getTicket = new Promise((resolve, reject) => {
+	getWorkConfig(location.href).then(res=>{
+		if (/(iPhone|iPad|iPod|iOS|macintosh|mac os x)/i.test(navigator.userAgent)) {
+			wx.config({
+				beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题
+				debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
+				appId: res.data.appId, // 必填,企业微信的corpID
+				timestamp:res.data.timestamp , // 必填,生成签名的时间戳
+				nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
+				signature: res.data.signature,// 必填,签名,见 附录-JS-SDK使用权限签名算法
+				jsApiList: res.data.jsApiList // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
+			});
+			wx.ready(function() {
+				// resolve(wx);
+				setTimeout(()=>{
+					getWorkAgentConfig(location.href).then(response=>{
+						wx.agentConfig({
+						    corpid: response.data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
+						    agentid: response.data.agentid, // 必填,企业微信的应用id (e.g. 1000247)
+						    timestamp: response.data.timestamp, // 必填,生成签名的时间戳
+						    nonceStr: response.data.nonceStr, // 必填,生成签名的随机串
+						    signature: response.data.signature,// 必填,签名,见附录-JS-SDK使用权限签名算法
+						    // jsApiList: response.data.jsApiList, //必填,传入需要使用的接口名称
+						   jsApiList: ["getCurExternalContact", "getCurExternalChat", "getContext", "chooseImage","sendChatMessage","shareAppMessage"],
+							success: function(data) {
+						        resolve(data);
+						    },
+						    fail: function(err) {
+						        if(err.errMsg.indexOf('function not exist') > -1){
+									reject('版本过低请升级');
+						        }
+						    }
+						});
+					})
+				},1000)
+			})
+		}else{
+			// window.wx = window.jWeixin;
+			jWeixin.config({
+				beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题
+				debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
+				appId: res.data.appId, // 必填,企业微信的corpID
+				timestamp:res.data.timestamp , // 必填,生成签名的时间戳
+				nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
+				signature: res.data.signature,// 必填,签名,见 附录-JS-SDK使用权限签名算法
+				jsApiList: ["getCurExternalContact", "getCurExternalChat", "getContext", "chooseImage","sendChatMessage","shareAppMessage"] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
+			});
+			jWeixin.ready(function() {
+				// resolve(wx);
+				getWorkAgentConfig(location.href).then(response=>{
+					jWeixin.agentConfig({
+						corpid: response.data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
+						agentid: response.data.agentid, // 必填,企业微信的应用id (e.g. 1000247)
+						timestamp: response.data.timestamp, // 必填,生成签名的时间戳
+						nonceStr: response.data.nonceStr, // 必填,生成签名的随机串
+						signature: response.data.signature,// 必填,签名,见附录-JS-SDK使用权限签名算法
+						// jsApiList: response.data.jsApiList, //必填,传入需要使用的接口名称
+             jsApiList: ["getCurExternalContact", "getCurExternalChat", "getContext", "chooseImage","sendChatMessage","shareAppMessage"],
+						success: function(data) {
+							resolve(data);
+						},
+						fail: function(err) {
+							if(err.errMsg.indexOf('function not exist') > -1){
+								reject('版本过低请升级');
+							}
+						}
+					});
+				})
+			})
+		}
+		
+	}).catch(err=>{
+		reject(err);
+	})
+})
+
+const agentConfig = new Promise((resolve, reject)=>{
+	getWorkAgentConfig(location.href).then(res=>{
+		wx.agentConfig({
+		    corpid: res.data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
+		    agentid: res.data.agentid, // 必填,企业微信的应用id (e.g. 1000247)
+		    timestamp: res.data.timestamp, // 必填,生成签名的时间戳
+		    nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
+		    signature: res.data.signature,// 必填,签名,见附录-JS-SDK使用权限签名算法
+		    jsApiList: ["getCurExternalContact", "getCurExternalChat", "getContext", "chooseImage","sendChatMessage","shareAppMessage"]
+, //必填,传入需要使用的接口名称
+			success: function(res) {
+		        resolve(res);
+		    },
+		    fail: function(res) {
+		        if(res.errMsg.indexOf('function not exist') > -1){
+					reject('版本过低请升级');
+		        }
+		    }
+		});
+	})
+})
+
+
+
+
+
+
+ 
+

+ 85 - 0
main.js

@@ -0,0 +1,85 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import Vue from 'vue'
+import App from './App'
+import store from './store'
+import Cache from './utils/cache'
+import util from 'utils/util'
+import configs from './config/app.js'
+import socket from './libs/new_chat.js'
+Vue.prototype.$util = util;
+Vue.prototype.$config = configs;
+Vue.prototype.$Cache = Cache;
+Vue.prototype.$eventHub = new Vue();
+Vue.prototype.$socket = new socket();
+Vue.config.productionTip = false
+import skeleton from './components/skeleton/index.vue'
+
+Vue.component('skeleton', skeleton)
+// #ifdef MP
+import authorize from './components/authorize/index.vue'
+Vue.component('authorize', authorize)
+// #endif
+// #ifdef H5
+
+
+import { parseQuery } from "./utils";
+import Auth from './libs/wechat';
+import { SPREAD } from './config/cache';
+Vue.prototype.$wechat = Auth;
+
+
+
+let cookieName = "VCONSOLE",
+	query = parseQuery(),
+	urlSpread = query["spread"],
+	vconsole = query[cookieName.toLowerCase()],
+	md5Crmeb = "b14d1e9baeced9bb7525ab19ee35f2d2", //CRMEB MD5 加密开启vconsole模式
+	md5UnCrmeb = "3dca2162c4e101b7656793a1af20295c"; //UN_CREMB MD5 加密关闭vconsole模式
+
+if (urlSpread !== undefined) {
+	var spread = Cache.get(SPREAD);
+	urlSpread = parseInt(urlSpread);
+	if (!Number.isNaN(urlSpread) && spread !== urlSpread) {
+		Cache.set("spread", urlSpread || 0);
+	} else if (spread === 0 || typeof spread !== "number") {
+		Cache.set("spread", urlSpread || 0);
+	}
+}
+
+if (vconsole !== undefined) {
+  if (vconsole === md5UnCrmeb && Cache.has(cookieName))
+	  Cache.clear(cookieName);
+} else vconsole = Cache.get(cookieName);
+
+import VConsole from './pages/extension/components/vconsole.min.js'
+
+if (vconsole !== undefined && vconsole === md5Crmeb) {
+	Cache.set(cookieName, md5Crmeb, 3600);
+	let vConsole = new VConsole();
+}
+
+// let snsapiBase = 'snsapi_base';
+// Auth.isWeixin() && Auth.oAuth(snsapiBase);
+
+
+//全局路由前置守卫
+// #endif
+
+App.mpType = 'app'
+
+
+const app = new Vue({
+    ...App,
+	store,
+	Cache,
+})
+app.$mount();

+ 237 - 0
manifest.json

@@ -0,0 +1,237 @@
+{
+    "name" : "易博优购",
+    "appid" : "__UNI__331F6F8",
+    "description" : "易博优购",
+    "versionName" : "2.1.1",
+    "versionCode" : 211,
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "compatible" : {
+            "ignoreVersion" : true
+        },
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {
+            "VideoPlayer" : {},
+            "OAuth" : {},
+            "Payment" : {},
+            "Maps" : {},
+            "LivePusher" : {},
+            "Geolocation" : {}
+        },
+        "safearea" : {
+            "bottom" : {
+                "offset" : "none"
+            }
+        },
+        /* 应用发布信息 */
+        "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.CAPTURE_AUDIO_OUTPUT\"/>",
+                    "<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.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_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_EXTERNAL_STORAGE\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ],
+                "abiFilters" : [ "armeabi-v7a" ],
+                "permissionExternalStorage" : {
+                    "request" : "none",
+                    "prompt" : "应用保存运行状态等信息,需要获取读写手机存储(系统提示为访问设备上的照片、媒体内容和文件)权限,请允许。"
+                },
+                "permissionPhoneState" : {
+                    "request" : "none",
+                    "prompt" : "为保证您正常、安全地使用,需要获取设备识别码(部分手机提示为获取手机号码)使用权限,请允许"
+                }
+            },
+            /* ios打包配置 */
+            "ios" : {
+                "capabilities" : {
+                    "entitlements" : {
+                        "com.apple.developer.associated-domains" : [ "applinks:pro.crmeb.net" ]
+                    }
+                },
+                "privacyDescription" : {
+                    "NSLocationWhenInUseUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSPhotoLibraryUsageDescription" : "上传用户头像保存分享海报",
+                    "NSPhotoLibraryAddUsageDescription" : "上传用户头像保存分享海报",
+                    "NSLocationAlwaysAndWhenInUseUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSLocationAlwaysUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSCameraUsageDescription" : "上传用户头像保存分享海报"
+                },
+                "idfa" : true,
+                "dSYMs" : false
+            },
+            /* SDK配置 */
+            "sdkConfigs" : {
+                "payment" : {
+                    "weixin" : {
+                        "__platform__" : [ "ios", "android" ],
+                        "appid" : "wxe86bd3a95cfa66c3",
+                        "UniversalLinks" : "https://pro.crmeb.net/uni-universallinks/__UNI__7E0054B/"
+                    },
+                    "alipay" : {
+                        "__platform__" : [ "ios", "android" ]
+                    }
+                },
+                "share" : {
+                    "weixin" : {
+                        "appid" : "wx69a5bfe28c8b39e6",
+                        "UniversalLinks" : "https://pro.crmeb.net/uni-universallinks/__UNI__7E0054B/"
+                    }
+                },
+                "push" : {},
+                "maps" : {
+                    "amap" : {
+                        "appkey_ios" : "aeb768547b9d752891e37e1ca0a2b66d",
+                        "appkey_android" : "41ec5c3f4d110ce02a326210fe147be8"
+                    }
+                },
+                "oauth" : {
+                    "weixin" : {
+                        "appid" : "wxe86bd3a95cfa66c3",
+                        "appsecret" : "",
+                        "UniversalLinks" : "https://pro.crmeb.net/uni-universallinks/__UNI__7E0054B/"
+                    },
+                    "apple" : {}
+                },
+                "ad" : {},
+                "geolocation" : {
+                    "amap" : {
+                        "__platform__" : [ "ios", "android" ],
+                        "appkey_ios" : "aeb768547b9d752891e37e1ca0a2b66d",
+                        "appkey_android" : "41ec5c3f4d110ce02a326210fe147be8"
+                    }
+                }
+            },
+            "splashscreen" : {
+                "androidStyle" : "common",
+                "useOriginalMsgbox" : true
+            },
+            "icons" : {
+                "android" : {
+                    "hdpi" : "unpackage/res/icons/72x72.png",
+                    "xhdpi" : "unpackage/res/icons/96x96.png",
+                    "xxhdpi" : "unpackage/res/icons/144x144.png",
+                    "xxxhdpi" : "unpackage/res/icons/192x192.png"
+                },
+                "ios" : {
+                    "appstore" : "unpackage/res/icons/1024x1024.png",
+                    "ipad" : {
+                        "app" : "unpackage/res/icons/76x76.png",
+                        "app@2x" : "unpackage/res/icons/152x152.png",
+                        "notification" : "unpackage/res/icons/20x20.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "proapp@2x" : "unpackage/res/icons/167x167.png",
+                        "settings" : "unpackage/res/icons/29x29.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "spotlight" : "unpackage/res/icons/40x40.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png"
+                    },
+                    "iphone" : {
+                        "app@2x" : "unpackage/res/icons/120x120.png",
+                        "app@3x" : "unpackage/res/icons/180x180.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "notification@3x" : "unpackage/res/icons/60x60.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "settings@3x" : "unpackage/res/icons/87x87.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png",
+                        "spotlight@3x" : "unpackage/res/icons/120x120.png"
+                    }
+                }
+            }
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "wx58e0376b093df14a",
+        "setting" : {
+            "urlCheck" : false,
+            "minified" : false,
+            "postcss" : true,
+            "es6" : true
+        },
+        "permission" : {
+            "scope.userLocation" : {
+                "desc" : "你的位置信息将用于和门店的距离长度"
+            }
+        },
+        "requiredPrivateInfos" : [ "getLocation", "chooseLocation", "chooseAddress" ],
+        "usingComponents" : true,
+        "lazyCodeLoading" : "requiredComponents",
+        "optimization" : {
+            "subPackages" : true
+        }
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "h5" : {
+        "devServer" : {
+            "https" : false
+        },
+        "router" : {
+            "mode" : "history",
+            "base" : ""
+        },
+        "domain" : "",
+        "sdkConfigs" : {
+            "maps" : {
+                "qqmap" : {
+                    "key" : "SMJBZ-WCHK4-ZPZUA-DSIXI-XDDVQ-XWFX7"
+                }
+            }
+        },
+        "optimization" : {
+            "treeShaking" : {
+                "enable" : true
+            }
+        },
+        "async" : {
+            "timeout" : 200000
+        },
+        "title" : "加载中",
+        "template" : "index.html"
+    },
+    "plus" : {
+        "statusbar" : {
+            "immersed" : true
+        }
+    }
+}

+ 37 - 0
mixins/SendVerifyCode.js

@@ -0,0 +1,37 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+export default {
+  data() {
+    return {
+      disabled: false,
+      text: "获取验证码"
+    };
+  },
+  methods: {
+    sendCode() {
+      if (this.disabled) return;
+      this.disabled = true;
+      let n = 60;
+      this.text = "剩余 " + n + "s";
+      const run = setInterval(() => {
+        n = n - 1;
+        if (n < 0) {
+          clearInterval(run);
+        }
+        this.text = "剩余 " + n + "s";
+        if (this.text < "剩余 " + 0 + "s") {
+          this.disabled = false;
+          this.text = "重新获取";
+        }
+      }, 1000);
+    }
+  }
+};

+ 37 - 0
mixins/color.js

@@ -0,0 +1,37 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+export default {
+	data() {
+		return {
+			colorStyle: '',
+			navigation: 0,
+			colorNum: 0
+		};
+	},
+	created() {
+		this.colorStyle = uni.getStorageSync('viewColor')
+		uni.$on('ok', data => {
+			this.colorStyle = data
+		})
+		this.navigation = uni.getStorageSync('navigation')
+		uni.$on('navOk', data => {
+			this.navigation = data
+		})
+	},
+	methods: {
+		colorData(){
+			this.colorNum = uni.getStorageSync('statusColor')
+			uni.$on('colorOk', data => {
+				this.colorNum = data
+			})
+		}
+	}
+};

+ 399 - 0
package-lock.json

@@ -0,0 +1,399 @@
+{
+	"name": "H5",
+	"version": "1.1.41",
+	"lockfileVersion": 1,
+	"requires": true,
+	"dependencies": {
+		"ansi-regex": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+			"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+		},
+		"ansi-styles": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+			"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+		},
+		"babel-code-frame": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+			"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+			"requires": {
+				"chalk": "^1.1.3",
+				"esutils": "^2.0.2",
+				"js-tokens": "^3.0.2"
+			}
+		},
+		"babel-core": {
+			"version": "6.26.3",
+			"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
+			"integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
+			"requires": {
+				"babel-code-frame": "^6.26.0",
+				"babel-generator": "^6.26.0",
+				"babel-helpers": "^6.24.1",
+				"babel-messages": "^6.23.0",
+				"babel-register": "^6.26.0",
+				"babel-runtime": "^6.26.0",
+				"babel-template": "^6.26.0",
+				"babel-traverse": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"babylon": "^6.18.0",
+				"convert-source-map": "^1.5.1",
+				"debug": "^2.6.9",
+				"json5": "^0.5.1",
+				"lodash": "^4.17.4",
+				"minimatch": "^3.0.4",
+				"path-is-absolute": "^1.0.1",
+				"private": "^0.1.8",
+				"slash": "^1.0.0",
+				"source-map": "^0.5.7"
+			}
+		},
+		"babel-generator": {
+			"version": "6.26.1",
+			"resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
+			"integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+			"requires": {
+				"babel-messages": "^6.23.0",
+				"babel-runtime": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"detect-indent": "^4.0.0",
+				"jsesc": "^1.3.0",
+				"lodash": "^4.17.4",
+				"source-map": "^0.5.7",
+				"trim-right": "^1.0.1"
+			}
+		},
+		"babel-helpers": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+			"integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1"
+			}
+		},
+		"babel-messages": {
+			"version": "6.23.0",
+			"resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+			"integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-register": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+			"integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+			"requires": {
+				"babel-core": "^6.26.0",
+				"babel-runtime": "^6.26.0",
+				"core-js": "^2.5.0",
+				"home-or-tmp": "^2.0.0",
+				"lodash": "^4.17.4",
+				"mkdirp": "^0.5.1",
+				"source-map-support": "^0.4.15"
+			}
+		},
+		"babel-runtime": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+			"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+			"requires": {
+				"core-js": "^2.4.0",
+				"regenerator-runtime": "^0.11.0"
+			}
+		},
+		"babel-template": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+			"integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+			"requires": {
+				"babel-runtime": "^6.26.0",
+				"babel-traverse": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"babylon": "^6.18.0",
+				"lodash": "^4.17.4"
+			}
+		},
+		"babel-traverse": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+			"integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+			"requires": {
+				"babel-code-frame": "^6.26.0",
+				"babel-messages": "^6.23.0",
+				"babel-runtime": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"babylon": "^6.18.0",
+				"debug": "^2.6.8",
+				"globals": "^9.18.0",
+				"invariant": "^2.2.2",
+				"lodash": "^4.17.4"
+			}
+		},
+		"babel-types": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+			"integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+			"requires": {
+				"babel-runtime": "^6.26.0",
+				"esutils": "^2.0.2",
+				"lodash": "^4.17.4",
+				"to-fast-properties": "^1.0.3"
+			}
+		},
+		"babylon": {
+			"version": "6.18.0",
+			"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+			"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
+		},
+		"balanced-match": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+			"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+		},
+		"brace-expansion": {
+			"version": "1.1.11",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+			"requires": {
+				"balanced-match": "^1.0.0",
+				"concat-map": "0.0.1"
+			}
+		},
+		"chalk": {
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+			"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+			"requires": {
+				"ansi-styles": "^2.2.1",
+				"escape-string-regexp": "^1.0.2",
+				"has-ansi": "^2.0.0",
+				"strip-ansi": "^3.0.0",
+				"supports-color": "^2.0.0"
+			}
+		},
+		"concat-map": {
+			"version": "0.0.1",
+			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+			"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+		},
+		"convert-source-map": {
+			"version": "1.7.0",
+			"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+			"integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+			"requires": {
+				"safe-buffer": "~5.1.1"
+			}
+		},
+		"core-js": {
+			"version": "2.6.11",
+			"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
+			"integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg=="
+		},
+		"debug": {
+			"version": "2.6.9",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+			"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+			"requires": {
+				"ms": "2.0.0"
+			}
+		},
+		"detect-indent": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+			"integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+			"requires": {
+				"repeating": "^2.0.0"
+			}
+		},
+		"escape-string-regexp": {
+			"version": "1.0.5",
+			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+		},
+		"esutils": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+			"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
+		},
+		"globals": {
+			"version": "9.18.0",
+			"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+			"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
+		},
+		"has-ansi": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+			"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+			"requires": {
+				"ansi-regex": "^2.0.0"
+			}
+		},
+		"home-or-tmp": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+			"integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+			"requires": {
+				"os-homedir": "^1.0.0",
+				"os-tmpdir": "^1.0.1"
+			}
+		},
+		"invariant": {
+			"version": "2.2.4",
+			"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+			"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+			"requires": {
+				"loose-envify": "^1.0.0"
+			}
+		},
+		"is-finite": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
+			"integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w=="
+		},
+		"js-tokens": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+			"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
+		},
+		"jsesc": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+			"integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s="
+		},
+		"json5": {
+			"version": "0.5.1",
+			"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+			"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
+		},
+		"lodash": {
+			"version": "4.17.15",
+			"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+			"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+		},
+		"loose-envify": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+			"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+			"requires": {
+				"js-tokens": "^3.0.0 || ^4.0.0"
+			}
+		},
+		"minimatch": {
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+			"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+			"requires": {
+				"brace-expansion": "^1.1.7"
+			}
+		},
+		"minimist": {
+			"version": "1.2.5",
+			"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+			"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+		},
+		"mkdirp": {
+			"version": "0.5.5",
+			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+			"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+			"requires": {
+				"minimist": "^1.2.5"
+			}
+		},
+		"ms": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+			"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+		},
+		"os-homedir": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+			"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+		},
+		"os-tmpdir": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+			"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+		},
+		"path-is-absolute": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+			"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+		},
+		"private": {
+			"version": "0.1.8",
+			"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+			"integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
+		},
+		"regenerator-runtime": {
+			"version": "0.11.1",
+			"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+			"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+		},
+		"repeating": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+			"integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+			"requires": {
+				"is-finite": "^1.0.0"
+			}
+		},
+		"safe-buffer": {
+			"version": "5.1.2",
+			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+			"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+		},
+		"slash": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+			"integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
+		},
+		"source-map": {
+			"version": "0.5.7",
+			"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+			"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+		},
+		"source-map-support": {
+			"version": "0.4.18",
+			"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+			"integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+			"requires": {
+				"source-map": "^0.5.6"
+			}
+		},
+		"strip-ansi": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+			"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+			"requires": {
+				"ansi-regex": "^2.0.0"
+			}
+		},
+		"supports-color": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+			"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+		},
+		"to-fast-properties": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+			"integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
+		},
+		"trim-right": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+			"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="
+		},
+		"uni-luck-draw": {
+			"version": "1.3.2",
+			"resolved": "https://registry.npm.taobao.org/uni-luck-draw/download/uni-luck-draw-1.3.2.tgz",
+			"integrity": "sha1-X6Njgb6lF7ATHwyRYtl9ehWQz2c=",
+			"requires": {
+				"lucky-canvas": "^1.5.0"
+			}
+		}
+	}
+}

+ 1948 - 0
pages.json

@@ -0,0 +1,1948 @@
+{
+  "easycom": {
+    "^w-(.*)": "@/uni_modules/wmf-code/components/w-$1/index.vue" //二维码条形码的配置 如果是uni_modules
+  },
+  "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+    {
+      "path": "pages/guide/index",
+      "style": {
+        "app-plus": {
+          "titleNView": false //禁用原生导航栏
+        },
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/store_cate/store_cate",
+      "style": {
+        "navigationBarTitleText": "门店",
+        "navigationStyle": "custom",
+        "navigationBarTextStyle": "white"
+      }
+    },
+    {
+      "path": "pages/index/index",
+      "style": {
+        "navigationBarTitleText": "",
+        "navigationStyle": "custom",
+        "navigationBarTextStyle": "white"
+      }
+    },
+    {
+      "path": "pages/order_addcart/order_addcart",
+      "style": {
+        "navigationBarTitleText": "购物车",
+        "app-plus": {
+          // #ifdef APP-PLUS
+          "titleNView": {
+            "type": "default"
+          }
+          // #endif
+        }
+
+      }
+    },
+    {
+      "path": "pages/user/index",
+      "style": {
+
+        "navigationBarTitleText": "个人中心",
+        // #ifdef MP || APP-PLUS
+        "navigationStyle": "custom",
+        // "navigationBarBackgroundColor": "#e93323",
+        "navigationBarTextStyle": "black",
+        // #endif
+				// #ifdef MP
+				"disableScroll": true,
+				// #endif
+        "app-plus": {
+          // 将回弹属性关掉
+          "bounce": "none"
+        }
+      }
+    },
+    {
+      "path": "pages/goods_cate/goods_cate",
+      "style": {
+        "navigationBarTitleText": "商品分类",
+        // #ifdef MP || APP-PLUS
+        "navigationStyle": "custom",
+        // #endif
+        "app-plus": {
+          // #ifdef APP-PLUS
+          // "titleNView": {
+          // 	"type": "default"
+          // }
+          // #endif
+        }
+      }
+    }
+    //#ifdef H5
+    ,
+    {
+      "path": "pages/auth/index",
+      "style": {
+        "navigationBarTitleText": ""
+      }
+    }
+    //#endif
+  ],
+  // "plugins": {
+  // 	"live-player-plugin": {
+  // 		"version": "1.3.2",
+  // 		"provider": "wx2b03c6e691cd7370"
+  // 	}
+  // },
+  "subPackages": [{
+      "root": "pages/users",
+      "name": "users",
+      "pages": [{
+          "path": "user_vip_areer/index",
+          "style": {
+            "navigationBarTitleText": "经验记录",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "privacy/index",
+          "style": {
+            "navigationBarTitleText": "协议",
+          	// #ifdef MP || APP-PLUS
+          	"navigationStyle": "custom",
+          	// #endif
+            "app-plus": {
+              // #ifdef APP-PLUS
+              // "titleNView": {
+              //   "type": "default"
+              // }
+              // #endif
+            }
+          }
+        }, {
+          "path": "user_cancellation/index",
+          "style": {
+            "navigationBarTitleText": "注销说明",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "message_center/index",
+          "style": {
+            "navigationBarTitleText": "消息中心",
+            "enablePullDownRefresh": true,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "message_center/messageDetail",
+          "style": {
+            "navigationBarTitleText": "消息详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_invoice_order/index",
+          "style": {
+            "navigationBarTitleText": "订单详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "scan_login/index",
+          "style": {
+            "navigationBarTitleText": "授权登录"
+          }
+        },
+        {
+          "path": "user_invoice_list/index",
+          "style": {
+            "navigationBarTitleText": "发票管理",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_invoice_form/index",
+          "style": {
+            "navigationBarTitleText": "添加新发票",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        //#ifdef H5
+        {
+          "path": "alipay_invoke/index",
+          "style": {
+            "navigationBarTitleText": "支付提示"
+          }
+        },
+        //#endif
+        {
+          "path": "wechat_login/index",
+          "style": {
+            "navigationBarTitleText": "账户登录",
+            "navigationStyle": "custom",
+            "app-plus": {
+              "scrollIndicator": false //禁用原生导航栏
+            }
+          }
+        },
+        {
+          "path": "retrievePassword/index",
+          "style": {
+            "navigationBarTitleText": "忘记密码",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+				{
+				  "path": "user_set/index",
+				  "style": {
+				    "navigationBarTitleText": "设置",
+				    "app-plus": {
+				      // #ifdef APP-PLUS
+				      "titleNView": {
+				        "type": "default"
+				      }
+				      // #endif
+				    }
+				  }
+				},
+        {
+          "path": "user_info/index",
+          "style": {
+            "navigationBarTitleText": "个人资料",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_get_coupon/index",
+          "style": {
+            "navigationBarTitleText": "领取优惠券",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "visit_list/index",
+          "style": {
+            "navigationBarTitleText": "浏览记录",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_goods_collection/index",
+          "style": {
+            "navigationBarTitleText": "收藏商品",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_sgin/index",
+          "style": {
+            "navigationBarTitleText": "签到",
+            // #ifdef MP
+            // "navigationBarTextStyle": "white",
+            // "navigationBarBackgroundColor": "#e93323"
+            // #endif
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_sgin_list/index",
+          "style": {
+            "navigationBarTitleText": "签到记录",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_money/index",
+          "style": {
+            "navigationBarTitleText": "我的账户",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_bill/index",
+          "style": {
+            "navigationBarTitleText": "账单明细",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_integral/index",
+          "style": {
+            "navigationBarTitleText": "积分详情"
+
+              // #ifdef MP
+              ,
+            "navigationBarTextStyle": "black",
+            "navigationBarBackgroundColor": "#FFFFFF"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_coupon/index",
+          "style": {
+            "navigationBarTitleText": "我的优惠券",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_spread_user/index",
+          "style": {
+            "navigationBarTitleText": "我的推广"
+
+              // #ifdef MP
+              ,
+            "navigationBarTextStyle": "black",
+            "navigationBarBackgroundColor": "#FFFFFF"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_spread_code/index",
+          "style": {
+            "navigationBarTitleText": "分销海报",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_spread_money/index",
+          "style": {
+            "navigationBarTitleText": "佣金记录"
+
+              // #ifdef MP
+              ,
+            "navigationBarTextStyle": "black",
+            "navigationBarBackgroundColor": "#FFFFFF"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_cash/index",
+          "style": {
+            "navigationBarTitleText": "提现",
+            "navigationBarBackgroundColor": "#FFFFFF"
+              // #ifdef MP || APP-PLUS
+              ,
+            "navigationBarTextStyle": "black"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_vip/index",
+          "style": {
+            "navigationBarTitleText": "我的等级",
+            "navigationBarBackgroundColor": "#232323"
+              // #ifdef MP || APP-PLUS
+              ,
+            "navigationBarTextStyle": "white"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "user_distribution_level/index",
+          "style": {
+            "navigationBarTitleText": "分销等级",
+            "navigationBarBackgroundColor": "#232323"
+              // #ifdef MP || APP-PLUS
+              ,
+            "navigationBarTextStyle": "white"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_address_list/index",
+          "style": {
+            "navigationBarTitleText": "地址管理",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_address/index",
+          "style": {
+            "navigationBarTitleText": "添加地址",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_phone/index",
+          "style": {
+            "navigationBarTitleText": "绑定手机",
+
+            // #ifdef MP
+            // "navigationBarTextStyle": "white",
+            // "navigationBarBackgroundColor": "#e93323"
+            // #endif
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_payment/index",
+          "style": {
+            "navigationBarTitleText": "余额充值",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_pwd_edit/index",
+          "style": {
+            "navigationBarTitleText": "修改密码"
+
+              // #ifdef MP
+              // 	,
+              // "navigationBarTextStyle": "white"
+              // "navigationBarBackgroundColor": "#e93323"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "promoter-list/index",
+          "style": {
+            "navigationBarTitleText": "推广人列表"
+              // #ifdef MP
+              ,
+            "navigationBarBackgroundColor": "#FFFFFF",
+            "navigationBarTextStyle": "black"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "promoter-order/index",
+          "style": {
+            "navigationBarTitleText": "推广人订单"
+
+              // #ifdef MP
+              ,
+            "navigationBarTextStyle": "black",
+            "navigationBarBackgroundColor": "#FFFFFF"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "promoter_rank/index",
+          "style": {
+            "navigationBarTitleText": "推广人排行"
+
+              // #ifdef MP
+              ,
+            "navigationBarTextStyle": "black",
+            "navigationBarBackgroundColor": "#FFFFFF"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "commission_rank/index",
+          "style": {
+            "navigationBarTitleText": "佣金排行",
+            "navigationBarBackgroundColor": "#FFFFFF"
+              // #ifdef MP || APP-PLUS
+              ,
+            "navigationBarTextStyle": "black"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "user_return_list/index",
+          "style": {
+            "navigationBarTitleText": "退货列表",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "login/index",
+          "style": {
+            "navigationBarTitleText": "登录",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/short_video",
+      "name": "shortVideo",
+      "pages": [{
+        "enablePullDownRefresh": false,
+        //#ifdef APP
+        "path": "appSwiper/index",
+        //#endif	
+        //#ifndef APP
+        "path": "nvueSwiper/index",
+        //#endif
+        "style": {
+					"navigationBarTitleText": "短视频",
+          "app-plus": {
+            "titleNView": false,
+            "bounce": "none"
+          }
+        }
+
+      }
+		]
+    },
+    {
+      "root": "pages/goods_details",
+      "name": "goods_details",
+      "pages": [{
+          "path": "index",
+          "style": {
+            "navigationStyle": "custom"
+            // "app-plus": {
+            // 	// #ifdef APP-PLUS
+            // 	"titleNView": {
+            // 		"type": "default"
+            // 	}
+            // 	// #endif
+            // }
+          }
+        },
+        {
+          "path": "discountsGoodsList",
+          "style": {
+            "navigationBarTitleText": "套餐列表",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }
+      ]
+    },
+    // 门店分包
+    {
+      "root": "pages/store",
+      "name": "store",
+      "pages": [{
+          "path": "service/index",
+          "style": {
+            "navigationBarTitleText": "小米之家",
+						"app-plus": {
+						  // #ifdef APP-PLUS
+						  "titleNView": {
+						    "type": "default"
+						  }
+						  // #endif
+						}
+          }
+        }, {
+          "path": "search_stores/index",
+          "style": {
+            "navigationBarTitleText": "搜索列表",
+            "app-plus": {
+              "titleNView": {
+                "type": "搜索列表"
+              }
+            }
+          }
+        }, 
+				{
+          "path": "newcomers/index",
+					"style": {
+					  "navigationBarTitleText": "新人专享区",
+						"app-plus": {
+						  // #ifdef APP-PLUS
+						  "titleNView": {
+						    "type": "default"
+						  }
+						  // #endif
+						}
+					}
+        },
+				{
+				  "path": "ruleInfo/index",
+					"style": {
+					  "navigationBarTitleText": "活动规则",
+						"app-plus": {
+						  // #ifdef APP-PLUS
+						  "titleNView": {
+						    "type": "default"
+						  }
+						  // #endif
+						}
+					}
+				},
+        {
+          "path": "map/index",
+          "style": {
+            "navigationBarTitleText": "门店地图"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/activity",
+      "name": "activity",
+      "pages": [{
+          "path": "goods_bargain/index",
+          "style": {
+            // #ifdef MP
+            // "navigationBarTextStyle": "white",
+            // "navigationBarBackgroundColor": "#E93323",
+            "navigationBarTitleText": "砍价列表",
+            // #endif
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_bargain_details/index",
+          "style": {
+            "navigationStyle": "custom"
+              // #ifdef MP
+              ,
+            "navigationBarTextStyle": "white"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_combination/index",
+          "style": {
+            // #ifdef MP
+            // "navigationBarTextStyle": "white",
+            // "navigationBarBackgroundColor": "#E93323",
+            "navigationBarTitleText": "拼团活动",
+            // #endif
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_combination_details/index",
+          "style": {
+            "navigationStyle": "custom",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              // "titleNView": {
+              // 	"type": "default"
+              // }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_combination_status/index",
+          "style": {
+            "navigationBarTitleText": "拼团",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_seckill/index",
+          "style": {
+            "navigationBarTitleText": "限时秒杀"
+              // #ifdef MP
+              // "navigationBarTextStyle": "white"
+              // "navigationBarBackgroundColor": "#e93323"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_seckill_details/index",
+          "style": {
+            "navigationStyle": "custom"
+              // #ifdef MP
+              ,
+            "navigationBarTextStyle": "white"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              // "titleNView": {
+              // 	"type": "default"
+              // }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "poster-poster/index",
+          "style": {
+            "navigationBarTitleText": "砍价海报"
+              // #ifdef MP
+              // "navigationBarTextStyle": "white"
+              // "navigationBarBackgroundColor": "#d22516"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "bargain/index",
+          "style": {
+            "navigationBarTitleText": "砍价记录",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "presell/index",
+          "style": {
+            "navigationBarTitleText": "预售列表",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "discount/index",
+          "style": {
+            "navigationBarTitleText": "优惠活动",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/admin",
+      "name": "adminOrder",
+      "pages": [{
+          "path": "custom_date/index",
+          "style": {
+            "navigationBarTitleText": "选择日期"
+          }
+        },
+        {
+          "path": "order/index",
+          "style": {
+            "navigationBarTitleText": "订单统计",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "orderList/index",
+          "style": {
+            "navigationBarTitleText": "订单列表",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "orderDetail/index",
+          "style": {
+            "navigationBarTitleText": "订单详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "delivery/index",
+          "style": {
+            "navigationBarTitleText": "订单发货",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "statistics/index",
+          "style": {
+            "navigationBarTitleText": "订单数据统计",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "order_cancellation/index",
+          "style": {
+            "navigationBarTitleText": "订单核销",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "store/index",
+          "style": {
+            "navigationBarTextStyle": "white",
+            "navigationBarBackgroundColor": "#333333",
+            "navigationBarTitleText": "门店中心",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "store/custom_date/index",
+          "style": {
+            "navigationBarTitleText": "选择日期"
+          }
+        },
+        {
+          "path": "store/statistics/index",
+          "style": {
+            "navigationBarTitleText": "数据详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "store/orderDetail/index",
+          "style": {
+            "navigationBarTitleText": "订单详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "store/order/index",
+          "style": {
+            "navigationBarTitleText": "订单管理",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "store/deliverGoods/index",
+          "style": {
+            "navigationBarTitleText": "订单发货",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "distribution/index",
+          "style": {
+            "navigationBarTextStyle": "white",
+            "navigationBarBackgroundColor": "#333333",
+            "navigationBarTitleText": "配送员",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "distribution/scanning/index",
+          "style": {
+            "navigationBarTitleText": "扫描结果",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "distribution/scanning/detail/index",
+          "style": {
+            "navigationBarTitleText": "扫描结果详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "distribution/orderDetail/index",
+          "style": {
+            "navigationBarTitleText": "配送员订单详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "store/scanning/index",
+          "style": {
+            "navigationBarTitleText": "扫描结果",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "store/scanning/detail/index",
+          "style": {
+            "navigationBarTitleText": "扫描结果详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/columnGoods",
+      "name": "columnGoods",
+      "pages": [{
+          "path": "HotNewGoods/index",
+          "style": {
+            "navigationBarTitleText": "精品推荐",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "live_list/index",
+          "style": {
+            "navigationBarTitleText": "推荐好货"
+          }
+        },
+        {
+          "path": "HotNewGoods/feedback",
+          "style": {
+            "navigationBarTitleText": "我的客服",
+            "navigationBarTextStyle": "white",
+            "navigationBarBackgroundColor": "#3A3A3A",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/annex",
+      "pages": [{
+          "path": "web_view/index",
+          "style": {
+            "navigationBarTitleText": "",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "vip_paid/index",
+          "style": {
+            "navigationBarTitleText": "SVIP会员",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+				{
+				  "path": "vip_grade/index",
+				  "style": {
+				    "navigationBarTitleText": "会员中心",
+						"navigationBarTextStyle": "white",
+						"navigationBarBackgroundColor": "#302F35",
+				    "app-plus": {
+				      // #ifdef APP-PLUS
+				      "titleNView": {
+				        "type": "default"
+				      }
+				      // #endif
+				    }
+				  }
+				},
+				{
+				  "path": "record_list/index",
+				  "style": {
+				    "navigationBarTitleText": "消费记录",
+				    "app-plus": {
+				      // #ifdef APP-PLUS
+				      "titleNView": {
+				        "type": "default"
+				      }
+				      // #endif
+				    }
+				  }
+				},
+				{
+				  "path": "vip_grade_active/index",
+				  "style": {
+				    "navigationBarTitleText": "会员卡激活",
+				    "app-plus": {
+				      // #ifdef APP-PLUS
+				      "titleNView": {
+				        "type": "default"
+				      }
+				      // #endif
+				    }
+				  }
+				},
+        {
+          "path": "vip_coupon/index",
+          "style": {
+            "navigationBarTitleText": "会员优惠券",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "vip_clause/index",
+          "style": {
+            "navigationBarTitleText": "会员协议",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "vip_active/index",
+          "style": {
+            "navigationBarTitleText": "激活会员",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "offline_pay/index",
+          "style": {
+            "navigationBarTitleText": "支付",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "offline_result/index",
+          "style": {
+            "navigationBarTitleText": "支付结果",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "special/index",
+          "style": {
+            "navigationBarTitleText": "专题页",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/points_mall",
+      "pages": [{
+          "path": "index",
+          "style": {
+            "navigationBarTextStyle": "white",
+            "navigationBarBackgroundColor": "#333333",
+            "navigationBarTitleText": "积分商城",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "integral_goods_list",
+          "style": {
+            "navigationBarTitleText": "商品列表",
+            // "navigationBarTextStyle": "white",
+            // "navigationBarBackgroundColor": "#E93323",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "integral_goods_details",
+          "style": {
+            "navigationBarTitleText": "商品详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "exchange_record",
+          "style": {
+            "navigationBarTitleText": "兑换记录",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "integral_order",
+          "style": {
+            "navigationBarTitleText": "积分订单",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "user_address",
+          "style": {
+            "navigationBarTitleText": "选择地址",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "integral_order_status",
+          "style": {
+            "navigationBarTitleText": "兑换成功",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "integral_order_details",
+          "style": {
+            "navigationBarTitleText": "兑换订单详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "logistics_details",
+          "style": {
+            "navigationBarTitleText": "兑换物流详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/extension",
+      "name": "extension",
+      "pages": [{
+          "path": "invite_friend/index",
+          "style": {
+            "navigationBarTitleText": "邀请好友",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "customer_list/chat",
+          "style": {
+            "navigationBarTitleText": "对话详情",
+            "navigationStyle": "custom",
+            "app-plus": {
+              "scrollIndicator": false //禁用原生导航栏
+                // #ifdef APP-PLUS
+                ,
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            },
+            "disableScroll": true
+          }
+        },
+        {
+          "path": "news_list/index",
+          "style": {
+            "navigationBarTitleText": "资讯",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "news_details/index",
+          "style": {
+            "navigationBarTitleText": "资讯详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/work",
+      "name": "work",
+      "pages": [{
+          "path": "userInfo/index",
+          "style": {
+            "navigationBarTitleText": "客户信息"
+          }
+        },
+        {
+          "path": "orderList/index",
+          "style": {
+            "navigationBarTitleText": "交易管理"
+          }
+        },
+        {
+          "path": "orderDetail/index",
+          "style": {
+            "navigationBarTitleText": "订单详情"
+          }
+        },
+        {
+          "path": "record/index",
+          "style": {
+            "navigationBarTitleText": "记录"
+          }
+        },
+        {
+          "path": "groupInfo/index",
+          "style": {
+            "navigationBarTitleText": ""
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/goods",
+      "name": "goods",
+      "pages": [{
+          "path": "goods_list/index",
+          "style": {
+            "navigationBarTitleText": "商品列表",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_search/index",
+          "style": {
+            "navigationBarTitleText": "搜索商品",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "order_pay_status/index",
+          "style": {
+            "navigationBarTitleText": "支付成功",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }, {
+          "path": "order_pay_status/payLottery",
+          "style": {
+            "navigationBarTitleText": "支付成功",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_comment_list/index",
+          "style": {
+            "navigationBarTitleText": "商品评分",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_comment_con/index",
+          "style": {
+            "navigationBarTitleText": "商品评价",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_comment_con/comment_con",
+          "style": {
+            "navigationBarTitleText": "评价详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_comment_con/lottery_comment",
+          "style": {
+            "navigationBarTitleText": "订单评价",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_logistics/index",
+          "style": {
+            "navigationBarTitleText": "物流信息",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+				{
+				  "path": "delivery_detail/index",
+				  "style": {
+				    "navigationBarTitleText": "配送信息",
+				    "app-plus": {
+				      // #ifdef APP-PLUS
+				      "titleNView": {
+				        "type": "default"
+				      }
+				      // #endif
+				    }
+				  }
+				},
+        {
+          "path": "goods_details_store/index",
+          "style": {
+            "navigationBarTitleText": "门店列表",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_return_list/index",
+          "style": {
+            "navigationBarTitleText": "退货列表",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "goods_return/index",
+          "style": {
+            "navigationBarTitleText": "申请退货",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "order_details/index",
+          "style": {
+            "navigationBarTitleText": "订单详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "order_list/index",
+          "style": {
+            "navigationBarTitleText": "我的订单",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "order_pay/index",
+          "style": {
+            "navigationBarTitleText": "订单支付",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "order_refund_goods/index",
+          "style": {
+            "navigationBarTitleText": "退回商品",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "admin_order_detail/index",
+          "style": {
+            "navigationBarTitleText": "订单详情",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "order_confirm/index",
+          "style": {
+            "navigationBarTitleText": "提交订单",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "lottery/grids/index",
+          "style": {
+            "navigationBarTitleText": "抽奖活动",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
+        {
+          "path": "lottery/grids/record",
+          "style": {
+            "navigationBarTitleText": "中奖记录",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        }
+      ]
+    }
+  ],
+  "tabBar": {
+    "color": "#282828",
+    "selectedColor": "#ff3366",
+    "borderStyle": "black",
+    "backgroundColor": "#ffffff",
+    "list": [{
+        "pagePath": "pages/index/index",
+        "iconPath": "static/images/1-001.png",
+        "selectedIconPath": "static/images/1-002.png",
+        "text": "首页"
+      },
+      {
+        "pagePath": "pages/goods_cate/goods_cate",
+        "iconPath": "static/images/2-001.png",
+        "selectedIconPath": "static/images/2-002.png",
+        "text": "分类"
+      },
+      {
+        "pagePath": "pages/store_cate/store_cate",
+        "iconPath": "static/images/5-001.png",
+        "selectedIconPath": "static/images/5-002.png",
+        "text": "门店"
+      },
+      {
+        "pagePath": "pages/order_addcart/order_addcart",
+        "iconPath": "static/images/3-001.png",
+        "selectedIconPath": "static/images/3-002.png",
+        "text": "购物车"
+      },
+      {
+        "pagePath": "pages/user/index",
+        "iconPath": "static/images/4-001.png",
+        "selectedIconPath": "static/images/4-002.png",
+        "text": "我的"
+      }
+    ]
+  },
+  "globalStyle": {
+    "navigationBarTextStyle": "black",
+    "navigationBarTitleText": "加载中",
+    "navigationBarBackgroundColor": "#fff",
+    "backgroundColor": "#F8F8F8",
+    "titleNView": false
+  },
+  "condition": { //模式配置,仅开发期间生效
+    "current": 0, //当前激活的模式(list 的索引项)
+    "list": [{
+      "name": "", //模式名称
+      "path": "", //启动页面,必选
+      "query": "" //启动参数,在页面的onLoad函数里面得到
+    }]
+  }
+}

+ 261 - 0
pages/activity/bargain/index.vue

@@ -0,0 +1,261 @@
+<template>
+	<view :style="colorStyle">
+		<block v-if="bargain.length>0">
+			<div class="bargain-record" ref="container">
+				<div class="item" v-for="(item, index) in bargain" :key="index">
+					<div class="picTxt acea-row row-between-wrapper">
+						<div class="pictrue">
+							<image :src="item.image" />
+						</div>
+						<div class="text acea-row row-column-around">
+							<div class="line1" style="width: 100%;">{{ item.title }}</div>
+							<count-down :justify-left="'justify-content:left'" :is-day="true" :tip-text="'倒计时 '"
+								:day-text="' 天 '" :hour-text="' 时 '" :minute-text="' 分 '" :second-text="' 秒'"
+								:datatime="item.datatime" v-if="item.status === 1"></count-down>
+							<div class="successTxt font-num" v-else-if="item.status === 3">砍价成功</div>
+							<div class="endTxt" v-else>活动已结束</div>
+							<div class="money font-num">
+								已砍至<span class="symbol">¥</span><span class="num">{{ item.residue_price }}</span>
+							</div>
+						</div>
+					</div>
+					<div class="bottom acea-row row-between-wrapper">
+						<div class="purple" v-if="item.status === 1">活动进行中</div>
+						<div class="success" v-else-if="item.status === 3">砍价成功</div>
+						<div class="end" v-else>活动已结束</div>
+						<div class="acea-row row-middle row-right">
+							<div class="bnt cancel" v-if="item.status === 1"
+								@click="getBargainUserCancel(item.bargain_id)">
+								取消活动
+							</div>
+							<div class="bnt bg-color-red" v-if="item.status === 1" @click="goDetail(item.bargain_id)">
+								继续砍价
+							</div>
+							<!-- <div class="bnt bg-color-red" v-else @click="goList">重开一个</div> -->
+						</div>
+					</div>
+				</div>
+				<Loading :loaded="status" :loading="loadingList"></Loading>
+			</div>
+		</block>
+		<block v-if="bargain.length == 0">
+			<emptyPage title="暂无砍价记录~"></emptyPage>
+		</block>
+		<home v-if="navigation"></home>
+	</view>
+</template>
+<script>
+	import CountDown from "@/components/countDown";
+	import emptyPage from '@/components/emptyPage.vue'
+	import {
+		getBargainUserList,
+		getBargainUserCancel
+	} from "@/api/activity";
+	import {
+		getUserInfo
+	} from '@/api/user.js';
+	import Loading from "@/components/Loading";
+	import home from '@/components/home';
+	import colors from "@/mixins/color";
+	export default {
+		name: "BargainRecord",
+		components: {
+			CountDown,
+			Loading,
+			emptyPage,
+			home
+		},
+		props: {},
+		mixins: [colors],
+		data: function() {
+			return {
+				bargain: [],
+				status: false, //砍价列表是否获取完成 false 未完成 true 完成
+				loadingList: false, //当前接口是否请求完成 false 完成 true 未完成
+				page: 1, //页码
+				limit: 20, //数量
+				userInfo: {}
+			};
+		},
+		onLoad: function() {
+			this.getBargainUserList();
+			this.getUserInfo();
+		},
+		onShow(){
+			uni.removeStorageSync('form_type_cart');
+		},
+		methods: {
+			goDetail: function(id) {
+				uni.navigateTo({
+					url: `/pages/activity/goods_bargain_details/index?id=${id}&bargain=${this.userInfo.uid}`
+				})
+			},
+			// 砍价列表
+			goList: function() {
+				uni.navigateTo({
+					url: '/pages/activity/goods_bargain/index'
+				})
+			},
+			getBargainUserList: function() {
+				var that = this;
+				if (that.loadingList) return;
+				if (that.status) return;
+				getBargainUserList({
+						page: that.page,
+						limit: that.limit
+					})
+					.then(res => {
+						that.status = res.data.length < that.limit;
+						that.bargain.push.apply(that.bargain, res.data);
+						that.page++;
+						that.loadingList = false;
+					})
+					.catch(res => {
+						that.$util.Tips({
+							title: res
+						})
+					});
+			},
+			getBargainUserCancel: function(bargainId) {
+				var that = this;
+				getBargainUserCancel({
+						bargainId: bargainId
+					})
+					.then(res => {
+						that.status = false;
+						that.loadingList = false;
+						that.page = 1;
+						that.bargain = [];
+						that.getBargainUserList();
+						that.$util.Tips({
+							title: res.msg
+						})
+					})
+					.catch(res => {
+						that.$util.Tips({
+							title: res
+						})
+					});
+			},
+			/**
+			 * 获取个人用户信息
+			 */
+			getUserInfo: function() {
+				let that = this;
+				getUserInfo().then(res => {
+					that.userInfo = res.data;
+				});
+			},
+		},
+		onReachBottom() {
+			this.getBargainUserList();
+		}
+	};
+</script>
+
+<style lang="scss">
+	/*砍价记录*/
+	.bargain-record .item .picTxt .text .time .styleAll {
+		color: #fc4141;
+		font-size: 24rpx;
+	}
+
+	.bargain-record .item .picTxt .text .time .red {
+		color: #999;
+		font-size: 24rpx;
+	}
+
+	.bargain-record .item {
+		background-color: #fff;
+		margin-bottom: 12upx;
+	}
+
+	.bargain-record .item .picTxt {
+		height: 210upx;
+		border-bottom: 1px solid #f0f0f0;
+		padding: 0 30upx;
+	}
+
+	.bargain-record .item .picTxt .pictrue {
+		width: 150upx;
+		height: 150upx;
+	}
+
+	.bargain-record .item .picTxt .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 6upx;
+	}
+
+	.bargain-record .item .picTxt .text {
+		width: 515upx;
+		font-size: 30upx;
+		color: #282828;
+		height: 150upx;
+	}
+
+	.bargain-record .item .picTxt .text .time {
+		font-size: 24upx;
+		color: #868686;
+		justify-content: left !important;
+	}
+
+	.bargain-record .item .picTxt .text .successTxt {
+		font-size: 24rpx;
+	}
+
+	.bargain-record .item .picTxt .text .endTxt {
+		font-size: 24rpx;
+		color: #999;
+	}
+
+	.bargain-record .item .picTxt .text .money {
+		font-size: 24upx;
+	}
+
+	.bargain-record .item .picTxt .text .money .num {
+		font-size: 32upx;
+		font-weight: bold;
+	}
+
+	.bargain-record .item .picTxt .text .money .symbol {
+		font-weight: bold;
+	}
+
+	.bargain-record .item .bottom {
+		height: 100upx;
+		padding: 0 30upx;
+		font-size: 27upx;
+	}
+
+	.bargain-record .item .bottom .purple {
+		color: #f78513;
+	}
+
+	.bargain-record .item .bottom .end {
+		color: #999;
+	}
+
+	.bargain-record .item .bottom .success {
+		color: #e93323;
+	}
+
+	.bargain-record .item .bottom .bnt {
+		font-size: 27upx;
+		color: #fff;
+		width: 176upx;
+		height: 60upx;
+		border-radius: 32upx;
+		text-align: center;
+		line-height: 60upx;
+	}
+
+	.bargain-record .item .bottom .bnt.cancel {
+		color: #aaa;
+		border: 1px solid #ddd;
+	}
+
+	.bargain-record .item .bottom .bnt~.bnt {
+		margin-left: 18upx;
+	}
+</style>

+ 184 - 0
pages/activity/components/giftGoods/index.vue

@@ -0,0 +1,184 @@
+<template>
+	<!-- 赠送商品、积分下拉列表 -->
+	<view>
+		<view class="gift" :class="giftInfo.show === true ? 'on' : ''">
+			<view class="title">查看赠品<text class="iconfont icon-guanbi5" @click="closeGift"></text></view>
+			<view class="list">
+				<view class="item acea-row row-between-wrapper" v-for="(item,index) in giftInfo.giveProducts" :key="item.id">
+					<view class="pictrue">
+						<image :src="item.image"></image>
+					</view>
+					<view class="text">
+						<view class="name line1">{{item.store_name}}</view>
+						<view class="info line1">{{item.suk}}</view>
+						<view class="info line1">{{item.threshold_title}}</view>
+						<view class="bottom acea-row row-between-wrapper">
+							<view class="money">¥<text class="num">{{item.price}}</text></view>
+							<view class="limit">x{{item.limit_num}}</view>
+						</view>
+						<!-- #ifdef H5 || APP-PLUS -->
+						<slot name="bottom" :item="item"></slot>
+						<!-- #endif -->
+						<!-- #ifdef MP -->
+						<slot name="bottom{{index}}"></slot>
+						<!-- #endif -->
+					</view>
+				</view>
+				<view class="item acea-row row-between-wrapper" v-for="(item,index) in giftInfo.giveCoupon" :key="item.id">
+					<view class="pictrue on acea-row row-center-wrapper">
+						<view class="iconfont icon-youhuiquan2"></view>
+					</view>
+					<view class="text">
+						<view class="name acea-row row-middle">
+							<view class="lable">{{item.coupon_type==1?'品类券':item.coupon_type==2?'商品券':'通用券'}}</view>
+							<view class="names line1">{{item.coupon_title}}</view>
+						</view>
+						<view class="info">{{item.threshold_title}}</view>
+						<view class="bottom on acea-row row-between-wrapper">
+							<view class="money"><text v-if="item.coupon_type==1">¥</text><text class="num">{{item.coupon_type==1?item.coupon_price:parseFloat(item.coupon_price)/10}}</text><text v-if="item.coupon_type==2">折</text></view>
+							<view class="limit">x{{item.limit_num}}</view>
+						</view>
+					</view>
+				</view>
+				<view class="item item acea-row row-between-wrapper" v-for="(item,index) in giftInfo.giveIntegral" :key="item.id">
+					<view class="pictrue ons acea-row row-center-wrapper">
+						<view class="iconfont icon-jifen"></view>
+					</view>
+					<view class="text">
+						<view class="name line1">赠送积分</view>
+						<view class="info">{{item.threshold_title}}</view>
+						<view class="bottom on acea-row row-between-wrapper">
+							<view class="money"><text class="num">{{item.give_integral}}</text>积分</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="mask" @touchmove.prevent :hidden="giftInfo.show === false" @click="closeGift"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			giftInfo: {
+				type: Object,
+				default: () => {}
+			},
+		},
+		data() {
+			return {};
+		},
+		mounted() {},
+		methods: {
+			closeGift(){
+				this.$emit('myevent');
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.gift{
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		background-color: #fff;
+		z-index: 280;
+		border-radius: 16rpx 16rpx 0 0;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		padding-bottom: 22rpx;
+		padding-bottom: calc(22rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(22rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		.title{
+			font-size: 32rpx;
+			color: #282828;
+			text-align: center;
+			margin: 38rpx 0 36rpx 0;
+			position: relative;
+			.iconfont{
+				position: absolute;
+				right: 30rpx;
+				top:0;
+				font-size: 36rpx;
+			}
+		}
+		.list{
+			height: 750rpx;
+			margin: 0 30rpx;
+			overflow-x: hidden;
+			overflow-y: auto;
+			.item{
+				margin-bottom: 52rpx;
+				.pictrue{
+					width: 150rpx;
+					height: 150rpx;
+					border-radius: 10rpx;
+					&.on{
+						background-color: var(--view-minorColorT);
+					}
+					&.ons{
+						background-color: rgba(254, 150, 15, 0.1);
+						.iconfont{
+							color: #FE960F!important;
+						}
+					}
+					.iconfont{
+						font-size: 75rpx;
+						color: var(--view-theme);
+					}
+					image{
+						width: 100%;
+						height: 100%;
+						border-radius: 10rpx;
+					}
+				}
+				.text{
+					width: 520rpx;
+					color: #999999;
+					font-size: 28rpx;
+					.name{
+						color: #333333;
+						.lable{
+							font-size: 18rpx;
+							color: var(--view-theme);
+							border:1rpx solid var(--view-theme);
+							background-color: var(--view-minorColorT);
+							border-radius: 18rpx;
+							padding: 1rpx 6rpx;
+							margin-right: 8rpx;
+						}
+						.names{
+							width: 420rpx;
+						}
+					}
+					.info{
+						font-size: 24rpx;
+						margin-top: 6rpx;
+					}
+					.money{
+						color: var(--view-theme);
+						font-size: 24rpx;
+						.num{
+							font-size: 36rpx;
+						}
+					}
+					.bottom{
+						margin-top: 8rpx;
+						&.on{
+							margin-top: 32rpx;
+						}
+					}
+					.limit{
+						font-size: 24rpx;
+					}
+				}
+			}
+		}
+	}
+	.gift.on{
+		transform: translate3d(0, 0, 0);
+	}
+</style>

+ 323 - 0
pages/activity/discount/index.vue

@@ -0,0 +1,323 @@
+<template>
+	<view :style="colorStyle" class="discount">
+		<view class="header">
+			<text v-if="type == 1">限时折扣</text>
+			<text v-if="type == 4">满送活动</text>
+			<text v-if="type == 3">满减满折</text>
+			<text v-if="type == 2">第N件N折</text>
+		</view>
+		<view class="list">
+			<view class="item acea-row row-between-wrapper" v-for="(item,index) in list" :key="index"
+				@click="goDetails(item)">
+				<view class="pictrue">
+					<image :src="item.image"></image>
+				</view>
+				<view class="text">
+					<view class="conter">
+						<view class="name line2">{{item.store_name}}</view>
+						<view class="info acea-row row-between" v-if="type == 4" @click.stop="giftGoods(item)">
+							<view class="desc line2">{{item.promotions.desc}}</view>
+							<view class="iconfont icon-you"></view>
+						</view>
+					</view>
+					<view class="bnt acea-row row-between-wrapper" v-if="type != 4">
+						<view class="left">
+							<view class="title">
+								<!-- <view class="iconfont icon-xianshi"></view> -->
+								<view class="time" v-if="type == 1">限时:</view>
+								<countDown v-if="type == 1" class="time mt" :tip-text="' '"
+									:datatime="item.promotions.stop_time"></countDown>
+								<view class="time" v-if="type == 2">{{item.promotions.title}}</view>
+								<view class="time" v-if="type == 3">
+									{{item.promotions.promotions.length==1?'最高':''}}
+									{{item.promotions.promotions[0].discount_type==1?'可减'+item.promotions.promotions[0].discount:'可打'+parseFloat(item.promotions.promotions[0].discount)/10}}
+									{{item.promotions.promotions[0].discount_type==1?'元':'折'}}
+								</view>
+							</view>
+							<view class="money"><text class="label">¥</text><text class="num">{{item.price}}</text><text
+									class="y_money">¥{{item.ot_price}}</text></view>
+						</view>
+						<view class="right acea-row row-center-wrapper">立即抢购</view>
+					</view>
+					<view class="bntCon acea-row row-between-wrapper" v-else>
+						<view class="money">
+							<text class="label">¥</text>
+							<text class="num">{{item.price}}</text>
+							<text class="y_money">{{item.ot_price}}</text>
+						</view>
+						<view class="right acea-row row-center-wrapper">立即抢购</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class='loadingicon acea-row row-center-wrapper' v-if="list.length">
+			<text class='loading iconfont icon-jiazai' :hidden='loading==false'></text>{{loadTitle}}
+		</view>
+		<giftGoods :giftInfo="giftInfo" @myevent="myGift"></giftGoods>
+		<home v-if="navigation"></home>
+	</view>
+</template>
+
+<script>
+	import {
+		mapGetters
+	} from "vuex";
+	import {
+		promotionsList,
+		giveInfo
+	} from '@/api/activity.js';
+	import home from '@/components/home';
+	import colors from "@/mixins/color";
+	import countDown from '@/components/countDown';
+	import giftGoods from '../components/giftGoods/index.vue';
+	export default {
+		mixins: [colors],
+		data() {
+			return {
+				list: [],
+				loading: false,
+				loadend: false,
+				loadTitle: '加载更多', //提示语
+				page: 1,
+				limit: 10,
+				type: 0,
+				giftInfo:{
+					show:false,
+					giveCoupon:[],
+					giveIntegral:[],
+					giveProducts:[]
+				}
+			}
+		},
+		components: {
+			countDown,
+			giftGoods,
+			home
+		},
+		onLoad(option) {
+			this.type = option.promotions_type;
+			this.getList();
+		},
+		onShow(){
+			uni.removeStorageSync('form_type_cart');
+		},
+		onReachBottom: function() {
+			this.getList();
+		},
+		methods: {
+			giftGoods(item){
+				this.giftInfo.show = true;
+				giveInfo(item.promotions.id).then(res=>{
+					this.giftInfo.giveCoupon = res.data.giveCoupon;
+					this.giftInfo.giveProducts = res.data.giveProducts;
+					let giveIntegral = res.data.giveIntegral;
+					giveIntegral.forEach((item,index)=>{
+						item.id = index;
+					})
+					this.giftInfo.giveIntegral = giveIntegral;
+				}).catch(err=>{
+					return this.$util.Tips({
+						title: err
+					});
+				})
+			},
+			myGift(){
+				this.$set(this.giftInfo, 'show', false);
+			},
+			goDetails(item) {
+				uni.navigateTo({
+					url: `/pages/goods_details/index?id=${item.id}&promotions_type=${this.type}`
+				})
+			},
+			getList: function() {
+				let that = this
+				if (this.loadend) return false;
+				if (this.loading) return false;
+				that.loading = true;
+				that.loadTitle = '加载更多';
+				promotionsList(this.type, {
+					page: that.page,
+					limit: that.limit
+				}).then(res => {
+					let list = res.data.list,
+						loadend = list.length < that.limit;
+					let discountList = that.$util.SplitArray(list, that.list);
+					that.$set(that, 'list', discountList);
+					that.loadend = loadend;
+					that.loading = false;
+					that.loadTitle = loadend ? '没有更多内容啦~' : '加载更多';
+					that.page = that.page + 1;
+				}).catch(err => {
+					that.loading = false;
+					that.loadTitle = '加载更多';
+					return that.$util.Tips({
+						title: err
+					});
+				});
+			},
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+  .mt {
+    margin-top: 4rpx;
+  }
+	.discount {
+		.header {
+			width: 100%;
+			height: 280rpx;
+			background: url(../static/bg.png) no-repeat;
+			background-size: 100% 100%;
+			background-color: var(--view-theme);
+			font-size: 56rpx;
+			color: #fff;
+			text-align: center;
+			padding-top: 40rpx;
+		}
+
+		.list {
+			margin-top: -118rpx;
+
+			.item {
+				width: 710rpx;
+				height: 280rpx;
+				background-color: #fff;
+				border-radius: 16rpx;
+				margin: 0 auto 18rpx auto;
+				padding: 20rpx;
+
+				.pictrue {
+					width: 240rpx;
+					height: 240rpx;
+					border-radius: 16rpx;
+
+					image {
+						width: 100%;
+						height: 100%;
+						border-radius: 16rpx;
+					}
+				}
+
+				.text {
+					width: 416rpx;
+
+					.conter {
+						height: 150rpx;
+					}
+
+					.info {
+						font-size: 20rpx;
+						margin-top: 5rpx;
+						color: var(--view-theme);
+						.desc{
+							width: 380rpx;
+						}
+						.iconfont{
+							font-size: 18rpx;
+							padding-top: 5rpx;
+						}
+					}
+
+					.bntCon {
+						width: 416rpx;
+						height: 88rpx;
+
+						.money {
+							.label {
+								font-size: 24rpx;
+								font-weight: bold;
+								color: var(--view-theme);
+							}
+
+							.y_money {
+								color: #999999;
+								font-size: 20rpx;
+								text-decoration: line-through;
+								margin-left: 6rpx;
+							}
+
+							.num {
+								font-size: 32rpx;
+								color: var(--view-theme);
+								text-decoration: none;
+								font-weight: bold;
+							}
+						}
+
+						.right {
+							width: 156rpx;
+							height: 66rpx;
+							border-radius: 34rpx;
+							background: linear-gradient(135deg, var(--view-minorColor) 0%, var(--view-theme) 100%);
+							font-size: 26rpx;
+							color: #fff;
+						}
+					}
+
+					.bnt {
+						width: 416rpx;
+						height: 88rpx;
+						border-radius: 8rpx;
+						background-color: var(--view-minorColorT);
+
+						.left {
+							padding-left: 12rpx;
+
+							.time {
+								display: inline-block;
+								vertical-align: middle;
+							}
+
+							.title {
+								font-size: 18rpx;
+								color: var(--view-theme);
+
+								.iconfont {
+									font-size: 24rpx;
+									margin-right: 8rpx;
+									display: inline-block;
+									vertical-align: bottom;
+								}
+							}
+
+							.money {
+								width: 261rpx;
+								overflow: hidden;
+
+								.label {
+									font-size: 24rpx;
+									font-weight: bold;
+									color: var(--view-theme);
+								}
+
+								.y_money {
+									color: #999999;
+									font-size: 20rpx;
+									text-decoration: line-through;
+									margin-left: 6rpx;
+								}
+
+								.num {
+									font-size: 32rpx;
+									color: var(--view-theme);
+									text-decoration: none;
+									font-weight: bold;
+								}
+							}
+						}
+
+						.right {
+							width: 134rpx;
+							height: 100%;
+							border-radius: 8rpx;
+							background: linear-gradient(135deg, var(--view-minorColor) 0%, var(--view-theme) 100%);
+							color: #fff;
+							font-size: 26rpx;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

File diff suppressed because it is too large
+ 95 - 0
pages/activity/goods_bargain/index.vue


File diff suppressed because it is too large
+ 422 - 0
pages/activity/goods_bargain_details/index.vue


+ 369 - 0
pages/activity/goods_combination/index.vue

@@ -0,0 +1,369 @@
+<template>
+  <!-- 拼团活动模块 -->
+	<view class="group-list" :style="colorStyle">
+		<view class="swiper" v-if="bannerList.length">
+			<swiper indicator-dots="true" :autoplay="true" :circular="circular"
+			 :interval="interval" :duration="duration" indicator-color="rgba(0,0,0,0.3)">
+				<block v-for="(item,index) in bannerList" :key="index">
+					<swiper-item>
+						<view @click="goDetail(item)" class='slide-navigator acea-row row-between-wrapper'>
+							<image :src="item.img" class="slide-image"></image>
+						</view>
+					</swiper-item>
+				</block>
+			</swiper>
+		</view>
+		<view class="groupMember acea-row row-center-wrapper">
+			<view class="line"><image src="../static/groupLine.png"></image></view>
+			<view class="member acea-row row-center-wrapper">
+				<view class="pictrue" v-for="(item,index) in pinkPeople" :key="index" v-if="index<6"><image :src="item"></image></view>
+				 <text class="ml10">{{pinkCount}}人参与</text>
+				<view class="pictrue" v-if="pinkPeople.length>5">
+					<image :src="pinkPeople[pinkPeople.length-1]"></image>
+					<view class="iconfont icon-gengduo1"></view>
+				</view>
+			</view>
+			<view class="line right"><image src="../static/groupLine.png"></image></view>
+		</view>
+		<view class="list">
+			<view class="item acea-row row-between-wrapper" v-for="(item,index) in combinationList" :key='index' @tap="openSubcribe(item)">
+				<view class="pictrue"><image :src="item.image"></image></view>
+				<view class="text">
+					<view class="name line2">{{item.title}}</view>
+					<view class="bottom acea-row row-between row-bottom">
+						<view class="y_money">
+							<view class="price">¥{{item.product_price}}</view>
+							<view class="money">¥<text class="num">{{item.price}}</text></view>
+						</view>
+						<view class="bnt acea-row row-center-wrapper" v-if="item.stock>0&&item.quota>0">
+							<view class="light"><image src="../static/lightning.png"></image></view>
+							<view class="num">{{item.people}}人团</view>
+							<view class="go">去拼团</view>
+						</view>
+						<view class="bnt gray acea-row row-center-wrapper" v-else>已售罄</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="no-goods" :class="bannerList.length?'':'on'" v-if="!combinationList.length && !loading && isBanner">
+			<image :src="imgHost + '/statics/images/no-thing.png'" mode=""></image>
+			<text class="tip">暂无拼团商品,去看看其他商品吧~</text>
+		</view>
+		<home v-if="navigation"></home>
+	</view>
+</template>
+
+<script>
+	import {
+		getCombinationList,getCombinationBannerList,getPink
+	} from '@/api/activity.js';
+	import {
+		openPinkSubscribe
+	} from '../../../utils/SubscribeMessage.js';
+	import home from '@/components/home/index.vue'
+	import colors from "@/mixins/color";
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	let app = getApp();
+	export default {
+		components: {
+			home
+		},
+		mixins: [colors],
+		data() {
+			return {
+				pinkPeople:[],
+				pinkCount:0,
+				bannerList:[],
+				circular: true,
+				autoplay: true,
+				interval: 3000,
+				duration: 500,
+				combinationList: [],
+				limit: 10,
+				page: 1,
+				loading: false,
+				loadend: false,
+				isBanner: false,
+				imgHost:HTTP_REQUEST_URL
+			}
+		},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title:"拼团列表"
+			})
+			this.getCombinationList();
+			this.getBannerList();
+			this.getPink();
+		},
+		onShow(){
+			uni.removeStorageSync('form_type_cart');
+		},
+		methods: {
+			getPink:function(){
+				getPink({type:2}).then(res=>{
+					this.pinkPeople = res.data.avatars;
+					this.pinkCount = res.data.pink_count;
+				})
+			},
+			getBannerList: function(){
+				getCombinationBannerList().then(res=>{
+					this.bannerList = res.data;
+					this.isBanner = true;
+				})
+			},
+			goDetail(item) {
+				let url = item.link;
+				if (url.indexOf("http") != -1) {
+					// #ifdef H5
+					location.href = url
+					// #endif
+				} else {
+					if (['/pages/goods_cate/goods_cate', '/pages/order_addcart/order_addcart', '/pages/user/index', '/pages/index/index','/pages/store_cate/store_cate']
+						.indexOf(url) == -1) {
+						uni.navigateTo({
+							url: url
+						})
+					} else {
+						uni.switchTab({
+							url: url
+						})
+					}
+				}
+			},
+			openSubcribe: function(item) {
+				let page = item;
+				// #ifndef MP
+				uni.navigateTo({
+					url: `/pages/activity/goods_combination_details/index?id=${item.id}`
+				});
+				// #endif
+				// #ifdef MP
+				uni.showLoading({
+					title: '正在加载',
+				})
+				openPinkSubscribe().then(res => {
+					uni.hideLoading();
+					uni.navigateTo({
+						url: `/pages/activity/goods_combination_details/index?id=${item.id}`
+					});
+				}).catch(() => {
+					uni.hideLoading();
+				});
+				// #endif
+			},
+			getCombinationList: function() {
+				var that = this;
+				if (that.loadend) return;
+				if (that.loading) return;
+				var data = {
+					page: that.page,
+					limit: that.limit
+				};
+				this.loading = true
+				getCombinationList(data).then(function(res) {
+					var combinationList = that.combinationList;
+					var limit = that.limit;
+					that.page++;
+					that.loadend = limit > res.data.length;
+					that.combinationList = combinationList.concat(res.data);
+					that.page = that.data.page;
+					that.loading = false;
+				}).catch(() => {
+					that.loading = false
+				})
+			},
+		},
+		onReachBottom: function() {
+			this.getCombinationList();
+		},
+	}
+</script>
+
+<style lang="scss">
+  .ml10 {
+    margin-left: 10rpx;
+  }
+	page {
+		// background-color: var(--view-theme) !important;
+	}
+	.no-goods{
+		margin: 0 30rpx;
+		background-color: #fff;
+		text-align: center;
+		padding: 20rpx 0 100rpx 0;
+		color: #999;
+		border-radius: 10rpx;
+		height: calc(100vh - 500rpx);
+		box-sizing: border-box;
+		&.on{
+			height: calc(100vh - 200rpx);
+		}
+		image{
+			width: 414rpx;
+			height: 304rpx;
+			margin: 40rpx auto 0 auto;
+			display: block;
+			}
+	}
+	.group-list{
+		min-height: 100vh;
+		background-color: var(--view-theme) !important;
+		padding: 30rpx 0;
+		.swiper{
+			width: 100%;
+			position: relative;
+			box-sizing: border-box;
+			padding: 0 30rpx;
+			swiper{
+				width: 100%;
+				height: 300rpx;
+				.slide-image{
+					width: 100%;
+					height: 300rpx;
+					border-radius: 20rpx;
+				}
+				/deep/.uni-swiper-dot {
+					width: 8rpx !important;
+					height: 8rpx !important;
+					border-radius: 50%;
+				}
+				/deep/.uni-swiper-dot-active{
+					width: 18rpx !important;
+					border-radius: 4rpx;
+					background-color: var(--view-theme) !important;
+				}
+			}
+		}
+		.groupMember{
+			height: 100rpx;
+			.line{
+				width: 102rpx;
+				height: 4rpx;
+				&.right{
+					transform:rotate(180deg);
+				}
+				image{
+					width: 100%;
+					height: 100%;
+					display: block;
+				}
+			}
+			.member{
+				margin: 0 30rpx;
+				color: #fff;
+				.pictrue{
+					width: 46rpx;
+					height: 46rpx;
+					position: relative;
+					image{
+						border:2rpx solid #fff;
+						width: 100%;
+						height: 100%;
+						border-radius: 50%;
+					}
+					&~.pictrue{
+						margin-left: -8rpx;
+					}
+					.iconfont{
+						position: absolute;
+						width: 43rpx;
+						height: 43rpx;
+						background: rgba(51, 51, 51, 0.6);
+						border-radius: 50%;
+						top: 2rpx;
+						left:2rpx;
+						color: #fff;
+						font-size: 10rpx;
+						text-align: center;
+						line-height: 43rpx;
+					}
+				}
+			}
+		}
+		.list{
+			.item{
+				width: 690rpx;
+				height: 230rpx;
+				background-color: #fff;
+				border-radius: 14rpx;
+				padding: 0 22rpx;
+				margin: 0 auto 18rpx auto;
+				.pictrue{
+					width: 186rpx;
+					height: 186rpx;
+					image{
+						width: 100%;
+						height: 100%;
+						border-radius: 10rpx;
+					}
+				}
+				.text{
+					width: 440rpx;
+					.name{
+						color: #333;
+						font-size: 30rpx;
+						height: 82rpx;
+					}
+					.bottom{
+						margin-top: 10rpx;
+						.y_money{
+							font-size: 24rpx;
+							color: #999;
+							.price{
+								text-decoration: line-through;
+							}
+							.money{
+								color: var(--view-priceColor);
+								font-weight: 600;
+								.num{
+									font-size: 34rpx;
+								}
+							}
+						}
+						.bnt{
+							height: 58rpx;
+							font-size: 24rpx;
+							text-align: center;
+							position: relative;
+							background-color: var(--view-theme);
+							border-radius: 28rpx;
+							.light{
+								position: absolute;
+								width: 28rpx;
+								height: 58rpx;
+								top:0;
+								left:50%;
+								margin-left: -8rpx;
+								image{
+									width: 100%;
+									height: 100%;
+								}
+							}
+							.num{
+								width: 120rpx;
+								background-color: rgba(255,255,255,0.85);
+								color: var(--view-theme);
+								height: 100%;
+								line-height: 58rpx;
+								border-radius: 28rpx 0 14rpx 28rpx;
+							}
+							.go{
+								width: 112rpx;
+								background-color: var(--view-theme);
+								height: 100%;
+								line-height: 58rpx;
+								border-radius: 0 28rpx 28rpx 0;
+								color: #fff;
+							}
+							&.gray{
+								width: 148rpx;
+								background-color: #cccccc;
+								color: #fff;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

File diff suppressed because it is too large
+ 1946 - 0
pages/activity/goods_combination_details/index.vue


Some files were not shown because too many files changed in this diff