lhl 4 tháng trước cách đây
commit
baa67037d4
100 tập tin đã thay đổi với 28736 bổ sung0 xóa
  1. 26 0
      .gitignore
  2. 470 0
      App.vue
  3. 284 0
      README.md
  4. 28 0
      androidPrivacy.json
  5. 344 0
      api/activity.js
  6. 431 0
      api/admin.js
  7. 480 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. 394 0
      api/order.js
  13. 20 0
      api/points_mall.js
  14. 208 0
      api/public.js
  15. 93 0
      api/short-video.js
  16. 548 0
      api/store.js
  17. 754 0
      api/user.js
  18. 101 0
      api/work.js
  19. 60 0
      components/Loading/index.vue
  20. 214 0
      components/addressWindow/index.vue
  21. 266 0
      components/areaWindow/index.vue
  22. 428 0
      components/authorize/index.vue
  23. 142 0
      components/cartDiscount/index.vue
  24. 232 0
      components/cartList/index.vue
  25. 134 0
      components/countDown/index.vue
  26. 292 0
      components/couponListWindow/index.vue
  27. 248 0
      components/couponWindow/index.vue
  28. 150 0
      components/cusPreviewImg/index.vue
  29. 98 0
      components/customForm/index.vue
  30. 193 0
      components/d_goodList/index.vue
  31. 340 0
      components/eidtUserModal/index.vue
  32. 49 0
      components/emptyPage.vue
  33. 185 0
      components/ewcomerPop/index.vue
  34. 310 0
      components/filterPopup/index.vue
  35. 226 0
      components/goodClass/index.vue
  36. 169 0
      components/goodList/index.vue
  37. 144 0
      components/groupGoodsList/index.vue
  38. 159 0
      components/guide/index.vue
  39. 132 0
      components/home/index.vue
  40. 160 0
      components/homeList/index.vue
  41. 814 0
      components/jyf-parser/jyf-parser.vue
  42. 102 0
      components/jyf-parser/libs/CssHandler.js
  43. 577 0
      components/jyf-parser/libs/MpHtmlParser.js
  44. 80 0
      components/jyf-parser/libs/config.js
  45. 35 0
      components/jyf-parser/libs/handler.sjs
  46. 44 0
      components/jyf-parser/libs/handler.wxs
  47. 476 0
      components/jyf-parser/libs/trees.vue
  48. 143 0
      components/kefu/index.vue
  49. 94 0
      components/kefuIcon/index.vue
  50. 349 0
      components/maramlee-waterfalls-flow/maramlee-waterfalls-flow.vue
  51. 512 0
      components/orderGoods/index.vue
  52. 159 0
      components/pageFooter/index.vue
  53. 472 0
      components/payment/index.vue
  54. 199 0
      components/privacyAgreementPopup/index.vue
  55. 186 0
      components/productConSwiper/index.vue
  56. 860 0
      components/productWindow/index.vue
  57. 125 0
      components/recommend/index.vue
  58. 198 0
      components/skeleton/index.vue
  59. 246 0
      components/splitOrder/index.vue
  60. 207 0
      components/storeLis/index.vue
  61. 181 0
      components/thorui/tui-collapse.vue
  62. 140 0
      components/thorui/tui-drawer.vue
  63. 178 0
      components/thorui/tui-list-cell.vue
  64. 197 0
      components/timeSlot/index.vue
  65. 159 0
      components/timeranges/index.vue
  66. 546 0
      components/uni-calendar/calendar.js
  67. 152 0
      components/uni-calendar/uni-calendar-item.vue
  68. 435 0
      components/uni-calendar/uni-calendar.vue
  69. 327 0
      components/uni-calendar/util.js
  70. 398 0
      components/uniNoticeBar/uni-notice-bar.vue
  71. 257 0
      components/userEvaluation/index.vue
  72. 1201 0
      components/zb-code/qrcode.js
  73. 210 0
      components/zb-code/zb-code.vue
  74. 48 0
      config/app.js
  75. 44 0
      config/cache.js
  76. 18 0
      config/socket.js
  77. 33 0
      index.html
  78. 272 0
      js_sdk/wa-permission/permission.js
  79. 146 0
      libs/login.js
  80. 9 0
      libs/network.js
  81. 259 0
      libs/new_chat.js
  82. 38 0
      libs/order.js
  83. 218 0
      libs/routine.js
  84. 333 0
      libs/wechat.js
  85. 119 0
      libs/work.js
  86. 85 0
      main.js
  87. 247 0
      manifest.json
  88. 37 0
      mixins/SendVerifyCode.js
  89. 37 0
      mixins/color.js
  90. 399 0
      package-lock.json
  91. 2104 0
      pages.json
  92. 261 0
      pages/activity/bargain/index.vue
  93. 184 0
      pages/activity/components/giftGoods/index.vue
  94. 323 0
      pages/activity/discount/index.vue
  95. 95 0
      pages/activity/goods_bargain/index.vue
  96. 427 0
      pages/activity/goods_bargain_details/index.vue
  97. 355 0
      pages/activity/goods_combination/index.vue
  98. 1975 0
      pages/activity/goods_combination_details/index.vue
  99. 1015 0
      pages/activity/goods_combination_status/index.vue
  100. 394 0
      pages/activity/goods_seckill/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

+ 470 - 0
App.vue

@@ -0,0 +1,470 @@
+<script>
+	import {
+		checkLogin
+	} from './libs/login';
+	import {
+		HTTP_REQUEST_URL
+	} from './config/app';
+	import {
+		getShopConfig,
+		silenceAuth,
+		getLogo
+	} 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;'
+	let gold =
+	    '--view-theme: #E0A558;--view-priceColor:#DA8C18;--view-minorColor:rgba(224, 165, 88, 0.5);--view-minorColorT:rgba(224, 165, 88, 0.1);--view-bntColor:#1A1A1A;'
+
+
+	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>99?'99+':newCart+''
+					})
+				} else {
+					uni.hideTabBarRedDot({
+						index: 3
+					})
+				}
+			}
+		},
+		onLaunch: async function(option) {
+			//#ifdef APP
+			plus.screen.lockOrientation("portrait-primary");
+			//#endif
+			let that = this;
+			getLogo().then(res => {
+				uni.setStorageSync('BASIC_CONFIG', res.data)
+			});
+			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;
+					case 6:
+						uni.setStorageSync('viewColor', gold)
+						uni.$emit('ok', gold)
+						break;
+					default:
+						uni.setStorageSync('viewColor', red)
+						uni.$emit('ok', red)
+						break
+				}
+			});
+			if (option.query.spid) {
+				that.$Cache.set('spid', option.query.spid);
+				that.globalData.spid = option.query.spid;
+			}
+			// #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.spid === undefined ? val : val.spid;
+						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;
+				}
+			}
+			this.checkUpdateVersion();
+			// #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);
+						try {
+							let res = await silenceAuth({
+								code: code,
+								snsapi: 'snsapi_base',
+								spread_spid: that.$Cache.get('spid')
+							}).catch(error => {
+								uni.hideLoading()
+								return this.$util.Tips({
+									title: error
+								})
+							});
+							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);
+								}
+							}
+						}
+					} 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('spid', res.custom_params.pid);
+			// 				 that.globalData.spid = 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 spid = that.globalData.spid ? that.globalData.spid : '';
+				silenceAuth({
+						code: code,
+						spread_spid: spid,
+						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(err => {
+						return that.$util.Tips({
+							title:err
+						})
+					});
+			},
+			isWork() {
+				return navigator.userAgent.toLowerCase().indexOf('wxwork') !== -1 && navigator.userAgent.toLowerCase()
+					.indexOf("micromessenger") !== -1
+			},
+			/**
+			 * 检测当前的小程序
+			 * 是否是最新版本,是否需要下载、更新
+			 */
+			checkUpdateVersion() {
+				//判断微信版本是否 兼容小程序更新机制API的使用
+				if (wx.canIUse('getUpdateManager')) { 
+					const updateManager = wx.getUpdateManager();
+					//检测版本更新
+					updateManager.onCheckForUpdate(function(res) {
+						if (res.hasUpdate) {
+							updateManager.onUpdateReady(function() {
+								wx.showModal({
+									title: '温馨提示',
+									content: '检测到新版本,是否重启小程序?',
+									showCancel: false,
+									success: function(res) {
+										if (res.confirm) {
+											// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
+											updateManager.applyUpdate()
+										}
+									}
+								})
+							})
+							updateManager.onUpdateFailed(function() {
+								// 新版本下载失败
+								wx.showModal({
+									title: '已有新版本',
+									content: '请您删除小程序,重新搜索进入',
+								})
+							})
+						}
+					})
+				} else {
+					wx.showModal({
+						title: '溫馨提示',
+						content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
+					})
+				}
+			}
+		},
+		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;
+	}
+	
+	.activityFrame{
+			background-size: 100% 100%;
+			background-repeat: no-repeat;
+			position: absolute;
+			top:0;
+			left:0;
+			width: 100%;
+			height: 100%;
+			z-index: 1;
+	}
+	
+	.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"
+        }
+    }
+}

+ 344 - 0
api/activity.js

@@ -0,0 +1,344 @@
+// +----------------------------------------------------------------------
+// | 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, data,{
+		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);
+}
+
+/**
+ * 秒杀商品二维码
+ * @param {Object} id
+ */
+export function seckillQRCode(id) {
+  return request.get(`seckill/code/${id}`);
+}
+
+/**
+ * 获取拼团商品详情二维码
+ * @param {Object} id
+ */
+export function combinationQRCode(id) {
+  return request.get(`combination/detail_code/${id}`);
+}

+ 431 - 0
api/admin.js

@@ -0,0 +1,431 @@
+// +----------------------------------------------------------------------
+// | 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 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(id) {
+	return request.get("admin/order/delivery_info/"+id);
+}
+
+/**
+ * 配送员列表
+ * @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);
+}
+
+
+

+ 480 - 0
api/api.js

@@ -0,0 +1,480 @@
+// +----------------------------------------------------------------------
+// | 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
+	});
+}
+
+/**
+ * 获取DIY版本接口
+ * @param {Object} id
+ */
+export function getDiyVersion(id) {
+	return request.get(`diy/diy_version/${id}`, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 商品分类类版本
+ */
+export function getCategoryVersion() {
+	return request.get('category_version', {}, {
+		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');
+}
+
+

+ 394 - 0
api/order.js

@@ -0,0 +1,394 @@
+// +----------------------------------------------------------------------
+// | 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, luckRecordId) {
+	return request.post('order/confirm', {
+		cartId,
+		'new': news,
+		addressId,
+		'shipping_type': shippingType,
+		store_id,
+		'couponId':couponId,
+		luckRecordId
+	});
+}
+
+/**
+ * 获取当前金额能使用的优惠卷
+ * @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}`);
+}
+
+/**
+ * 订单核销记录
+ * @param {Object} id
+ */
+export function orderWriteRecords(id, data) {
+	return request.get(`order/write/records/${id}`, data);
+}

+ 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
+	});
+}

+ 208 - 0
api/public.js

@@ -0,0 +1,208 @@
+// +----------------------------------------------------------------------
+// | 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 }
+  );
+}
+
+/**
+ * 获取登录授权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
+// 	});
+// }
+
+export function authType(data) {
+	return request.get("v2/routine/auth_type", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 公众号登录
+ * @returns {*}
+ */
+export function wechatAuthLogin(data) {
+	return request.get("v2/wechat/auth_login", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 公众号绑定手机号
+ * @param {Object} data
+ */
+export function wechatBindingPhone(data) {
+	return request.post('v2/wechat/auth_binding_phone', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 授权登录
+ * @returns {*}
+ */
+export function authLogin(data) {
+	return request.get("v2/routine/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 {Object} data
+ */
+export function routineBindingPhone(data) {
+	return request.post('v2/routine/auth_binding_phone', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 小程序手机号登录
+ * @param {Object} data
+ */
+export function phoneLogin(data) {
+	return request.post('v2/routine/phone_login', 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, spid) {
+	return request.get(
+		"v2/wechat/auth", 
+		{code : code, spread_spid : spid}, 
+		{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
+  );
+}
+
+

+ 548 - 0
api/store.js

@@ -0,0 +1,548 @@
+// +----------------------------------------------------------------------
+// | 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 getProductStoreDetail(id,data) {
+	return request.get('product/store/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
+	});
+}
+
+/**
+ * 发起拼单
+ * @param {Object} data
+ */
+export function initCollage(data) {
+	return request.get("v2/user/initiate/collage",data);
+}
+
+/**
+ * 检查用户是否发起拼单
+ */
+export function hasCollage() {
+	return request.get("v2/is/user/initiate/collage");
+}
+
+/**
+ * 检查拼单
+ * @param {Object} data
+ */
+export function getCollage(data) {
+	return request.get("v2/is/initiate/collage", data);
+}
+
+/**
+ * 拼单购物车列表
+ * @param {Object} data
+ */
+export function getCollageCart(data) {
+	return request.get("v2/user/initiate/collage/cart_list", data);
+}
+
+/**
+ * 拼单用户购物车统计数量
+ * @param {Object} data
+ */
+export function getCollageCount(data) {
+	return request.get("v2/user/initiate/collage/count", data);
+}
+
+/**
+ * 用户添加拼单商品
+ * @param {Object} data
+ */
+export function addCollageCart(data) {
+  return request.post('v2/add/collage/partake', data);
+}
+
+/**
+ * 获取用户拼单数据
+ * @param {Object} data
+ */
+export function getCollagePartake(data) {
+	return request.get("v2/user/collage/partake", data);
+}
+
+/**
+ * 复制他人拼单商品
+ * @param {Object} data
+ */
+export function duplicateCollagePartake(data) {
+	return request.get("v2/duplicate/collage/partake", data);
+}
+
+/**
+ * 用户清空拼单数据
+ * @param {Object} data
+ */
+export function emptyCollagePartake(data) {
+	return request.get("v2/empty/collage/partake", data);
+}
+
+/**
+ * 取消拼单
+ * @param {Object} data
+ */
+export function cancelCollage(data) {
+	return request.get("v2/user/cancel", data);
+}
+
+/**
+ * 结算拼单
+ * @param {Object} data
+ */
+export function settleCollage(data) {
+	return request.get("v2/user/settle/collage", data);
+}
+
+/**
+ * 验证是否在配送范围
+ * @param {Object} data
+ */
+export function isWithin(data) {
+	return request.get("v2/is/within", data);
+}
+
+/**
+ * 门店桌码配置
+ */
+export function getTableData(data) {
+	return request.get("v2/table/data", data);
+}
+
+/**
+ * 记录桌码
+ * @param {Object} data
+ */
+export function addTableCode(data) {
+	return request.get("v2/add/table/code", data);
+}
+
+/**
+ * 检查桌码记录
+ * @param {Object} data
+ */
+export function isTableCode(data) {
+	return request.get("v2/is/table/code", data);
+}
+
+/**
+ * 处理换桌商品
+ * @param {Object} data
+ */
+export function changeTable(data) {
+	return request.get("v2/changing/table", data);
+}
+
+/**
+ * 购物车统计数量
+ * @param {Object} data
+ */
+export function getCartCount(data) {
+	return request.get("v2/cart/count", data);
+}
+
+/**
+ * 获取门店信息
+ * @param {Object} data
+ */
+export function getStoreData(data) {
+	return request.get("v2/get/store/data", data);
+}
+
+/**
+ * 获取购物车
+ * @param {Object} data
+ */
+export function getCateList(data) {
+	return request.get("v2/get/cate/list", data);
+}
+
+/**
+ * 用户添加桌码商品
+ * @param {Object} data
+ */
+export function addTableCate(data) {
+	return request.get("v2/add/table/cate", data);
+}
+
+/**
+ * 确认下单
+ * @param {Object} data
+ */
+export function placeOrder(data) {
+	return request.get("v2/user/place/order", data);
+}
+
+/**
+ * 获取桌码数据
+ * @param {Object} data
+ */
+export function getTablePartake(data) {
+	return request.get("v2/get/table/partake", data);
+}
+
+/**
+ * 获取二维码信息
+ * @param {Object} data
+ */
+export function getCodeData(data) {
+	return request.get("v2/get/code/data", data);
+}
+
+/**
+ * 获取桌码记录
+ * @param {Object} data
+ */
+export function getTableCode(data) {
+	return request.get("v2/get/table/code", data);
+}
+
+/**
+ * 桌码结账
+ * @param {Object} data
+ */
+export function settleTable(data) {
+	return request.get("v2/user/settle/table", data);
+}
+
+/**
+ * 用户清空购物车
+ * @param {Object} data
+ */
+export function emptyTableData(data) {
+	return request.get("v2/user/empty/data", data);
+}

+ 754 - 0
api/user.js

@@ -0,0 +1,754 @@
+// +----------------------------------------------------------------------
+// | 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 applySupplier(id,data) {
+	return request.post("user/apply/supplier/"+id, data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 供应商详情接口
+ *
+ */
+export function userApply(id) {
+	return request.get("user/apply/"+id,{},{
+		noAuth: true
+	});
+}
+
+/**
+ * 供应商记录接口
+ *
+ */
+export function recordList(id) {
+	return request.get("user/apply/record",{},{
+		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);
+}
+
+
+
+
+

+ 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>

+ 214 - 0
components/addressWindow/index.vue

@@ -0,0 +1,214 @@
+<template>
+	<view>
+		<!-- 下拉选择地址 -->
+		<view class="address-window" :class="{ on: address.address, ons: !isFooter }">
+			<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,
+			},
+			isFooter: {
+			  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');
+				if (!this.addressList.length && this.pagesUrl.indexOf('isCollage') != -1) {
+					let index = this.pagesUrl.indexOf('?')
+					return uni.navigateTo({
+						url: '/pages/users/user_address/index'+this.pagesUrl.slice(index)
+					});
+				}
+				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;
+			margin-bottom: calc(150rpx + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+			margin-bottom: calc(150rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		}
+	}
+
+	.address-window .pictrue {
+		width: 414rpx;
+		height: 336rpx;
+		margin: 0 auto;
+	}
+
+	.address-window .pictrue image {
+		width: 100%;
+		height: 100%;
+	}
+</style>

+ 266 - 0
components/areaWindow/index.vue

@@ -0,0 +1,266 @@
+<template>
+	<!-- 地址下拉框 -->
+	<view>
+		<view class="address-window" :class="display==true?'on':''">
+			<view class='title'>请选择所在地区<text class='iconfont icon-guanbi' @tap='close'></text></view>
+			<view class="address-count">
+				<view class="address-selected">
+					<view v-for="(item,index) in selectedArr" :key="index" class="selected-list" :class="{active:index === selectedIndex}" @click="change(item.pid, index)">
+						{{item.label}}
+						<text class="iconfont icon-xiangyou"></text>
+					</view>
+					<view class="selected-list" :class="{active:-1 === selectedIndex}"  v-if="showMore" @click="change(-1, -1)">
+						<text class="iconfont icon-xiangyou"></text>
+						请选择
+					</view>
+				</view>
+				<scroll-view scroll-y="true" :scroll-top="scrollTop" class="address-list" @scroll="scroll">
+					<view v-for="(item,index) in addressList" :key="index" class="list" :class="{active:item.id === activeId}" @click="selected(item)">
+						<text class="item-name">{{item.label}}</text>
+						<text v-if="item.id === activeId" class="iconfont icon-duihao2"></text>
+					</view>
+				</scroll-view>
+			</view>
+		</view>
+		<view class='mask' catchtouchmove="true" :hidden='display==false' @tap='close'></view>
+	</view>
+</template>
+
+<script>
+	// +----------------------------------------------------------------------
+	// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+	// +----------------------------------------------------------------------
+	// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+	// +----------------------------------------------------------------------
+	// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+	// +----------------------------------------------------------------------
+	// | Author: CRMEB Team <admin@crmeb.com>
+	// +----------------------------------------------------------------------
+	import { getCityData } from '@/api/api.js';
+	
+	const CACHE_ADDRESS = {};
+	
+	export default {
+		props: {
+			display: {
+				type: Boolean,
+				default: true
+			},
+			cityShow: {
+				type: Number,
+				default: 3
+			},
+			address: {
+				type:Array | Object,
+				default:[]
+			},
+		},
+		data() {
+			return {
+				active: 0,
+				//地址列表
+				addressList: [],
+				selectedArr: [],
+				selectedIndex: -1,
+				is_loading: false,
+				old: { scrollTop: 0 },
+				scrollTop: 0
+			};
+		},
+		computed:{
+			activeId(){
+				return this.selectedIndex == -1 ? 0 : this.selectedArr[this.selectedIndex].id
+			},
+			showMore(){
+				return this.selectedArr.length ? (this.selectedArr[this.selectedArr.length - 1].hasOwnProperty('children') && ((this.cityShow==1 && this.addressList.level<2) || (this.cityShow==2 && this.addressList.level<3) || (this.cityShow==3 && this.addressList.level<4))) : true
+			}
+		},
+		watch:{
+			address(n){
+				this.selectedArr = n ? [...n] : []
+			},
+			display(n){
+				if(!n) {
+					this.addressList = [];
+					this.selectedArr =  this.address ? [...this.address] : [];
+					this.selectedIndex = -1;
+					this.is_loading = false;
+				}else{
+					this.loadAddress(0)
+				}
+			}
+		},
+		mounted() {
+			this.loadAddress(0)
+		},
+		methods: {
+			change(pid,index){
+				if(this.selectedIndex == index) return;
+				if(pid === -1){
+					pid = this.selectedArr.length ? this.selectedArr[this.selectedArr.length -1].id : 0;
+				}
+				this.selectedIndex = index;
+				this.loadAddress(pid);
+			},
+			loadAddress(pid){
+				if(CACHE_ADDRESS[pid]){
+					this.addressList = CACHE_ADDRESS[pid];
+					return ;
+				}
+				this.is_loading = true;
+				getCityData(pid).then(res=>{
+					this.is_loading = false;
+					CACHE_ADDRESS[pid] = res.data;
+					this.addressList = res.data;
+				})
+				this.goTop()
+			},
+			selected(item){
+				if(this.is_loading) return;
+				if(this.selectedIndex > -1){
+					this.selectedArr.splice(this.selectedIndex + 1,999)
+					this.selectedArr[this.selectedIndex] = item;
+					this.selectedIndex = -1;
+				}else if(!item.pid){
+					this.selectedArr = [item];
+				}else{
+					this.selectedArr.push(item);
+				}
+				if(item.hasOwnProperty('children') && ((this.cityShow==1 && this.addressList[0].level<2) || (this.cityShow==2 && this.addressList[0].level<3) || (this.cityShow==3 && this.addressList[0].level<4))){
+					this.loadAddress(item.id);
+				} else {
+					this.$emit('submit', [...this.selectedArr]);
+					this.$emit('changeClose');
+				}
+				this.goTop()
+			},
+			close: function() {
+				this.$emit('changeClose');
+			},
+			scroll : function(e) {
+				this.old.scrollTop = e.detail.scrollTop
+			},
+			goTop: function(e) {
+			    this.scrollTop = this.old.scrollTop
+			    this.$nextTick(() => {
+			        this.scrollTop = 0
+			    });
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.address-window {
+		background-color: #fff;
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		width: 100%;
+		z-index: 101;
+		border-radius: 30rpx 30rpx 0 0;
+		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-count{
+		.address-selected{
+			padding: 0 30rpx;
+			margin-top: 10rpx;
+			position: relative;
+			padding-bottom: 20rpx;
+			border-bottom: 2rpx solid #f7f7f7;
+		}
+		.selected-list{
+			font-size: 26rpx;
+			color: #282828;
+			line-height: 50rpx;
+			padding-bottom: 10rpx;
+			padding-left: 60rpx;
+			position: relative;
+			&.active{
+				color: var(--view-theme);
+			}
+			&:before,&:after{
+				content: '';
+				display: block;
+				position: absolute;			
+			}
+			&:before{
+				width: 4rpx;
+				height: 100%;
+				background-color: var(--view-theme);
+				top: 0;
+				left: 10rpx;
+			}
+			&:after{
+				width: 12rpx;
+				height: 12rpx;
+				background: var(--view-theme);
+				border-radius: 100%;
+				left: 6rpx;
+				top: 50%;
+				margin-top: -8rpx;
+			}
+			&:first-child,&:last-child{
+				&:before{
+					height: 50%;
+				}
+			}
+			&:first-child{
+				&:before{
+					top: auto;
+					bottom: 0;
+				}
+			}
+			.iconfont{
+				font-size: 20rpx;
+				float: right;
+				color: #dddddd;
+			}
+		}
+		scroll-view{
+			height: 550rpx;
+		}
+		.address-list{
+			padding: 0 30rpx;
+			margin-top: 20rpx;
+			box-sizing: border-box;
+			.list{
+				.iconfont{
+					float: right;
+					color: #ddd;
+					font-size: 22rpx;
+				}
+				.item-name{
+					display: inline-block;
+					line-height: 50rpx;
+					margin-bottom: 20rpx;
+					font-size: 26rpx;
+				}
+				&.active{
+					color: var(--view-theme);
+					.iconfont{
+						color: var(--view-theme);
+					}
+				}
+			}
+		}
+	}
+</style>

+ 428 - 0
components/authorize/index.vue

@@ -0,0 +1,428 @@
+<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">
+				<checkbox-group @change='ChangeIsDefault' v-if="agreement">
+					<checkbox :checked="protocol ? true : false" />您已同意商城<text class="agree"
+						@click="privacy('user')">《用户协议》</text>
+					与<text class="agree" @click="privacy('privacy')">《隐私协议》</text>
+				</checkbox-group>
+				<view v-else>
+					登录注册即同意商城
+					<text class="agree" @click="privacy('user')">《用户协议》</text>与<text class="agree" @click="privacy('privacy')">《隐私协议》</text>
+				</view>
+			</view>
+			<template v-if="routineAuthType.indexOf(1) != -1">
+				<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>
+			</template>
+			<!-- <button v-if="routineAuthType.indexOf(2) != -1"  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>
+		<block>
+			<editUserModal :isShow="isShow" @closeEdit="closeEdit" @editSuccess="editSuccess">
+			</editUserModal>
+		</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 editUserModal from '@/components/eidtUserModal/index.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 {
+				isShow: false,//判断获取用户头像是否出现
+				isUp: false,
+				phone: '',
+				isPhoneBox: false,
+				logoUrl: '',
+				code: '',
+				authKey: '',
+				options: '',
+				userInfo: {},
+				codeNum: 0,
+				canUseGetUserProfile: false,
+				mp_is_new: this.$Cache.get('MP_VERSION_ISNEW') || false,
+				agreement: 0,
+				protocol: false,
+				routineAuthType: []
+			};
+		},
+		components: {
+			// mobileLogin,
+			routinePhone,
+			editUserModal
+		},
+		mounted(options) {
+			if (uni.getUserProfile) {
+				this.canUseGetUserProfile = true;
+			}
+			getLogo().then(res => {
+				this.logoUrl = res.data.logo_url;
+				this.agreement = res.data.store_user_agreement;
+				this.routineAuthType = res.data.routine_auth_type;
+			});
+			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
+				})
+			},
+			ChangeIsDefault(e) {
+				this.$set(this, 'protocol', !this.protocol);
+			},
+			// 小程序 22.11.8日删除getUserProfile 接口获取用户昵称头像
+			userLogin() {
+				if (!this.protocol && this.agreement) {
+					return this.$util.Tips({
+						title: '请先阅读并同意协议'
+					});
+				}
+				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(res.data.store_user_avatar || 0)
+							}
+						}).catch(err => {
+							uni.hideLoading();
+							uni.showToast({
+								title: err,
+								icon: 'none',
+								duration: 2000
+							});
+						})
+					})
+					.catch(err => {
+						uni.hideLoading();
+						uni.showToast({
+							title: err,
+							icon: 'none',
+							duration: 2000
+						});
+					});
+			},
+			editSuccess() {
+				this.isShow = false
+				this.$emit('onLoadFun');
+			},
+			closeEdit() {
+				this.isShow = false
+				this.$emit('onLoadFun');
+				this.$util.Tips({
+					title: '登录成功',
+					icon: 'success'
+				});
+			},
+			// 弹窗关闭
+			// maskClose(store_user_avatar) {
+			// 	this.isUp = false;
+			// 	if (store_user_avatar) {
+			// 	   this.$emit('onLoadFun');
+			// 	}
+			// },
+			bindPhoneClose(data) {
+				if (data.isStatus) {
+					uni.hideLoading();
+					this.isPhoneBox = false;
+					if(data.store_user_avatar){
+						this.isShow = true
+					}else{
+						this.$emit('onLoadFun');
+						this.$util.Tips({
+							title: '登录成功',
+							icon: 'success'
+						});
+					}
+					// this.getUserInfo(data.store_user_avatar)
+					// this.$util.Tips({
+					// 	title: '登录成功',
+					// 	icon: 'success'
+					// }, {
+					// 	tab: 3
+					// });
+				} else {
+					this.isPhoneBox = false;
+				}
+			},
+			// #ifdef MP
+			/**
+			 * 获取个人用户信息
+			 */
+			getUserInfo: function(store_user_avatar) {
+				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);
+					if(store_user_avatar){
+						that.isShow = true
+					}else{
+						that.$emit('onLoadFun');
+						that.$util.Tips({
+							title: '登录成功',
+							icon: 'success'
+						});
+					}
+				});
+			},
+			setUserInfo(e) {
+				if (!this.protocol && this.agreement) {
+					return this.$util.Tips({
+						title: '请先阅读并同意协议'
+					});
+				}
+				this.close();
+				uni.showLoading({
+					title: '正在登录中'
+				});
+				Routine.getCode()
+					.then(code => {
+						this.getWxUser(code);
+					})
+					.catch(res => {
+						uni.hideLoading();
+					});
+			},
+			//小程序授权api替换 getUserInfo
+			getUserProfile() {
+				if (!this.protocol && this.agreement) {
+					return this.$util.Tips({
+						title: '请先阅读并同意协议'
+					});
+				}
+				this.close();
+				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('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
+									});
+									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: 560rpx;
+		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: var(--view-theme);
+			font-size: 30rpx;
+		}
+		.btn2{
+			width: 536rpx;
+			height: 86rpx;
+			border-radius: 43rpx;
+			border: 2rpx solid  var(--view-theme);
+			color:  var(--view-theme);
+			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>

+ 232 - 0
components/cartList/index.vue

@@ -0,0 +1,232 @@
+<template>
+	<view>
+		<!-- 分类购物车下拉列表 -->
+		<view class="cartList" :class="{on:cartData.iScart,ons:!isFooter}">
+			<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" @touchmove.stop.prevent="moveHandle"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props:{
+			cartData: {
+				type: Object,
+				default: () => {}
+			},
+			isFooter: {
+			  type: Boolean,
+			  default: false
+			}
+		},
+		data() {
+			return {};
+		},
+		mounted(){
+		},
+		methods: {
+			moveHandle(){
+				
+			},
+			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 110rpx 30rpx;
+		padding-bottom: calc(110rpx + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(110rpx + 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);
+		}
+		&.ons{
+			// #ifndef H5
+			padding-bottom: 0;
+			padding-bottom: calc(0 + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+			padding-bottom: calc(0 + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+			// #endif
+		}
+		.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>

+ 292 - 0
components/couponListWindow/index.vue

@@ -0,0 +1,292 @@
+<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[0]" :class="['acea-row', 'row-middle', coupon.type === 0 ? 'on' : '']" @click="setType(0)">通用券</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[2]" :class="['acea-row', 'row-middle', coupon.type === 2 ? 'on' : '']" @click="setType(2)">商品券</view>
+				<view v-if="coupon.count[3]" :class="['acea-row', 'row-middle', coupon.type === 3 ? 'on' : '']" @click="setType(3)">品牌券</view>
+			</view>
+			<view class='title' v-else>优惠券<text class='iconfont icon-guanbi' @click='close'></text></view>
+			<view v-if="coupon.count" class="occupy"></view>
+			<scroll-view class="coupon-list" scroll-y="true">
+				<view class="coupon-list-inner" 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-if='item.type===2'>商品券</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>
+			</scroll-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 {
+		height: 721rpx;
+		padding: 0;
+		margin: 0;
+		padding-bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/
+		padding-bottom: env(safe-area-inset-bottom); ///兼容 IOS>11.2/
+	}
+	
+	.coupon-list-window .coupon-list-inner {
+		padding: 18rpx 30rpx 0 30rpx;
+		overflow: hidden;
+	}
+
+	.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>

+ 98 - 0
components/customForm/index.vue

@@ -0,0 +1,98 @@
+<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 && ['uploadPicture','dateranges'].indexOf(item.name) == -1) || (item.value.length && ['uploadPicture','dateranges'].indexOf(item.name) != -1)">
+			<view class="title">{{item.titleConfig.value}}:</view>
+			<view v-if="item.name == 'uploadPicture'" 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-else-if="item.name == 'dateranges'" class="conter">
+			   <text v-if="item.value.length">{{item.value[0]+'/'+item.value[1]}}</text>
+			</view>
+			<view v-else 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 .title{
+		width: 200rpx;
+	}
+	
+	.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>

+ 193 - 0
components/d_goodList/index.vue

@@ -0,0 +1,193 @@
+<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> -->
+						<uni-badge class="uni-badge-left-margin" :text="item.cart_num" absolute="rightTop" v-if="item.spec_type">
+						  <!-- 多规格 -->
+						  <view class="bnt acea-row row-center-wrapper" @click.stop="goCartDuo(item)">
+						  	选规格
+						  </view>
+						</uni-badge>
+						<!-- 单规格 -->
+						<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>

+ 340 - 0
components/eidtUserModal/index.vue

@@ -0,0 +1,340 @@
+<template>
+	<view :style="colorStyle">
+		<view class="product-window" :class="{'on':isShow}">
+			<view class="iconfont icon-guanbi" @click="closeAttr"></view>
+			<view class="mp-data">
+				<image :src="mpData.site_logo" mode=""></image>
+				<text class="mp-name">{{mpData.site_name || ''}} 申请</text>
+			</view>
+			<view class="trip-msg">
+				<view class="title">
+					获取您的昵称、头像
+				</view>
+				<view class="trip">
+					提供具有辨识度的用户中心界面
+				</view>
+			</view>
+			<form @submit="formSubmit">
+				<view class="edit">
+					<view class="avatar edit-box">
+						<view class="left">
+							<view class="head">头像</view>
+							<!-- <image :src="userInfo.avatar || defaultAvatar" mode=""></image> -->
+							<view class="avatar-box" v-if="!mp_is_new" @click.stop='uploadpic'>
+								<image :src="userInfo.avatar || defHead"></image>
+							</view>
+							<button v-else class="avatar-box" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
+								<image :src="userInfo.avatar || defHead"></image>
+							</button>
+						</view>
+						<!-- <view class="iconfont icon-xiangyou"></view> -->
+					</view>
+					<view class="nickname edit-box">
+						<view class="left">
+							<view class="head">昵称</view>
+							<view class='input'><input type='nickname' :always-embed="true" :adjust-position="true" cursor-spacing="30" placeholder-class="pl-sty"
+									placeholder="请输入昵称" name='nickname' :maxlength="16"
+									:value='userInfo.nickname'></input>
+							</view>
+						</view>
+						<!-- <view class="iconfont icon-xiangyou"></view> -->
+					</view>
+
+				</view>
+
+				<view class="bottom">
+					<button class="save" formType="submit" :class="{'open': userInfo.avatar}">
+						保存
+					</button>
+				</view>
+			</form>
+		</view>
+		<canvas canvas-id="canvas" v-if="canvasStatus"
+			:style="{width: canvasWidth + 'px', height: canvasHeight + 'px',position: 'absolute',left:'-100000px',top:'-100000px'}"></canvas>
+		<view class="mask" @touchmove.prevent v-if="isShow" @click="closeAttr"></view>
+	</view>
+	</uni-popup>
+
+</template>
+
+<script>
+	import colors from "@/mixins/color";
+	import Cache from '@/utils/cache';
+	import {
+		userEdit,
+	} from '@/api/user.js';
+	import {
+		copyRight
+	} from '@/api/api.js';
+	export default {
+		mixins: [colors],
+		props: {
+			isShow: {
+				type: Boolean,
+				value: false
+			}
+		},
+		data() {
+			return {
+				defHead: require('@/static/images/def_avatar.png'),
+				mp_is_new: this.$Cache.get('MP_VERSION_ISNEW') || false,
+				userInfo: {
+					avatar: '',
+					nickname: '',
+				},
+				mpData: {
+					site_logo: '',
+					site_name: ''
+				},
+				canvasStatus: false,
+				configData: this.$Cache.get('BASIC_CONFIG')
+			};
+		},
+		mounted() {
+			try{
+				let MPSiteData = uni.getStorageSync('MPSiteData');
+				if (MPSiteData) {
+					this.mpData = JSON.parse(MPSiteData);
+				} else{
+					this.getCopyRight();
+				}
+			}catch(e){
+				//TODO handle the exception
+			}
+		},
+		methods: {
+			getCopyRight(){
+				copyRight().then(res => {
+					let { site_logo, site_name } = res.data;
+					this.mpData.site_logo = site_logo;
+					this.mpData.site_name = site_name;
+					uni.setStorageSync('MPSiteData', JSON.stringify(this.mpData));
+				}).catch(err => {
+					return this.$util.Tips({
+						title: err.msg
+					});
+				});
+			},
+			/**
+			 * 上传文件
+			 * 
+			 */
+			uploadpic: function() {
+				let that = this;
+				this.canvasStatus = true
+				that.$util.uploadImageChange('upload/image', (res) => {
+					let userInfo = that.userInfo;
+					if (userInfo !== undefined) {
+						that.userInfo.avatar = res.data.url;
+					}
+					this.canvasStatus = false
+				}, (res) => {
+					this.canvasStatus = false
+				}, (res) => {
+					this.canvasWidth = res.w
+					this.canvasHeight = res.h
+				});
+			},
+			// 微信头像获取
+			onChooseAvatar(e) {
+				const {
+					avatarUrl
+				} = e.detail
+				this.$util.uploadImgs('upload/image', avatarUrl, (res) => {
+					this.userInfo.avatar = res.data.url
+				}, (err) => {
+					console.log(err)
+				})
+			},
+			closeAttr: function() {
+				this.$emit('closeEdit');
+			},
+			/**
+			 * 提交修改
+			 */
+			formSubmit(e) {
+				let that = this
+				if (!this.userInfo.avatar) return that.$util.Tips({
+					title: '请上传头像'
+				});
+				if (!e.detail.value.nickname) return that.$util.Tips({
+					title: '请输入昵称'
+				});
+				this.userInfo.nickname = e.detail.value.nickname
+				userEdit(this.userInfo).then(res => {
+					this.$emit('editSuccess')
+					return that.$util.Tips({
+						title: res.msg,
+						icon: 'success'
+					}, {
+						tab: 3,
+						url: this.configData.wechat_auth_switch ? 2 : 1
+					});
+				}).catch(msg => {
+					return that.$util.Tips({
+						title: msg || '保存失败'
+					});
+				});
+			}
+		}
+	}
+</script>
+<style>
+	.pl-sty {
+		color: #999999;
+		font-size: 30rpx;
+	}
+</style>
+<style scoped lang="scss">
+	.product-window.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.mask {
+		z-index: 100;
+	}
+
+	.product-window {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		background-color: #fff;
+		z-index: 1000;
+		border-radius: 20rpx 20rpx 0 0;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		padding: 38rpx 40rpx;
+		padding-bottom: 80rpx;
+		padding-bottom: calc(80rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(80rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+
+		.icon-guanbi {
+			position: absolute;
+			top: 30rpx;
+			right: 30rpx;
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #999;
+			padding: 10rpx;
+		}
+
+		.mp-data {
+			display: flex;
+			align-items: center;
+			margin-bottom: 30rpx;
+
+			.mp-name {
+				font-size: 28rpx;
+				font-weight: bold;
+				color: #000000;
+			}
+
+			image {
+				width: 48rpx;
+				height: 48rpx;
+				border-radius: 50%;
+				margin-right: 16rpx;
+			}
+		}
+
+		.trip-msg {
+			padding-bottom: 32rpx;
+			border-bottom: 1px solid #F5F5F5;
+
+			.title {
+				font-size: 30rpx;
+				font-weight: bold;
+				color: #000;
+				margin-bottom: 6rpx;
+			}
+
+			.trip {
+				font-size: 26rpx;
+				color: #777777;
+			}
+		}
+
+		.edit {
+			border-bottom: 1px solid #F5F5F5;
+
+			.avatar {
+				border-bottom: 1px solid #F5F5F5;
+			}
+
+			.nickname {
+				.input {
+					width: 100%;
+
+				}
+
+				input {
+					height: 80rpx;
+				}
+			}
+
+			.edit-box {
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				font-size: 30rpx;
+				padding: 22rpx 0;
+
+				.left {
+					display: flex;
+					align-items: center;
+					flex: 1;
+
+					.head {
+						color: rgba(0, 0, 0, 0.9);
+						white-space: nowrap;
+						margin-right: 60rpx;
+					}
+
+					button {
+						flex: 1;
+						display: flex;
+						align-items: center;
+					}
+				}
+
+				image {
+					width: 80rpx;
+					height: 80rpx;
+					border-radius: 6rpx;
+				}
+			}
+
+			.icon-xiangyou {
+				color: #cfcfcf;
+			}
+		}
+
+		.bottom {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+
+			.save {
+				border: 1px solid #F5F5F5;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 368rpx;
+				height: 80rpx;
+				border-radius: 12rpx;
+				margin-top: 52rpx;
+				background-color: #F5F5F5;
+				color: #ccc;
+				font-size: 30rpx;
+				font-weight: bold;
+			}
+
+			.save.open {
+				border: 1px solid #fff;
+				background-color: var(--view-theme);
+				color: #fff;
+			}
+		}
+	}
+</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>

+ 226 - 0
components/goodClass/index.vue

@@ -0,0 +1,226 @@
+<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>
+							<uni-badge class="uni-badge-left-margin" :text="item.cart_num" absolute="rightTop" v-if="item.spec_type">
+							  <!-- 多规格 -->
+							  <view class="bnt acea-row row-center-wrapper" @click.stop="goCartDuo(item)">
+							  	选规格
+							  	<!-- <text class="num" v-if="isLogin && item.cart_num">{{item.cart_num}}</text> -->
+							  </view>
+							</uni-badge>
+							<!-- 单规格 -->
+							<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;
+							height: 24rpx;
+							text-align: center;
+							line-height: 24rpx;
+							background-color: #fff;
+							color: var(--view-theme);
+							border-radius: 15px;
+							position: absolute;
+							right: -13rpx;
+							top: -11rpx;
+							font-size: 16rpx;
+							padding: 0 5rpx;
+							border: 1px solid var(--view-theme);
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 169 - 0
components/goodList/index.vue

@@ -0,0 +1,169 @@
+<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 class="activityFrame" v-if="item.activity_frame.image" :style="'background-image: url('+item.activity_frame.image+');'"></view>
+				</view>
+				<view class='underline'>
+					<view class='text'>
+						<view class="nameCon">
+							<view class='line2'>{{item.store_name}}</view>
+						</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'>
+	.activityFrame{
+		border-radius: 20rpx;
+	}
+	.goodList{
+		padding-top: 30rpx;
+	}
+	.goodList .item {
+		position: relative;
+		padding-left: 20rpx;
+		margin-bottom: 30rpx;
+	}
+
+	.goodList .item .pictrue {
+		width: 240rpx;
+		height: 240rpx;
+		position: relative;
+	}
+
+	.goodList .item .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 12rpx;
+	}
+
+	.goodList .item .pictrue .numPic {
+		position: absolute;
+		left: 7rpx;
+		top: 7rpx;
+		width: 50rpx;
+		height: 50rpx;
+		border-radius: 50%;
+	}
+
+	.goodList .item .underline {
+		padding-right: 30rpx;
+	}
+
+	.goodList .item:nth-last-child(1) .underline {
+		border-bottom: 0;
+	}
+
+	.goodList .item .text {
+		font-size: 30rpx;
+		color: #222;
+		width: 440rpx;
+		.nameCon{
+			height: 136rpx;
+		}
+	}
+
+	.goodList .item .text .money {
+		font-size: 26rpx;
+		font-weight: bold;
+	}
+
+	.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>

+ 144 - 0
components/groupGoodsList/index.vue

@@ -0,0 +1,144 @@
+<template>
+	<view v-if="goodsList.length" class="goods-list">
+		<view v-for="item in goodsList" class="item">
+			<view class="head">
+				<image class="avatar" :src="item.userInfo.avatar || '/static/images/f.png'" mode="aspectFill"></image>
+				<view class="name-wrap">
+					<view class="name-inner">
+						<view class="name">{{ item.userInfo.nickname }}</view>
+						<view v-if="item.userInfo.uid == uid">(我)</view>
+					</view>
+				</view>
+			</view>
+			<view class="body">
+				<view v-for="cell in item.goods" :key="cell.id" class="cell">
+					<image class="image" :src="cell.productInfo.attrInfo.image" mode="aspectFill"></image>
+					<view class="name-wrap">
+						<view class="name">{{ cell.productInfo.store_name }}</view>
+						<view class="attr">{{ cell.productInfo.attrInfo.suk }}</view>
+						<view class="money">¥{{ cell.truePrice }}</view>
+					</view>
+					<view class="">x {{ cell.cart_num }}</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapGetters
+	} from 'vuex';
+
+	export default {
+		props: {
+			goodsList: {
+				type: Array,
+				default: () => {
+					return [];
+				}
+			},
+		},
+		computed: mapGetters(['uid']),
+	};
+</script>
+
+<style lang="scss" scoped>
+	.goods-list {
+		.item {
+			border-radius: 14rpx;
+			background-color: #FFFFFF;
+
+			+.item {
+				margin-top: 20rpx;
+			}
+
+			.head {
+				display: flex;
+				align-items: center;
+				height: 86rpx;
+				padding: 0 26rpx;
+				border-bottom: 1rpx solid #F0F0F0;
+				font-size: 26rpx;
+				color: #333333;
+
+				.name-wrap {
+					flex: 1;
+					min-width: 0;
+					margin-left: 20rpx;
+				}
+
+				.name-inner {
+					display: inline-flex;
+					align-items: center;
+					max-width: 100%;
+				}
+
+				.name {
+					flex: 1;
+					min-width: 0;
+					overflow: hidden;
+					white-space: nowrap;
+					text-overflow: ellipsis;
+				}
+			}
+
+			.avatar {
+				display: block;
+				width: 40rpx;
+				height: 40rpx;
+				border-radius: 50%;
+			}
+
+			.body {
+				padding-left: 24rpx;
+
+				.cell {
+					display: flex;
+					padding: 24rpx 26rpx 26rpx 0;
+					font-size: 26rpx;
+					line-height: 40rpx;
+					color: #999999;
+
+					+.cell {
+						border-top: 1rpx solid #EEEEEE;
+					}
+
+					.name-wrap {
+						flex: 1;
+						min-width: 0;
+						margin: 0 20rpx;
+					}
+
+					.name {
+						overflow: hidden;
+						white-space: nowrap;
+						text-overflow: ellipsis;
+						font-size: 28rpx;
+						line-height: 40rpx;
+						color: #333333;
+					}
+
+					.attr {
+						margin-top: 8rpx;
+						font-size: 20rpx;
+						line-height: 28rpx;
+					}
+
+					.money {
+						margin-top: 14rpx;
+						line-height: 36rpx;
+						color: #E93323;
+					}
+				}
+
+				.image {
+					display: block;
+					width: 130rpx;
+					height: 130rpx;
+					border-radius: 6rpx;
+				}
+			}
+		}
+	}
+</style>

+ 159 - 0
components/guide/index.vue

@@ -0,0 +1,159 @@
+<template>
+	<!-- 开屏广告 -->
+	<view class="content">
+		<swiper class="swiper" :class="advData.value.length==1?'on':''" :autoplay="autoplay" :duration="duration" @change="stopChange"
+			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: {
+			stopChange(){
+				if(this.advData.value.length == 1){
+					return false
+				}
+			},
+			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)
+					this.$util.JumpPath(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;
+		&.on{
+			position: relative;
+			&:after {
+			 content: '';
+			 position: absolute;
+			 top: 0;
+			 left: 0;
+			 right: 0;
+			 bottom: 0;
+			 z-index: 2;
+			}
+		}
+	}
+
+	.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>

+ 132 - 0
components/home/index.vue

@@ -0,0 +1,132 @@
+<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;
+		border: 1px solid #fff;
+	}
+
+	.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>

+ 160 - 0
components/homeList/index.vue

@@ -0,0 +1,160 @@
+<template>
+	<!-- 顶部下拉导航 -->
+	<!-- #ifdef APP-PLUS -->
+	<view class="animated dialog_nav" :style="{ top: (navH+15) + 'rpx', marginTop: sysHeight + 'px'}" :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;
+			/* #ifndef H5 */
+			top:-30px !important;
+			/* #endif */
+			&::before{
+				/* #ifndef MP */
+				left: -160rpx!important;
+				/* #endif */
+				/* #ifdef MP */
+				left: 0rpx !important;
+				/* #endif */
+			}
+		}
+		&.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 && uni.env && 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>

+ 94 - 0
components/kefuIcon/index.vue

@@ -0,0 +1,94 @@
+<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}`
+				let obj = {
+					store_name: this.storeInfo.store_name,
+					path: `/pages/goods_details/index?id=${this.storeInfo.id}`,
+					image:this.storeInfo.image
+				}
+				this.$util.getCustomer(userInfo,url,obj,1)
+			}
+		},
+		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>

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

@@ -0,0 +1,349 @@
+<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="aspectFill"
+				  :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>
+				<video
+					v-if="product_video_status && item.video_link"
+					:src="item.video_link"
+					:controls="false"
+					:show-center-play-btn="false"
+					:id="`video${item.id}`"
+					:poster="item[imageSrcKey] || ''"
+					class="video"
+					objectFit="cover"
+					loop
+					muted
+				></video>
+				<view class="activityFrame" v-if="item.activity_frame.image" :style="'background-image: url('+item.activity_frame.image+');'"></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="aspectFill"
+		    :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>
+			<!-- #ifdef H5 -->
+			<video
+				v-if="product_video_status && item.video_link"
+				:src="item.video_link"
+				:controls="false"
+				:show-center-play-btn="false"
+				:id="`video${item.id}`"
+				:poster="item[imageSrcKey] || ''"
+				objectFit="cover"
+				class="video"
+				loop
+				muted
+			></video>
+			<!-- #endif -->
+			<view class="activityFrame" v-if="item.activity_frame.image" :style="'background-image: url('+item.activity_frame.image+');'"></view>
+	  </view>
+      <slot v-bind="item" />
+    </view>
+    <!--  #endif -->
+  </view>
+</template>
+<script>
+import store from '../../store';
+import {
+		diyProduct
+	} from '@/api/store.js';
+	import {
+		mapMutations
+	} from 'vuex';
+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,
+	  updateCount: 0,
+	  product_video_status: false
+    };
+  },
+  watch: {
+  	list: {
+		handler(newValue, oldValue) {
+			// #ifndef APP-PLUS
+			if (!newValue.length) {
+				return;
+			}
+			this.$nextTick(() => {
+				this.updateCount++;
+				if (!this.product_video_status) {
+					return;
+				}
+				uni.getNetworkType({
+					success: (res) => {
+						if (['wifi', 'unknown'].includes(res.networkType)) {
+							// 监听
+							this.observeVideo();
+						}
+						if (['2g', '3g', '4g', '5g'].includes(res.networkType)) {
+							if (!this.$store.state.app.autoplay) {
+								if (this.updateCount != 1) {
+									return;
+								}
+								return uni.showModal({
+									content: '当前使用移动网络,是否继续播放视频?',
+									success: (res) => {
+										if (res.confirm) {
+											// 监听
+											this.SET_AUTOPLAY(true);
+											this.observeVideo();
+										}
+									}
+								});
+							}
+							// 监听
+							this.observeVideo();
+						}
+					}
+				});
+			});
+			// #endif
+		},
+		immediate: true
+  	}
+  },
+  created() {
+	  let that = this;
+    this.refresh();
+	let product_video_status = null;
+	try{
+		product_video_status = JSON.parse(uni.getStorageSync('product_video_status'));
+	}catch(e){
+		//TODO handle the exception
+	}
+	if (typeof product_video_status == 'boolean') {
+		this.product_video_status = product_video_status;
+	} else{
+		this.getdiyProduct();
+	}
+  },
+  methods: {
+	  ...mapMutations(['SET_AUTOPLAY']),
+	  observeVideo() {
+	  	let observer = uni.createIntersectionObserver(this, { observeAll: true });
+	  	observer.relativeToViewport().observe('.video', res => {
+	  		if (res.intersectionRatio) {
+				setTimeout(() => {
+					uni.createVideoContext(res.id, this).play();
+				}, 200)
+	  		} else{
+				setTimeout(() => {
+					uni.createVideoContext(res.id, this).pause();
+				}, 200)
+	  		}
+	  	});
+		this.$once('hook:beforeDestroy', () => {
+			observer.disconnect();
+		});
+	  },
+	  // div商品详情
+	getdiyProduct() {
+		diyProduct().then(res => {
+			uni.setStorageSync('product_video_status',JSON.stringify(res.data.product_video_status))
+			this.product_video_status = res.data.product_video_status;
+		})
+	},
+    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: 346rpx;
+    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;
+			}
+		}
+		.activityFrame{
+			border-radius: $border-radius $border-radius 0 0;
+		}
+	}
+	
+	
+	
+    .waterfalls-list-image {
+	  width: 100%;
+	  height: 346rpx !important;
+      will-change: transform;
+      border-radius: $border-radius $border-radius 0 0;
+      display: block;
+      &.single {
+        border-radius: $border-radius;
+      }
+    }
+  }
+  
+  .video {
+	  position: absolute;
+	  top: 0;
+	  left: 0;
+	  width: 100%;
+	  height: 346rpx !important;
+	  border-radius: $border-radius $border-radius 0 0;
+  }
+}
+</style>

+ 512 - 0
components/orderGoods/index.vue

@@ -0,0 +1,512 @@
+<template>
+	<!-- 订单商品 -->
+	<view class="orderGoods" :class="product_type?'on':''">
+		<view class='total' v-if="!split && totalNmu>0">
+			<view>共{{totalNmu+totaliveNmu}}件商品</view>
+			<!-- <navigator v-if="isGroup" class="navigator" :url="`/pages/store/group_goods/index?collage_id=${collageId}`" hover-class="none">拼单详情<text class="iconfont icon-xiangyou"></text></navigator> -->
+			<navigator v-if="[1,2,3,4,5].includes(statusType) && (deliveryType==2 || sendType=='send')" class="navigator" :url="`/pages/goods/verify_record/index?oid=${oid}`" hover-class="none">核销记录<text class="iconfont icon-xiangyou"></text></navigator>
+		</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 v-if="item.type != 8">
+								¥{{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" v-if="item.type != 8">
+					<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';
+    import { type } from 'os';
+	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,
+			},
+			// isGroup: {
+			// 	type: Boolean,
+			// 	default: false
+			// },
+			collageId: {
+				type: Number,
+				default: 0
+			}
+		},
+		data() {
+			return {
+				totaliveNmu:0,
+				totalNmu: 0,
+				operationModel: false,
+				status: ""
+			};
+		},
+		watch: {
+			cartInfo: function(nVal, oVal) {
+				console.log(this.$parent)
+				let num = 0
+				nVal.forEach((item, index) => {
+					num += item.cart_num
+				})
+				this.totalNmu = num
+			},
+			giveCartInfo:function(nVal, oVal){
+				let num = 0
+				nVal.forEach((item, index) => {
+					num += item.cart_num
+				})
+				this.totaliveNmu = num
+			},
+			giveData(val) {
+				console.log(val)
+			}
+		},
+		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);
+		}
+		
+		.navigator {
+			font-size: 24rpx;
+			color: #999999;
+			
+			.iconfont {
+				margin-left: 10rpx;
+				font-size: 24rpx;
+				color: #999999;
+			}
+		}
+	}
+
+	.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>

+ 159 - 0
components/pageFooter/index.vue

@@ -0,0 +1,159 @@
+<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> -->
+					<uni-badge v-if="item.link === '/pages/order_addcart/order_addcart' && cartNum>0" class="uni-badge-left-margin" :text="cartNum" absolute="rightTop">
+					</uni-badge>
+				</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
+				if(item.link == '/pages/short_video/appSwiper/index' || item.link == '/pages/short_video/nvueSwiper/index'){
+					//#ifdef APP
+					item.link = '/pages/short_video/appSwiper/index'
+					//#endif
+					//#ifndef APP
+					item.link = '/pages/short_video/nvueSwiper/index'
+					//#endif
+				}
+				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 + '')
+				});
+			}
+		}
+	}
+</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>

+ 199 - 0
components/privacyAgreementPopup/index.vue

@@ -0,0 +1,199 @@
+<template>
+	<view :style="colorStyle">
+		<view class="mask" @touchmove.prevent :hidden="isShow === false"></view>
+		<view class="product-window" :class="{'on':isShow}">
+			<view class="mp-data">
+				<text class="mp-name">服务与隐私协议</text>
+			</view>
+			<view class="trip-msg">
+				<view class="trip">
+					{{`请仔细阅读以下内容,并作出适当的选择:`}}
+				</view>
+			</view>
+			<view class="trip-title">
+				隐私政策概要
+			</view>
+			<view class="trip-msg">
+				<view class="trip">
+					当您点击同意并继续使用产品服务时,即表示您已理解并同意该条款内容,该条款将对您产生法律约束力。如您拒绝,将无法继续下一步操作。
+				</view>
+			</view>
+			<view class="main-color" @click.stop="privacy('privacy')">点击阅读{{agreementName}}</view>
+			<view class="bottom">
+				<button class="save open" type="default" id="agree-btn" open-type="agreePrivacyAuthorization"
+					@agreeprivacyauthorization="handleAgree">同意并继续</button>
+				<button class="reject" @click="rejectAgreement">取消</button>
+			</view>
+		</view>
+	</view>
+
+</template>
+
+<script>
+	import colors from "@/mixins/color";
+	export default {
+		mixins: [colors],
+		data() {
+			return {
+				isShow: false,
+				agreementName: '',
+				configData: this.$Cache.get('BASIC_CONFIG'),
+			};
+		},
+		mounted() {
+			wx.getPrivacySetting({
+				success: res => {
+					if (res.needAuthorization) {
+						// 需要弹出隐私协议
+						this.isShow = true
+						this.agreementName = res.privacyContractName
+					} else {
+						this.$emit('onAgree');
+						// 用户已经同意过隐私协议,所以不需要再弹出隐私协议,也能调用已声明过的隐私接口
+						// wx.getUserProfile()
+						// wx.chooseMedia()
+						// wx.getClipboardData()
+						// wx.startRecord()
+					}
+				},
+				fail: () => {},
+				complete: () => {}
+			})
+		},
+		methods: {
+			// 同意
+			handleAgree() {
+				this.isShow = false
+				this.$emit('onAgree');
+			},
+			// 拒绝
+			rejectAgreement() {
+				this.isShow = false
+				uni.switchTab({
+					url: '/pages/index/index'
+				})
+				this.$emit('onReject');
+			},
+			// 跳转协议
+			privacy(type) {
+				uni.navigateTo({
+					url: "/pages/users/privacy/index?type=" + type
+				})
+			},
+		}
+	}
+</script>
+<style>
+	.pl-sty {
+		color: #999999;
+		font-size: 30rpx;
+	}
+</style>
+<style scoped lang="scss">
+	.product-window.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.mask {
+		z-index: 99;
+	}
+
+	.product-window {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		background-color: #fff;
+		z-index: 1000;
+		border-radius: 40rpx 40rpx 0 0;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		padding: 64rpx 40rpx;
+		padding-bottom: 38rpx;
+		padding-bottom: calc(38rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(38rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.06);
+
+		.icon-guanbi {
+			position: absolute;
+			top: 40rpx;
+			right: 40rpx;
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #999;
+		}
+
+		.mp-data {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-bottom: 40rpx;
+
+			.mp-name {
+				font-size: 34rpx;
+				font-weight: 500;
+				color: #333333;
+				line-height: 48rpx;
+			}
+		}
+
+		.trip-msg {
+			padding-bottom: 32rpx;
+
+			.title {
+				font-size: 30rpx;
+				font-weight: bold;
+				color: #000;
+				margin-bottom: 6rpx;
+			}
+
+			.trip {
+				color: #333333;
+				font-size: 28rpx;
+				font-family: PingFang SC-Regular, PingFang SC;
+				font-weight: 400;
+			}
+		}
+
+		.trip-title {
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #333333;
+			margin-bottom: 8rpx;
+		}
+
+		.main-color {
+			font-size: 28rpx;
+			font-weight: 400;
+			color: var(--view-theme);
+			margin-bottom: 40rpx;
+		}
+
+		.bottom {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+
+			.save,
+			.reject {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 670rpx;
+				height: 80rpx;
+				border-radius: 80rpx;
+				background-color: #F5F5F5;
+				color: #333;
+				font-size: 30rpx;
+				font-weight: 500;
+			}
+
+			.save {
+				background-color: var(--view-theme);
+				color: #fff;
+				margin-bottom: 24rpx;
+			}
+		}
+	}
+</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>

+ 860 - 0
components/productWindow/index.vue

@@ -0,0 +1,860 @@
+<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 v-if="parseFloat(attr.productSelect.integral)"><text class="num">{{ attr.productSelect.integral }}</text>积分</text>
+								<text v-if="parseFloat(attr.productSelect.price) && parseFloat(attr.productSelect.integral)">+</text>
+								<text v-if="parseFloat(attr.productSelect.price)">¥<text class="num">{{ attr.productSelect.price }}</text></text>
+							</text>
+							<text v-else>¥<text class="num">{{ attr.productSelect.price }}</text></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':isStoreBuy?'on2':''">商城配送</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 != 1"></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 != 1"></text></view>
+						</view>
+					</view>
+				</view>
+				<view class="cart acea-row row-between-wrapper" v-if="type != 'setMeal' && type !='points'">
+				  <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" :always-embed="true" :adjust-position="true" cursor-spacing="30"
+								@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" :isFooter="isFooter" :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,
+		mapState
+	} from 'vuex';
+	export default {
+		computed: {
+			...mapState({
+				nearbyStore: state => state.app.nearbyStore
+			}),
+			...mapGetters(['isLogin'])
+		},
+		components:{
+		  addressWindow
+		},
+		props: {
+			isStoreBuy: {
+				type: Number,
+				value: 0
+			},
+			productId: {
+				type: Number | String,
+				value: 0
+			},
+			productType: {
+				type: Number | String,
+				value: 0
+			},
+			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: ''
+			},
+			isFooter: {
+			  type: Boolean,
+			  default: false
+			}
+		},
+		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
+			// }
+			'attr.deliveryType'(newValue, oldValue) {
+				if (JSON.stringify(newValue) != JSON.stringify(oldValue)) {
+					if (newValue.length) {
+						if(this.active<1){
+							this.getList();
+							// if (this.user_latitude && this.user_longitude) {
+							// 	this.getList();
+							// } else {
+							// 	this.selfLocation();
+							// }
+						}
+						let num = 1;
+						if(newValue[0] == 1 && this.isStoreBuy){
+							num = newValue[1];
+						}else{
+							num = newValue[0];
+						}
+						this.flag = num
+						this.$emit('deliveryFun',num);
+					}
+				}
+			}
+		},
+		methods: {
+			closeStore(){
+				this.isStore = false;
+			},
+			openStore(){
+				if(this.attr.isType != 1){
+					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,this.flag);
+				},
+				// 切换地址
+				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();
+						},
+						fail:(res)=>{
+							console.log(res)
+							// #ifdef MP
+							uni.getSetting({
+								success: res=>{
+									if(typeof(res.authSetting['scope.userLocation']) != 'undefined' && !res.authSetting['scope.userLocation']){
+									  uni.setStorageSync('refuseLocation', true);
+									}
+								}
+							})
+							// #endif
+						}
+						// complete: function() {
+						// 	self.getList();
+						// }
+					});
+					// #ifdef H5	
+				}
+				// #endif
+			},
+			getList: function(id) {
+				let data = {
+					latitude: this.user_latitude || "", //纬度
+					longitude: this.user_longitude || "", //经度
+					page: 1,
+					limit: 100,
+					product_id: this.productId,
+					is_store:'',   //查找所有门店列表
+					type: this.type == 'seckill'?1:0,
+					store_id: id?id:this.nearbyStore
+				};
+				storeListApi(data)
+					.then(res => {
+						let list = res.data.list.list;
+						if(!id && 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.$store.getters.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],this.flag);
+					})
+					.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 == 1 && this.isStoreBuy){
+						return false
+					}
+					if(index === '2' || index === '3'){
+						if ((!this.user_latitude || !this.user_longitude) && !uni.getStorageSync('refuseLocation')) {
+							this.selfLocation();
+						}
+					}
+					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);
+					this.$emit('onstoreId',this.storeList[0],index);
+		  },
+		  showLocation(){
+			  if ((!this.user_latitude || !this.user_longitude) && !uni.getStorageSync('refuseLocation')) {
+			  	this.selfLocation();
+			  }
+		  },
+		  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.on2{
+		background: #bbb;
+		color: #fff;
+		border-color: #bbb;
+	}
+	.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>

+ 125 - 0
components/recommend/index.vue

@@ -0,0 +1,125 @@
+<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 class="activityFrame" v-if="item.activity_frame.image" :style="'background-image: url('+item.activity_frame.image+');'"></view>
+				</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">
+	.activityFrame{
+		border-radius: 20rpx;
+	}
+	.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>

+ 207 - 0
components/storeLis/index.vue

@@ -0,0 +1,207 @@
+<template>
+	<!-- 门店列表 -->
+	<view class="list">
+		<view class="item">
+			<view class="name line1"><text class="iconfont icon-shangjiadingdan"></text>{{storeList.name}}</view>
+			<view class="address line1"><text class="font-num" v-if="storeList.range">距您{{ storeList.range }}km</text><text class="spot" v-if="storeList.range">·</text>{{ storeList.address }}{{ ", " + storeList.detailed_address }}</view>
+			
+		</view>
+	</view>
+</template>
+<script>
+	import {
+		storeListApi
+	} from "@/api/store";
+	import {
+		isWeixin
+	} from "@/utils/index";
+	// #ifdef H5
+	import {
+		wechatEvevt,
+		wxShowLocation
+	} from "@/libs/wechat";
+	// #endif
+	import {
+		mapState,
+		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,
+			},
+			type: {
+				type: String,
+				default: ''
+			},
+			storeList: {
+				typeof: Object,
+				default: {}
+			}
+		},
+		data() {
+			return {
+				page: 1,
+				limit: 20,
+				loaded: false,
+				loading: false,
+				system_store: {},
+				user_latitude: 0,
+				user_longitude: 0
+			};
+		},
+		computed: mapState({
+			nearbyStore: state => state.app.nearbyStore
+		}),
+		created() {
+			// try {
+			// 	this.user_latitude = uni.getStorageSync('user_latitude');
+			// 	this.user_longitude = uni.getStorageSync('user_longitude');
+			// 	this.selfLocation();
+			// 	if(!this.$util.checkOpenGPSServiceByAndroidIOS()){
+			// 		this.getList();
+			// 	}
+			// } catch (e) {
+			// 	this.getList();
+			// }
+		},
+		mounted() {
+			// if (this.user_latitude && this.user_longitude) {
+			// 	this.getList();
+			// } else {
+			// 	this.selfLocation();
+			// }
+		},
+		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,
+					type: this.type == 'seckill'?1:0,
+					store_id: this.storeId?this.storeId:this.nearbyStore
+				};
+				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>

+ 197 - 0
components/timeSlot/index.vue

@@ -0,0 +1,197 @@
+<template>
+	<!-- 日期组件 -->
+	<view>
+		<view class="dataList">
+			<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>
+	.dataList {
+		display: flex;
+		justify-content: space-between;
+		padding: 24rpx 30rpx;
+		background-color: #fff;
+		color: #666666;
+		font-size: 26rpx;
+		width: 100%;
+		box-sizing: border-box;
+
+		.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>

+ 159 - 0
components/timeranges/index.vue

@@ -0,0 +1,159 @@
+<template>
+	<view>
+	  <view class="time1" :class='isShow==true?"on":""'>
+	    <view class="top acea-row row-between-wrapper">
+	    	<text @tap="cancel">取消</text>
+	    	<text @tap="confirm">确定</text>
+	    </view>
+	    <picker-view class="picker" :value="value" @change="getime" indicator-style="height:34px;">
+	    	<picker-view-column>
+	    		<view class="hours" v-for="(item,index) in hoursList" :key="index">{{item}}</view>
+	    	</picker-view-column>
+	    	<picker-view-column>
+	    		<view class="minutes" v-for="(item,index) in minutes" :key="index">{{item}}</view>
+	    	</picker-view-column>
+	    	<picker-view-column>
+	    		<view class="center">-</view>
+	    	</picker-view-column>
+	    	<picker-view-column>
+	    		<view class="hours" v-for="(item,index) in hoursList" :key="index">{{item}}</view>
+	    	</picker-view-column>
+	    	<picker-view-column>
+	    		<view class="minutes" v-for="(item,index) in minutes" :key="index">{{item}}</view>
+	    	</picker-view-column>
+	    </picker-view>
+	  </view>
+	  <view class="mask" @tap="cancel" catchtouchmove="true" :hidden="isShow==false"></view>
+	</view>
+</template>
+<script>
+	let minutes=[]
+	for (let i = 0; i <= 59; i++) {
+		if(i<10){
+			i="0"+i
+		}
+	  minutes.push(i)
+	}
+	let hoursList = []
+	for (let i = 0; i <= 23; i++) {
+		if(i<10){
+			i="0"+i
+		}
+	  hoursList.push(i)
+	}
+	export default{
+		props:{
+		  isShow:{
+			type: Boolean,
+			default: false
+		  },
+		  time:{
+		  	type: Array,
+		  	default() {
+		  	  return [];
+		  	}
+		  }
+		},
+		watch:{
+			time:function(){
+				this.value=this.time
+			}
+		},
+		created(){
+			
+		},
+		data(){
+			return{
+				value:this.time,//默认结束开始时间
+				hoursList,
+				minutes,
+			}
+		},
+		methods:{
+			confirm(){
+				let time = this.value[0]+":"+this.value[1]+" - "+this.value[3]+":"+this.value[4]
+				if(this.value[3]>this.value[0] || (this.value[3]==this.value[0] && this.value[4]>=this.value[1])){
+				  this.$emit("confrim",{time:time,val:this.value})
+				}else{
+				  return this.$util.Tips({
+				    title: '开始时间必须小于结束时间'
+				  });
+				}
+			},
+			cancel(){
+				let time = this.value[0]+":"+this.value[1]+" - "+this.value[3]+":"+this.value[4]
+				this.$emit("cancel",{time:time})
+			},
+			getime(e){
+				let val = e.detail.value
+				this.value[0] = this.hoursList[val[0]] 
+				this.value[1] = this.minutes[val[1]] 
+				this.value[2] = val[2]
+				this.value[3] = this.hoursList[val[3]] 
+				this.value[4] = this.minutes[val[4]]
+			},
+		}
+	}
+</script>
+<style lang="scss">
+.time1{
+	width:100%;
+	margin: 0 auto;
+	background-color:#FFFFFF;
+	color: #000;
+	height: 568rpx;
+	position: fixed;
+	bottom: 0;
+	z-index: 99;
+	transform: translate3d(0, 200%, 0);
+	transition: all .3s cubic-bezier(.25, .5, .5, .9);
+	&.on{
+	 transform: translate3d(0, 0, 0);
+	}
+	.top{
+		height: 90rpx;
+		border-bottom: 1px solid #eee;
+		padding: 0 30rpx;
+		text{
+			font-size: 32rpx;
+			&:nth-child(1){
+				color: #888;
+			}
+			&:nth-child(2){
+				color: #007aff;
+			}
+		}
+	}
+	.tip12{
+		width: 100%;
+		height: 100rpx;
+		view{
+			width: 50%;
+			text-align: center;
+			line-height: 100rpx;
+			font-size: 40rpx;
+			color: #000000;
+		}
+	}
+	.hours{
+		font-size: 32rpx;
+		color: #000;
+		line-height:34px; 
+		text-align: center;
+	}
+	.minutes{
+		font-size: 32rpx;
+		color: #000;
+		line-height:34px; 
+		text-align: center;
+	}
+	.center{
+		line-height:34px;
+		text-align: center;
+	}
+}
+.picker{
+	width: 100%;
+	height: 476rpx;
+}
+</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>

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

@@ -0,0 +1,435 @@
+<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.setMultiple('')
+				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>

+ 257 - 0
components/userEvaluation/index.vue

@@ -0,0 +1,257 @@
+<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 class="acea-row row-middle">
+						<text class="iconfont icon-pinglun1"></text>
+						<text>{{item.replyComment?item.replyComment.sum:0}}</text>
+					</view>
+					<view class="iconZan acea-row row-middle" @click.stop="praise(item,indexw)">
+						<text class="icon iconfont" :class="item.is_praise?'icon-weizan font-num':'icon-zan'"></text>
+						<text>{{item.praise}}</text>
+					</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,indexw){
+				if(this.isLogin){
+					if (item.is_praise) {
+						getUnReplyPraise(item.id).then(res => {
+							item.is_praise = !item.is_praise
+							item.praise = item.praise - 1
+							this.$emit('replyFun',this.reply)
+							return this.$util.Tips({
+								title: res.msg
+							});
+						});
+					} else {
+						getReplyPraise(item.id).then(res => {
+							item.is_praise = !item.is_praise
+							item.praise = item.praise + 1
+							this.$emit('replyFun',this.reply)
+							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 .icons .iconZan{
+		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: 20rpx;
+			color: #fff;
+			border-radius: 6rpx;
+			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>

+ 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>

+ 48 - 0
config/app.js

@@ -0,0 +1,48 @@
+// +----------------------------------------------------------------------
+// | 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://shop.yiqucbb.cn`,
+	// 长连接 格式:wss://您的域名 
+	VUE_APP_WS_URL: `wss://shop.yiqucbb.cn/ws`,
+	// #endif
+	// H5配置
+	// #ifdef H5
+	//H5接口是浏览器地址,非单独部署不用修改
+	HTTP_REQUEST_URL:  window.location.protocol + "//" + window.location.host,
+	// 长连接地址,非单独部署不用修改
+	VUE_APP_WS_URL: `wss://${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
+}

+ 44 - 0
config/cache.js

@@ -0,0 +1,44 @@
+// +----------------------------------------------------------------------
+// | 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: 'spid',
+	//缓存经度
+	CACHE_LONGITUDE: 'LONGITUDE',
+	//缓存纬度
+	CACHE_LATITUDE: 'LATITUDE',
+	// 移动网络下视频自动播放
+	NON_WIFI_AUTOPLAY: 'NON_WIFI_AUTOPLAY'
+}

+ 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>
+			<%= htmlWebpackPlugin.options.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
+}

+ 146 - 0
libs/login.js

@@ -0,0 +1,146 @@
+// +----------------------------------------------------------------------
+// | 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);
+	let wechatStatus = uni.getStorageSync('wechatStatus');
+	const BASIC_CONFIG = Cache.get('BASIC_CONFIG')
+	// #ifdef H5
+	if (isWeixin() && wechatStatus) {
+		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
+	let url
+	if (!BASIC_CONFIG.wechat_auth_switch) {
+		url = '/pages/users/binding_phone/index?pageType=0'
+	} else {
+		url = '/pages/users/wechat_login/index'
+	}
+	uni.navigateTo({
+		url
+	})
+	// 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}&spid=${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);
+	});
+}

+ 218 - 0
libs/routine.js

@@ -0,0 +1,218 @@
+// +----------------------------------------------------------------------
+// | 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;
+	}
+	/**
+	 * 获取用户信息
+	 */
+	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();

+ 333 - 0
libs/wechat.js

@@ -0,0 +1,333 @@
+// +----------------------------------------------------------------------
+// | 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,
+	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("spid")))
+				.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

+ 119 - 0
libs/work.js

@@ -0,0 +1,119 @@
+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(window.location.href.split('#')[0]).then(res=>{
+		if (/(iPhone|iPad|iPod|iOS|macintosh|mac os x)/i.test(navigator.userAgent)) {
+			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: res.data.jsApiList // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
+				jsApiList: ["getCurExternalContact", "getCurExternalChat", "getContext", "chooseImage","sendChatMessage","shareAppMessage"]
+			});
+			jWeixin.ready(function() {
+				// resolve(wx);
+				setTimeout(()=>{
+					getWorkAgentConfig(window.location.href.split('#')[0]).then(response=>{
+						let jWeixi = wx;
+						jWeixi.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["spid"],
+	vconsole = query[cookieName.toLowerCase()],
+	md5Crmeb = "b14d1e9baeced9bb7525ab19ee35f2d2", //CRMEB MD5 加密开启vconsole模式
+	md5UnCrmeb = "3dca2162c4e101b7656793a1af20295c"; //UN_CREMB MD5 加密关闭vconsole模式
+
+if (urlSpread !== undefined) {
+	var spid = Cache.get(SPREAD);
+	urlSpread = parseInt(urlSpread);
+	if (!Number.isNaN(urlSpread) && spid !== urlSpread) {
+		Cache.set("spid", urlSpread || 0);
+	} else if (spid === 0 || typeof spid !== "number") {
+		Cache.set("spid", 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();

+ 247 - 0
manifest.json

@@ -0,0 +1,247 @@
+{
+    "name" : "易趣水果",
+    "appid" : "__UNI__8FE1373",
+    "description" : "易趣水果",
+    "versionName" : "2.6.0",
+    "versionCode" : 267,
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "compatible" : {
+            "ignoreVersion" : true
+        },
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : false,
+            "waiting" : false,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {
+            "VideoPlayer" : {},
+            "Share" : {},
+            "OAuth" : {},
+            "Payment" : {},
+            "Maps" : {},
+            "LivePusher" : {},
+            "Geolocation" : {},
+            "Barcode" : {},
+            "Camera" : {}
+        },
+        "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" : "wx69a5bfe28c8b39e6",
+                        "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" : "wx69a5bfe28c8b39e6",
+                        "appsecret" : "ee83a6c94edbc5dd7a5b4614316d85a7",
+                        "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" : "wx6ca9ac1a01f617a1",
+        "setting" : {
+            "urlCheck" : false,
+            "minified" : true,
+            "postcss" : true,
+            "es6" : true
+        },
+        "permission" : {
+            "scope.userLocation" : {
+                "desc" : "你的位置信息将用于和门店的距离长度"
+            }
+        },
+        "requiredPrivateInfos" : [ "getLocation", "chooseLocation", "chooseAddress" ],
+        "usingComponents" : true,
+        /* "lazyCodeLoading" : "requiredComponents", */
+        "optimization" : {
+            "subPackages" : true
+        },
+        "__usePrivacyCheck__" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "h5" : {
+        "devServer" : {
+            "https" : false,
+            "proxy" : {
+                "/api" : {
+                    "target" : "https://shop.yiqucbb.cn",
+                    "changeOrigin" : true
+                }
+            }
+        },
+        "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"
+			}
+		}
+	}
+}

+ 2104 - 0
pages.json

@@ -0,0 +1,2104 @@
+{
+  "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",
+		"disableScroll": true
+      }
+    },
+    {
+      "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": "购物车",
+    	// #ifdef MP || APP-PLUS
+    	"navigationStyle": "custom",
+    	// #endif
+        "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": "binding_phone/index",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationStyle": "custom",
+				"app-plus": {
+					"scrollIndicator": "none"
+				}
+			}
+		},
+        {
+          "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
+            }
+          }
+        },
+		{
+		  "path": "supplier/index",
+		  "style": {
+		    "navigationBarTitleText": "供应商入驻",
+		    "app-plus": {
+		      // #ifdef APP-PLUS
+		      "titleNView": {
+		        "type": "default"
+		      }
+		      // #endif
+		    }
+		  }
+		},
+		{
+		  "path": "supplier_state/index",
+		  "style": {
+		    "navigationBarTitleText": "申请状态",
+		    "app-plus": {
+		      // #ifdef APP-PLUS
+		      "titleNView": {
+		        "type": "default"
+		      }
+		      // #endif
+		    }
+		  }
+		},
+		{
+		  "path": "record_list/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"
+          			// #ifdef MP
+          			,
+          			"disableScroll": true
+          			// #endif
+            // "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": "store_list/index",
+		  "style": {
+			"navigationBarTitleText": "门店列表",
+			"app-plus": {
+				"titleNView": {
+					"type": "default"
+				}
+			}
+		  }
+		},
+        {
+		  //#ifdef APP
+		  "path": "mapnvue/index",
+		  //#endif	
+		  //#ifndef APP
+		  "path": "map/index",
+		  //#endif
+          "style": {
+            "navigationBarTitleText": "门店地图"
+          }
+        }
+		// #ifdef MP || H5
+		,
+		{
+			"path": "group_buy/index",
+			"style": {
+				"navigationBarTitleText": "拼单进行中",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "group_cart/index",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "group_goods/index",
+			"style": {
+				"navigationBarTitleText": "订单详情"
+			}
+		}
+		// #endif
+		// #ifdef MP
+		,
+		{
+			"path": "table_code/index",
+			"style": {
+				"navigationBarTitleText": "商品列表",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "table_confirm/index",
+			"style": {
+				"navigationBarTitleText": "提交订单",
+				"navigationStyle": "custom",
+				"enablePullDownRefresh": true
+			}
+		}
+		// #endif
+      ]
+    },
+    {
+      "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": {
+            // "navigationBarTextStyle": "white",
+            // "navigationBarBackgroundColor": "#E93323",
+            "navigationBarTitleText": "拼团列表",
+            "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
+            }
+        	// #ifdef MP
+        	,
+        	"disableScroll": true
+        	// #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": "black"
+              // #endif
+              ,
+            "app-plus": {
+              // #ifdef APP-PLUS
+              // "titleNView": {
+              // 	"type": "default"
+              // }
+              // #endif
+            }
+        	// #ifdef MP
+        	,
+        	"disableScroll": true
+        	// #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
+            }
+        	// #ifdef MP
+        	,
+        	"disableScroll": true
+        	// #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": "商品列表",
+          			 // #ifndef MP
+          			 "navigationBarTextStyle": "black",
+          			 // #endif
+          			// #ifdef MP
+          			"navigationBarTextStyle": "white",
+          			"navigationStyle": "custom",
+          			// #endif
+            "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
+            }
+          }
+        },
+		{
+		  "path": "lottery/grids/order",
+		  "style": {
+		    "navigationBarTitleText": "中奖商品",
+		    "app-plus": {
+		      // #ifdef APP-PLUS
+		      "titleNView": {
+		        "type": "default"
+		      }
+		      // #endif
+		    }
+		  }
+		},
+		{
+			"path": "verify_record/index",
+			"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}&spid=${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>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 95 - 0
pages/activity/goods_bargain/index.vue


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 427 - 0
pages/activity/goods_bargain_details/index.vue


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

@@ -0,0 +1,355 @@
+<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;
+				this.$util.JumpPath(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;
+						line-height: 41rpx;
+					}
+					.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>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1975 - 0
pages/activity/goods_combination_details/index.vue


+ 1015 - 0
pages/activity/goods_combination_status/index.vue

@@ -0,0 +1,1015 @@
+<template>
+	<div class="group-con" :style="colorStyle">
+		<div class="header acea-row row-between-wrapper">
+			<div class="pictrue"><img :src="storeCombination.image" /></div>
+			<div class="text">
+				<div class="line1" v-text="storeCombination.title"></div>
+				<div class="money">
+					¥
+					<span class="num" v-text="storeCombination.price || 0"></span>
+					<span class="team cart-color" v-text="(storeCombination.people || 0) + '人拼'"></span>
+				</div>
+			</div>
+			<div v-if="pinkBool === -1" class="iconfont icon-pintuanshibai"></div>
+			<div v-else-if="pinkBool === 1" class="iconfont icon-pintuanchenggong font-num"></div>
+		</div>
+		<div class="wrapper">
+			<div class="title acea-row row-center-wrapper" v-if="pinkBool === 0">
+				<div class="line"></div>
+				<div class="name acea-row row-center-wrapper">
+					剩余
+					<CountDown :is-day="false" :tip-text="' '" :day-text="' '" :hour-text="' : '" :minute-text="' : '"
+						:second-text="' '" :datatime="pinkT.stop_time"></CountDown>
+					结束
+				</div>
+				<div class="line"></div>
+			</div>
+			<div class="tips font-num" v-if="pinkBool === 1">恭喜您拼团成功</div>
+			<div class="tips" v-else-if="pinkBool === -1">还差{{ count }}人,拼团失败</div>
+			<div class="tips font-num" v-else-if="pinkBool === 0">拼团中,还差{{ count }}人拼团成功</div>
+			<div class="list acea-row row-middle"
+				:class="[pinkBool === 1 || pinkBool === -1 ? 'result' : '', iShidden ? 'on' : '']">
+				<div class="pictrue">
+					<img :src="pinkT.avatar" />
+					<div class="label">团长</div>
+				</div>
+				<div class="pictrue" v-if="pinkAll.length > 0" v-for="(item, index) in pinkAll" :key="index"><img :src="item.avatar" /></div>
+				<div class="pictrue" v-for="index in count" :key="index">
+					<image class="img-none" src="../static/vacancy.png"> </image>
+				</div>
+			</div>
+			<div v-if="(pinkBool === 1 || pinkBool === -1) && pinkAll.length > 9" class="lookAll acea-row row-center-wrapper"
+				@click="lookAll">
+				{{ iShidden ? '收起' : '查看全部' }}
+				<span class="iconfont" :class="iShidden ? 'icon-xiangshang' : 'icon-xiangxia'"></span>
+			</div>
+			<view class="teamBnt bg-color-red" v-if="!isLogin" @click="getIsLogin">立即登录</view>
+			<div v-if="userBool === 1 && isOk == 0 && pinkBool === 0">
+				<div class="teamBnt bg-color-red" @click="listenerActionSheet">邀请好友参团</div>
+			</div>
+			<div class="teamBnt bg-color-red" v-else-if="userBool === 0 && pinkBool === 0 && count > 0">
+			 <div v-if="endTime" @click="goDetail(storeCombination.id)">我要开团</div>
+			 <div v-else @click="pay">我要参团</div>
+			</div>
+			<div class="teamBnt bg-color-red" v-if="pinkBool === 1 || pinkBool === -1"
+				@click="goDetail(storeCombination.id)">再次开团</div>
+			<div class="cancel" @click="getCombinationRemove"
+				v-if="pinkBool === 0 && userBool === 1 && pinkT.uid == userInfo.uid">
+				<span class="iconfont icon-guanbi3"></span>
+				取消开团
+			</div>
+			<div class="lookOrder" v-if="pinkBool === 1" @click="goOrder">
+				查看订单信息
+				<span class="iconfont icon-xiangyou"></span>
+			</div>
+		</div>
+		<div class="group-recommend">
+			<div class="title acea-row row-between-wrapper">
+				<div>大家都在拼</div>
+				<div class="more" @click="goList">
+					更多拼团
+					<span class="iconfont icon-jiantou"></span>
+				</div>
+			</div>
+			<div class="list acea-row row-middle">
+				<div class="item" v-for="(item, index) in storeCombinationHost" :key="index" @click="goDetail(item.id)">
+					<div class="pictrue">
+						<img :src="item.image" />
+						<div class="team" v-text="item.people + '人团'"></div>
+					</div>
+					<div class="name line1" v-text="item.title"></div>
+					<div class="money font-color-red" v-text="'¥' + item.price"></div>
+				</div>
+			</div>
+		</div>
+		<product-window :attr="attr" :limitNum="1" :iSbnt="1" :productType="storeCombination.product_type" :productId="storeCombination.product_id" @myevent="onMyEvent" @ChangeAttr="ChangeAttr"
+			@ChangeCartNum="ChangeCartNum" @iptCartNum="iptCartNum" @attrVal="attrVal" @goCat="goPay" @deliveryFun="deliveryFun" @onAddressId="onAddressId" @onstoreId="onstoreId"></product-window>
+		<!-- 分享按钮 -->
+		<view class="generate-posters acea-row row-middle" :class="posters ? 'on' : ''">
+			<!-- #ifndef MP -->
+			<button class="item" hover-class='none' v-if="weixinStatus === true" @click="H5ShareBox = true">
+				<!-- <button class="item" hover-class='none' v-if="weixinStatus === true" @click="setShareInfoStatus"> -->
+				<view class="iconfont icon-weixin3"></view>
+				<view class="">发送给朋友</view>
+			</button>
+			<!-- #endif -->
+			<!-- #ifdef MP -->
+			<button class="item" open-type="share" hover-class='none' @click="goFriend">
+				<view class="iconfont icon-weixin3"></view>
+				<view class="">发送给朋友</view>
+			</button>
+			<!-- #endif -->
+			<!-- #ifdef APP-PLUS -->
+			<view class="item" @click="appShare('WXSceneSession')">
+				<view class="iconfont icon-weixin3"></view>
+				<view class="">微信好友</view>
+			</view>
+			<view class="item" @click="appShare('WXSenceTimeline')">
+				<view class="iconfont icon-pengyouquan"></view>
+				<view class="">微信朋友圈</view>
+			</view>
+			<!-- #endif -->
+			<!-- #ifndef APP-PLUS -->
+			<button class="item" hover-class='none' @tap="goPoster">
+				<view class="iconfont icon-haibao"></view>
+				<view class="">生成海报</view>
+			</button>
+			<!-- #endif -->
+		</view>
+		<view class="mask" v-if="posters" @click="listenerActionClose"></view>
+		<!-- 发送给朋友图片 -->
+		<view class="share-box" v-if="H5ShareBox">
+			<image :src="imgHost + '/statics/images/share-info.png'" @click="H5ShareBox = false"></image>
+		</view>
+		<!-- <Product-window v-on:changeFun="changeFun" :attr="attr" :limitNum='1' :iSbnt='1'></Product-window> -->
+		<home v-if="navigation"></home>
+		<!-- #ifdef MP -->
+		<!-- <authorize v-if="isShowAuth" @authColse="authColse" @onLoadFun="onLoadFun"></authorize> -->
+		<!-- #endif -->
+	</div>
+</template>
+<script>
+	import CountDown from '@/components/countDown';
+	import ProductWindow from '@/components/productWindow';
+	import util from '../../../utils/util.js';
+	import {
+		toLogin
+	} from '@/libs/login.js';
+	import {
+		mapGetters
+	} from 'vuex';
+	import {
+		getCombinationPink,
+		postCombinationRemove
+	} from '@/api/activity';
+	import {
+		postCartAdd
+	} from '@/api/store';
+	import home from '@/components/home';
+	const NAME = 'GroupRule';
+	import {
+		TOKENNAME,
+		HTTP_REQUEST_URL
+	} from '@/config/app.js';
+	const app = getApp();
+	import colors from '@/mixins/color.js';
+	export default {
+		name: NAME,
+		components: {
+			CountDown,
+			ProductWindow,
+			home
+		},
+		props: {},
+		mixins:[colors],
+		data: function() {
+			return {
+				currentPinkOrder: '', //当前拼团订单
+				isOk: 0, //判断拼团是否完成
+				pinkBool: 0, //判断拼团是否成功|0=失败,1=成功
+				userBool: 0, //判断当前用户是否在团内|0=未在,1=在
+				pinkAll: [], //团员
+				pinkT: [], //团长信息
+				storeCombination: [], //拼团产品
+				storeCombinationHost: [], //拼团推荐
+				pinkId: 0,
+				count: 0, //拼团剩余人数
+				iShidden: false,
+				isOpen: false, //是否打开属性组件
+				attr: {
+					cartAttr: false,
+					productSelect: {
+						image: '',
+						store_name: '',
+						price: '',
+						quota: 0,
+						unique: '',
+						cart_num: 1,
+						quota_show: 0,
+						product_stock: 0,
+						num: 0
+					},
+					productAttr: [],
+					deliveryType:[],
+					isType:0,
+					relation_id:0,
+					store_self_mention:0
+				},
+				cart_num: '',
+				userInfo: {},
+				posters: false,
+				weixinStatus: false,
+				H5ShareBox: false, //公众号分享图片
+				isAuto: false, //没有授权的不会自动授权
+				isShowAuth: false, //是否隐藏授权
+				attrTxt: '请选择', //属性页面提示
+				attrValue: '', //已选属性
+				imgHost:HTTP_REQUEST_URL,
+				addressId:'',
+				store_id :'',
+				delivery_type:0,
+				store_name:'',
+				endTime:false
+			};
+		},
+		computed: mapGetters({
+			'isLogin': 'isLogin',
+			'userData': 'userInfo'
+		}),
+		watch: {
+			isLogin: {
+				handler: function(newV, oldV) {
+					if (newV) {
+						this.getCombinationPink();
+					}else{
+						this.getIsLogin();
+					}
+				},
+				deep: true
+			},
+			userData: {
+				handler: function(newV, oldV) {
+					if (newV) {
+						this.userInfo = newV;
+						app.globalData.openPages = '/pages/activity/goods_combination_status/index?id=' + this.pinkId;
+					}
+				},
+				deep: true
+			}
+		},
+		onLoad(options) {
+			var that = this;
+			// #ifdef MP
+			if (options.scene) {
+				var value = util.getUrlParams(decodeURIComponent(options.scene));
+				if (typeof value === 'object') {
+					if (value.id) options.id = value.id;
+					//记录推广人uid
+					if (value.spid) app.globalData.spid = value.spid;
+				}
+			}
+			// #endif
+			if (options.id) {
+				that.pinkId = options.id;
+			}
+			// 记录推广人uid;
+			if (options.spid) app.globalData.spid = options.spid;
+			if (that.isLogin == false) {
+				this.$Cache.set('login_back_url', `/pages/activity/goods_combination_status/index?id=${options.id}`);
+				this.getIsLogin();
+			} else {
+				this.getCombinationPink();
+			}
+		},
+		onShow(){
+			uni.removeStorageSync('form_type_cart');
+		},
+		//#ifdef MP
+		/**
+		 * 用户点击右上角分享
+		 */
+		onShareAppMessage: function() {
+			let that = this;
+			return {
+				title: '您的好友' + that.userInfo.nickname + '邀请您参团' + that.storeCombination.title,
+				path: app.globalData.openPages,
+				imageUrl: that.storeCombination.image
+			};
+		},
+		//#endif
+		methods: {
+			onLoadFun(){
+				this.getCombinationPink();
+				this.isShowAuth = false;
+			},
+			getIsLogin(){
+				toLogin()
+			},
+			// 授权关闭
+			// authColse: function(e) {
+			//   this.isShowAuth = e
+			// },
+			// 获取配送方式
+			deliveryFun(e){
+				this.delivery_type = e;
+			},
+			// 获取配送地址id
+			onAddressId(row){
+				this.addressId=row.id
+			},
+			// 获取自提地址id
+			onstoreId(row) {
+			  this.store_id = row.id;
+				this.store_name = row.name;
+			},
+			// app分享
+			// #ifdef APP-PLUS
+			appShare(scene) {
+				let that = this
+				let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
+				let curRoute = routes[routes.length - 1].$page.fullPath // 获取当前页面路由,也就是最后一个打开的页面路由
+				uni.share({
+					provider: "weixin",
+					scene: scene,
+					type: 0,
+					href: `${HTTP_REQUEST_URL}${curRoute}`,
+					title: '您的好友' + that.userInfo.nickname + '邀请您参团' + that.storeCombination.title,
+					imageUrl: that.storeCombination.small_image,
+					success: function(res) {
+						uni.showToast({
+							title: '分享成功',
+							icon: 'success'
+						})
+						that.posters = false;
+					},
+					fail: function(err) {
+						uni.showToast({
+							title: '分享失败',
+							icon: 'none',
+							duration: 2000
+						})
+						that.posters = false;
+					}
+				});
+			},
+			// #endif
+			/**
+			 * 分享打开
+			 * 
+			 */
+			listenerActionSheet: function() {
+				if (this.isLogin == false) {
+					this.getIsLogin();
+				} else {
+					// #ifdef H5
+					if (this.$wechat.isWeixin() === true) {
+						this.weixinStatus = true;
+					}
+					// #endif
+					this.posters = true;
+
+				}
+			},
+			// 分享关闭
+			listenerActionClose: function() {
+				this.posters = false;
+			},
+			// 小程序关闭分享弹窗;
+			goFriend: function() {
+				this.posters = false;
+			},
+			/**
+			 * 购物车手动填写
+			 *
+			 */
+			iptCartNum: function(e) {
+				this.$set(this.attr.productSelect, 'cart_num', e);
+				this.$set(this, 'cart_num', e);
+			},
+			attrVal(val) {
+				this.attr.productAttr[val.indexw].index = this.attr.productAttr[val.indexw].attr_values[val.indexn];
+			},
+			onMyEvent: function() {
+				this.$set(this.attr, 'cartAttr', false);
+				this.$set(this, 'isOpen', false);
+			},
+			//将父级向子集多次传送的函数合二为一;
+			// changeFun: function(opt) {
+			// 	if (typeof opt !== "object") opt = {};
+			// 	let action = opt.action || "";
+			// 	let value = opt.value === undefined ? "" : opt.value;
+			// 	this[action] && this[action](value);
+			// },
+			// changeattr: function(res) {
+			// 	var that = this;
+			// 	that.attr.cartAttr = res;
+			// },
+			//选择属性;
+			ChangeAttr: function(res) {
+				this.$set(this, 'cart_num', 1);
+				let productSelect = this.productValue[res];
+				if (productSelect) {
+					this.$set(this.attr.productSelect, 'image', productSelect.image);
+					this.$set(this.attr.productSelect, 'price', productSelect.price);
+					this.$set(this.attr.productSelect, 'quota', productSelect.quota);
+					this.$set(this.attr.productSelect, 'unique', productSelect.unique);
+					this.$set(this.attr.productSelect, 'cart_num', 1);
+					this.$set(this.attr.productSelect, 'product_stock', productSelect.product_stock);
+					this.$set(this.attr.productSelect, 'quota_show', productSelect.quota_show);
+					this.$set(this, 'attrValue', res);
+					this.$set(this, 'attrTxt', '已选择');
+				} else {
+					this.$set(this.attr.productSelect, 'image', this.storeCombination.image);
+					this.$set(this.attr.productSelect, 'price', this.storeCombination.price);
+					this.$set(this.attr.productSelect, 'quota', 0);
+					this.$set(this.attr.productSelect, 'unique', '');
+					this.$set(this.attr.productSelect, 'cart_num', 0);
+					this.$set(this.attr.productSelect, 'quota_show', 0);
+					this.$set(this.attr.productSelect, 'product_stock', 0);
+					this.$set(this, 'attrValue', '');
+					this.$set(this, 'attrTxt', '请选择');
+				}
+			},
+			ChangeCartNum: function(res) {
+				//changeValue:是否 加|减
+				//获取当前变动属性
+				let productSelect = this.productValue[this.attrValue];
+				if (this.cart_num) {
+					productSelect.cart_num = this.cart_num;
+					this.attr.productSelect.cart_num = this.cart_num;
+				}
+				//如果没有属性,赋值给商品默认库存
+				if (productSelect === undefined && !this.attr.productAttr.length) productSelect = this.attr
+					.productSelect;
+				if (productSelect === undefined) return;
+				let stock = productSelect.stock || 0;
+				let quotaShow = productSelect.quota_show || 0;
+				let quota = productSelect.quota || 0;
+				let productStock = productSelect.product_stock || 0;
+				let num = this.attr.productSelect;
+				let nums = this.storeCombination.num || 0;
+				//设置默认数据
+				if (productSelect.cart_num == undefined) productSelect.cart_num = 1;
+				if (res) {
+					num.cart_num++;
+					let arrMin = [];
+					arrMin.push(nums);
+					arrMin.push(quota);
+					arrMin.push(productStock);
+					let minN = Math.min.apply(null, arrMin);
+					if (num.cart_num >= minN) {
+						this.$set(this.attr.productSelect, 'cart_num', minN ? minN : 1);
+						this.$set(this, 'cart_num', minN ? minN : 1);
+					}
+					// if(quotaShow >= productStock){
+					// 	 if (num.cart_num > productStock) {
+					// 	 	this.$set(this.attr.productSelect, "cart_num", productStock);
+					// 	 	this.$set(this, "cart_num", productStock);
+					// 	 }
+					// }else{
+					// 	if (num.cart_num > quotaShow) {
+					// 		this.$set(this.attr.productSelect, "cart_num", quotaShow);
+					// 		this.$set(this, "cart_num", quotaShow);
+					// 	}
+					// }
+					this.$set(this, 'cart_num', num.cart_num);
+					this.$set(this.attr.productSelect, 'cart_num', num.cart_num);
+				} else {
+					num.cart_num--;
+					if (num.cart_num < 1) {
+						this.$set(this.attr.productSelect, 'cart_num', 1);
+						this.$set(this, 'cart_num', 1);
+					}
+					this.$set(this, 'cart_num', num.cart_num);
+					this.$set(this.attr.productSelect, 'cart_num', num.cart_num);
+				}
+				// if (res) {
+				// 	num.cart_num++;
+				// 	if (num.cart_num > quota) {
+				// 		this.$set(this.attr.productSelect, "cart_num", quota);
+				// 		this.$set(this, "cart_num", quota);
+				// 	}
+				// } else {
+				// 	num.cart_num--;
+				// 	if (num.cart_num < 1) {
+				// 		this.$set(this.attr.productSelect, "cart_num", 1);
+				// 		this.$set(this, "cart_num", 1);
+				// 	}
+				// }
+			},
+			//默认选中属性;
+			DefaultSelect() {
+				let productAttr = this.attr.productAttr,
+					value = [];
+				for (var key in this.productValue) {
+					if (this.productValue[key].quota > 0) {
+						value = this.attr.productAttr.length ? key.split(',') : [];
+						break;
+					}
+				}
+				for (let i = 0; i < productAttr.length; i++) {
+					this.$set(productAttr[i], 'index', value[i]);
+				}
+				//sort();排序函数:数字-英文-汉字;
+				let productSelect = this.productValue[value.join(',')];
+				if (productSelect && productAttr.length) {
+					this.$set(this.attr.productSelect, 'store_name', this.storeCombination.title);
+					this.$set(this.attr.productSelect, 'image', productSelect.image);
+					this.$set(this.attr.productSelect, 'price', productSelect.price);
+					this.$set(this.attr.productSelect, 'quota', productSelect.quota);
+					this.$set(this.attr.productSelect, 'unique', productSelect.unique);
+					this.$set(this.attr.productSelect, 'cart_num', 1);
+					this.$set(this.attr.productSelect, 'product_stock', productSelect.product_stock);
+					this.$set(this.attr.productSelect, 'quota_show', productSelect.quota_show);
+					this.$set(this, 'attrValue', value.join(','));
+					this.attrValue = value.join(',');
+					this.$set(this, 'attrTxt', '已选择');
+				} else if (!productSelect && productAttr.length) {
+					this.$set(this.attr.productSelect, 'store_name', this.storeCombination.title);
+					this.$set(this.attr.productSelect, 'image', this.storeCombination.image);
+					this.$set(this.attr.productSelect, 'price', this.storeCombination.price);
+					this.$set(this.attr.productSelect, 'quota', 0);
+					this.$set(this.attr.productSelect, 'unique', '');
+					this.$set(this.attr.productSelect, 'cart_num', 0);
+					this.$set(this.attr.productSelect, 'product_stock', 0);
+					this.$set(this.attr.productSelect, 'quota_show', 0);
+					this.$set(this, 'attrValue', '');
+					this.$set(this, 'attrTxt', '请选择');
+				} else if (!productSelect && !productAttr.length) {
+					this.$set(this.attr.productSelect, 'store_name', this.storeCombination.title);
+					this.$set(this.attr.productSelect, 'image', this.storeCombination.image);
+					this.$set(this.attr.productSelect, 'price', this.storeCombination.price);
+					this.$set(this.attr.productSelect, 'quota', 0);
+					this.$set(this.attr.productSelect, 'unique', this.storeCombination.unique || '');
+					this.$set(this.attr.productSelect, 'cart_num', 1);
+					this.$set(this.attr.productSelect, 'quota_show', 0);
+					this.$set(this.attr.productSelect, 'product_stock', 0);
+					this.$set(this, 'attrValue', '');
+					this.$set(this, 'attrTxt', '请选择');
+				}
+			},
+			setProductSelect: function() {
+				var that = this;
+				var attr = that.attr;
+				attr.productSelect.image = that.storeCombination.image;
+				attr.productSelect.store_name = that.storeCombination.title;
+				attr.productSelect.price = that.storeCombination.price;
+				attr.productSelect.quota = 0;
+				attr.productSelect.quota_show = 0;
+				attr.productSelect.product_stock = 0;
+				attr.cartAttr = false;
+				that.$set(that, 'attr', attr);
+			},
+			pay: function() {
+				var that = this;
+				that.attr.cartAttr = true;
+				that.isOpen = true;
+			},
+			goPay() {
+				var that = this;
+				var data = {};
+				// that.attr.cartAttr = res;
+				data.productId = that.storeCombination.product_id;
+				data.cartNum = that.attr.productSelect.cart_num;
+				data.uniqueId = that.attr.productSelect.unique;
+				data.combinationId = that.storeCombination.id;
+				data.new = 1;
+				data.store_id = this.store_id;
+				data.addressId = this.addressId;
+				data.delivery_type = this.delivery_type;
+				postCartAdd(data)
+					.then(res => {
+						uni.navigateTo({
+						  url: '/pages/goods/order_confirm/index?new=1&cartId=' + res.data.cartId+'&pinkId=' + that.pinkId+'&delivery_type='+that.delivery_type+'&addressId='+that.addressId+'&store_id='+that.store_id+'&store_name='+that.store_name+'&product_id=' + that.storeCombination.product_id
+						});
+					})
+					.catch(res => {
+						that.$util.Tips({
+							title: res
+						});
+					});
+			},
+			goPoster: function() {
+				var that = this;
+				that.posters = false;
+				uni.navigateTo({
+					url: '/pages/activity/poster-poster/index?type=2&id=' + that.pinkId
+				});
+			},
+			goOrder: function() {
+				var that = this;
+				uni.navigateTo({
+					url: '/pages/goods/order_details/index?order_id=' + that.currentPinkOrder
+				});
+			},
+			//拼团列表
+			goList: function() {
+				uni.navigateTo({
+					url: '/pages/activity/goods_combination/index'
+				});
+			},
+			//拼团详情
+			goDetail: function(id) {
+				this.pinkId = id;
+				uni.navigateTo({
+					url: '/pages/activity/goods_combination_details/index?id=' + id
+				});
+			},
+			//拼团信息
+			getCombinationPink: function() {
+				var that = this;
+				getCombinationPink(that.pinkId)
+					.then(res => {
+						that.$set(that.attr, 'isType', res.data.store_combination.type);
+						that.$set(that.attr, 'relation_id', res.data.store_combination.relation_id);
+						that.$set(that.attr, 'store_self_mention', res.data.store_self_mention);
+						that.$set(that, 'storeCombinationHost', res.data.store_combination_host);
+						res.data.pinkT.stop_time = parseInt(res.data.pinkT.stop_time);
+						let timestamp = Date.parse(new Date())/1000;
+						that.endTime = parseInt(timestamp)>res.data.pinkT.stop_time;
+						that.$set(that, 'storeCombination', res.data.store_combination);
+						that.$set(that.attr.productSelect, 'num', res.data.store_combination.num);
+						that.$set(that, 'pinkT', res.data.pinkT);
+						that.$set(that, 'pinkAll', res.data.pinkAll);
+						that.$set(that, 'count', res.data.count);
+						that.$set(that, 'userBool', res.data.userBool);
+						that.$set(that, 'pinkBool', res.data.pinkBool);
+						that.$set(that, 'isOk', res.data.is_ok);
+						that.$set(that, 'currentPinkOrder', res.data.current_pink_order);
+						that.$set(that, 'userInfo', res.data.userInfo);
+						app.globalData.openPages = '/pages/activity/goods_combination_status/index?id=' + this.pinkId;
+						res.data.store_combination.delivery_type.sort((x,y)=>x - y);
+						that.$set(that.attr, 'deliveryType', res.data.store_combination.delivery_type);
+						that.attr.productAttr = res.data.store_combination.productAttr;
+						that.productValue = res.data.store_combination.productValue;
+						//#ifdef H5
+						that.setOpenShare();
+						//#endif
+						that.setProductSelect();
+						if (that.attr.productAttr != 0) that.DefaultSelect();
+						if(res.data.is_ok==1&&res.data.userBool==0){
+							 return this.$util.Tips({
+							 	title: '你不是该团的成员',
+							 }, () => {
+								 uni.navigateTo({
+									 url: '/pages/activity/goods_combination/index'
+								 })
+							 });
+						}
+					})
+					.catch(err => {
+						return this.$util.Tips({
+							title: err,
+						}, () => {
+							uni.navigateBack()
+							 // uni.switchTab({
+							 // 	 url: '/pages/index/index'
+							 // })
+						});
+					});
+			},
+			//#ifdef H5
+			setOpenShare() {
+				let that = this;
+				let configTimeline = {
+					title: '您的好友' + that.userInfo.nickname + '邀请您参团' + that.storeCombination.title,
+					desc: that.storeCombination.title,
+					link: window.location.protocol + '//' + window.location.host +
+						'/pages/activity/goods_combination_status/index?id=' + that.pinkId + '&spid='+ that.userInfo.uid,
+					imgUrl: that.storeCombination.image
+				};
+				if (this.$wechat.isWeixin()) {
+					this.$wechat
+						.wechatEvevt(['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareAppMessage',
+							'onMenuShareTimeline'
+						], configTimeline)
+						.then(res => {})
+						.catch(res => {
+							if (res.is_ready) {
+								res.wx.updateAppMessageShareData(configTimeline);
+								res.wx.updateTimelineShareData(configTimeline);
+								res.wx.onMenuShareAppMessage(configTimeline);
+								res.wx.onMenuShareTimeline(configTimeline);
+							}
+						});
+				}
+			},
+			//#endif
+			//拼团取消
+			getCombinationRemove: function() {
+				var that = this;
+				postCombinationRemove({
+						id: that.pinkId,
+						cid: that.storeCombination.id
+					})
+					.then(res => {
+						that.$util.Tips({
+							title: res.msg
+						}, {
+							tab: 3
+						});
+					})
+					.catch(res => {
+						that.$util.Tips({
+							title: res
+						});
+					});
+			},
+			lookAll: function() {
+				this.iShidden = !this.iShidden;
+			}
+		}
+	};
+</script>
+<style lang="scss" scoped>
+	.generate-posters {
+		width: 100%;
+		height: 170rpx;
+		background-color: #fff;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		z-index: 300;
+		transform: translate3d(0, 100%, 0);
+		transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
+		border-top: 1rpx solid #eee;
+	}
+
+	.generate-posters.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.generate-posters .item {
+		flex: 1;
+		text-align: center;
+		font-size: 30rpx;
+	}
+
+	.generate-posters .item .iconfont {
+		font-size: 80rpx;
+		color: #5eae72;
+	}
+
+	.generate-posters .item .iconfont.icon-haibao {
+		color: #5391f1;
+	}
+
+	/*开团*/
+	.group-con .header {
+		width: 100%;
+		height: 186rpx;
+		background-color: #fff;
+		border-top: 1px solid #f5f5f5;
+		padding: 0 30rpx;
+		position: relative;
+	}
+
+	.group-con .header .iconfont {
+		font-size: 100rpx;
+		position: absolute;
+		color: #ccc;
+		right: 33rpx;
+		bottom: 20rpx;
+	}
+
+	.group-con .header .pictrue {
+		width: 140rpx;
+		height: 140rpx;
+	}
+
+	.group-con .header .pictrue img {
+		width: 100%;
+		height: 100%;
+		border-radius: 6rpx;
+	}
+
+	.group-con .header .text {
+		width: 540rpx;
+		font-size: 30rpx;
+		color: #222;
+	}
+
+	.group-con .header .text .money {
+		font-size: 24rpx;
+		font-weight: bold;
+		margin-top: 15rpx;
+	}
+
+	.group-con .header .text .money .num {
+		font-size: 32rpx;
+	}
+
+	.group-con .header .text .money .team {
+		padding: 1rpx 10rpx;
+		font-weight: normal;
+		border-radius: 50rpx;
+		font-size: 20rpx;
+		vertical-align: 4rpx;
+		margin-left: 15rpx;
+	}
+
+	.group-con .wrapper {
+		background-color: #fff;
+		margin-top: 20rpx;
+		padding: 2rpx 0 35rpx 0;
+	}
+
+	.group-con .wrapper .title {
+		margin-top: 30rpx;
+	}
+
+	.group-con .wrapper .title .line {
+		width: 136rpx;
+		height: 1px;
+		background-color: #ddd;
+	}
+
+	.group-con .wrapper .title .name {
+		margin: 0 45rpx;
+		font-size: 28rpx;
+		color: #282828;
+	}
+
+	.group-con .wrapper .title .name .time {
+		margin: 0 14rpx;
+	}
+
+	.group-con .wrapper .title .name .timeTxt {
+		color: #fc4141;
+	}
+
+	.group-con .wrapper .title .name /deep/.time .styleAll {
+	    background-color: var(--view-minorColorT);
+	    text-align: center;
+	    border-radius: 3rpx;
+	    font-size: 28rpx;
+	    font-weight: bold;
+	    display: inline-block;
+	    vertical-align: middle;
+	    color: var(--view-theme);
+	    padding: 2rpx 5rpx;
+	}
+
+	.group-con .wrapper .tips {
+		font-size: 30rpx;
+		font-weight: bold;
+		text-align: center;
+		margin-top: 30rpx;
+		color: #999;
+	}
+
+	.group-con .wrapper .list {
+		padding: 0 30rpx;
+		margin-top: 25rpx;
+	}
+
+	.group-con .wrapper .list.result {
+		max-height: 240rpx;
+		overflow: hidden;
+		padding-top: 20rpx;
+	}
+
+	.group-con .wrapper .list.result.on {
+		max-height: 2000rpx;
+	}
+
+	.group-con .wrapper .list .pictrue {
+		width: 94rpx;
+		height: 94rpx;
+		margin: 0 0 29rpx 35rpx;
+		position: relative;
+	}
+	
+	.group-con .wrapper .list .pictrue .label{
+		position: absolute;
+		top:-14rpx;
+		right: -26rpx;
+		width: 78rpx;
+		height: 34rpx;
+		color: #fff;
+		font-size: 24rpx;
+		background-color: var(--view-theme);
+		text-align: center;
+		line-height: 34rpx;
+		border-radius: 40rpx;
+	}
+
+	.group-con .wrapper .list .pictrue img,
+	.group-con .wrapper .list .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 50%;
+		border: 2rpx solid var(--view-theme);
+	}
+
+	.group-con .wrapper .list .pictrue image.img-none {
+		border: none;
+	}
+
+	.group-con .wrapper .lookAll {
+		font-size: 24rpx;
+		color: #282828;
+		padding-top: 10rpx;
+	}
+
+	.group-con .wrapper .lookAll .iconfont {
+		font-size: 25rpx;
+		margin: 2rpx 0 0 10rpx;
+	}
+
+	.group-con .wrapper .teamBnt {
+		font-size: 30rpx;
+		width: 620rpx;
+		height: 86rpx;
+		border-radius: 50rpx;
+		text-align: center;
+		line-height: 86rpx;
+		color: #fff;
+		margin: 21rpx auto 0 auto;
+	}
+
+	.group-con .wrapper .cancel,
+	.group-con .wrapper .lookOrder {
+		text-align: center;
+		font-size: 24rpx;
+		color: #282828;
+		padding-top: 30rpx;
+	}
+
+	.group-con .wrapper .cancel .iconfont {
+		font-size: 35rpx;
+		color: #2c2c2c;
+		vertical-align: -4rpx;
+		margin-right: 9rpx;
+	}
+
+	.group-con .wrapper .lookOrder .iconfont {
+		font-size: 25rpx;
+		color: #2c2c2c;
+		margin-left: 10rpx;
+	}
+
+	.group-con .group-recommend {
+		background-color: #fff;
+		margin-top: 25rpx;
+	}
+
+	.group-con .group-recommend .title {
+		padding-right: 30rpx;
+		margin-left: 30rpx;
+		height: 85rpx;
+		border-bottom: 1px solid #eee;
+		font-size: 28rpx;
+		color: #282828;
+	}
+
+	.group-con .group-recommend .title .more {
+		color: #808080;
+	}
+
+	.group-con .group-recommend .title .more .iconfont {
+		margin-left: 13rpx;
+		font-size: 28rpx;
+	}
+
+	.group-con .group-recommend .list {
+		margin-top: 30rpx;
+	}
+
+	.group-con .group-recommend .list .item {
+		width: 210rpx;
+		margin: 0 0 25rpx 30rpx;
+	}
+
+	.group-con .group-recommend .list .item .pictrue {
+		width: 100%;
+		height: 210rpx;
+		position: relative;
+	}
+
+	.group-con .group-recommend .list .item .pictrue img {
+		width: 100%;
+		height: 100%;
+		border-radius: 10rpx;
+	}
+
+	.group-con .group-recommend .list .item .pictrue .team {
+		position: absolute;
+		top: 28rpx;
+		left: -5rpx;
+		min-width: 100rpx;
+		height: 36rpx;
+		line-height: 36rpx;
+		text-align: center;
+		border-radius: 0 18rpx 18rpx 0;
+		font-size: 20rpx;
+		color: #fff;
+		background-color: var(--view-theme);
+		// background-image: linear-gradient(to right, #fb5445 0%, #e93323 100%);
+	}
+
+	.group-con .group-recommend .list .item .name {
+		font-size: 28rpx;
+		color: #333;
+		margin-top: 0.18rem;
+	}
+
+	.group-con .group-recommend .list .item .money {
+		font-weight: bold;
+		font-size: 28rpx;
+	}
+
+	.share-box {
+		z-index: 1000;
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+
+		image {
+			width: 100%;
+			height: 100%;
+		}
+	}
+</style>

+ 394 - 0
pages/activity/goods_seckill/index.vue

@@ -0,0 +1,394 @@
+<template>
+  <!-- 限时秒杀模块 -->
+	<div :style="colorStyle">
+		<view class='flash-sale'>
+			<view class="saleBox"></view>
+			<view class='header' v-if="timeList.length>0">
+				<image :src='timeList[active].slide'></image>
+			</view>
+			<view class="seckillList acea-row row-between-wrapper">
+				<view class="priceTag">
+					<image src="../static/priceTag.png"></image>
+				</view>
+				<view class='timeLsit'>
+					<scroll-view class="scroll-view_x style-add" scroll-x scroll-with-animation :scroll-left="scrollLeft"  :scroll-into-view="intoindex">
+						<block v-for="(item,index) in timeList" :key='index'>
+							<view @tap='settimeList(item,index)' class='item' :class="active == index?'on':''" :id='"sort"+index'>
+								<view class='time'>{{item.time}}</view>
+								<view class="state">{{item.state}}</view>
+							</view>
+						</block>
+					</scroll-view>
+				</view>
+			</view>
+			<view class='list'>
+				<block v-for="(item,index) in seckillList" :key='index'>
+					<view class='item acea-row row-between-wrapper' @tap='goDetails(item)'>
+						<view class='pictrue'>
+							<image :src='item.image'></image>
+							<view class="activityFrame" v-if="item.activity_image" :style="'background-image: url('+item.activity_image+');'"></view>
+						</view>
+						<view class='text acea-row row-column-around'>
+							<view class='name line1'>{{item.title}}</view>
+							<view class='money'>
+								<text class="font-color">¥</text>
+								<text class='num font-color'>{{item.price}}</text>
+								<text class="y_money">¥{{item.ot_price}}</text>
+							</view>
+							<view class="limit">限量 <text class="limitPrice">{{item.quota_show}}{{item.unit_name || ''}}</text></view>
+							<view class="progress">
+								<view class='bg-reds' :style="'width:'+item.percent+'%;'"></view>
+								<view class='piece'>已抢{{item.percent}}%</view>
+							</view>
+						</view>
+						<view class='grab bg-color' v-if="status == 1">马上抢</view>
+						<view class='grab bg-color' v-else-if="status == 2">未开始</view>
+						<view class='grab bg-color-hui' v-else>已结束</view>
+					</view>
+				</block>
+			</view>
+		</view>
+		<view class="no-goods" v-if="seckillList.length == 0 && (page != 1 || active== 0)">
+			<image :src="imgHost + '/statics/images/no-thing.png'" mode=""></image>
+			<text class="tip">暂无秒杀商品,去看看其他商品吧~</text>
+		</view>
+		<home v-if="navigation"></home>
+	</div>
+</template>
+
+<script>
+	import {
+		getSeckillIndexTime,
+		getSeckillList
+	} from '../../../api/activity.js';
+	import home from '@/components/home/index.vue'
+	import colors from '@/mixins/color.js'
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default {
+		components: {
+			home
+		},
+		mixins:[colors],
+		data() {
+			return {
+				topImage: '',
+				seckillList: [],
+				timeList: [],
+				active: 5,
+				scrollLeft: 0,
+				interval: 0,
+				status: 1,
+				countDownHour: "00",
+				countDownMinute: "00",
+				countDownSecond: "00",
+				page: 1,
+				limit: 8,
+				loading: false,
+				loadend: false,
+				pageloading: false,
+				intoindex:'',
+				imgHost:HTTP_REQUEST_URL
+			}
+		},
+		onLoad() {
+			this.getSeckillConfig();
+		},
+		onShow(){
+			uni.removeStorageSync('form_type_cart');
+		},
+		methods: {
+			getSeckillConfig: function() {
+				let that = this;
+				getSeckillIndexTime().then(res => {
+					that.topImage = res.data.lovely;
+					that.timeList = res.data.seckillTime;
+					that.active = res.data.seckillTimeIndex;
+					that.$nextTick(()=>{
+						that.intoindex = 'sort'+res.data.seckillTimeIndex
+					})
+					if (that.timeList.length) {
+						// wxh.time(that.data.timeList[that.data.active].stop, that);
+						that.scrollLeft = (that.active - 1.37) * 100
+						setTimeout(function() {
+							that.loading = true
+						}, 2000);
+						that.seckillList = [],
+							that.page = 1
+						that.status = that.timeList[that.active].status
+						that.getSeckillList();
+					}
+				});
+			},
+			getSeckillList: function() {
+				var that = this;
+				var data = {
+					page: that.page,
+					limit: that.limit
+				};
+				if (that.loadend) return;
+				if (that.pageloading) return;
+				this.pageloading = true
+				getSeckillList(that.timeList[that.active].id, data).then(res => {
+					var seckillList = res.data;
+					var loadend = seckillList.length < that.limit;
+					that.page++;
+					that.seckillList = that.seckillList.concat(seckillList),
+						that.page = that.page;
+					that.pageloading = false;
+					that.loadend = loadend;
+				}).catch(err => {
+					that.pageloading = false
+				});
+			},
+			settimeList: function(item, index) {
+				var that = this;
+				this.active = index
+				if (that.interval) {
+					clearInterval(that.interval);
+					that.interval = null
+				}
+				that.interval = 0,
+					that.countDownHour = "00";
+				that.countDownMinute = "00";
+				that.countDownSecond = "00";
+				that.status = that.timeList[that.active].status;
+				that.loadend = false;
+				that.page = 1;
+				that.seckillList = [];
+				// wxh.time(e.currentTarget.dataset.stop, that);
+				that.getSeckillList();
+			},
+			goDetails(item){
+				uni.navigateTo({
+					url: '/pages/activity/goods_seckill_details/index?id=' + item.id + '&time=' + this.timeList[this.active].stop + '&status=' + this.status + '&time_id=' + this.timeList[this.active].id
+				})
+			}
+		},
+		/**
+		 * 页面上拉触底事件的处理函数
+		 */
+		onReachBottom: function() {
+			this.getSeckillList();
+		}
+	}
+</script>
+
+<style lang="scss">
+  .style-add {
+    width:auto;
+    overflow:hidden;
+    height:106rpx;
+  }
+	page {
+		background-color: #F5F5F5 !important;
+	}
+	.no-goods{
+		margin: 0 30rpx;
+		background-color: #fff;
+		text-align: center;
+		padding: 20rpx 0 100rpx 0;
+		color: #999;
+		border-radius: 10rpx;
+		image{
+			width: 414rpx;
+			height: 304rpx;
+			margin: 40rpx auto 0 auto;
+			display: block;
+			}
+	}
+	.flash-sale .header {
+		width: 710rpx;
+		height: 300rpx;
+		margin: -215rpx auto 0 auto;
+		border-radius: 20rpx;
+	}
+
+	.flash-sale .header image {
+		width: 100%;
+		height: 100%;
+		border-radius: 20rpx;
+	}
+
+	.flash-sale .seckillList {
+		padding: 0 20rpx;
+	}
+
+	.flash-sale .seckillList .priceTag {
+		width: 75rpx;
+		height: 70rpx;
+	}
+
+	.flash-sale .seckillList .priceTag image {
+		width: 100%;
+		height: 100%;
+	}
+
+	.flash-sale .timeLsit {
+		width: 610rpx;
+		white-space: nowrap;
+		margin: 10rpx 0;
+	}
+
+	.flash-sale .timeLsit .item {
+		display: inline-block;
+		font-size: 20rpx;
+		color: #666;
+		text-align: center;
+		padding: 11rpx 0;
+		box-sizing: border-box;
+		height: 96rpx;
+		margin-right: 35rpx;
+	}
+
+	.flash-sale .timeLsit .item .time {
+		font-size: 36rpx;
+		font-weight: 600;
+		color: #333;
+	}
+
+	.flash-sale .timeLsit .item.on .time {
+		color: var(--view-theme);
+	}
+
+	.flash-sale .timeLsit .item.on .state {
+		width: 90rpx;
+		height: 30rpx;
+		border-radius: 15rpx;
+		background: var(--view-theme);
+		color: #fff;
+	}
+
+	.flash-sale .countDown {
+		height: 92rpx;
+		border-bottom: 1rpx solid #f0f0f0;
+		margin-top: -14rpx;
+		font-size: 28rpx;
+		color: #282828;
+	}
+
+	.flash-sale .countDown .num {
+		font-size: 28rpx;
+		font-weight: bold;
+		background-color: #ffcfcb;
+		padding: 4rpx 7rpx;
+		border-radius: 3rpx;
+	}
+
+	.flash-sale .countDown .text {
+		font-size: 28rpx;
+		color: #282828;
+		margin-right: 13rpx;
+	}
+
+	.flash-sale .list .item {
+		height: 230rpx;
+		position: relative;
+		width: 710rpx;
+		margin: 0 auto 20rpx auto;
+		background-color: #fff;
+		border-radius: 20rpx;
+		padding: 0 25rpx;
+	}
+
+	.flash-sale .list .item .pictrue {
+		width: 180rpx;
+		height: 180rpx;
+		border-radius: 10rpx;
+		position: relative;
+	}
+	
+	.activityFrame{
+		border-radius: 10rpx;
+	}
+
+	.flash-sale .list .item .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 10rpx;
+	}
+
+	.flash-sale .list .item .text {
+		width: 460rpx;
+		font-size: 30rpx;
+		color: #333;
+		height: 166rpx;
+	}
+
+	.flash-sale .list .item .text .name {
+		width: 100%;
+	}
+
+	.flash-sale .list .item .text .money {
+		font-size: 30rpx;
+		color: #E93323;
+	}
+
+	.flash-sale .list .item .text .money .num {
+		font-size: 40rpx;
+		font-weight: 500;
+		font-family: 'Guildford Pro';
+	}
+
+	.flash-sale .list .item .text .money .y_money {
+		font-size: 24rpx;
+		color: #999;
+		text-decoration-line: line-through;
+		margin-left: 15rpx;
+	}
+
+	.flash-sale .list .item .text .limit {
+		font-size: 22rpx;
+		color: #999;
+		margin-bottom: 5rpx;
+	}
+
+	.flash-sale .list .item .text .limit .limitPrice {
+		margin-left: 10rpx;
+	}
+
+	.flash-sale .list .item .text .progress {
+		overflow: hidden;
+		background-color: #FFEFEF;
+		width: 260rpx;
+		border-radius: 18rpx;
+		height: 18rpx;
+		position: relative;
+	}
+
+	.flash-sale .list .item .text .progress .bg-reds {
+		width: 0;
+		height: 100%;
+		transition: width 0.6s ease;
+		background: linear-gradient(90deg, rgba(233, 51, 35, 1) 0%, rgba(255, 137, 51, 1) 100%);
+	}
+
+	.flash-sale .list .item .text .progress .piece {
+		position: absolute;
+		left: 8%;
+		transform: translate(0%, -50%);
+		top: 49%;
+		font-size: 16rpx;
+		color: #FFB9B9;
+	}
+
+	.flash-sale .list .item .grab {
+		font-size: 28rpx;
+		color: #fff;
+		width: 150rpx;
+		height: 54rpx;
+		border-radius: 27rpx;
+		text-align: center;
+		line-height: 54rpx;
+		position: absolute;
+		right: 30rpx;
+		bottom: 30rpx;
+		background: #bbbbbb;
+	}
+
+	.flash-sale .saleBox {
+		width: 100%;
+		height: 230rpx;
+		background: var(--view-theme);
+		border-radius: 0 0 50rpx 50rpx;
+	}
+</style>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác