cmy 9 months ago
commit
94b0f513fc
100 changed files with 26553 additions and 0 deletions
  1. 27 0
      .gitignore
  2. 476 0
      App.vue
  3. 275 0
      README.md
  4. 28 0
      androidPrivacy.json
  5. 393 0
      api/activity.js
  6. 873 0
      api/admin.js
  7. 489 0
      api/api.js
  8. 27 0
      api/esp.js
  9. 123 0
      api/kefu.js
  10. 43 0
      api/lottery.js
  11. 305 0
      api/new_store.js
  12. 410 0
      api/order.js
  13. 229 0
      api/public.js
  14. 103 0
      api/short-video.js
  15. 608 0
      api/store.js
  16. 788 0
      api/user.js
  17. 101 0
      api/work.js
  18. 395 0
      components/BaseCalendar.vue
  19. 129 0
      components/BaseMoney.vue
  20. 92 0
      components/BaseTag.vue
  21. 60 0
      components/Loading/index.vue
  22. 141 0
      components/NavBar.vue
  23. 198 0
      components/WaterfallsFlow/WaterfallsFlow.vue
  24. 109 0
      components/WaterfallsFlow/WaterfallsFlowItem.vue
  25. 130 0
      components/addressWindow/index.vue
  26. 340 0
      components/areaWindow/index.vue
  27. 3 0
      components/authorize/index.vue
  28. 75 0
      components/cartDiscount/index.vue
  29. 210 0
      components/cartList/index.vue
  30. 148 0
      components/countDown/index.vue
  31. 221 0
      components/couponListWindow/index.vue
  32. 159 0
      components/couponWindow/index.vue
  33. 137 0
      components/cusPreviewImg/index.vue
  34. 98 0
      components/customForm/index.vue
  35. 271 0
      components/easy-loadimage/easy-loadimage.vue
  36. 340 0
      components/eidtUserModal/index.vue
  37. 45 0
      components/emptyPage.vue
  38. 185 0
      components/ewcomerPop/index.vue
  39. 417 0
      components/filterPopup/index.vue
  40. 218 0
      components/goodClass/index.vue
  41. 140 0
      components/groupGoodsList/index.vue
  42. 150 0
      components/guide/index.vue
  43. 132 0
      components/home/index.vue
  44. 125 0
      components/homeList/index.vue
  45. 814 0
      components/jyf-parser/jyf-parser.vue
  46. 102 0
      components/jyf-parser/libs/CssHandler.js
  47. 577 0
      components/jyf-parser/libs/MpHtmlParser.js
  48. 80 0
      components/jyf-parser/libs/config.js
  49. 35 0
      components/jyf-parser/libs/handler.sjs
  50. 44 0
      components/jyf-parser/libs/handler.wxs
  51. 476 0
      components/jyf-parser/libs/trees.vue
  52. 159 0
      components/kefu/index.vue
  53. 94 0
      components/kefuIcon/index.vue
  54. 252 0
      components/pageFooter/index.vue
  55. 199 0
      components/privacyAgreementPopup/index.vue
  56. 264 0
      components/productConSwiper/index.vue
  57. 907 0
      components/productWindow/index.vue
  58. 59 0
      components/recommend/index.vue
  59. 198 0
      components/skeleton/index.vue
  60. 45 0
      components/specs/index.vue
  61. 257 0
      components/splitOrder/index.vue
  62. 181 0
      components/thorui/tui-collapse.vue
  63. 140 0
      components/thorui/tui-drawer.vue
  64. 178 0
      components/thorui/tui-list-cell.vue
  65. 204 0
      components/timeSlot/index.vue
  66. 159 0
      components/timeranges/index.vue
  67. 144 0
      components/tui-drawer/tui-drawer.vue
  68. 209 0
      components/tui-modal/index.vue
  69. 315 0
      components/tui-swipe-action/index.vue
  70. 546 0
      components/uni-calendar/calendar.js
  71. 152 0
      components/uni-calendar/uni-calendar-item.vue
  72. 435 0
      components/uni-calendar/uni-calendar.vue
  73. 327 0
      components/uni-calendar/util.js
  74. 398 0
      components/uniNoticeBar/uni-notice-bar.vue
  75. 137 0
      components/userEvaluation/index.vue
  76. 1201 0
      components/zb-code/qrcode.js
  77. 210 0
      components/zb-code/zb-code.vue
  78. 46 0
      config/cache.js
  79. 18 0
      config/socket.js
  80. 33 0
      index.html
  81. 272 0
      js_sdk/wa-permission/permission.js
  82. 146 0
      libs/login.js
  83. 9 0
      libs/network.js
  84. 257 0
      libs/new_chat.js
  85. 44 0
      libs/order.js
  86. 217 0
      libs/routine.js
  87. 333 0
      libs/wechat.js
  88. 119 0
      libs/work.js
  89. 92 0
      main.js
  90. 240 0
      manifest.json
  91. 41 0
      mixins/SendVerifyCode.js
  92. 37 0
      mixins/color.js
  93. 124 0
      mixins/location.js
  94. 356 0
      mixins/skuSelect.js
  95. 399 0
      package-lock.json
  96. 1904 0
      pages.json
  97. 180 0
      pages/activity/bargain/index.vue
  98. 393 0
      pages/activity/coupon/index.vue
  99. 256 0
      pages/activity/goods_bargain/index.vue
  100. 1573 0
      pages/activity/goods_bargain_details/index.vue

+ 27 - 0
.gitignore

@@ -0,0 +1,27 @@
+.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
+/config/app.js

+ 476 - 0
App.vue

@@ -0,0 +1,476 @@
+<script>
+	import {checkLogin} from './libs/login';
+	import {HTTP_REQUEST_URL} from './config/app';
+	import { LOGIN_STATUS } from "./config/cache.js"
+	import { getShopConfig, silenceAuth, getLogo } from '@/api/public';
+	import Auth from '@/libs/wechat.js';
+	import Routine from './libs/routine.js';
+	import { colorChange, copyRight } from '@/api/api.js';
+	import { getUserInfo } from "@/api/user.js" 
+	import { mapGetters } from "vuex"
+	import { silenceBindingSpread } from "@/utils/index.js";
+	// #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-gradient:#4DEA4D'
+	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-gradient:#FF7931'
+	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-gradient:#5ACBFF'
+	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-gradient:#FF67AD'
+	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-gradient:#FF9451'
+	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;--view-gradient:#FFCD8C'
+	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) {
+			uni.hideTabBar()
+			//#ifdef APP
+			plus.screen.lockOrientation("portrait-primary");
+			//#endif
+			let that = this;
+			getLogo().then(res => {
+				uni.setStorageSync('BASIC_CONFIG', res.data)
+			});
+			//获取配置
+			copyRight().then(res => {
+				let data = res.data;
+				uni.setStorageSync('wechatStatus', data.wechat_status)
+				// #ifndef APP-PLUS
+				this.site_config = data.record_No;
+				// #endif
+				if(!data.copyrightContext && !data.copyrightImage){
+					data.copyrightImage = '/static/images/support.png'
+				}
+				uni.setStorageSync('copyNameInfo', data.copyrightContext);
+				uni.setStorageSync('copyImageInfo', data.copyrightImage);
+				// #ifdef MP
+				uni.setStorageSync('MPSiteData', JSON.stringify({site_logo:data.site_logo,site_name:data.site_name}));
+				// #endif
+			}).catch(err => {
+				return this.$util.Tips({
+					title: err.msg
+				});
+			});
+			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
+				}
+			});
+			// 通过vuex获取并储存商品详情,商品分类可视化的数据
+			this.$store.dispatch("getDiyProduct");
+			// 判断分销uid
+			if (option.query.spid) {
+				that.$Cache.set('spid', option.query.spid);
+				that.globalData.spid = option.query.spid;
+				silenceBindingSpread();
+			}
+			// #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')) {
+				let val = that.$util.getUrlParams(decodeURIComponent(option.query.scene));
+				switch (option.scene) {
+					//扫描小程序码
+					case 1047:
+						that.globalData.spid = val.spid === undefined ? val : val.spid;
+						break;
+						//长按图片识别小程序码
+					case 1048:
+					    that.globalData.spid = val.spid === undefined ? val : val.spid;
+						that.globalData.code = option.query.scene;
+						break;
+						//手机相册选取小程序码
+					case 1049:
+					    that.globalData.spid = val.spid === undefined ? val : val.spid;
+						that.globalData.code = option.query.scene;
+						break;
+						//直接进入小程序
+					case 1001:
+						that.globalData.spid = val.spid === undefined ? val : val.spid;
+						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();
+				});
+			}else if(this.$store.getters.isLogin && this.getExpired()){
+				//处理小程序有token情况下但是静默授权失败
+				this.$Cache.clear(LOGIN_STATUS);
+				Routine.getCode().then(code => {
+					this.silenceAuth(code);
+				})
+			}
+			// #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
+		},
+		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: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
+					})
+				}
+			},
+			async getExpired(){
+				// 通过一个个人中心的接口判断token是否生效,catch捕获到就证明token过期,返回true
+				try {
+					await getUserInfo();
+					return false; // token有效
+				} catch (err) {
+					return true; // token过期
+				}
+			}
+		},
+	};
+</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/unocss.css';
+	@import 'static/fonts/font.scss';
+
+	view {
+		box-sizing: border-box;
+	}
+
+	page {
+		font-family: PingFang SC;
+	}
+
+	.placeholder{
+		color: #ccc;
+	}
+
+	.bg-color-red {
+		background-color: var(--view-theme) !important;
+	}
+
+	.syspadding {
+		padding-top: var(--status-bar-height);
+	}
+
+	.flex {
+		display: flex;
+	}
+
+	.uni-scroll-view::-webkit-scrollbar {
+		/* 隐藏滚动条,但依旧具备可以滚动的功能 */
+		display: none;
+	}
+
+	::-webkit-scrollbar {
+		width: 0;
+		height: 0;
+		color: transparent;
+	}
+
+	.uni-system-open-location .map-content.fix-position {
+		height: 100vh;
+		top: 0;
+		bottom: 0;
+	}
+	/* #endif */
+</style>

+ 275 - 0
README.md

@@ -0,0 +1,275 @@
+# 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
+
+# 启动项目(本地开发环境)
+点击运行
+
+# 打包项目
+点击发行
+~~~
+
+

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

+ 393 - 0
api/activity.js

@@ -0,0 +1,393 @@
+// +----------------------------------------------------------------------
+// | 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 activityCodeApi(type, id, data) {
+	return request.get(`get_qrcode/${type}/${id}`, data);
+}
+
+/**
+ * 获取砍价海报详细信息
+ */
+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, {
+		noAuth: true
+	});
+}
+
+/**
+ * 限时折扣商品列表
+ */
+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}`);
+}
+
+/**
+ * 获取新人礼信息
+ *
+ */
+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');
+}
+
+/**
+ * 积分商城
+ */
+export function getStoreIntegral(data) {
+	return request.get("store_integral/index", data, {
+		noAuth: true
+	});
+}
+
+
+/**
+ * 积分商城积分范围导航
+ */
+export function getIntegralCategory() {
+	return request.get("store_integral/category");
+}
+
+/**
+ * 首页排行榜
+ */
+export function diyRankApi() {
+	return request.get("diy/product_rank",{},{
+		noAuth: true
+	});
+}

+ 873 - 0
api/admin.js

@@ -0,0 +1,873 @@
+// +----------------------------------------------------------------------
+// | 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 getStoreOrderList(where) {
+	return request.get("store/order/list", where, {
+		login: true
+	});
+}
+/**
+ * 平台-提醒发货
+ */
+export function getDelivery(id) {
+	return request.get(`admin/order/delivery/remind/${id}`,{
+		login: true
+	});
+}
+
+/**
+ * 订单改价
+ */
+export function setAdminOrderPrice(data) {
+	return request.post("admin/order/price", data, {
+		login: true
+	});
+}
+/**
+ * 门店中心-订单改价
+ */
+export function setStoreOrderPrice(data) {
+	return request.post("store/order/price", data, {
+		login: true
+	});
+}
+/**
+ * 订单备注
+ */
+export function setAdminOrderRemark(data) {
+	return request.post("admin/order/remark", data, {
+		login: true
+	});
+}
+/**
+ * 门店-订单备注
+ */
+export function setStoreOrderRemark(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 setStoreRefundRemark(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 getStoreOrderDetail(orderId) {
+	return request.get("store/order/detail/" + orderId, {}, {
+		login: true
+	});
+}
+
+/**
+ * 订单详情(退款)
+ */
+export function getAdminRefundDetail(orderId) {
+	return request.get("admin/refund_order/detail/" + orderId, {}, {
+		login: true
+	});
+}
+
+/**
+ * 门店-订单详情(退款)
+ */
+export function getStoreRefundDetail(orderId) {
+	return request.get("store/refund_order/detail/" + orderId, {}, {
+		login: true
+	});
+}
+
+/**
+ * 订单发货信息获取
+ */
+export function getAdminOrderDelivery(orderId) {
+	return request.get(
+		"admin/order/delivery/gain/" + orderId, {}, {
+			login: true
+		}
+	);
+}
+
+/**
+ * 门店中心-订单发货信息获取
+ */
+export function getStoreOrderDelivery(orderId) {
+	return request.get(
+		"store/order/delivery/gain/" + orderId, {}, {
+			login: true
+		}
+	);
+}
+
+/**
+ * 订单发货保存
+ */
+export function setAdminOrderDelivery(id, data) {
+	return request.post("admin/order/delivery/keep/" + id, data, {
+		login: true
+	});
+}
+
+/**
+ * 门店-订单发货保存
+ */
+export function setStoreOrderDelivery(id, data) {
+	return request.post("store/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 setStoreOfflinePay(data) {
+	return request.post("store/order/offline", data, {
+		login: true
+	});
+}
+/**
+ * 订单确认退款
+ */
+export function setOrderRefund(data) {
+	return request.post("admin/order/refund", data, {
+		login: true
+	});
+}
+
+/**
+ * 门店中心 - 订单确认退款
+ */
+export function setStoreOrderRefund(data) {
+	return request.post("store/order/refund", data, {
+		login: true
+	});
+}
+
+/**
+ * 获取快递公司
+ * @returns {*}
+ */
+export function getLogistics(data) {
+	return request.get("logistics", data, {
+		login: false
+	});
+}
+
+/**
+ * 订单核销
+ * @returns {*}
+ */
+export function orderVerific(code, auth) {
+	return request.post("admin/order/order_verific", {
+		code,
+		auth,
+	});
+}
+
+/**
+ * 门店-订单核销
+ * @returns {*}
+ */
+export function storeOrderVerific(code, auth) {
+	return request.post("store/order/order_verific", {
+		code,
+		auth,
+	});
+}
+
+/**
+ * 获取物流公司模板
+ * @returns {*}
+ */
+export function orderExportTemp(data) {
+	return request.get("admin/order/export_temp", data);
+}
+
+/**
+ * 门店-获取物流公司模板
+ * @returns {*}
+ */
+export function storeOrderExportTemp(data) {
+	return request.get("store/order/export_temp", data);
+}
+
+/**
+ * 获取订单打印默认配置
+ * @returns {*}
+ */
+export function orderDeliveryInfo() {
+	return request.get("admin/order/delivery_info");
+}
+
+/**
+ * 门店-获取订单打印默认配置
+ * @returns {*}
+ */
+export function storeOrderDeliveryInfo() {
+	return request.get("store/order/delivery_info");
+}
+
+/**
+ * 配送员列表
+ * @returns {*}
+ */
+export function orderOrderDelivery() {
+	return request.get("admin/order/delivery");
+}
+
+/**
+ * 门店-配送员列表
+ * @returns {*}
+ */
+export function storeOrderDelivery() {
+	return request.get("store/order/delivery");
+}
+
+
+// 门店
+
+/**
+ * 店员用户信息
+ */
+export function userInfo() {
+	return request.get("store/staff/info");
+}
+
+/**
+ * 工作台-今日销售额统计
+ */
+export function staffStaging(data) {
+	return request.get("store/staff/staging",data);
+}
+
+/**
+ * 工作台-数据统计
+ */
+export function statisticsMenuApi(data) {
+	return request.get("store/staff/statistics",data);
+}
+
+/**
+ * 门店中心-订单统计
+ */
+export function orderInfo(data) {
+	return request.get("store/order/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 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 adminCartDel(uid,data) {
+	return request.delete(`admin/order/cart/del/${uid}`,data);
+}
+
+/**
+ * 代客下单-修改购物车数量
+ */
+export function adminCartNum(uid,data) {
+	return request.post(`admin/order/cart/num/${uid}`,data);
+}
+
+
+
+
+
+/**
+ * 配送员-核销订单获取商品信息 (门店平台一个接口)
+ */
+export function orderCartInfo(data) {
+	return request.post("store/order/cart_info",data);
+}
+
+
+/**
+ * 配送员-订单核销 (门店平台一个接口)
+ */
+export function orderWriteoff(data) {
+	return request.post("store/order/writeoff",data);
+}
+
+/**
+ * 统计管理-获取订单可拆分商品列表
+ */
+export function orderSplitInfo(id) {
+	return request.get("admin/order/split_cart_info/"+id);
+}
+
+/**
+ * 门店-统计管理-获取订单可拆分商品列表
+ */
+export function storeOrderSplitInfo(id) {
+	return request.get("store/order/split_cart_info/"+id);
+}
+
+/**
+ * 统计管理-提交
+ */
+export function orderSplitDelivery(id,data) {
+	return request.put("admin/order/split_delivery/"+id,data);
+}
+
+/**
+ * 门店-统计管理-提交
+ */
+export function storeOrderSplitDelivery(id,data) {
+	return request.put("store/order/split_delivery/"+id,data);
+}
+
+/**
+ * 统计管理-退货退款
+ */
+export function orderRefundAgree(id) {
+	return request.post("admin/order/refund_agree/"+id);
+}
+
+/**
+ * 门店中心-退货退款
+ */
+export function storeOrderRefundAgree(id) {
+	return request.post("store/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);
+}
+
+/**
+ * 门店中心-退款列表
+ */
+export function storeRefundList(data) {
+	return request.get("store/refund_order/list",data);
+}
+
+/**
+ * 平台-商品列表
+ */
+export function adminProductList(data) {
+	return request.get("admin/product/admin_list",data);
+}
+
+/**
+ * 门店-商品列表
+ */
+export function storeProductList(data) {
+	return request.get("store/product/admin_list",data);
+}
+
+/**
+ * 平台-商品列表-上下架
+ */
+export function productSetShow(data) {
+	return request.post('admin/product/set_show',data);
+}
+
+/**
+ * 门店-商品列表-上下架
+ */
+export function storeProductSetShow(data) {
+	return request.post('store/product/set_show',data);
+}
+
+/**
+ * 平台-商品列表-标签
+ */
+export function getProductLabel() {
+	return request.get('admin/product/product_label');
+}
+
+/**
+ * 门店-商品列表-标签
+ */
+export function storeProductLabel() {
+	return request.get('store/product/product_label');
+}
+
+/**
+ * 平台-商品列表-提交标签/分类
+ */
+export function postBatchProcess(data) {
+	return request.post('admin/product/batch_process',data);
+}
+
+/**
+ * 门店-商品列表-提交标签/分类
+ */
+export function storeBatchProcess(data) {
+	return request.post('store/product/batch_process',data);
+}
+
+/**
+ * 平台-商品列表-修改库存价格
+ */
+export function postUpdateAttrs(id,data) {
+	return request.post(`admin/product/update_attrs/${id}`,data);
+}
+
+/**
+ * 门店-商品列表-修改库存价格
+ */
+export function postStoreUpdateAttrs(id,data) {
+	return request.post(`store/product/update_attrs/${id}`,data);
+}
+
+/**
+ * 平台-商品列表-获取规格
+ */
+export function getGetAttrs(id) {
+	return request.get(`admin/product/get_attr/${id}`);
+}
+
+/**
+ * 门店-商品列表-获取规格
+ */
+export function getStoreGetAttrs(id) {
+	return request.get(`store/product/get_attr/${id}`);
+}
+
+/**
+ * 平台-商品列表-获取分类
+ */
+export function getCategory() {
+	return request.get(`admin/product/category`);
+}
+
+/**
+ * 门店-商品列表-获取分类
+ */
+export function getStoreCategory() {
+	return request.get(`store/product/category`);
+}
+
+/**
+ * 平台-用户列表
+ */
+export function getUserList(data) {
+	return request.get(`admin/user/list`,data);
+}
+
+/**
+ * 门店-用户列表
+ */
+export function getStoreUserList(data) {
+	return request.get(`store/user/list`,data);
+}
+
+/**
+ * 平台-修改余额、积分
+ */
+export function postUserUpdateOther(uid,data) {
+	return request.post(`admin/user/update_other/${uid}`,data);
+}
+
+/**
+ * 平台-分组列表
+ */
+export function getGroupList() {
+	return request.get(`admin/user/group/list`);
+}
+
+/**
+ * 平台-门店列表
+ */
+export function getStoreGroupList() {
+	return request.get(`store/user/group/list`);
+}
+
+/**
+ * 平台-修改用户信息
+ */
+export function postUserUpdate(data) {
+	return request.post(`admin/user/update`,data);
+}
+
+/**
+ * 平台-优惠券
+ */
+export function getUserCoupon(data) {
+	return request.get(`admin/user/coupon/grant`,data);
+}
+
+/**
+ * 平台-用户标签
+ */
+export function getUserLabel() {
+	return request.get(`admin/user/label/0`);
+}
+
+/**
+ * 门店-用户标签
+ */
+export function getStoreUserLabel() {
+	return request.get(`store/user/label/0`);
+}
+
+/**
+ * 平台-等级列表
+ */
+export function getLevelList() {
+	return request.get(`admin/user/level/list`);
+}
+
+/**
+ * 门店-等级列表
+ */
+export function getStoreLevelList() {
+	return request.get(`store/user/level/list`);
+}
+
+/**
+ * 平台-用户详情
+ */
+export function getUserInfo(uid) {
+	return request.get(`admin/user/info/${uid}`);
+}
+
+/**
+ * 门店-用户详情
+ */
+export function getStoreUserInfo(uid) {
+	return request.get(`store/user/info/${uid}`);
+}
+
+/**
+ * 代客下单-用户列表
+ */
+export function adminUserList(data) {
+	return request.get("admin/user/list",data);
+}
+
+/**
+ * 代客下单-商品分类
+ */
+export function adminCategory() {
+	return request.get("admin/product/category");
+}
+
+/**
+ * 代客下单-商品列表
+ */
+export function adminProList(data) {
+	return request.get("admin/product/list",data);
+}
+
+/**
+ * 代客下单-加入购物车
+ */
+export function adminCartAdd(uid,data) {
+	return request.post(`admin/order/cart/add/${uid}`,data);
+}
+
+/**
+ * 代客下单-购物车列表
+ */
+export function adminCartList(uid,data) {
+	return request.get(`admin/order/cart/${uid}`,data);
+}
+
+/**
+ * 代客下单-用户地址列表
+ */
+export function adminUserAddressList(uid,data) {
+	return request.get(`admin/user/address/list/${uid}`,data);
+}
+
+/**
+ * 代客下单-订单确认
+ */
+export function orderConfirm(uid,data) {
+	return request.post(`admin/order/confirm/${uid}`,data);
+}
+
+/**
+ * 代客下单-订单计算
+ */
+export function postOrderComputed(key,uid,data) {
+	return request.post(`admin/order/computed/${key}/${uid}`,data);
+}
+
+/**
+ * 代客下单-获取用户可使用优惠券列表
+ */
+export function getCouponsOrderPrice(uid,data) {
+	return request.get(`admin/order/coupons/${uid}`,data);
+}
+
+/**
+ * 代客下单-订单查创建
+ */
+export function orderCreate(key,uid,data) {
+	return request.post(`admin/order/create/${key}/${uid}`,data);
+}
+
+/**
+ * 代客下单-订单收银台
+ */
+export function getCashierApi(uid,data) {
+	return request.post(`admin/order/pay/${uid}`,data);
+}
+
+/**
+ * 代客下单-轮询获取订单支付状态
+ */
+export function getPayStatusApi(data) {
+	return request.get(`admin/order/pay/status`,data);
+}
+
+/**
+ * 代客下单-下单订单记录
+ */
+export function adminOrderRecordList(data) {
+	return request.get(`admin/order/place/list`,data);
+}
+
+/**
+ * 工作台折线图数据统计
+ */
+export function getOrderChart(data) {
+	return request.get('admin/order/time/chart', data);
+}
+
+/**
+ * 门店工作台折线图数据统计
+ */
+export function getStoreChart(type,data) {
+	return request.get(`store/staff/chart/${type}`, data);
+}
+
+/**
+ * 工作台待发货等数据
+ */
+export function getOrderStaging() {
+	return request.get('admin/order/staging');
+}
+
+/**
+ * 工作台今日订单数等数据
+ */
+export function getOrderTime(data) {
+	return request.get('admin/order/time', data);
+}
+
+/**
+ * 拆单退款
+ * @param {Object} id
+ * @param {Object} data
+ */
+export function openRefund(id, data) {
+	return request.post(`admin/order/open/refund/${id}`,data);
+}
+
+/**
+ * 核销订单商品列表
+ * @param {Object} data
+ */
+export function offOrderInfo(data) {
+	return request.post(`admin/order/info`,data);
+}
+
+/**
+ * 核销订单
+ * @param {Object} order_id
+ * @param {Object} data
+ */
+export function orderWirteOff(order_id, data) {
+	return request.post(`admin/order/wirteoff/${order_id}`,data);
+}
+
+/**
+ * 订单核销记录
+ * @param {Object} id
+ * @param {Object} data
+ */
+export function orderWirteOffRecords(id, data) {
+	return request.post(`admin/order/writeoff/records/${id}`, data);
+}
+
+/**
+ * 门店-订单核销记录
+ * @param {Object} id
+ * @param {Object} data
+ */
+export function storeWirteOffRecords(id, data) {
+	return request.post(`store/order/writeoff/records/${id}`, data);
+}
+
+/**
+ * 确认订单详情(是否显示快递配送)
+ * @param {Object} data
+ */
+export function check_shipping(data) {
+	return request.post(`admin/order/check_shipping`, data);
+}

+ 489 - 0
api/api.js

@@ -0,0 +1,489 @@
+// +----------------------------------------------------------------------
+// | 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
+	});
+}
+
+
+export function getCouponsNum() {
+	return request.get('coupons/user/num', {}, {
+		noAuth: true
+	});
+}
+
+export function getSign() {
+	return request.get('diy/sign', {}, {
+		noAuth: true
+	});
+}

+ 27 - 0
api/esp.js

@@ -0,0 +1,27 @@
+// +----------------------------------------------------------------------
+// | 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');
+}
+
+/**
+ * 门店-erp设置
+ * 
+ */
+export function storeErpConfig(id,data) {
+	return request.get('store/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');
+}
+
+

+ 410 - 0
api/order.js

@@ -0,0 +1,410 @@
+// +----------------------------------------------------------------------
+// | 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(data) {
+	return request.get('order/data',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
+	});
+}
+
+//再次申请售后
+export function orderRefundAgain(id) {
+	return request.post('order/refund/again/' + id);
+}
+
+/**
+ * 订单收货
+ * @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 data
+ */
+export function getCashierOrder(orderId, type) {
+	return request.get(`order/cashier/${orderId}/${type}`);
+}
+
+
+/**
+ * 获取订单下单奖励
+ * @param object data
+ */
+export function getOrderPrizeApi(orderId) {
+	return request.post(`order/prize/${orderId}`);
+}
+

+ 229 - 0
api/public.js

@@ -0,0 +1,229 @@
+// +----------------------------------------------------------------------
+// | 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
+		}
+	);
+}
+
+/**
+ * 小程序手机号登录
+ * @param {Object} data
+ */
+export function phoneLogin(data) {
+	return request.post('v2/routine/phone_login', 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 wechatBindingPhone(data) {
+	return request.post('v2/wechat/auth_binding_phone', data, {
+		noAuth: true
+	});
+}
+
+
+/**
+ * code生成用户
+ * @returns {*}
+ */
+
+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
+	});
+}
+
+/**
+ * 获取登录授权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
+	});
+}
+/**
+ * 授权登录
+ * @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 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
+	});
+}

+ 103 - 0
api/short-video.js

@@ -0,0 +1,103 @@
+// +----------------------------------------------------------------------
+// | 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
+  );
+}
+
+/**
+ * 热门视频信息
+ * 
+ */
+export function videoInfo(id) {
+  return request.get(
+    `marketing/short_video/info/${id}`
+  );
+}
+
+

+ 608 - 0
api/store.js

@@ -0,0 +1,608 @@
+// +----------------------------------------------------------------------
+// | 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 diyProductApi() {
+	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(data) {
+	return request.get('search/keyword', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取搜索关键字获取
+ * 
+ */
+export function getHotWordApi() {
+	return request.get('search/hot_keyword', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取搜索销量评分商品列表
+ * 
+ */
+export function getSearchRecommendApi(type) {
+	return request.get(`search/recommend/${type}`, {}, {
+		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 searchFilterApi(data) {
+	return request.get("search/filter",data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 分类列表-同级分类
+ */
+export function levelCategoryApi(data) {
+	return request.get("level_category",data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 新人专享商品详情
+ */
+export function newcomerDetail(id) {
+	return request.get("marketing/newcomer/product_detail/"+id,{},{
+		noAuth: true
+	});
+}
+
+/**
+ * 排行榜商品分类
+ */
+export function rankCategoryApi() {
+	return request.get("product/rank/category",{},{
+		noAuth: true
+	});
+}
+
+/**
+ * 排行榜商品列表
+ * @param {type} type 1:销量 2:评分
+ * @param {data} 分页
+ */
+export function rankListApi(type, data) {
+	return request.get(`product/rank/${type}`,data,{
+		noAuth: true
+	});
+}
+
+/**
+ * 搭配够商品列表
+ * @param {id} 商品id
+ * @param {data} 分页参数
+ */
+export function matchPayListApi(id, data) {
+	return request.get(`store_discounts/list/${id}`,data,{
+		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 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);
+}
+
+/**
+ * 拼单购物车列表
+ * @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);
+}
+
+/**
+ * 门店桌码配置
+ */
+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 emptyTableData(data) {
+	return request.get("v2/user/empty/data", 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);
+}

+ 788 - 0
api/user.js

@@ -0,0 +1,788 @@
+// +----------------------------------------------------------------------
+// | 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 getMenuData() {
+	return request.get('menu/date');
+}
+
+/**
+ * 登录成功后更新公众号用户信息
+ */
+export function updateWechatInfo(data) {
+	return request.get('v2/user/wechat', data);
+}
+
+/**
+ * 设置用户分享
+ *
+ */
+export function userShare() {
+	return request.post('user/share');
+}
+
+/**
+ * h5用户登录
+ * @param data object 用户账号密码
+ */
+export function loginH5(data) {
+	return request.post("login", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户手机号登录
+ * @param data object 用户手机号 也只能
+ */
+export function loginMobile(data) {
+	return request.post("login/mobile", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 验证码key
+ */
+export function getCodeApi() {
+	return request.get("verify_code", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户发送验证码
+ * @param data object 用户手机号
+ */
+export function registerVerify(data) {
+	return request.post("register/verify", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户手机号注册
+ * @param data object 用户手机号 验证码 密码
+ */
+export function register(data) {
+	return request.post("register", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户手机号修改密码
+ * @param data object 用户手机号 验证码 密码
+ */
+export function registerReset(data) {
+	return request.post("register/reset", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取用户中心菜单
+ *
+ */
+export function getMenuList() {
+	return request.get("menu/user", {}, {
+		noAuth: true
+	});
+}
+
+/*
+ * 签到用户信息
+ * */
+export function postSignUser(sign) {
+	return request.post("sign/user", sign);
+}
+
+/**
+ * 获取签到配置
+ *
+ */
+export function getSignConfig() {
+	return request.get('sign/config')
+}
+
+/**
+ * 获取签到列表
+ * @param object data
+ */
+export function getSignList(data) {
+	return request.get('sign/list', data);
+}
+
+/**
+ * 用户签到
+ */
+export function setSignIntegral() {
+	return request.post('sign/integral')
+}
+
+/**
+ * 签到列表(年月)
+ * @param object data
+ *
+ */
+export function getSignMonthList(data) {
+	return request.get('sign/month', data)
+}
+
+/**
+ * 签到日历
+ * @param {Object} data
+ */
+export function getSignCalendar(data) {
+	return request.get('sign/calendar', 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 rechargeAPi(data) {
+	return request.post("recharge/recharge", data);
+}
+
+/*
+ * 充值支付
+ * */
+export function rechargePayAPi(data) {
+	return request.post("recharge/pay", 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);
+}
+
+/**
+ * 购买会员卡支付
+ * @param {Object} data
+ */
+export function memberCardPayApi(data) {
+	return request.post('user/member/card/pay', data);
+}
+
+/**
+ * 会员优惠券
+ */
+export function memberCouponsList(page, limit) {
+	return request.get('user/member/coupons/list', {
+		page,
+		limit
+	});
+}
+
+/**
+ * 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/message', 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
+	});
+}
+
+/*
+ * 获取分销说明
+ * */
+export function getDistributionInfo(type) {
+	return request.get(`agreement/2`, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取分销等级列表
+ * @param int id 任务id
+ */
+export function agentLevelList() {
+	return request.get('v2/agent/level_list');
+}
+
+/**
+ * 获取分销任务列表
+ * @param int id 任务id
+ */
+export function agentLevelTaskList(id) {
+	return request.get('v2/agent/level_task_list?id=' + id);
+}
+
+/**
+ * 获取定位详细地址
+ * @param int id
+ *
+ */
+export function getGeocoder(data) {
+	return request.get(`geoLbscoder?location=${data.lat},${data.long}`, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取当前定位选中的地址
+ * @param int id
+ *
+ */
+export function getCityList(address) {
+	return request.get('v2/cityList', {
+		address
+	}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取版权
+ *
+ */
+export function getCopyRight() {
+	return request.get('get_copyright', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取code码
+ * @param int id
+ *
+ */
+export function getRandCode() {
+	return request.get('user/rand_code');
+}
+
+/**
+ * 注销用户
+ * @param int id
+ *
+ */
+export function cancelUser() {
+	return request.get('cancel/user');
+}
+
+/**
+ * 获取激活会员卡需要的信息
+ * @param int id
+ *
+ */
+export function levelInfo() {
+	return request.get('user/level/activate_info');
+}
+
+/**
+ * 用户激活会员卡
+ * @param int id
+ *
+ */
+export function levelActivate(data) {
+	return request.post('user/level/activate', data);
+}
+
+/**
+ * 用户设置签到提醒
+ */
+export function signRemind(status) {
+	return request.get(`sign/remind/${status}`);
+}
+
+/**
+ * 供应商入住
+ * @param data
+ * 
+ */
+export function spplyCreateApi(id, data) {
+	return request.post(`user/apply/supplier/${id}`, data);
+}
+
+/**
+ * 供应商详情接口
+ *
+ */
+export function userApply(id) {
+	return request.get("user/apply/" + id);
+}
+
+/**
+ * 供应商记录接口
+ *
+ */
+export function recordList() {
+	return request.get("user/apply/record");
+}
+
+/**
+ * 文章点赞
+ *
+ */
+export function articleStarApi(id, data) {
+	return request.get(`article/like/${id}`, 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
+	});
+}

+ 395 - 0
components/BaseCalendar.vue

@@ -0,0 +1,395 @@
+<template>
+	<!-- 打卡日历页面 -->
+	<view class="all">
+		<view class="bar">
+			<!-- 上一个月 -->
+			<view class="previous barbtn" @click="changeMonth(-1)">
+				<view class="iconfont icon-ic_left2"></view>
+			</view>
+			<!-- 显示年月 -->
+			<view class="date">{{ nowYear || '--' }} 年 {{ nowMonth || '--' }} 月</view>
+			<!-- 下一个月 -->
+			<view class="next barbtn" @click="changeMonth(1)">
+				<view class="iconfont icon-ic_right2"></view>
+			</view>
+		</view>
+		<!-- 显示星期 -->
+		<view class="week-area">
+			<view class="week-txt" v-for="(item, index) in weeksTxt[langType]" :key="index">{{ item }}</view>
+		</view>
+
+		<view class="myDateTable">
+			<view v-for="(item, j) in calendarDays" :key="j" class="dateCell">
+				<view v-if="item.date == undefined || item.date == null" class="cell"></view>
+				<template v-else>
+					<!-- 已签到日期 -->
+					<view v-if="item.isSign == true" class="cell signColor bgWhite">
+						<!-- {{ item.date }} -->
+						<image class="sign-today" src="@/pages/users/static/sign-today.png" mode=""></image>
+						<view class="sign">已签</view>
+					</view>
+					<!-- 漏签 -->
+					<view @click="clickSign(item.date, 0)" class="cell outSignStyle" v-else-if="item.isBeforeToday && item.isThisMonth">
+						<!-- redColor bgGray -->
+						{{ item.date }}
+						<!-- <view class="redDot"></view> -->
+					</view>
+					<!-- 今日未签到-->
+					<view @click="clickSign(item.date, 1)" class="cell whiteColor" v-else-if="item.date == today && nowMonth == toMonth && nowYear == toYear">今</view>
+					<!-- 当前日期之后 -->
+					<view class="whiteColor cell" v-else>
+						{{ item.date }}
+					</view>
+				</template>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				calendarDays: [],
+				SignData: [], // 已经签到的数据
+				nowYear: 0, //当前选的年
+				nowMonth: 0, //当前选的月
+				today: parseInt(new Date().getDate()), //系统本日
+				toMonth: parseInt(new Date().getMonth() + 1), //系统本月
+				toYear: parseInt(new Date().getFullYear()), //系统本年
+				weeksTxt: {
+					ch: ['日', '一', '二', '三', '四', '五', '六'],
+					en: ['Sun', 'Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat']
+				}
+			};
+		},
+		props: {
+			isReplenishSign: {
+				// 是否允许过期补签
+				type: Boolean,
+				default: false
+			},
+			isFullCalendar: {
+				// 是否需要填满日历,前后空的格子填入上/下个月的日期
+				type: Boolean,
+				default: false
+			},
+			yearMonth: {
+				// 2022-01 这种格式,默认当前年月
+				type: String,
+				default: new Date().getFullYear() + '-' + new Date().getMonth() + 1
+			},
+			dataSource: {
+				//已签到的数据源,例: 5、6号已签到: ["2022-01-05","2022-01-06"],兼容个位数前可加可不加0
+				type: Array,
+				default: () => {
+					return [];
+				}
+			},
+			langType: {
+				//只是示例一个翻译而已,要想所有都翻译自己可以再加加
+				type: String,
+				default: 'ch' //en
+			}
+		},
+		created() {
+			if (!/en|ch/g.test(this.langType)) {
+				this.langType = 'ch'; // 非中英,则固定中文
+			}
+			const ymArr = this.yearMonth.split('-');
+			this.buildCalendar(ymArr[0], ymArr[1]);
+			this.onSignDataChange(this.dataSource);
+		},
+		watch: {
+			dataSource: 'onSignDataChange'
+		},
+		methods: {
+			clickSign(date, type) {
+				//type=0补签,type=1当日签到
+				var strTip = '签到';
+
+				if (type == 0) {
+					if (!this.isReplenishSign) {
+						// 未开启补签,阻止继续执行
+						console.log('————补签功能未开启————');
+						return;
+					}
+					strTip = '补签';
+				}
+				uni.showToast({
+					title: date + '号' + strTip + '成功',
+					icon: 'success',
+					position: 'bottom'
+				});
+				this.$emit('clickChange', this.nowYear + '-' + this.nowMonth + '-' + date); //传给调用模板页面
+				// 父页面要在clickChange里去修改输入的数据源dataSource,否则视图不更新的!
+			},
+			//构建日历数据
+			buildCalendar(y, m) {
+				this.nowYear = y;
+				this.nowMonth = m;
+				this.calculateEmptyGrids(y, m);
+				this.calculateDays(y, m);
+				if (this.isFullCalendar) {
+					this.fullCell();
+				}
+			},
+			// 监听到签到数据源改变
+			onSignDataChange(newData, oldData = []) {
+				this.SignData = newData;
+				this.matchSign();
+			},
+			//匹配标记已经签到的日子
+			matchSign() {
+				var signs = this.SignData;
+				var daysArr = this.calendarDays;
+				for (var i = 0; i < signs.length; i++) {
+					var current = new Date(this.toIOSDate(signs[i])).getTime(); // ios只认/格式的日期
+					for (var j = 0; j < daysArr.length; j++) {
+						if (current == new Date(this.toIOSDate(daysArr[j].fullDate)).getTime()) {
+							daysArr[j].isSign = true;
+						}
+					}
+				}
+				this.calendarDays = daysArr;
+				// console.log(this.calendarDays );
+			},
+			// 计算当月1号前空了几个格子,把它填充在calendarDays数组的前面
+			calculateEmptyGrids(year, month) {
+				//计算每个月时要清零
+				this.calendarDays = [];
+				const firstDayOfWeek = this.getFirstDayOfWeek(year, month);
+				if (firstDayOfWeek > 0) {
+					for (let i = 0; i < firstDayOfWeek; i++) {
+						this.calendarDays.push({
+							date: null, // 显示的日期
+							fullDate: null, // 日期yyyy-mm-dd格式
+							isBeforeToday: true, // 今日之前
+							isSign: false, // 是否签到
+							isThisMonth: false // 是本月
+						});
+					}
+				}
+			},
+			// 绘制当月天数占的格子,并把它放到days数组中
+			calculateDays(year, month) {
+				const thisMonthDays = this.getMonthDayLength(year, month);
+				const toDate = new Date(this.toYear + '/' + this.toMonth + '/' + this.today);
+				for (let i = 1; i <= thisMonthDays; i++) {
+					const fullDate = year + '-' + month + '-' + i;
+					const isBeforeToday = new Date(this.toIOSDate(fullDate)) < toDate;
+					this.calendarDays.push({
+						date: i,
+						fullDate,
+						isBeforeToday,
+						isSign: false,
+						isThisMonth: true
+					});
+				}
+				//console.log(this.calendarDays);
+			},
+			// 切换控制年月,上一个月,下一个月
+			changeMonth(type) {
+				console.log(type)
+				const nowYear = parseInt(this.nowYear);
+				const nowMonth = parseInt(this.nowMonth);
+				const newObj = this.getOperateMonthDate(nowYear, nowMonth, type);
+				this.buildCalendar(newObj.year, newObj.month); // 重新构建日历数据
+				this.$emit('dateChange', this.nowYear + '-' + this.nowMonth); //传给调用模板页面去拿新数据
+			},
+			// 获取当月共多少天,也就是获取月的最后一天
+			getMonthDayLength(year, month) {
+				return new Date(year, month, 0).getDate();
+			},
+			// 获取当月第一天星期几
+			getFirstDayOfWeek(year, month, day = 1) {
+				return new Date(Date.UTC(year, month - 1, day)).getDay();
+			},
+			toIOSDate(strDate) {
+				// iso不认识"-"拼接的日期,所以转/
+				return strDate ? strDate.replace(/-/g, '/') : strDate;
+			},
+			// 需要填满格子,上/下个月的日期拉出来填满格子
+			fullCell() {
+				const endDay = this.getMonthDayLength(this.nowYear, this.nowMonth);
+				const beforeEmptyLength = this.getFirstDayOfWeek(this.nowYear, this.nowMonth);
+				const afterEmptyLength = 6 - this.getFirstDayOfWeek(this.nowYear, this.nowMonth, endDay);
+
+				const last = this.getOperateMonthDate(this.nowYear, this.nowMonth, -1);
+				const lastMonthEndDay = this.getMonthDayLength(last.year, last.month);
+				for (let i = 0; i < beforeEmptyLength; i++) {
+					const date = lastMonthEndDay - beforeEmptyLength + i + 1;
+					this.calendarDays[i].date = date;
+					this.calendarDays[i].fullDate = last.year + '-' + last.month + '-' + date;
+				}
+				const next = this.getOperateMonthDate(this.nowYear, this.nowMonth, 1);
+				for (let i = 1; i <= afterEmptyLength; i++) {
+					this.calendarDays.push({
+						date: i, // 显示的日期
+						fullDate: next.year + '-' + next.month + '-' + i, // 日期yyyy-mm-dd格式
+						isBeforeToday: false, // 今日之前
+						isSign: false, // 是否签到
+						isThisMonth: false // 是本月
+					});
+				}
+				// console.log(beforeEmptyLength,afterEmptyLength,lastMonthEndDay);
+
+				// console.log(this.calendarDays);
+			},
+			// 获取加/减一个月的日期
+			getOperateMonthDate(yy, mm, num) {
+				let month = parseInt(mm) + parseInt(num);
+				let year = parseInt(yy);
+				if (month > 12) {
+					month = 1;
+					year++;
+				} else if (month < 1) {
+					month = 12;
+					year--;
+				}
+				return {
+					month,
+					year
+				};
+			}
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	.all {
+
+		// margin-top: 20rpx;
+		.cir-bg {
+			position: absolute;
+			left: 0;
+			top: 0;
+			width: 324rpx;
+			height: 230rpx;
+			background: #fee3de;
+			opacity: 1;
+			filter: blur(133px);
+		}
+	}
+
+	.all .bar {
+		display: flex;
+		flex-direction: row;
+		justify-content: space-between;
+		padding: 60rpx 64rpx 64rpx;
+	}
+
+	.bar .barbtn {
+		width: 52rpx;
+		height: 52rpx;
+		background: rgba(233, 51, 35, 0.1);
+		border-radius: 50%;
+		display: flex;
+
+		.iconfont {
+			margin: auto;
+			color: rgba(233, 51, 35, 0.8);
+		}
+	}
+
+	.all .week-area {
+		display: flex;
+		justify-content: space-between;
+		padding: 10px 0;
+		box-sizing: border-box;
+		width: 91vw;
+		margin: 10px auto;
+		border-radius: 10px;
+	}
+
+	.all .week-txt {
+		text-align: center;
+		width: 88rpx;
+		font-size: 24rpx;
+		line-height: 34rpx;
+		color: #999999;
+	}
+
+	.myDateTable {
+		margin: 0 auto;
+		width: 91vw;
+		border-radius: 10px;
+	}
+
+	.myDateTable .dateCell {
+		width: 13vw;
+		padding: 1vw;
+		display: inline-block;
+		text-align: center;
+		font-size: 36rpx;
+		box-sizing: border-box;
+		overflow: hidden;
+	}
+
+	.dateCell .cell {
+		display: flex;
+		border-radius: 16rpx;
+		height: 120rpx;
+		justify-content: center;
+		align-items: center;
+		box-sizing: border-box;
+		flex-direction: column;
+		font-family: 'SemiBold';
+
+		.sign-today {
+			width: 40rpx;
+			height: 40rpx;
+		}
+
+		.sign {
+			font-size: 18rpx;
+			font-weight: 500;
+			color: #e93323;
+			margin-top: 10rpx;
+		}
+	}
+
+	.whiteColor {
+		color: #981007;
+	}
+
+	.signColor {
+		color: #ffffff;
+	}
+
+	.bgWhite {
+		background-color: #fceae9;
+	}
+
+	.bgGray {
+		background-color: rgba(255, 255, 255, 0.42);
+	}
+
+	.bgBlue {
+		font-size: 14px;
+		background-color: #4b95e6;
+	}
+
+	.redColor {
+		color: #ff0000;
+	}
+
+	.outSignStyle {
+		// border: 1px solid #981007;
+		color: #981007;
+	}
+
+	.redDot {
+		width: 3px;
+		height: 3px;
+		border-radius: 16rpx;
+		background-color: red;
+	}
+
+	.date {
+		font-size: 36rpx;
+		font-family: PingFang SC-Medium, PingFang SC;
+		font-weight: 500;
+		color: #981007;
+	}
+</style>

+ 129 - 0
components/BaseMoney.vue

@@ -0,0 +1,129 @@
+<template>
+	<view :class="{ line: line, weight: weight }"
+		:style="{color:color, fontFamily: SemiBold ? 'SemiBold' : 'Regular'}"
+		class="base-money">
+		<text v-show="preFix" class="preFix" :style="{'font-size': preFixSize + 'rpx','color':textColor}">{{preFix}}</text>
+		<text class="symbol" :style="{'font-size': symbolSize +'rpx'}">¥</text><text class="integer"
+			:style="{'font-size': integerSize +'rpx'}">{{ integer }}</text>
+		<text v-if="digits && showDigits" class="decimal"
+			:style="{'font-size': decimalSize +'rpx'}">.{{ decimal }}</text>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'BaseMoney',
+		props: {
+			// 小数位数,为0则不显示
+			digits: {
+				type: Number,
+				default: 2
+			},
+			money: {
+				type: String | Number,
+				default: ""
+			},
+			// 删除线
+			line: {
+				type: Boolean,
+				default: false
+			},
+			// 粗体
+			weight: {
+				type: Boolean,
+				default: false
+			},
+			color:{
+				type: String,
+				default: 'var(--view-theme)'
+			},
+			textColor:{
+				type: String,
+				default: '#999'
+			},
+			symbolSize: {
+				type: String,
+				default: '20'
+			},
+			integerSize: {
+				type: String,
+				default: '26'
+			},
+			decimalSize: {
+				type: String,
+				default: '24'
+			},
+			inline: {
+				type: Boolean,
+				default: false
+			},
+			preFix:{
+				type: String,
+				default: ''
+			},
+			preFixSize:{
+				type: String,
+				default: '24'
+			},
+			SemiBold:{
+				type: Boolean,
+				default: true
+			},
+			isCoupon:{
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				integer: 0,
+				decimal: 0
+			};
+		},
+		watch: {
+			money: {
+				handler(newValue, oldValue) {
+					let value = Number(newValue).toFixed(this.digits);
+					value = value.split('.');
+					this.integer = value[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+					if (value[1]) {
+						this.decimal = value[1];
+					}
+				},
+				immediate: true
+			}
+		},
+		computed:{
+			showDigits(){
+				if(this.isCoupon){
+					if(this.decimal == '00') return false
+				}else{
+					return true
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.base-money {
+		display: inline-block;
+		&.line {
+			text-decoration: line-through;
+		}
+
+		&.weight {
+			font-weight: 500;
+		}
+	}
+	.preFix{
+		font-weight: 500 !important;
+		font-family: PingFang SC-Medium, PingFang SC !important;
+	}
+	.SemiBold{
+		font-family:'SemiBold';
+	}
+	.Regular{
+		font-family:'Regular';
+	}
+</style>

+ 92 - 0
components/BaseTag.vue

@@ -0,0 +1,92 @@
+<template>
+	<view class="base-tag" :class="{middle: size == 'middle'}" v-if="!imgSrc" :style="[tagStyle]" >{{text}}</view>
+	<view class="img-tag" :class="{'middle-img-tag': size == 'middle'}" v-else>
+		<image class="w-full h-full" :src="imgSrc" mode="heightFix"></image>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "tag",
+		props: {
+			size: {
+				// 标签大小 normal, small
+				type: String,
+				default: "normal"
+			},
+			// 标签内容
+			text: {
+				type: String,
+				default: ""
+			},
+			circle: {
+				type: [Boolean, String],
+				default: false
+			},
+			background: {
+				type: String,
+				default: '#e93323'
+			},
+			color: {
+				type: String,
+				default: '#ffffff'
+			},
+			borderColor:{
+				type: String,
+				default: ''
+			},
+			imgSrc:{
+				type: String,
+				default: ''
+			}
+		},
+		computed:{
+			tagStyle(){
+				return {
+					background: this.background,
+					color: this.color,
+					border: this.borderColor ? `1rpx solid ${this.borderColor}` : 'none'
+				}
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	.base-tag {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		height: 30rpx;
+		font-size: 18rpx;
+		padding: 0 8rpx;
+		color: #333;
+		border-radius: 4rpx;
+		background-color: #fff;
+		margin-right: 8rpx;
+		box-sizing: border-box;
+		margin-bottom: 8rpx;
+	}
+	.middle{
+		height: 36rpx;
+		padding: 0 12rpx;
+		border-radius: 8rpx;
+		font-size: 20rpx;
+		margin-right: 16rpx;
+	}
+	.img-tag{
+		display: block;
+		height: 30rpx;
+		border-radius: 4rpx;
+		margin-right: 8rpx;
+		box-sizing: border-box;
+		margin-bottom: 8rpx;
+	}
+	.middle-img-tag{
+		height: 36rpx;
+		margin-right: 16rpx;
+		image{
+			border-radius: 8rpx;
+		}
+	}
+</style>

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

+ 141 - 0
components/NavBar.vue

@@ -0,0 +1,141 @@
+<template>
+	<view class="navbar">
+		<view class="content" :style="{ background: isScrolling ? '#fff' : bagColor }">
+			<view :style="{ height: `${getHeight.barTop}px` }"></view>
+			<view class="acea-row row-center-wrapper bar" :style="{ height: `${getHeight.barHeight}px` }">
+				<view class="back-icon acea-row row-center-wrapper">
+					<view
+						v-show="showBack"
+						@click="back"
+						class="iconfont icon-ic_leftarrow back-icon"
+						:style="{ color: `${iconColor}`, fontSize: `${iconSize}`, fontWeight: `${iconWeight}` }"
+					>
+					</view>
+					<view
+						v-show="showHome"
+						@click="home"
+						class="iconfont icon-icon_home back-icon"
+						:style="{ color: `${iconColor}`, fontSize: `${iconSize}`, fontWeight: `${iconWeight}` }"
+					>
+					</view>
+				</view>
+				<view class="title" :style="{ color: `${textColor}`, fontSize: `${textSize}`, fontWeight: `${textWeight}` }">{{ titleText }}</view>
+				<view class="right-icon acea-row row-center-wrapper">
+					<view v-show="showRight" class="right-icon"></view>
+				</view>
+			</view>
+		</view>
+		<view class="placeholder">
+			<view :style="{ height: `${getHeight.barTop}px` }"></view>
+			<view :style="{ height: `${getHeight.barHeight}px` }"></view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	name: 'navbar',
+	props: {
+		// 滚动至下部
+		isScrolling: {
+			type: Boolean,
+			default: false
+		},
+		// 是否显示返回icon
+		showBack: {
+			type: Boolean,
+			default: false
+		},
+		showHome: {
+			type: Boolean,
+			default: false
+		},
+		// Title
+		titleText: {
+			type: String,
+			default: ''
+		},
+		// icon 颜色
+		iconColor: {
+			type: String,
+			default: '#000000'
+		},
+		// icon 字号
+		iconSize: {
+			type: String,
+			default: '40rpx'
+		},
+		// icon 字重
+		iconWeight: {
+			type: String,
+			default: 'bold'
+		},
+		// Title 颜色
+		textColor: {
+			type: String,
+			default: '#333'
+		},
+		// Title 字号
+		textSize: {
+			type: String,
+			default: '34rpx'
+		},
+		// Title 字重
+		textWeight: {
+			type: String,
+			default: '500'
+		},
+		// 背景色
+		bagColor: {
+			type: String,
+			default: 'transparent'
+		}
+	},
+	data() {
+		return {
+			getHeight: this.$util.getWXStatusHeight()
+		};
+	},
+	methods: {
+		back() {
+			console.log(111)
+			uni.navigateBack();
+		},
+		home() {
+			uni.switchTab({
+				url:'/pages/index/index'
+			})
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+.navbar {
+	position: relative;
+	color: #333;
+	.content {
+		position: fixed;
+		top: 0;
+		right: 0;
+		left: 0;
+		z-index: 998;
+		background-color: var(--view-theme);
+		font-weight: 500;
+		font-size: 34rpx;
+		color: #ffffff;
+		.back-icon,
+		.right-icon {
+			width: 40rpx;
+			height: 40rpx;
+		}
+		.bar {
+			padding: 0 30rpx;
+		}
+		.title {
+			flex: 1;
+			text-align: center;
+		}
+	}
+}
+</style>

+ 198 - 0
components/WaterfallsFlow/WaterfallsFlow.vue

@@ -0,0 +1,198 @@
+<template>
+    <view :class="'wf-page wf-page'+type">
+        <!--    left    -->
+        <view>
+            <view id="left" v-if="leftList.length">
+                <view v-for="(item,index) in leftList" :key="index"
+                      class="wf-item" @tap="itemTap(item)">
+                    <WaterfallsFlowItem :item="item" :isStore="isStore" :type="type" :recommend="recommend"/>
+                </view>
+            </view>
+        </view>
+        <!--    right    -->
+        <view>
+            <view id="right" v-if="rightList.length">
+                <view v-for="(item,index) in rightList" :key="index"
+                      class="wf-item" @tap="itemTap(item)">					  
+                    <WaterfallsFlowItem :item="item" :isStore="isStore" :type="type" :recommend="recommend"/>
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+import WaterfallsFlowItem from './WaterfallsFlowItem.vue'
+export default {
+    components: {
+        WaterfallsFlowItem
+    },
+    props: {
+        // 瀑布流列表
+        wfList: {
+            type: Array,
+            require: true
+        },
+        updateNum: {
+            type: Number,
+            default: 10
+        },
+		type: {
+			type: Number,
+			default: 0			
+		},
+		isStore: {
+			type: [String, Number],
+			default: '1'
+		},
+		recommend:{
+			type: Boolean,
+			default: false
+		}
+    },
+    data() {
+        return {
+            allList: [],       // 全部列表
+            leftList: [],      // 左边列表
+            rightList: [],     // 右边列表
+            mark: 0,           // 列表标记
+            boxHeight: [],     // 下标0和1分别为左列和右列高度
+        };
+    },
+    watch: {
+        // 监听列表数据变化
+        wfList:  {
+			handler(nVal,oVal){
+				// 如果数据为空或新的列表数据少于旧的列表数据(通常为下拉刷新或切换排序或使用筛选器),初始化变量
+
+				if (!this.wfList.length ||
+				    (this.wfList.length === this.updateNum && this.wfList.length <= this.allList.length)) {
+				    this.allList = [];
+				    this.leftList = [];
+				    this.rightList = [];
+				    this.boxHeight = [];
+				    this.mark = 0;
+				}
+				
+				// 如果列表有值,调用waterfall方法
+
+				if (this.wfList.length) {
+				    this.allList = this.wfList;
+					this.leftList = [];
+					this.rightList = [];
+					this.boxHeight = [];
+					this.allList.forEach((v, i) => {
+						if(this.allList.length < 3 || (this.allList.length <= 7  && this.allList.length - i > 1) || (this.allList.length > 7 && this.allList.length - i > 2)) {
+							if(i % 2){
+								this.rightList.push(v);
+							}else{
+								this.leftList.push(v);
+							}
+						}
+					});
+					if(this.allList.length < 3){
+						this.mark = this.allList.length+1;
+					}else if(this.allList.length <= 7){
+						this.mark = this.allList.length - 1;
+					}else{
+						this.mark = this.allList.length - 2;
+					}
+					if(this.mark < this.allList.length){
+						this.waterFall()
+					}
+				}
+			},
+			immediate: true,
+			deep:true
+        },
+		mounted(){
+		},
+
+        // 监听标记,当标记发生变化,则执行下一个item排序
+        mark() {
+            const len = this.allList.length;
+            if (this.mark < len && this.mark !== 0 && this.boxHeight.length) {
+                this.waterFall();
+            }
+        }
+    },
+    methods: {
+        // 瀑布流排序
+        waterFall() {
+            const i = this.mark;
+            if (i == 0) {
+                // 初始化,从左边开始插入
+                this.leftList.push(this.allList[i]);
+                // 更新左边列表高度
+                this.getViewHeight(0);
+            } else if (i == 1) {
+                // 第二个item插入,默认为右边插入
+                this.rightList.push(this.allList[i]);
+                // 更新右边列表高度
+                this.getViewHeight(1);
+            } else {
+                // 根据左右列表高度判断下一个item应该插入哪边
+                if(!this.boxHeight.length){
+                	this.rightList.length < this.leftList.length 
+                	? this.rightList.push(this.allList[i])
+                	: this.leftList.push(this.allList[i]);
+                } else {
+                	const leftOrRight = this.boxHeight[0] > this.boxHeight[1] ? 1 : 0;
+                	if (leftOrRight) {
+                	    this.rightList.push(this.allList[i])
+                	} else {
+                	    this.leftList.push(this.allList[i])
+                	}
+                }
+				// 更新插入列表高度
+				this.getViewHeight();
+            }
+        },
+        // 获取列表高度
+        getViewHeight() {
+            // 使用nextTick,确保页面更新结束后,再请求高度
+            this.$nextTick(() => {
+            	setTimeout(()=>{
+            		uni.createSelectorQuery().in(this).select('#right').boundingClientRect(res => {
+            				res ? this.boxHeight[1] = res.height : '';
+            			uni.createSelectorQuery().in(this).select('#left').boundingClientRect(res => {
+            				res ? this.boxHeight[0] = res.height : '';	
+            				this.mark = this.mark + 1;				
+            			}).exec();
+            		}).exec();
+            	},100)               
+            })
+        },
+        // item点击
+        itemTap(item) {
+            this.$emit('itemTap', item)
+        },
+		// item点击
+
+		goShop(item) {
+		    this.$emit('goShop', item)
+		}
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+$page-padding: 10px;
+$grid-gap: 10px;
+
+.wf-page {
+    display: grid;
+    grid-template-columns: 1fr 1fr;
+    grid-gap: $grid-gap;
+}
+.wf-item {
+    width: calc((100vw - 2 * #{$page-padding} - #{$grid-gap}) / 2);
+    padding-bottom: $grid-gap;
+}
+.wf-page1 .wf-item{
+	margin-top: 20rpx;
+	background-color: #fff;
+	border-radius: 20rpx;
+	padding-bottom: 0;
+}
+</style>

+ 109 - 0
components/WaterfallsFlow/WaterfallsFlowItem.vue

@@ -0,0 +1,109 @@
+<template>
+	<view class="wf-item-page wf-page0">
+		<view class='pictrue'>
+			<easy-loadimage
+			mode="widthFix"
+			:image-src="item.image"
+			:borderSrc="item.activity_frame.image"
+			width="100%"
+			height="345rpx"
+			borderRadius="16rpx 16rpx 0 0"></easy-loadimage>
+		</view>
+		<view class="info_box">
+			<view class="w-full line2 fs-28 text--w111-333 lh-40rpx">{{item.store_name}}</view>
+			<view class="flex items-end flex-wrap mt-12 w-full" v-if="item.store_label.length">
+				<BaseTag
+					:text="label.label_name"
+					:color="label.color"
+					:background="label.bg_color"
+					:borderColor="label.border_color"
+					:circle="label.border_color ? true : false"
+					:imgSrc="label.icon"
+					v-for="(label, idx) in item.store_label" :key="idx"></BaseTag>
+			</view>
+			<view class="flex-between-center mt-7" v-if="recommend">
+				<baseMoney :money="item.price" symbolSize="24" integerSize="40" decimalSize="24" weight></baseMoney>
+				<view class="w-44 h-44 rd-24 bg-gradient flex-center">
+					<text class="iconfont icon-ic_ShoppingCart1 text--w111-fff fs-26"></text>
+				</view>
+			</view>
+			<view class="mt-8" v-else>
+				<view class="flex-y-center flex-wrap mt-8">
+					<baseMoney :money="item.price" symbolSize="24" integerSize="40" decimalSize="24" weight></baseMoney>
+					<view class="inline-block h-26 lh-28rpx rd-14rpx bg--w111-F7E9CD fs-22 ml-8" 
+						v-if="Number(item.vip_price) > 0 && item.is_vip">
+						<text class="inline-block h-26 lh-28rpx svip_rd fs-18 bg--w111-484643 text--w111-FDDAA4 px-8">SVIP</text>
+						<text class="px-8 fs-22">¥{{item.vip_price}}</text>
+					</view>
+				</view>
+				<view class="flex-between-center mt-12">
+					<text class="fs-22 text--w111-999">已售{{item.sales}}{{item.unit_name}}</text>
+					<view class="w-44 h-44 rd-24 bg-gradient flex-center" @tap.stop="addCartChange">
+						<text class="iconfont icon-ic_ShoppingCart1 text--w111-fff fs-26"></text>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+	import easyLoadimage from '@/components/easy-loadimage/easy-loadimage.vue'
+	import {mapGetters} from "vuex";
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default {
+		components: {
+			easyLoadimage
+		},
+		props: {
+			item: {
+				type: Object,
+				require: true
+			},
+			type: {
+				type: Number,
+				default: 0
+			},
+			recommend:{
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				domain: HTTP_REQUEST_URL,
+			}
+		},
+		methods: {
+			addCartChange(){
+				this.$eventHub.$emit('onCartAddChange',this.item);
+			},
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.wf-item-page {
+		background: #fff;
+		overflow: hidden;
+		border-radius: 20rpx;
+	}
+	.info_box{
+		padding: 16rpx 20rpx;
+		border-radius: 0 0 20rpx 20rpx;
+		background-color: #fff;
+	}
+	.text-primary-con{
+		color: var(--view-theme);
+	}
+	.bg-primary-light{
+		background: var(--view-minorColorT);
+	}
+	.bg--w111-484643{
+		background: linear-gradient(90deg, #484643 0%, #1F1B17 100%);
+	}
+	.text--w111-FDDAA4{
+		color: #FDDAA4;
+	}
+	.svip_rd{
+		border-radius: 14rpx 0 8rpx 14rpx;
+	}
+</style>

+ 130 - 0
components/addressWindow/index.vue

@@ -0,0 +1,130 @@
+<template>
+	<view>
+		<base-drawer mode="bottom" :visible="address.address" background-color="transparent" mask maskClosable @close="close">
+			<view class="w-full bg--w111-fff rd-t-40rpx py-32">
+				<view class="text-center fs-32 text--w111-333 fw-500">选择地址</view>
+				<view class="mt-64 px-32">
+					<view class="mb-38 flex-between-center" 
+						v-for="(item,index) in addressList" :key="index"
+						:class="{'font-num': active==index}"
+						@tap='tapAddress(index,item.id,item)'>
+						<text class='iconfont icon-ic_location5 fs-36'></text>
+						<view class="flex-1 pl-40">
+							<view class="fs-28 fw-500">{{item.real_name}}<text class='phone'>{{item.phone}}</text></view>
+							<view class="w-560 line1 mt-4">{{item.province}}{{item.city}}{{item.district}}{{item.street}}{{item.detail}}</view>
+						</view>
+					</view>
+					<view v-if="!is_loading && !addressList.length">
+						<emptyPage title="暂无地址信息~" src="/statics/images/noAddress.png"></emptyPage>
+					</view>
+				</view>
+				<view class="mx-20 pb-safe">
+					<view class="mt-52 h-72 flex-center rd-36px bg-color fs-26 text--w111-fff" @tap='goAddressPages'>选择其它地址</view>
+				</view>
+			</view>
+		</base-drawer>
+	</view>
+</template>
+
+<script>
+	import {getAddressList} from '@/api/user.js';
+	import {adminUserAddressList} from '@/api/admin.js';
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
+	import emptyPage from '@/components/emptyPage.vue';
+	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,
+			},
+			userId: {
+				type: [String, Number],
+				default: 0,
+			},
+		},
+		components: {
+			baseDrawer,
+			emptyPage
+		},
+		data() {
+			return {
+				active: 0,
+				//地址列表
+				addressList: [],
+				is_loading: true,
+				imgHost: HTTP_REQUEST_URL
+			};
+		},
+		methods: {
+			tapAddress: function(e, addressid, row) {
+				this.active = e;
+				this.$emit('OnChangeAddress', addressid, row);
+			},
+			close: function() {
+				this.$emit('changeClose');
+				this.$emit('changeTextareaStatus');
+			},
+			goAddressPages: function() {
+				this.$emit('changeClose');
+				this.$emit('changeTextareaStatus');
+				uni.navigateTo({
+					url: this.pagesUrl
+				});
+			},
+			getAddressList: function() {
+				let that = this;
+				if (that.userId) {
+					adminUserAddressList(that.userId, {
+						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);
+						this.$emit('addressList', addressList);
+						that.is_loading = false;
+					})
+					return;
+				}
+				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);
+					this.$emit('addressList', addressList);
+					that.is_loading = false;
+				})
+			}
+		}
+	}
+</script>

+ 340 - 0
components/areaWindow/index.vue

@@ -0,0 +1,340 @@
+<template>
+	<!-- 地址下拉框 -->
+	<tuiDrawer :visible="display" mode="bottom" backgroundColor="transparent" @close="close">
+		<view class="address-window">
+			<view class='title'>
+				请选择所在地区
+				<view class="btn" @click="confirm" v-if="!checkStrictly">确定</view>
+			</view>
+			<view class="address-count">
+				<view class="acea-row row-middle address-selected-box">
+					<view class="address-selected acea-row">
+						<view v-for="(item,index) in selectedArr" :key="index" class="selected-list" :class="{active:index === selectedIndex}" @click="change(item.pid, index)">
+							{{item.label}}
+						</view>
+						<view class="selected-list" :class="{active:-1 === selectedIndex}" v-if="showMore" @click="change(-1, -1)">
+							请选择
+						</view>
+					</view>
+					<view class="btn" @click="refresh" v-if="!checkStrictly">
+						<text class="iconfont icon-ic_Refresh"></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>
+	</tuiDrawer>
+</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';
+	import tuiDrawer from '@/components/tui-drawer/tui-drawer.vue';
+
+	const CACHE_ADDRESS = {};
+
+	export default {
+		components: {
+			tuiDrawer
+		},
+		props: {
+			display: {
+				type: Boolean,
+				default: false
+			},
+			cityShow: {
+				type: Number,
+				default: 3
+			},
+			address: {
+				type: Array | Object,
+				default: []
+			},
+			checkStrictly: {
+				type: Boolean,
+				default: true
+			},
+		},
+		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
+				});
+			},
+			confirm() {
+				this.$emit('submit', [...this.selectedArr]);
+				this.$emit('changeClose');
+			},
+			refresh() {
+				this.selectedArr = []
+				this.loadAddress(0)
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.address-window {
+		background: #FFFFFF;
+		border-radius: 30rpx 30rpx 0 0;
+	}
+
+	.address-window .title {
+		font-size: 32rpx;
+		font-weight: bold;
+		text-align: center;
+		height: 108rpx;
+		line-height: 108rpx;
+		position: relative;
+	}
+
+	.address-window .title .iconfont {
+		position: absolute;
+		right: 30rpx;
+		color: #8a8a8a;
+		font-size: 35rpx;
+	}
+
+	.address-window .title .btn {
+		position: absolute;
+		top: 50%;
+		right: 40rpx;
+		font-weight: 400;
+		font-size: 28rpx;
+		color: #333333;
+		transform: translateY(-50%);
+	}
+
+	.address-count {
+		.address-selected-box {
+			padding: 0 32rpx 0 0;
+			border-bottom: 2rpx solid #F5F5F5;
+
+			.btn {
+				width: 96rpx;
+				height: 36rpx;
+				border: 1rpx solid #CCCCCC;
+				border-radius: 18rpx;
+				transform: rotateZ(360deg);
+				text-align: center;
+				font-size: 20rpx;
+				line-height: 36rpx;
+				color: #666666;
+
+				.iconfont {
+					margin-right: 4rpx;
+					font-size: 20rpx;
+				}
+			}
+		}
+
+		.address-selected {
+			flex: 1;
+			padding: 0 40rpx;
+			position: relative;
+		}
+
+		.selected-list {
+			font-size: 26rpx;
+			color: #282828;
+			line-height: 50rpx;
+			// padding-bottom: 16rpx;
+			padding: 16rpx 0;
+			margin-left: 40rpx;
+			position: relative;
+
+			&.active::after {
+				content: "";
+				position: absolute;
+				bottom: 0;
+				left: 50%;
+				width: 32rpx;
+				height: 6rpx;
+				border-radius: 2rpx;
+				background: var(--view-theme);
+				transform: translateX(-50%);
+				// 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;
+			// 	}
+			// }
+			&:first-child {
+				margin-left: 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>

+ 3 - 0
components/authorize/index.vue

@@ -0,0 +1,3 @@
+<template>
+	<view></view>
+</template>

+ 75 - 0
components/cartDiscount/index.vue

@@ -0,0 +1,75 @@
+<template>
+	<view>
+		<!-- 购物车优惠明细 -->
+		<base-drawer mode="bottom" :visible="discountInfo.discount" background-color="transparent" mask maskClosable @close="closeDiscount">
+		  <view class="w-full bg--w111-fff rd-t-40rpx py-32">
+		    <view class="text-center fs-32 text--w111-333 fw-500">金额明细</view>
+		    <view class="mt-32 p-32 scroll-content" :style="[moneyPD.pb]">
+				<view class="flex-between-center">
+					<view class="fs-26">商品总价:</view>
+					<view class="fs-28 SemiBold">¥{{discountInfo.deduction.sum_price}}</view>
+				</view>
+				<!-- <view class="flex-between-center mt-38">
+					<view class="fs-26">优惠抵扣:</view>
+					<view class="fs-28 SemiBold">-¥{{$util.$h.Sub(discountInfo.deduction.sum_price,discountInfo.deduction.pay_price)}}</view>
+				</view> -->
+				<view class="flex-between-center mt-38" v-if="discountInfo.deduction.coupon_price">
+					<view class="fs-26">{{discountInfo.coupon.coupon_title}}</view>
+					<view class="fs-28 SemiBold">-¥{{discountInfo.deduction.coupon_price}}</view>
+				</view>
+				<view class="flex-between-center mt-38" v-if="discountInfo.deduction.first_order_price">
+					<view class="fs-26">新人首单优惠</view>
+					<view class="fs-28 SemiBold">-¥{{discountInfo.deduction.first_order_price}}</view>
+				</view>
+				<view class="flex-between-center mt-38" v-if="discountInfo.deduction.promotions_price">
+					<view class="fs-26">优惠活动</view>
+					<view class="fs-28 SemiBold">-¥{{discountInfo.deduction.promotions_price}}</view>
+				</view>
+				<view class="flex-between-center mt-38" v-if="discountInfo.deduction.vip_price">
+					<view class="fs-26">会员优惠</view>
+					<view class="fs-28 SemiBold">-¥{{discountInfo.deduction.vip_price}}</view>
+				</view>
+				<view class="flex-between-center mt-44" v-if="discountInfo.deduction.vip_price">
+					<view class="fs-28 fw-500">优惠合计</view>
+					<view class="fs-32 SemiBold font-num">-¥{{$util.$h.Sub(discountInfo.deduction.sum_price,discountInfo.deduction.pay_price)}}</view>
+				</view>
+			</view>
+		  </view>
+		</base-drawer>
+	</view>
+</template>
+
+<script>
+	import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
+	export default {
+		props: {
+			discountInfo: {
+				type: Object,
+				default: () => {}
+			},
+			moneyPD: {
+				type: Object,
+				default: () => {}
+			}
+		},
+		components:{
+			baseDrawer
+		},
+		data() {
+			return {};
+		},
+		mounted() {},
+		methods: {
+			closeDiscount(){
+				this.$emit('myevent');
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.scroll-content {
+		max-height: 600rpx;
+		overflow-y: auto;
+	}
+</style>

+ 210 - 0
components/cartList/index.vue

@@ -0,0 +1,210 @@
+<template>
+	<view>
+		<!-- 分类购物车下拉列表 -->
+		<view :style="[parent.isFooter?listH:'']" class="cartList" :class="{on:cartData.iScart,ons:!isFooter}" @touchmove.stop.prevent="moveHandle">
+			<view class="title acea-row row-between-wrapper">
+				<view class="name">购物车 <text class="fs-24 text--w111-999 pl-8">(共{{cartNums||cartNum}}件商品)</text></view>
+				<view class="del acea-row row-middle" @click="subDel"><view class="iconfont icon-ic_delete"></view>清空</view>
+			</view>
+			<view class="list">
+				<!-- <scroll-view scroll-y="true" style="max-height: 800rpx;margin-bottom: 146rpx;"> -->
+				<scroll-view scroll-y="true" :style="{
+					'max-height': '800rpx',
+					'margin-bottom': 146+marginBottom+'rpx'
+				}">
+					<view class="item flex" 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="flex-1 flex-col justify-between ml-20">
+							<view class="w-full">
+								<view class="lh-40rpx fs-28 text--w111-333 line2"
+									:class="(item.attrStatus && item.status)?'':'on'">{{item.productInfo.store_name}}</view>
+								<view class="inline-block max-w-460 h-38 lh-38rpx mt-12  bg--w111-f5f5f5  text--w111-999 rd-20rpx px-12 text-center fs-22"
+									v-if="item.productInfo.spec_type && item.attrStatus">
+									<view class="flex">
+										<text class="line1">属性: {{item.productInfo.attrInfo.suk}}</text>
+										<text class="iconfont icon-ic_downarrow fs-24 ml-12"></text>
+									</view>
+								</view>
+								<view class="inline-block max-w-460 h-38 lh-38rpx mt-12  bg--w111-f5f5f5  text--w111-999 rd-20rpx px-12 text-center fs-22"
+									v-else>
+									<view class="flex">
+										<text class="line1">属性: {{item.productInfo.attrInfo.suk}}</text>
+										<text class="iconfont icon-ic_downarrow fs-24 ml-12"></text>
+									</view>
+								</view>
+							</view>
+							<view class="flex-between-center mt-20">
+								<baseMoney :money="item.truePrice" symbolSize="24" integerSize="40" decimalSize="24" weight></baseMoney>
+								<view class="flex-y-center" v-if="item.attrStatus && item.status">
+									<view class="flex-center w-48 h-48 rd-30rpx bg--w111-f5f5f5 text--w111-333" @click="leaveCart(index)">
+										<text class="iconfont icon-ic_Reduce fs-32"></text>
+									</view>
+									<view class="fs-30 text--w111-333 px-20">{{item.cart_num}}</view>
+									<view class="flex-center w-48 h-48 rd-30rpx bg-color text--w111-fff" @click="joinCart(index)">
+										<text class="iconfont icon-ic_increase fs-32"></text>
+									</view>
+								</view>
+								<view class="noBnt" v-else-if="!item.attrStatus">已售罄</view>
+								<view class="noBnt" v-else-if="!item.status">已下架</view>
+							</view>
+						</view>
+					</view>
+				</scroll-view>
+			</view>
+		</view>
+		<view class="mask" v-if="cartData.iScart" @click="closeList" @touchmove.stop.prevent="moveHandle"></view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	export default {
+		props:{
+			cartData: {
+				type: Object,
+				default: () => {}
+			},
+			isFooter: {
+			  type: Boolean,
+			  default: false
+			},
+			marginBottom: {
+				type: Number,
+				default: 0
+			},
+			cartNums: {
+				type: Number,
+				default: 0
+			},
+		},
+		inject: ['parent'],
+		computed:{
+			listH(){
+				let H = `calc(${this.parent.pdHeight*2+100}rpx + env(safe-area-inset-bottom))`
+				return{
+					paddingBottom: H
+				}
+			},
+			...mapState({
+				cartNum: state => state.indexData.cartNum
+			})
+		},
+		data() {
+			return {};
+		},
+		mounted(){
+		},
+		methods: {
+			moveHandle(){
+				return false
+			},
+			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: 40rpx 32rpx 0;
+		padding-bottom: calc(100rpx + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(100rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		box-sizing: border-box;
+		border-radius:40rpx 40rpx 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{
+			margin-bottom: 32rpx;
+			.name{
+				font-size:32rpx;
+				color: #333;
+				font-weight:500;
+			}
+			.del{
+				font-size: 24rpx;
+				color: #666;
+				.iconfont{
+					margin-right: 8rpx;
+					font-size: 28rpx;
+				}
+			}
+		}
+		.list{
+			max-height: 1000rpx;
+			.item{
+				margin-bottom: 32rpx;
+				.pictrue{
+					width: 200rpx;
+					height: 200rpx;
+					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;
+					}
+				}
+			}
+		}
+	}
+	.noBnt{
+		width:126rpx;
+		height:44rpx;
+		background:#f5f5f5;
+		border-radius:22rpx;
+		text-align: center;
+		line-height: 44rpx;
+		font-size: 24rpx;
+		color: #333;
+	}
+	.max-w-460{
+		max-width: 460rpx;;
+	}
+</style>

+ 148 - 0
components/countDown/index.vue

@@ -0,0 +1,148 @@
+<template>
+	<view class="time" :style="justifyLeft">
+		<!-- 倒计时 -->
+		<text class="title red" v-if="tipText.trim()">{{ tipText }}</text>
+		<text class="styleAll" :style="'background-color:' + bgColor + ';color:' + colors + ';'" v-if="isDay === true">
+			{{ day }}
+			<text class="dayTxt">{{ inDayText }}</text>
+		</text>
+		<text class="timeTxt red" :style="'color:' + dotColor" v-if="dayText">{{ dayText }}</text>
+		<text class="styleAll" :style="'background-color:' + bgColor + ';color:' + colors + ';'">{{ hour }}</text>
+		<text class="timeTxt red" :style="'color:' + dotColor" v-if="hourText">{{ hourText }}</text>
+		<text class="styleAll" :style="'background-color:' + bgColor + ';color:' + colors + ';'">{{ minute }}</text>
+		<text class="timeTxt red" :style="'color:' + dotColor" 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:' + dotColor" 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: '倒计时'
+		},
+		inDayText: {
+			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: '#e93323'
+		},
+		dotColor: {
+			type: String,
+			default: '#ffffff'
+		}
+	},
+	data: function () {
+		return {
+			day: '00',
+			hour: '00',
+			minute: '00',
+			second: '00',
+			times: null
+		};
+	},
+	watch:{
+		datatime:{
+			handler(val){
+				this.show_time();
+			},
+			immediate: true
+		}
+	},
+	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';
+					clearInterval(that.times);
+					that.times = null;
+					that.$emit('endTime', 1);
+				}
+			}
+			runTime();
+			this.times = setInterval(runTime, 1000);
+		}
+	}
+};
+</script>
+
+<style>
+.time {
+	display: flex;
+	justify-content: center;
+}
+.timeTxt {
+	margin: 0 4rpx;
+}
+</style>

+ 221 - 0
components/couponListWindow/index.vue

@@ -0,0 +1,221 @@
+<template>
+	<view>
+		<base-drawer mode="bottom" :visible="coupon.coupon" background-color="transparent" mask maskClosable @close="close">
+			<view class="w-full bg--w111-f5f5f5 rd-t-40rpx">
+				<view class="flex-around-center fs-30 nav" v-if="coupon.count">
+					<view v-if="coupon.count[2]" class="h-100 flex-y-center" :class="coupon.type === 2 ? 'active' : ''" @tap="setType(2)">商品券</view>
+					<view v-if="coupon.count[1]" class="h-100 flex-y-center" :class="coupon.type === 1 ? 'active' : ''" @tap="setType(1)">品类券</view>
+					<view v-if="coupon.count[0]" class="h-100 flex-y-center" :class="coupon.type === 0 ? 'active' : ''" @tap="setType(0)">通用券</view>
+				</view>
+				<view class="text-center fs-32 text--w111-333 fw-500 pt-32 relative" v-else>
+					优惠券
+					<view class="w-36 h-36 rd-50-p111- flex-center close-btn" @tap="close">
+						<text class="iconfont icon-ic_close fs-24 text--w111-666"></text>
+					</view>
+				</view>
+				<view class="px-20 scroll-content">
+					<scroll-view scroll-y="true" style="max-height: 800rpx">
+						<view class="coupon-list" v-if="coupon.list.length">
+							<view v-for="(item, index) in coupon.list" :key="index" @tap="getCouponUser(index, item.id)">
+								<view class="mt-24 h-170 bg--w111-fff text-center rd-16rpx flex">
+									<view class="left-bg bg-gradient">
+										<view class="left-container w-full h-full relative flex-col flex-between-center py-32">
+											<baseMoney :money="item.coupon_price" symbolSize="28" integerSize="52" decimalSize="28" color="#ffffff" isCoupon v-if="item.coupon_type == 1"></baseMoney>
+											<view v-else class="text--w111-fff fs-52">
+												{{ parseFloat(item.coupon_price) / 10 }}
+												<text class="fs-28">折</text>
+											</view>
+											<text class="fs-24 text--w111-fff">满{{ item.use_min_price }}元可用</text>
+										</view>
+									</view>
+									<view class="right-box pt-24 pl-24 pr-14 pb-22 flex-1 flex-col justify-between bg--w111-fff">
+										<view class="flex-y-center">
+											<view class="fs-28 fw-500 text--w111-333 lh-40rpx line1 w-360 text-left">{{ item.title }}</view>
+										</view>
+										<view class="flex-between-center">
+											<view class="fs-20 text--w111-666 lh-28rpx" v-if="item.coupon_time">领取后{{ item.coupon_time }}天内可用</view>
+											<view class="fs-20 text--w111-666 lh-28rpx" v-else>{{ item.start_time ? item.start_time + '-' : '' }}{{ item.end_time }}</view>
+											<view class="con_btn bg-primary-light text-primary-con w-136 h-52 rd-28rpx fs-22 flex-center" v-if="coupon.count">
+												{{ item.is_use ? '去使用' : '立即领取' }}
+											</view>
+											<view class="iconfont fs-36 pr-14" :class="" v-else>
+												<view class="iconfont icon-a-ic_CompleteSelect font-color" :class="item.receive_type === 4 ? 'svip' : 'font-num'" v-if="item.is_use"></view>
+												<view class="iconfont icon-ic_unselect text--w111-ccc" v-else></view>
+											</view>
+										</view>
+										<view class="flex-y-center fs-20 text--w111-999 lh-28rpx mt-20">
+											<text>{{ item.type | typeFilter }}</text>
+											<view v-show="item.rule" @tap.stop="toggleRule(index)">
+												<text class="pl-8 fs-20">| 查看用券规则</text>
+												<text class="iconfont icon-ic_downarrow fs-20 ml-4"></text>
+											</view>
+										</view>
+									</view>
+								</view>
+								<view class="rule-desc" v-show="item.ruleshow" v-html="item.rule"></view>
+							</view>
+							<view class="h-200"></view>
+						</view>
+						<view class="mt-28" v-else>
+							<emptyPage title="暂无优惠券" src="/statics/images/noCoupon.gif"></emptyPage>
+						</view>
+					</scroll-view>
+				</view>
+			</view>
+		</base-drawer>
+	</view>
+</template>
+
+<script>
+import { setCouponReceive } from '@/api/api.js';
+import { HTTP_REQUEST_URL } from '@/config/app';
+import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
+import dayjs from '@/plugin/dayjs/dayjs.min.js';
+import emptyPage from '@/components/emptyPage.vue';
+export default {
+	filters: {
+		dateFormat: function (value) {
+			return dayjs(value * 1000).format('YYYY/MM/DD');
+		},
+		typeFilter(val) {
+			let obj = {
+				0: '通用券',
+				1: '品类券',
+				2: '商品券',
+				3: '品牌券'
+			};
+			return obj[val];
+		}
+	},
+	props: {
+		//打开状态 0=领取优惠券,1=使用优惠券
+		openType: {
+			type: Number,
+			default: 0
+		},
+		coupon: {
+			type: Object,
+			default: function () {
+				return {};
+			}
+		}
+	},
+	components: {
+		baseDrawer,
+		emptyPage
+	},
+	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) {
+				that.$emit('ChangCoupons', 0);
+				return;
+			}
+			switch (this.openType) {
+				case 0:
+					//领取优惠券
+					setCouponReceive(id)
+						.then((res) => {
+							that.$emit('ChangCouponsUseState', index);
+							that.$util.Tips({
+								title: '领取成功'
+							});
+						})
+						.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);
+		},
+		toggleRule(index) {
+			this.$emit('ruleToggle', index);
+		}
+	}
+};
+</script>
+
+<style scoped lang="scss">
+.nav {
+	height: 100rpx;
+	border-bottom: 1px solid #eee;
+}
+.active {
+	border-bottom: 1px solid var(--view-theme);
+	color: var(--view-theme);
+}
+.left-bg {
+	width: 190rpx;
+	height: 170rpx;
+	background-size: 100%;
+	background-repeat: no-repeat;
+	border-radius: 24rpx 0 0 24rpx;
+}
+.right-box {
+	border-radius: 0 24rpx 24rpx 0;
+}
+.left-container {
+	background: radial-gradient(circle at 0px 84rpx, #f5f5f5 12rpx, transparent 0px) top;
+	&:after {
+		content: '';
+		position: absolute;
+		top: 0;
+		right: 0px;
+		width: 6rpx;
+		height: 100%;
+		background-image: radial-gradient(circle at 6rpx 12rpx, #ffffff 6rpx, transparent 6rpx);
+		background-size: 6rpx 18rpx;
+	}
+}
+.text-primary-con {
+	color: var(--view-theme);
+}
+.bg-primary-light {
+	background: var(--view-minorColorT);
+}
+.con-border {
+	border: 1px solid var(--view-theme);
+}
+.scroll-content {
+	height: 800rpx;
+	.coupon-list{
+		margin-bottom: 120rpx;
+	}
+}
+.rule-desc {
+	margin-top: -16rpx;
+	padding: 40rpx 24rpx 24rpx;
+	white-space: pre-wrap;
+	font-size: 20rpx;
+	line-height: 28rpx;
+	background-color: #fff;
+	border-radius: 0 0 16rpx 16rpx;
+	color: #999;
+}
+.close-btn {
+	position: absolute;
+	right: 32rpx;
+	top: 36rpx;
+	background-color: #eee;
+}
+</style>

+ 159 - 0
components/couponWindow/index.vue

@@ -0,0 +1,159 @@
+<template>
+	<view>
+		<!-- 优惠券弹窗 -->
+		<view class="coupon-window relative" :class="{ on: window}">
+			<view class="box-1 cover relative">
+				<view class="box-2 bg--w111-fff relative px-32">
+					<view class="box-ht cover abs-lt"></view>
+					<view class="flex-center mt-26 fs-36 lh-60rpx fw-500 relative z-20">
+						恭喜获得<text class="red">{{couponList.length}}张</text>优惠券
+					</view>
+					<view class="box-item mt-16 flex-between-center relative z-20"
+						v-for="(item,index) in couponList" :key="index">
+						<baseMoney
+						:money="item.coupon_price"
+						symbolSize="32"
+						integerSize="52"
+						decimalSize="32"
+						color="#e93323"
+						isCoupon
+						v-if="item.coupon_type==1"></baseMoney>
+						<view v-else class="font-color SemiBold fs-42 SemiBold">{{parseFloat(item.coupon_price)/10}}折</view>
+						<view>
+							<view class="fs-28 lh-40rpx red w-234 line1">{{item.coupon_title}}</view>
+							<view class="fs-20 lh-28rpx text--w111-666 mt-8" v-if="item.coupon_time">领取后{{item.coupon_time}}天内可用</view>
+							<view class="fs-20 lh-28rpx text--w111-666 mt-8" v-else>{{item.start_time ? item.start_time+'-' : ''}}{{item.end_time === 0 ? '不限时': item.end_time}}</view>
+						</view>
+					</view>
+				</view>
+				<view class="box-3 cover abs-lb">
+					<view class="btn-box flex-center fs-34 fw-500" @tap="goPage">立即领取</view>
+				</view>
+			</view>
+			<text class="iconfont icon-ic_close1 fs-60 text--w111-fff" @tap="close"></text>
+		</view>
+		<view class='mask' catchtouchmove="true" :hidden="window==false"  @touchmove.stop.prevent></view>
+	</view>
+</template>
+
+<script>
+	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: '',
+			},
+		},
+		data() {
+			return {
+				imgHost:HTTP_REQUEST_URL
+			};
+		},
+		methods: {
+			goPage(){
+				this.$emit('onColse');
+				uni.navigateTo({
+					url: '/pages/activity/coupon/index'
+				})
+			},
+			close:function(){
+			  this.$emit('onColse');
+			}
+		}
+	}
+</script>
+
+
+<style scoped lang="scss">
+	.mask {
+		z-index: 9999;
+	}
+
+	.coupon-window {
+		width: 574rpx;
+		height: 860rpx;
+		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;
+	}
+	.coupon-window.on {
+		transform: translate3d(0, 0, 0);
+	}
+	.box-1{
+		width: 100%;
+		height: 462rpx;
+		position: absolute;
+		left: 0;
+		bottom: 108rpx;
+		background-image: url('@/static/img/new_coupon_bg4.png');
+	}
+	.box-2{
+		width: 524rpx;
+		max-height: 508rpx;
+		position: absolute;
+		left: 50%;
+		transform: translateX(-50%);
+		bottom: 188rpx;
+		border-radius: 40rpx 40rpx 0 0;
+		overflow-y: auto;
+	}
+	.box-3{
+		width: 100%;
+		height: 242rpx;
+		background-image: url('@/static/img/new_coupon_bg3.png');
+	}
+	.box-ht{
+		width: 524rpx;
+		height: 136rpx;
+		background-image: url('@/static/img/new_coupon_bg1.png');
+	}
+	.box-item{
+		width: 100%;
+		height: 140rpx;
+		background-image: url('@/static/img/new_coupon_bg2.png');
+		background-size: 100%;
+		padding: 0 40rpx 0 20rpx;
+	}
+	.btn-box{
+		width: 460rpx;
+		height: 88rpx;
+		background: linear-gradient(90deg, #FFD10C 0%, #FEEF4C 100%);
+		border-radius: 44rpx;
+		position: absolute;
+		left: 50%;
+		transform: translateX(-50%);
+		bottom: 48rpx;
+	}
+	.cover{
+		background-size: cover;
+	}
+	.icon-ic_close1{
+		position: absolute;
+		left: 50%;
+		transform: translateX(-50%);
+		bottom: 0;
+	}
+	.red{
+		color: #e93323;
+	}
+	.SemiBold{
+		font-family:'SemiBold';
+	}
+</style>

+ 137 - 0
components/cusPreviewImg/index.vue

@@ -0,0 +1,137 @@
+<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" />
+				</swiper-item>
+			</swiper>
+		</view>
+		<view class="pagebox" v-if="list.length>0">{{ Number(currentIndex) + 1 }} / {{ list.length }}</view>
+	</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: 3000;
+	@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%;
+		top: 164rpx;
+		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>

+ 271 - 0
components/easy-loadimage/easy-loadimage.vue

@@ -0,0 +1,271 @@
+<template>
+	<view class="easy-loadimage" :style="[boxStyle]" :id="uid">
+		<image class="origin-img" :src="imageSrc" mode="aspectFill" 
+			v-if="loadImg&&!isLoadError" 
+			v-show="showImg"
+			:style="[imgStyle]"
+			:class="{'no-transition':!openTransition,'show-transition':showTransition&&openTransition}"
+			@load="handleImgLoad" @error="handleImgError">
+		</image>
+		<image class="border-img" :src="borderSrc" mode="aspectFill"
+			v-if="loadImg&&!isLoadError&&borderSrc"
+			v-show="showImg"
+			:style="[imgStyle]"
+			:class="{'no-transition':!openTransition,'show-transition':showTransition&&openTransition}">
+		</image>
+		<view class="loadfail-img" v-else-if="isLoadError"></view>
+		<view :class="['loading-img','spin-circle',loadingMode]" v-show="!showImg&&!isLoadError"></view>
+	</view>
+</template>
+<script>
+	import {throttle} from '@/utils/validate.js';
+
+	// 生成全局唯一id
+	function generateUUID() {
+		return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+			let r = Math.random() * 16 | 0,
+				v = c == 'x' ? r : (r & 0x3 | 0x8);
+			return v.toString(16);
+		})
+	}
+	export default {
+		props: {
+			imageSrc: {
+				type: String,
+				default: ""
+			},
+			borderSrc: {
+				type: String,
+				default: ""
+			},
+			mode: {
+				type: String,
+				default: ""
+			},
+			loadingMode: {
+				type: String,
+				default: 'looming-gray'
+			},
+			openTransition: {
+				type: Boolean,
+				default: true,
+			},
+			viewHeight: {
+				type: Number,
+				default () {
+					return uni.getSystemInfoSync().windowHeight;
+				}
+			},
+			width:{
+				type: String,
+				default: ''
+			},
+			height:{
+				type: String,
+				default: ''
+			},
+			borderRadius:{
+				type: String,
+				default: ''
+			}
+		},
+		data() {
+			const that = this;
+			return {
+				// uid:'',
+				uid: 'uid-' + generateUUID(),
+				loadImg: false,
+				showImg: false,
+				isLoadError: false,
+				borderLoaded: 0,
+				showTransition: false,
+				scrollFn: throttle(function() {
+					// 加载img时才执行滚动监听判断是否可加载
+					if (that.loadImg || that.isLoadError) return;
+					const id = that.uid
+					const query = uni.createSelectorQuery().in(that);
+					query.select('#' + id).boundingClientRect(data => {
+						if (!data) return;
+						if (data.top - that.viewHeight < 0) {
+							that.loadImg = !!that.imageSrc;
+							that.isLoadError = !that.loadImg;
+						}
+					}).exec()
+				}, 200)
+			}
+		},
+		computed:{
+			boxStyle(){
+				return {
+					width: this.width,
+					height: this.height,
+					borderRadius: this.borderRadius
+				}
+			},
+			imgStyle(){
+				return {
+					borderRadius: this.borderRadius
+				}
+			}
+		},
+		methods: {
+			init() {
+				this.$nextTick(this.onScroll)
+			},
+			handleBorderLoad() {
+				this.borderLoaded = 1;
+			},
+			handleBorderError() {
+				this.borderLoaded = 2;
+			},
+			handleImgLoad(e) {
+				// console.log('success');
+				this.showImg = true;
+				// this.$nextTick(function(){
+				//     this.showTransition = true
+				// })
+				setTimeout(() => {
+					this.showTransition = true
+				}, 50)
+			},
+			handleImgError(e) {
+				// console.log('fail');
+				this.isLoadError = true;
+			},
+			onScroll() {
+				this.scrollFn();
+			},
+		},
+		mounted() {
+			this.init()
+			uni.$on('scroll', this.scrollFn);
+			this.onScroll()
+		},
+		beforeDestroy() {
+			uni.$off('scroll', this.scrollFn);
+		}
+	}
+</script>
+
+<style scoped>
+	.easy-loadimage {
+		position: relative;
+
+	}
+
+	.border-img {
+		position: absolute;
+		width: 100%;
+		height: 100%;
+		/* max-height: 360rpx; */
+		top: 0;
+		left: 0;
+	}
+
+	/* 官方优化图片tips */
+	image {
+		will-change: transform
+	}
+
+	/* 渐变过渡效果处理 */
+	image.origin-img {
+		width: 100%;
+		height: 100%;
+		opacity: 0.3;
+		/* max-height: 360rpx; */
+	}
+
+	image.origin-img.show-transition {
+		transition: opacity .5s;
+		opacity: 1;
+	}
+
+	image.origin-img.no-transition {
+		opacity: 1;
+	}
+
+	/* 渐变过渡效果处理 */
+	image.border-img {
+		width: 100%;
+		height: 100%;
+		opacity: 0.3;
+		/* max-height: 360rpx; */
+	}
+
+	image.border-img.show-transition {
+		transition: opacity .5s;
+		opacity: 1;
+	}
+
+	image.border-img.no-transition {
+		opacity: 1;
+	}
+
+	/* 加载失败、加载中的占位图样式控制 */
+	.loadfail-img {
+		height: 100%;
+		background: url('~@/static/easy-loadimage/loadfail.png') no-repeat center;
+		background-size: 50%;
+	}
+
+	.loading-img {
+		height: 100%;
+	}
+
+	/* 转圈 */
+	.spin-circle {
+		background: url('~@/static/easy-loadimage/loading.png') no-repeat center;
+		background-size: 60%;
+	}
+
+	/* 动态灰色若隐若现 */
+	.looming-gray {
+		animation: looming-gray 1s infinite linear;
+		background-color: #e3e3e3;
+		border-radius: 12rpx;
+	}
+
+	@keyframes looming-gray {
+		0% {
+			background-color: #e3e3e3aa;
+		}
+
+		50% {
+			background-color: #e3e3e3;
+		}
+
+		100% {
+			background-color: #e3e3e3aa;
+		}
+	}
+
+	/* 骨架屏1 */
+	.skeleton-1 {
+		background-color: #e3e3e3;
+		background-image: linear-gradient(100deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0) 80%);
+		background-size: 100rpx 100%;
+		background-repeat: repeat-y;
+		background-position: 0 0;
+		animation: skeleton-1 .6s infinite;
+	}
+
+	@keyframes skeleton-1 {
+		to {
+			background-position: 200% 0;
+		}
+	}
+
+	/* 骨架屏2 */
+	.skeleton-2 {
+		background-image: linear-gradient(-90deg, #fefefe 0%, #e6e6e6 50%, #fefefe 100%);
+		background-size: 400% 400%;
+		background-position: 0 0;
+		animation: skeleton-2 1.2s ease-in-out infinite;
+	}
+
+	@keyframes skeleton-2 {
+		to {
+			background-position: -135% 0;
+		}
+	}
+</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>

+ 45 - 0
components/emptyPage.vue

@@ -0,0 +1,45 @@
+<template>
+	<!-- 无数据时显示 -->
+	<view class="empty-page w-full flex-col flex-center pt-82 bg--w111-fff rd-24rpx">
+		<image class="empty-img" :src="imgSrc"></image>
+		<view class="fs-26 text--w111-999 lh-36rpx pt-16">{{title}}</view>
+		<slot name="bottom"></slot>
+	</view>
+</template>
+
+<script>
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default{
+		props: {
+			title: {
+				type: String,
+				default: '暂无记录',
+			},
+			src:{
+				type: String,
+				default: '/statics/images/empty-box.gif',
+			}
+		},
+		data(){
+			return{
+				imgHost:HTTP_REQUEST_URL
+			}
+		},
+		computed:{
+			imgSrc(){
+				return HTTP_REQUEST_URL + this.src
+			}
+		}
+	}
+
+</script>
+
+<style lang="scss">
+	.pt-82{
+		padding: 82rpx 0 160rpx;
+	}
+	.empty-img{
+		width: 440rpx;
+		height: 360rpx;
+	}
+</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: #FFDE5C;
+			border-radius: 39rpx;
+			font-size: 30rpx;
+			font-weight: 500;
+			color: #B66A08;
+			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>

+ 417 - 0
components/filterPopup/index.vue

@@ -0,0 +1,417 @@
+<template>
+	<view :style="colorStyle">
+		<tui-drawer :mode="mode" :visible="visible" @close="closeDrawer">
+			<view class="acea-row row-column container">
+				<!-- #ifdef MP -->
+				<view :style="{height: getHeight.barTop+'px'}"></view>
+				<view :style="{height: getHeight.barHeight+'px'}" class="head-box acea-row row-center-wrapper">筛选</view>
+				<!-- #endif -->
+				<!-- #ifndef MP -->
+				<view class="head-box acea-row row-center-wrapper">筛选</view>
+				<!-- #endif -->
+				<scroll-view scroll-y="true" class="scroll-view">
+					<view class="d-container">
+						<!-- 品牌 -->
+						<view class="box brand-box">
+							<tui-collapse :index="brandIndex" :current="brandCurrent" @click="brandCollapse">
+								<template v-slot:title>
+									<tui-list-cell>品牌</tui-list-cell>
+								</template>
+								<template v-slot:content>
+									<view class="box-list acea-row">
+										<view class="box-list acea-row">
+											<view class="list acea-row row-center-wrapper line1" :class="{'bgcolor':spanIndex.indexOf(index)>-1}" v-for="(item,index) in list" :key="index"
+												@click="changeSpan(index,item)">
+												{{item.brand_name}}
+											</view>
+										</view>
+									</view>
+								</template>
+							</tui-collapse>
+						</view>
+						<!-- 分类 -->
+						<view class="box">
+							<view class="font">分类</view>
+							<scroll-view scroll-x="true" class="scroll-x-view" v-if="level == 3">
+								<view class="item" :class="{ on: navOneActive == index }" v-for="(item,index) in categoryList" :key="item.id" @click="tapNavOne(item,index)">
+									<view class="img-box">
+										<image :src="item.pic" class="img"></image>
+									</view>
+									<view class="title">{{item.cate_name}}</view>
+								</view>
+							</scroll-view>
+							<template v-for="(item,index) in categoryErList">
+								<tui-collapse :key="item.id" :index="index" :current="item.current" :disabled="item.disabled" @click="change">
+									<template v-slot:title>
+										<tui-list-cell>{{item.cate_name}}</tui-list-cell>
+									</template>
+									<template v-slot:content>
+										<view class="box-list acea-row">
+											<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="btn-box acea-row">
+					<view class="btn" @click="submit(2)">
+						重置
+					</view>
+					<view class="btn btnColor" @click="submit(1)">
+						确认
+					</view>
+				</view>
+				<view class="safe-area-inset-bottom"></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, //品牌数据
+
+			},
+			level: {
+				type: Number,
+				default: 2
+			}
+		},
+		mixins: [colors],
+		data() {
+			return {
+				getHeight: this.$util.getWXStatusHeight(),
+				statusBarHeight: statusBarHeight,
+				visible: false,
+				mode: "right",
+				sortIndex: 0,
+				spanIndex: [],
+				newList: [],
+				open: 1,
+				forArr: [],
+				serchData: {
+					sort: '', //new 最新, sales价值
+					sort_type: '', // DESC 倒序 ASC 正序
+					send: '',
+					cate_id: [],
+				},
+				brandIndex: 0,
+				brandCurrent: 0,
+				navOneActive: 0,
+				categoryList: [],
+				categoryErList: [],
+			}
+		},
+		computed: {
+			storeArr() {
+				return this.storeCategory
+			},
+			list() {
+				if (this.open === 1) {
+					return this.storeBrand.slice(0, 10)
+				} else if (this.open === 2) {
+					return this.storeBrand
+				}
+			},
+		},
+		watch: {
+			storeCategory(val) {
+				this.categoryList = val;
+				if (this.level == 2) {
+					this.categoryErList = this.categoryList;
+				} else {
+					this.categoryErList = this.categoryList[0].children;
+				}
+				this.sortIndex = this.categoryErList[0].children[0].id;
+				console.log(this.sortIndex)
+			},
+		},
+		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 cid = this.categoryList[this.navOneActive].id;
+				let sid = row.pid;
+				let tid = row.id;
+				if (this.level == 2) {
+					cid = row.pid;
+					sid = row.id;
+					tid = 0;
+				}
+				let data = {
+					cid: cid,
+					sid: sid,
+					tid: tid,
+				}
+				console.log(data)
+				this.$emit('categoryChange', data)
+			},
+			change(e) {
+				let index = e.index;
+				let item = this.categoryErList[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)
+			},
+			brandCollapse(e) {
+				this.brandCurrent = this.brandCurrent == e.index ? -1 : e.index;
+			},
+			tapNavOne(item, index) {
+				this.navOneActive = index;
+				this.categoryErList = this.categoryList[this.navOneActive].children;
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.safe-area-inset-bottom {
+		height: 0;
+		height: constant(safe-area-inset-bottom);
+		height: env(safe-area-inset-bottom);
+	}
+
+	.container {
+		flex-wrap: nowrap;
+		height: 100%;
+
+		.head-box {
+			height: 80rpx;
+			font-weight: 500;
+			font-size: 34rpx;
+			color: #333333;
+		}
+
+		.scroll-view {
+			flex: 1;
+			min-height: 0;
+		}
+
+		.btn-box {
+			padding: 20rpx 32rpx;
+
+			.btn {
+				flex: 1;
+				height: 72rpx;
+				border: 1rpx solid var(--view-theme);
+				border-radius: 36rpx;
+				margin-left: 14rpx;
+				text-align: center;
+				font-weight: 500;
+				font-size: 26rpx;
+				line-height: 72rpx;
+				color: var(--view-theme);
+				transform: rotateZ(360deg);
+
+				&:first-child {
+					margin-left: 0;
+				}
+			}
+
+			.btnColor {
+				background: var(--view-theme);
+				color: #FFFFFF;
+			}
+		}
+	}
+
+	.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: 24rpx;
+		font-size: 28rpx;
+		font-weight: 500;
+		color: #333333;
+	}
+
+	.font-live {
+		font-size: 28rpx;
+		font-weight: 500;
+		color: #333333;
+	}
+
+	.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 {
+		padding: 0 32rpx;
+
+		.box {
+			.title {
+				/* #ifndef MP */
+				// margin-top: 30rpx;
+				/* #endif */
+				// display: flex;
+				// justify-content: space-between;
+				// padding: 24rpx 0;
+			}
+
+			.box-list {
+				margin: 0 -26rpx 0 0;
+
+				.list {
+					width: 184rpx;
+					height: 56rpx;
+					border-radius: 28rpx;
+					margin: 0 26rpx 24rpx 0;
+					background: #F5F5F5;
+					font-size: 24rpx;
+					color: #333333;
+				}
+			}
+		}
+	}
+
+	.scroll-x-view {
+		white-space: nowrap;
+
+		.item {
+			display: inline-block;
+			padding: 24rpx 0;
+			margin-right: 8rpx;
+			vertical-align: middle;
+
+			&.on {
+				.img-box {
+					border-color: var(--view-theme);
+				}
+
+				.title {
+					background: linear-gradient(90deg, var(--view-gradient) 0%, var(--view-theme) 100%);
+					color: #FFFFFF;
+				}
+			}
+		}
+
+		.img-box {
+			width: 104rpx;
+			height: 104rpx;
+			padding: 6rpx;
+			border: 3rpx solid transparent;
+			border-radius: 50%;
+			margin: 0 auto;
+		}
+
+		.img {
+			width: 92rpx;
+			height: 92rpx;
+			border-radius: 50%;
+		}
+
+		.title {
+			width: 120rpx;
+			height: 40rpx;
+			border-radius: 20rpx;
+			margin-top: 8rpx;
+			text-align: center;
+			font-size: 24rpx;
+			line-height: 40rpx;
+			color: #333333;
+		}
+	}
+</style>

+ 218 - 0
components/goodClass/index.vue

@@ -0,0 +1,218 @@
+<template>
+	<!-- 分类三商品列表 -->
+	<view class="goodsList">
+		<view class="item acea-row" v-for="(item,index) in tempArr" :key="item.id" @click="goDetail(item)">
+			<view class="pictrue">
+				<image :src="item.image" mode="aspectFit"></image>
+			</view>
+			<view class="pictxt acea-row row-column">
+				<view class="text line1">{{item.store_name}}</view>
+				<view class="acea-row label-wrap">
+					<BaseTag v-for="label in item.store_label" :key="label.id" :text="label.label_name" :color="label.color" :borderColor="label.border_color" :background="label.bg_color"
+						:circle="!!label.border_color" :imgSrc="label.icon"></BaseTag>
+				</view>
+				<view class="bottom acea-row row-between-wrapper">
+					<BaseMoney :money="item.price" symbolSize="28" integerSize="44" decimalSize="28"></BaseMoney>
+					<template v-if="item.stock>0">
+						<view class="btn-box"
+							v-if="(item.activity && (item.activity.type === '1' || item.activity.type === '2' || item.activity.type === '3')) || item.product_type!=0 || item.custom_form.length || item.is_presale_product">
+							<text class="iconfont icon-ic_ShoppingCart1"></text>
+						</view>
+						<template v-else>
+							<!-- 多规格 -->
+							<uni-badge v-if="item.spec_type" class="uni-badge-left-margin" :text="item.cart_num" absolute="rightTop">
+								<view class="btn-box" @click.stop="goCartDuo(item)">
+									<text class="iconfont icon-ic_ShoppingCart1"></text>
+								</view>
+							</uni-badge>
+							<!-- 单规格 -->
+							<template v-else>
+								<view v-if="item.cart_num" class="cart acea-row">
+									<view class="btn acea-row row-center-wrapper" @click.stop="CartNumDes(index,item)">
+										<text class="iconfont icon-ic_Reduce"></text>
+									</view>
+									<view class="num">{{item.cart_num}}</view>
+									<view class="btn acea-row row-center-wrapper" @click.stop="CartNumAdd(index,item)">
+										<text class="iconfont icon-ic_increase"></text>
+									</view>
+								</view>
+								<view v-else>
+									<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 class="btn-box acea-row row-center-wrapper" v-else @click.stop="goCartDan(item,index)">
+											<text class="iconfont icon-ic_ShoppingCart1"></text>
+										</view>
+									</view>
+									<view v-else class="bnt acea-row row-center-wrapper">立即购买</view>
+								</view>
+							</template>
+						</template>
+					</template>
+					<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 {};
+		},
+		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 {
+			flex-wrap: nowrap;
+			margin-bottom: 24rpx;
+
+			.pictrue {
+				width: 176rpx;
+				height: 176rpx;
+				position: relative;
+
+				image {
+					width: 100%;
+					height: 100%;
+					border-radius: 16rpx;
+				}
+			}
+
+			.pictxt {
+				flex: 1;
+				flex-wrap: nowrap;
+				min-width: 0;
+				padding-left: 20rpx;
+
+				.text {
+					font-size: 28rpx;
+					line-height: 40rpx;
+					color: #333333;
+				}
+
+				.label-wrap {
+					flex: 1;
+					min-height: 0;
+					padding-top: 12rpx;
+				}
+
+				.bottom {
+					.cart {
+						.btn {
+							width: 48rpx;
+							height: 48rpx;
+							border-radius: 50%;
+							background: var(--view-theme);
+							text-align: center;
+							line-height: 48rpx;
+
+							.iconfont {
+								font-size: 28rpx;
+								color: #FFFFFF;
+							}
+						}
+
+						.num {
+							width: 60rpx;
+							height: 48rpx;
+							text-align: center;
+							font-weight: 500;
+							font-size: 30rpx;
+							line-height: 48rpx;
+							color: #333333;
+						}
+					}
+
+					.btn-box {
+						width: 48rpx;
+						height: 48rpx;
+						border-radius: 50%;
+						background-color: var(--view-theme);
+						text-align: center;
+						line-height: 48rpx;
+					}
+
+					.icon-ic_ShoppingCart1 {
+						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>

+ 140 - 0
components/groupGoodsList/index.vue

@@ -0,0 +1,140 @@
+<template>
+	<view v-if="goodsList.length" class="goods-list">
+		<view v-for="item in goodsList" :key="item.userInfo.uid" class="item">
+			<view class="head acea-row row-middle">
+				<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 line1">{{ 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 acea-row">
+					<image class="image" :src="cell.productInfo.attrInfo.image" mode="aspectFill"></image>
+					<view class="name-wrap">
+						<view class="name line2">{{ cell.productInfo.store_name }}</view>
+						<view class="attr line1">{{ cell.productInfo.attrInfo.suk }}</view>
+					</view>
+					<view class="money-wrap">
+						<BaseMoney :money="cell.truePrice" symbolSize="20" integerSize="32" decimalSize="20" color="#333333"></BaseMoney>
+						<view class="num">共{{ cell.cart_num }}件</view>
+					</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 {
+			padding: 0 24rpx;
+			border-radius: 24rpx;
+			margin-top: 20rpx;
+			background: #FFFFFF;
+
+			&:first-child {
+				margin-top: 0;
+			}
+
+			.head {
+				height: 108rpx;
+				border-bottom: 1rpx solid #F5F5F5;
+				transform: rotateZ(360deg);
+				font-size: 26rpx;
+				color: #333333;
+
+				.name-wrap {
+					flex: 1;
+					min-width: 0;
+					padding-left: 20rpx;
+				}
+
+				.name-inner {
+					display: inline-flex;
+					align-items: center;
+					max-width: 100%;
+				}
+
+				.name {
+					flex: 1;
+					min-width: 0;
+				}
+			}
+
+			.avatar {
+				width: 40rpx;
+				height: 40rpx;
+				border-radius: 50%;
+			}
+
+			.body {
+				padding: 32rpx 0;
+
+				.cell {
+					margin-top: 32rpx;
+
+					&:first-child {
+						margin-top: 0;
+					}
+
+					.name-wrap {
+						flex: 1;
+						min-width: 0;
+						padding: 0 20rpx;
+					}
+
+					.name {
+						font-size: 28rpx;
+						line-height: 40rpx;
+						color: #333333;
+					}
+
+					.attr {
+						margin-top: 12rpx;
+						font-size: 24rpx;
+						line-height: 34rpx;
+						color: #999999;
+					}
+				}
+
+				.image {
+					width: 136rpx;
+					height: 136rpx;
+					border-radius: 16rpx;
+				}
+
+				.money-wrap {
+					text-align: right;
+				}
+
+				.num {
+					margin-top: 10rpx;
+					font-size: 24rpx;
+					line-height: 34rpx;
+					color: #999999;
+				}
+			}
+		}
+	}
+</style>

+ 150 - 0
components/guide/index.vue

@@ -0,0 +1,150 @@
+<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
+		},
+		beforeDestroy() {
+			clearInterval(this.timecount)
+		},
+		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;
+	}
+
+	.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-yonghu-xianxing'></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>

+ 125 - 0
components/homeList/index.vue

@@ -0,0 +1,125 @@
+<template>
+	<!-- 顶部下拉导航 -->
+	<view class="animated dialog_nav dialogIndex" 
+		:style="{ top: navH + 'px' }" v-show="currentPage">
+		<view class="dialog_nav_item" :class="item.after" 
+			v-for="(item,index) in headerNav" :key="index" 
+			@tap="linkPage(item.url)">
+			<text class="iconfont" :class="item.icon"></text>
+			<text class="pl-20">{{item.name}}</text>
+		</view>
+	</view>
+</template>
+<script>
+	export default {
+		name: "homeIdex",
+		props: {
+			navH: {
+				type: String|Number,
+				default: ""
+			},
+			currentPage: {
+				type: Boolean,
+				default: false
+			},
+			openNavList:{
+				type: Array,
+				default: ()=>[]
+			}
+		},
+		data() {
+			return {
+				selectNavList:[
+					{name:'首页',icon:'icon-ic_mall',url:'/pages/index/index',after:'dialog_after'},
+					{name:'搜索',icon:'icon-ic_search',url:'/pages/goods/goods_search/index',after:'dialog_after'},
+					{name:'购物车',icon:'icon-ic_ShoppingCart1',url:'/pages/order_addcart/order_addcart',after:'dialog_after'},
+					{name:'我的收藏',icon:'icon-ic_star',url:'/pages/users/user_goods_collection/index',after:'dialog_after'},
+					{name:'个人中心',icon:'icon-a-ic_user1',url:'/pages/user/index'},
+				]
+			};
+		},
+		computed:{
+			headerNav(){
+				let arr = [];
+				this.selectNavList.forEach((item,index)=>{
+					if(this.openNavList.includes(index)){
+						arr.push(item);
+					}
+				})
+				return arr
+			}
+		},
+		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
+					})
+				}
+			}
+		},
+	};
+</script>
+
+<style scoped lang="scss">
+	.dialog_nav{
+		position: fixed;
+		left: 14rpx;
+		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;
+			left: -26rpx;
+			right: 0;
+			margin:auto;
+			top:-9px;
+			border-bottom: 10px solid #FFFFFF;
+			border-left: 10px solid transparent;    /*transparent 表示透明*/
+			border-right: 10px solid transparent;
+		}
+		&.dialogIndex{
+			left: 14rpx;
+			&::before{
+				left: 0rpx;
+			}
+		}
+	}
+	.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>

+ 159 - 0
components/kefu/index.vue

@@ -0,0 +1,159 @@
+<template>
+  <!-- 客服列表 -->
+  <view v-if="show" :style="colorStyle">
+    <view class="discountInfo on">
+      <view class="title">
+		  客服列表
+		  <view class="btn acea-row row-center-wrapper" style="flex-wrap: nowrap;" @click="closeDiscount"><text class="iconfont icon-ic_close"></text></view>
+	</view>
+      <view class="list">
+        <view class="item acea-row row-middle" 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 acea-row row-center-wrapper" @click="callPhone(item)">
+            <view class="inner">联系客服</view>
+          </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){
+					if (item.customer_phone) {
+						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: 40rpx 40rpx 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 {
+		height: 108rpx;
+		font-weight: 500;
+      font-size: 32rpx;
+	  line-height: 108rpx;
+      color: #333333;
+      text-align: center;
+      position: relative;
+
+      .btn {
+        position: absolute;
+		top: 50%;
+        right: 32rpx;
+		width: 36rpx;
+		height: 36rpx;
+		border-radius: 50%;
+		background: #EEEEEE;
+		transform: translateY(-50%);
+		text-align: center;
+		line-height: 36rpx;
+      }
+	  
+	  .iconfont {
+		  font-size: 24rpx;
+		  color: #999999;
+		  vertical-align: text-bottom;
+	  }
+    }
+
+    .list {
+      height: 750rpx;
+      margin: 34rpx 32rpx;
+      overflow-x: hidden;
+      overflow-y: auto;
+
+      .item {
+        height: 80rpx;
+		margin-bottom: 40rpx;
+
+        .img {
+          width: 80rpx;
+          height: 80rpx;
+          border-radius: 50%;
+          border: 1rpx solid #EEEEEE;
+		  transform: rotateZ(360deg);
+        }
+
+        .text {
+			flex: 1;
+			padding: 0 20rpx;
+          font-size: 28rpx;
+          color: #333333;
+        }
+
+        .contact {
+          width: 166rpx;
+          height: 56rpx;
+		  border-radius: 40rpx;
+          background: var(--view-theme);
+		  text-align: center;
+          font-size: 24rpx;
+		  line-height: 56rpx;
+          color: var(--view-theme);
+		  // overflow: hidden;
+		  
+		  .inner {
+			  width: 168rpx;
+			  height: 56rpx;
+			  // border-radius: 28rpx;
+			  background: rgba(255, 255, 255, 0.9);
+		  }
+        }
+      }
+    }
+  }
+
+  .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>

+ 252 - 0
components/pageFooter/index.vue

@@ -0,0 +1,252 @@
+<template>
+	<!-- 底部导航 -->
+	<view v-if="showTabBar">
+		<view class="fixed-lb w-full pb-safe z-999" :style="[bgColor]">
+			<view class="page-footer-wrapper">
+				<view class="page-footer" :class="{
+					'page-footer2': newData.navStyleConfig.tabVal == 1,
+					'page-footer3': newData.navStyleConfig.tabVal == 2,
+				}" id="target" :style="[componentStyle]">
+					<view class="foot-item flex-1 flex-col flex-center h-96 relative" v-for="(item,index) in newData.menuList" :key="index" @click="goRouter(item)">
+						<template v-if="item.link.split('?')[0] == activeRouter">
+							<image v-if="newData.navStyleConfig.tabVal != 1" :src="item.imgList[0]"></image>
+							<view v-if="newData.navStyleConfig.tabVal != 2" class="txt active" :style="[txtActiveColor]">{{item.name}}</view>
+						</template>
+						<template v-else>
+							<image v-if="newData.navStyleConfig.tabVal != 1" :src="item.imgList[1]"></image>
+							<view v-if="newData.navStyleConfig.tabVal != 2" class="txt" :style="[txtColor]">{{item.name}}</view>
+						</template>
+						<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>
+		<view :style="{ height: `${footerHeight}px` }"></view>
+		<view class="safe-area-inset-bottom"></view>
+	</view>
+</template>
+
+<script>
+	import {mapState,mapGetters} from "vuex"
+	import {getNavigation} from '@/api/public.js'
+	import {getCartCounts} from '@/api/order.js';
+	import {getDiyVersion} from '@/api/api.js';
+	export default {
+		name: 'pageFooter',
+		props: {},
+		computed: {
+			...mapGetters(['isLogin', 'cartNum']),
+			txtActiveColor() {
+				let styleObject = {};
+				if (this.newData.toneConfig && this.newData.toneConfig.tabVal) {
+					styleObject['color'] = this.newData.activeTxtColor.color[0].item;
+				}
+				return styleObject;
+			},
+			txtColor() {
+				let styleObject = {};
+				if (this.newData.toneConfig && this.newData.toneConfig.tabVal) {
+					styleObject['color'] = this.newData.txtColor.color[0].item;
+				}
+				return styleObject;
+			},
+			bgColor() {
+				let styleObject = {};
+				if (!this.newData.name) {
+					return styleObject;
+				}
+				if (!this.newData.navConfig.tabVal) {
+					styleObject['background'] = this.newData.bgColor.color[0].item;
+				}
+				return styleObject;
+			},
+			componentStyle() {
+				let styleObject = {};
+				let borderRadius = ``;
+				if (!this.newData.name) {
+					return styleObject;
+				}
+				if (this.newData.navConfig.tabVal) {
+					borderRadius = `${this.newData.fillet.val * 2}rpx`;
+					if (this.newData.fillet.type) {
+						borderRadius =
+							`${this.newData.fillet.valList[0].val * 2}rpx ${this.newData.fillet.valList[1].val * 2}rpx ${this.newData.fillet.valList[3].val * 2}rpx ${this.newData.fillet.valList[2].val * 2}rpx`;
+					}
+					styleObject['right'] = `${this.newData.prConfig.val * 2}rpx`;
+					styleObject['bottom'] = `${this.newData.mbConfig.val * 2}rpx`;
+					styleObject['left'] = `${this.newData.prConfig.val * 2}rpx`;
+					styleObject['padding-top'] = `${this.newData.topConfig.val * 2}rpx`;
+					styleObject['padding-bottom'] = `${this.newData.bottomConfig.val * 2}rpx`;
+					styleObject['border-radius'] = borderRadius;
+					styleObject['background'] = this.newData.bgColor2.color[0].item;
+				} else {
+					styleObject['padding-top'] = `${this.newData.topConfig.val * 2}rpx`;
+					styleObject['padding-bottom'] = `${this.newData.bottomConfig.val * 2}rpx`;
+					styleObject['background'] = this.newData.bgColor.color[0].item;
+				}
+				return styleObject;
+			},
+		},
+		// watch: {
+		// 	'newData.menuList'(newValue, oldValue) {
+		// 		this.$nextTick(() => {
+		// 			const query = uni.createSelectorQuery().in(this);
+		// 			query.select("#target").boundingClientRect(({
+		// 				height
+		// 			}) => {
+		// 				this.footerHeight = height;
+		// 			}).exec();
+		// 		});
+		// 	}
+		// },
+		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: '',
+				showTabBar: false,
+				footerHeight: 0
+			}
+		},
+		methods: {
+			setNavigationInfo(data) {
+				this.newData = data;
+				this.showTabBar = data.effectConfig.tabVal;
+				let pdHeight = data.topConfig.val + data.bottomConfig.val;
+				this.$emit('newDataStatus', data.effectConfig.tabVal,pdHeight)
+				if (data.effectConfig.tabVal) {
+					uni.hideTabBar()
+				} else {
+					uni.showTabBar()
+				}
+			},
+			getNavigationInfo() {
+				getNavigation().then(res => {
+					uni.setStorageSync('diyVersionNav', res.data);
+					this.setNavigationInfo(res.data);
+				})
+			},
+			navigationInfo() {
+				let footerNavigation = uni.getStorageSync('footerNavigation');
+				if (footerNavigation) {
+					getDiyVersion(0).then(res => {
+						let diyVersion = uni.getStorageSync('diyVersionNav');
+						if ((res.data.version + '0') === diyVersion) {
+							this.setNavigationInfo(footerNavigation);
+						} else {
+							uni.setStorageSync('diyVersionNav', (res.data.version + '0'));
+							this.getNavigationInfo();
+						}
+					});
+				} else {
+					this.getNavigationInfo();
+				}
+			},
+			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() {
+				getCartCounts().then(res => {
+					this.$store.commit('indexData/setCartNum', res.data.count + '')
+				}).catch(err=>{
+					console.log(err.msg);
+				})
+			},
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.safe-area-inset-bottom {
+		height: 0;
+		height: constant(safe-area-inset-bottom);
+		height: env(safe-area-inset-bottom);
+	}
+
+	.page-footer-wrapper {
+		position: relative;
+	}
+
+	.page-footer {
+		position: absolute;
+		right: 0;
+		bottom: 0;
+		left: 0;
+		display: flex;
+
+		.foot-item image {
+			display: block;
+			height: 40rpx;
+			width: 40rpx;
+			margin: 0 auto;
+		}
+
+		.foot-item .txt {
+			margin-top: 4rpx;
+			font-size: 20rpx;
+			line-height: 28rpx;
+			color: #333333;
+
+			&.active {
+				color: var(--view-theme);
+			}
+		}
+	}
+
+	.page-footer2 .foot-item .txt {
+		margin-top: 0;
+		font-size: 32rpx;
+		line-height: 44rpx;
+		color: #333333;
+
+		&.active {
+			color: var(--view-theme);
+		}
+	}
+
+	.page-footer2.float .foot-item::before,
+	.page-footer3.float .foot-item::before {
+		content: "";
+		position: absolute;
+		top: 50%;
+		left: 0;
+		width: 2rpx;
+		height: 32rpx;
+		background: #CCCCCC;
+		transform: translateY(-50%);
+	}
+
+	.page-footer2.float .foot-item:first-child::before,
+	.page-footer3.float .foot-item:first-child::before {
+		display: none;
+	}
+</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>

+ 264 - 0
components/productConSwiper/index.vue

@@ -0,0 +1,264 @@
+<template>
+  <!-- 商品详情轮播图 -->
+  <view class="product-bg" :style="[swiperHeight]">
+    <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 class="w-full flex-center absolute left-0 bottom-54rpx z-4" v-if="imgUrls.length > 1 && showDot">
+      <block v-for="(_, index) in imgUrls" :key="index">
+        <view class="dot_item h-4 rd-2rpx" :style="{ 'background-color': currents == index ? '#fff' : 'rgba(255,255,255,0.4)', width: dotWidth + 'rpx' }"></view>
+      </block>
+    </view>
+    <view class="w-full flex-center abs-lb h-200 white-jianbian"></view>
+  </view>
+</template>
+
+<script>
+export default {
+  props: {
+    imgUrls: {
+      type: Array,
+      default: () => []
+    },
+    videoline: {
+      type: String,
+      default: ''
+    },
+    showDot: {
+      type: Number,
+      default: 1
+    },
+    autoHeight: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      indicatorDots: false,
+      circular: true,
+      autoplay: true,
+      interval: 3000,
+      duration: 500,
+      currents: 0,
+      controls: true,
+      isPlay: true,
+      videoContext: '',
+      imgHeight:0
+    };
+  },
+  mounted() {
+    if (this.videoline) {
+      this.imgUrls.shift();
+    }
+    // #ifndef APP-PLUS
+    this.videoContext = uni.createVideoContext('myVideo', this);
+    // #endif
+  },
+  computed: {
+    dotWidth() {
+      let windowWidth = uni.getSystemInfoSync().windowWidth;
+      return (windowWidth * 2 - (40 + (this.imgUrls.length - 1) * 12)) / this.imgUrls.length;
+    },
+    swiperHeight() {
+      let windowWidth = uni.getSystemInfoSync().windowWidth;
+      let that = this;
+      uni.getImageInfo({
+        src: this.imgUrls[0],
+        success: (image) => {
+          that.imgHeight = image.height * windowWidth / image.width;
+        }
+      });
+
+      if (this.autoHeight) {
+        return {
+          height: `${this.imgHeight}px`
+        };
+      } else {
+        return {
+          height: '750rpx'
+        };
+      }
+    }
+  },
+  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);
+    }
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.item-box {
+  width: 100%;
+  height: 100%;
+}
+
+.product-bg {
+  width: 100%;
+  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%;
+}
+
+.dot_item ~ .dot_item {
+  margin-left: 12rpx;
+}
+.white-jianbian {
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
+}
+</style>

+ 907 - 0
components/productWindow/index.vue

@@ -0,0 +1,907 @@
+<template>
+	<view>
+		<view class="product-window"
+			:class="(attr.cartAttr === true ? 'on' : '') + ' ' + (iSbnt?'join':'') + ' ' + (iScart?'joinCart':'')"
+			@touchmove.stop.prevent="moveHandle">
+			<view class="textpic acea-row">
+				<view class="pictrue" @click="showImg()">
+					<image :src="attr.productSelect.image"></image>
+					<view class="icon flex-center" v-if="fangda">
+						<view class="iconfont icon-ic_enlarge"></view>
+					</view>
+				</view>
+				<view class="pl-24 pt-24 flex-col">
+					<view class="flex-y-center" v-if="attr.productSelect.integral">
+						<image src="../../static/img/mall05.png" class="w-32 h-32"></image>
+						<text class="lh-40rpx font-num fs-40 SemiBold pl-8">{{attr.productSelect.integral}}</text>
+						<text class="fs-28 lh-40rpx px-8 text--w111-666">+</text>
+						<baseMoney :money="attr.productSelect.price" symbolSize="28" integerSize="40" decimalSize="28" color="var(--view-theme)" weight></baseMoney>
+					</view>
+					<baseMoney
+					:money="attr.productSelect.price"
+					symbolSize="32"
+					integerSize="48"
+					decimalSize="32"
+					incolor="var(--primary-theme-con)"
+					weight v-else></baseMoney>
+					<view class="inline-block h-48 lh-48rpx text-center rd-24rpx bg-color fs-24 text--w111-fff px-20 mt-16"
+						v-if="type == 0">
+						预估到手 <text class="fs-28 fw-600 pl-8">¥{{attr.productSelect.delivery_price}}</text>
+					</view>
+					<view class="mt-12 fs-24 text-#999">库存:{{ attr.productSelect.stock }}</view>
+				</view>
+				<view class="close w-36 h-36 bg--w111-eee rd-36px acea-row row-center-wrapper" @click="closeAttr">
+					<text class="iconfont icon-ic_close fs-24"></text>
+				</view>
+			</view>
+			<view class="rollTop">
+				<scroll-view scroll-y="true" :style="'max-height: '+windowHeight+'rpx'" >
+					<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="selfPickup" @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 on1" v-if="flag ==1 && isDelivery" @click="openAddress">
+							<view class="acea-row row-middle">
+								<view class="max-w-596 line1">{{addressInfo}}</view>
+								<view class="iconfont icon-ic_rightarrow ml-8 fs-28"></view>
+							</view>
+							<view class="info">{{nameInfo}}</view>
+						</view>
+						<view class="address" :class="[deliveryType]" v-if="flag ==3 && isDelivery" @click="openStore">
+							<view class="acea-row row-middle">
+								<view class="max-w-596 line1">{{deliveryName}}</view>
+								<view class="iconfont icon-ic_rightarrow ml-8 fs-28" v-if="attr.isType != 1"></view>
+							</view>
+							<view class="info">
+								<text class="iconfont icon-ic_location51 fs-24 mr-10"></text>{{deliveryAddress}}<text class="ml-16">{{distance}}</text>
+							</view>
+						</view>
+						<view class="address" :class="attr.deliveryType.includes('1')?'on3':'on1'" v-if="flag ==2 && isDelivery"  @click="openStore">
+							<view class="acea-row row-middle">
+								<view class="max-w-596 line1">{{deliveryName}}</view>
+								<view class="iconfont icon-ic_rightarrow ml-8 fs-28" v-if="attr.isType != 1"></view>
+							</view>
+							<view class="info">
+								<text class="iconfont icon-ic_location51 fs-24 mr-10"></text>{{deliveryAddress}}<text class="ml-16">{{distance}}</text>
+							</view>
+						</view>
+					</view>
+				</scroll-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-ic_Reduce"></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-ic_Reduce"></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 class="item plus acea-row row-center-wrapper"
+							:class="attr.productSelect.cart_num >= attr.productSelect.stock ? 'on' : ''" @click="CartNumAdd">
+							<text class="iconfont icon-ic_increase"></text>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view v-if="isExtends">
+				<view class="joinBnt bg-gray" v-if="attr.productSelect.stock <= 0">已售罄</view>
+				<view class="joinBnt bg-color" v-else @click="cartConfirm">确定</view>
+			</view>
+			<view class="joinBnt bg-color"
+				v-if="iSbnt && attr.productSelect.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="mask" @touchmove.stop.prevent="moveHandle" :hidden="attr.cartAttr === false" @click="closeAttr"></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-middle">
+						<view class="iconfont icon-ic_location51"></view>
+						<view class="info">{{item.address}}{{item.detailed_address}}</view>
+					</view>
+					<view class="time acea-row row-middle">
+						<view class="iconfont icon-icon_clock"></view>
+						<view>营业时间:{{item.day_time}}</view>
+					</view>
+					<view class="iconfont icon-xuanzhong6" v-if="active == index"></view>
+				</view>
+			</view>
+		</view>
+		<view class="mask on" @touchmove.prevent :hidden="isStore === false" @click="closeStore"></view>
+		<addressWindow ref="addressWindow" :pagesUrl="pagesUrl" :fromType="1" :address="address" @changeClose="changeClose" @OnChangeAddress="OnChangeAddress">
+		</addressWindow>
+	</view>
+</template>
+
+<script>
+	let windowHeight = (uni.getSystemInfoSync().windowHeight*(3/4)-238)*2;
+	import addressWindow from '@/components/addressWindow';
+	import {getAddressDefault} 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']),
+			selfPickup(){
+				let obj = this.attr.deliveryType.includes('2') && this.selfStoreList.length
+				return obj
+			},
+			deliveryType(){
+				let on = ''
+				if(this.attr.deliveryType.includes('1') && this.selfPickup){
+					on = 'on2'
+				}else if((!this.attr.deliveryType.includes('1') && this.selfPickup) || (this.attr.deliveryType.includes('1') && !this.selfPickup)){
+					on = 'on3'
+				}else{
+					on = 'on1'
+				}
+				return on
+			}
+		},
+		components:{
+		  addressWindow
+		},
+		props: {
+			isStoreBuy: {
+				type: Number,
+				value: 0
+			},
+			// 商品id
+			productId: {
+				type: Number | String,
+				value: 0
+			},
+			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: [Number, String],
+				default: 0
+			},
+			fangda: {
+				type: Boolean,
+				default: true
+			},
+			isExtends:{
+				type: Boolean,
+				default: false
+			},
+			storeId:{
+				type: Number,
+				value: 0
+			}
+		},
+		data() {
+			return {
+				flag:1,
+				nameInfo:'', //地址用户信息
+				addressInfo:'', // 商城快递
+				deliveryName:'', // 门店配送
+				distance:'',
+				deliveryAddress:'',
+				address: {
+					address: false
+				},
+				pagesUrl:'',
+				user_latitude: 0,
+				user_longitude: 0,
+				isDelivery: false,
+				storeList: [],
+				deliveryStoreList: [],
+				selfStoreList: [],
+				active:0,
+				isStore: false,
+				windowHeight:windowHeight,
+				isAddress:false
+			};
+		},
+		watch: {
+			'attr.deliveryType'(newValue, oldValue) {
+				if (JSON.stringify(newValue) != JSON.stringify(oldValue)) {
+					if (newValue.length) {
+						if(this.active<1){
+							this.getList();
+						}
+						let num = 1;
+						if(newValue[0] == 1 && this.isStoreBuy){
+							num = newValue[1];
+						}else{
+							num = newValue[0];
+						}
+						this.flag = num
+						this.$emit('deliveryFun',num);
+					}
+				}
+			},
+			'storeId'(){
+				this.defaultStore();
+				this.$emit('onstoreId',this.storeList[this.active],this.flag);
+			}
+		},
+		mounted() {
+			try {
+				this.user_latitude = uni.getStorageSync('user_latitude');
+				this.user_longitude = uni.getStorageSync('user_longitude');
+			} catch (e) {}
+			uni.$off('activeAddress');
+			uni.$on('activeAddress', data => {
+				this.getAddressDefault();
+			})
+		},
+		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.nameInfo = row.real_name+'\xa0\xa0'+row.phone
+				this.addressInfo = row.province+'省'+row.city+row.district+row.street+row.detail
+				this.$emit('onAddressId',row)
+			},
+			// 打开地址弹窗
+			openAddress(){
+				let pagesUrl = '/pages/users/user_address/index?fromType=1';
+				if(!this.isAddress){
+					this.$refs.addressWindow.getAddressList();
+					this.address.address = true;
+					this.pagesUrl = pagesUrl
+				}else{
+					uni.navigateTo({
+						url: pagesUrl
+					});
+				}
+			},
+			// 关闭地址弹窗;
+			changeClose: function() {
+			  this.$set(this.address, 'address', false);
+			},
+			// 配送地址
+			getAddressDefault() {
+				getAddressDefault().then(res=>{
+					let data = res.data;
+					this.isAddress = Array.isArray(data);
+					if(!Array.isArray(data)){
+						this.nameInfo = data.real_name+'\xa0\xa0'+data.phone
+						this.addressInfo = data.province+'省'+data.city+data.district+data.street+data.detail
+						this.$emit('onAddressId',data)
+					}else{
+						this.addressInfo = '点击添加地址'
+					}
+				}).catch(err=>{
+				   this.$util.Tips({
+					   title: err
+				   })
+				})
+			},
+			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 == 1?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.deliveryType.indexOf('3') != -1)){
+							this.isDelivery = true;
+							if(this.$store.getters.isLogin){
+								this.getAddressDefault()
+							}
+						}
+						// 拆分自提门店列表和配送门店列表
+						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.defaultStore();
+						this.$emit('onstoreId',this.storeList[this.active],this.flag);
+					})
+					.catch(err => {
+						this.$util.Tips({
+							title: err
+						})
+					});
+			},
+			defaultStore(){
+				let storeId = this.storeId?this.storeId:this.nearbyStore
+				let storeIndex = 0
+				this.storeList.forEach((item,index)=>{
+					if(item.id == storeId){
+						storeIndex = index
+					}
+				})
+				this.active = storeIndex;
+				this.deliveryName = this.storeList[storeIndex].name;
+				this.deliveryAddress = this.storeList[storeIndex].detailed_address+'\xa0';
+				this.distance = '距您'+this.storeList[storeIndex].range+'km';
+			},
+			// 选择配送方式
+			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.defaultStore();
+				this.$emit('deliveryFun',index);
+				this.$emit('onstoreId',this.storeList[this.active],index);
+			},
+			showLocation(){
+				if ((!this.user_latitude || !this.user_longitude) && !uni.getStorageSync('refuseLocation')) {
+					this.selfLocation();
+				}
+			},
+			moveHandle(){},
+			goCat: function() {
+				this.$emit('goCat');
+			},
+			/**
+			 * 购物车手动输入数量
+			 *
+			 */
+			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;
+			},
+			showImg() {
+				this.$emit('getImg');
+			},
+			cartConfirm(){
+				this.$emit('onConfirm');
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.mask{
+		&.on{
+			z-index: 100;
+		}
+	}
+	.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 {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		background-color: #fff;
+		z-index: 100;
+		border-radius: 40rpx 40rpx 0 0;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		padding-bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/
+		padding-bottom: env(safe-area-inset-bottom);///兼容 IOS>11.2/
+		
+		&.store{
+			background-color: #F5F5F5;
+			border-radius: 40rpx 40rpx 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.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.product-window.join {
+		padding-bottom: 30rpx;
+	}
+
+	.product-window.joinCart {
+		padding-bottom: 30rpx;
+		z-index: 1000;
+	}
+
+	.product-window .textpic {
+		padding: 0 32rpx;
+		margin-top: 48rpx;
+		position: relative;
+		.close{
+			position: absolute;
+			right: 38rpx;
+			top: -14rpx;
+		}
+	}
+
+	.product-window .textpic .pictrue {
+		width: 180rpx;
+		height: 180rpx;
+		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: 16rpx;
+	}
+
+	.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 {
+		margin-top: 36rpx;
+	}
+	.product-window .productWinList{
+		.address{
+			width: 690rpx;
+			background: #F5F5F5;
+			padding: 24rpx 38rpx 24rpx 20rpx;
+			margin: 28rpx auto;
+			font-weight: 400;
+			color: #333333;
+			font-size: 28rpx;
+			border-radius: 8rpx;
+			position: relative;
+			&::before{
+				position: absolute;
+				content: '';
+				top:-10rpx;
+				width: 0;
+				height: 0;
+				border-left: 14rpx solid transparent;
+				border-right: 14rpx solid transparent;
+				border-bottom: 12rpx solid #F5F5F5;
+			}
+			&.on1{
+				&::before{
+					left:78rpx;
+				}
+			}
+			&.on2{
+				&::before{
+					left: 480rpx;
+				}
+			}
+			&.on3{
+				&::before{
+					left:280rpx;
+				}
+			}
+			.info{
+				font-weight: 400;
+				color: #999999;
+				font-size: 24rpx;
+				margin-top: 12rpx;
+				.con{
+					width: 416rpx;
+				}
+			}
+		}
+	}
+	.product-window .productWinList .item~.item {
+		margin-top: 36rpx;
+	}
+
+	.product-window .productWinList .item .title {
+		font-size: 28rpx;
+		font-weight: 500;
+		color: #333;
+		padding: 0 32rpx;
+	}
+
+	.product-window .productWinList .item .listn {
+		padding: 0 32rpx 0 16rpx;
+	}
+
+	.product-window .productWinList .item .listn .itemn {
+		// height: 56rpx;
+		// line-height: 56rpx;
+		border: 1rpx solid #F2F2F2;
+		font-size: 24rpx;
+		color: #333;
+		padding: 10rpx 44rpx;
+		border-radius: 28rpx;
+		margin: 24rpx 0 0 16rpx;
+		background-color: #F2F2F2;
+		word-break: break-all;
+	}
+
+	.product-window .productWinList .item .listn .itemn.on {
+		color: var(--view-theme);
+		background: var(--view-minorColorT);
+		border-color: var(--view-theme);
+	}
+
+	.product-window .productWinList .item .listn .itemn.limit {
+		color: #999;
+		text-decoration: line-through;
+	}
+
+	.product-window .cart {
+		padding: 0 30rpx;
+	}
+
+	.product-window .cart .title {
+		font-size: 28rpx;
+		color: #333;
+	}
+
+	.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 {
+		// border-color: #e3e3e3;
+		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;
+		border-radius: 4rpx;
+	}
+
+	.product-window .joinBnt {
+		font-size: 28rpx;
+		width: 710rpx;
+		height: 80rpx;
+		border-radius: 40rpx;
+		text-align: center;
+		line-height: 80rpx;
+		color: #fff;
+		margin: 74rpx auto 12rpx;
+	}
+
+	.product-window .joinBnt.on {
+		background-color: #bbb;
+		color: #fff;
+	}
+	.mt-74{
+		margin-top: 74rpx;
+	}
+	.join_cart{
+		background-color: var(--view-bntColor);
+	}
+	.bg-gray{
+		background-color: #CCCCCC;
+	}
+</style>

+ 59 - 0
components/recommend/index.vue

@@ -0,0 +1,59 @@
+<template>
+	<!-- 热门推荐 -->
+	<view class='recommend' :style="colorStyle">
+		<view class="flex-center">
+			<image class="zs" src="../../static/img/recommend_zs.png"></image>
+			<text class="fs-32 fw-500 text--w111-333 lh-44rpx px-6">{{ title }}</text>
+			<image class="zs" src="../../static/img/recommend_zs.png"></image>
+		</view>
+		<view class="relative mt-24">
+			<view class="jinabian"></view>
+			<waterfallsFlow ref="waterfallsFlow" :wfList="hostProduct" recommend @itemTap="goDetail"></waterfallsFlow>
+		</view>
+	</view>
+</template>
+
+<script>
+import {mapGetters} from "vuex";
+import { goShopDetail } from '@/libs/order.js'
+import colors from "@/mixins/color";
+import waterfallsFlow from "@/components/WaterfallsFlow/WaterfallsFlow.vue";
+export default {
+	props: {
+		hostProduct: {
+			type: Array,
+			default: function() {
+				return [];
+			}
+		},
+		title: {
+			type: String,
+			default: '猜你喜欢'
+		}
+	},
+	components: {
+		waterfallsFlow,
+	},
+	mixins: [colors],
+	computed: mapGetters(['uid']),
+	methods: {
+		goDetail(item){
+			goShopDetail(item, this.uid).catch(res => {
+				uni.navigateTo({
+					url: `/pages/goods_details/index?id=${item.id}`
+				});
+			});
+		}
+	},
+}
+</script>
+
+<style scoped lang="scss">
+	.recommend{
+		padding-top:40rpx;
+	}
+	.zs{
+		width:42rpx;
+		height:36rpx;
+	}
+</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>

+ 45 - 0
components/specs/index.vue

@@ -0,0 +1,45 @@
+<template>
+  <!-- 产品参数 -->
+  <base-drawer mode="bottom" :visible="specsInfo.show" background-color="transparent" mask maskClosable @close="closeSpecs">
+    <view class="w-full bg--w111-fff rd-t-40rpx py-32">
+      <view class="text-center fs-32 text--w111-333 fw-500 mb-34">参数</view>
+      <scroll-view scroll-y="true" class="h-400">
+        <view class="px-32 scroll-content">
+          <view class="item flex break_word" v-for="(item,index) in specsInfo.specs" :key="index">
+            <view class="w-160 text--w111-999 mr-12">{{item.name}}</view>
+            <view class="flex-1">{{item.value}}</view>
+          </view>
+        </view>
+      </scroll-view>
+      <view class="mx-20 pb-safe">
+        <view class="mt-52 h-72 flex-center rd-36px bg-color fs-26 text--w111-fff" @click="closeSpecs">确定</view>
+      </view>
+    </view>
+  </base-drawer>
+</template>
+
+<script>
+import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
+export default {
+  props: {
+    specsInfo: {
+      type: Object,
+      default: () => {}
+    },
+  },
+  components: {
+    baseDrawer
+  },
+  methods: {
+    closeSpecs() {
+      this.$emit('myevent');
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.item ~ .item{
+  margin-top: 40rpx;
+}
+</style>

+ 257 - 0
components/splitOrder/index.vue

@@ -0,0 +1,257 @@
+<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="acea-row row-middle money-section">
+								实付款:<view class='money'>¥{{item.cart_info.sum_true_price}}</view>
+							</view>
+						</view>
+						<view class='carnum acea-row row-center-wrapper'>
+							<view class="reduce iconfont icon-ic_Reduce" :class="item.surplus_num == 1 ? 'on' : ''" @click.stop='subCart(item)'></view>
+							<view class='num'>{{item.surplus_num}}</view>
+							<view class="plus iconfont icon-ic_increase" :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 {
+		width: 710rpx;
+		background-color: #fff;
+		border-radius: 16rpx;
+		margin: 24rpx auto 0 auto;
+		padding: 32rpx 26rpx;
+	}
+
+	.splitOrder .all {
+		padding: 20rpx 30rpx;
+	}
+
+	.splitOrder .all .checkAll {
+		margin-left: 20rpx;
+	}
+
+	.splitOrder .items~.items {
+		margin-top: 48rpx;
+	}
+
+	.splitOrder .items .picTxt {
+		width: 604rpx;
+		position: relative;
+	}
+
+	.splitOrder .items .picTxt .name {
+		width: 444rpx;
+	}
+
+	.splitOrder .items .picTxt .pictrue {
+		width: 136rpx;
+		height: 136rpx;
+	}
+
+	.splitOrder .items .picTxt .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 16rpx;
+	}
+
+	.splitOrder .items .picTxt .text {
+		width: 450rpx;
+		font-size: 28rpx;
+		color: #333;
+		font-weight: 400;
+	}
+
+	.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: 22rpx;
+		color: #999;
+		margin-top: 12rpx;
+		width: 284rpx;
+	}
+
+	.splitOrder .items .picTxt .text .money-section {
+		margin-top: 18rpx;
+		font-size: 22rpx;
+		color: #999999;
+	}
+
+	.splitOrder .items .picTxt .text .money {
+		font-size: 36rpx;
+		color: #333;
+		font-family: 'Regular';
+		color: #FF7D00;
+	}
+
+	.splitOrder .items .picTxt .carnum {
+		height: 36rpx;
+		position: absolute;
+		bottom: 0;
+		right: 0;
+	}
+
+	.splitOrder .items .picTxt .carnum view {
+		width: 66rpx;
+		text-align: center;
+		height: 100%;
+		line-height: 36rpx;
+		font-size: 24rpx;
+		color: #333;
+	}
+
+	.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;
+		font-size: 26rpx;
+	}
+
+	.splitOrder .items .picTxt .carnum .plus.on {
+		border-color: #e3e3e3;
+		color: #dedede;
+	}
+
+	.splitOrder .items .picTxt .carnum .num {
+		color: #282828;
+		background: #F5F5F5;
+		width: 72rpx;
+	}
+</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>

+ 204 - 0
components/timeSlot/index.vue

@@ -0,0 +1,204 @@
+<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-ic_downarrow 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) {
+				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)
+				}else{
+					star = new Date(e.fulldate + ' 00:00:00').getTime() / 1000
+					stop = new Date(e.fulldate + ' 23:59:59').getTime() / 1000
+					self.where.start = star
+					self.where.stop = stop
+					self.loaded = false;
+					self.loading = false;
+					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 20rpx;
+		background-color: #fff;
+		color: #999;
+		font-size: 24rpx;
+		width: 100%;
+		box-sizing: border-box;
+
+		.times {
+			display: flex;
+
+			.item {
+				margin-right: 20rpx;
+				background: #F5F5F5;
+				padding: 8rpx 24rpx;
+				border-radius: 30rpx;
+
+			}
+
+			.item.on {
+				color: var(--view-theme);
+				background-color: var(--view-minorColorT);
+			}
+		}
+		.item{
+			padding: 10rpx 0rpx;
+		}
+	}
+
+	.aaa {
+		padding-left: 10rpx;
+		font-size: 26rpx !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>

+ 144 - 0
components/tui-drawer/tui-drawer.vue

@@ -0,0 +1,144 @@
+<template>
+	<view>
+		<view v-if="mask" class="tui-drawer-mask" :class="{ 'tui-drawer-mask_show': visible }" :style="{ zIndex: maskZIndex }" 
+			@tap="handleMaskClick" @touchmove.stop.prevent="moveHandle"></view>
+		<view
+			class="tui-drawer-container"
+			:class="[`tui-drawer-container_${mode}`, visible ? `tui-drawer-${mode}__show` : '']"
+			:style="{ zIndex: zIndex, backgroundColor: backgroundColor }"
+			@touchmove.stop.prevent="moveHandle"
+		>
+			<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: 990
+		},
+		//mask z-index
+		maskZIndex: {
+			type: [Number, String],
+			default: 980
+		},
+		backgroundColor: {
+			type: String,
+			default: '#fff'
+		}
+	},
+	methods: {
+		moveHandle(){
+			return false
+		},
+		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>

+ 209 - 0
components/tui-modal/index.vue

@@ -0,0 +1,209 @@
+<template>
+	<view class="tui-modal__container" :class="[show ? 'tui-modal-show' : '']" :style="{zIndex:zIndex}">
+		<view class="tui-modal-box"
+			:class="[fadeIn || show ? 'tui-modal-normal' : 'tui-modal-scale', show ? 'tui-modal-show' : '']">
+			<view v-if="!custom">
+				<view class="tui-modal-title" v-if="title">{{ title }}</view>
+				<view class="tui-modal-content" :class="[title ? '' : 'tui-mtop']"
+					>{{ content }}</view>
+				<view class="tui-modalBtn-box">
+					<view class="tui-modal-btn flex-center tui-modal-btn-cancel" @tap="handleClick(0)">{{cancelText}}</view>
+					<view class="tui-modal-btn flex-center tui-modal-btn-confirm" @tap="handleClick(1)">{{confirmText}}</view>
+				</view>
+			</view>
+			<view v-else>
+				<slot></slot>
+			</view>
+		</view>
+		<view v-if="isMask" class="tui-modal-mask" :class="[show ? 'tui-mask-show' : '']"
+			:style="{zIndex:maskZIndex,background:maskColor}" @tap="handleClickCancel"
+			@touchmove.stop.prevent></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'tuiModal',
+		emits: ['click', 'cancel'],
+		props: {
+			//是否显示
+			show: {
+				type: Boolean,
+				default: false
+			},
+			//标题
+			title: {
+				type: String,
+				default: ''
+			},
+			//内容
+			content: {
+				type: String,
+				default: ''
+			},
+			cancelText:{
+				type: String,
+				default: '取消'
+			},
+			confirmText:{
+				type: String,
+				default: '确定'
+			},
+			//点击遮罩 是否可关闭
+			maskClosable: {
+				type: Boolean,
+				default: true
+			},
+			//是否显示mask
+			isMask: {
+				type: Boolean,
+				default: true
+			},
+			maskColor: {
+				type: String,
+				default: 'rgba(0, 0, 0, 0.6)'
+			},
+			//淡入效果,自定义弹框插入input输入框时传true
+			fadeIn: {
+				type: Boolean,
+				default: false
+			},
+			//自定义弹窗内容
+			custom: {
+				type: Boolean,
+				default: false
+			},
+			//容器z-index
+			zIndex: {
+				type: Number,
+				default: 9997
+			},
+			//mask z-index
+			maskZIndex: {
+				type: Number,
+				default: 9990
+			}
+		},
+		data() {
+			return {};
+		},
+		methods: {
+			handleClick(index) {
+				if (!this.show) return;
+				this.$emit('click', {
+					index: Number(index)
+				});
+			},
+			handleClickCancel() {
+				if (!this.maskClosable) return;
+				this.$emit('cancel');
+			}
+		}
+	};
+</script>
+
+<style scoped>
+	.tui-modal__container {
+		width: 100%;
+		height: 100%;
+		position: fixed;
+		left: 0;
+		top: 0;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		visibility: hidden;
+	}
+
+	.tui-modal-box {
+		position: relative;
+		opacity: 0;
+		visibility: hidden;
+		box-sizing: border-box;
+		transition: all 0.3s ease-in-out;
+		width:600rpx;
+		padding: 40rpx;
+		border-radius:32rpx;
+		background-color: #fff;
+		z-index: 9999;
+	}
+
+	.tui-modal-scale {
+		transform: scale(0);
+	}
+
+	.tui-modal-normal {
+		transform: scale(1);
+	}
+
+	.tui-modal-show {
+		opacity: 1;
+		visibility: visible;
+	}
+
+	.tui-modal-mask {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		transition: all 0.3s ease-in-out;
+		opacity: 0;
+		visibility: hidden;
+	}
+
+	.tui-mask-show {
+		visibility: visible;
+		opacity: 1;
+	}
+
+	.tui-modal-title {
+		text-align: center;
+		font-size: 32rpx;
+		line-height: 52rpx;
+		color: #333;
+		font-weight: 500;
+	}
+
+	.tui-modal-content {
+		text-align: center;
+		color: #666;
+		font-size: 30rpx;
+		line-height: 40rpx;
+		margin: 24rpx auto 40rpx;
+	}
+
+	.tui-mtop {
+		margin-top: 30rpx;
+	}
+
+	.tui-mbtm {
+		margin-bottom: 30rpx;
+	}
+
+	.tui-modalBtn-box {
+		width: 100%;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+	}
+
+	.tui-flex-column {
+		flex-direction: column;
+	}
+
+	.tui-modal-btn {
+		width: 244rpx;
+		height: 72rpx;
+		border-radius: 36rpx;
+		font-size: 26rpx;
+	}
+	.tui-modal-btn-cancel{
+		border: 1px solid var(--view-theme);
+		color: var(--view-theme);
+	}
+	.tui-modal-btn-confirm{
+		background-color: var(--view-theme);
+		color: #fff;
+	}
+</style>

+ 315 - 0
components/tui-swipe-action/index.vue

@@ -0,0 +1,315 @@
+<template>
+	<view class="tui-swipeout-wrap" :style="{ backgroundColor: backgroundColor }">
+		<view class="tui-swipeout-item" :class="[isShowBtn ? 'swipe-action-show' : '']" 
+			:style="{ transform: 'translate(' + position.pageX + 'px,0)' }">
+			<view class="tui-swipeout-content" @touchstart="handlerTouchstart"
+			@touchmove="handlerTouchmove" @touchend="handlerTouchend" @mousedown="handlerTouchstart"
+			@mousemove="handlerTouchmove" @mouseup="handlerTouchend">
+				<slot name="content"></slot>
+			</view>
+			<view class="tui-swipeout-button-right-group" v-if="actions.length > 0" @touchend.stop="loop">
+				<view class="tui-swipeout-button-right-item" v-for="(item, index) in actions" :key="index"
+					:style="{ backgroundColor: item.background || '#f7f7f7', color: item.color, width: item.width + 'px' }"
+					:data-index="index" @tap="handlerButton">
+					<image :src="item.icon" v-if="item.icon"
+						:style="{ width: px(item.imgWidth), height: px(item.imgHeight) }"></image>
+					<text :style="{ fontSize: px(item.fontsize) }">{{ item.name }}</text>
+				</view>
+			</view>
+			<!--actions长度设置为0,可直接传按钮进来-->
+			<view class="tui-swipeout-button-right-group" @touchend.stop="loop" @tap="handlerParentButton"
+				v-if="actions.length === 0" :style="{ width: operateWidth + 'px', right: '-' + operateWidth + 'px' }">
+				<slot name="button"></slot>
+			</view>
+		</view>
+		<view v-if="isShowBtn && showMask" class="swipe-action_mask" @tap.stop="closeButtonGroup"
+			@touchstart.stop.prevent="closeButtonGroup"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'tuiSwipeAction',
+		emits: ['click'],
+		props: {
+			// name: '删除',
+			// color: '#fff',
+			// fontsize: 32,//单位rpx
+			// width: 80, //单位px
+			// icon: 'like.png',//此处为图片地址
+			// background: '#ed3f14'
+			actions: {
+				type: Array,
+				default () {
+					return [];
+				}
+			},
+			//点击按钮时是否自动关闭
+			closable: {
+				type: Boolean,
+				default: true
+			},
+			//设为false,可以滑动多行不关闭菜单
+			showMask: {
+				type: Boolean,
+				default: true
+			},
+			operateWidth: {
+				type: Number,
+				default: 80
+			},
+			params: {
+				type: Object,
+				default () {
+					return {};
+				}
+			},
+			//禁止滑动
+			forbid: {
+				type: Boolean,
+				default: false
+			},
+			//手动开关
+			open: {
+				type: Boolean,
+				default: false
+			},
+			//背景色
+			backgroundColor: {
+				type: String,
+				default: '#fff'
+			}
+		},
+		watch: {
+			actions(newValue, oldValue) {
+				this.updateButtonSize();
+			},
+			open(newValue) {
+				this.manualSwitch(newValue);
+			}
+		},
+		data() {
+			return {
+				//start position
+				tStart: {
+					pageX: 0,
+					pageY: 0
+				},
+				//限制滑动距离
+				limitMove: 0,
+				//move position
+				position: {
+					pageX: 0,
+					pageY: 0
+				},
+				isShowBtn: false,
+				move: false
+			};
+		},
+		mounted() {
+			this.updateButtonSize();
+		},
+		methods: {
+			swipeDirection(x1, x2, y1, y2) {
+				return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : y1 - y2 > 0 ? 'Up' :
+					'Down';
+			},
+			//阻止事件冒泡
+			loop() {
+			},
+			updateButtonSize() {
+				const actions = this.actions;
+				if (actions.length > 0) {
+					const query = uni.createSelectorQuery().in(this);
+					let limitMovePosition = 0;
+					actions.forEach(item => {
+						limitMovePosition += item.width || 0;
+					});
+					this.limitMove = limitMovePosition;
+				} else {
+					this.limitMove = this.operateWidth;
+				}
+			},
+			handlerTouchstart(event) {
+				if (this.forbid) return;
+				let touches = event.touches
+				if (touches && touches.length > 1) return;
+				this.move = true;
+				touches = touches ? event.touches[0] : {};
+				if (!touches || (touches.pageX === undefined && touches.pageY === undefined)) {
+					touches = {
+						pageX: event.pageX,
+						pageY: event.pageY
+					};
+				}
+				const tStart = this.tStart;
+				if (touches) {
+					for (let i in tStart) {
+						if (touches[i]) {
+							tStart[i] = touches[i];
+						}
+					}
+				}
+			},
+			swipper(touches) {
+				const start = this.tStart;
+				const spacing = {
+					pageX: touches.pageX - start.pageX,
+					pageY: touches.pageY - start.pageY
+				};
+				if (this.limitMove < Math.abs(spacing.pageX)) {
+					spacing.pageX = -this.limitMove;
+				}
+				this.position = spacing;
+			},
+			handlerTouchmove(event) {
+				if (this.forbid || !this.move) return;
+				const start = this.tStart;
+				let touches = event.touches ? event.touches[0] : {};
+				if (!touches || (touches.pageX === undefined && touches.pageY === undefined)) {
+					touches = {
+						pageX: event.pageX,
+						pageY: event.pageY
+					};
+				}
+				if (touches) {
+					const direction = this.swipeDirection(start.pageX, touches.pageX, start.pageY, touches.pageY);
+					if (direction === 'Left' && Math.abs(this.position.pageX) !== this.limitMove) {
+						this.swipper(touches);
+					}
+				}
+			},
+			handlerTouchend(event) {
+				if (this.forbid || !this.move) return;
+				this.move = false;
+				const start = this.tStart;
+				let touches = event.changedTouches ? event.changedTouches[0] : {};
+				if (!touches || (touches.pageX === undefined && touches.pageY === undefined)) {
+					touches = {
+						pageX: event.pageX,
+						pageY: event.pageY
+					};
+				}
+				if (touches) {
+					const direction = this.swipeDirection(start.pageX, touches.pageX, start.pageY, touches.pageY);
+					const spacing = {
+						pageX: touches.pageX - start.pageX,
+						pageY: touches.pageY - start.pageY
+					};
+					if (Math.abs(spacing.pageX) >= 40 && direction === 'Left') {
+						spacing.pageX = spacing.pageX < 0 ? -this.limitMove : this.limitMove;
+						this.isShowBtn = true;
+					} else {
+						spacing.pageX = 0;
+					}
+					if (spacing.pageX== 0) {
+						this.isShowBtn = false;
+					}
+					this.position = spacing;
+					
+				}
+			},
+			handlerButton(event) {
+				if (this.closable) {
+					this.closeButtonGroup();
+				}
+				const dataset = event.currentTarget.dataset;
+				this.$emit('click', {
+					index: Number(dataset.index),
+					item: this.params
+				});
+			},
+			closeButtonGroup() {
+				this.position = {
+					pageX: 0,
+					pageY: 0
+				};
+				this.isShowBtn = false;
+			},
+			//控制自定义按钮菜单
+			handlerParentButton(event) {
+				if (this.closable) {
+					this.closeButtonGroup();
+				}
+			},
+			manualSwitch(isOpen) {
+				let x = 0;
+				if (isOpen) {
+					if (this.actions.length === 0) {
+						x = this.operateWidth;
+					} else {
+						let width = 0;
+						this.actions.forEach(item => {
+							width += item.width;
+						});
+						x = width;
+					}
+				}
+				this.position = {
+					pageX: -x,
+					pageY: 0
+				};
+			},
+			px(num) {
+				return uni.upx2px(num) + 'px';
+			}
+		}
+	};
+</script>
+
+<style scoped>
+	.tui-swipeout-wrap {
+		position: relative;
+		overflow: hidden;
+	}
+
+	.swipe-action-show {
+		position: relative;
+		z-index: 998;
+	}
+
+	.tui-swipeout-item {
+		width: 100%;
+		/* padding: 15px 20px; */
+		box-sizing: border-box;
+		transition: transform 0.2s ease;
+		font-size: 14px;
+		cursor: pointer;
+	}
+
+	.tui-swipeout-content {
+		white-space: nowrap;
+		overflow: hidden;
+	}
+
+	.tui-swipeout-button-right-group {
+		position: absolute;
+		right: -100%;
+		top: 0;
+		height: 100%;
+		z-index: 1;
+		width: 100%;
+	}
+
+	.tui-swipeout-button-right-item {
+		height: 100%;
+		float: left;
+		white-space: nowrap;
+		box-sizing: border-box;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		text-align: center;
+	}
+
+	.swipe-action_mask {
+		display: block;
+		opacity: 0;
+		position: fixed;
+		z-index: 997;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+	}
+</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="iconfont icon-ic_leftarrow"></view>
+				</view>
+				<text class="uni-calendar__header-text">{{ (nowDate.year||'') +'年'+( nowDate.month||'') +'月'}}</text>
+				<view class="uni-calendar__header-btn-box" @click="next">
+					<view class="iconfont icon-ic_rightarrow"></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>

+ 137 - 0
components/userEvaluation/index.vue

@@ -0,0 +1,137 @@
+<template>
+	<!-- 评价列表 -->
+	<view>
+		<scroll-view ref="scroll" scroll-x="true" class="scroll w-690 mt-24 pl-20" show-scrollbar="true" @scroll="scroll">
+			<view id="scrollBox" ref="scrollBox" class="scrll-box">
+				<view class="inline-block mr-20" v-for="item in reply" :key="item.id" @click.stop="details(item)">
+					<view class="h-192 rd-16rpx bg--w111-f5f5f5 flex justify-between">
+						<view class="flex-1 p-24">
+							<view class="flex-y-center">
+								<image class="w-64 h-64 rd-50-p111-" :src="item.avatar" mode="aspectFill"></image>
+								<view class="flex-col pl-16">
+									<text class="text--w111-333 fs-24">{{ item.nickname }}</text>
+									<view class="flex">
+										<text class="iconfont icon-ic_star1 fs-18 text-primary-con" v-for="star in Number(item.star)" :key="star"></text>
+									</view>
+								</view>
+							</view>
+							<view class="w-324 mt-12 text--w111-333 fs-24 break_word line2">{{ item.comment }}</view>
+						</view>
+						<image v-if="item.pics.length" class="w-192 h-192 rd-16rpx" :src="item.pics[0]"></image>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+		<view class="flex-center mt-24" v-if="reply.length > 1">
+			<view class="w-64 h-6 rd-3px bg--w111-eee scrpll-l">
+				<view class="w-32 h-6 rd-3px scrpll-line" :style="{ left: srollLeft + '%' }"></view>
+			</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() {
+		return {
+			srollLeft: 0, // 距离左边
+			srollBoxWidth: 0, //内部宽度
+			boxWidth: 0 //容器宽度
+		};
+	},
+	mounted() {
+		this.$nextTick((e) => {
+			this.srollLeft = 0;
+			const query = wx.createSelectorQuery().in(this);
+			query
+				.select('.scrll-box')
+				.boundingClientRect((res) => {
+					this.srollBoxWidth = res.width;
+				})
+				.exec();
+			query
+				.select('.scroll')
+				.boundingClientRect((res) => {
+					this.boxWidth = res.width - 10;
+				})
+				.exec();
+		});
+	},
+	methods: {
+		scroll(e) {
+			this.srollLeft = ((e.detail.scrollLeft / (this.srollBoxWidth - this.boxWidth)) * 100).toFixed(0) / 2;
+		},
+		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 lang="scss">
+.scrll-box {
+	display: flex;
+	flex-wrap: nowrap;
+	width: max-content;
+}
+.scrpll-l {
+	position: relative;
+}
+.scrpll-line {
+	position: absolute;
+	background-color: var(--view-theme);
+	left: 0;
+	top: 0;
+}
+.text-primary-con {
+	color: var(--view-theme);
+}
+</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>

+ 46 - 0
config/cache.js

@@ -0,0 +1,46 @@
+// +----------------------------------------------------------------------
+// | 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',
+	//判断是门店还是平台管理端;
+	STORE_NUM: 'STORE_NUM',
+  // 移动网络下视频自动播放
+  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);
+		}
+	});
+}

+ 257 - 0
libs/new_chat.js

@@ -0,0 +1,257 @@
+// +----------------------------------------------------------------------
+// | 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) => {
+			this.networkStatus = true;
+			if (this.socketTask) {
+				this.socketTask.close();	
+			}
+			uni.$on('timeout', this.timeoutEvent.bind(this))
+		}, () => {
+			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;

+ 44 - 0
libs/order.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>
+// +----------------------------------------------------------------------
+
+let app = getApp()
+
+export function goShopDetail(item, uid) {
+	return new Promise((resolve,reject) => {
+		if(item.is_presale_product){
+			uni.navigateTo({
+				url: `/pages/activity/goods_details/index?id=${item.id}&type=6`
+			})
+		}else{
+			if (item.activity && item.activity.type == 1) {
+				uni.navigateTo({
+					url: `/pages/activity/goods_details/index?id=${item.activity.id}&type=1&time_id=${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_details/index?id=${item.activity.id}&type=3`
+				})
+			} else {
+				reject(item);
+			}
+		}
+	});
+}
+
+
+export function goPage() {
+	return new Promise(resolve => {
+		resolve(true);
+	});
+}

+ 217 - 0
libs/routine.js

@@ -0,0 +1,217 @@
+// +----------------------------------------------------------------------
+// | 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('版本过低请升级');
+		        }
+		    }
+		});
+	})
+})
+
+
+
+
+
+
+ 
+

+ 92 - 0
main.js

@@ -0,0 +1,92 @@
+// +----------------------------------------------------------------------
+// | 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'
+import BaseMoney from './components/BaseMoney.vue';
+import BaseTag from './components/BaseTag.vue';
+import easyLoadimage from './components/easy-loadimage/easy-loadimage.vue'
+import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
+Vue.component('skeleton', skeleton)
+Vue.component('BaseMoney', BaseMoney)
+Vue.component('BaseTag', BaseTag)
+Vue.component('baseDrawer', baseDrawer)
+Vue.component('easyLoadimage', easyLoadimage)
+// #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();

+ 240 - 0
manifest.json

@@ -0,0 +1,240 @@
+{
+    "name" : "multi-store",
+    "appid" : "__UNI__0A10130",
+    "description" : "crmeb商城",
+    "versionName" : "3.0.0",
+    "versionCode" : 301,
+    "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
+        }
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "h5" : {
+        "devServer" : {
+            "https" : false
+        },
+        "router" : {
+            "mode" : "history",
+            "base" : ""
+        },
+        "domain" : "",
+        "sdkConfigs" : {
+            "maps" : {
+                "qqmap" : {
+                    "key" : "SMJBZ-WCHK4-ZPZUA-DSIXI-XDDVQ-XWFX7"
+                }
+            }
+        },
+        "optimization" : {
+            "treeShaking" : {
+                "enable" : true
+            }
+        },
+        "async" : {
+            "timeout" : 200000
+        },
+        "title" : "加载中",
+        "template" : "index.html"
+    },
+    "plus" : {
+        "statusbar" : {
+            "immersed" : true
+        }
+    }
+}

+ 41 - 0
mixins/SendVerifyCode.js

@@ -0,0 +1,41 @@
+// +----------------------------------------------------------------------
+// | 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: "获取验证码",
+	  run: undefined
+    };
+  },
+  methods: {
+    sendCode() {
+      if (this.disabled) return;
+      this.disabled = true;
+      let n = 60;
+      this.text = "剩余 " + n + "s";
+      this.run = setInterval(() => {
+        n = n - 1;
+        if (n < 0) {
+          clearInterval(this.run);
+        }
+        this.text = "剩余 " + n + "s";
+        if (this.text < "剩余 " + 0 + "s") {
+          this.disabled = false;
+          this.text = "重新获取";
+        }
+      }, 1000);
+    }
+  },
+  beforeDestroy() {
+	  clearInterval(this.run);
+  },
+};

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

+ 124 - 0
mixins/location.js

@@ -0,0 +1,124 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+import { getGeocoder } from '@/api/user.js';
+import { getnearbyStore } from '@/api/new_store.js';
+import { mapMutations } from 'vuex';
+export default {
+  data() {
+    return {
+		location: {},
+		addressInfo:'选择地址',
+		addressInfos:"选择地址",
+		storeName: '',
+		storeId:0
+	};
+  },
+  watch: {
+  	location(value) {
+  		this.getnearbyStore(value);
+  	}
+  },
+  mounted(){
+	uni.$on('activeFn', data => {
+		if(data){
+			this.storeName = data.name;
+			this.storeId = data.id;
+			this.SET_NEARBY(data.id);
+		}
+	});  
+  },
+  methods: {
+	...mapMutations(['SET_NEARBY']),
+	selfLocation() {
+		let self = this
+		// #ifdef MP || APP-PLUS
+		uni.getLocation({
+			type: 'gcj02',
+			success: (res) => {
+				try {
+					uni.setStorageSync('user_latitude', res.latitude);
+					uni.setStorageSync('user_longitude', res.longitude);
+					self.getGeocoderCity(res.latitude,res.longitude);
+					self.location = { latitude: res.latitude, longitude: res.longitude };
+				} catch {}
+			},
+			fail:(res)=>{
+				// #ifdef MP
+				uni.getSetting({
+					success: res=>{
+						if(typeof(res.authSetting['scope.userLocation']) != 'undefined' && !res.authSetting['scope.userLocation']){
+						  uni.setStorageSync('refuseLocation', true);
+						}
+					}
+				})
+				// #endif
+			}
+		});
+		// #endif
+		// #ifdef H5
+		if (this.$wechat.isWeixin()) {
+			this.$wechat.location().then(res => {
+				uni.setStorageSync('user_latitude', res.latitude);
+				uni.setStorageSync('user_longitude', res.longitude);
+				self.getGeocoderCity(res.latitude,res.longitude);
+			})
+		} else {
+			uni.getLocation({
+				type: 'gcj02',
+				success: function(res) {
+					try {
+						uni.setStorageSync('user_latitude', res.latitude);
+						uni.setStorageSync('user_longitude', res.longitude);
+						self.getGeocoderCity(res.latitude,res.longitude);
+					} catch {}
+				}
+			});
+		}
+		// #endif
+	},
+	getGeocoderCity(latitude,longitude){
+		getGeocoder({
+			lat: latitude,
+			long: longitude
+		}).then(res=>{
+			let address = res.data.address_component;
+			this.addressInfo = address?address.city.slice(0,4) : '选择地址';
+			this.addressInfos = address?(address.city+address.district).slice(0,7) : '选择地址';
+		})
+	},
+	chooseLocation: function() {
+		let that = this;
+		if(that.fixConfig == 0){
+			uni.navigateTo({
+				url:'/pages/store/list/index?type=1&isCollage=1&storeId='+this.storeId
+			})
+		}else{
+			uni.chooseLocation({
+				success: (res) => {
+					let address = that.$util.addressInfo(res.address);
+					this.addressInfo = address?address.city.slice(0,4) : '选择地址';
+					this.addressInfos = address?(address.city+address.district).slice(0,7) : '选择地址';
+					that.location = { latitude: res.latitude, longitude: res.longitude };
+				},
+				fail: (err)=>{
+					console.log(err)
+				}
+			})
+		}
+	},
+	getnearbyStore(data) {
+		getnearbyStore(data).then(res => {
+			this.storeId = res.data.info.id;
+			this.SET_NEARBY(res.data.info.id);
+			this.storeName = res.data.info.name;
+		});
+	}
+  }
+};

+ 356 - 0
mixins/skuSelect.js

@@ -0,0 +1,356 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+import {
+	getCategoryList,
+	getProductslist,
+	getAttr,
+	postCartNum
+} from '@/api/store.js';
+import {cartDel} from "@/api/order.js";
+import {toLogin} from '@/libs/login.js';
+export default {
+	data() {
+		return {
+			attr: {
+				cartAttr: false,
+				productAttr: [],
+				productSelect: {}
+			},
+			productValue: [],
+		};
+	},
+	created() {
+
+	},
+	methods: {
+		/**
+		 * 默认选中属性
+		 *
+		 */
+		DefaultSelect: function() {
+			let productAttr = this.attr.productAttr;
+			let value = [];
+			for (let key in this.productValue) {
+				if (this.productValue[key].stock > 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(",")];
+			this.$set(this.attr.productSelect,"store_name",this.storeName);
+			if (productSelect && productAttr.length) {
+				this.$set(this.attr.productSelect, "image", productSelect.image);
+				this.$set(this.attr.productSelect, "price", productSelect.price);
+				this.$set(this.attr.productSelect, "stock", productSelect.stock);
+				this.$set(this.attr.productSelect, "unique", productSelect.unique);
+				this.$set(this.attr.productSelect, "cart_num", 1);
+				this.$set(this.attr.productSelect, 'vip_price', productSelect.vip_price);
+				this.$set(this, "attrValue", value.join(","));
+			} else if (!productSelect && productAttr.length) {
+				this.$set(this.attr.productSelect, "image", this.storeInfo.image);
+				this.$set(this.attr.productSelect, "price", this.storeInfo.price);
+				this.$set(this.attr.productSelect, "stock", 0);
+				this.$set(this.attr.productSelect, "unique", "");
+				this.$set(this.attr.productSelect, "cart_num", 0);
+				this.$set(this, "attrValue", "");
+				this.$set(this.attr.productSelect, 'vip_price', this.storeInfo.vip_price);
+			} else if (!productSelect && !productAttr.length) {
+				this.$set(this.attr.productSelect, "image", this.storeInfo.image);
+				this.$set(this.attr.productSelect, "price", this.storeInfo.price);
+				this.$set(this.attr.productSelect, "stock", this.storeInfo.stock);
+				this.$set(this.attr.productSelect,"unique",this.storeInfo.unique || "");
+				this.$set(this.attr.productSelect, "cart_num", 1);
+				this.$set(this, "attrValue", "");
+				this.$set(this.attr.productSelect, 'vip_price', this.storeInfo.vip_price);
+			}
+		},
+		/**
+		 * 属性变动赋值
+		 *
+		 */
+		ChangeAttr: function(res) {
+			let productSelect = this.productValue[res];
+			if (productSelect && productSelect.stock >= 0) {
+				this.$set(this.attr.productSelect, "image", productSelect.image);
+				this.$set(this.attr.productSelect, "price", productSelect.price);
+				this.$set(this.attr.productSelect, "stock", productSelect.stock);
+				this.$set(this.attr.productSelect, "unique", productSelect.unique);
+				this.$set(this.attr.productSelect, 'vip_price', productSelect.vip_price);
+				this.$set(this.attr.productSelect, "cart_num", 1);
+				this.$set(this, "attrValue", res);
+			} else {
+				this.$set(this.attr.productSelect, 'image', this.storeInfo.image);
+				this.$set(this.attr.productSelect, 'price', this.storeInfo.price);
+				this.$set(this.attr.productSelect, 'stock', 0);
+				this.$set(this.attr.productSelect, 'unique', '');
+				this.$set(this.attr.productSelect, 'cart_num', 0);
+				this.$set(this.attr.productSelect, 'vip_price', this.storeInfo.vip_price);
+				this.$set(this, 'attrValue', '');
+			}
+		},
+		attrVal(val) {
+			this.$set(this.attr.productAttr[val.indexw], 'index', this.attr.productAttr[val.indexw].attr_values[val
+				.indexn]);
+		},
+		/**
+		 * 购物车手动填写
+		 *
+		 */
+		iptCartNum: function(e) {
+			this.$set(this.attr.productSelect, 'cart_num', e);
+		},
+		onMyEvent: function() {
+			this.$set(this.attr, 'cartAttr', false);
+		},
+		// 改变多属性购物车
+		ChangeCartNumDuo(changeValue) {
+			//获取当前变动属性
+			let productSelect = this.productValue[this.attrValue];
+			//如果没有属性,赋值给商品默认库存
+			if (productSelect === undefined && !this.attr.productAttr.length)
+				productSelect = this.attr.productSelect;
+			//无属性值即库存为0;不存在加减;
+			if (productSelect === undefined) return;
+			let stock = productSelect.stock || 0;
+			let num = this.attr.productSelect;
+			this.ChangeCartNum(changeValue, num, stock, 1);
+		},
+		// 改变单属性购物车
+		ChangeCartNumDan(changeValue, index, item) {
+			let num = this.tempArr[index];
+			let stock = this.tempArr[index].stock;
+			this.ChangeCartNum(changeValue, num, stock, 0, item.id);
+		},
+		ChangeSubDel: function(event) {
+			let that = this,
+				list = that.cartData.cartList,
+				ids = [];
+			list.forEach(item => {
+				ids.push(item.id)
+			});
+			cartDel(ids.join(",")).then(res => {
+				that.$set(that.cartData, 'cartList', []);
+				that.cartData.iScart = false;
+				that.totalPrice = 0.00;
+				that.page = 1;
+				that.loadend = false;
+				that.tempArr = [];
+				that.productslist();
+				that.getCartNum();
+			})
+		},
+		ChangeOneDel: function(id, index) {
+			let that = this,
+				list = that.cartData.cartList;
+			cartDel(id.toString()).then(res => {
+				list.splice(index, 1);
+				if (!list.length) {
+					that.cartData.iScart = false;
+					that.page = 1;
+					that.loadend = false;
+					that.tempArr = [];
+					that.productslist();
+				};
+				that.getCartNum();
+			})
+		},
+		// 多规格加入购物车;
+		goCatNum() {
+			this.goCat(1, this.id, 1);
+		},
+		closeList(e) {
+			this.$set(this.cartData, 'iScart', e);
+		},
+		// 已经加入购物车时的购物加减;
+		ChangeCartList(changeValue, index) {
+			let list = this.cartData.cartList;
+			let num = list[index];
+			let stock = list[index].trueStock;
+			this.ChangeCartNum(changeValue, num, stock, 0, num.product_id, index, 1);
+			if (!list.length) {
+				this.cartData.iScart = false;
+				this.page = 1;
+				this.loadend = false;
+				this.tempArr = [];
+				this.productslist();
+			}
+		},
+		// 购物车加减计算函数
+		ChangeCartNum(changeValue, num, stock, isDuo, id, index, cart) {
+			if (changeValue) {
+				num.cart_num++;
+				if (num.cart_num > stock) {
+					if (isDuo) {
+						this.$set(this.attr.productSelect, "cart_num", stock ? stock : 1);
+						this.$set(this, "cart_num", stock ? stock : 1);
+					} else {
+						num.cart_num = stock ? stock : 0;
+						this.$set(this, 'tempArr', this.tempArr);
+						this.$set(this.cartData, 'cartList', this.cartData.cartList);
+					}
+					return this.$util.Tips({
+						title: "该产品没有更多库存了"
+					});
+				} else {
+					if (!isDuo) {
+						if (cart) {
+							this.goCat(0, id, 1, 1, num.product_attr_unique);
+							this.getTotalPrice();
+						} else {
+							this.goCat(0, id, 1);
+						}
+					}
+				}
+			} else {
+				num.cart_num--;
+				if (num.cart_num == 0) {
+					this.cartData.cartList.splice(index, 1);
+					if (isDuo) {
+						this.$set(this.attr.productSelect, "cart_num", 1);
+						this.$set(this, "cart_num", 1);
+					}
+				}
+				if (num.cart_num < 0) {
+					if (isDuo) {
+						this.$set(this.attr.productSelect, "cart_num", 1);
+						this.$set(this, "cart_num", 1);
+					} else {
+						num.cart_num = 0;
+						this.$set(this, 'tempArr', this.tempArr);
+						this.$set(this.cartData, 'cartList', this.cartData.cartList);
+					}
+				} else {
+					if (!isDuo) {
+						if (cart) {
+							this.goCat(0, id, 0, 1, num.product_attr_unique);
+							this.getTotalPrice();
+						} else {
+							this.goCat(0, id, 0);
+						}
+					}
+				}
+			}
+			this.tempArr.forEach((item)=>{
+				if(item.id == id){
+					item.cart_num = num.cart_num;
+				}
+			})
+		},
+		/*
+		 * 加入购物车
+		 */
+		goCat: function(duo, id, type, cart, unique) {
+			let that = this;
+
+			if (duo) {
+				let productSelect = that.productValue[this.attrValue];
+				//如果有属性,没有选择,提示用户选择
+				console.log(productSelect);
+				
+				
+				
+				
+				if (
+					that.attr.productAttr.length &&
+					productSelect === undefined
+				) {
+					return that.$util.Tips({
+						title: "产品库存不足,请选择其它属性"
+					});
+				}
+			}
+			let q = {
+				product_id: id,
+				num: duo ? that.attr.productSelect.cart_num : 1,
+				type: type,
+				unique: duo ? that.attr.productSelect.unique : cart ? unique : ""
+			};
+
+			postCartNum(q)
+				.then(function(res) {
+					if (duo) {
+						that.attr.cartAttr = false;
+						// that.page = 1;
+						// that.loadend = false;
+						that.tempArr.forEach((item, index) => {
+							if (item.id == that.id) {
+								let arrtStock = that.attr.productSelect.stock
+								let objNum = parseInt(item.cart_num) + parseInt(that.attr.productSelect.cart_num);
+								item.cart_num = objNum > arrtStock?arrtStock:objNum
+							}
+						})
+						// that.productslist();
+					}
+					
+					that.$util.Tips({
+						title: res.msg
+					});
+					
+					that.getCartNum();
+					if (!cart) {
+						that.getCartList(1);
+					}
+				})
+				.catch(err => {
+					return that.$util.Tips({
+						title: err
+					});
+				});
+		},
+		goCartDuo(item) {
+			if (!this.isLogin) {
+				toLogin();
+			} else {
+				if(item.cart_button == 0){
+					if(item.is_presale_product){
+						uni.navigateTo({
+							url: `/pages/activity/goods_details/index?id=${item.id}&type=6`
+						})
+					}else{
+						uni.navigateTo({
+							url: `/pages/goods_details/index?id=${item.id}&fromType=1`
+						})
+					}
+				}else{
+					this.storeName = item.store_name;
+					this.getAttrs(item.id);
+					this.$set(this, 'id', item.id);
+					this.$set(this.attr, 'cartAttr', true);
+				}
+			}
+		},
+		// 点击默认单属性购物车
+		goCartDan(item, index) {
+			if (!this.isLogin) {
+				toLogin();
+			} else {
+				if(item.cart_button == 0){
+					if(item.is_presale_product){
+						uni.navigateTo({
+							url: `/pages/activity/goods_details/index?id=${item.id}&type=6`
+						})
+					}else{
+						uni.navigateTo({
+							url: `/pages/goods_details/index?id=${item.id}&fromType=1`
+						})
+					}
+				}else{
+					this.tempArr[index].cart_num = 1;
+					this.$set(this, 'tempArr', this.tempArr);
+					this.goCat(0, item.id, 1);
+				}
+			}
+		},
+	}
+};

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

+ 1904 - 0
pages.json

@@ -0,0 +1,1904 @@
+{
+	"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/index/index",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationStyle": "custom",
+				"navigationBarTextStyle": "black"
+			}
+		},
+		{
+			"path": "pages/order_addcart/order_addcart",
+			"style": {
+				"navigationBarTitleText": "购物车",
+				"app-plus": {
+					// #ifdef APP-PLUS
+					"titleNView": {
+						"type": "default"
+					}
+					// #endif
+				}
+			}
+		},
+		{
+			"path": "pages/goods_details/index",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/user/index",
+			"style": {
+
+				"navigationBarTitleText": "个人中心",
+				// #ifdef MP || APP-PLUS
+				"navigationStyle": "custom",
+				// "navigationBarBackgroundColor": "#e93323",
+				"navigationBarTextStyle": "black",
+				// #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
+				}
+			}
+		},
+		{
+			"path": "pages/store_list/index",
+			"style": {
+				"navigationBarTitleText": "门店列表",
+				// #ifdef MP || APP-PLUS
+				"navigationStyle": "custom",
+				// #endif
+				"app-plus": {
+					// #ifdef APP-PLUS
+					// "titleNView": {
+					// 	"type": "default"
+					// }
+					// #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": "协议",
+						"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": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"navigationBarTitleText": "消息中心",
+						"enablePullDownRefresh": true,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "message_center/messageDetail",
+					"style": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"navigationBarTitleText": "消息中心",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_invoice_order/index",
+					"style": {
+						"navigationBarTitleText": "订单详情",
+						"navigationStyle": "custom",
+						"navigationBarTextStyle": "white"
+					}
+				},
+				{
+					"path": "scan_login/index",
+					"style": {
+						"navigationBarTitleText": "授权登录"
+					}
+				},
+				{
+					"path": "user_invoice_list/index",
+					"style": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"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": false //禁用原生导航栏
+						}
+					}
+				},
+				{
+					"path": "retrievePassword/index",
+					"style": {
+						"navigationBarTitleText": "忘记密码",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_set/index",
+					"style": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"navigationBarTitleText": "设置",
+						// #ifdef MP || APP-PLUS
+						"navigationStyle": "custom",
+						// #endif
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_info/index",
+					"style": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"navigationBarTitleText": "个人资料",
+						// #ifdef MP || APP-PLUS
+						"navigationStyle": "custom",
+						// #endif
+						"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": "签到",
+						"navigationStyle": "custom",
+						// #ifdef MP
+						// "navigationBarTextStyle": "white",
+						// "navigationBarBackgroundColor": "#e93323"
+						// #endif
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_sgin_list/index",
+					"style": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"navigationBarTitleText": "签到记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_money/index",
+					"style": {
+						"navigationBarTitleText": "我的账户",
+						"navigationStyle": "custom",
+						"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": "积分详情",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "user_integral_detail/index",
+					"style": {
+						"navigationBarTitleText": "积分明细",
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"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": {
+						"navigationStyle": "custom",
+						"navigationBarTitleText": "我的推广"
+					}
+				},
+				{
+					"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_distribution_info/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": "提现",
+						// #ifndef APP-PLUS
+						"navigationBarTextStyle": "white",
+						// #endif
+						// #ifdef APP-PLUS
+						"navigationBarTextStyle": "black",
+						// #endif
+						"navigationStyle": "custom",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_cash/status",
+					"style": {
+						"navigationBarTitleText": "提现审核",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_vip/index",
+					"style": {
+						"navigationBarTitleText": "会员中心",
+						"navigationBarBackgroundColor": "#232323",
+						"navigationStyle": "custom"
+							// #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",
+						"navigationStyle": "custom"
+							// #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_agreement_list/index",
+					"style": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"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_address/addClient",
+					"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": "账户充值",
+						"navigationStyle": "custom",
+						"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": {
+						"navigationStyle": "custom",
+						"navigationBarTextStyle": "black",
+						"navigationBarTitleText": "推广人排行",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "commission_rank/index",
+					"style": {
+						"navigationStyle": "custom",
+						// #ifdef APP-PLUS
+						"navigationBarTextStyle": "black",
+						// #endif
+						// #ifndef APP-PLUS
+						"navigationBarTextStyle": "white",
+						// #endif
+						"navigationBarTitleText": "佣金排行",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_return_list/index",
+					"style": {
+						"navigationBarTitleText": "售后退款",
+						"navigationBarBackgroundColor": "#F5F5F5",
+						"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": "",
+						"navigationStyle": "custom",
+						"enablePullDownRefresh": false
+					}
+				},
+				{
+					"path": "supplier/state",
+					"style": {
+						"navigationBarTitleText": "审核进度",
+						"enablePullDownRefresh": false,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "supplier/record",
+					"style": {
+						"navigationBarTitleText": "申请记录",
+						"enablePullDownRefresh": false,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_member_code/index",
+					"style": {
+						"navigationBarTitleText": "会员码",
+						"navigationStyle": "custom",
+						"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": {
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white",
+					"app-plus": {
+						"titleNView": false,
+						"bounce": "none"
+					}
+				}
+
+			}]
+		},
+		{
+			"root": "pages/store",
+			"name": "store",
+			"pages": [
+				{
+				  "path": "list/index",
+				  "style": {
+					"navigationBarTitleText": "门店列表",
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white"
+				  }
+				},
+				{
+				  //#ifdef APP
+				  "path": "mapnvue/index",
+				  //#endif	
+				  //#ifndef APP
+				  "path": "map/index",
+				  //#endif
+				  "style": {
+				    "navigationBarTitleText": "门店地图"
+				  }
+				},
+				{
+				  "path": "home/index",
+				  "style": {
+					"navigationBarTitleText": "门店",
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white"
+				  }
+				},
+				{
+				  "path": "info/index",
+				  "style": {
+					"navigationBarTitleText": "店铺信息",
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white"
+				  }
+				},
+				{
+				  "path": "group_buy/index",
+				  "style": {
+					"navigationBarTitleText": "门店拼单",
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white"
+				  }
+				},
+				{
+				  "path": "group_cart/index",
+				  "style": {
+					"navigationBarTitleText": "拼单-选商品",
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white"
+				  }
+				},
+				{
+				  "path": "table_code/index",
+				  "style": {
+					"navigationBarTitleText": "扫码点单",
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white"
+				  }
+				},
+				{
+				  "path": "table_confirm/index",
+				  "style": {
+					"navigationBarTitleText": "点餐列表",
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white"
+				  }
+				},
+				{
+				  "path": "service/index",
+				  "style": {
+					"navigationBarTitleText": "联系客服",
+					"navigationStyle": "custom",
+					"navigationBarTextStyle": "white"
+				  }
+				},
+				{
+				  "path": "group_goods/index",
+				  "style": {
+					"navigationBarTitleText": "拼单详情",
+					"navigationBarBackgroundColor": "#F5F5F5"
+				  }
+				}
+			]
+		},
+		{
+			"root": "pages/activity",
+			"name": "activity",
+			"pages": [{
+					"path": "goods_bargain/index",
+					"style": {
+						"navigationStyle": "custom",
+						"navigationBarTextStyle": "white",
+						"navigationBarTitleText": "砍价列表"
+					}
+				},
+				{
+					"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": {
+						"navigationBarTitleText": "拼团列表",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "goods_combination_status/index",
+					"style": {
+						"navigationBarTitleText": "拼团",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "goods_seckill/index",
+					"style": {
+						"navigationBarTitleText": "限时秒杀",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "goods_details/index",
+					"style": {
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "poster-poster/index",
+					"style": {
+						"navigationBarTitleText": "砍价海报",
+						"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": "预售列表",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "points_mall/index",
+					"style": {
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "coupon/index",
+					"style": {
+						"navigationBarTitleText": "",
+						"navigationStyle": "custom",
+						"enablePullDownRefresh": false
+					}
+				},
+				{
+					"path": "new_customer/index",
+					"style": {
+						"navigationBarTitleText": "",
+						"navigationStyle": "custom",
+						"enablePullDownRefresh": false
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/admin",
+			"name": "adminOrder",
+			"pages": [
+				{
+					"path": "user/list",
+					"style": {
+						"navigationStyle": "custom",
+						"navigationBarTitleText": "用户管理"
+					}
+				},
+				{
+					"path": "user/index",
+					"style": {
+						"navigationStyle": "custom",
+						"navigationBarTitleText": "用户详情"
+					}
+				},
+				{
+					"path": "goods/index",
+					"style": {
+						"navigationStyle": "custom",
+						"navigationBarTitleText": "商品管理"
+					}
+				},
+				{
+					"path": "goods/specs",
+					"style": {
+						"navigationBarTitleText": "修改价格",
+						 "navigationBarBackgroundColor": "#F5F5F5",
+						 "app-plus": {
+						 	// #ifdef APP-PLUS
+						 	"titleNView": {
+						 		"type": "default"
+						 	}
+						 	// #endif
+						 }
+					}
+				},
+				{
+					"path": "goods/specsStock",
+					"style": {
+						"navigationBarTitleText": "修改库存",
+						 "navigationBarBackgroundColor": "#F5F5F5",
+						 "app-plus": {
+						 	// #ifdef APP-PLUS
+						 	"titleNView": {
+						 		"type": "default"
+						 	}
+						 	// #endif
+						 }
+					}
+				},
+				{
+					"path": "order/index",
+					"style": {
+						"navigationStyle": "custom",
+						"navigationBarTitleText": "订单统计",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "order/store"                                                                                                                                                                                 ,
+					"style": {
+						"navigationStyle": "custom",
+						"navigationBarTitleText": "数据统计",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "orderList/index",
+					"style": {
+						"navigationStyle": "custom",
+						"navigationBarTitleText": "订单管理"
+					}
+				},
+				{
+					"path": "orderDetail/index",
+					"style": {
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "delivery/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": "distribution/index",
+					"style": {
+						"navigationStyle": "custom",
+						"app-plus": {}
+					}
+				}, 
+				{
+					"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": {
+						"navigationStyle": "custom"
+					}
+				}, 
+				{
+					"path": "work/index",
+					"style": {
+						"navigationBarTitleText": "工作台",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "work/store",
+					"style": {
+						"navigationBarTitleText": "工作台",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "logistics/index",
+					"style": {
+						"navigationStyle": "custom"
+					}
+				}, {
+					"path": "refundOrderList/index",
+					"style": {
+						"navigationBarTitleText": "售后订单",
+						"navigationStyle": "custom"
+					}
+				}, {
+					"path": "refund/index",
+					"style": {
+						"navigationBarTitleText": "立即退款"
+					}
+				}, {
+					"path": "refundOrderDetail/index",
+					"style": {
+						"navigationStyle": "custom"
+					}
+				}, {
+					"path": "writeRecordList/index",
+					"style": {
+						"navigationBarBackgroundColor": "#F5F5F5",
+						"navigationBarTitleText": "核销记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "offOrderResult/index",
+					"style": {
+						"navigationBarBackgroundColor": "#F5F5F5",
+						"navigationBarTitleText": "扫码核销"
+					}
+				}, {
+					"path": "writeOffCard/index",
+					"style": {
+						"navigationBarBackgroundColor": "#F5F5F5",
+						"navigationBarTitleText": "次卡核销",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/columnGoods",
+			"name": "columnGoods",
+			"pages": [{
+					"path": "live_list/index",
+					"style": {
+						"navigationBarTitleText": "推荐好货"
+					}
+				},
+				{
+					"path": "rank/index",
+					"style": {
+						"navigationBarTitleText": "",
+						"navigationStyle": "custom",
+						"enablePullDownRefresh": false
+					}
+				}
+			]
+		},
+		{
+			"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会员",
+						"navigationStyle": "custom",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "vip_paid_active/index",
+					"style": {
+						"navigationBarTitleText": "会员中心",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+
+					"path": "vip_paid_rights/index",
+					"style": {
+						"navigationBarTitleText": "会员权益",
+						"navigationStyle": "custom",
+						"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": "会员卡激活",
+						"navigationStyle": "custom",
+						"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/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": "customer_list/feedback",
+					"style": {
+						"navigationBarTitleText": "我的客服",
+						"navigationBarTextStyle": "white",
+						"navigationBarBackgroundColor": "#3A3A3A",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"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": "商品列表",
+						"navigationBarTextStyle": "black",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "goods_search/index",
+					"style": {
+						"navigationBarTitleText": "搜索商品",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "order_pay_status/index",
+					"style": {
+						"navigationBarTitleText": "支付成功",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"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": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"navigationBarTitleText": "评价详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "goods_comment_con/lottery_comment",
+					"style": {
+						"navigationBarTitleText": "订单评价",
+						"navigationStyle": "custom",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "goods_logistics/index",
+					"style": {
+						"navigationBarTitleText": "物流信息",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "goods_return_list/index",
+					"style": {
+						"navigationBarTitleText": "批量退款",
+						"navigationBarBackgroundColor": "#F5F5F5",
+						"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": "订单详情",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "order_list/index",
+					"style": {
+						"navigationBarTitleText": "我的订单",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "order_refund_goods/index",
+					"style": {
+						"navigationBarTitleText": "退回商品",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "order_confirm/index",
+					"style": {
+						"navigationBarTitleText": "提交订单",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "lottery/grids/index",
+					"style": {
+						"navigationBarTitleText": "抽奖活动",
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path": "lottery/wheel/index",
+					"style": {
+						"navigationBarTitleText": "抽奖活动"
+					}
+				},
+				{
+					"path": "lottery/grids/record",
+					"style": {
+						"navigationBarTitleText": "中奖记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "cashier/index",
+					"style": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"navigationBarTitleText": "订单支付",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+
+				}, {
+					"path": "order_after_details/index",
+					"style": {
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"navigationBarTextStyle":"black",
+						"navigationBarTitleText": "售后详情",
+						"enablePullDownRefresh": false,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+
+				},
+				{
+					"path": "match_pay/index",
+					"style": {
+						"navigationBarTitleText": "搭配购",
+						"enablePullDownRefresh": false,
+						"navigationStyle": "custom"
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/behalf",
+			"name": "behalf",
+			"pages": [{
+					"path": "user_list/index",
+					"style": {
+						"navigationBarTitleText": "代客下单",
+						"navigationBarTextStyle": "black",
+						"navigationBarBackgroundColor": "#F5F5F5",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path" : "goods_list/index",
+					"style" :
+					{
+						"navigationBarTitleText" : "",
+						"navigationStyle": "custom",
+						"enablePullDownRefresh" : false
+					}
+				},
+				{
+					"path" : "record/index",
+					"style" :
+					{
+						"navigationBarTitleText" : "下单记录",
+						"enablePullDownRefresh" : false,
+						"navigationBarBackgroundColor":"#f5f5f5",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path" : "order_confirm/index",
+					"style" :
+					{
+						"navigationBarTitleText" : "",
+						"enablePullDownRefresh" : false,
+						"navigationStyle": "custom"
+					}
+				},
+				{
+					"path" : "cashier/index",
+					"style" :
+					{
+						"navigationBarTitleText" : "订单支付",
+						"enablePullDownRefresh" : false,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		}
+	],
+	"tabBar": {
+		"color": "#282828",
+		"selectedColor": "#E93323",
+		"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_list/index",
+				"iconPath": "static/images/3-001.png",
+				"selectedIconPath": "static/images/3-002.png",
+				"text": "门店"
+			},
+			{
+				"pagePath": "pages/order_addcart/order_addcart",
+				"iconPath": "static/images/4-001.png",
+				"selectedIconPath": "static/images/4-002.png",
+				"text": "购物车"
+			},
+			{
+				"pagePath": "pages/user/index",
+				"iconPath": "static/images/5-001.png",
+				"selectedIconPath": "static/images/5-002.png",
+				"text": "我的"
+			}
+		]
+	},
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "加载中",
+		"navigationBarBackgroundColor": "#fff",
+		"backgroundColor": "#F8F8F8",
+		"titleNView": false
+	},
+	"condition": { //模式配置,仅开发期间生效
+		"current": 0, //当前激活的模式(list 的索引项)
+		"list": [{
+			"name": "", //模式名称
+			"path": "", //启动页面,必选
+			"query": "" //启动参数,在页面的onLoad函数里面得到
+		}]
+	}
+}

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

@@ -0,0 +1,180 @@
+<template>
+	<view :style="colorStyle">
+		<view class="px-20">
+			<view class="order_card bg--w111-fff rd-24rpx pt-32 pb-32 pl-24 pr-24"
+			v-for="(item, index) in bargain" :key="index">
+				<view class="flex-between-center">
+					<text class="fs-28 lh-40rpx">{{item.add_time}}</text>
+					<text class="font-color fs-26" v-if="item.status === 1">活动进行中</text>
+					<text class="font-color fs-26" v-else-if="item.status === 3">砍价成功</text>
+					<text class="font-color fs-26" v-else>活动已结束</text>
+				</view>
+				<view class="flex-between-center mt-26">
+					<image :src="item.image" class="w-136 h-136 rd-16rpx"></image>
+					<view class="flex-1 pl-20">
+						<view class="w-504 line2 fs-28 lh-40rpx">{{item.title}}</view>
+						<view class="flex items-baseline mt-20">
+							<text class="fs-24 text--w111-999">已砍至</text>
+							<baseMoney :money="item.residue_price" symbolSize="20" integerSize="32" decimalSize="20" weight></baseMoney>
+						</view>
+					</view>
+				</view>
+				<view class="pt-24 bt mt-32 flex-between-center">
+					<view class="flex-y-center fs-24" v-if="item.status === 1">
+						<text class="pr-12 text--w111-999">剩余:</text>
+						<count-down
+						justify-left="justify-content:left"
+						:is-day="true"
+						tip-text=" "
+						day-text=" "
+						hour-text="时"
+						minute-text="分"
+						second-text="秒"
+						dotColor="#999"
+						:datatime="item.datatime"></count-down>
+					</view>
+					<text class="pr-12 text--w111-999 fs-24" v-if="item.status === 2">活动已结束</text>
+					<text class="pr-12 text--w111-999 fs-24" v-if="item.status === 3">砍价已成功</text>
+					<view class="flex">
+						<view class="btn w-154 h-56 rd-30rpx flex-center fs-24 border_ccc"
+							v-if="item.status === 1"
+							@tap="getBargainUserCancel(item.bargain_id)"
+							>取消活动</view>
+						<view class="btn w-154 h-56 rd-30rpx flex-center fs-24 bg-color text--w111-fff"
+							v-if="item.status === 1"
+							@tap="goDetail(item.bargain_id)"
+							>{{item.pay_status ? '立即付款' : '继续砍价'}}</view>
+						<view class="btn w-154 h-56 rd-30rpx flex-center fs-24 bg-color text--w111-fff"
+							v-if="[2,3].includes(item.status)" @tap="goPage('/pages/activity/goods_bargain/index')">重开一个</view>
+					</view>
+				</view>
+			</view>
+			<Loading :loaded="status" :loading="loadingList"></Loading>
+		</view>
+		<view class="px-20 mt-20" v-if="!bargain.length">
+			<emptyPage title="暂无砍价记录~" src="/statics/images/noOrder.gif"></emptyPage>
+		</view>
+	</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}`
+				})
+			},
+			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;
+				});
+			},
+			goPage(url){
+				uni.navigateTo({
+					url
+				})
+			}
+		},
+		onReachBottom() {
+			this.getBargainUserList();
+		}
+	};
+</script>
+
+<style lang="scss">
+	.order_card{
+		margin-top:20rpx;
+	}
+	.border_ccc {
+		border: 1rpx solid #ccc;
+	}
+	.bt{
+		border-top: 1rpx solid #eee;
+	}
+	.btn ~ .btn{
+		margin-left: 16rpx;
+	}
+</style>

+ 393 - 0
pages/activity/coupon/index.vue

@@ -0,0 +1,393 @@
+<template>
+	<view :style="colorStyle">
+		<view class="w-full h-400 relative z-10" :style="{'height': (186 + sysHeight) * 2 + 'rpx', 'background' : headerBg}">
+			<view class="fixed-lt w-full z-20" :style="{'padding-top': sysHeight + 'px','background': pageScrollStatus ? 'var(--view-theme)' : 'transparent'}">
+				<view class="w-full px-20 pl-20 h-80 flex-between-center">
+					<text class="iconfont icon-ic_leftarrow fs-40 text--w111-fff" @tap="backPage"></text>
+					<text class="fs-34 fw-500 text--w111-fff">领券中心</text>
+					<text></text>
+				</view>
+			</view>
+			<view class="abs-box flex-col">
+				<image src="../static/get_coupon_text.png" class="w-184 h-46"></image>
+				<text class="fs-24 lh-34rpx text--w111-fff pt-20">天天来领券,优惠看的见</text>
+			</view>
+			<image class="w-530 h-226 block abs-rb bottom-t20" :src="imgHost+'/statics/images/get_coupon_bg.png'"></image>
+		</view>
+		<view class="relative rd-t-40rpx bg--w111-f5f5f5 w-full content">
+			<view class="_box flex-between-center text--w111-666 fs-30 lh-42rpx"
+				:class="pageScrollStatus ? '' : 'rd-t-40rpx'"
+				:style="{'top': (36 + sysHeight) * 2 + 'rpx'}">
+				<text :class="current == 0 ? 'font-num fw-500' : ''" @tap="changeTab(0)">默认排序</text>
+				<view class="flex-y-center" @tap="changeTab(1)">
+					<text :class="current == 1 ? 'font-num fw-500' : ''">最新</text>
+					<text v-show="params.timeOrder == 'desc'" class="iconfont icon-ic_down2 fs-14 ml-6 font-num"></text>
+					<text v-show="params.timeOrder == 'asc'" class="iconfont icon-ic_up2 fs-14 ml-6 font-num"></text>
+					<text v-show="params.timeOrder == ''" class="iconfont icon-ic_down2 fs-14 ml-6"></text>
+					<!-- timeOrder -->
+				</view>
+				<view class="flex-y-center" @tap="changeTab(2)">
+					<text :class="current == 2 ? 'font-num fw-500' : ''">价值</text>
+					<text v-show="params.priceOrder == 'desc'" class="iconfont icon-ic_down2 fs-14 ml-6 font-num"></text>
+					<text v-show="params.priceOrder == 'asc'" class="iconfont icon-ic_up2 fs-14 ml-6 font-num"></text>
+					<text v-show="params.priceOrder == ''" class="iconfont icon-ic_down2 fs-14 ml-6"></text>
+				</view>
+				<view class="flex-y-center" @tap="showDrop = !showDrop">
+					<text class="menu_line"></text>
+					<text>筛选</text>
+					<text class="iconfont icon-ic_sort pl-8"></text>
+				</view>
+				<view class="drop-box bg--w111-f5f5f5 flex justify-between" v-if="showDrop">
+					<view class="inline-block h-52 rd-28rpx px-28 lh-52rpx text-center fs-24 bg--w111-fff"
+						v-for="(item, index) in navList" :key="index"
+						:class="params.type === item.type ? 'active-tab' : ''"
+						@tap="setType(item.type)">{{item.name}}</view>
+				</view>
+			</view>
+			<view class="px-20" v-if="couponsList.length">
+				<view class="relative card-item" v-for="(item,index) in couponsList" :key="index">
+					<view class="card w-full h-200 bg--w111-fff rd-24rpx p-20 flex justify-between"
+						:class="{svip: item.receive_type === 4}">
+						<view class="flex">
+							<easy-loadimage
+							mode="widthFix"
+							:image-src="item.products[0].image"
+							width="160rpx"
+							height="160rpx"
+							borderRadius="16rpx" v-if="item.products[0] && item.products[0].image"></easy-loadimage>
+							<view class="w-160 h-160 rd-16rpx flex-center fs-22 text--w111-999" v-else>暂无商品</view>
+							<view class="w-338 pl-24">
+								<view class="w-286 h-72 lh-36rpx line2 fw-500" :class="item.is_use ? 'text--w111-ccc' : ''">{{item.title}}</view>
+								<view class="fs-20 lh-28rpx mt-8" :class="item.is_use ? 'text--w111-ccc' : 'text--w111-666'"
+									v-if="item.coupon_time">领取后{{item.coupon_time}}天内可用</view>
+								<view class="fs-20 lh-28rpx mt-8" :class="item.is_use ? 'text--w111-ccc' : 'text--w111-666'"
+									v-else>{{ item.start_time ? item.start_time + '-' : '' }}{{ item.end_time }}</view>
+									<view class="flex-y-center fs-20 text--w111-999 lh-28rpx mt-20">
+										<text>{{item.type | typeFilter}}</text>
+										<view  v-show="item.rule" @tap="toggleRule(item)">
+											<text class="pl-8"> | 查看用券规则</text>
+											<text class="iconfont icon-ic_downarrow fs-20 ml-4"></text>
+										</view>
+									</view>
+							</view>
+						</view>
+						<view class="flex-1 flex-col flex-center">
+							<baseMoney
+							:money="item.coupon_price"
+							symbolSize="28"
+							integerSize="44"
+							decimalSize="28"
+							:color="item.is_use ? '#cccccc' : item.receive_type === 4 ? '#333' : 'var(--view-theme)'"
+							isCoupon
+							v-if="item.coupon_type==1"></baseMoney>
+							<view v-else class="fs-44 SemiBold"
+								:style="{color: item.is_use ? '#cccccc' : item.receive_type === 4 ? '#333' : 'var(--view-theme)'}"
+								>{{ parseFloat(item.coupon_price) / 10 }} <text class="pingfang fs-28 pl-4">折</text></view>
+							<text class="fs-20 lh-28rpx mt-8"
+								:class="item.is_use ? 'text--w111-ccc' : 'font-num'">满{{item.use_min_price}}可用</text>
+							<view class="w-128 h-48 rd-30rpx flex-center fs-20 bg-hui text--w111-fff mt-16" v-if="item.is_use == true">已领取</view>
+							<view class="w-128 h-48 rd-30rpx flex-center fs-20 bg-hui text--w111-fff mt-16" v-else-if="item.is_use == 2">已领完</view>
+							<view class="w-128 h-48 rd-30rpx flex-center fs-20 bg-gradient text--w111-fff mt-16" v-else
+								@tap="getCoupon(item.id, index)">立即领取</view>
+						</view>
+					</view>
+					<view class="rule-desc" v-html="item.rule" v-show="item.ruleShow"></view>
+				</view>
+			</view>
+			<view class='loadingicon flex-center' v-if="couponsList.length">
+				<text class='loading iconfont icon-jiazai' :hidden='loading==false'></text>{{loadTitle}}
+			</view>
+			<view class="px-20" v-if="!couponsList.length">
+				<emptyPage title="暂无优惠券,去看点别的吧~" src="/statics/images/noCoupon.gif"></emptyPage>
+			</view>
+		</view>
+		<view class="mask" v-if="showDrop" @tap="showDrop = false"></view>
+	</view>
+</template>
+
+<script>
+	let sysHeight = uni.getSystemInfoSync().statusBarHeight;
+	import { getCoupons, setCouponReceive } from '@/api/api.js';
+	import emptyPage from '@/components/emptyPage.vue';
+	import { toLogin } from '@/libs/login.js';
+	import { mapGetters } from "vuex";
+	import colors from '@/mixins/color.js';
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default {
+		mixins:[colors],
+		components:{ emptyPage },
+		data() {
+			return {
+				sysHeight:sysHeight,
+				couponsList: [],
+				loading: false,
+				loadend: false,
+				loadTitle: '加载更多', //提示语
+				params:{
+					page: 1,
+					limit: 20,
+					type: '',
+					defaultOrder: 1,
+					timeOrder: '',
+					priceOrder: ''
+				},
+				isAuto: false, //没有授权的不会自动授权
+				isShowAuth: false, //是否隐藏授权
+				navList: [
+					{name: '快过期',type: -1},
+					{name: '通用券',type: 0},
+					{name: '品类券',type: 1},
+					{name: '商品券',type: 2},
+					{name: '品牌券',type: 3},
+				],
+				count: 0,
+				imgHost:HTTP_REQUEST_URL,
+				pageScrollStatus:false,
+				showDrop: false,
+				current:0,
+				price: 0,
+			};
+		},
+		computed:{
+			...mapGetters(['isLogin']),
+			headerBg(){
+				return 'linear-gradient(90deg, var(--view-gradient) 0%, var(--view-theme) 100%)'
+			}
+		},
+		filters:{
+			typeFilter(val){
+				let obj = {
+					0: '通用券',
+					1: '品类券',
+					2: '商品券',
+					3: '品牌券',
+				};
+				return obj[val]
+			}
+		},
+		onPageScroll(object) {
+			if (object.scrollTop > 130) {
+				this.pageScrollStatus = true;
+			} else if (object.scrollTop < 130) {
+				this.pageScrollStatus = false;
+			}
+			uni.$emit('scroll');
+		},
+		onLoad() {
+			if (this.isLogin) {
+				this.getUseCoupons();
+			} else {
+				toLogin()
+			}
+		},
+		/**
+		 * 页面上拉触底事件的处理函数
+		 */
+		onReachBottom() {
+			this.getUseCoupons();
+		},
+		methods: {
+			changeTab(val){
+				this.current = val;
+				if(val == 0){
+					this.params.defaultOrder = 1;
+					this.params.timeOrder = '';
+					this.params.priceOrder = '';
+				}else if(val == 1){
+					if(this.params.timeOrder == '') {
+						this.params.timeOrder = 'asc'
+					}else if (this.params.timeOrder == 'asc'){
+						this.params.timeOrder = 'desc'
+					}else if(this.params.timeOrder == 'desc'){
+						this.params.timeOrder = ''
+					}
+					this.params.defaultOrder = '';
+					this.params.priceOrder = '';
+				} else if(val == 2){
+					if(this.params.priceOrder == '') {
+						this.params.priceOrder = 'asc'
+					}else if (this.params.priceOrder == 'asc'){
+						this.params.priceOrder = 'desc'
+					}else if(this.params.priceOrder == 'desc'){
+						this.params.priceOrder = ''
+					}
+					this.params.defaultOrder = '';
+					this.params.timeOrder = '';
+				}
+				this.params.page = 1;
+				this.couponsList = [];
+				this.loadend = false;
+				this.loading = false;
+				this.getUseCoupons();
+			},
+			toggleRule(item){
+				item.ruleShow = !item.ruleShow
+			},
+			backPage(){
+				uni.navigateBack()
+			},
+			goDetails(item){
+				uni.navigateTo({
+					url: '/pages/goods_details/index?id=' + item.id
+				})
+			},
+			getCoupon: function(id, index) {
+				let that = this;
+				let list = that.couponsList;
+				//领取优惠券
+				setCouponReceive(id).then(function(res) {
+					list[index].is_use = true;
+					that.$set(that, 'couponsList', list);
+					that.$util.Tips({
+						title: '领取成功'
+					});
+				}).catch(error => {
+					return that.$util.Tips({
+						title: error
+					});
+				})
+			},
+			/**
+			 * 获取领取优惠券列表
+			 */
+			getUseCoupons: function() {
+				let that = this
+				if (this.loadend) return false;
+				if (this.loading) return false;
+				that.loading = true;
+				that.loadTitle = '加载更多';
+				getCoupons(this.params).then(res => {
+					let list = res.data.list,
+						loadend = list.length < that.params.limit,
+						countIndex = [];
+					list.map(item=>{
+						this.$set(item,'ruleShow',false);
+					})
+					let couponsList = that.$util.SplitArray(list, that.couponsList);
+					that.$set(that, 'couponsList', couponsList);
+					that.loadend = loadend;
+					that.loading = false;
+					that.loadTitle = loadend ? '没有更多内容啦~' : '加载更多';
+					that.params.page++;
+				}).catch(err => {
+					that.loading = false;
+					that.loadTitle = '加载更多';
+				});
+			},
+			setType(type) {
+				if (this.params.type !== type) {
+					this.params.type = type;
+					this.couponsList = [];
+					this.params.page = 1;
+					this.loadend = false;
+					this.showDrop = false;
+					this.getUseCoupons();
+				}
+			}
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	.abs-box{
+		width: 264rpx;
+		position: absolute;
+		left: 48rpx;
+		bottom: 80rpx;
+	}
+	.content{
+		top: -44rpx;
+	}
+	.menu_line {
+		width: 1rpx;
+		height: 26rpx;
+		background: #ccc;
+		margin: 0 32rpx 0 20rpx;
+	}
+	._box{
+		padding: 28rpx 32rpx;
+		background: #f5f5f5;
+		position: sticky;
+		z-index: 99;
+	}
+	.drop-box{
+		width: 100%;
+		height: 102rpx;
+		position: absolute;
+		left: 0;
+		top: 92rpx;
+		border-radius: 0 0 40rpx 40rpx;
+		z-index: 199;
+		padding: 16rpx 32rpx 0;
+	}
+	.active-tab{
+		background: var(--view-minorColorT);
+		color: var(--view-theme);
+		border: 1px solid var(--view-theme);
+	}
+	.svip .font-num{
+		color: #333333 !important;
+	}
+	.svip .bg-gradient{
+		background: linear-gradient(90deg, #584834 0%, #32302D 100%);
+		color: #FACC7D;
+	}
+	.bg-hui{
+		color: #ffffff !important;
+		background: #cccccc !important;
+	}
+	.indent{
+		text-indent: 60rpx;
+	}
+	.card{
+		background-image:
+		radial-gradient(circle at 500rpx top, #f5f5f5, #f5f5f5 10rpx, transparent 11rpx),
+		radial-gradient(circle at 500rpx bottom, #f5f5f5, #f5f5f5 10rpx, transparent 11rpx);
+		position: relative;
+		&:before{
+			content: '';
+			position: absolute;
+			left: 500rpx;
+			top: 16rpx;
+			height: 168rpx;
+			border-left: 2px dotted #ddd;
+		}
+		.name {
+			width: 286rpx;
+			height: 80rpx;
+			line-height: 40rpx;
+			color: #333;
+			font-weight: 500;
+			font-size: 28rpx;
+		}
+		.type-tag{
+			display: inline-block;
+			background: var(--view-minorColorT);
+			color: var(--view-theme);
+			border-radius: 14rpx;
+			padding: 2rpx 10rpx;
+			font-size: 20rpx;
+			margin-right: 8rpx;
+			vertical-align: middle;
+		}
+	}
+	.card-item ~ .card-item{
+		margin-top: 20rpx;
+	}
+	.rule-desc{
+		margin-top: -16rpx;
+		padding: 40rpx 24rpx 24rpx;
+		white-space: pre-wrap;
+		font-size: 20rpx;
+		line-height: 28rpx;
+		background: linear-gradient(180deg, #F7F7F7 0%, #FFFFFF 100%);
+		border-radius: 0 0 24rpx 24rpx;
+		color: #999;
+	}
+	.SemiBold{
+		font-family: 'SemiBold'
+	}
+	.pingfang{
+		font-family: PingFang SC, PingFang SC;
+	}
+</style>

+ 256 - 0
pages/activity/goods_bargain/index.vue

@@ -0,0 +1,256 @@
+<template>
+  <!-- 砍价列表模块 -->
+	<view class="box">
+		<view class='bargain-list'>
+			<view class='header' :style="'background-image: url('+imgHost+'/statics/images/bargain-list-bg.png);'">
+				<!-- #ifndef MP -->
+				<text class="iconfont icon-ic_leftarrow" @click="goarrow"></text>
+				<!-- #endif -->
+				<!-- #ifdef MP -->
+				<view class="bargainTitle">
+					<view :style="{height:getHeight.barTop+'px'}"></view>
+					<view class="sysTitle acea-row row-center-wrapper" :style="{height:getHeight.barHeight+'px'}">
+						<text class="iconfont icon-ic_leftarrow" @click="goarrow"></text>
+					</view>
+				</view>
+				<!-- #endif -->
+			</view>
+			<view class='list' v-if="bargainList.length">
+				<block v-for="(item,index) in bargainList" :key="index">
+					<view class='item flex justify-between relative'
+						@tap="openSubscribe('/pages/activity/goods_bargain_details/index?id='+ item.id +'&spid='+ userInfo.uid)">
+						<!-- <image class="w-240 h-240 rd-16rpx" :src='item.image'></image> -->
+						<easy-loadimage
+						mode="widthFix" 
+						:image-src="item.image"
+						width="240rpx"
+						height="240rpx"
+						borderRadius="20rpx"></easy-loadimage>
+						<view class='w-410 fs-28 flex-col justify-between'>
+							<view>
+								<view class='w-410 lh-40rpx line2'>{{item.title}}</view>
+								<view class='fs-22 fw-500 mt-8 red'>
+									<text class='iconfont icon-ic_fire fs-22 mr-8'></text>
+									{{item.people}}人正在参与
+								</view>
+							</view>
+							<view class="flex-between-center">
+								<view>
+									<view class='flex items-baseline red'>
+										<text class="fs-22 lh-30rpx fw-500">最低: </text>
+										<baseMoney :money="item.min_price" symbolSize="24" integerSize="40" decimalSize="24" incolor="#E93323" weight></baseMoney>
+									</view>
+									<view class="otPrice">¥{{item.ot_price}}</view>
+								</view>
+								<view class='cutBnt w-144 h-56 rd-30rpx flex-center fs-24 text--w111-fff'>参与砍价</view>
+							</view>
+						</view>
+					</view>
+				</block>
+			</view>
+			<view class="list no-goods" v-if="!bargainList.length && !loading">
+				<image :src="imgHost + '/statics/images/noActivity.gif'" mode=""></image>
+				<text class="fs-26 text--w111-999 pt-16">暂无砍价商品,去看看其他商品吧~</text>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+	let app = getApp();
+	import { HTTP_REQUEST_URL } from '@/config/app';
+	import { getBargainList } from '@/api/activity.js';
+	import { openBargainSubscribe } from '@/utils/SubscribeMessage.js';
+	import { getUserInfo } from '@/api/user.js';
+	import { toLogin } from '@/libs/login.js';
+	import { mapGetters } from "vuex";
+	export default {
+		data() {
+			return {
+				bargainList: [],
+				page: 1,
+				limit: 20,
+				loading: false,
+				loadend: false,
+				userInfo: {},
+				isAuto: false, //没有授权的不会自动授权
+				isShowAuth: false, //是否隐藏授权
+				imgHost:HTTP_REQUEST_URL,
+				// #ifdef MP
+				getHeight: this.$util.getWXStatusHeight()
+				// #endif
+			};
+		},
+		computed: mapGetters(['isLogin']),
+		watch: {
+			isLogin: {
+				handler: function(newV, oldV) {
+					if (newV) {
+						// #ifndef MP
+						this.getUserInfo();
+						// #endif
+					}
+				},
+				deep: true
+			}
+		},
+		onLoad: function(options) {
+			uni.setNavigationBarTitle({
+				title: "砍价列表"
+			})
+			this.getBargainList();
+			if (this.isLogin) {
+				this.getUserInfo();
+			}
+		},
+		onShow(){
+			uni.removeStorageSync('form_type_cart');
+		},
+		onPageScroll(object) {
+			uni.$emit('scroll');
+		},
+		methods: {
+			// 授权关闭
+			authColse: function(e) {
+				this.isShowAuth = e
+			},
+			goarrow(){
+				uni.navigateBack()
+			},
+			/*
+			 * 获取用户信息
+			 */
+			getUserInfo: function() {
+				let that = this;
+				getUserInfo().then(res => {
+					that.$set(that, 'userInfo', res.data);
+				});
+			},
+			openSubscribe: function(e) {
+				if(this.isLogin){
+					let page = e;
+					// #ifndef MP
+					uni.navigateTo({
+						url: page
+					});
+					// #endif
+					// #ifdef MP
+					uni.showLoading({
+						title: '正在加载',
+					})
+					openBargainSubscribe().then(res => {
+						uni.hideLoading();
+						uni.navigateTo({
+							url: page,
+						});
+					}).catch((err) => {
+						uni.hideLoading();
+					});
+					// #endif
+				}else{
+					toLogin()
+				}
+			},
+			getBargainList: function() {
+				let that = this;
+				if (that.loadend) return;
+				if (that.loading) return;
+				that.loading = true;
+				getBargainList({
+					page: that.page,
+					limit: that.limit
+				}).then(function(res) {
+					that.$set(that, 'bargainList', that.bargainList.concat(res.data));
+					that.$set(that, 'page', that.page + 1);
+					that.$set(that, 'loadend', that.limit > res.data.length);
+					that.$set(that, 'loading', false);
+				}).catch(res => {
+					that.loading = false;
+				});
+			},
+		},
+		onReachBottom: function() {
+			this.getBargainList();
+		},
+	}
+</script>
+
+<style lang="scss">
+	.bargainTitle{
+		position: fixed;
+		left:0;
+		top:0;
+		width: 100%;
+		z-index: 99;
+		.sysTitle{
+			width: 100%;
+			position: relative;
+			.iconfont{
+				position: absolute;
+				font-size: 36rpx;
+				left:11rpx;
+				width: 80rpx;
+				color:#fff;
+			}
+		}
+	}
+	.no-goods{
+		text-align: center;
+		padding-bottom: 60rpx!important;
+		color: #999;
+		image{
+			width: 440rpx;
+			height: 360rpx;
+			margin: 40rpx auto 0 auto;
+			display: block;
+		}
+	}
+
+	.bargain-list .header {
+		background-repeat: no-repeat;
+		background-size: 100% 100%;
+		width: 750rpx;
+		height: 926rpx;
+		padding-top: 55rpx;
+		box-sizing: border-box;
+		
+		.iconfont{
+			color: #fff;
+			font-size: 40rpx;
+			margin-left: 15rpx;
+		}
+	}
+
+	.bargain-list .list {
+		background-color: #fff;
+		border-radius: 24rpx;
+		margin: -510rpx 20rpx 66rpx 20rpx;
+		padding: 32rpx 20rpx;
+	}
+	
+	.item~.item{
+		margin-top: 40rpx;
+	}
+	
+	.red{
+		color: #E93323;
+	}
+	
+	.otPrice{
+		font-size: 26rpx;
+		font-family: Regular;
+		color: #999;
+		text-decoration: line-through;
+		margin-top: 4rpx;
+	}
+
+	.cutBnt {
+		background: linear-gradient(90deg, #FF7931 0%, #E93323 100%);
+	}
+
+	.bargain-list .list .load {
+		font-size: 24rpx;
+		height: 85rpx;
+		text-align: center;
+		line-height: 85rpx;
+	}
+</style>

+ 1573 - 0
pages/activity/goods_bargain_details/index.vue

@@ -0,0 +1,1573 @@
+<template>
+	<view class="bargainCon" :style="colorStyle">
+		<skeleton :show="showSkeleton" :isNodes="isNodes" ref="skeleton" loading="chiaroscuro" selector="skeleton"
+			bgcolor="#FFF"></skeleton>
+		<view class="bargain skeleton" :style="{visibility: showSkeleton ? 'hidden' : 'visible'}">
+			<view :style="'background-image: url('+(bargainUid != userInfo.uid ?supportBg:bargaBg)+');'"
+				class="header">
+				<!-- #ifndef MP -->
+				<view class="iconfont icon-ic_leftarrow" @click="goBack"></view>
+				<!-- #endif -->
+				<!-- #ifdef MP -->
+				<view class="bargainTitle">
+					<view :style="{height:getHeight.barTop+'px'}"></view>
+					<view class="sysTitle acea-row row-center-wrapper" :style="{height:getHeight.barHeight+'px'}">
+						<text class="iconfont icon-ic_leftarrow" @click="goBack"></text>
+					</view>
+				</view>
+				<!-- #endif -->
+				<view class="rule-btn w-72 flex-center fs-24 text--w111-fff" :style="{top: 81 + sysHeight + 'px'}"
+					@tap="showDrawer = true">规则</view>
+				<view class="rule-btn w-124 flex-center fs-24 text--w111-fff" :style="{top: 110 + sysHeight + 'px'}"
+					@tap="goRecord">砍价记录</view>
+			</view>
+			<view class="wrapperCon">
+				<view class="timeCon" :style="'background-image: url('+ countdownBg +');'">
+					<view v-if="bargainUid == userInfo.uid">
+						<countDown 
+						:tipText="'倒计时:'" 
+						inDayText="天" 
+						dayText=":" 
+						hourText=":" 
+						minuteText=":" 
+						secondText=" "
+						:datatime="datatime" 
+						bgColor="#E93323"
+						colors="#FFFFFF"
+						dotColor="#E93323"
+						:isDay="true" 
+						@endTime='endTime' 
+						v-if='endTimes == 0'></countDown>
+						<view class="endTimes" v-else>此商品砍价已结束</view>
+					</view>
+					<view v-if="bargainUid != userInfo.uid" class="pictxt acea-row row-center-wrapper">
+						<view class="pictrue">
+							<image :src="bargainUserInfo.avatar"></image>
+						</view>
+						<view class="text">
+							<text class="name">{{ bargainUserInfo.nickname || '' }}</text>
+							邀请您帮忙砍价
+						</view>
+					</view>
+				</view>
+				<view class="wrapper">
+					<view class="pictxt acea-row row-between-wrapper" @tap="goProduct">
+						<view class="pictrue skeleton-rect">
+							<!-- <image :src="bargainInfo.image"></image> -->
+							<easy-loadimage
+							mode="widthFix" 
+							:image-src="bargainInfo.image"
+							width="240rpx"
+							height="240rpx"
+							borderRadius="16rpx"></easy-loadimage>
+						</view>
+						<view class="text">
+							<view class="top">
+								<view class="name line2 skeleton-rect">
+									<!-- <span class='labelN' v-if="bargainInfo.brand_name && bargainInfo.brand_name.trim()">{{bargainInfo.brand_name}}</span> -->
+								  {{ bargainInfo.title }}
+								</view>
+								<view class="tips">已有<text class="num">{{payCount}}人</text>砍价成功</view>
+							</view>
+							<baseMoney :money="bargainInfo.price" color='#E93323' :preFix="'当前'" symbolSize="32" integerSize="48"
+								decimalSize="32" preFixSize='22' weight></baseMoney>
+							<!-- <view class="successNum skeleton-rect">最低:¥{{ bargainInfo.min_price }}</view> -->
+						</view>
+					</view>
+					<!-- 进度条 -->
+					<block v-if="bargainUserHelpInfo.price > 0">
+						<view class="cu-progress acea-row row-middle round margin-top" :class="endTimes?'on':''">
+							<view class="acea-row row-middle bg-red"
+								:style="'width:' + bargainUserHelpInfo.pricePercent + '%;'">
+								<view v-if="">
+									<image class="img" :class="bargainUserHelpInfo.alreadyPrice<=0?'on':''" :src="knife"></image>
+									<view class="triangle" v-if="bargainUserHelpInfo.alreadyPrice>0"></view>
+									<view class="hacked" v-if="bargainUserHelpInfo.alreadyPrice>0">
+										已砍{{ bargainUserHelpInfo.alreadyPrice }}元
+									</view>
+								</view>
+							</view>
+						</view>
+						<view class="money acea-row row-right">
+							<view>还剩<text class="num">{{ bargainUserHelpInfo.price }}元</text></view>
+						</view>
+					</block>
+					<view class="skeleton-rect" v-if="!isLogin" @click="getIsLogin">
+						<view class="bargainBnt">立即登录</view>
+					</view>
+					<view class="skeleton-rect" v-if="endTimes">
+						<view class="bargainBnt grey">活动已结束</view>
+						<view class="seeGood" @click="goIndex">再去逛逛<text class="iconfont icon-ic_rightarrow"></text></view>
+					</view>
+					<view v-else>
+						<!-- 自己砍价 -->
+						<view class="skeleton-rect"
+							v-if="bargainUid == userInfo.uid && (!userBargainStatus || userBargainStatus == bargainSumCount) && bargainUserHelpInfo.price > 0">
+							<view class="bargainBnt" @tap="userBargain" v-if="productStock > 0 && quota > 0">立即参与砍价</view>
+							<view class="bargainBnt grey" v-if="productStock <= 0 || quota <= 0">商品暂无库存</view>
+						</view>
+						<!-- 帮助砍价、帮砍成功: -->
+						<view class="skeleton-rect"
+							v-if="bargainUid == userInfo.uid && bargainUserHelpInfo.price > 0 && userBargainStatus != bargainSumCount">
+							<view class="bargainBnt" @tap="getBargainUserBargainPricePoster">邀请好友帮忙砍价</view>
+							<view class="tip">
+								已有
+								<text class="num">{{ bargainUserHelpInfo.count }}</text>
+								位好友成功帮您砍价
+							</view>
+						</view>
+										
+						<view v-if="bargainUid != userInfo.uid && userBargainStatusHelp && bargainUserHelpInfo.price > 0">
+							<view class="bargainBnt skeleton-rect" @tap="setBargainHelp">帮好友砍一刀</view>
+						</view>
+						<view v-if="bargainUid != userInfo.uid && userBargainStatusHelp && bargainUserHelpInfo.price == 0">
+							<view class="bargainSuccess skeleton-rect">
+								<text class="iconfont icon-a-ic_CompleteSelect"></text>
+								好友已砍价成功
+							</view>
+							<view class="bargainBnt grey skeleton-rect" v-if="productStock <= 0 || quota <= 0">商品暂无库存</view>
+							<view v-else>
+								<view class="bargainBnt grey skeleton-rect" v-if="bargainInfo.is_bargain">我也要参与</view>
+								<view class="bargainBnt skeleton-rect" @tap="currentBargainUser" v-else>我也要参与</view>
+							</view>
+						</view>
+						<view v-if="bargainUid != userInfo.uid && !userBargainStatusHelp">
+							<view class="bargainSuccess skeleton-rect" v-if="productStock <= 0 || quota <= 0">
+								<text class="iconfont icon-a-ic_CompleteSelect"></text>
+								已成功帮助好友砍价
+							</view>
+							<view class="bargainBnt grey" v-if="productStock <= 0 || quota <= 0">商品暂无库存</view>
+							<view v-else>
+								<view class="bargainBnt grey skeleton-rect" v-if="bargainInfo.is_bargain">我也要参与</view>
+								<view class="bargainBnt skeleton-rect" @tap="currentBargainUser" v-else>我也要参与</view>
+							</view>
+						</view>
+						<view v-if="bargainUserHelpInfo.price == 0 && bargainUid == userInfo.uid && statusPay != 3">
+							<view class="bargainSuccess on skeleton-rect">
+								<text class="iconfont icon-a-ic_CompleteSelect"></text>
+								恭喜您砍价成功,快去支付吧~
+							</view>
+							<view class="bargainBnt grey" v-if="productStock <= 0 || quota <= 0">商品暂无库存</view>
+							<view class="bargainBnt skeleton-rect" v-else @tap="goPay">立即支付</view>
+							<view class="bargainBnt on skeleton-rect" @tap="goBargainList">抢更多商品</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="bargainGang skeleton-rect" v-if="bargainUserHelpList.length">
+				<view class="title acea-row row-center-wrapper" :style="'background-image: url('+ bargainTitle +');'">
+					<view class="pictrue"></view>
+					<view class="titleCon">砍价帮</view>
+					<view class="pictrue on"></view>
+				</view>
+				<view class="tips">共有<text class="num">{{bargainUserHelpList.length}}</text>位好友成功帮您砍价</view>
+				<view class="list">
+					<block v-for="(item, index) in bargainUserHelpList" :key="index" v-if="index < 3 || !couponsHidden">
+						<view class="item acea-row row-between-wrapper">
+							<view class="pictxt acea-row row-between-wrapper">
+								<view class="pictrue">
+									<image :src="item.avatar"></image>
+								</view>
+								<view class="text">
+									<view class="name line1">{{ item.nickname }}</view>
+									<view class="line1">{{ item.add_time }}</view>
+								</view>
+							</view>
+							<view class="money">
+								砍掉<text class="label">¥</text><text class="num">{{ item.price }}</text>
+							</view>
+						</view>
+					</block>
+					<view class="open acea-row row-center-wrapper" @click="openTap"
+						v-if="bargainUserHelpList.length > 3">
+						{{ couponsHidden ? '展开全部好友' : '关闭全部好友' }}
+						<text class="iconfont"
+							:class="couponsHidden == true ? 'icon-ic_downarrow' : 'icon-ic_uparrow'"></text>
+					</view>
+				</view>
+				<view class="load" v-if="!limitStatus" @tap="getBargainUser">点击加载更多</view>
+			</view>
+			<view class="goodsDetails skeleton-rect">
+				<view class="title acea-row row-center-wrapper" :style="'background-image: url('+ bargainTitle +');'">
+					<view class="pictrue"></view>
+					<view class="titleCon">商品详情</view>
+					<view class="pictrue on"></view>
+				</view>
+				<view class="conter">
+					<!-- #ifndef APP-PLUS -->
+					<jyf-parser :html="bargainInfo.description" ref="article" :tag-style="tagStyle"></jyf-parser>
+					<!-- #endif -->
+					<!-- #ifdef APP-PLUS -->
+					<view v-html="bargainInfo.description"></view>
+					<!-- #endif -->
+				</view>
+			</view>
+			<view class="bargainTip" :class="active == true ? 'on' : ''">
+				<view class="pictrue">
+					<image :src="bargainPop"></image>
+				</view>
+				<view v-if="bargainUid == userInfo.uid">
+					<view class="cutOff">
+						<view class="title">您已砍掉<text class="num">{{ bargainUserBargainPrice.price }}元</text></view>
+						<view>听说分享次数越多,</view>
+						<view>砍价成功的几率越高哦!</view>
+					</view>
+					<!-- #ifdef MP -->
+					<button class="tipBnt" @tap="getBargainUserBargainPricePoster"><text class="iconfont icon-ic_kanjia"></text>邀请好友帮砍价</button>
+					<!-- #endif -->
+					<!-- #ifdef H5 -->
+					<view class="tipBnt" @tap="getBargainUserBargainPricePoster"><text class="iconfont icon-ic_kanjia"></text>邀请好友帮砍价</view>
+					<!-- #endif -->
+				</view>
+				<view v-else>
+					<view class="cutOff">
+						<view class="title">成功帮砍<text class="num">{{ bargainUserBargainPrice.price }}元</text></view>
+						<view>您也可以砍价低价拿哦,</view>
+						<view>快去挑选心仪的商品吧~</view>
+					</view>
+					<view class="tipBnt grey" v-if="bargainInfo.is_bargain">我也要参与</view>
+					<view @tap="currentBargainUser" class="tipBnt" v-else>我也要参与</view>
+				</view>
+			</view>
+			<view class="mask" catchtouchmove="true" v-show="active == true" @tap="close"></view>
+		</view>
+		<!-- 分享按钮 -->
+		<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="getBargainUserBargainPricePoster">
+				<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>
+		<!-- #ifdef H5 -->
+		<view class="followCode" v-if="followCode">
+			<view class="pictrue">
+				<view class="code-bg"><img class="imgs" :src="codeSrc" /></view>
+			</view>
+			<view class="mask" @click="closeFollowCode"></view>
+		</view>
+		<zb-code ref="qrcode" v-show="false" :show="codeShow" :cid="cid" :val="val" :size="size" :unit="unit"
+			:background="background" :foreground="foreground" :pdground="pdground" :icon="icon" :iconSize="iconsize"
+			:onval="onval" :loadMake="loadMake" @result="qrR" />
+		<!-- #endif -->
+		<base-drawer mode="bottom" :visible="showDrawer" background-color="transparent" mask maskClosable @close="closeDrawer">
+			<view class="w-full bg--w111-fff rd-t-40rpx py-32 relative">
+				<view class="text-center fs-32 text--w111-333 fw-500">砍价规则</view>
+				<view class="close flex-center" @tap='closeDrawer'>
+					<text class="iconfont icon-ic_close fs-24 text--w111-999"></text>
+				</view>
+				<view class="mt-48 px-32 scroll-content">
+					<jyf-parser :html="bargainInfo.rule" ref="article" :tag-style="tagStyle"></jyf-parser>
+				</view>
+				<view class="mx-20 pb-safe">
+				  <view class="mt-52 h-72 flex-center rd-36px bg-red fs-26 text--w111-fff" @click="closeDrawer">我知道了</view>
+				</view>
+			</view>
+		</base-drawer>
+	</view>
+</template>
+
+<script>
+	let sysHeight = uni.getSystemInfoSync().statusBarHeight;
+	import zbCode from '@/components/zb-code/zb-code.vue';
+	import baseDrawer from '@/components/tui-drawer/tui-drawer.vue';
+	import {
+		getBargainDetail,
+		postBargainStartUser,
+		postBargainStart,
+		postBargainHelpPrice,
+		postBargainHelpCount,
+		postBargainHelp,
+		postBargainHelpList,
+		postBargainShare
+	} from '@/api/activity.js';
+	import {
+		postCartAdd
+	} from '@/api/store.js';
+	import util from '@/utils/util.js';
+	import {
+		toLogin
+	} from '@/libs/login.js';
+	import {
+		mapGetters
+	} from 'vuex';
+	import countDown from '@/components/countDown';
+	import home from '@/components/home';
+	import parser from '@/components/jyf-parser/jyf-parser';
+	import {
+		silenceBindingSpread
+	} from '@/utils';
+	import {
+		TOKENNAME,
+		HTTP_REQUEST_URL
+	} from '@/config/app.js';
+	const app = getApp();
+	import colors from "@/mixins/color";
+	export default {
+		components: {
+			baseDrawer,
+			countDown,
+			home,
+			'jyf-parser': parser
+		},
+		/**
+		 * 页面的初始数据
+		 */
+		mixins: [colors],
+		data() {
+			return {
+				// #ifdef MP
+				getHeight: this.$util.getWXStatusHeight(),
+				// #endif
+				sysHeight: sysHeight,
+				showSkeleton: true, //骨架屏显示隐藏
+				isNodes: 0, //控制什么时候开始抓取元素节点,只要数值改变就重新抓取
+				countDownDay: '00',
+				countDownHour: '00',
+				countDownMinute: '00',
+				countDownSecond: '00',
+				active: false,
+				id: 0, //砍价产品编号
+				userInfo: {}, //当前用户信息
+				bargainUid: 0, //开启砍价用户
+				bargainUserInfo: {}, //开启砍价用户信息
+				bargainUserId: 0, //开启砍价编号
+				bargainInfo: {
+					brand_name:''
+				}, //砍价产品
+				offset: 0,
+				limit: 20,
+				limitStatus: false,
+				bargainUserHelpList: [],
+				bargainUserHelpInfo: [],
+				bargainUserBargainPrice: 0,
+				status: '', // 0 开启砍价   1  朋友帮忙砍价  2 朋友帮忙砍价成功 3 完成砍价  4 砍价失败 5已创建订单
+				bargainCount: [], //分享人数  浏览人数 参与人数
+				retunTop: true,
+				bargainPartake: 0,
+				isHelp: false,
+				interval: null,
+				userBargainStatus: 0, //判断自己是否砍价
+				bargainSumCount: 0, // 购买次数
+				productStock: 0, //判断是否售罄;
+				quota: 0, //判断是否已限量;
+				userBargainStatusHelp: true,
+				navH: '',
+				statusPay: '',
+				bargainPrice: 0,
+				datatime: 0,
+				offest: '',
+				tagStyle: {
+					img: 'width:100%;display:block;',
+					table: 'width:100%',
+					video: 'width:100%'
+				},
+				H5ShareBox: false, //公众号分享图片
+				systemH: 100,
+				isAuto: false, //没有授权的不会自动授权
+				isShowAuth: false, //是否隐藏授权
+				// pages: '',
+				posters: false,
+				weixinStatus: false,
+				couponsHidden: true,
+				followCode: false,
+				//二维码参数
+				codeShow: false,
+				cid: '1',
+				ifShow: true,
+				val: "", // 要生成的二维码值
+				size: 200, // 二维码大小
+				unit: 'upx', // 单位
+				background: '#FFF', // 背景色
+				foreground: '#000', // 前景色
+				pdground: '#000', // 角标色
+				icon: '', // 二维码图标
+				iconsize: 40, // 二维码图标大小
+				lv: 3, // 二维码容错级别 , 一般不用设置,默认就行
+				onval: true, // val值变化时自动重新生成二维码
+				loadMake: true, // 组件加载完成后自动生成二维码
+				src: '', // 二维码生成后的图片地址或base64
+				codeSrc: "",
+				picUrl: {},
+				payCount: 0, //砍价成功人数;
+				endTimes:0,
+				imgHost:HTTP_REQUEST_URL,
+				supportBg: HTTP_REQUEST_URL+'/statics/images/bargain/bargain-support.png',
+				bargaBg: HTTP_REQUEST_URL+'/statics/images/bargain/bargain-con.png',
+				countdownBg: HTTP_REQUEST_URL+'/statics/images/bargain/bargain-countdown-bg.png',
+				knife: HTTP_REQUEST_URL+'/statics/images/bargain/bargain-knife.png',
+				bargainTitle: HTTP_REQUEST_URL+'/statics/images/bargain/bargain-title-bg.png',
+				bargainPop: HTTP_REQUEST_URL+'/statics/images/bargain/bargain-pop.jpg',
+				showDrawer: false,
+			};
+		},
+		computed: mapGetters(['isLogin']),
+		watch: {
+			isLogin: {
+				handler: function(newV, oldV) {
+					if (newV) {
+						// #ifndef MP
+						this.addShareBargain();
+						// #endif
+					}
+				},
+				deep: true
+			}
+		},
+		/**
+		 * 生命周期函数--监听页面加载
+		 */
+		onLoad: function(options) {
+			this.colorData();
+			var that = this;
+			// #ifdef MP
+			uni.getSystemInfo({
+				success: function(res) {
+					that.systemH = res.statusBarHeight;
+					that.navH = that.systemH + 10;
+				}
+			});
+			// #endif
+			var pages = getCurrentPages();
+			if (pages.length <= 1) {
+				that.retunTop = false;
+			}
+			//扫码携带参数处理
+			// #ifdef MP
+			if (options.scene) {
+				var value = util.getUrlParams(decodeURIComponent(options.scene));
+				if (typeof value === 'object') {
+					if (value.id) options.id = value.id;
+					if (value.spid) options.spid = value.spid;
+				} else {
+					app.globalData.spid = value;
+				}
+			}
+			// #endif
+			
+			if (options.hasOwnProperty('id')) {
+				that.id = options.id;
+				that.bargainUid = options.spid || 0;
+				//记录推广人uid
+				if (options.spid) app.globalData.spid = options.spid;
+			}
+			this.getBargainDetails();
+			if (this.isLogin) {
+				if (that.bargainUid == 'undefined' || !that.bargainUid) {
+					that.bargainUid = that.$store.state.app.uid;
+				}
+				this.addShareBargain();
+				// app.globalData.openPages = '/pages/activity/goods_bargain_details/index?id=' + this.id + '&bargain=' + this.bargainUid +
+				// 	'&spid=' + e.detail.uid;
+				// this.$set(that, 'bargainPartake', e.detail.uid);
+			} else {
+				this.$Cache.set('login_back_url',
+					`/pages/activity/goods_bargain_details/index?id=${options.id}&spid=${this.bargainUid}`);
+				this.getIsLogin();
+			}
+
+			this.isLogin && silenceBindingSpread();
+			uni.setNavigationBarTitle({
+				title: '砍价详情'
+			});
+		},
+		methods: {
+			endTime(e){
+				console.log('1111',e);
+				this.endTimes = e;
+				
+			},
+			getIsLogin(){
+				toLogin()
+			},
+			// 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.bargainInfo.title,
+					imageUrl: that.bargainInfo.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;
+					}
+				});
+			},
+			qrR(res) {
+				this.codeSrc = res
+			},
+			// #endif
+			/**
+			 * 分享打开
+			 * 
+			 */
+			listenerActionSheet: function() {
+				if (this.isLogin == false) {
+					this.getIsLogin();
+				} else {
+					// #ifdef H5
+					if (this.$wechat.isWeixin() === true) {
+						this.weixinStatus = true;
+					}
+					// #endif
+					this.posters = true;
+
+				}
+			},
+			getBargainUserBargainPricePoster() {
+				uni.navigateTo({
+					url: '/pages/activity/poster-poster/index?type=1&id=' + this.id + '&spid=' + this.bargainUid
+				});
+			},
+			// 分享关闭
+			listenerActionClose: function() {
+				this.posters = false;
+			},
+			// 小程序关闭分享弹窗;
+			goFriend: function() {
+				this.posters = false;
+			},
+			openTap() {
+				this.$set(this, 'couponsHidden', !this.couponsHidden);
+			},
+			// 授权关闭
+			authColse: function(e) {
+				this.isShowAuth = e;
+			},
+			// 去商品页
+			goProduct() {
+				uni.navigateTo({
+					url: `/pages/goods_details/index?id=${this.bargainInfo.product_id}`
+				});
+			},
+			// 自己砍价;
+			userBargain: function() {
+				let that = this;
+				if (that.userInfo.uid == that.bargainUid) {
+					if (that.userBargainStatus == that.bargainInfo.num) {
+						return that.$util.Tips({
+							title: `该商品每人限购${that.bargainInfo.num}${that.bargainInfo.unit_name}`
+						});
+					} else {
+						that.setBargain();
+					}
+				}
+			},
+			goBack: function() {
+				uni.navigateBack();
+			},
+			gobargainUserInfo: function() {
+				//获取开启砍价用户信息
+				var that = this;
+				var data = {
+					userId: that.bargainUid
+				};
+				postBargainStartUser({
+					bargainId: that.id,
+					bargainUserUid: that.bargainUid
+				}).then(res => {
+					that.$set(that, 'bargainUserInfo', res.data);
+				});
+			},
+			goPay: function() {
+				//立即支付
+				var that = this;
+				var data = {
+					productId: that.bargainInfo.product_id,
+					bargainId: that.id,
+					cartNum: 1,
+					uniqueId: '',
+					combinationId: 0,
+					secKillId: 0,
+					new: 1
+				};
+				postCartAdd(data)
+					.then(res => {
+						uni.navigateTo({
+							url: '/pages/goods/order_confirm/index?new=1&cartId=' + res.data.cartId
+						});
+					})
+					.catch(err => {
+						return that.$util.Tips({
+							title: err
+						});
+					});
+			},
+			getBargainDetails: function() {
+				//获取砍价产品详情
+				var that = this;
+				var id = that.id;
+				getBargainDetail(id)
+					.then(function(res) {
+						that.payCount = res.data.payCount;
+						that.bargainInfo = res.data.bargain;
+						if(that.bargainInfo.description){
+						   that.bargainInfo.description = that.bargainInfo.description.replace(
+						   	/<img/gi,
+						   	'<img style="max-width:100%;height:auto;float:left;display:block" '
+						   );
+						   that.bargainInfo.description = that.bargainInfo.description.replace(
+						   	/<video/gi,
+						   	'<video style="width:100%;height:auto;display:block" '
+						   );
+						}
+						that.bargainPrice = res.data.bargain.price;
+						that.userInfo = res.data.userInfo;
+						that.bargainSumCount = res.data.bargainSumCount;
+						that.userBargainStatus = res.data.userBargainStatus;
+						that.productStock = res.data.bargain.attr.product_stock;
+						that.quota = res.data.bargain.attr.quota;
+						that.datatime = res.data.bargain.stop_time;
+						uni.setNavigationBarTitle({
+							title: res.data.bargain.title.substring(0, 13) + '...'
+						});
+						that.bargainUserHelpList = [];
+						if(that.isLogin){
+							that.getBargainHelpCount();
+							that.getBargainUser();
+							that.gobargainUserInfo();
+						}
+						//#ifdef H5
+						that.setOpenShare();
+						//#endif
+						setTimeout(() => {
+							that.showSkeleton = false
+						}, 300)
+					})
+					.catch(function(err) {
+						that.$util.Tips({
+							title: err
+						}, {
+							tab: 2,
+							url: '/pages/activity/goods_bargain/index'
+						});
+					});
+			},
+			getBargainHelpCount: function() {
+				//获取砍价帮总人数、剩余金额、进度条、已经砍掉的价格
+				var that = this;
+				var data = {
+					bargainId: that.id,
+					bargainUserUid: that.bargainUid
+				};
+				postBargainHelpCount(data).then(res => {
+					var price = util.$h.Sub(that.bargainPrice, res.data.alreadyPrice);
+					that.bargainUserHelpInfo = res.data;
+					that.bargainInfo.price = parseFloat(price) <= 0 ? 0 : price;
+					that.userBargainStatusHelp = res.data.userBargainStatus;
+					that.statusPay = res.data.status;
+				});
+			},
+			currentBargainUser: function() {
+				//当前用户砍价
+				this.$set(this, 'bargainUid', this.userInfo.uid);
+				this.setBargain();
+			},
+			setBargain: function() {
+				//参与砍价
+				var that = this;
+				postBargainStart(that.id).then(res=>{
+					if (res.data.code === 'subscribe') {
+						that.$set(that, 'followCode', true);
+						this.codeSrc = res.data.url
+						return;
+					}
+					that.$set(that, 'bargainUserId', res.data);
+					that.getBargainUserBargainPrice();
+					that.setBargainHelp();
+					that.getBargainHelpCount();
+					that.userBargainStatus = 1;
+				}).catch(err=>{
+					that.$util.Tips({
+						title: err
+					});
+				})
+			},
+			setBargainHelp: function() {
+				//帮好友砍价
+				var that = this;
+				var data = {
+					bargainId: that.id,
+					bargainUserUid: that.bargainUid
+				};
+				postBargainHelp(data)
+					.then(res => {
+						if (res.data.code === 'subscribe') {
+							that.$set(that, 'followCode', true);
+							this.codeSrc = res.data.url
+							return;
+						}
+						that.$set(that, 'bargainUserHelpList', []);
+						that.$set(that, 'isHelp', true);
+						that.getBargainUser();
+						that.getBargainUserBargainPrice();
+						that.getBargainHelpCount();
+
+					})
+					.catch(err => {
+						that.$util.Tips({
+							title: err
+						});
+						that.$set(that, 'bargainUserHelpList', []);
+						that.getBargainUser();
+					});
+			},
+			getBargainUser: function() {
+				//获取砍价帮
+				var that = this;
+				var data = {
+					bargainId: that.id,
+					bargainUserUid: that.bargainUid,
+					offset: that.offset,
+					limit: that.limit
+				};
+				postBargainHelpList(data).then(res => {
+					var bargainUserHelpListNew = [];
+					var bargainUserHelpList = that.bargainUserHelpList;
+					var len = res.data.length;
+
+					bargainUserHelpListNew = bargainUserHelpList.concat(res.data);
+
+					that.$set(that, 'bargainUserHelpList', res.data);
+					that.$set(that, 'limitStatus', data.limit > len);
+					that.$set(that, 'offest', Number(data.offset) + Number(data.limit));
+				});
+			},
+			getBargainUserBargainPrice: function() {
+				//获取帮忙砍价砍掉多少金额
+				var that = this;
+				var data = {
+					bargainId: that.id,
+					bargainUserUid: that.bargainUid
+				};
+				postBargainHelpPrice(data)
+					.then(res => {
+						that.$set(that, 'bargainUserBargainPrice', res.data);
+						that.$set(that, 'active', true);
+					})
+					.catch(err => {
+						that.$set(that, 'active', false);
+					});
+			},
+			goBargainList: function() {
+				uni.navigateTo({
+					url: '/pages/activity/goods_bargain/index'
+				});
+			},
+			goIndex(){
+				uni.switchTab({
+					url: '/pages/index/index'
+				});
+			},
+			close: function() {
+				this.$set(this, 'active', false);
+			},
+			onLoadFun: function(e) {
+				let that = this;
+				if (that.bargainUid == 'undefined' || !that.bargainUid) {
+					that.bargainUid = that.$store.state.app.uid;
+				}
+				this.getBargainDetails();
+				this.addShareBargain();
+				this.isShowAuth = false;
+			},
+			addShareBargain: function() {
+				//添加分享次数 获取人数
+				var that = this;
+				postBargainShare(this.id).then(res => {
+					that.$set(that, 'bargainCount', res.data);
+				});
+			},
+			//#ifdef H5
+			setOpenShare() {
+				let that = this;
+				let configTimeline = {
+					title: '您的好友' + that.userInfo.nickname + '邀请您砍价' + that.bargainInfo.title,
+					desc: that.bargainInfo.info,
+					link: window.location.protocol + '//' + window.location.host +
+						'/pages/activity/goods_bargain_details/index?id=' +
+						that.id + '&spid=' + that.bargainUid,
+					imgUrl: that.bargainInfo.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);
+							}
+						});
+				}
+			},
+			closeFollowCode: function() {
+				this.$set(this, 'followCode', false);
+			},
+
+			//#endif
+			closeDrawer(){
+				this.showDrawer = false;
+			},
+			goRecord(){
+				uni.navigateTo({
+					url: '/pages/activity/bargain/index'
+				})
+			}
+		},
+
+		/**
+		 * 生命周期函数--监听页面初次渲染完成
+		 */
+		onReady: function() {
+			this.isNodes++;
+		},
+		/**
+		 * 生命周期函数--监听页面显示
+		 */
+		onShow(){
+			uni.removeStorageSync('form_type_cart');
+		},
+		/**
+		 * 生命周期函数--监听页面隐藏
+		 */
+		onHide: function() {
+			if (this.interval !== null) clearInterval(this.interval);
+		},
+
+		/**
+		 * 生命周期函数--监听页面卸载
+		 */
+		onUnload: function() {
+			if (this.interval !== null) clearInterval(this.interval);
+		},
+
+		//#ifdef MP
+		/**
+		 * 用户点击右上角分享
+		 */
+		onShareAppMessage: function() {
+			let that = this,
+				share = {
+					title: '您的好友' + that.userInfo.nickname + '邀请您帮他砍' + that.bargainInfo.title + ' 快去帮忙吧!',
+					path: '/pages/activity/goods_bargain_details/index?id=' + this.id + '&spid=' + this.bargainUid,
+					imageUrl: that.bargainInfo.image
+				};
+			that.close();
+			that.addShareBargain();
+			return share;
+		}
+		//#endif
+	};
+</script>
+
+<style lang="scss">
+	.bargainTitle{
+		position: fixed;
+		left:0;
+		top:0;
+		width: 100%;
+		z-index: 99;
+		.sysTitle{
+			width: 100%;
+			position: relative;
+			.iconfont{
+				position: absolute;
+				font-size: 36rpx;
+				left:11rpx;
+				width: 80rpx;
+				color:#fff;
+			}
+		}
+	}
+	.bargainCon{
+		// background-color: var(--view-theme);
+		padding-bottom: 50rpx;
+		min-height: 100vh;
+	}
+	.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;
+	}
+	.rule-btn{
+		height: 48rpx;
+		background: rgba(0,0,0,0.3);
+		border-radius: 24rpx 0 0 24rpx;
+		position: fixed;
+		right: 0;
+		z-index: 9;
+	}
+	
+
+	.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;
+	}
+
+	.bargain .bargainGang .open {
+		font-size: 24rpx;
+		color: #999;
+		margin-top: 30rpx;
+	}
+
+	.bargain .bargainGang .open .iconfont {
+		font-size: 25rpx;
+		margin: 5rpx 0 0 10rpx;
+	}
+
+	.bargain .header {
+		background-repeat: no-repeat;
+		background-size: 100% 100%;
+		width: 100%;
+		height: 1000rpx;
+		margin: 0 auto;
+		padding-top: 55rpx;
+		box-sizing: border-box;
+		
+		.iconfont{
+			color: #fff;
+			font-size: 40rpx;
+			margin-left: 34rpx;
+		}
+	}
+
+	.bargain .header .people {
+		text-align: center;
+		color: #fff;
+		font-size: 20rpx;
+		position: absolute;
+		width: 100%;
+		/* #ifdef MP || APP-PLUS */
+		height: 44px;
+		line-height: 44px;
+		top: 40rpx;
+		/* #endif */
+		/* #ifdef H5 */
+		top: 58rpx;
+		/* #endif */
+	}
+	
+	.bargain .wrapperCon{
+		width: 710rpx;
+		margin: -624rpx auto 0 auto;
+	} 
+
+	.bargain .wrapper,
+	.bargain .bargainGang,
+	.bargain .goodsDetails {
+		width: 100%;
+		background-color: #fff;
+		border-radius: 0 0 24rpx 24rpx;
+		padding: 17rpx 20rpx 0 20rpx;
+		padding-bottom: 50rpx;
+	}
+	
+	.bargain .bargainGang .tips{
+		font-size: 24rpx;
+		font-weight: 400;
+		color: #333333;
+		text-align: center;
+		margin-top: 30rpx;
+		.num{
+			color: #E93323;
+			font-weight: 500;
+			padding: 0 8rpx;
+		}
+	}
+	
+	.bargain .wrapperCon .timeCon{
+		background-repeat: no-repeat;
+		background-size: 100% 100%;
+		width: 100%;
+		height: 116rpx;
+		/deep/.time{
+			padding-top: 14px;
+			.styleAll{
+				background-color: #E93323;
+				color: #fff;
+				display: inline-block;
+				min-width: 34rpx;
+				height: 36rpx;
+				border-radius: 8rpx;
+				text-align: center;
+				line-height: 36rpx;
+				font-size: 28rpx;
+				font-family:'SemiBold';
+				padding: 0 2rpx;
+				.dayTxt{
+					font-size: 12px;
+				}
+			}
+			.title{
+				color: #333 !important;
+			}
+			.red{
+				color: #E93323;
+				padding: 0 6rpx;
+			}
+		}
+		.pictxt{
+			height: 96rpx;
+			.pictrue{
+				width: 60rpx;
+				height: 60rpx;
+				border-radius: 50%;
+				
+				image{
+					width: 100%;
+					height: 100%;
+					border-radius: 50%;
+				}
+			}
+			.text{
+				font-size: 28rpx;
+				color: #333;
+				font-weight: 400;
+				margin-left: 18rpx;
+				.name{
+					font-weight: 600;
+					color: #E93323;
+					margin-right: 10rpx;
+				}
+			}
+		}
+		.endTimes{
+			font-size: 28rpx;
+			color: #333;
+			font-weight: 400;
+			text-align: center;
+			height: 96rpx;
+			line-height: 96rpx;
+		}
+	}
+
+	.bargain .wrapper .pictxt {
+		// margin: 26rpx 0 37rpx 0;
+	}
+
+	.bargain .wrapper .pictxt .pictrue {
+		width: 240rpx;
+		height: 240rpx;
+		position: relative;
+	}
+
+	.bargain .wrapper .pictxt .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 16rpx;
+	}
+
+	.bargain .wrapper .pictxt .text {
+		width: 400rpx;
+		font-size: 28rpx;
+		color: #333;
+		.tips{
+			font-weight: 400;
+			color: #999999;
+			font-size: 22rpx;
+			margin-top: 12rpx;
+			.num{
+				color: #FE960F;
+				margin: 0 6rpx;
+			}
+		}
+		.top{
+			height: 188rpx;
+		}
+	}
+	
+	.bargain .wrapper .pictxt .text .name{
+		width: 100%;
+		height: 74rpx;
+		visibility: visible;
+	}
+	
+	.bargain .wrapper .pictxt .text .labelN{
+		font-size: 20rpx;
+		color: var(--view-theme);
+		font-weight: 500;
+		border:1px solid var(--view-theme);
+		border-radius: 6rpx;
+		padding: 2rpx 4rpx;
+		margin-right: 10rpx;
+		display: inline-block;
+		vertical-align: text-top;
+	}
+
+	.bargain .wrapper .pictxt .text .successNum {
+		font-size: 22rpx;
+		color: #999;
+	}
+
+	.bargain .wrapper .cu-progress {
+		// overflow: hidden;
+		height: 20rpx;
+		background-color: rgba(233, 51, 35, 0.08);
+		width: 100%;
+		border-radius: 20rpx;
+		margin-top: 60rpx;
+		&.on{
+			background-color:#F5F5F5;
+		}
+	}
+
+	.bargain .wrapper .cu-progress .bg-red {
+		width: 0;
+		height: 100%;
+		transition: width 0.6s ease;
+		border-radius: 20rpx;
+		background-color: #E93323;
+		position: relative;
+		.img{
+			width: 88rpx;
+			height: 88rpx;
+			position: absolute;
+			right: -30rpx;
+			top:50%;
+			margin-top: -38rpx;
+			&.on{
+				right: -62rpx;
+			}
+		}
+		.triangle{
+			width: 0;
+			height: 0;
+			border-left: 15rpx solid transparent;  
+			border-right: 15rpx solid transparent;  
+			border-bottom: 15rpx solid #E93323;
+			position: absolute;
+			right: 0;
+			top: 30rpx;
+		}
+		.hacked{
+			position: absolute;
+			height: 41rpx;
+			line-height: 43rpx;
+			padding: 0 6rpx;
+			background: #E93323;
+			color: #fff;
+			font-size: 22rpx;
+			right: -50rpx;
+			top:42rpx;
+			border-radius: 10rpx;
+			font-weight: 400;
+		}
+	}
+
+	.bargain .wrapper .money {
+		font-size: 22rpx;
+		color: #999;
+		margin-top: 16rpx;
+		.num{
+			font-weight: 400;
+			color: #E93323;
+			margin-left: 4rpx;
+		}
+	}
+
+	.bargain .wrapper .bargainSuccess {
+		font-size: 32rpx;
+		color: #333;
+		text-align: center;
+		margin-top: 52rpx;
+		&.on{
+			color: #E93323;
+		}
+	}
+
+	.bargain .wrapper .bargainSuccess .iconfont {
+		font-size: 34rpx;
+		color: #00b42a;
+		padding-right: 8rpx;
+		vertical-align: -3rpx;
+	}
+	
+	.bargain .wrapper .seeGood{
+		font-weight: 400;
+		color: #E93323;
+		font-size: 30rpx;
+		text-align: center;
+		margin-top: 32rpx;
+	}
+
+	.bargain .wrapper .bargainBnt {
+		font-size: 28rpx;
+		font-weight: 500;
+		color: #fff;
+		width: 670rpx;
+		height: 88rpx;
+		border-radius: 50rpx;
+		background: linear-gradient(90deg, #E93323 0%, #FF7931 100%);
+		text-align: center;
+		line-height: 88rpx;
+		margin-top: 42rpx;
+	}
+
+	.bargain .wrapper .bargainBnt.on {
+		color: #E93323;
+		background: linear-gradient(90deg, #FCEAE9 0%, #FCEAE9 100%);
+	}
+
+	.bargain .wrapper .bargainBnt.grey {
+		color: #fff;
+		background-image: linear-gradient(to right, #ccc 0%, #ccc 100%);
+	}
+
+	.bargain .wrapper .tip {
+		font-size: 22rpx;
+		color: #999;
+		text-align: center;
+		margin-top: 22rpx;
+		font-weight: 400;
+	}
+
+	.bargain .wrapper .tip .num {
+		color: #E93323;
+		margin: 0 8rpx;
+	}
+
+	.bargain .bargainGang,.bargain .goodsDetails {
+		margin: 20rpx auto 0 auto;
+		width: 710rpx;
+		padding: 0 0 34rpx 0;
+		border-radius: 22rpx;
+	}
+
+	.bargain .bargainGang .title,
+	.bargain .goodsDetails .title {
+		font-size: 32rpx;
+		font-weight: bold;
+		height: 80rpx;
+		background-repeat: no-repeat;
+		background-size: 100% 100%;
+		width: 100%;
+		height: 86rpx;
+		color: #E93323;
+		font-size: 36rpx;
+	}
+
+	.bargain .bargainGang .title .pictrue,
+	.bargain .goodsDetails .title .pictrue {
+		width: 60rpx;
+		height: 4rpx;
+		background: linear-gradient(270deg, #E93323 0%, rgba(255,255,255,0) 100%);
+	}
+
+	.bargain .bargainGang .title .pictrue.on,
+	.bargain .goodsDetails .title .pictrue.on {
+		transform: rotate(180deg);
+	}
+
+	.bargain .bargainGang .title .titleCon,
+	.bargain .goodsDetails .title .titleCon {
+		margin: 0 28rpx;
+	}
+	
+	.bargain .bargainGang .list{
+		margin-top: 10rpx;
+		padding: 0 20rpx;
+	}
+
+	.bargain .bargainGang .list .item {
+		height: 140rpx;
+	}
+
+	.bargain .bargainGang .list .item .pictxt {
+		width: 316rpx;
+	}
+
+	.bargain .bargainGang .list .item .pictxt .pictrue {
+		width: 80rpx;
+		height: 80rpx;
+	}
+
+	.bargain .bargainGang .list .item .pictxt .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 50%;
+	}
+
+	.bargain .bargainGang .list .item .pictxt .text {
+		width: 225rpx;
+		font-size: 22rpx;
+		color: #999;
+	}
+
+	.bargain .bargainGang .list .item .pictxt .text .name {
+		font-size: 30rpx;
+		color: #333;
+		margin-bottom: 4rpx;
+		font-weight: 400;
+	}
+
+	.bargain .bargainGang .list .item .money {
+		font-size: 22rpx;
+		color: #999;
+		
+		.label{
+			font-size: 28rpx;
+			color: #E93323;
+			font-weight: 600;
+			margin-left: 10rpx;
+		}
+		
+		.num{
+			font-size: 44rpx;
+			color: #E93323;
+			font-family: 'SemiBold';
+		}
+	}
+
+	.bargain .bargainGang .load {
+		font-size: 24rpx;
+		text-align: center;
+		line-height: 80rpx;
+		height: 80rpx;
+		color: var(--view-theme);
+	}
+
+	.bargain .goodsDetails .conter {
+		overflow: hidden;
+		word-break: break-all;
+	}
+
+	.bargain .goodsDetails .conter image {
+		width: 100% !important;
+		display: block !important;
+	}
+
+	.bargain .bargainTip {
+		position: fixed;
+		top: 50%;
+		left: 50%;
+		width: 480rpx;
+		margin-left: -240rpx;
+		z-index: 111;
+		border-radius: 48rpx;
+		background-color: #fff;
+		transition: all 0.3s ease-in-out 0s;
+		opacity: 0;
+		transform: scale(0);
+		padding-bottom: 60rpx;
+		margin-top: -330rpx;
+	}
+
+	.bargain .bargainTip.on {
+		opacity: 1;
+		transform: scale(1);
+	}
+
+	.bargain .bargainTip .pictrue {
+		width: 100%;
+		height: 266rpx;
+	}
+
+	.bargain .bargainTip .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 20rpx 20rpx 0 0;
+	}
+
+	.bargain .bargainTip .cutOff {
+		font-size: 24rpx;
+		color: #333;
+		padding: 0 29rpx;
+		text-align: center;
+		margin-top: 30rpx;
+		
+		.title{
+			font-weight: 500;
+			font-size: 32rpx;
+			margin-bottom: 12rpx;
+			.num{
+				color: #FF7D00;
+			}
+		}
+	}
+
+	.bargain .bargainTip .tipBnt {
+		font-size: 26rpx;
+		color: #fff;
+		width: 360rpx;
+		height: 72rpx;
+		border-radius: 36rpx;
+		background: linear-gradient(90deg, #E93323 0%, #FF7931 100%);
+		box-shadow: 0px 6px 16px 0px rgba(216,7,7,0.5);
+		text-align: center;
+		line-height: 72rpx;
+		margin: 40rpx auto 0 auto;
+		
+		.iconfont{
+			margin-right: 10rpx;
+		}
+		
+		&.grey{
+			background: linear-gradient(90deg, #ccc 0%, #ccc 100%);
+			box-shadow: unset;
+		}
+	}
+
+	.bargain_view {
+		width: 100%;
+		height: 48rpx;
+		background: rgba(0, 0, 0, 0.5);
+		opacity: 1;
+		border-radius: 0 0 6rpx 6rpx;
+		position: absolute;
+		bottom: 0;
+		font-size: 22rpx;
+		color: #fff;
+		text-align: center;
+		line-height: 48rpx;
+	}
+
+	.iconfonts {
+		font-size: 22rpx !important;
+	}
+
+	.wxParse-div {
+		width: auto !important;
+		height: auto !important;
+	}
+
+	.bargain .mask {
+		z-index: 100;
+	}
+
+	.share-box {
+		z-index: 1000;
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+
+		image {
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+	.followCode {
+		.pictrue {
+			width: 500rpx;
+			height: 530rpx;
+			border-radius: 12px;
+			left: 50%;
+			top: 50%;
+			margin-left: -250rpx;
+			margin-top: -360rpx;
+			position: fixed;
+			z-index: 10000;
+
+			.code-bg {
+				display: flex;
+				justify-content: center;
+				width: 100%;
+				height: 100%;
+				background-image: url('~@/static/images/code-bg.png');
+				background-size: 100% 100%;
+			}
+
+			.imgs {
+				width: 310rpx;
+				height: 310rpx;
+				margin-top: 92rpx;
+			}
+		}
+
+		.mask {
+			z-index: 9999;
+		}
+	}
+	
+	.close{
+		position: absolute;
+		right: 32rpx;
+		top: 36rpx;
+		width: 36rpx;
+		height: 36rpx;
+		border-radius: 50%;
+		background-color: #eee;
+	}
+	.scroll-content{
+		max-height: 800rpx;
+		overflow-y: auto;
+	}
+	.bg-red{
+		background-color: #E93323;
+	}
+</style>

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