cmy 1 year ago
commit
030f846eb5
100 changed files with 25763 additions and 0 deletions
  1. 3 0
      .gitignore
  2. 362 0
      App.vue
  3. 28 0
      androidPrivacy.json
  4. 308 0
      api/activity.js
  5. 187 0
      api/admin.js
  6. 453 0
      api/api.js
  7. 162 0
      api/kefu.js
  8. 43 0
      api/lottery.js
  9. 369 0
      api/order.js
  10. 18 0
      api/points_mall.js
  11. 204 0
      api/public.js
  12. 153 0
      api/rent.js
  13. 277 0
      api/store.js
  14. 691 0
      api/user.js
  15. 37 0
      api/wx.js
  16. 248 0
      components/Authorize.vue
  17. 57 0
      components/Loading/index.vue
  18. 186 0
      components/addressWindow/index.vue
  19. 209 0
      components/cartList/index.vue
  20. 128 0
      components/countDown/index.vue
  21. 286 0
      components/couponListWindow/index.vue
  22. 243 0
      components/couponWindow/index.vue
  23. 160 0
      components/cusPreviewImg/index.vue
  24. 189 0
      components/d_goodList/index.vue
  25. 227 0
      components/easy-loadimage/easy-loadimage.vue
  26. 314 0
      components/eidtUserModal/index.vue
  27. 42 0
      components/emptyPage.vue
  28. 230 0
      components/goodClass/index.vue
  29. 165 0
      components/goodList/index.vue
  30. 156 0
      components/guide/index.vue
  31. 131 0
      components/home/index.vue
  32. 196 0
      components/homeList/index.vue
  33. 188 0
      components/indexGoods/index.vue
  34. 814 0
      components/jyf-parser/jyf-parser.vue
  35. 102 0
      components/jyf-parser/libs/CssHandler.js
  36. 577 0
      components/jyf-parser/libs/MpHtmlParser.js
  37. 80 0
      components/jyf-parser/libs/config.js
  38. 35 0
      components/jyf-parser/libs/handler.sjs
  39. 44 0
      components/jyf-parser/libs/handler.wxs
  40. 476 0
      components/jyf-parser/libs/trees.vue
  41. 84 0
      components/kefuIcon/index.vue
  42. 300 0
      components/menuIcon.vue
  43. 352 0
      components/orderGoods/index.vue
  44. 228 0
      components/pageFooter/index.vue
  45. 33 0
      components/pageLoading.vue
  46. 103 0
      components/parabolaBall/ParabolaBall.vue
  47. 508 0
      components/payment/index.vue
  48. 191 0
      components/productConSwiper/index.vue
  49. 412 0
      components/productWindow/index.vue
  50. 120 0
      components/promotionGood/index.vue
  51. 135 0
      components/recommend/index.vue
  52. 147 0
      components/shareRedPackets/index.vue
  53. 190 0
      components/skeleton/index.vue
  54. 52 0
      components/swipers/index.vue
  55. 185 0
      components/tabNav.vue
  56. 324 0
      components/tuiDrawer/index.vue
  57. 427 0
      components/update/app-update.vue
  58. BIN
      components/update/images/close.png
  59. BIN
      components/update/images/img.png
  60. BIN
      components/update/images/round.png
  61. BIN
      components/update/images/update-img.png
  62. 147 0
      components/userEvaluation/index.vue
  63. 923 0
      components/zb-code/qrcode.js
  64. 210 0
      components/zb-code/zb-code.vue
  65. 33 0
      config/app.js
  66. 42 0
      config/cache.js
  67. 18 0
      config/socket.js
  68. 77 0
      libs/chat.js
  69. 142 0
      libs/login.js
  70. 99 0
      libs/new_chat.js
  71. 42 0
      libs/order.js
  72. 251 0
      libs/routine.js
  73. 352 0
      libs/uniApi.js
  74. 339 0
      libs/wechat.js
  75. 96 0
      main.js
  76. 266 0
      manifest.json
  77. 37 0
      mixins/SendVerifyCode.js
  78. 26 0
      mixins/color.js
  79. 274 0
      mixins/sharePoster.js
  80. 399 0
      package-lock.json
  81. 1722 0
      pages.json
  82. 260 0
      pages/activity/bargain/index.vue
  83. 80 0
      pages/activity/goods_bargain/index.vue
  84. 370 0
      pages/activity/goods_bargain_details/index.vue
  85. 383 0
      pages/activity/goods_combination/index.vue
  86. 1681 0
      pages/activity/goods_combination_details/index.vue
  87. 974 0
      pages/activity/goods_combination_status/index.vue
  88. 390 0
      pages/activity/goods_seckill/index.vue
  89. 1289 0
      pages/activity/goods_seckill_details/index.vue
  90. 430 0
      pages/activity/poster-poster/index.vue
  91. 108 0
      pages/activity/presell/index.vue
  92. 1734 0
      pages/activity/presell_details/index.vue
  93. BIN
      pages/activity/static/bargainBg.jpg
  94. BIN
      pages/activity/static/buled.png
  95. BIN
      pages/activity/static/bulet.jpg
  96. BIN
      pages/activity/static/couponBg.png
  97. BIN
      pages/activity/static/greend.png
  98. BIN
      pages/activity/static/greent.jpg
  99. BIN
      pages/activity/static/groupLine.png
  100. BIN
      pages/activity/static/lightning.png

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+.DS_Store
+unpackage/dist
+.hbuilderx

+ 362 - 0
App.vue

@@ -0,0 +1,362 @@
+<script>
+	import {
+		checkLogin
+	} from './libs/login';
+	import {
+		HTTP_REQUEST_URL
+	} from './config/app';
+	import {
+		getShopConfig,
+		silenceAuth
+	} from '@/api/public';
+	import Auth from '@/libs/wechat.js';
+	import Routine from './libs/routine.js';
+	import {
+		silenceBindingSpread
+	} from "@/utils";
+	import {
+		getCartCounts,
+	} from '@/api/order.js';
+	import {
+		colorChange,
+		getCrmebCopyRight,
+
+	} from '@/api/api.js';
+	import {
+		getLangJson
+	} from '@/api/user.js'
+	import {
+		mapGetters
+	} from "vuex"
+	import colors from '@/mixins/color.js';
+	import Cache from '@/utils/cache';
+	let green =
+		'--view-theme: rgba(66,202,77,1);--view-theme-16: #42CA4D;--view-priceColor:#FF7600;--view-minorColor:rgba(108, 198, 94, 0.5);--view-minorColorT:rgba(66, 202, 77, 0.1);--view-bntColor:#FE960F;--view-op-ten: rgba(66,202,77, 0.1);--view-main-start:#70E038; --view-main-over:#42CA4D;--view-op-point-four: rgba(66,202,77, 0.04);'
+	let red =
+		'--view-theme: rgba(32,33,53,1);--view-theme-16:rgba(22,22,39,1);--view-priceColor:#75EFFA;--view-minorColor:rgba(32,33,53,1);--view-minorColorT:rgba(32,33,53,0.1);--view-bntColor:#FE960F;--view-op-ten: rgba(233,51,35, 0.1);--view-main-start:rgba(22,22,39,1); --view-main-over:rgba(32,33,53,1);--view-op-point-four: rgba(233,51,35, 0.04);'
+	let blue =
+		'--view-theme: rgba(29,176,252,1);--view-theme-16:#1db0fc;--view-priceColor:#FD502F;--view-minorColor:rgba(58, 139, 236, 0.5);--view-minorColorT:rgba(9, 139, 243, 0.1);--view-bntColor:#22CAFD;--view-op-ten: rgba(29,176,252, 0.1);--view-main-start:#40D1F4; --view-main-over:#1DB0FC;--view-op-point-four: rgba(29,176,252, 0.04);'
+	let pink =
+		'--view-theme: rgba(255,68,143,1);--view-theme-16:#ff448f;--view-priceColor:#FF448F;--view-minorColor:rgba(255, 68, 143, 0.5);--view-minorColorT:rgba(255, 68, 143, 0.1);--view-bntColor:#282828;--view-op-ten: rgba(255,68,143, 0.1);--view-main-start:#FF67AD; --view-main-over:#FF448F;--view-op-point-four: rgba(255,68,143, 0.04);'
+	let orange =
+		'--view-theme: rgba(254,92,45,1); --view-theme-16:#FE5C2D;--view-priceColor:#FE5C2D;--view-minorColor:rgba(254, 92, 45, 0.5);--view-minorColorT:rgba(254, 92, 45, 0.1);--view-bntColor:#FDB000;--view-op-ten: rgba(254,92,45, 0.1);--view-main-start:#FF9445; --view-main-over:#FE5C2D;--view-op-point-four: rgba(254,92,45, 0.04);'
+
+	export default {
+		globalData: {
+			spid: 0,
+			code: 0,
+			isLogin: false,
+			userInfo: {},
+			MyMenus: [],
+			globalData: false,
+			isIframe: false,
+			tabbarShow: true,
+			windowHeight: 0,
+			locale: ''
+		},
+		mixins: [colors],
+		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: Number(uni.getStorageSync('FOOTER_ADDCART')) || 2,
+						text: newCart + ''
+					})
+				} else {
+					uni.hideTabBarRedDot({
+						index: Number(uni.getStorageSync('FOOTER_ADDCART')) || 2
+					})
+				}
+			}
+		},
+		onShow() {
+			const queryData = uni.getEnterOptionsSync() // uni-app版本 3.5.1+ 支持
+			if (queryData.query.spread) {
+				this.$Cache.set('spread', queryData.query.spread);
+				this.globalData.spid = queryData.query.spread;
+				this.globalData.pid = queryData.query.spread;
+				silenceBindingSpread(this.globalData)
+			}
+			if (queryData.query.spid) {
+				this.$Cache.set('spread', queryData.query.spid);
+				this.globalData.spid = queryData.query.spid;
+				this.globalData.pid = queryData.query.spid;
+				silenceBindingSpread(this.globalData)
+			}
+			// #ifdef MP
+			if (queryData.query.scene) {
+				switch (queryData.scene) {
+					//扫描小程序码
+					case 1047:
+						this.globalData.code = queryData.query.scene;
+						break;
+						//长按图片识别小程序码
+					case 1048:
+						this.globalData.code = queryData.query.scene;
+						break;
+						//手机相册选取小程序码
+					case 1049:
+						this.globalData.code = queryData.query.scene;
+						break;
+						//直接进入小程序
+					case 1001:
+						this.globalData.spid = queryData.query.scene;
+						break;
+				}
+				silenceBindingSpread(this.globalData)
+			}
+			// #endif
+		},
+		async onLaunch(option) {
+			uni.hideTabBar()
+			let that = this;
+			colorChange('color_change').then(res => {
+				uni.setStorageSync('is_diy', res.data.is_diy)
+				uni.$emit('is_diy', res.data.is_diy)
+				switch (res.data.status) {
+					case 1:
+						uni.setStorageSync('viewColor', blue)
+						uni.$emit('ok', blue, res.data.status)
+						break;
+					case 2:
+						uni.setStorageSync('viewColor', green)
+						uni.$emit('ok', green, res.data.status)
+						break;
+					case 3:
+						uni.setStorageSync('viewColor', red)
+						uni.$emit('ok', red, res.data.status)
+						break;
+					case 4:
+						uni.setStorageSync('viewColor', pink)
+						uni.$emit('ok', pink, res.data.status)
+						break;
+					case 5:
+						uni.setStorageSync('viewColor', orange)
+						uni.$emit('ok', orange, res.data.status)
+						break;
+					default:
+						uni.setStorageSync('viewColor', red)
+						uni.$emit('ok', red, res.data.status)
+						break
+				}
+			});
+			if (!Cache.has('localeSet')) {
+				getLangJson().then(res => {
+					Cache.set('locale', Object.keys(res.data)[0])
+					uni.setStorageSync('localeJson', res.data);
+					Cache.set('localeSet', true, 600) // 语言类型缓存时间
+				})
+			}
+
+			// #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;
+			}
+
+			const updateManager = wx.getUpdateManager();
+			const startParamObj = wx.getEnterOptionsSync();
+			if (wx.canIUse('getUpdateManager') && startParamObj.scene != 1154) {
+				const updateManager = wx.getUpdateManager()
+				updateManager.onCheckForUpdate(function(res) {
+					// 请求完新版本信息的回调
+					// console.log(res.hasUpdate)
+					if (res.hasUpdate) {
+						updateManager.onUpdateFailed(function() {
+							return that.Tips({
+								title: '新版本下载失败'
+							});
+						});
+						updateManager.onUpdateReady(function() {
+							wx.showModal({
+								title: '更新提示',
+								content: '新版本已经下载好,是否重启当前应用?',
+								success(res) {
+									if (res.confirm) {
+										updateManager.applyUpdate()
+									}
+								}
+							})
+						})
+						updateManager.onUpdateFailed(function() {
+							wx.showModal({
+								title: '发现新版本',
+								content: '请删除当前小程序,重启搜索打开...',
+							})
+						})
+					}
+				})
+			}
+			// #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.3') >= 0) {
+				that.$Cache.set('MP_VERSION_ISNEW', true)
+			} else {
+				that.$Cache.set('MP_VERSION_ISNEW', false)
+			}
+			// #endif
+
+			// #ifdef H5
+			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') && option.query.type == "iframeWindow") {
+				this.globalData.isIframe = true;
+			} else {
+				this.globalData.isIframe = false;
+			}
+			// #endif
+			// #ifdef MP
+			// 小程序静默授权
+			// if (!this.$store.getters.isLogin) {
+			// 	Routine.getCode()
+			// 		.then(code => {
+			// 			this.silenceAuth(code);
+			// 		})
+			// 		.catch(res => {
+			// 			uni.hideLoading();
+			// 		});
+			// }
+			// #endif
+			// #ifdef H5
+			// 添加crmeb chat 统计
+			var __s = document.createElement('script');
+			__s.src = `${HTTP_REQUEST_URL}/api/get_script`;
+			document.head.appendChild(__s);
+			// #endif
+			getCrmebCopyRight().then(res => {
+				uni.setStorageSync('copyRight', res.data)
+			})
+		},
+		// #ifdef H5
+		onHide() {
+			this.$Cache.clear('snsapiKey')
+		},
+		// #endif
+		methods: {
+			// 小程序静默授权
+			// silenceAuth(code) {
+			// 	let that = this;
+			// 	let spread = that.globalData.spid ? that.globalData.spid : '';
+			// 	silenceAuth({
+			// 			code: code,
+			// 			spread_spid: spread,
+			// 			spread_code: that.globalData.code
+			// 		})
+			// 		.then(res => {
+			// 			if (res.data.token !== undefined && res.data.token) {
+			// 				uni.hideLoading();
+			// 				let time = res.data.expires_time - this.$Cache.time();
+			// 				that.$store.commit('LOGIN', {
+			// 					token: res.data.token,
+			// 					time: time
+			// 				});
+			// 				that.$store.commit('SETUID', res.data.userInfo.uid);
+			// 				that.$store.commit('UPDATE_USERINFO', res.data.userInfo);
+			// 			}
+			// 		})
+			// 		.catch(res => {});
+			// },
+		},
+
+	};
+</script>
+
+<style>
+	@import url('@/plugin/emoji-awesome/css/tuoluojiang.css');
+	@import url('@/plugin/animate/animate.min.css');
+	@import 'static/css/base.css';
+	@import 'static/iconfont/iconfont.css';
+	@import 'static/css/guildford.css';
+	@import 'static/css/style.scss';
+
+	view {
+		box-sizing: border-box;
+	}
+
+	page {
+		font-family: PingFang SC;
+	}
+
+	.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;
+	}
+
+	.open-location {
+		width: 100%;
+		height: 100vh;
+	}
+</style>

+ 28 - 0
androidPrivacy.json

@@ -0,0 +1,28 @@
+{
+    "version" : "1",
+    "prompt" : "template",
+    "title" : "用户协议与隐私政策",
+    "message" : "\t请务必审慎阅读、充分理解“用户协议与 隐私政策”各条款,包括但不限于:为了 向你提供即时通讯、内容分享等服务,我 们需要收集你的设备信息、操作日志等个 人信息。你可以在“设置”中查看、变更、删除个人信息并管理你的授权。<br/>\r
+ 你可以阅读 <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"
+        }
+    }
+}

+ 308 - 0
api/activity.js

@@ -0,0 +1,308 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 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);
+}
+
+/**
+ * 拼团 开团
+ */
+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, uid) {
+	return request.get(`bargain/detail/${id}?bargainUid=${uid}`);
+}
+
+/**
+ * 砍价 开启砍价用户信息
+ */
+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);
+}
+
+/**
+ * 砍价海报
+ * @param object data
+ * 
+ */
+export function getBargainPoster(data) {
+	return request.post('bargain/poster', data)
+}
+
+/**
+ * 拼团海报
+ * @param object data
+ * 
+ */
+export function getCombinationPoster(data) {
+	return request.post('combination/poster', data)
+}
+
+/**
+ * 砍价取消
+ */
+export function getBargainUserCancel(data) {
+	return request.post("bargain/user/cancel", data);
+}
+
+/**
+ * 获取秒杀小程序二维码
+ */
+export function seckillCode(id, data) {
+	return request.get("seckill/code/" + id, data);
+}
+
+/**
+ * 获取拼团小程序二维码
+ */
+export function scombinationCode(id) {
+	return request.get("combination/code/" + id);
+}
+
+/**
+ * 获取砍价海报详细信息
+ */
+export function getCombinationPosterData(id) {
+	return request.get("combination/poster_info/" + id);
+}
+
+
+/**
+ * 获取砍价海报详细信息
+ */
+export function getBargainPosterData(id) {
+	return request.get("bargain/poster_info/" + id);
+}
+
+/**
+ * 获取积分订单详细信息
+ */
+export function integralOrderConfirm(data) {
+	return request.post('store_integral/order/confirm', data);
+}
+
+/**
+ * 获取积分订单创建
+ */
+export function integralOrderCreate(data) {
+	return request.post('store_integral/order/create', data);
+}
+/**
+ * 获取积分订单详情
+ * @param string cartId
+ */
+export function integralOrderDetails(order) {
+	return request.get(`store_integral/order/detail/${order}`);
+}
+
+/**
+ * 积分产品详情
+ * @param int id
+ * 
+ */
+export function getIntegralProductDetail(id) {
+	return request.get('store_integral/detail/' + id, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 积分商城商品列表
+ * @param object data
+ */
+export function getStoreIntegralList(data) {
+	return request.get('store_integral/list', data, );
+}
+
+/**
+ * 积分兑换列表
+ * @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 getPresellList(data) {
+	return request.get("advance/list", data);
+}

+ 187 - 0
api/admin.js

@@ -0,0 +1,187 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+import request from "@/utils/request.js";
+
+/**
+ * 统计数据
+ */
+export function getStatisticsInfo() {
+	return request.get("admin/order/statistics", {}, {
+		login: true
+	});
+}
+/**
+ * 订单月统计
+ */
+export function getStatisticsMonth(where) {
+	return request.get("admin/order/data", where, {
+		login: true
+	});
+}
+/**
+ * 订单月统计
+ */
+export function getAdminOrderList(where) {
+	return request.get("admin/order/list", where, {
+		login: true
+	});
+}
+/**
+ * 订单改价
+ */
+export function setAdminOrderPrice(data) {
+	return request.post("admin/order/price", data, {
+		login: true
+	});
+}
+/**
+ * 订单备注
+ */
+export function setAdminOrderRemark(data) {
+	return request.post("admin/order/remark", data, {
+		login: true
+	});
+}
+/**
+ * 订单详情
+ */
+export function getAdminOrderDetail(orderId) {
+	return request.get("admin/order/detail/" + orderId, {}, {
+		login: true
+	});
+}
+
+/**
+ * 退款订单详情
+ */
+export function getAdminRefundOrderDetail(orderId) {
+	return request.get("admin/refund_order/detail/" + orderId, {}, {
+		login: true
+	});
+}
+
+/**
+ * 订单发货信息获取
+ */
+export function getAdminOrderDelivery(orderId) {
+	return request.get(
+		"admin/order/delivery/gain/" + orderId, {}, {
+			login: true
+		}
+	);
+}
+
+/**
+ * 订单发货保存
+ */
+export function setAdminOrderDelivery(id, data) {
+	return request.post("admin/order/delivery/keep/" + id, data, {
+		login: true
+	});
+}
+/**
+ * 订单统计图
+ */
+export function getStatisticsTime(data) {
+	return request.get("admin/order/time", data, {
+		login: true
+	});
+}
+/**
+ * 线下付款订单确认付款
+ */
+export function setOfflinePay(data) {
+	return request.post("admin/order/offline", data, {
+		login: true
+	});
+}
+/**
+ * 订单确认退款
+ */
+export function setOrderRefund(data) {
+	return request.post("admin/order/refund", data, {
+		login: true
+	});
+}
+
+/**
+ * 获取快递公司
+ * @returns {*}
+ */
+export function getLogistics(data) {
+	return request.get("logistics", data, {
+		login: false
+	});
+}
+
+/**
+ * 订单核销
+ * @returns {*}
+ */
+export function orderVerific(verify_code, is_confirm) {
+	return request.post("order/order_verific", {
+		verify_code,
+		is_confirm
+	});
+}
+
+/**
+ * 获取物流公司模板
+ * @returns {*}
+ */
+export function orderExportTemp(data) {
+	return request.get("admin/order/export_temp", data);
+}
+
+/**
+ * 获取订单打印默认配置
+ * @returns {*}
+ */
+export function orderDeliveryInfo() {
+	return request.get("admin/order/delivery_info");
+}
+
+/**
+ * 配送员列表
+ * @returns {*}
+ */
+export function orderOrderDelivery() {
+	return request.get("admin/order/delivery");
+}
+
+/**
+ * 退款列表
+ * @returns {*}
+ */
+export function orderRefund_order(where) {
+	return request.get("admin/refund_order/list", where, {
+		login: true
+	});
+}
+
+/**
+ * 订单备注(退款)
+ */
+export function setAdminRefundRemark(data) {
+	return request.post("admin/refund_order/remark", data, {
+		login: true
+	});
+}
+
+/**
+ * 订单同意退货
+ */
+export function agreeExpress(data) {
+	return request.post("admin/order/agreeExpress", data, {
+		login: true
+	});
+}

+ 453 - 0
api/api.js

@@ -0,0 +1,453 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 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 object data
+ */
+export function getCouponsIndex(data) {
+	return request.get('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(phone, reset, key, captchaType, captchaVerification) {
+	return request.post('register/verify', {
+		phone: phone,
+		type: reset === undefined ? 'reset' : reset,
+		key: key,
+		captchaType: captchaType,
+		captchaVerification: captchaVerification
+	}, {
+		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 getTempIds() {
+	return request.get('wechat/temp_ids', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 首页拼团数据
+ */
+export function pink() {
+	return request.get('pink', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取城市信息
+ */
+export function getCity() {
+	return request.get('city_list', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取列表
+ */
+export function getLiveList(page, limit) {
+	return request.get('wechat/live', {
+		page,
+		limit
+	}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取首页DIY;
+ */
+export function getDiy(id) {
+	return request.get(`v2/diy/get_diy/default${id ? '?id='+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');
+}
+/**
+ * 获取网站基础配置
+ */
+export function siteConfig(data) {
+	return request.get('site_config', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * App微信登录
+ * @returns {*}
+ */
+export function wechatAppAuth(data) {
+	return request.post("wechat/app_auth", data, {
+		noAuth: true
+	});
+}
+/**
+ * 获取客服类型
+ * @returns {*}
+ */
+export function getCustomerType(data) {
+	return request.get("get_customer_type", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取开屏广告
+ * @returns {*}
+ */
+export function getOpenAdv(data) {
+	return request.get("get_open_adv", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取版权信息
+ */
+export function getCrmebCopyRight() {
+	return request.get('copyright', {}, {
+		noAuth: true
+	})
+}

+ 162 - 0
api/kefu.js

@@ -0,0 +1,162 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 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);
+}
+/**
+ * 获取客服端口
+ * @constructor
+ */
+export function getWorkermanUrl(data) {
+	return request.get('get_workerman_url', {}, {
+		noAuth: true
+	})
+}
+
+/**
+ * 客服扫码登录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~2023 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);
+}

+ 369 - 0
api/order.js

@@ -0,0 +1,369 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 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) {
+	return request.get("cart/count", {
+		numType: numType === undefined ? 0 : numType
+	});
+}
+/**
+ * 获取购物车列表
+ * 
+ */
+export function getCartList(data) {
+	return request.get("cart/list", 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) {
+	if (typeof ids === 'object')
+		ids = ids.join(',');
+	return request.post('cart/del', {
+		ids: ids
+	});
+}
+/**
+ * 订单列表
+ * @param object data
+ */
+export function getOrderList(data) {
+	return request.get('order/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);
+}
+
+/**
+ * 删除已退款和拒绝退款的订单
+ * @param string uni
+ * 
+ */
+export function refundOrderDel(uni) {
+	return request.get('order/refund/del/' + uni, {});
+}
+
+/**
+ * 订单统计数据
+ */
+export function orderData() {
+	return request.get('order/data')
+}
+
+/**
+ * 订单取消
+ * @param string id
+ * 
+ */
+export function orderCancel(id) {
+	return request.post('order/cancel', {
+		id: id
+	});
+}
+
+/**
+ * 删除已完成订单
+ * @param string uni
+ * 
+ */
+export function orderDel(uni) {
+	return request.post('order/del', {
+		uni: uni
+	});
+}
+
+/**
+ * 订单详情
+ * @param string uni 
+ */
+export function getOrderDetail(uni, cart_id) {
+	return request.get('order/detail/' + uni + `${cart_id ? `/${cart_id}`:''}`);
+}
+/**
+ * 退款订单详情
+ * @param string uni 
+ */
+export function getRefundOrderDetail(uni, cart_id) {
+	return request.get('order/refund_detail/' + uni + `${cart_id ? `/${cart_id}`:''}`);
+}
+
+/**
+ * 再次下单
+ * @param string uni
+ * 
+ */
+export function orderAgain(uni) {
+	return request.post('order/again', {
+		uni: uni
+	});
+}
+
+/**
+ * 订单收货
+ * @param string uni
+ * 
+ */
+export function orderTake(uni) {
+	return request.post('order/take', {
+		uni: uni
+	});
+}
+
+/**
+ * 订单查询物流信息
+ * @returns {*}
+ */
+export function express(uni, type) {
+	return request.get("order/express/" + uni + `${type?'/refund':''}`);
+}
+
+/**
+ * 获取退款理由
+ * 
+ */
+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, shipping_type) {
+	return request.post('order/confirm', {
+		cartId,
+		'new': news,
+		addressId,
+		shipping_type
+	});
+}
+
+/**
+ * 获取确认订单页面是否展示快递配送和到店自提
+ * @param string cartId
+ */
+export function checkShipping(cartId, news) {
+	return request.post('order/check_shipping', {
+		cartId,
+		'new': news
+	});
+}
+
+/**
+ * 获取当前金额能使用的优惠卷
+ * @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() {
+	return request.get("v2/cart_list");
+}
+
+/**
+ * 退款商品列表
+ */
+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);
+}
+
+/**
+ * 新订单列表 2.1版本
+ * @param object data
+ */
+export function getNewOrderList(data) {
+	return request.get('order/refund/list', data);
+}
+
+/**
+ * 退款订单详情
+ * @param string uni 
+ */
+export function refundOrderDetail(uni) {
+	return request.get('order/refund/detail/' + uni);
+}
+
+/**
+ * 放弃申请退款
+ * @param string uni 
+ */
+export function cancelRefundOrder(uni) {
+	return request.post('order/refund/cancel/' + uni);
+}

+ 18 - 0
api/points_mall.js

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

+ 204 - 0
api/public.js

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

+ 153 - 0
api/rent.js

@@ -0,0 +1,153 @@
+import request from "@/utils/request.js";
+
+/**
+ * 获取车辆列表
+ * @param data object 
+ */
+export function getCarList(data) {
+	return request.get(
+		"v3/rent", data
+	);
+}
+/**
+ * 获取车辆详情
+ * @param data object 
+ */
+export function getCarDetail(data) {
+	return request.get(
+		`v3/rent/${data.id}`
+	);
+}
+/**
+ * 创建订单
+ * @param data object 
+ */
+export function postCarCreate(data) {
+	return request.post(
+		`v3/rent/create`, data
+	);
+}
+/**
+ * 订单状态查询
+ * @param data object 
+ */
+export function getOrderStatus(id) {
+	return request.get(
+		`v3/rentinfo/detail/${id}`
+	);
+}
+/**
+ * 订单列表
+ * @param data object 
+ */
+export function getRentOrder(data) {
+	return request.get(
+		`v3/rent/order`, data
+	);
+}
+
+/**
+ * 订单统计数据
+ * @param data object 
+ */
+export function getRentOrderData(data) {
+	return request.get(
+		`v3/rent/order_data`, data
+	);
+}
+
+/**
+ * 订单详情
+ * @param data object 
+ */
+export function getRentOrderDteail(id) {
+	return request.get(
+		`v3/rent/order_detail/${id}`
+	);
+}
+/**
+ * 订单支付
+ * @param data object 
+ */
+export function postRentPay(data) {
+	return request.post(
+		`v3/rent/pay`, data
+	);
+}
+/**
+ * 绑定车辆
+ * @param data object 
+ */
+export function rentSetcar(data) {
+	return request.post(
+		`v3/rent/setcar`, data
+	);
+}
+
+/**
+ * 获取我的车辆
+ * @param data object 
+ * {
+ *	status:unlock开锁,lock关锁,deblock解锁,cushion开坐垫,find寻车
+ *}
+ */
+export function getMyCar(data) {
+	return request.get(
+		`v3/car/my`, data
+	);
+}
+
+/**
+ * 发送车辆指令
+ * @param data object 
+ */
+export function getLock(data) {
+	return request.get(
+		`v3/car/control/${data.type}`, data
+	);
+}
+
+
+
+/**
+ * 车辆控制记录
+ * @param data object 
+ * {
+	 type:auth授权record行程notice报警record_charge收费position当前车辆信息
+ }
+ * 
+ */
+export function getOneinfo(data) {
+	return request.get(
+		`v3/car/oneinfo/${data.type}`, data
+	);
+}
+/**
+ * 车辆行车记录
+ * @param data object 
+ */
+export function getRouterDetail(data) {
+	return request.get(
+		`v3/car/onedetail/${data.type}`, data
+	);
+}
+/**
+ * 车辆授权
+ * @param data object 
+ */
+export function postCarAuth(data) {
+	return request.post(
+		`v3/car/auth/0`, data
+	);
+}
+
+/**
+ * 撤销车辆授权
+ * @param data object 
+ */
+export function deleteCarAuth(data) {
+	return request.delete(
+		`v3/car/auth/${data.id}`, data
+	);
+}
+

+ 277 - 0
api/store.js

@@ -0,0 +1,277 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 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) {
+	return request.get('product/detail/' + 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,
+		'product': 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
+	});
+}
+
+/**
+ * 获取产品列表
+ * @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 int id
+ * @param object data
+ * 
+ */
+export function getReplyList(id, data) {
+	return request.get('reply/list/' + id, data)
+}
+
+/**
+ * 产品评价数量和好评度
+ * @param int id
+ */
+export function getReplyConfig(id) {
+	return request.get('reply/config/' + id);
+}
+
+/**
+ * 获取搜索关键字获取
+ * 
+ */
+export function getSearchKeyword() {
+	return request.get('search/keyword', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 门店列表
+ * @returns {*}
+ */
+export function storeListApi(data) {
+	return request.get("store_list", data);
+}
+
+/**
+ * 套餐列表
+ * @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);
+}
+/**
+ * 代理商申请
+ * 
+ */
+export function create(data) {
+	return request.post(`agent/apply/${data.id}`, data);
+}
+
+/**
+ * 代理商规则
+ * @param object data
+ */
+export function getAgentAgreement(data) {
+	return request.get('agent/get_agent_agreement', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户发送验证码
+ * @param data object 用户手机号
+ */
+export function registerVerify(data) {
+	return request.post("register/verify", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 验证码key
+ */
+export function getCodeApi() {
+	return request.get("verify_code", {}, {
+		noAuth: true
+	});
+}
+/**
+ * 获取代理商表单信息
+ */
+export function getGoodsDetails() {
+	return request.get("agent/apply/info", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取首页的属性
+ * @returns {*}
+ */
+export function getAttr(id, type) {
+	return request.get("v2/get_attr/" + id + "/" + type);
+}
+/**
+ * 获取首页商品列表(所有活动的)
+ * @param object data
+ */
+export function getHomeProducts(data) {
+	return request.get('home/products', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 预售详情
+ * @returns {*}
+ */
+export function getPresellProductDetail(id) {
+	return request.get("advance/detail/" + id);
+}
+
+/**
+ * 获取浏览记录列表
+ * @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)
+}

+ 691 - 0
api/user.js

@@ -0,0 +1,691 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 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 userShare() {
+	return request.post('user/share');
+}
+
+/**
+ * h5用户登录
+ * @param data object 用户账号密码
+ */
+export function loginH5(data) {
+	return request.post("login", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户手机号登录
+ * @param data object 用户手机号 也只能
+ */
+export function loginMobile(data) {
+	return request.post("login/mobile", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 验证码key
+ */
+export function getCodeApi() {
+	return request.get("verify_code", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户发送验证码
+ * @param data object 用户手机号
+ */
+export function registerVerify(data) {
+	return request.post("register/verify", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * h5用户手机号注册
+ * @param data object 用户手机号 验证码 密码
+ */
+export function register(data) {
+	return request.post("register", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户手机号修改密码
+ * @param data object 用户手机号 验证码 密码
+ */
+export function registerReset(data) {
+	return request.post("register/reset", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取用户中心菜单
+ *
+ */
+export function getMenuList() {
+	return request.get("menu/user", {}, {
+		noAuth: true
+	});
+}
+
+/*
+ * 签到用户信息
+ * */
+export function postSignUser(sign) {
+	return request.post("sign/user", sign);
+}
+
+/**
+ * 获取签到配置
+ * 
+ */
+export function getSignConfig() {
+	return request.get('sign/config')
+}
+
+/**
+ * 获取签到列表
+ * @param object data
+ */
+export function getSignList(data) {
+	return request.get('sign/list', data);
+}
+
+/**
+ * 用户签到
+ */
+export function setSignIntegral() {
+	return request.post('sign/integral')
+}
+
+/**
+ * 签到列表(年月)
+ * @param object data
+ * 
+ */
+export function getSignMonthList(data) {
+	return request.get('sign/month', data)
+}
+
+/**
+ * 活动状态
+ * 
+ */
+export function userActivity() {
+	return request.get('user/activity');
+}
+
+/*
+ * 资金明细(types|0=全部,1=消费,2=充值,3=返佣,4=提现)
+ * */
+export function getCommissionInfo(q, types) {
+	return request.get("spread/commission/" + types, q);
+}
+
+/*
+ * 积分记录
+ * */
+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);
+}
+
+/**
+ * 
+ * 事业部/推广订单
+ * @param object data
+ */
+export function divisionOrder(data) {
+	return request.post('division/order', data);
+}
+
+/*
+ * 获取推广人排行
+ * */
+export function getRankList(q) {
+	return request.get("rank", q);
+}
+
+/*
+ * 获取佣金排名
+ * */
+export function getBrokerageRank(q) {
+	return request.get("brokerage_rank", q);
+}
+
+/**
+ * 提现申请
+ * @param object data
+ */
+export function extractCash(data) {
+	return request.post('extract/cash', data)
+}
+
+/**
+ * 提现银行/提现最低金额
+ * 
+ */
+export function extractBank() {
+	return request.get('extract/bank');
+}
+
+/**
+ * 会员等级列表
+ * 
+ */
+export function userLevelGrade() {
+	return request.get('user/level/grade');
+}
+
+/**
+ * 获取某个等级任务
+ * @param int id 任务id
+ */
+export function userLevelTask(id) {
+	return request.get('user/level/task/' + id);
+}
+
+
+/**
+ * 检查用户是否可以成为会员
+ * 
+ */
+export function userLevelDetection() {
+	return request.get('user/level/detection');
+}
+
+/**
+ * 
+ * 地址列表
+ * @param object data
+ */
+export function getAddressList(data) {
+	return request.get('address/list', data);
+}
+
+/**
+ * 设置默认地址
+ * @param int id
+ */
+export function setAddressDefault(id) {
+	return request.post('address/default/set', {
+		id: id
+	})
+}
+
+/**
+ * 修改 添加地址
+ * @param object data
+ */
+export function editAddress(data) {
+	return request.post('address/edit', data);
+}
+
+/**
+ * 删除地址
+ * @param int id
+ * 
+ */
+export function delAddress(id) {
+	return request.post('address/del', {
+		id: id
+	})
+}
+
+/**
+ * 获取单个地址
+ * @param int id 
+ */
+export function getAddressDetail(id) {
+	return request.get('address/detail/' + id);
+}
+
+/**
+ * 修改用户信息
+ * @param object
+ */
+export function userEdit(data) {
+	return request.post('user/edit', data);
+}
+
+/*
+ * 退出登录
+ * */
+export function getLogout() {
+	return request.get("logout");
+}
+/**
+ * 小程序充值
+ * 
+ */
+export function rechargeRoutine(data) {
+	return request.post('recharge/routine', data)
+}
+/*
+ * 公众号充值
+ * */
+export function rechargeWechat(data) {
+	return request.post("recharge/wechat", data);
+}
+/**
+ * 获取默认地址
+ * 
+ */
+export function getAddressDefault() {
+	return request.get('address/default');
+}
+
+/**
+ * 充值金额选择
+ */
+export function getRechargeApi() {
+	return request.get("recharge/index");
+}
+
+/**
+ * 登陆记录
+ */
+export function setVisit(data) {
+	return request.post('user/set_visit', {
+		...data
+	}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 客服列表
+ */
+export function serviceList() {
+	return request.get("user/service/list");
+}
+/**
+ * 客服详情
+ */
+export function getChatRecord(data) {
+	return request.get("v2/user/service/record", data);
+}
+
+/**
+ * 静默绑定推广人
+ * @param {Object} puid
+ */
+export function spread(puid) {
+	return request.post("user/spread", puid);
+}
+
+/**
+ * 会员详情
+ */
+export function getlevelInfo() {
+	return request.get("user/level/info");
+}
+
+/**
+ * 会员经验列表
+ */
+export function getlevelExpList(data) {
+	return request.get("user/level/expList", data);
+}
+
+/**
+ * 修改用户信息
+ * @param {Object} data
+ */
+export function updateUserInfo(data) {
+	return request.post('v2/user/user_update', data);
+}
+
+/**
+ * 微信直接手机号登录
+ */
+export function phoneWxSilenceAuth(data) {
+	return request.post('v2/phone_wx_silence_auth', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 小程序直接手机号登录
+ */
+export function phoneSilenceAuth(data) {
+	return request.post('v2/phone_silence_auth', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户发票列表
+ * @param {Object} data
+ */
+export function invoiceList(data) {
+	return request.get('v2/invoice', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户添加|修改发票
+ * @param {Object} data
+ */
+export function invoiceSave(data) {
+	return request.post('v2/invoice/save', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 用户删除发票
+ * @param {Object} data
+ */
+export function invoiceDelete(id) {
+	return request.get('v2/invoice/del/' + id);
+}
+
+/**
+ * 获取用户默认发票
+ * @param {Object} type
+ */
+export function invoiceDefault(type) {
+	return request.get('v2/invoice/get_default/' + type);
+}
+
+/**
+ * 用户单个发票详情
+ * @param {Object} id
+ */
+export function invoiceDetail(id) {
+	return request.get('v2/invoice/detail/' + id);
+}
+
+/**
+ * 订单申请开票
+ * @param {Object} id
+ */
+export function invoiceOrder(data) {
+	return request.post('v2/order/make_up_invoice', data);
+}
+
+/**
+ * 订单详情中申请开票
+ * @param {Object} id
+ */
+export function makeUpinvoice(data) {
+	return request.post('v2/order/make_up_invoice', data);
+}
+
+/**
+ * 会员卡主界面
+ */
+export function memberCard() {
+	return request.get('user/member/card/index');
+}
+
+/**
+ * 卡密领取会员卡
+ * @param {Object} data
+ */
+export function memberCardDraw(data) {
+	return request.post('user/member/card/draw', data);
+}
+
+/**
+ * 购买会员卡
+ * @param {Object} data
+ */
+export function memberCardCreate(data) {
+	return request.post('user/member/card/create', data);
+}
+
+/**
+ * 会员优惠券
+ */
+export function memberCouponsList() {
+	return request.get('user/member/coupons/list');
+}
+
+/**
+ * svip推荐商品
+ * @param {Object} id
+ */
+export function groomList(id, data) {
+	return request.get(`groom/list/${id}`, data);
+}
+
+/**
+ * 付费会员结束
+ * @param {Object} data
+ */
+export function memberOverdueTime(data) {
+	return request.get('user/member/overdue/time', data);
+}
+
+/**
+ * 新版分享海报信息获取
+ * 
+ */
+export function spreadMsg() {
+	return request.get('user/spread_info');
+}
+
+
+/**
+ * 图片链接转base64
+ * 
+ */
+export function imgToBase(data) {
+	return request.post('image_base64', data);
+}
+
+/**
+ * 获取小程序二维码
+ * 
+ */
+export function routineCode(data) {
+	return request.get('user/routine_code', data);
+}
+
+/**
+ * 消息中心
+ */
+export function serviceRecord(data) {
+	return request.get('user/record', data);
+}
+
+/**
+ * 消息中心-站内信列表
+ */
+export function messageSystem(data) {
+	return request.get('user/message_system/list', data);
+}
+
+/**
+ * 消息中心-站内信列表详情
+ */
+export function getMsgDetails(id) {
+	return request.get('user/message_system/detail/' + id);
+}
+
+/**
+ * 消息中心-消息已读/删除
+ */
+export function msgLookDel(data) {
+	return request.get('user/message_system/edit_message', data);
+}
+
+/**
+ * 苹果账号登录
+ * @param {Object} data
+ */
+export function appleLogin(data) {
+	return request.post('apple_login', data, {
+		noAuth: true
+	});
+}
+
+/*
+ * 获取隐私协议
+ * */
+export function getUserAgreement(type) {
+	return request.get(`get_agreement/${type}`, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取分销等级列表
+ * @param int id 任务id
+ */
+export function agentLevelList() {
+	return request.get('v2/agent/level_list');
+}
+
+/**
+ * 获取分销任务列表
+ * @param int id 任务id
+ */
+export function agentLevelTaskList(id) {
+	return request.get('v2/agent/level_task_list?id=' + id);
+}
+
+/**
+ * 获取代付详情
+ * @param int id 任务id
+ */
+export function friendDetail(id) {
+	return request.get('order/friend_detail?order_id=' + id);
+}
+
+/**
+ * 员工列表
+ * @param object data
+ * 
+ */
+export function clerkPeople(data) {
+	return request.get('agent/get_staff_list', data)
+}
+
+/**
+ * 
+ * 员工比例
+ * @param object data
+ */
+export function setClerkPercent(data) {
+	return request.post('agent/set_staff_percent', data);
+}
+
+/**
+ * 
+ * 删除员工
+ * @param object data
+ */
+export function delClerkPercent(id) {
+	return request.get(`agent/del_staff/${id}`);
+}
+
+/**
+ * 注销用户
+ * @param int id
+ * 
+ */
+export function cancelUser() {
+	return request.get('user_cancel');
+}
+/**
+ * 获取多语言类型
+ */
+
+export function getLangList() {
+	return request.get('get_lang_type_list', {}, {
+		noAuth: true
+	})
+}
+
+/**
+ * 获取多语言JSON
+ */
+
+export function getLangJson() {
+	return request.get('get_lang_json', {}, {
+		noAuth: true
+	})
+}

+ 37 - 0
api/wx.js

@@ -0,0 +1,37 @@
+import request from '@/utils/request'
+// 微信分享信息
+export function share(data) {
+	return request({
+		url: '/api/share',
+		method: 'get',
+		data
+	});
+}
+// #ifdef H5
+//微信配置
+export function wechatConfig(data) {
+	return request({
+		url: '/api/wechat/config',
+		method: 'get',
+		data
+	});
+}
+// 微信code地址
+export function wechatAuth(data) {
+	return request({
+		url: '/api/wechat/auth',
+		method: 'get',
+		data
+	});
+}
+// #endif
+// #ifdef MP-WEIXIN
+// 微信code地址
+export function wechatMpAuth(data) {
+	return request({
+		url: '/api/wechat/mp_auth',
+		method: 'post',
+		data
+	});
+}
+// #endif

+ 248 - 0
components/Authorize.vue

@@ -0,0 +1,248 @@
+<template>
+	<view>
+		<view class="Popup" v-if="isShowAuth">
+			<image :src="logoUrl"></image>
+			<view class="title">授权提醒</view>
+			<view class="tip">请授权头像等信息,以便为您提供更好的服务</view>
+			<view class="bottom flex">
+				<view class="item" @click="close">随便逛逛</view>
+				<!-- #ifdef APP-PLUS -->
+				<button class="item grant" @click="setUserInfo">去授权</button>
+				<!-- #endif -->
+				<!-- #ifdef MP -->
+				<button class="item grant" type="primary" open-type="getPhoneNumber" lang="zh_CN" @getphonenumber="setUserInfo">去授权</button>
+				<!-- #endif -->
+			</view>
+		</view>
+		<view class="mask" v-if="isShowAuth" @click="close"></view>
+	</view>
+</template>
+
+<script>
+const app = getApp();
+import Cache from '../utils/cache';
+import { getLogo, silenceAuth, getUserPhone } from '../api/public';
+import { LOGO_URL, EXPIRES_TIME, USER_INFO, STATE_R_KEY } from '../config/cache';
+import { mapGetters } from 'vuex';
+import Routine from '../libs/routine';
+import store from '../store';
+
+export default {
+	name: 'Authorize',
+	props: {
+		isAuto: {
+			type: Boolean,
+			default: true
+		},
+		isGoIndex: {
+			type: Boolean,
+			default: true
+		},
+		isShowAuth: {
+			type: Boolean,
+			default: false
+		}
+	},
+	data() {
+		return {
+			logoUrl: '',
+			authKey: ''
+		};
+	},
+	computed: mapGetters(['isLogin', 'userInfo']),
+	watch: {
+		isLogin(n) {
+			n === true && this.$emit('onLoadFun', this.userInfo);
+		}
+	},
+	mounted() {
+		this.getLogoUrl();
+		let that = this;
+		if (!this.isLogin && !Cache.has(STATE_R_KEY)) {
+			wx.login({
+				success(res) {
+					Cache.set(STATE_R_KEY, res.code, 10800);
+					let spread = app.globalData.spid ? app.globalData.spid : '';
+					// silenceAuth({ code: res.code, spread: spread, spid: app.globalData.code })
+					// 	.then(res => {
+					// 		if (res.data.key !== undefined && res.data.key) {
+					// 			that.authKey = res.data.key;
+					// 		} else {
+					// 			app.globalData.code = 0;
+					// 			let time = res.data.expires_time - Cache.time();
+					// 			// store.commit('UPDATE_USERINFO', res.data.userInfo);
+					// 			store.commit('LOGIN', { token: res.data.token, time: time });
+					// 			// store.commit('SETUID', res.data.userInfo.uid);
+					// 			// Cache.set(EXPIRES_TIME,res.data.expires_time,time);
+					// 			// Cache.set(USER_INFO,res.data.userInfo,time);
+					// 		}
+					// 	})
+					// 	.catch(res => {
+					// 	});
+				}
+			});
+		} else {
+			this.setAuthStatus();
+		}
+	},
+	methods: {
+		setAuthStatus() {
+			Routine.authorize()
+				.then(res => {
+					if (res.islogin === false) this.setUserInfo();
+					else this.$emit('onLoadFun', this.userInfo);
+				})
+				.catch(res => {
+					if (this.isAuto) this.$emit('authColse', true);
+				});
+		},
+		getUserInfo(code) {
+			Routine.getUserInfo()
+				.then(res => {
+					let userInfo = res.userInfo;
+					userInfo.code = code;
+					userInfo.spread_spid = app.globalData.spid; //获取推广人ID
+					userInfo.spread_code = app.globalData.code; //获取推广人分享二维码ID
+					Routine.authUserInfo(userInfo)
+						.then(res => {
+							uni.hideLoading();
+							this.$emit('authColse', false);
+							this.$emit('onLoadFun', this.userInfo);
+						})
+						.catch(res => {
+							uni.hideLoading();
+							uni.showToast({
+								title: res.msg,
+								icon: 'none',
+								duration: 2000
+							});
+						});
+				})
+				.catch(res => {
+					uni.hideLoading();
+				});
+		},
+		getUserPhoneNumber(encryptedData, iv, code) {
+			getUserPhone({
+				encryptedData: encryptedData,
+				iv: iv,
+				code: code,
+				spid: app.globalData.spid,
+				spread: app.globalData.code
+			})
+				.then(res => {
+					let time = res.data.expires_time - this.$Cache.time();
+					this.$store.commit('LOGIN', {
+						token: res.data.token,
+						time: time
+					});
+					this.$emit('authColse', false);
+					this.$emit('onLoadFun', res.data.userInfo);
+					uni.hideLoading();
+				})
+				.catch(res => {
+					uni.hideLoading();
+				});
+		},
+		setUserInfo(e) {
+			uni.showLoading({ title: '正在登录中' });
+			Routine.getCode()
+				.then(code => {
+					this.getUserPhoneNumber(e.detail.encryptedData, e.detail.iv, code);
+				})
+				.catch(res => {
+					uni.hideLoading();
+				});
+		},
+		getLogoUrl() {
+			let that = this;
+			if (Cache.has(LOGO_URL)) {
+				this.logoUrl = Cache.get(LOGO_URL);
+				return;
+			}
+			getLogo().then(res => {
+				that.logoUrl = res.data.logo_url;
+				Cache.set(LOGO_URL, that.logoUrl);
+			});
+		},
+		close() {
+			let pages = getCurrentPages(),
+				currPage = pages[pages.length - 1];
+			if (this.isGoIndex) {
+				uni.navigateTo({ url: '/pages/index/index' });
+			} else {
+				this.$emit('authColse', false);
+			}
+			// if (currPage && currPage.isShowAuth != undefined){
+			// 	currPage.isShowAuth = true;
+			// }
+		}
+	}
+};
+</script>
+
+<style scoped lang="scss">
+.Popup {
+	width: 500rpx;
+	background-color: #fff;
+	position: fixed;
+	top: 50%;
+	left: 50%;
+	margin-left: -250rpx;
+	transform: translateY(-50%);
+	z-index: 320;
+}
+.Popup image {
+	width: 150rpx;
+	height: 150rpx;
+	margin: -67rpx auto 0 auto;
+	display: block;
+	border: 8rpx solid #fff;
+	border-radius: 50%;
+}
+.Popup .title {
+	font-size: 28rpx;
+	color: #000;
+	text-align: center;
+	margin-top: 30rpx;
+}
+.Popup .tip {
+	font-size: 22rpx;
+	color: #555;
+	padding: 0 24rpx;
+	margin-top: 25rpx;
+}
+.Popup .bottom .item {
+	width: 50%;
+	height: 80rpx;
+	background-color: #eeeeee;
+	text-align: center;
+	line-height: 80rpx;
+	font-size: 24rpx;
+	color: #666;
+	margin-top: 54rpx;
+}
+.Popup .bottom .item.on {
+	width: 100%;
+}
+.flex {
+	display: flex;
+}
+.Popup .bottom .item.grant {
+	font-size: 28rpx;
+	color: #fff;
+	font-weight: bold;
+	background-color: var(--view-theme);
+	border-radius: 0;
+	padding: 0;
+}
+.mask {
+	position: fixed;
+	top: 0;
+	right: 0;
+	left: 0;
+	bottom: 0;
+	background-color: rgba(0, 0, 0, 0.65);
+	z-index: 310;
+}
+</style>

+ 57 - 0
components/Loading/index.vue

@@ -0,0 +1,57 @@
+<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>
+				{{$t(`正在加载中`)}}
+			</view>
+			<view v-else>
+				{{$t(`上拉加载更多`)}}
+			</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: #000;
+	}
+	.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>

+ 186 - 0
components/addressWindow/index.vue

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

+ 209 - 0
components/cartList/index.vue

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

+ 128 - 0
components/countDown/index.vue

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

+ 286 - 0
components/couponListWindow/index.vue

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

+ 243 - 0
components/couponWindow/index.vue

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

+ 160 - 0
components/cusPreviewImg/index.vue

@@ -0,0 +1,160 @@
+<template>
+	<view class="previewImg" v-if="showBox" @touchmove.stop.prevent>
+		<view class="mask" @click="close">
+			<swiper @change="changeSwiper" class="mask-swiper" :current="currentIndex" :circular="circular"
+				:duration="duration">
+				<swiper-item v-for="(src, i) in list" :key="i" class="flex flex-column justify-center align-center">
+					<image class="mask-swiper-img" :src="src.image" mode="widthFix" />
+					<view class="mask_sku">
+						<text class="sku_name">{{src.suk}}</text>
+						<text class="sku_price">{{$t(`¥`)}}{{src.price}}</text>
+					</view>
+				</swiper-item>
+			</swiper>
+		</view>
+		<view class="pagebox" v-if="list.length>0">{{ Number(currentIndex) + 1 }} / {{ list.length }}</view>
+		<!-- #ifndef MP -->
+		<!-- <text class="iconfont icon-fenxiang share_btn" @click="shareFriend()"></text> -->
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'cusPreviewImg',
+		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) {}
+		},
+		methods: {
+			// 左右切换
+			changeSwiper(e) {
+				this.currentIndex = e.target.current;
+				this.$emit('changeSwitch', e.target.current)
+			},
+			open(current) {
+				if (!current || !this.list.length) return;
+				this.currentIndex = this.list.map((item) => item.suk).indexOf(current);
+				this.showBox = true;
+			},
+			close() {
+				this.showBox = false;
+			},
+			shareFriend() {
+				this.$emit('shareFriend')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@mixin full {
+		width: 100%;
+		height: 100%;
+	}
+
+	.previewImg {
+		position: fixed;
+		top: 0;
+		left: 0;
+		z-index: 300;
+		@include full;
+
+		.mask {
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			background-color: #000;
+			opacity: 1;
+			z-index: 8;
+			@include full;
+
+			&-swiper {
+				@include full;
+
+				&-img {
+					width: 100%;
+				}
+			}
+		}
+
+		.pagebox {
+			position: absolute;
+			width: 100%;
+			bottom: 20rpx;
+			z-index: 300;
+			color: #fff;
+			text-align: center;
+		}
+	}
+
+	.mask_sku {
+		color: #fff;
+		max-width: 80%;
+		z-index: 300;
+		text-align: center;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		margin-top: 30rpx;
+
+		.sku_name {
+			font-size: 12px;
+			border: 1px solid #fff;
+			padding: 10rpx 30rpx 10rpx;
+			border-radius: 40px;
+			box-sizing: border-box;
+		}
+
+		.sku_price {
+			padding-top: 10px;
+		}
+	}
+
+	.font12 {
+		font-size: 24rpx;
+	}
+
+	.share_btn {
+		position: absolute;
+		top: 70rpx;
+		right: 50rpx;
+		font-size: 40rpx;
+		color: #fff;
+		z-index: 300;
+	}
+
+	.flex-column {
+		flex-direction: column;
+	}
+
+	.justify-center {
+		justify-content: center;
+	}
+
+	.align-center {
+		align-items: center;
+	}
+</style>

+ 189 - 0
components/d_goodList/index.vue

@@ -0,0 +1,189 @@
+<template>
+	<view class="goodsList">
+		<view class="item" v-for="(item,index) in tempArr" :key='index' @click="goDetail(item)">
+			<view class="pictrue">
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '1'">{{$t(`秒杀`)}}</span>
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '2'">{{$t(`砍价`)}}</span>
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '3'">{{$t(`拼团`)}}</span>
+				<image :src="item.recommend_image" mode="" v-if="item.recommend_image"></image>
+				<image :src="item.image" mode="" v-else></image>
+			</view>
+			<view class="text line2">{{item.store_name}}</view>
+			<view class="bottom acea-row row-between-wrapper">
+				<view class="sales acea-row row-middle">
+					<view class="money font-color"><text>{{$t(`¥`)}}</text>{{item.price}}</view>
+					<view>{{$t(`已售`)}}{{item.sales}}</view>
+				</view>
+				<view v-if="item.stock>0">
+					<view class="bnt"
+						v-if="(item.activity && (item.activity.type === '1' || item.activity.type === '2' || item.activity.type === '3') || item.is_virtual) || !item.cart_button">
+						{{$t(`立即购买`)}}</view>
+					<view v-else>
+						<!-- 多规格 -->
+						<view class="bnt" @click.stop="goCartDuo(item)" v-if="item.spec_type">
+							{{$t(`加入购物车`)}}
+							<view class="num" v-if="isLogin && item.cart_num">{{item.cart_num}}</view>
+						</view>
+						<!-- 单规格 -->
+						<view class="bnt" v-if="!item.spec_type && !item.cart_num" @click.stop="goCartDan(item,index)">
+							{{$t(`加入购物车`)}}</view>
+						<view class="cart acea-row row-middle" v-if="!item.spec_type && item.cart_num">
+							<view class="pictrue iconfont icon-jianhao" @click.stop="CartNumDes(index,item)"></view>
+							<view class="num">{{item.cart_num}}</view>
+							<view class="pictrue iconfont icon-jiahao" @click.stop="CartNumAdd(index,item)"></view>
+						</view>
+					</view>
+				</view>
+				<view class="bnt end" v-else>{{$t(`已售罄`)}}</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 {
+				addIng: false
+			};
+		},
+		created() {},
+		mounted() {},
+		methods: {
+			goDetail(item) {
+				this.$emit('detail', item);
+			},
+			goCartDuo(item) {
+				this.$emit('gocartduo', item);
+			},
+			goCartDan(item, index) {
+				this.$emit('gocartdan', item, index);
+			},
+			CartNumDes(index, item) {
+				if (this.addIng) return
+				this.addIng = true
+				this.$emit('ChangeCartNumDan', false, index, item);
+			},
+			CartNumAdd(index, item) {
+				if (this.addIng) return
+				this.addIng = true
+				this.$emit('ChangeCartNumDan', true, index, item);
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	.goodsList {
+		padding: 0 30rpx;
+
+		.item {
+			width: 100%;
+			box-sizing: border-box;
+			margin-bottom: 63rpx;
+
+			.pictrue {
+				width: 100%;
+				height: 290rpx;
+				border-radius: 16rpx;
+				position: relative;
+
+				image {
+					width: 100%;
+					height: 100%;
+					border-radius: 10rpx;
+				}
+			}
+
+			.text {
+				font-size: 30rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #282828;
+				margin: 20rpx 0;
+			}
+
+			.bottom {
+				.sales {
+					font-size: 22rpx;
+					color: #8E8E8E;
+
+					.money {
+						font-size: 42rpx;
+						font-weight: bold;
+						margin-right: 18rpx;
+
+						text {
+							font-size: 28rpx;
+						}
+					}
+				}
+
+				.cart {
+					height: 56rpx;
+
+					.pictrue {
+						color: var(--view-theme);
+						font-size: 46rpx;
+						width: 50rpx;
+						height: 50rpx;
+						text-align: center;
+						line-height: 50rpx;
+					}
+
+					.num {
+						font-size: 30rpx;
+						color: #282828;
+						font-weight: bold;
+						width: 80rpx;
+						text-align: center;
+					}
+				}
+
+				.bnt {
+					padding: 0 30rpx;
+					height: 56rpx;
+					line-height: 56rpx;
+					background: var(--view-theme);
+					border-radius: 42rpx;
+					font-size: 26rpx;
+					color: #fff;
+					position: relative;
+
+					&.end {
+						background: rgba(203, 203, 203, 1);
+					}
+
+					.num {
+						background-color: var(--view-priceColor);
+						min-width: 12rpx;
+						color: #fff;
+						border-radius: 15px;
+						position: absolute;
+						right: -14rpx;
+						top: -15rpx;
+						font-size: 22rpx;
+						padding: 0 10rpx;
+						height: 34rpx;
+						line-height: 34rpx;
+					}
+				}
+			}
+		}
+	}
+</style>

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

@@ -0,0 +1,227 @@
+<template>
+	<view class="easy-loadimage" :id="uid">
+		<image class="origin-img" :src="imageSrc" mode="aspectFill" v-if="loadImg&&!isLoadError" v-show="showImg"
+			:class="{'no-transition':!openTransition,'show-transition':showTransition&&openTransition}"
+			@load="handleImgLoad" @error="handleImgError">
+		</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 '@/libs/uniApi';
+
+	// 生成全局唯一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: ""
+			},
+			mode: {
+				type: String,
+				default: ""
+			},
+			loadingMode: {
+				type: String,
+				default: 'looming-gray'
+			},
+			openTransition: {
+				type: Boolean,
+				default: true,
+			},
+			viewHeight: {
+				type: Number,
+				default () {
+					return uni.getSystemInfoSync().windowHeight;
+				}
+			}
+		},
+		data() {
+			const that = this;
+			return {
+				// uid:'',
+				uid: 'uid-' + generateUUID(),
+				loadImg: false,
+				showImg: false,
+				isLoadError: false,
+				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)
+			}
+		},
+		methods: {
+			init() {
+				this.$nextTick(this.onScroll)
+			},
+			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;
+	}
+
+	@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>

+ 314 - 0
components/eidtUserModal/index.vue

@@ -0,0 +1,314 @@
+<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.siteLogo" mode=""></image>
+				<text class="mp-name">{{mpData.siteName}} 申请</text>
+			</view>
+			<view class="trip-msg">
+				<view class="title">
+					{{$t(`获取您的昵称、头像`)}}
+				</view>
+				<view class="trip">
+					{{$t(`提供具有辨识度的用户中心界面`)}}
+				</view>
+			</view>
+			<form @submit="formSubmit">
+				<view class="edit">
+					<view class="avatar edit-box">
+						<view class="left">
+							<view class="head">{{$t(`头像`)}}</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">{{$t(`昵称`)}}</view>
+							<view class='input'><input type='nickname' placeholder-class="pl-sty"
+									:placeholder="$t(`请输入昵称`)" 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}">
+						{{$t(`保存`)}}
+					</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';
+	export default {
+		mixins: [colors],
+		props: {
+			isShow: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				defHead: require('@/static/images/def_avatar.png'),
+				mp_is_new: this.$Cache.get('MP_VERSION_ISNEW') || false,
+				userInfo: {
+					avatar: '',
+					nickname: '',
+				},
+				mpData: uni.getStorageSync('copyRight'),
+				canvasStatus: false,
+			};
+		},
+		mounted() {
+
+		},
+		methods: {
+			/**
+			 * 上传文件
+			 * 
+			 */
+			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) {
+				console.log(e, 'eeeeee')
+				let that = this
+				if (!this.userInfo.avatar) return that.$util.Tips({
+					title: that.$t(`请上传头像`)
+				});
+				if (!e.detail.value.nickname) return that.$util.Tips({
+					title: that.$t(`请输入昵称`)
+				});
+				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
+					});
+				}).catch(msg => {
+					return that.$util.Tips({
+						title: msg || that.$t(`保存失败`)
+					}, {
+						tab: 3,
+						url: 1
+					});
+				});
+			}
+		}
+	}
+</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: 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: 40rpx;
+			right: 40rpx;
+			font-size: 24rpx;
+			font-weight: bold;
+			color: #999;
+		}
+
+		.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: #07C160;
+				color: #fff;
+			}
+		}
+	}
+</style>

+ 42 - 0
components/emptyPage.vue

@@ -0,0 +1,42 @@
+<template>
+	<view class="empty-box">
+		<image :src="imgHost + '/statics/images/empty-box.png'"></image>
+		<view class="txt">{{title || $t(`暂无记录`)}}</view>
+	</view>
+</template>
+
+<script>
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default{
+		props: {
+			title: {
+				type: String,
+				default: '',
+			},
+		},
+		data(){
+			return{
+				imgHost:HTTP_REQUEST_URL
+			}
+		}
+	}
+	
+</script>
+
+<style lang="scss">
+	.empty-box{
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		margin-top: 200rpx;
+		image{
+			width: 414rpx;
+			height: 240rpx;
+		}
+		.txt{
+			font-size: 26rpx;
+			color: $uni-color-tip;
+		}
+	}
+</style>

+ 230 - 0
components/goodClass/index.vue

@@ -0,0 +1,230 @@
+<template>
+	<view class="goodsList">
+		<view class="item acea-row row-between-wrapper" v-for="(item,index) in tempArr" :key='index'
+			@click="goDetail(item)">
+			<view class="pictrue">
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '1'">{{$t(`秒杀`)}}</span>
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '2'">{{$t(`砍价`)}}</span>
+				<span class="pictrue_log pictrue_log_class" v-if="item.activity && item.activity.type === '3'">{{$t(`拼团`)}}</span>
+				<image :src="item.image" mode=""></image>
+			</view>
+			<view class="pictxt">
+				<view class="text line2">{{item.store_name}}</view>
+				<view class="bottom acea-row row-between-wrapper">
+					<view class="money font-color">
+						<text class="sign">{{$t(`¥`)}}</text>{{item.price}}
+						<!-- <span class="vip" v-if="item.vip_price">
+							<image src="../../static/images/vip01.png"></image>
+							¥{{item.vip_price}}
+						</span>
+						<text class="y_money" v-else>¥{{item.ot_price}}</text> -->
+					</view>
+					<view v-if="item.stock>0">
+						<view class="iconfont icon-gouwuche6 acea-row row-center-wrapper"
+							v-if="item.activity && (item.activity.type === '1' || item.activity.type === '2' || item.activity.type === '3')">
+						</view>
+						<view v-else>
+							<!-- 多规格 -->
+							<view class="bnt acea-row row-center-wrapper" @click.stop="goCartDuo(item)"
+								v-if="item.spec_type">
+								{{$t(`选规格`)}}
+								<text class="num" v-if="isLogin && item.cart_num">{{item.cart_num}}</text>
+							</view>
+							<!-- 单规格 -->
+							<view class="iconfont icon-gouwuche6 acea-row row-center-wrapper"
+								v-if="!item.spec_type && !item.cart_num" @click.stop="goCartDan(item,index)"></view>
+							<view class="cart acea-row row-middle" v-if="!item.spec_type && item.cart_num">
+								<view class="pictrue iconfont icon-jianhao acea-row row-center-wrapper"
+									@click.stop="CartNumDes(index,item)"></view>
+								<view class="num">{{item.cart_num}}</view>
+								<view class="pictrue iconfont icon-jiahao acea-row row-center-wrapper"
+									@click.stop="CartNumAdd(index,item)"></view>
+							</view>
+						</view>
+					</view>
+					<view class="bnt acea-row row-center-wrapper end" v-else>{{$t(`已售罄`)}}</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 {
+				addIng: false
+			};
+		},
+		created() {},
+		mounted() {},
+		methods: {
+			goDetail(item) {
+				this.$emit('detail', item);
+			},
+			goCartDuo(item) {
+				this.$emit('gocartduo', item);
+			},
+			goCartDan(item, index) {
+				this.$emit('gocartdan', item, index);
+			},
+			CartNumDes(index, item) {
+				if (this.addIng) return
+				this.addIng = true
+				this.$emit('ChangeCartNumDan', false, index, item);
+			},
+			CartNumAdd(index, item) {
+				if (this.addIng) return
+				this.addIng = true
+				this.$emit('ChangeCartNumDan', true, index, item);
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	.goodsList {
+		padding: 0 30rpx;
+
+		.item {
+			width: 100%;
+			box-sizing: border-box;
+			margin-bottom: 63rpx;
+
+			.pictrue {
+				width: 140rpx;
+				height: 140rpx;
+				border-radius: 10rpx;
+				position: relative;
+				border-radius: 22rpx;
+
+				image {
+					width: 100%;
+					height: 100%;
+					border-radius: 22rpx;
+				}
+			}
+
+			.pictxt {
+				width: 372rpx;
+
+				.text {
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #333333;
+				}
+
+				.bottom {
+					margin-top: 22rpx;
+
+					.money {
+						font-size: 34rpx;
+						font-weight: 800;
+
+						.sign {
+							font-size: 24rpx;
+						}
+
+						.y_money {
+							font-size: 20rpx;
+							color: #999999;
+							margin-left: 14rpx;
+							font-weight: normal;
+							text-decoration: line-through;
+						}
+
+						.vip {
+							font-size: 22rpx;
+							color: #333333;
+							font-weight: normal;
+							margin-left: 14rpx;
+
+							image {
+								width: 38rpx;
+								height: 18rpx;
+								margin-right: 6rpx;
+							}
+						}
+					}
+
+					.cart {
+						height: 46rpx;
+
+						.pictrue {
+							color: var(--view-theme);
+							font-size: 46rpx;
+							width: 46rpx;
+							height: 46rpx;
+							text-align: center;
+							line-height: 46rpx;
+
+							&.icon-jiahao {
+								color: var(--view-theme);
+							}
+						}
+
+						.num {
+							font-size: 30rpx;
+							color: #333333;
+							font-weight: bold;
+							width: 60rpx;
+							text-align: center;
+						}
+					}
+
+					.icon-gouwuche6 {
+						width: 46rpx;
+						height: 46rpx;
+						background-color: var(--view-theme);
+						border-radius: 50%;
+						color: #fff;
+						font-size: 30rpx;
+					}
+
+					.bnt {
+						padding: 0 20rpx;
+						height: 45rpx;
+						background: var(--view-theme);
+						border-radius: 23rpx;
+						font-size: 22rpx;
+						color: #fff;
+						position: relative;
+
+						&.end {
+							background: #cccccc;
+						}
+
+						.num {
+							min-width: 14rpx;
+							background-color: #fff;
+							color: var(--view-theme);
+							border-radius: 15px;
+							position: absolute;
+							right: -13rpx;
+							top: -11rpx;
+							font-size: 16rpx;
+							padding: 0 10rpx;
+							border: 1px solid var(--view-theme);
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 165 - 0
components/goodList/index.vue

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

+ 156 - 0
components/guide/index.vue

@@ -0,0 +1,156 @@
+<template>
+	<view class="content">
+		<swiper class="swiper" :autoplay="autoplay" indicator-dots="true" indicator-color="rgba(255,255,255,0.6)"
+			:duration="duration" v-if="advData.type == 'pic' && advData.value.length">
+			<swiper-item v-for="(item,index) in advData.value" :key="index" @click="jump(item.link)">
+				<view class="swiper-item">
+					<view class="swiper-item-img">
+						<image :src="item.img" mode="scaleToFill"></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" @click.stop="launchFlag()">{{$t(`跳过`)}}<text v-if="closeType == 1">{{times}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				autoplay: false,
+				duration: 500,
+				jumpover: this.$t(`跳过`),
+				experience: this.$t(`立即体验`),
+				timecount: undefined,
+				times: 0
+			}
+		},
+		props: {
+			advData: {
+				type: Object,
+				default: () => {}
+			},
+			// 1 倒计时 2 手动关闭(预留)
+			closeType: {
+				type: Number,
+				default: 1
+			},
+		},
+		mounted() {
+			this.timer()
+		},
+		onHide() {
+			clearInterval(this.timecount)
+		},
+		methods: {
+			timer() {
+				this.times = this.advData.time
+				let t = this.advData.time || 5
+				this.timecount = setInterval(() => {
+					t--
+					this.times = t
+					if (t <= 0) {
+						clearInterval(this.timecount)
+						this.launchFlag()
+					}
+				}, 1000)
+			},
+			launchFlag() {
+				clearInterval(this.timecount)
+				uni.switchTab({
+					url: '/pages/index/index'
+				});
+			},
+			jump(url) {
+				if (url) {
+					clearInterval(this.timecount)
+					if (url.indexOf("http") != -1) {
+						uni.navigateTo({
+							url: `/pages/annex/web_view/index?url=${url}`
+						});
+					} else {
+						uni.reLaunch({
+							url: url,
+							fail: () => {
+								uni.switchTab({
+									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: 100%;
+		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;
+	}
+
+	.jump-over {
+		right: 30rpx;
+		top: 80rpx;
+	}
+
+	.video-box {
+		width: 100vw;
+		height: 100vh;
+
+		.vid {
+			width: 100%;
+			height: 100%;
+		}
+	}
+</style>

+ 131 - 0
components/home/index.vue

@@ -0,0 +1,131 @@
+<template>
+	<view :style="colorStyle">
+		<view style="touch-action: none;">
+			<view class="home" style="position:fixed;" :style="{ top: top + 'px'}" id="right-nav"
+				@touchmove.stop.prevent="setTouchMove">
+				<view class="homeCon bg-color" :class="homeActive === true ? 'on' : ''" v-if="homeActive">
+					<navigator hover-class='none' open-type="switchTab" url='/pages/index/index'
+						class='iconfont icon-shouye-xianxing'>
+					</navigator>
+					<navigator hover-class='none' open-type="switchTab" url='/pages/order_addcart/order_addcart'
+						class='iconfont icon-caigou-xianxing'></navigator>
+					<navigator hover-class='none' open-type="switchTab" url='/pages/user/index'
+						class='iconfont icon-yonghu1'></navigator>
+				</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: 999;
+		right: 15rpx;
+		display: flex;
+	}
+
+	.home .homeCon {
+		border-radius: 50rpx;
+		opacity: 0;
+		height: 0;
+		color: var(--view-theme);
+		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;
+		opacity: 0.8;
+		backdrop-filter: blur(10px);
+	}
+
+	.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);
+	}
+
+	.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>

+ 196 - 0
components/homeList/index.vue

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

+ 188 - 0
components/indexGoods/index.vue

@@ -0,0 +1,188 @@
+<template>
+	<view>
+		<view class="list">
+			<view class="product-box">
+				<view class="product-list" v-for="(item, i1) in tmp_data" :key="i1" @click="goGoodsDetail(item)">
+					<view class="product-item">
+						<!-- <image :src="item.image" mode="scaleToFill" fade-show style="width: 100%;"></image> -->
+						<easy-loadimage mode="widthFix" :image-src="item.image"></easy-loadimage>
+						<view class="info">
+							<view class="title line2">
+								<text class="tag" v-if="item.activity && item.activity.type === '1'">{{$t(`秒杀`)}}</text>
+								<text class="tag" v-if="item.activity && item.activity.type === '2'">{{$t(`砍价`)}}</text>
+								<text class="tag" v-if="item.activity && item.activity.type === '3'">{{$t(`拼团`)}}</text>
+								<text class="tag" v-if="item.checkCoupon">{{$t(`券`)}}</text>
+								{{ item.store_name }}
+							</view>
+
+							<view class="price-box">
+								<view>
+									<text>{{$t(`¥`)}}</text>
+									{{ item.price }}
+								</view>
+								<view class="sales">
+									{{$t(`已售`)}} {{item.sales}}
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		goShopDetail,
+		goPage
+	} from '@/libs/order.js'
+	export default {
+		name: 'goodsWaterfall',
+		props: {
+			dataLists: {
+				default: []
+			}
+		},
+		data() {
+			return {
+				lists: [],
+				showLoad: false,
+				tmp_data: []
+			};
+		},
+		methods: {
+			goGoodsDetail(item) {
+				goPage().then(res => {
+					goShopDetail(item, this.uid).then(res => {
+						uni.navigateTo({
+							url: `/pages/goods_details/index?id=${item.id}`
+						})
+					})
+				})
+			},
+		},
+		mounted() {
+			const that = this
+			that.tmp_data = that.dataLists
+			// that.showLoadFlag()
+		},
+		watch: {
+			dataLists() {
+				this.loaded = []
+				this.loadErr = []
+				this.tmp_data = this.dataLists
+			},
+		},
+	};
+</script>
+
+<style lang="scss" scoped>
+	.list {
+		display: flex;
+		margin: 0 30rpx;
+	}
+
+	.product-box {
+		display: flex;
+		flex: 1;
+		flex-wrap: wrap;
+		width: 100%;
+	}
+
+	.flow_item {
+		margin: 15upx;
+		border-radius: 20upx;
+		background: #f4f4f4;
+		overflow: hidden;
+	}
+
+	.flow_item_con {
+		padding: 10upx 20upx 20upx;
+	}
+
+	.flow_item_title {
+		position: relative;
+		font-size: 32upx;
+		font-weight: 700;
+		margin-bottom: 5upx;
+	}
+
+	.flow_item_des {
+		font-size: 24upx;
+	}
+
+	.pl10 {
+		padding-left: 10rpx;
+	}
+
+	.product-list {
+		display: flex;
+		width: calc(50% - 16rpx);
+		margin: 2rpx 8rpx;
+
+		.product-item {
+			position: relative;
+			width: 100%;
+			background: #fff;
+			border-radius: 10rpx;
+			margin-bottom: 8rpx;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			
+			/deep/image,
+			/deep/.easy-loadimage,
+			/deep/uni-image {
+				width: 100%;
+				height: 330rpx;
+				border-radius: 10rpx 10rpx 0 0;
+			}
+
+			.info {
+				flex: 1;
+				padding: 14rpx 16rpx;
+				display: flex;
+				flex-direction: column;
+				justify-content: space-between;
+
+				.title {
+					font-size: 28rpx;
+					height: 76rpx;
+				}
+
+				.tag {
+					border-radius: 4rpx;
+					border: 1px solid var(--view-theme);
+					color: var(--view-theme);
+					font-size: 20rpx;
+					padding: 0rpx 4rpx;
+					margin: 10rpx 0;
+					margin-right: 10rpx;
+					width: max-content;
+				}
+
+				.price-box {
+					font-size: 34rpx;
+					font-weight: 700;
+					margin-top: 8px;
+					color: var(--view-priceColor);
+					display: flex;
+					justify-content: space-between;
+					// align-items: flex-end;
+					align-items: center;
+
+					text {
+						font-size: 28rpx;
+					}
+
+					.sales {
+						color: #999999;
+						font-size: 24rpx;
+						font-weight: 400;
+					}
+				}
+			}
+		}
+	}
+</style>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 84 - 0
components/kefuIcon/index.vue

@@ -0,0 +1,84 @@
+<template>
+	<!-- #ifdef APP-PLUS || H5 -->
+	<text class="acea-row row-center-wrapper cartf iconfont icon-kefu3" :style="{ top: top + 'px'}" @click="goCustomer"
+		@touchmove.stop.prevent="setTouchMove"></text>
+	<!-- #endif -->
+	<!-- #ifdef MP -->
+	<view v-if="routineContact == 0" class="acea-row row-center-wrapper cartf iconfont icon-kefu3"
+		:style="{ top: top + 'px'}" @touchmove.stop.prevent="setTouchMove" @click="goCustomer"></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>
+	import {
+		getCustomer
+	} from '@/utils/index.js'
+	let app = getApp();
+	export default {
+		name: "kefuIcon",
+		props: {
+			ids: {
+				type: Number,
+				default: 0
+			},
+			routineContact: {
+				type: Number,
+				default: 0
+			},
+			storeInfo: {
+				type: Object,
+				default: () => {}
+			},
+			goodsCon: {
+				type: Number,
+				default: 0
+			}
+		},
+		data: function() {
+			return {
+				top: "480"
+			};
+		},
+		mounted() {
+			// #ifdef H5
+			this.top = parseFloat(window.innerHeight) - 200
+			// #endif
+		},
+		methods: {
+			goCustomer() {
+				getCustomer(`/pages/extension/customer_list/chat?productId=${this.ids}`)
+			},
+			setTouchMove(e) {
+				let that = this;
+				if (e.touches[0].clientY < 480 && e.touches[0].clientY > 66) {
+					that.top = e.touches[0].clientY
+				}
+			}
+		},
+		created() {}
+	};
+</script>
+
+<style lang="scss">
+	.cartf {
+		width: 96rpx;
+		height: 96rpx;
+		background: rgba(255, 255, 255, 0.8);
+		box-shadow: 0 3rpx 16rpx rgba(0, 0, 0, 0.08);
+		backdrop-filter: blur(10px);
+		border-radius: 50%;
+		font-size: 47rpx;
+		color: #666;
+		position: fixed;
+		right: 15rpx;
+		z-index: 9;
+	}
+</style>

+ 300 - 0
components/menuIcon.vue

@@ -0,0 +1,300 @@
+<template>
+	<view>
+		<view id="home" class="home acea-row row-center-wrapper"
+			:class="[returnShow ? 'p10':'p20', text_opacity >= 1 ? 'opacity':'']" :style="{ marginTop: menuButton.top +'px', width: menuButton.width + 'px'}">
+			<view v-if="returnShow" class="iconfont icon-xiangzuo" :class="text_opacity >= 1 ? 'opacity':''"
+				@tap="returns">
+			</view>
+
+			<view class="line" v-if="returnShow"></view>
+			<view class="animation-box">
+				<transition name="fade">
+					<view v-if="!Active" class="iconfont icon-gengduo4" :class="text_opacity >= 1 ? 'opacity':''"
+						@click="open">
+					</view>
+					<!-- 	<view v-if="Active" class="iconfont icon-guanbi5" @click="open">
+					</view> -->
+				</transition>
+				<transition name="fade" mode="out-in">
+					<!-- 	<view v-if="!Active" class="iconfont icon-gengduo4" @click="open">
+					</view> -->
+					<view v-if="Active" class="iconfont icon-guanbi5" :class="text_opacity >= 1 ? 'opacity':''"
+						@click="open">
+					</view>
+				</transition>
+			</view>
+			<view class="homeCon bg-color" :class="Active === true ? 'active' : ''" v-if="Active" @click="open">
+				<view class="homeCon-box" v-for="(item,index) in iconList" :key="index"
+					@click="jumpUrl(item.path,item.jumpType)">
+					<text class='iconfont' :class="item.iconName">
+					</text>
+					<text class="text">{{item.name}}</text>
+				</view>
+
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "menuIcon",
+		data() {
+			return {
+				Active: false,
+				returnShow: true, //判断顶部返回是否出现
+				homeTop: 20,
+				text_opacity: 0,
+				menuButton:{},
+				iconList: [{
+						name: this.$t(`首页`),
+						iconName: "icon-shouye8",
+						path: '/pages/index/index',
+						jumpType: 1
+					},
+					{
+						name: this.$t(`购物车`),
+						iconName: "icon-gouwuche7",
+						path: '/pages/order_addcart/order_addcart',
+						jumpType: 1
+					},
+					{
+						name: this.$t(`搜索`),
+						iconName: "icon-sousuo6",
+						path: '/pages/goods/goods_search/index',
+						jumpType: 0
+					},
+					{
+						name: this.$t(`我的收藏`),
+						iconName: "icon-shoucang3",
+						path: '/pages/users/user_goods_collection/index',
+						jumpType: 0
+					},
+					{
+						name: this.$t(`个人中心`),
+						iconName: "icon-yonghu1",
+						path: '/pages/user/index',
+						jumpType: 1
+					}
+				]
+			};
+		},
+		props: {
+			showMenuIcon: {
+				type: Boolean,
+				default: false
+			},
+			opacity: {
+				type: Number,
+				default: 1
+			}
+		},
+		watch: {
+			showMenuIcon(e) {
+				this.Active = e
+			},
+			opacity(e) {
+				this.text_opacity = e
+			}
+		},
+		mounted() {
+			var pages = getCurrentPages();
+			this.returnShow = pages.length === 1 ? false : true;
+			this.$nextTick(() => {
+				// #ifdef MP
+				this.menuButton = uni.getMenuButtonBoundingClientRect();
+				const query = uni.createSelectorQuery().in(this);
+				query
+					.select('#home')
+					.boundingClientRect(data => {
+						this.homeTop = this.menuButton.top * 2 + this.menuButton.height - data.height + 2;
+					})
+					.exec();
+				// #endif
+			});
+		},
+		methods: {
+			open() {
+				this.Active = !this.Active
+				if (this.Active) this.$emit('open', true)
+			},
+			// 后退
+			returns() {
+				uni.navigateBack();
+			},
+			jumpUrl(url, type) {
+				(type === 1 ? uni.switchTab : uni.navigateTo)({url})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.home {
+		/* #ifdef H5 */
+		top: 20rpx !important;
+		/* #endif */
+	}
+
+	.home.opacity {
+		background: rgba(255, 255, 255, 1);
+		border: 1px solid #d7d7d7;
+	}
+
+	.home {
+		color: #333;
+		position: fixed;
+		// width: 130rpx;
+		// padding: 0 20rpx;
+		height: 62rpx;
+		z-index: 99;
+		left: 33rpx;
+		border: 1px solid #d7d7d7;
+		background: rgba(255, 255, 255, 0.8);
+		border-radius: 30rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		.opacity {
+			color: #000;
+		}
+
+		.icon-gengduo4,
+		.icon-guanbi5 {
+			position: absolute;
+			width: 40rpx;
+			font-weight: bold;
+		}
+			
+		.icon-xiangzuo{
+			font-weight: bold;
+			line-height: 28rpx;
+		}
+		.icon-gengduo4 {
+			font-size: 28rpx;
+			text-align: center;
+		}
+	}
+
+	.home .animation-box {
+		position: relative;
+		width: 40rpx;
+		height: 28rpx;
+	}
+
+	.icon-guanbi5 {
+		font-size: 28rpx;
+		text-align: center;
+	}
+
+	.home .homeCon {
+		display: flex;
+		flex-direction: column;
+		font-size: 26rpx;
+		padding: 4rpx;
+		opacity: 0;
+		border: 1px solid #f2f2f2;
+
+		&::before {
+			content: "";
+			width: 0;
+			height: 0;
+			border-left: 15rpx solid transparent;
+			border-right: 15rpx solid transparent;
+			border-bottom: 17rpx solid #fff;
+			position: absolute;
+			top: -15rpx;
+			right: 66rpx;
+			border-bottom-color: #f2f2f2;
+		}
+
+		&::after {
+			content: "";
+			width: 0;
+			height: 0;
+			border-left: 15rpx solid transparent;
+			border-right: 15rpx solid transparent;
+			border-bottom: 17rpx solid #fff;
+			position: absolute;
+			top: -13rpx;
+			right: 66rpx;
+		}
+
+		.homeCon-box {
+			display: flex;
+			align-items: center;
+			flex-wrap: nowrap;
+			width: 100%;
+			padding: 15rpx 20rpx;
+
+			.text {
+				display: flex;
+				flex-wrap: nowrap;
+			}
+		}
+
+		.iconfont {
+			display: flex;
+			align-items: center;
+			padding: 5rpx 3rpx;
+			margin-right: 5rpx;
+		}
+
+		.homeCon-box:nth-child(even) {
+			border-top: 1px solid #f2f2f2;
+			border-bottom: 1px solid #f2f2f2;
+		}
+	}
+
+	.home .homeCon.active {
+		position: absolute;
+		opacity: 1;
+		top: 75rpx;
+		animation: bounceInLeft 0.5s cubic-bezier(0.215, 0.310, 0.655, 1.000);
+		width: max-content;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		border-radius: 10rpx;
+		color: #333;
+		background: #fff !important;
+		box-shadow: $uni-index-box-shadow;
+	}
+
+	.home .line {
+		width: 2rpx;
+		height: 26rpx;
+		margin: 0 18rpx 0 16rpx;
+		background: rgba(255, 255, 255, 1);
+	}
+
+	.home .line.opacity {
+		color: #050505;
+		background-color: #050505;
+	}
+
+	.home .icon-xiangzuo {
+		font-size: 28rpx;
+	}
+
+	.fade-enter-active,
+	.fade-leave-active {
+		transition: opacity .3s;
+	}
+
+	.fade-enter,
+	.fade-leave-to
+
+	/* .fade-leave-active below version 2.1.8 */
+		{
+		opacity: 0;
+	}
+
+	.p10 {
+		padding: 0 25rpx;
+	}
+
+	.p20 {
+		padding: 0 40rpx;
+	}
+</style>

+ 352 - 0
components/orderGoods/index.vue

@@ -0,0 +1,352 @@
+<template>
+	<view class="orderGoods">
+		<view class='total' v-if="is_behalf"><text>
+				{{$t(`代付金额`)}}:
+				<text class="pay-price">¥{{pay_price || 0}}</text>
+			</text>
+		</view>
+		<view class='total' v-else-if="!split && !is_behalf">{{$t(`共`)}}{{totalNmu}}{{$t(`件商品`)}}</view>
+		<view class='total' v-else-if="split">
+			<text>{{$t(`订单包裹`)}} {{index + 1}}</text>
+			<view class="rig-btn" v-if="status_type === -1">
+				<view class="refund">{{$t(`申请退款中`)}}</view>
+			</view>
+			<view class="rig-btn" v-else-if="status_type === -2">
+				<view class="refund">{{$t(`已退款`)}}</view>
+			</view>
+			<view class="rig-btn" v-else-if="status_type === 4">
+				<view class="done">{{$t(`已完成`)}}</view>
+			</view>
+		</view>
+
+		<view class='goodWrapper'>
+			<view class='' :class="{op:!item.is_valid}" v-for="(item,index) in cartInfo" :key="index"
+				@click="jumpCon(item.product_id)">
+				<view class="item acea-row row-between-wrapper">
+					<view class='pictrue' :class="{gray:!item.is_valid}">
+						<image :src='item.productInfo.attrInfo.image' v-if="item.productInfo.attrInfo"></image>
+						<image :src='item.productInfo.image' v-else></image>
+					</view>
+					<view class='text'>
+						<view class='acea-row row-between-wrapper'>
+							<view class='name line1'>{{item.productInfo.store_name}}</view>
+							<view class='num'>x {{item.cart_num}}</view>
+						</view>
+						<view class='attr line1' v-if="item.productInfo.attrInfo">{{item.productInfo.attrInfo.suk}}
+						</view>
+						<view class='money font-color pic' v-if="item.productInfo.attrInfo">
+							<text :class="{gray:!item.is_valid}">
+								{{$t(`¥`)}}{{item.productInfo.attrInfo.price}}
+							</text>
+							<view class="refund" v-if="item.refund_num && statusType !=-2">{{item.refund_num}}{{$t(`件退款中`)}}
+							</view>
+							<text class="valid" v-if="!item.is_valid && shipping_type === 0">{{$t(`不支持配送`)}}</text>
+							<text class="valid" v-if="!item.productInfo.store_mention && shipping_type === 1">{{$t(`不支持自提`)}}</text>
+						</view>
+						<view class='money font-color pic' v-else>
+							<text :class="{gray:!item.is_valid}">{{$t(`¥`)}}{{item.productInfo.price}}</text>
+							<text class="valid" v-if="!item.is_valid && shipping_type === 0">{{$t(`仅支持到店`)}}</text>
+							<text class="valid" v-if="!item.productInfo.store_mention && shipping_type === 1">{{$t(`仅支持配送`)}}</text>
+						</view>
+						<view class='evaluate' v-else-if="item.is_reply==1">{{$t(`已评价`)}}</view>
+					</view>
+				</view>
+				<view class="botton-btn">
+					<view class='logistics' v-if="item.is_reply==0 && evaluate==3 && pid != -1 && isShow"
+						@click.stop="evaluateTap(item.unique,orderId)">
+						{{$t(`评价`)}}</view>
+					<view class='logistics'
+						v-if="paid === 1 && refund_status === 0 && item.refund_num !=item.cart_num && !is_confirm && isShow && virtualType == 0"
+						@click.stop="openSubcribe(item)">
+						{{$t(`申请退款`)}}</view>
+					<view class="rig-btn" v-if="status_type === 2 && index === cartInfo.length - 1 || !split">
+						<view v-if="delivery_type === 'express'" class="logistics" @click.stop="logistics(orderId)">{{$t(`查看物流`)}}
+						</view>
+						<view class="logistics sure" v-if="status_type === 2" @click.stop="confirmOrder(orderId)">{{$t(`确认收货`)}}
+						</view>
+					</view>
+				</view>
+			</view>
+
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			// 订单状态
+			statusType: {
+				type: Number,
+				default: 0,
+			},
+			virtualType: {
+				type: Number,
+				default: 0,
+			},
+			evaluate: {
+				type: Number,
+				default: 0,
+			},
+			oid: {
+				type: Number,
+				default: 0,
+			},
+			// 1已支付 0未支付
+			paid: {
+				type: Number,
+				default: 0,
+			},
+			cartInfo: {
+				type: Array,
+				default: function() {
+					return [];
+				}
+			},
+			orderId: {
+				type: String,
+				default: '',
+			},
+			shipping_type: {
+				type: Number,
+				default: -1,
+			},
+			delivery_type: {
+				type: String,
+				default: '',
+			},
+			pay_price: {
+				type: String,
+				default: '',
+			},
+			jump: {
+				type: Boolean,
+				default: false,
+			},
+			is_confirm: {
+				type: Boolean,
+				default: false,
+			},
+			// is_behalf 是否是代付列表
+			is_behalf: {
+				type: Boolean,
+				default: false,
+			},
+			split: {
+				type: Boolean,
+				default: false,
+			},
+			jumpDetail: {
+				type: Boolean,
+				default: false,
+			},
+			index: {
+				type: Number,
+				default: 0,
+			},
+			pid: {
+				type: Number,
+				default: 0,
+			},
+			refund_status: {
+				type: Number,
+				default: 0,
+			},
+			status_type: {
+				type: Number,
+				default: 0,
+			},
+			isShow: {
+				type: Boolean,
+				default: true,
+			},
+		},
+		data() {
+			return {
+				totalNmu: 0,
+				operationModel: false,
+				status: "",
+			};
+		},
+		watch: {
+			cartInfo: function(nVal, oVal) {
+				let num = 0
+				nVal.forEach((item, index) => {
+					num += item.cart_num
+				})
+				this.totalNmu = num
+			}
+		},
+		mounted() {
+			let num = 0
+			this.$nextTick(() => {
+				this.cartInfo.forEach((item, index) => {
+					num += item.cart_num
+				})
+				this.$set(this, 'totalNmu', num)
+			})
+
+		},
+		methods: {
+			evaluateTap: function(unique, orderId) {
+				uni.navigateTo({
+					url: "/pages/goods/goods_comment_con/index?unique=" + unique + "&uni=" + orderId
+				})
+			},
+			jumpCon(id) {
+				if (this.jump) {
+					uni.navigateTo({
+						url: `/pages/goods_details/index?id=${id}`
+					})
+				} else if (this.jumpDetail) {
+					uni.navigateTo({
+						url: `/pages/goods/order_details/index?order_id=${this.orderId}`
+					})
+				}
+			},
+			logistics(order_id) {
+				uni.navigateTo({
+					url: '/pages/goods/goods_logistics/index?orderId=' + order_id
+				})
+			},
+			confirmOrder(orderId) {
+				this.$emit('confirmOrder', orderId)
+			},
+			changeOperation() {
+				this.operationModel = !this.operationModel
+			},
+			openSubcribe(item) {
+				let cartList = [];
+				cartList.push({
+					cart_id: item.id,
+					cart_num: item.surplus_refund_num
+				})
+				let obj = JSON.stringify(cartList);
+				this.$emit('openSubcribe',
+					`/pages/goods/goods_return/index?orderId=${this.orderId}&id=${this.oid}&cartIds=${obj}`)
+			},
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.fontcolor {
+		color: #e93323;
+	}
+
+	.orderGoods {
+		background-color: #fff;
+	}
+
+	.orderGoods .total {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		width: 100%;
+		// height: 86rpx;
+		padding: 0 30rpx;
+		border-bottom: 2rpx solid #f0f0f0;
+		font-size: 30rpx;
+		color: #282828;
+		line-height: 86rpx;
+		box-sizing: border-box;
+
+
+	}
+
+	.botton-btn {
+		display: flex;
+		align-items: right;
+		justify-content: flex-end;
+		padding: 0rpx 20rpx 20rpx 20rpx;
+	}
+
+	.rig-btn {
+		display: flex;
+		align-items: center;
+
+		.refund {
+			font-size: 26rpx;
+			color: #e93323;
+		}
+
+		.done {
+			font-size: 26rpx;
+			color: #F19D2F;
+		}
+	}
+
+	.logistics {
+		// height: 46rpx;
+		line-height: 30rpx;
+		color: #666666;
+		font-size: 20rpx;
+		border: 1px solid #CCCCCC;
+		border-radius: 30rpx;
+		padding: 8rpx 22rpx;
+		margin-left: 10rpx;
+	}
+
+	.sure {
+		color: #e93323;
+		border: 1px solid #e93323;
+	}
+
+	.more-operation {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		padding: 10rpx 0;
+		color: #bbb;
+	}
+
+	.b-top {
+		margin-left: 30rpx;
+		margin-right: 30rpx;
+		border-top: 1px solid #f0f0f0
+	}
+
+	.fade-enter-active,
+	.fade-leave-active {
+		transition: all 0.1s;
+	}
+
+	.fade-enter,
+	.fade-leave-to
+
+	/* .fade-leave-active below version 2.1.8 */
+		{
+		opacity: 0;
+		transform: translateY(-10px);
+	}
+
+	.op {
+		opacity: 0.5;
+		
+	}
+	
+	.gray {
+		filter: grayscale(100%);
+		filter: gray;
+	}
+
+	.pic {
+		display: flex;
+		justify-content: space-between;
+	}
+
+	.valid {
+		margin-left: 20rpx;
+		font-size: 24rpx;
+	}
+
+	.pay-price {
+		color: #E93323;
+	}
+
+	.refund {
+		text-align: right;
+		font-size: 26rpx;
+		color: var(--view-theme);
+	}
+</style>

+ 228 - 0
components/pageFooter/index.vue

@@ -0,0 +1,228 @@
+<template>
+	<view v-if="newData">
+		<view class="page-footer" id="target">
+			<view class="foot-item" v-for="(item,index) in newData.menuList" :key="index" @click="goRouter(item)"
+				:style="{'background-color':newData.bgColor.color[0].item}">
+				<block v-if="item.link == activityTab">
+					<image :src="item.imgList[0]" class="active"></image>
+					<view class="txt" :style="{color:newData.activeTxtColor.color[0].item}">{{$t(item.name)}}</view>
+				</block>
+				<block v-else>
+					<image :src="item.imgList[1]"></image>
+					<view class="txt" :style="{color:newData.txtColor.color[0].item}">{{$t(item.name)}}</view>
+				</block>
+				<div class="count-num" v-if="item.link === '/pages/order_addcart/order_addcart' &&  cartNum>0">
+					{{cartNum > 99 ? '99+' : cartNum}}
+				</div>
+			</view>
+		</view>
+	</view>
+
+</template>
+
+<script>
+	import {
+		mapState,
+		mapGetters
+	} from "vuex"
+	import {
+		getNavigation
+	} from '@/api/public.js'
+	import {
+		getCartCounts,
+	} from '@/api/order.js';
+	export default {
+		name: 'pageFooter',
+		props: {
+			status: {
+				type: Number | String,
+				default: 1
+			},
+			countNum: {
+				type: Number | String,
+				default: 0
+			},
+		},
+		data() {
+			return {
+				newData: undefined,
+				footHeight: 0,
+				isShow: false // 弹出动画
+			}
+		},
+		computed: {
+			...mapState({
+				configData: state => state.app.pageFooter,
+			}),
+		},
+		computed: mapGetters(['isLogin', 'cartNum', 'activityTab']),
+		watch: {
+			activityTab: {
+				handler(nVal, oVal) {
+					console.log(nVal, 'nval')
+				},
+				deep: true
+			},
+			configData: {
+				handler(nVal, oVal) {
+					let self = this
+					const query = uni.createSelectorQuery().in(this);
+					this.newData = nVal
+					this.$nextTick(() => {
+						query.select('#target').boundingClientRect(data => {
+							uni.$emit('footHeight', data.height)
+							if (data) {
+								self.footHeight = data.height + 50
+							}
+						}).exec();
+					})
+				},
+				deep: true
+			},
+		},
+		created() {
+			let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
+			let curRoute = routes[routes.length - 1].route //获取当前页面路由
+			this.$store.commit('ACTIVITYTAB', '/' + curRoute);
+		},
+		mounted() {
+			getNavigation().then(res => {
+				uni.setStorageSync('pageFoot', res.data)
+				this.$store.commit('FOOT_UPLOAD', res.data)
+				this.newData = res.data
+			})
+			let that = this
+			uni.hideTabBar()
+			this.newData = this.$store.state.app.pageFooter
+			if (this.isLogin) {
+				this.getCartNum()
+			}
+		},
+
+		methods: {
+			goRouter(item) {
+				var pages = getCurrentPages();
+				var page = pages[pages.length - 1].route;
+				this.$store.commit('ACTIVITYTAB', item.link);
+				if (item.link == '/' + page) return
+				uni.switchTab({
+					url: item.link,
+					fail(err) {
+						uni.redirectTo({
+							url: item.link
+						})
+					}
+				})
+			},
+			getCartNum: function() {
+				let that = this;
+				getCartCounts().then(res => {
+					that.cartCount = res.data.count;
+					this.$store.commit('indexData/setCartNum', res.data.count > 99 ? '...' : res.data.count)
+				});
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.page-footer {
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		z-index: 999;
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		flex-wrap: nowrap;
+		width: 100%;
+		height: 98rpx;
+		height: calc(98rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		height: calc(98rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		box-sizing: border-box;
+		// border-top: solid 1rpx #F3F3F3;
+		backdrop-filter: blur(10px);
+		background-color: #fff;
+		box-shadow: 0px 0px 17rpx 1rpx rgba(206, 206, 206, 0.32);
+		padding-bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/
+		padding-bottom: env(safe-area-inset-bottom); ///兼容 IOS>11.2/
+		// transform: translate3d(0, 100%, 0);
+		// transition: all .3s cubic-bezier(.25, .5, .5, .9);
+
+		.foot-item {
+			display: flex;
+			width: max-content;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+			position: relative;
+			width: 100%;
+			height: 100%;
+
+
+			.count-num {
+				position: absolute;
+				display: flex;
+
+				justify-content: center;
+				align-items: center;
+				width: 40rpx;
+				height: 40rpx;
+				top: 0rpx;
+				right: calc(50% - 55rpx);
+				color: #fff;
+				font-size: 20rpx;
+				background-color: #FD502F;
+				border-radius: 50%;
+				padding: 4rpx;
+			}
+
+			.active {
+				animation: mymove 1s 1;
+			}
+
+			@keyframes mymove {
+				0% {
+					transform: scale(1);
+					/*开始为原始大小*/
+				}
+
+				10% {
+					transform: scale(0.8);
+				}
+
+				30% {
+					transform: scale(1.1);
+					/*放大1.1倍*/
+				}
+
+				50% {
+					transform: scale(0.9);
+					/*放大1.1倍*/
+				}
+
+				70% {
+					transform: scale(1.05);
+				}
+
+				90% {
+					transform: scale(1);
+				}
+			}
+		}
+
+		.foot-item image {
+			height: 50rpx;
+			width: 50rpx;
+			text-align: center;
+			margin: 0 auto;
+		}
+
+		.foot-item .txt {
+			font-size: 24rpx;
+
+
+
+		}
+	}
+</style>

+ 33 - 0
components/pageLoading.vue

@@ -0,0 +1,33 @@
+<template>
+	<view class="load" v-if="status">
+		{{$t(`正在加载中`)}}
+	</view>
+</template>
+
+<script>
+	export default{
+		data(){
+			return {
+				status:false
+			}
+		},
+		mounted() {
+			this.status = uni.getStorageSync('loadStatus')
+			uni.$once('loadClose',()=>{
+				this.status = false
+			})
+		}
+	}
+</script>
+
+<style lang="scss">
+.load{
+	z-index: 99999;
+	position: fixed;
+	left: 0;
+	top: 0;
+	width: 100%;
+	height: 100%;
+	background-color: #fff;
+}
+</style>

+ 103 - 0
components/parabolaBall/ParabolaBall.vue

@@ -0,0 +1,103 @@
+<template>
+	<view>
+		<view v-for="(item, index) in dots" :key="index" :style="{
+			position: 'fixed',
+			borderRadius: '50%',
+			left: item.left + 'px',
+			top: item.top + 'px',
+			display: item.show ? '' : 'none',
+			width: size + 'px',
+			height: size + 'px',
+			background: color,
+			zIndex: zIndex
+		}">
+			<image :src="item.src" mode="aspectFill" style="width: 100%;height: 100%;border-radius:inherit"
+				v-if="item.src"></image>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			size: { // 尺寸:单位px
+				type: Number,
+				default: 20
+			},
+			color: {
+				type: String,
+				default: '#f5222d'
+			},
+			zIndex: {
+				type: Number,
+				default: 999
+			},
+			duration: {
+				type: Number,
+				default: 500
+			}
+		},
+		data() {
+			return {
+				dots: [
+					/* { src: '', left: 0, top: 0, show: false } */
+				]
+			};
+		},
+		methods: {
+			showBall({
+				start,
+				end,
+				src
+			}) {
+				return new Promise(resolve => {
+					let ball = this.dots.find(v => !v.show)
+					if (!ball) {
+						ball = {
+							src: '',
+							left: 0,
+							top: 0,
+							show: false
+						}
+						this.dots.push(ball)
+					}
+					let t = this.duration,
+						starX = start.x - this.size / 2,
+						starY = start.y - this.size / 2,
+						endX = 50 - this.size / 2,
+						endY = 640 - this.size / 2,
+
+						starT = Date.now()
+					let Sx = endX - starX,
+						Sy = endY - starY,
+						Ax = -(2 * Sx / (t * t)) / 5, // 加速度
+						Ay = Math.abs(Ax),
+						Vox = Sx / t - (Ax * t) / 2, // 初速度
+						Voy = Sy / t - (Ay * t) / 2
+
+
+					const run = () => {
+						const To = Date.now() - starT
+						const x = starX + (Vox * To + Ax * To * To / 2),
+							y = starY + (Voy * To + Ay * To * To / 2)
+						ball.left = x
+						ball.top = y
+						if (To < t) {
+							setTimeout(run)
+						} else {
+							ball.show = false
+							resolve()
+						}
+					}
+					ball.src = src
+					ball.show = true
+					run()
+				})
+			}
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 508 - 0
components/payment/index.vue

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

+ 191 - 0
components/productConSwiper/index.vue

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

+ 412 - 0
components/productWindow/index.vue

@@ -0,0 +1,412 @@
+<template>
+	<view :style="colorStyle">
+		<view class="product-window"
+			:class="(attr.cartAttr === true ? 'on' : '') + ' ' + (iSbnt?'join':'') + ' ' + (iScart?'joinCart':'')">
+			<view class="textpic acea-row row-between-wrapper">
+				<view class="pictrue" @click="showImg()">
+					<image :src="attr.productSelect.image"></image>
+				</view>
+				<view class="text">
+					<view class="line1">
+						{{ attr.productSelect.store_name }}
+					</view>
+					<view class="money font-color">
+						<view class="acea-row row-middle">
+							{{$t(`¥`)}}<text class="num">{{ attr.productSelect.price }}</text>
+							<text class='vip-money'
+								v-if="is_vip>0 && attr.productSelect.vip_price">{{$t(`¥`)}}{{attr.productSelect.vip_price}}</text>
+							<view class="vipImg" v-if="is_vip>0 && attr.productSelect.vip_price">
+								<image src="../../static/images/svip.gif"></image>
+							</view>
+						</view>
+						<text class="stock" v-if='isShow && !type'>{{$t(`库存`)}}: {{ attr.productSelect.stock }}</text>
+						<text class='stock'
+							v-if="limitNum">{{type ? $t(`库存`) : $t(`限量`)}}:{{type ? attr.productSelect.quota : limitNum + unitName}}</text>
+					</view>
+				</view>
+				<view class="iconfont icon-guanbi" @click="closeAttr"></view>
+			</view>
+			<view class="rollTop">
+				<view class="productWinList">
+					<view class="item" v-for="(item, indexw) in attr.productAttr" :key="indexw">
+						<view class="title">{{ $t(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">
+								{{ $t(itemn.attr) }}
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="cart acea-row row-between-wrapper" v-if="!is_virtual">
+					<view class="title">{{$t(`数量`)}}</view>
+					<view class="carnum acea-row row-left">
+						<view class="item reduce acea-row row-center-wrapper"
+							:class="attr.productSelect.cart_num <= 1 ? 'on' : ''"
+							v-if="attr.productSelect.cart_num <= 1">
+							<text class="iconfont icon-shangpinshuliang-jian"></text>
+						</view>
+						<view class="item reduce acea-row row-center-wrapper"
+							:class="attr.productSelect.cart_num <= 1 ? 'on' : ''" @click="CartNumDes" v-else>
+							<text class="iconfont icon-shangpinshuliang-jian"></text>
+						</view>
+						<view class='item num acea-row row-middle'>
+							<input type="number" v-model="attr.productSelect.cart_num"
+								data-name="productSelect.cart_num"
+								@input="bindCode(attr.productSelect.cart_num)"></input>
+						</view>
+						<view v-if="iSplus" class="item plus acea-row row-center-wrapper" :class="
+				      attr.productSelect.cart_num >= attr.productSelect.stock || (limitNum && attr.productSelect.cart_num >= limitNum)
+				        ? 'on'
+				        : ''
+				    " @click="CartNumAdd">
+							<text class="iconfont icon-shangpinshuliang-jia"></text>
+						</view>
+						<view v-else class='item plus'
+							:class='(attr.productSelect.cart_num >= attr.productSelect.quota) || (attr.productSelect.cart_num >= attr.productSelect.product_stock) || (attr.productSelect.cart_num >= attr.productSelect.num) || (type=="seckill" && attr.productSelect.cart_num >= attr.productSelect.once_num) ? "on":""'
+							@click='CartNumAdd'>+</view>
+					</view>
+				</view>
+			</view>
+			<view class="joinBnt bg-color"
+				v-if="iSbnt && attr.productSelect.product_stock>0 &&attr.productSelect.quota>0" @click="goCat">
+				{{$t(`我要参团`)}}
+			</view>
+			<view class="joinBnt on"
+				v-else-if="(iSbnt && attr.productSelect.quota<=0)||(iSbnt &&attr.productSelect.product_stock<=0)">
+				{{$t(`已售罄`)}}
+			</view>
+			<view class="joinBnt bg-color" v-if="iScart && attr.productSelect.stock" @click="goCat">{{$t(`确定`)}}</view>
+			<view class="joinBnt on" v-else-if="iScart && !attr.productSelect.stock">{{$t(`已售罄`)}}</view>
+		</view>
+		<view class="mask" @touchmove.prevent :hidden="attr.cartAttr === false" @click="closeAttr"></view>
+	</view>
+</template>
+
+<script>
+	import colors from "@/mixins/color";
+	export default {
+		mixins: [colors],
+		props: {
+			attr: {
+				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
+			},
+			is_virtual: {
+				type: Number,
+				value: 0
+			},
+			type: {
+				type: String,
+				default: ''
+			},
+			unitName: {
+				type: String,
+				default: ''
+			},
+		},
+		data() {
+			return {};
+		},
+		mounted() {
+
+		},
+		methods: {
+			getpreviewImage: function() {
+				uni.previewImage({
+					urls: this.attr.productSelect.image.split(','),
+					current: this.attr.productSelect.image
+				});
+			},
+			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);
+				if (this.limitNum == 1) {
+					if (this.attr.productSelect.quota > 0) {
+						this.attr.productSelect.cart_num = 1
+					} else {
+						this.attr.productSelect.cart_num = 0
+					}
+				}
+
+			},
+			//获取被选中属性;
+			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');
+			},
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.vip-money {
+		color: #282828;
+		font-size: 28rpx;
+		font-weight: 700;
+		margin-left: 6rpx;
+	}
+
+	.vipImg {
+		width: 68rpx;
+		height: 27rpx;
+
+		image {
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+	.product-window {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		background-color: #fff;
+		z-index: 100;
+		border-radius: 16rpx 16rpx 0 0;
+		transform: translate3d(0, 100%, 0);
+		transition: all .3s cubic-bezier(.25, .5, .5, .9);
+		padding-bottom: 140rpx;
+		padding-bottom: calc(140rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		padding-bottom: calc(140rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+	}
+
+	.product-window.on {
+		transform: translate3d(0, 0, 0);
+	}
+
+	.product-window.join {
+		padding-bottom: 30rpx;
+	}
+
+	.product-window.joinCart {
+		padding-bottom: 30rpx;
+		z-index: 10000;
+	}
+
+	.product-window .textpic {
+		padding: 0 130rpx 0 30rpx;
+		margin-top: 29rpx;
+		position: relative;
+	}
+
+	.product-window .textpic .pictrue {
+		width: 150rpx;
+		height: 150rpx;
+	}
+
+	.product-window .textpic .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 10rpx;
+	}
+
+	.product-window .textpic .text {
+		width: 410rpx;
+		font-size: 32rpx;
+		color: #202020;
+	}
+
+	.product-window .textpic .text .money {
+		font-size: 24rpx;
+		margin-top: 40rpx;
+	}
+
+	.product-window .textpic .text .money .num {
+		font-size: 36rpx;
+	}
+
+	.product-window .textpic .text .money .stock {
+		color: #999;
+		margin-left: 6rpx;
+		margin-right: 20rpx;
+	}
+
+	.product-window .textpic .iconfont {
+		position: absolute;
+		right: 30rpx;
+		top: -5rpx;
+		font-size: 35rpx;
+		color: #8a8a8a;
+	}
+
+	.product-window .rollTop {
+		max-height: 500rpx;
+		overflow: auto;
+		margin-top: 36rpx;
+	}
+
+	.product-window .productWinList .item~.item {
+		margin-top: 36rpx;
+	}
+
+	.product-window .productWinList .item .title {
+		font-size: 30rpx;
+		color: #999;
+		padding: 0 30rpx;
+	}
+
+	.product-window .productWinList .item .listn {
+		padding: 0 30rpx 0 16rpx;
+	}
+
+	.product-window .productWinList .item .listn .itemn {
+		border: 1px solid #F2F2F2;
+		font-size: 26rpx;
+		color: #282828;
+		padding: 7rpx 33rpx;
+		border-radius: 25rpx;
+		margin: 20rpx 0 0 14rpx;
+		background-color: #F2F2F2;
+	}
+
+	.product-window .productWinList .item .listn .itemn.on {
+		color: var(--view-theme);
+		background: var(--view-minorColorT);
+		border-color: var(--view-theme);
+	}
+
+	.product-window .productWinList .item .listn .itemn.limit {
+		color: #999;
+		text-decoration: line-through;
+	}
+
+	.product-window .cart {
+		margin-top: 36rpx;
+		padding: 0 30rpx;
+	}
+
+	.product-window .cart .title {
+		font-size: 30rpx;
+		color: #999;
+	}
+
+	.product-window .cart .carnum {
+		height: 54rpx;
+		margin-top: 24rpx;
+	}
+
+	.product-window .cart .carnum .iconfont {
+		font-size: 25rpx;
+	}
+
+	.product-window .cart .carnum view {
+		// border: 1px solid #a4a4a4;
+		width: 84rpx;
+		text-align: center;
+		height: 100%;
+		line-height: 54rpx;
+		color: #282828;
+		font-size: 45rpx;
+	}
+
+	.product-window .cart .carnum .reduce {
+		border-right: 0;
+		border-radius: 6rpx 0 0 6rpx;
+		line-height: 48rpx;
+		font-size: 60rpx;
+	}
+
+	.product-window .cart .carnum .reduce.on {
+		// 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;
+	}
+
+	.product-window .joinBnt {
+		font-size: 30rpx;
+		width: 620rpx;
+		height: 86rpx;
+		border-radius: 50rpx;
+		text-align: center;
+		line-height: 86rpx;
+		color: #fff;
+		margin: 21rpx auto 0 auto;
+	}
+
+	.product-window .joinBnt.on {
+		background-color: #bbb;
+		color: #fff;
+	}
+</style>

+ 120 - 0
components/promotionGood/index.vue

@@ -0,0 +1,120 @@
+<template>
+	<view class='promotionGood' :style="colorStyle">
+		<block v-for="(item,index) in benefit" :key="index">
+			<view class='item' @tap="goDetail(item)" hover-class="none">
+				<view class='pictrue'>
+					<easy-loadimage mode="widthFix" :image-src="item.image"></easy-loadimage>
+				</view>
+				<view class='money'>
+					<text class="rmb">{{$t(`¥`)}} </text><text class="price"> {{item.price}}</text>
+					<!-- <text class="ot-price">{{item.ot_price}}</text> -->
+				</view>
+			</view>
+		</block>
+	</view>
+</template>
+<script>
+	import {
+		mapGetters
+	} from "vuex";
+	import {
+		goPage,
+		goShopDetail
+	} from '@/libs/order.js'
+	import colors from "@/mixins/color";
+	export default {
+		computed: mapGetters(['uid']),
+		mixins: [colors],
+		props: {
+			benefit: {
+				type: Array,
+				default: function() {
+					return [];
+				}
+			}
+		},
+		data() {
+			return {
+
+			};
+		},
+		methods: {
+			goDetail(item) {
+				goPage().then(res => {
+					goShopDetail(item, this.uid).then(res => {
+						uni.navigateTo({
+							url: `/pages/goods_details/index?id=${item.id}`
+						})
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang='scss'>
+	.promotionGood {
+		padding: 0 30rpx;
+		display: flex;
+		flex-wrap: wrap;
+		padding: 15rpx 24rpx;
+
+		.item {
+			width: 215rpx;
+			display: flex;
+			flex-direction: column;
+			justify-content: center;
+			padding: 9rpx;
+
+			.pictrue {
+				height: 198rpx;
+				border-radius: 12rpx;
+
+
+
+				/deep/,
+				/deep/image,
+				/deep/.easy-loadimage,
+				/deep/uni-image {
+					width: 100%;
+					height: 198rpx;
+					border-radius: 12rpx;
+				}
+
+				image {
+					width: 100%;
+					height: 100%;
+					border-radius: 12rpx;
+				}
+			}
+
+			.money {
+				font-size: 30rpx;
+				color: var(--view-priceColor);
+				margin-top: 10rpx;
+				overflow: hidden; //超出的文本隐藏
+				text-overflow: ellipsis; //溢出用省略号显示
+				white-space: nowrap; //溢出不换行
+				margin: 0 auto;
+
+				.rmb {
+					font-weight: bold;
+					color: var(--view-priceColor);
+					font-size: 20rpx;
+					margin-right: 2rpx;
+				}
+
+				.price {
+					font-weight: bold;
+				}
+
+				.ot-price {
+					color: #999;
+					text-decoration: line-through;
+					font-size: 20rpx;
+					margin-left: 4rpx;
+				}
+			}
+		}
+	}
+</style>

+ 135 - 0
components/recommend/index.vue

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

+ 147 - 0
components/shareRedPackets/index.vue

@@ -0,0 +1,147 @@
+<template>
+	<view v-if="sharePacket.isState" class='sharing-packets' :class='sharePacket.isState && showAnimate ? "":"right"'>
+		<view class='sharing-con' @click='goShare'>
+			<image :src="imgHost + '/statics/images/red-packets.png'" />
+			<view class='text font-color'>
+				<view>{{$t(`最高返佣`)}}</view>
+				<view class='money'><text class='label'>{{$t(`¥`)}}</text>{{sharePacket.priceName}}</view>
+				<view class='tip'>{{$t(`推广享佣金`)}}</view>
+				<view class='shareBut'>{{$t(`立即分享`)}}</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {HTTP_REQUEST_URL} from '@/config/app';
+	export default {
+
+		props: {
+			sharePacket: {
+				type: Object,
+				default: function() {
+					return {
+						isState: true,
+						priceName: ''
+					}
+				}
+			},
+			showAnimate: {
+				type: Boolean,
+				default: true
+			},
+		},
+		watch: {
+			showAnimate(nVal, oVal) {
+				setTimeout(res => {
+					this.isAnimate = nVal
+				}, 1000)
+			}
+		},
+		data() {
+			return {
+				imgHost:HTTP_REQUEST_URL,
+				isAnimate: true
+			};
+		},
+
+		methods: {
+			closeShare: function() {
+				this.$emit('closeChange');
+			},
+			goShare: function() {
+				if (this.isAnimate) {
+					this.$emit('listenerActionSheet');
+				} else {
+					this.isAnimate = true
+					this.$emit('boxStatus', true);
+				}
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.sharing-packets {
+		position: fixed;
+		left: 30rpx;
+		bottom: 200rpx;
+		z-index: 5;
+		transition: all 0.3s ease-in-out 0s;
+		opacity: 1;
+		transform: scale(1);
+
+		&.right {
+			left: -170rpx;
+		}
+	}
+
+	// .sharing-packets.on {
+	// 	transform: scale(0);
+	// 	opacity: 0;
+	// }
+
+	.sharing-packets .iconfont {
+		width: 44rpx;
+		height: 44rpx;
+		border-radius: 50%;
+		text-align: center;
+		line-height: 44rpx;
+		background-color: #999;
+		font-size: 20rpx;
+		color: #fff;
+		margin: 0 auto;
+		box-sizing: border-box;
+		padding-left: 1px;
+	}
+
+	.sharing-packets .line {
+		width: 2rpx;
+		height: 40rpx;
+		background-color: #999;
+		margin: 0 auto;
+	}
+
+	.sharing-packets .sharing-con {
+		width: 187rpx;
+		height: 210rpx;
+		position: relative;
+	}
+
+	.sharing-packets .sharing-con image {
+		width: 100%;
+		height: 100%;
+	}
+
+	.sharing-packets .sharing-con .text {
+		position: absolute;
+		top: 30rpx;
+		font-size: 20rpx;
+		width: 100%;
+		text-align: center;
+	}
+
+	.sharing-packets .sharing-con .text .money {
+		font-size: 32rpx;
+		font-weight: bold;
+		margin-top: 5rpx;
+	}
+
+	.sharing-packets .sharing-con .text .money .label {
+		font-size: 20rpx;
+	}
+
+	.sharing-packets .sharing-con .text .tip {
+		font-size: 18rpx;
+		color: #999;
+		margin-top: 5rpx;
+	}
+
+	.sharing-packets .sharing-con .text .shareBut {
+		font-size: 22rpx;
+		color: #fff;
+		margin-top: 14rpx;
+		height: 50rpx;
+		line-height: 50rpx;
+	}
+</style>

+ 190 - 0
components/skeleton/index.vue

@@ -0,0 +1,190 @@
+<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="rect_idx + '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="circle_idx + '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(function(res) {
+					if (res[0] && res[0].length > 0)
+						that.systemInfo.height = res[0][0].height + res[0][0].top;
+				}).exec()
+
+				//绘制矩形
+				this.rectHandle();
+
+				//绘制圆形
+				this.radiusHandle();
+			},
+			rectHandle: function() {
+				const that = this;
+
+				//绘制不带样式的节点
+				uni.createSelectorQuery().selectAll(`.${this.selector}-rect`).boundingClientRect().exec(function(res) {
+					that.skeletonRectLists = res[0];
+				});
+
+			},
+			radiusHandle() {
+				const that = this;
+
+				uni.createSelectorQuery().selectAll(`.${this.selector}-radius`).boundingClientRect().exec(function(res) {
+					that.skeletonCircleLists = res[0];
+				});
+			}
+		}
+	}
+</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>

+ 52 - 0
components/swipers/index.vue

@@ -0,0 +1,52 @@
+<template>
+	    <view class='swiper'>
+	        <swiper :autoplay="autoplay" :circular="circular" :interval="interval" :duration="duration" @change="swiperChange">
+	            <block v-for="(item,index) in imgUrls" :key="index">
+	              <swiper-item>
+	                <navigator :url="item.link" style='width:100%;height:100%;' hover-class='none'><image :src="item.img" class="slide-image"/></navigator>
+	              </swiper-item>
+	            </block>
+	        </swiper>
+	        <view class="dots acea-row">
+	          <view class="dot" :class="index == currentSwiper ? 'active' : ''" v-for="(item,index) in imgUrls" :key="index"></view>
+	        </view>
+	    </view>
+</template>
+
+	<script>
+		export default {
+			
+			props: {
+				 imgUrls: {
+				 	type: Array,
+				 	default: function(){
+				 		return [];
+				 	}
+				 }
+			},
+			data() {
+				return {
+					circular: true,
+					    autoplay: true,
+					    interval: 3000,
+					    duration: 500,
+					    currentSwiper: 0
+				};
+			},
+			
+			methods: {
+				swiperChange: function (e) {
+					 this.currentSwiper = e.detail.current
+				    }
+			}
+		}
+	</script>
+
+<style scoped lang="scss">
+	.swiper{width:100%;height:282rpx;position:relative;}
+	.swiper swiper{width:100%;height:100%;position:relative;}
+	.swiper swiper .slide-image{width:100%;height:100%;}
+	.swiper .dots{position:absolute;right:40rpx;bottom:20rpx;}
+	.swiper .dots .dot{width:12rpx;height:12rpx;border:2rpx solid #fff;border-radius:50%;margin-right:15rpx;}
+	.swiper .dots .dot.active{border-color:#e93323;background-color:#e93323;}
+</style>

+ 185 - 0
components/tabNav.vue

@@ -0,0 +1,185 @@
+<template>
+	<view class="navTabBox">
+		<view class="longTab">
+			<scroll-view scroll-x="true" style="white-space: nowrap; display: flex;" scroll-with-animation :scroll-left="tabLeft" show-scrollbar="true">
+				<view class="longItem" :style='"width:"+isWidth+"px"' :data-index="index" :class="index===tabClick?'click':''" v-for="(item,index) in tabTitle" :key="index" :id="'id'+index" @click="longClick(index)">{{item.cate_name}}</view>
+				<view class="underlineBox" :style='"transform:translateX("+isLeft+"px);width:"+isWidth+"px"'>
+					<view class="underline"></view>
+				</view>
+			</scroll-view>
+		</view>
+		<view class="child-box" v-if="tabClick>0 && tabTitle[tabClick].children.length>0">
+			<scroll-view scroll-x="true" style="white-space: nowrap; display: flex;align-items: center; height: 100%;" scroll-with-animation :scroll-left="tabLeft" show-scrollbar="false">
+				<view class="wrapper">
+					<view v-for="(item,index) in tabTitle[tabClick].children" class="child-item" :class="{on:index == childIndex}" @click="childTab(tabClick,index)">
+						<image :src="item.pic" mode=""></image>
+						<view class="txt">{{item.cate_name}}</view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		getProductslist,
+		getProductHot
+	} from '@/api/store.js';
+	export default {
+		name: 'navTab',
+		props: {
+			tabTitle: {
+				type: Array,
+				default: []
+			}
+
+		},
+		data() {
+			return {
+				tabClick: 0, //导航栏被点击
+				isLeft: 0, //导航栏下划线位置
+				isWidth: 0, //每个导航栏占位
+				tabLeft:0,
+				swiperIndex:0,
+				childIndex:0,
+				childID:0
+			};
+		},
+		created() {
+			
+			var that = this
+			// 获取设备宽度
+			uni.getSystemInfo({
+				success(e) {
+					that.isWidth = e.windowWidth / 5 
+				}
+			})
+		},
+		methods: {
+			// 导航栏点击
+			longClick(index){
+				this.childIndex = 0;
+				if(this.tabTitle.length>5){
+					var tempIndex = index - 2;
+					tempIndex = tempIndex<=0 ? 0 : tempIndex;
+					this.tabLeft = (index-2) * this.isWidth //设置下划线位置
+				}
+				this.tabClick = index //设置导航点击了哪一个
+				this.isLeft = index * this.isWidth //设置下划线位置
+				let obj = {
+					type:'big',  //大标题
+					index:index
+				}
+				this.parentEmit(obj)
+				// this.$parent.currentTab = index //设置swiper的第几页
+			},
+			// 导航子类点击
+			childTab(tabClick,index){
+				this.childIndex = index
+				let obj = {
+					parentIndex:tabClick,
+					childIndex:index,
+					type:'small' //小标题
+				}
+				this.parentEmit(obj)
+			},
+			parentEmit(data){
+				this.$emit('changeTab', data);
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.navTabBox {
+		width: 100%;
+		color: rgba(255, 255, 255, 1);
+		.click {
+			color: white;
+		}
+		.longTab {
+			width: 100%;
+			/* #ifdef H5 */
+			padding-bottom: 20rpx;
+			/* #endif */
+			/* #ifdef MP */
+			padding-top: 12rpx;
+			padding-bottom: 12rpx;
+			/* #endif */
+			.longItem{ 
+				height: 50upx; 
+				display: inline-block;
+				line-height: 50upx;
+				text-align: center;
+				font-size: 30rpx;
+				&.click{
+					font-weight: bold;
+				}
+			}
+			.underlineBox {
+				height: 3px;
+				width: 20%;
+				display: flex;
+				align-content: center;
+				justify-content: center;
+				transition: .5s;
+				.underline {
+					width: 33rpx;
+					height: 4rpx;
+					background-color: white;
+				}
+			}
+		}
+	}
+	.child-box{
+		width: 100%;
+		position: relative;
+		// height: 152rpx;
+		background-color: #fff;
+		/* #ifdef H5 */
+		box-shadow: 0 2px 5px 1px rgba(0, 0, 0, 0.02);
+		/* #endif */
+		/* #ifdef MP */
+		box-shadow: 0 2rpx 3rpx 1rpx #f9f9f9;
+		/* #endif */
+		
+		.wrapper{
+			display: flex;
+			align-items: center;
+			padding: 20rpx 0;
+			background: #fff;
+			/* #ifdef H5 */
+			//box-shadow: 0 2px 5px 1px rgba(0, 0, 0, 0.06);
+			/* #endif */
+		}
+		.child-item{
+			flex-shrink: 0;
+			width:140rpx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			margin-left: 10rpx;
+			image{
+				width: 90rpx;
+				height: 90rpx;
+				border-radius: 50%;
+			}
+			.txt{
+				font-size: 24rpx;
+				color: #282828;
+				text-align: center;
+				margin-top: 10rpx;
+			}
+			&.on{
+				image{
+					border: 1px solid $theme-color-opacity;
+				}
+				.txt{
+					color: $theme-color;
+				}
+			}
+		}
+	}
+</style>

+ 324 - 0
components/tuiDrawer/index.vue

@@ -0,0 +1,324 @@
+<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"
+				:style="colorStyle">
+				<view class="tui-swipeout-button-right-item" v-for="(item, index) in actions" :key="index"
+					:style="{ backgroundColor: index == 0 ? 'var(--view-theme)' : '#ccc', color: index == 1 ? '#f2f2f2' : '#f2f2f2', 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>
+</template>
+
+<script>
+	import colors from '@/mixins/color';
+	export default {
+		name: 'tuiSwipeAction',
+		emits: ['click'],
+		mixins: [colors],
+		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;
+		/* margin-bottom: 24rpx; */
+
+	}
+
+
+	.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-item :active {
+    background-color: #fff !important;
+  } */
+
+	.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>

+ 427 - 0
components/update/app-update.vue

@@ -0,0 +1,427 @@
+<template>
+	<view class="wrap" v-if="popup_show">
+		<view class="popup-bg" :style="getHeight">
+			<view class="popup-content" :class="{ 'popup-content-show': popup_show }">
+				<view class="update-wrap">
+					<image src="./images/img.png" class="top-img"></image>
+					<view class="content">
+						<text class="title">{{$t(`发现新版本`)}}{{ update_info.version }}</text>
+						<!-- 升级描述 -->
+						<view class="title-sub" v-html="update_info.info"></view>
+						<!-- 升级按钮 -->
+						<button class="btn" v-if="downstatus < 1" @click="nowUpdate()">
+							{{$t(`立即升级`)}}
+						</button>
+						<!-- 下载进度 -->
+						<view class="sche-wrap" v-else>
+							<!-- 更新包下载中 -->
+							<view class="sche-bg">
+								<view class="sche-bg-jindu" :style="lengthWidth"></view>
+							</view>
+							<text class="down-text">{{$t(`下载进度`)}}:{{ (downSize / 1024 / 1024).toFixed(2) }}M/{{
+                  (fileSize / 1024 / 1024).toFixed(2)
+                }}M</text>
+						</view>
+					</view>
+				</view>
+				<image src="./images/close.png" class="close-ioc" @click="closeUpdate()"></image>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	let vm;
+	import {
+		getUpdateInfo
+	} from '@/api/public.js'
+
+	export default {
+		name: "appUpdate",
+		//@是否强制更新
+		props: {
+			tabbar: {
+				type: Boolean,
+				default: false, //是否有原生tabbar组件
+			},
+			getVer: {
+				type: Boolean,
+				default: false, //是否有原生tabbar组件
+			},
+		},
+		data() {
+			return {
+				popup_show: false, //弹窗是否显示
+				platform: "", //ios or android
+				version: "1.0.0", //当前软件版本
+				need_update: false, // 是否更新
+				downing: false, //是否下载中
+				downstatus: 0, //0未下载  1已开始 2已连接到资源  3已接收到数据  4下载完成
+				update_info: {
+					os: "", //设备系统
+					version: "", //最新版本
+					info: "", //升级说明
+				},
+				fileSize: 0, //文件大小
+				downSize: 0, //已下载大小
+				viewObj: null, //原生遮罩view
+			};
+		},
+		created() {
+			vm = this;
+			if (!this.getVer) this.update()
+		},
+		computed: {
+			// 下载进度计算
+			lengthWidth: function() {
+				let w = (this.downSize / this.fileSize) * 100;
+				if (!w) {
+					w = 0;
+				} else {
+					w = w.toFixed(2);
+				}
+				return {
+					width: w + "%", //return 宽度半分比
+				};
+			},
+			getHeight() {
+				let bottom = 0;
+				if (this.tabbar) {
+					bottom = 50;
+				}
+				return {
+					bottom: bottom + "px",
+					height: "auto",
+				};
+			},
+		},
+		methods: {
+			// 检查更新
+			update() {
+				// #ifdef APP-PLUS
+				// 获取手机系统信息
+				uni.getSystemInfo({
+					success: function(res) {
+						vm.platform = res.platform; //ios  or android
+						console.log("手机系统信息", vm.platform);
+					},
+				});
+
+				// 获取版本号
+				plus.runtime.getProperty(plus.runtime.appid, function(inf) {
+					vm.version = inf.version;
+				});
+				console.log("当前版本", vm.version);
+				this.getUpdateInfo(); //获取更新信息
+				// #endif
+			},
+
+			// 获取线上版本信息
+			getUpdateInfo() {
+				//向后台发起请求,获取最新版本号
+				getUpdateInfo(this.platform === "ios" ? 2 : 1)
+					.then((res) => {
+						if(Array.isArray(res.data)){
+						 return	this.$emit('isNew')
+						}
+						const tagDate = uni.getStorageSync('app_update_time') || '',
+							nowDate = new Date().toLocaleDateString();
+						if (tagDate !== nowDate && !this.getVer) {
+							uni.setStorageSync('app_update_time', new Date().toLocaleDateString());
+						} else if ((tagDate !== nowDate) && this.getVer) {
+							if (!res.data.is_force) return
+						} else if (tagDate == nowDate && !this.getVer && !res.data.is_force) {
+							return
+						}
+						// 这里的返回的数据跟后台约定
+						let data = res.data;
+						// 循环获取当前设备对应的更新数据
+						vm.update_info = data;
+						if (!vm.update_info.platform) {
+							// 后台未配置当前系统的升级数据
+						} else {
+							vm.checkUpdate(); ///检查是否更新
+						}
+					})
+					.catch((err) => {
+						vm.popup_show = false
+					});
+			},
+			// 检查是否更新
+			checkUpdate() {
+				vm.need_update = vm.compareVersion(vm.version, vm.update_info.version); // 检查是否需要升级
+				if (vm.need_update) {
+					vm.popup_show = true; //线上版本号大于当前安装的版本号  显示升级框
+					if (vm.tabbar) {
+						//页面是否有原生tabbar组件
+						// 创建原生view用来遮罩tabbar的点击事件 (如果是没有用原生的tabbar这一步可以取消)
+						vm.viewObj = new plus.nativeObj.View("viewObj", {
+							bottom: "0px",
+							left: "0px",
+							height: "50px",
+							width: "100%",
+							backgroundColor: "rgba(0,0,0,.6)",
+						});
+						vm.viewObj.show(); //显示原生遮罩
+					}
+				} else {
+					this.$emit('isNew')
+				}
+			},
+
+			// 取消更新
+			closeUpdate() {
+				if (vm.update_info.is_force) {
+					// 强制更新,取消退出app
+					this.platform == "android" ?
+						plus.runtime.quit() :
+						plus.ios
+						.import("UIApplication")
+						.sharedApplication()
+						.performSelector("exit");
+				} else {
+					vm.popup_show = false; //关闭升级弹窗
+					if (vm.viewObj) vm.viewObj.hide(); //隐藏原生遮罩
+				}
+			},
+			// 立即更新
+			nowUpdate() {
+				if (vm.downing) return false; //如果正在下载就停止操作
+				vm.downing = true; //状态改变 正在下载中
+
+				if (/\.apk$/.test(vm.update_info.url)) {
+					// 如果是apk地址
+					vm.download_wgt(); // 安装包/升级包更新
+				} else if (/\.wgt$/.test(vm.update_info.url)) {
+					// 如果是更新包
+					vm.download_wgt(); // 安装包/升级包更新
+				} else {
+					plus.runtime.openURL(vm.update_info.url, function() {
+						//调用外部浏览器打开更新地址
+						plus.nativeUI.toast("打开错误");
+					});
+				}
+			},
+			// 下载升级资源包
+			download_wgt() {
+				plus.nativeUI.showWaiting("下载更新文件..."); //下载更新文件...
+				let options = {
+					method: "get",
+				};
+				let dtask = plus.downloader.createDownload(
+					vm.update_info.url,
+					options,
+					function(d, status) {}
+				);
+
+				dtask.addEventListener("statechanged", function(task, status) {
+					if (status === null) {} else if (status == 200) {
+						//在这里打印会不停的执行,请注意,正式上线切记不要在这里打印东西///////////////////////////////////////////////////
+						vm.downstatus = task.state;
+						switch (task.state) {
+							case 3: // 已接收到数据
+								vm.downSize = task.downloadedSize;
+								if (task.totalSize) {
+									vm.fileSize = task.totalSize; //服务器须返回正确的content-length才会有长度
+								}
+								break;
+							case 4:
+								vm.installWgt(task.filename); // 安装wgt包
+								break;
+						}
+					} else {
+						plus.nativeUI.closeWaiting();
+						plus.nativeUI.toast("下载出错");
+						vm.downing = false;
+						vm.downstatus = 0;
+					}
+				});
+				dtask.start();
+			},
+
+			// 安装文件
+			installWgt(path) {
+				plus.nativeUI.showWaiting("安装更新文件..."); //安装更新文件...
+				plus.runtime.install(
+					path, {},
+					function() {
+						plus.nativeUI.closeWaiting();
+						// 应用资源下载完成!
+						plus.nativeUI.alert("应用资源下载完成!", function() {
+							plus.runtime.restart();
+						});
+					},
+
+					function(e) {
+						plus.nativeUI.closeWaiting();
+						// 安装更新文件失败
+						plus.nativeUI.alert("安装更新文件失败[" + e.code + "]:" + e.message);
+					}
+				);
+			},
+			// 对比版本号
+			compareVersion(ov, nv) {
+				if (!ov || !nv || ov == "" || nv == "") {
+					return false;
+				}
+				let b = false,
+					ova = ov.split(".", 4),
+					nva = nv.split(".", 4);
+				for (let i = 0; i < ova.length && i < nva.length; i++) {
+					let so = ova[i],
+						no = parseInt(so),
+						sn = nva[i],
+						nn = parseInt(sn);
+					if (nn > no || sn.length > so.length) {
+						return true;
+					} else if (nn < no) {
+						return false;
+					}
+				}
+				if (nva.length > ova.length && 0 == nv.indexOf(ov)) {
+					return true;
+				} else {
+					return false;
+				}
+			},
+		},
+	};
+</script>
+
+<style lang="scss" scoped>
+	.popup-bg {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		position: fixed;
+		top: 0;
+		left: 0rpx;
+		right: 0;
+		bottom: 0;
+		width: 750rpx;
+		background-color: rgba(0, 0, 0, 0.6);
+		z-index: 10000;
+	}
+
+	.popup-content {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+	}
+
+	.popup-content-show {
+		animation: mymove 500ms;
+		transform: scale(1);
+	}
+
+	@keyframes mymove {
+		0% {
+			transform: scale(0);
+			/*开始为原始大小*/
+		}
+
+		100% {
+			transform: scale(1);
+		}
+	}
+
+	.update-wrap {
+		width: 580rpx;
+		border-radius: 18rpx;
+		position: relative;
+		display: flex;
+		flex-direction: column;
+		background-color: #ffffff;
+		padding: 170rpx 30rpx 0;
+
+		.top-img {
+			position: absolute;
+			left: 0;
+			width: 100%;
+			height: 256rpx;
+			top: -128rpx;
+		}
+
+		.content {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			padding-bottom: 40rpx;
+
+			.title {
+				font-size: 32rpx;
+				font-weight: bold;
+				color: #6526f3;
+			}
+
+			.title-sub {
+				text-align: center;
+				font-size: 24rpx;
+				color: #666666;
+				padding: 30rpx 0;
+			}
+
+			.btn {
+				width: 460rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				color: #ffffff;
+				font-size: 30rpx;
+				height: 80rpx;
+				line-height: 80rpx;
+				border-radius: 100px;
+				background-color: #6526f3;
+				margin-top: 20rpx;
+			}
+		}
+	}
+
+	.close-ioc {
+		width: 70rpx;
+		height: 70rpx;
+		margin-top: 30rpx;
+	}
+
+	.sche-wrap {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: flex-end;
+		padding: 10rpx 50rpx 0;
+
+		.sche-wrap-text {
+			font-size: 24rpx;
+			color: #666;
+			margin-bottom: 20rpx;
+		}
+
+		.sche-bg {
+			position: relative;
+			background-color: #cccccc;
+			height: 30rpx;
+			border-radius: 100px;
+			width: 480rpx;
+			display: flex;
+			align-items: center;
+
+			.sche-bg-jindu {
+				position: absolute;
+				left: 0;
+				top: 0;
+				height: 30rpx;
+				min-width: 40rpx;
+				border-radius: 100px;
+				background: url(images/round.png) #5775e7 center right 4rpx no-repeat;
+				background-size: 26rpx 26rpx;
+			}
+		}
+
+		.down-text {
+			font-size: 24rpx;
+			color: #5674e5;
+			margin-top: 16rpx;
+		}
+	}
+</style>

BIN
components/update/images/close.png


BIN
components/update/images/img.png


BIN
components/update/images/round.png


BIN
components/update/images/update-img.png


+ 147 - 0
components/userEvaluation/index.vue

@@ -0,0 +1,147 @@
+<template>
+	<view class="evaluateWtapper">
+		<view class="evaluateItem" v-for="(item, indexw) in reply" :key="indexw">
+			<view class="pic-text acea-row row-middle">
+				<view class="pictrue">
+					<image :src="item.avatar"></image>
+				</view>
+				<view class="acea-row row-middle">
+					<view class="acea-row row-middle" style="margin-right: 15rpx;">
+						<view class="name line1">{{ item.nickname }}</view>
+						<view class="vipImg" v-if="item.is_money_level>0"><image src="../../static/images/svip.gif"></image></view>
+					</view>
+					<view class="start" :class="'star' + item.star"></view>
+				</view>
+			</view>
+			<view class="time">{{ item.add_time }} {{ item.suk }}</view>
+			<view class="evaluate-infor">{{ item.comment }}</view>
+			<view class="imgList acea-row">
+				<view class="pictrue" v-for="(itemn, indexn) in item.pics" :key="indexn">
+					<image :src="itemn" class="image" @click='getpreviewImage(indexw, indexn)'></image>
+				</view>
+			</view>
+			<view class="reply" v-if="item.merchant_reply_content">
+				<text class="font-num">{{$t(`店小二`)}}</text>:{{
+          item.merchant_reply_content
+        }}
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+	export default {
+		props: {
+			reply: {
+				type: Array,
+				default: () => []
+			}
+		},
+		data: function() {
+			return {};
+		},
+		methods: {
+			getpreviewImage: function(indexw, indexn) {
+				uni.previewImage({
+					urls: this.reply[indexw].pics,
+					current: this.reply[indexw].pics[indexn]
+				});
+			}
+		}
+	}
+</script>
+<style scoped lang='scss'>
+	.vipImg{
+		width: 68rpx;
+		height: 27rpx;
+		image{
+			width: 100%;
+			height: 100%;
+			margin-left: 10rpx;
+		}
+	}
+	.evaluateWtapper .evaluateItem {
+		background-color: #fff;
+		padding-bottom: 25rpx;
+	}
+
+	.evaluateWtapper .evaluateItem~.evaluateItem {
+		border-top: 1rpx solid #f5f5f5;
+	}
+
+	.evaluateWtapper .evaluateItem .pic-text {
+		font-size: 26rpx;
+		color: #282828;
+		height: 95rpx;
+		padding: 0 30rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .pic-text .pictrue {
+		width: 60rpx;
+		height: 60rpx;
+		margin-right: 20rpx;
+		border-radius: 50%;
+	}
+
+	.evaluateWtapper .evaluateItem .pic-text .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 50%;
+	}
+
+	.evaluateWtapper .evaluateItem .pic-text .name {
+		max-width: 450rpx;
+		font-size: 30rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .time {
+		font-size: 24rpx;
+		color: #82848f;
+		padding: 0 30rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .evaluate-infor {
+		font-size: 28rpx;
+		color: #282828;
+		margin-top: 19rpx;
+		padding: 0 30rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .imgList {
+		padding: 0 30rpx 0 15rpx;
+		margin-top: 25rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .imgList .pictrue {
+		width: 156rpx;
+		height: 156rpx;
+		margin: 0 0 15rpx 15rpx;
+	}
+
+	.evaluateWtapper .evaluateItem .imgList .pictrue image {
+		width: 100%;
+		height: 100%;
+		background-color: #f7f7f7;
+	}
+
+	.evaluateWtapper .evaluateItem .reply {
+		font-size: 26rpx;
+		color: #454545;
+		background-color: #f7f7f7;
+		border-radius: 5rpx;
+		margin: 20rpx 30rpx 0 30rpx;
+		padding: 20rpx;
+		position: relative;
+	}
+
+	.evaluateWtapper .evaluateItem .reply::before {
+		content: "";
+		width: 0;
+		height: 0;
+		border-left: 20rpx solid transparent;
+		border-right: 20rpx solid transparent;
+		border-bottom: 30rpx solid #f7f7f7;
+		position: absolute;
+		top: -14rpx;
+		left: 40rpx;
+	}
+</style>

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

@@ -0,0 +1,923 @@
+
+let QRCode={};
+(function(){
+function unicodeFormat8(code){
+var c0,c1,c2;
+if(code<128){
+return[code];
+}else if(code<2048){
+c0=192+(code>>6);
+c1=128+(code&63);
+return[c0,c1];
+}else{
+c0=224+(code>>12);
+c1=128+(code>>6&63);
+c2=128+(code&63);
+return[c0,c1,c2];
+}
+}
+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;
+}
+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,
+getModuleCount:function(){
+return this.moduleCount;
+},
+make:function(){
+this.getRightType();
+this.dataCache=this.createData();
+this.createQrcode();
+},
+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);
+},
+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;
+}
+}
+}
+},
+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);
+}
+},
+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);
+}
+},
+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;
+}
+}
+}
+}
+}
+},
+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;
+}
+},
+setupTypeInfo:function(test,maskPattern){
+var data=(QRErrorCorrectLevel[this.errorCorrectLevel]<<3)|maskPattern;
+var bits=QRUtil.getBCHTypeInfo(data);
+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;
+}
+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;
+}
+}
+this.modules[this.moduleCount-8][8]=(!test);
+},
+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);
+}
+while(buffer.length%8!=0){
+buffer.putBit(false);
+}
+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);
+},
+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;
+},
+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),
+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;
+},
+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;
+},
+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);
+}
+},
+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];
+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;
+}
+}
+}
+}
+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;
+}
+}
+if(head^current){
+sameCount++;
+}else{
+head=current;
+if(sameCount>=5){
+lostPoint+=(3+sameCount-5);
+}
+sameCount=1;
+}
+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];
+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;
+}
+}
+}
+}
+if(head^current){
+sameCount++;
+}else{
+head=current;
+if(sameCount>=5){
+lostPoint+=(3+sameCount-5);
+}
+sameCount=1;
+}
+}
+}
+var ratio=Math.abs(100*darkCount/moduleCount/moduleCount-50)/5;
+lostPoint+=ratio*10;
+return lostPoint;
+}
+};
+var QRMath={
+glog:function(n){
+if(n<1){
+throw new Error("glog("+n+")");
+}
+return QRMath.LOG_TABLE[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;
+}
+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;
+},
+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);
+},
+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);
+}
+};
+var RS_BLOCK_TABLE=[
+[1,26,19],
+[1,26,16],
+[1,26,13],
+[1,26,9],
+[1,44,34],
+[1,44,28],
+[1,44,22],
+[1,44,16],
+[1,70,55],
+[1,70,44],
+[2,35,17],
+[2,35,13],
+[1,100,80],
+[2,50,32],
+[2,50,24],
+[4,25,9],
+[1,134,108],
+[2,67,43],
+[2,33,15,2,34,16],
+[2,33,11,2,34,12],
+[2,86,68],
+[4,43,27],
+[4,43,19],
+[4,43,15],
+[2,98,78],
+[4,49,31],
+[2,32,14,4,33,15],
+[4,39,13,1,40,14],
+[2,121,97],
+[2,60,38,2,61,39],
+[4,40,18,2,41,19],
+[4,40,14,2,41,15],
+[2,146,116],
+[3,58,36,2,59,37],
+[4,36,16,4,37,17],
+[4,36,12,4,37,13],
+[2,86,68,2,87,69],
+[4,69,43,1,70,44],
+[6,43,19,2,44,20],
+[6,43,15,2,44,16],
+[4,101,81],
+[1,80,50,4,81,51],
+[4,50,22,4,51,23],
+[3,36,12,8,37,13],
+[2,116,92,2,117,93],
+[6,58,36,2,59,37],
+[4,46,20,6,47,21],
+[7,42,14,4,43,15],
+[4,133,107],
+[8,59,37,1,60,38],
+[8,44,20,4,45,21],
+[12,33,11,4,34,12],
+[3,145,115,1,146,116],
+[4,64,40,5,65,41],
+[11,36,16,5,37,17],
+[11,36,12,5,37,13],
+[5,109,87,1,110,88],
+[5,65,41,5,66,42],
+[5,54,24,7,55,25],
+[11,36,12],
+[5,122,98,1,123,99],
+[7,73,45,3,74,46],
+[15,43,19,2,44,20],
+[3,45,15,13,46,16],
+[1,135,107,5,136,108],
+[10,74,46,1,75,47],
+[1,50,22,15,51,23],
+[2,42,14,17,43,15],
+[5,150,120,1,151,121],
+[9,69,43,4,70,44],
+[17,50,22,1,51,23],
+[2,42,14,19,43,15],
+[3,141,113,4,142,114],
+[3,70,44,11,71,45],
+[17,47,21,4,48,22],
+[9,39,13,16,40,14],
+[3,135,107,5,136,108],
+[3,67,41,13,68,42],
+[15,54,24,5,55,25],
+[15,43,15,10,44,16],
+[4,144,116,4,145,117],
+[17,68,42],
+[17,50,22,6,51,23],
+[19,46,16,6,47,17],
+[2,139,111,7,140,112],
+[17,74,46],
+[7,54,24,16,55,25],
+[34,37,13],
+[4,151,121,5,152,122],
+[4,75,47,14,76,48],
+[11,54,24,14,55,25],
+[16,45,15,14,46,16],
+[6,147,117,4,148,118],
+[6,73,45,14,74,46],
+[11,54,24,16,55,25],
+[30,46,16,2,47,17],
+[8,132,106,4,133,107],
+[8,75,47,13,76,48],
+[7,54,24,22,55,25],
+[22,45,15,13,46,16],
+[10,142,114,2,143,115],
+[19,74,46,4,75,47],
+[28,50,22,6,51,23],
+[33,46,16,4,47,17],
+[8,152,122,4,153,123],
+[22,73,45,3,74,46],
+[8,53,23,26,54,24],
+[12,45,15,28,46,16],
+[3,147,117,10,148,118],
+[3,73,45,23,74,46],
+[4,54,24,31,55,25],
+[11,45,15,31,46,16],
+[7,146,116,7,147,117],
+[21,73,45,7,74,46],
+[1,53,23,37,54,24],
+[19,45,15,26,46,16],
+[5,145,115,10,146,116],
+[19,75,47,10,76,48],
+[15,54,24,25,55,25],
+[23,45,15,25,46,16],
+[13,145,115,3,146,116],
+[2,74,46,29,75,47],
+[42,54,24,1,55,25],
+[23,45,15,28,46,16],
+[17,145,115],
+[10,74,46,23,75,47],
+[10,54,24,35,55,25],
+[19,45,15,35,46,16],
+[17,145,115,1,146,116],
+[14,74,46,21,75,47],
+[29,54,24,19,55,25],
+[11,45,15,46,46,16],
+[13,145,115,6,146,116],
+[14,74,46,23,75,47],
+[44,54,24,7,55,25],
+[59,46,16,1,47,17],
+[12,151,121,7,152,122],
+[12,75,47,26,76,48],
+[39,54,24,14,55,25],
+[22,45,15,41,46,16],
+[6,151,121,14,152,122],
+[6,75,47,34,76,48],
+[46,54,24,10,55,25],
+[2,45,15,64,46,16],
+[17,152,122,4,153,123],
+[29,74,46,14,75,47],
+[49,54,24,10,55,25],
+[24,45,15,46,46,16],
+[4,152,122,18,153,123],
+[13,74,46,32,75,47],
+[48,54,24,14,55,25],
+[42,45,15,32,46,16],
+[20,147,117,4,148,118],
+[40,75,47,7,76,48],
+[43,54,24,22,55,25],
+[10,45,15,67,46,16],
+[19,148,118,6,149,119],
+[18,75,47,31,76,48],
+[34,54,24,34,55,25],
+[20,45,15,61,46,16]
+];
+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;
+}
+}
+};
+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++;
+}
+};
+let qrcodeAlgObjCache=[];
+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'){
+opt={
+text:opt
+};
+}
+if(opt){
+for(var i in opt){
+this.options[i]=opt[i];
+}
+}
+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
+});
+}
+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;
+}
+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();
+ctxi.moveTo(x+r,y);
+ctxi.arcTo(x+width,y,x+width,y+r,r);
+ctxi.arcTo(x+width,y+height,x+width-r,y+height,r);
+ctxi.arcTo(x,y+height,x,y+height-r,r);
+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: false
+		},
+		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>

+ 33 - 0
config/app.js

@@ -0,0 +1,33 @@
+module.exports = {
+	// 小程序配置
+	// #ifdef MP || APP-PLUS
+	// 请求域名 格式: https://您的域名
+	HTTP_REQUEST_URL: `http://yc.frp.liuniu946.com`,
+	// #endif
+
+	// H5配置
+	// #ifdef H5
+	//H5接口是浏览器地址,非单独部署不用修改
+	HTTP_REQUEST_URL: window.location.protocol + "//" + window.location.host+'/frp',
+	// #endif 
+
+	// 以下配置在不做二开的前提下,不需要做任何的修改
+	HEADER: {
+		'content-type': 'application/json',
+		//#ifdef H5
+		'Form-type': navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1 ? 'wechat' : 'h5',
+		//#endif
+		//#ifdef MP
+		'Form-type': 'routine',
+		//#endif
+		//#ifdef APP-VUE
+		'Form-type': 'app',
+		//#endif
+	},
+	// 回话密钥名称 请勿修改此配置
+	TOKENNAME: 'Authori-zation',
+	// 缓存时间 0 永久
+	EXPIRE: 0,
+	//分页最多显示条数
+	LIMIT: 10
+}

+ 42 - 0
config/cache.js

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

+ 18 - 0
config/socket.js

@@ -0,0 +1,18 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 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
+}

+ 77 - 0
libs/chat.js

@@ -0,0 +1,77 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import $store from "@/store";
+import {
+	VUE_APP_WS_URL
+} from "@/utils/index.js";
+const Socket = function() {
+	let url = VUE_APP_WS_URL
+	this.ws = new WebSocket(wss(url));
+	this.ws.onopen = this.onOpen.bind(this);
+	this.ws.onerror = this.onError.bind(this);
+	this.ws.onmessage = this.onMessage.bind(this);
+	this.ws.onclose = this.onClose.bind(this);
+};
+
+function wss(wsSocketUrl) {
+	let ishttps = document.location.protocol == 'https:';
+	if (ishttps) {
+		return wsSocketUrl.replace('ws:', 'wss:');
+	} else {
+		return wsSocketUrl.replace('wss:', 'ws:');
+	}
+}
+
+Socket.prototype = {
+	vm(vm) {
+		this.vm = vm;
+	},
+	close() {
+		clearInterval(this.timer);
+		this.ws.close();
+	},
+	onOpen() {
+		this.init();
+		this.send({
+			type: "login",
+			data: $store.state.app.token
+		});
+		this.vm.$emit("socket_open");
+	},
+	init() {
+		var that = this;
+		this.timer = setInterval(()=> {
+			that.send({
+				type: "ping"
+			});
+		}, 10000);
+	},
+	send(data) {
+		return this.ws.send(JSON.stringify(data));
+	},
+	onMessage(res) {
+		const {
+			type,
+			data = {}
+		} = JSON.parse(res.data);
+		this.vm.$emit(type, data);
+	},
+	onClose: function() {
+		clearInterval(this.timer);
+	},
+	onError: function(e) {
+		this.vm.$emit("socket_error", e);
+	}
+};
+
+Socket.prototype.constructor = Socket;
+
+export default Socket;

+ 142 - 0
libs/login.js

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

+ 99 - 0
libs/new_chat.js

@@ -0,0 +1,99 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import $store from "@/store";
+import {
+	HTTP_REQUEST_URL
+} from "@/config/app.js";
+import {
+	VUE_APP_WS_URL
+} from "@/utils/index.js";
+import {
+	getServerType
+} from '@/api/api.js';
+const Socket = function() {
+
+	// this.ws.close(this.close.bind(this));
+};
+
+
+// #ifdef H5
+function wss(wsSocketUrl) {
+	let ishttps = document.location.protocol == 'https:';
+	if (ishttps) {
+		return wsSocketUrl.replace('ws:', 'wss:');
+	} else {
+		return wsSocketUrl.replace('wss:', 'ws:');
+	}
+}
+// #endif
+
+
+
+Socket.prototype = {
+	// close() {
+	//   clearInterval(this.timer);
+	//   this.ws.close();
+	// },
+	onSocketOpen: function(my) {
+		uni.$emit('socketOpen', my)
+	},
+	init: function() {
+		var that = this;
+		this.timer = setInterval(function() {
+			that.send({
+				type: "ping"
+			});
+		}, 10000);
+	},
+	send: function(data) {
+		let datas = JSON.stringify(data)
+		return uni.sendSocketMessage({
+			data: datas
+		});
+	},
+	onMessage: function(res) {
+		const {
+			type,
+			data = {}
+		} = JSON.parse(res.data);
+		uni.$emit(type, data)
+	},
+
+	onClose: function() {
+		uni.closeSocket()
+		clearInterval(this.timer);
+		uni.$emit("socket_close");
+	},
+	onError: function(e) {
+		uni.$emit("socket_error", e);
+	},
+	close: function() {
+		uni.closeSocket();
+	},
+	onStart: function(token, form_type) {
+		let wssUrl = `${VUE_APP_WS_URL}`
+		this.ws = uni.connectSocket({
+			url: wssUrl + '?type=user&token=' + token + '&form_type=' + form_type,
+			header: {
+				'content-type': 'application/json'
+			},
+			method: 'GET',
+			success: (res) => {}
+		});
+		this.ws.onOpen(this.onSocketOpen.bind(this))
+		this.ws.onError(this.onError.bind(this));
+		this.ws.onMessage(this.onMessage.bind(this))
+		this.ws.onClose(this.onClose.bind(this));
+	}
+};
+
+Socket.prototype.constructor = Socket;
+export default Socket;

+ 42 - 0
libs/order.js

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

+ 251 - 0
libs/routine.js

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

+ 352 - 0
libs/uniApi.js

@@ -0,0 +1,352 @@
+
+export function navigateTo(type,url,opt){
+let toUrl=url;
+let api='navigateTo';
+toUrl=opt?toUrl+'?'+convertObj(opt):toUrl;
+switch(type){
+case 1:
+api='navigateTo';
+break;
+case 2:
+api='redirectTo';
+break;
+case 3:
+api='reLaunch';
+break;
+case 4:
+api='switchTab';
+break;
+default:
+api='navigateTo'
+break;
+}
+uni[api]({
+url:toUrl,
+animationType:'slide-in-right',
+animationDuration:200
+});
+}
+export function navigateBack(delta){
+uni.navigateBack({
+delta:delta
+});
+}
+export function setStorage(key,val){
+if(typeof val=='string'){
+uni.setStorageSync(key,val);
+return val
+}
+uni.setStorageSync(key,JSON.stringify(val));
+}
+export function getStorage(key){
+let uu=uni.getStorageSync(key);
+try{
+if(typeof JSON.parse(uu)!='number'){
+uu=JSON.parse(uu);
+}
+}catch(e){}
+return uu;
+}
+export function removeStorage(key){
+if(key){
+uni.removeStorageSync(key);
+}
+}
+export function clearStorage(){
+try{
+uni.clearStorageSync();
+}catch(e){
+throw new Error('处理失败');
+}
+}
+export function Toast(title,icon='none',obj={},duration=800){
+let toastData={
+title:title,
+duration:duration,
+position:'center',
+mask:true,
+icon:icon?icon:'none',
+...obj
+};
+uni.showToast(toastData);
+}
+export function Loading(title='正在加载...',obj={}){
+uni.showLoading({
+title:title,
+mask:true,
+...obj
+});
+}
+export function hideLoading(){
+try{
+uni.hideLoading();
+}catch(e){
+throw new Error('处理失败');
+}
+}
+export function Modal(title='提示',content='这是一个模态弹窗!',obj={
+showCancel:true,
+cancelText:'取消',
+confirmText:'确定'
+}){
+obj.cancelText='确定';
+obj.confirmText='取消';
+return new Promise((reslove,reject)=>{
+uni.showModal({
+title:title,
+content:content,
+...obj,
+success:(res)=>{
+if(res.confirm){
+reslove()
+}
+if(res.cancel){
+reject()
+}
+}
+});
+})
+}
+export function ActionSheet(itemList,itemColor="#000000"){
+return new Promise((reslove,reject)=>{
+uni.showActionSheet({
+itemList:itemList,
+itemColor:itemColor,
+success:(res)=>{
+reslove(res.tapIndex);
+},
+fail:function(res){
+reject(res.errMsg);
+}
+});
+})
+}
+export function ScrollTo(ScrollTop){
+uni.pageScrollTo({
+scrollTop:ScrollTop,
+duration:300
+})
+}
+export function GetUserInfo(){
+return new Promise((reslove,reject)=>{
+uni.getUserInfo({
+success(res){
+console.log(res);
+reslove(res);
+},
+fail(rej){
+reject(rej);
+}
+})
+})
+}
+export function Authorize(scoped='scope.userInfo'){
+return new Promise((reslove,reject)=>{
+uni.authorize({
+scope:scoped,
+success(res){
+reslove(res);
+},
+fail(rej){
+reject(rej);
+}
+})
+})
+}
+export function convertObj(opt){
+let str='';
+let arr=[];
+Object.keys(opt).forEach(item=>{
+arr.push(`${item}=${opt[item]}`);
+})
+str=arr.join('&');
+return str;
+}
+export function throttle(fn,delay){
+var lastArgs;
+var timer;
+var delay=delay||200;
+return function(...args){
+lastArgs=args;
+if(!timer){
+timer=setTimeout(()=>{
+timer=null;
+fn.apply(this,lastArgs);
+},delay);
+}
+}
+}
+export function chooseImage(count){
+return new Promise((reslove,reject)=>{
+uni.chooseImage({
+count:count,
+sizeType:['original','compressed'],
+sourceType:['album','camera'],
+success:(res)=>{
+reslove(res);
+},
+fail:(rej)=>{
+reject(rej);
+}
+});
+})
+}
+export function serialize(data){
+if(data!=null&&data!=''){
+try{
+return JSON.parse(JSON.stringify(data));
+}catch(e){
+if(data instanceof Array){
+return[];
+}
+return{};
+}
+}
+return data;
+}
+Date.prototype.format=function(fmt){
+let o={
+'M+':this.getMonth()+1,
+'d+':this.getDate(),
+'h+':this.getHours(),
+'m+':this.getMinutes(),
+'s+':this.getSeconds(),
+'q+':Math.floor((this.getMonth()+3)/3),
+S:this.getMilliseconds()
+};
+if(/(y+)/.test(fmt)){
+fmt=fmt.replace(RegExp.$1,String(this.getFullYear()).substr(4-RegExp.$1.length));
+}
+for(let k in o){
+if(new RegExp('('+k+')').test(fmt)){
+fmt=fmt.replace(RegExp.$1,RegExp.$1.length==1?o[k]:('00'+o[k]).substr(String(o[k]).length));
+}
+}
+return fmt;
+};
+export function formatDate(nS,format){
+if(!nS){
+return'';
+}
+format=format||'yyyy-MM-dd hh:mm:ss';
+return new Date(nS).format(format);
+}
+export function pathToBase64(path){
+return new Promise(function(resolve,reject){
+if(typeof window==='object'&&'document'in window){
+if(typeof FileReader==='function'){
+var xhr=new XMLHttpRequest()
+xhr.open('GET',path,true)
+xhr.responseType='blob'
+xhr.onload=function(){
+if(this.status===200){
+let fileReader=new FileReader()
+fileReader.onload=function(e){
+resolve(e.target.result)
+}
+fileReader.onerror=reject
+fileReader.readAsDataURL(this.response)
+}
+}
+xhr.onerror=reject
+xhr.send()
+return
+}
+var canvas=document.createElement('canvas')
+var c2x=canvas.getContext('2d')
+var img=new Image
+img.onload=function(){
+canvas.width=img.width
+canvas.height=img.height
+c2x.drawImage(img,0,0)
+resolve(canvas.toDataURL())
+canvas.height=canvas.width=0
+}
+img.onerror=reject
+img.src=path
+return
+}
+if(typeof plus==='object'){
+plus.io.resolveLocalFileSystemURL(getLocalFilePath(path),function(entry){
+entry.file(function(file){
+var fileReader=new plus.io.FileReader()
+fileReader.onload=function(data){
+resolve(data.target.result)
+}
+fileReader.onerror=function(error){
+reject(error)
+}
+fileReader.readAsDataURL(file)
+},function(error){
+reject(error)
+})
+},function(error){
+reject(error)
+})
+return
+}
+if(typeof wx==='object'&&wx.canIUse('getFileSystemManager')){
+wx.getFileSystemManager().readFile({
+filePath:path,
+encoding:'base64',
+success:function(res){
+resolve('data:image/png;base64,'+res.data)
+},
+fail:function(error){
+reject(error)
+}
+})
+return
+}
+reject(new Error('not support'))
+})
+}
+export function showWeekFirstDay(){
+var date=new Date();
+var weekday=date.getDay()||7;
+date.setDate(date.getDate()-weekday+1);
+return formatDate(date,'yyyy-MM-dd');
+}
+export function showMonthFirstDay(){
+var MonthFirstDay=new Date().setDate(1);
+return formatDate(new Date(MonthFirstDay).getTime(),'yyyy-MM-dd');
+}
+var now=new Date();
+var nowMonth=now.getMonth();
+var nowYear=now.getYear();
+nowYear+=(nowYear<2000)?1900:0;
+function getQuarterStartMonth(){
+var quarterStartMonth=0;
+if(nowMonth<3){
+quarterStartMonth=0;
+}
+if(2<nowMonth&&nowMonth<6){
+quarterStartMonth=3;
+}
+if(5<nowMonth&&nowMonth<9){
+quarterStartMonth=6;
+}
+if(nowMonth>8){
+quarterStartMonth=9;
+}
+return quarterStartMonth;
+}
+export function getQuarterStartDate(){
+var quarterStartDate=new Date(nowYear,getQuarterStartMonth(),1);
+return formatDate(quarterStartDate,'yyyy-MM-dd');
+}
+export function unique(data){
+data=data||[];
+var n={};
+for(var i=0;i<data.length;i++){
+var v=JSON.stringify(data[i]);
+if(typeof(v)=="undefined"){
+n[v]=1;
+}
+}
+data.length=0;
+for(var i in n){
+data[data.length]=i;
+}
+return data;
+}

+ 339 - 0
libs/wechat.js

@@ -0,0 +1,339 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+// #ifdef H5
+import WechatJSSDK from "@/plugin/jweixin-module/index.js";
+
+
+import {
+	getWechatConfig,
+	wechatAuth,
+	getShopConfig,
+	wechatAuthV2
+} from "@/api/public";
+import {
+	WX_AUTH,
+	STATE_KEY,
+	LOGINTYPE,
+	BACK_URL
+} from '@/config/cache';
+import {
+	parseQuery
+} from '@/utils';
+import store from '@/store';
+import Cache from '@/utils/cache';
+
+class AuthWechat {
+
+	constructor() {
+		//微信实例化对象
+		this.instance = WechatJSSDK;
+		//是否实例化
+		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 = encodeURI(window.location.href)
+		// }
+		return /(Android)/i.test(navigator.userAgent) ? document.location.href : window.entryUrl;
+	}
+
+	/**
+	 * 初始化wechat(分享配置)
+	 */
+	wechat() {
+		return new Promise((resolve, reject) => {
+			// if (this.status && !this.isAndroid()) return resolve(this.instance);
+			getWechatConfig()
+				.then(res => {
+					this.instance.config(res.data);
+					this.initConfig = res.data;
+					this.status = true;
+					this.instance.ready(() => {
+						resolve(this.instance);
+					})
+				}).catch(err => {
+					this.status = false;
+					reject(err);
+				});
+		});
+	}
+
+	/**
+	 * 验证是否初始化
+	 */
+	verifyInstance() {
+		let that = this;
+		return new Promise((resolve, reject) => {
+			if (that.instance === null && !that.status) {
+				that.wechat().then(res => {
+					resolve(that.instance);
+				}).catch(() => {
+					return reject();
+				})
+			} else {
+				return resolve(that.instance);
+			}
+		})
+	}
+	// 微信公众号的共享地址
+	openAddress() {
+		return new Promise((resolve, reject) => {
+			this.wechat().then(wx => {
+				this.toPromise(wx.openAddress).then(res => {
+					resolve(res);
+				}).catch(err => {
+					reject(err);
+				});
+			}).catch(err => {
+				reject(err);
+			})
+		});
+	}
+
+	// 获取经纬度;
+	location() {
+		return new Promise((resolve, reject) => {
+			this.wechat().then(wx => {
+				this.toPromise(wx.getLocation, {
+					type: 'wgs84'
+				}).then(res => {
+					resolve(res);
+				}).catch(err => {
+					reject(err);
+				});
+			}).catch(err => {
+				reject(err);
+			})
+		});
+	}
+
+	// 使用微信内置地图查看位置接口;
+	seeLocation(config) {
+		return new Promise((resolve, reject) => {
+			this.wechat().then(wx => {
+				this.toPromise(wx.openLocation, config).then(res => {
+					resolve(res);
+				}).catch(err => {
+					reject(err);
+				});
+			}).catch(err => {
+				reject(err);
+			})
+		});
+	}
+
+	/**
+	 * 微信支付
+	 * @param {Object} config
+	 */
+	pay(config) {
+		return new Promise((resolve, reject) => {
+			this.wechat().then((wx) => {
+				this.toPromise(wx.chooseWXPay, config).then(res => {
+					resolve(res);
+				}).catch(res => {
+					reject(res);
+				});
+			}).catch(res => {
+				reject(res);
+			});
+		});
+	}
+
+	toPromise(fn, config = {}) {
+		return new Promise((resolve, reject) => {
+			fn({
+				...config,
+				success(res) {
+					resolve(res);
+				},
+				fail(err) {
+					reject(err);
+				},
+				complete(err) {
+					reject(err);
+				},
+				cancel(err) {
+					reject(err);
+				}
+			});
+		});
+	}
+
+	/**
+	 * 自动去授权
+	 */
+	oAuth(snsapiBase, url) {
+		// if (uni.getStorageSync('authIng')) return
+
+		if (uni.getStorageSync(WX_AUTH) && store.state.app.token && snsapiBase == 'snsapi_base') return;
+		let {
+			code
+		} = parseQuery();
+		let snsapiCode = uni.getStorageSync('snsapiCode')
+		if (code instanceof Array) {
+			code = code[code.length - 1]
+		}
+		if (snsapiCode instanceof Array) {
+			snsapiCode = snsapiCode[snsapiCode.length - 1]
+		}
+		if (!code || code == snsapiCode) {
+			uni.setStorageSync('authIng', true)
+			return this.toAuth(snsapiBase, url);
+		} else {
+			// if(Cache.has('snsapiKey'))
+			// 	return this.auth(code).catch(error=>{
+			// 		uni.showToast({
+			// 			title:error,
+			// 			icon:'none'
+			// 		})
+			// 	})
+		}
+	}
+
+	clearAuthStatus() {
+
+	}
+
+	/**
+	 * 授权登陆获取token
+	 * @param {Object} code
+	 */
+	auth(code) {
+		return new Promise((resolve, reject) => {
+			let loginType = Cache.get(LOGINTYPE);
+			wechatAuthV2(code, parseInt(Cache.get("spread")))
+				.then(({
+					data
+				}) => {
+					// store.commit("LOGIN", {
+					// 	token: data.token,
+					// 	time: Cache.strTotime(data.expires_time) - Cache.time()
+					// });
+					// store.commit("SETUID", data.userInfo.uid);
+					Cache.set(WX_AUTH, code);
+					Cache.clear(STATE_KEY);
+					resolve(data);
+				})
+				.catch(reject);
+		});
+	}
+
+	/**
+	 * 获取跳转授权后的地址
+	 * @param {Object} appId
+	 */
+	getAuthUrl(appId, snsapiBase, backUrl) {
+		if (backUrl) {
+			let backUrlArr = backUrl.split('&');
+			let newUrlArr = backUrlArr.filter(item => {
+				if (item.indexOf('code=') === -1) {
+					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

+ 96 - 0
main.js

@@ -0,0 +1,96 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 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'
+import i18n from './utils/lang.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 pageLoading from './components/pageLoading.vue'
+import skeleton from './components/skeleton/index.vue'
+import easyLoadimage from '@/components/easy-loadimage/easy-loadimage.vue'
+Vue.component('skeleton', skeleton)
+Vue.component('pageLoading', pageLoading)
+Vue.component('easyLoadimage', easyLoadimage)
+
+
+// #ifdef H5
+
+
+import {
+	parseQuery
+} from "./utils";
+import Auth from './libs/wechat';
+import {
+	SPREAD
+} from './config/cache';
+Vue.prototype.$wechat = Auth;
+
+
+
+let cookieName = "VCONSOLE",
+	query = parseQuery(),
+	urlSpread = query["spread"],
+	vconsole = query[cookieName.toLowerCase()],
+	md5Crmeb = "b14d1e9baeced9bb7525ab19ee35f2d2", //CRMEB MD5 加密开启vconsole模式
+	md5UnCrmeb = "3dca2162c4e101b7656793a1af20295c"; //UN_CREMB MD5 加密关闭vconsole模式
+
+if (urlSpread !== undefined) {
+	var spread = Cache.get(SPREAD);
+	urlSpread = parseInt(urlSpread);
+	if (!Number.isNaN(urlSpread) && spread !== urlSpread) {
+		Cache.set("spread", urlSpread || 0);
+	} else if (spread === 0 || typeof spread !== "number") {
+		Cache.set("spread", urlSpread || 0);
+	}
+}
+
+if (vconsole !== undefined) {
+	if (vconsole === md5UnCrmeb && Cache.has(cookieName))
+		Cache.clear(cookieName);
+} else vconsole = Cache.get(cookieName);
+
+import VConsole from './pages/extension/components/vconsole.min.js'
+
+if (vconsole !== undefined && vconsole === md5Crmeb) {
+	Cache.set(cookieName, md5Crmeb, 3600);
+	let vConsole = new VConsole();
+}
+
+// let snsapiBase = 'snsapi_base';
+// Auth.isWeixin() && Auth.oAuth(snsapiBase);
+
+// 记录进入app时的url
+if (typeof window.entryUrl === 'undefined' || window.entryUrl === '') {
+	window.entryUrl = location.href
+}
+
+//全局路由前置守卫
+// #endif
+
+App.mpType = 'app'
+
+
+const app = new Vue({
+	...App,
+	store,
+	Cache,
+	i18n,
+})
+app.$mount();

+ 266 - 0
manifest.json

@@ -0,0 +1,266 @@
+{
+    "name" : "壹柒科技",
+    "appid" : "__UNI__9417D5E",
+    "description" : "壹柒科技",
+    "versionName" : "4.6.0",
+    "versionCode" : 461,
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : false,
+            "waiting" : false,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {
+            "Payment" : {},
+            "Share" : {},
+            "VideoPlayer" : {},
+            "OAuth" : {},
+            "Maps" : {}
+        },
+        "safearea" : {
+            "bottom" : {
+                "offset" : "none"
+            }
+        },
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<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.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.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.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", "arm64-v8a", "x86" ],
+                "permissionExternalStorage" : {
+                    "request" : "none",
+                    "prompt" : "应用保存运行状态等信息,需要获取读写手机存储(系统提示为访问设备上的照片、媒体内容和文件)权限,请允许。"
+                },
+                "permissionPhoneState" : {
+                    "request" : "none" //拨打电话权限关闭
+                }
+            },
+            /* ios打包配置 */
+            "ios" : {
+                "capabilities" : {
+                    "entitlements" : {
+                        "com.apple.developer.associated-domains" : [
+                            "applinks:",
+                            "applinks:",
+                            "applinks:",
+                            "applinks:static-679f0930-8f60-425c-9033-8c135f397ea5.bspapp.com"
+                        ]
+                    }
+                },
+                "privacyDescription" : {
+                    "NSLocationWhenInUseUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSPhotoLibraryUsageDescription" : "上传用户头像保存分享海报",
+                    "NSPhotoLibraryAddUsageDescription" : "上传用户头像保存分享海报",
+                    "NSLocationAlwaysAndWhenInUseUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSLocationAlwaysUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSCameraUsageDescription" : "上传用户头像保存分享海报"
+                },
+                "idfa" : false,
+                "dSYMs" : false
+            },
+            /* SDK配置 */
+            "sdkConfigs" : {
+                "payment" : {
+                    "alipay" : {
+                        "__platform__" : [ "ios", "android" ]
+                    },
+                    "weixin" : {
+                        "__platform__" : [ "ios", "android" ],
+                        "appid" : "wx277a269f3d736d67",
+                        "UniversalLinks" : "https://bzapp.crmeb.net/uni-universallinks/__UNI__A3F1ED4/"
+                    }
+                },
+                "share" : {
+                    "weixin" : {
+                        "appid" : "wx277a269f3d736d67",
+                        "UniversalLinks" : "https://bzapp.crmeb.net/uni-universallinks/__UNI__A3F1ED4/"
+                    }
+                },
+                "push" : {
+                    "unipush" : {
+                        "version" : "2",
+                        "offline" : true,
+                        "hms" : {},
+                        "oppo" : {},
+                        "vivo" : {},
+                        "mi" : {},
+                        "meizu" : {},
+                        "fcm" : {}
+                    }
+                },
+                "maps" : {
+                    "amap" : {
+                        "appkey_ios" : "aeb768547b9d752891e37e1ca0a2b66d",
+                        "appkey_android" : "a40e1e7e908aa1fa1b8ca25c8027f03a"
+                    }
+                },
+                "oauth" : {
+                    "apple" : {},
+                    "weixin" : {
+                        "appid" : "wx277a269f3d736d67",
+                        "appsecret" : "bd08741a055c2ecac5826ff1c048464b",
+                        "UniversalLinks" : "https://bzapp.crmeb.net/uni-universallinks/__UNI__A3F1ED4/"
+                    }
+                },
+                "ad" : {},
+                "geolocation" : {
+                    "amap" : {
+                        "__platform__" : [ "ios", "android" ],
+                        "appkey_ios" : "aeb768547b9d752891e37e1ca0a2b66d",
+                        "appkey_android" : "41ec5c3f4d110ce02a326210fe147be8"
+                    }
+                },
+                "statics" : {
+                    "google" : {
+                        "config_ios" : "",
+                        "config_android" : ""
+                    }
+                }
+            },
+            "splashscreen" : {
+                "androidStyle" : "common",
+                "iosStyle" : "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" : "wx1234567890",
+        "setting" : {
+            "urlCheck" : false,
+            "minified" : true,
+            "postcss" : true,
+            "es6" : true
+        },
+        "permission" : {
+            "scope.userLocation" : {
+                "desc" : "你的位置信息将用于和门店的距离长度"
+            }
+        },
+        "optimization" : {
+            "subPackages" : true
+        },
+        "usingComponents" : true,
+        "requiredPrivateInfos" : [
+            "getLocation",
+            "onLocationChange",
+            "startLocationUpdateBackground",
+            "chooseAddress"
+        ]
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "h5" : {
+        "devServer" : {
+            "proxy" : {
+                "^/frp" : {
+                    "target" : "http://yc.frp.liuniu946.com",
+                    // "target": "http://heyu.frp.liuniu946.com",
+                    "changeOrigin" : true,
+                    "pathRewrite" : {
+                        "/frp" : "" // rewrite path
+                    }
+                }
+            },
+            "https" : false
+        },
+        "router" : {
+            "mode" : "history",
+            "base" : ""
+        },
+        "domain" : "",
+        "sdkConfigs" : {
+            "maps" : {
+                "qqmap" : {
+                    "key" : "NO7BZ-APDKP-UCBD7-VT7CX-R5UZK-JBF2W"
+                }
+            }
+        },
+        "optimization" : {
+            "treeShaking" : {
+                "enable" : true
+            },
+            "subPackages" : true
+        },
+        "async" : {
+            "timeout" : 200000
+        },
+        "title" : "加载中"
+    },
+    "plus" : {
+        "statusbar" : {
+            "immersed" : true
+        }
+    },
+    "_spaceID" : "679f0930-8f60-425c-9033-8c135f397ea5",
+    "lazyCodeLoading" : "requiredComponents"
+}
+/* ios打包配置 */
+

+ 37 - 0
mixins/SendVerifyCode.js

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

+ 26 - 0
mixins/color.js

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

+ 274 - 0
mixins/sharePoster.js

@@ -0,0 +1,274 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+import {
+	imageBase64
+} from "@/api/public";
+import {
+	getProductCode, // 普通商品小程序code
+} from "@/api/store.js";
+import {
+	scombinationCode, // 拼团code
+	seckillCode // 秒杀
+} from '@/api/activity.js';
+import i18n from '../utils/lang.js';
+let sysHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
+export const sharePoster = {
+	data() {
+		return {
+			//二维码参数
+			codeShow: false,
+			cid: '1',
+			codeVal: "", // 要生成的二维码值
+			size: 200, // 二维码大小
+			unit: 'upx', // 单位
+			background: '#FFF', // 背景色
+			foreground: '#000', // 前景色
+			pdground: '#000', // 角标色
+			codeIcon: '', // 二维码图标
+			iconsize: 40, // 二维码图标大小
+			lv: 3, // 二维码容错级别 , 一般不用设置,默认就行
+			onval: true, // val值变化时自动重新生成二维码
+			loadMake: true, // 组件加载完成后自动生成二维码
+			base64Show: 0,
+			shareQrcode: 0,
+			followCode: '',
+			selectSku: {},
+			currentPage: false,
+			sysHeight: sysHeight,
+			isShow: 0,
+			storeImageBase64: ''
+		};
+	},
+	methods: {
+		qrR(res) {
+			// #ifdef H5
+			if (!this.$wechat.isWeixin() || this.shareQrcode != '1') {
+				this.PromotionCode = res;
+				this.followCode = ''
+			}
+			// #endif
+			// #ifdef APP-PLUS
+			this.PromotionCode = res;
+			// #endif
+		},
+		getImageBase64() {
+			let that = this;
+			imageBase64(that.storeImage, this.storeInfo.wechat_code)
+				.then((res) => {
+					that.storeImageBase64 = res.data.image;
+					if (this.storeInfo.wechat_code) {
+						that.PromotionCode = res.data.code;
+					}
+				})
+				.catch(() => {});
+		},
+		initPoster(arr2) {
+			let that = this;
+			uni.getImageInfo({
+				src: that.PromotionCode,
+				success() {
+					if (arr2[2] == "") {
+						//海报二维码不存在则从新下载
+						that.downloadFilePromotionCode(function(
+							msgPromotionCode) {
+							arr2[2] = msgPromotionCode;
+							if (arr2[2] == "")
+								return that.$util.Tips({
+									title: i18n.t(
+										`海报二维码生成失败`
+									),
+								});
+							that.$util.PosterCanvas(
+								arr2,
+								that.storeInfo.store_name,
+								that.storeInfo.price,
+								that.storeInfo.ot_price,
+								function(tempFilePath) {
+									that.$set(that,
+										"posterImage",
+										tempFilePath);
+									that.$set(that,
+										"posterImageStatus",
+										true);
+									that.$set(that,
+										"canvasStatus",
+										false);
+									that.$set(that,
+										"actionSheetHidden",
+										!that
+										.actionSheetHidden
+									);
+								}
+							);
+						});
+					} else {
+						//生成推广海报
+						that.$nextTick(e => {
+							that.$util.PosterCanvas(
+								arr2,
+								that.storeInfo.store_name,
+								that.storeInfo.price,
+								that.storeInfo.ot_price,
+								function(tempFilePath) {
+									that.$set(that,
+										"posterImage",
+										tempFilePath);
+									that.$set(that,
+										"posterImageStatus",
+										true);
+									that.$set(that,
+										"canvasStatus",
+										false);
+									that.$set(that,
+										"actionSheetHidden",
+										!that
+										.actionSheetHidden
+									);
+								}
+							);
+						})
+
+					}
+				},
+				fail: function(res) {
+					// #ifdef H5
+					return that.$util.Tips({
+						title: res,
+					});
+					// #endif
+					// #ifdef MP
+					return that.$util.Tips({
+						title: i18n.t(`正在下载海报,请稍后再试`),
+					});
+					// #endif
+				},
+			});
+		},
+		/**
+		 * 生成海报
+		 */
+		async goPoster(type) {
+			let that = this;
+			that.posters = false;
+			that.$set(that, "canvasStatus", true);
+			let arr2
+			// #ifdef MP
+			let met = type === 'scombination' ? scombinationCode(that.id) : type === 'seckill' ? seckillCode(
+				that
+				.id) : getProductCode(that.id)
+			met.then((res) => {
+					uni.downloadFile({
+						url: that.setDomain(res.data.code),
+						success: function(res) {
+							that.$set(that, "isDown", false);
+							that.$set(that, "PromotionCode", res.tempFilePath)
+							if (typeof successFn == "function")
+								successFn && successFn(res.tempFilePath);
+							arr2 = [that.posterbackgd, that.storeImage, that.PromotionCode];
+							that.initPoster(arr2)
+						},
+						fail: function() {
+							that.$set(that, "isDown", false);
+							that.$set(that, "PromotionCode", "");
+						},
+					});
+				})
+				.catch((err) => {
+					that.$set(that, "isDown", false);
+					that.$set(that, "PromotionCode", "");
+					return that.$util.Tips({
+						title: err,
+					});
+				});
+			// #endif
+			// #ifdef H5 || APP-PLUS
+			arr2 = [that.posterbackgd, that.storeImageBase64, that.PromotionCode];
+			console.log(arr2)
+			if (!that.storeImageBase64)
+				return that.$util.Tips({
+					title: i18n.t(`正在下载海报,请稍后再试`),
+				});
+			that.initPoster(arr2)
+			// #endif
+		},
+		//替换安全域名
+		setDomain(url) {
+			url = url ? url.toString() : "";
+			//本地调试打开,生产请注销
+			if (url.indexOf("https://") > -1) return url;
+			else return url.replace("http://", "https://");
+		},
+		//获取海报产品图
+		downloadFilestoreImage() {
+			let that = this;
+			uni.downloadFile({
+				url: that.setDomain(that.storeInfo.image),
+				success: function(res) {
+					that.storeImage = res.tempFilePath;
+					that.storeImageBase64 = res.tempFilePath;
+				},
+				fail: function() {
+					return that.$util.Tips({
+						title: "",
+					});
+					that.storeImage = "";
+				},
+			});
+		},
+		/**
+		 * 获取产品分销二维码
+		 * @param function successFn 下载完成回调
+		 *
+		 */
+		downloadFilePromotionCode(successFn) {
+			let that = this;
+			// #ifdef MP
+			getProductCode(that.id)
+				.then((res) => {
+					uni.downloadFile({
+						url: that.setDomain(res.data.code),
+						success: function(res) {
+							that.$set(that, "isDown", false);
+							that.$set(that, "PromotionCode", res.tempFilePath)
+							if (typeof successFn == "function")
+								successFn && successFn(res.tempFilePath);
+						},
+						fail: function() {
+							that.$set(that, "isDown", false);
+							that.$set(that, "PromotionCode", "");
+						},
+					});
+				})
+				.catch((err) => {
+					that.$set(that, "isDown", false);
+					that.$set(that, "PromotionCode", "");
+					return that.$util.Tips({
+						title: err,
+					});
+				});
+			// #endif
+			// #ifdef APP-PLUS
+			uni.downloadFile({
+				url: that.setDomain(that.PromotionCode),
+				success: function(res) {
+					that.$set(that, "isDown", false);
+					if (typeof successFn == "function")
+						successFn && successFn(res.tempFilePath);
+					else that.$set(that, "PromotionCode", res.tempFilePath);
+				},
+				fail: function() {
+					that.$set(that, "isDown", false);
+					that.$set(that, "PromotionCode", "");
+				},
+			});
+			// #endif
+		},
+	}
+};

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

+ 1722 - 0
pages.json

@@ -0,0 +1,1722 @@
+{
+	"pages": [ //pages数组中第一项表示应用启动页
+		{
+			"path": "pages/guide/index",
+			"style": {
+				"app-plus": {
+					"titleNView": false //禁用原生导航栏
+				}
+			}
+		},
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationStyle": "custom",
+				"navigationBarTextStyle": "white",
+				"app-plus": {
+					"scrollIndicator": "none"
+				}
+			}
+		},
+		{
+			"path": "pages/order_addcart/order_addcart",
+			"style": {
+				"navigationBarTitleText": "购物车",
+				"app-plus": {
+					// #ifdef APP-PLUS
+					"titleNView": {
+						"type": "default"
+					}
+					// #endif
+				}
+
+			}
+		},
+		{
+			"path": "pages/user/index",
+			"style": {
+
+				"navigationBarTitleText": "个人中心",
+				"enablePullDownRefresh": true
+					// #ifdef MP || APP-PLUS
+					,
+				"navigationStyle": "custom",
+				// "navigationBarBackgroundColor": "#e93323",
+				"navigationBarTextStyle": "black"
+				// #endif
+			}
+		},
+		{
+			"path": "pages/goods_cate/goods_cate",
+			"style": {
+				"navigationBarTitleText": "商品分类",
+				"app-plus": {
+					// #ifdef APP-PLUS
+					"titleNView": {
+						"type": "default"
+					}
+					// #endif
+				}
+
+			}
+		},
+		{
+			"path": "pages/renttab/index",
+			"style": {
+				"navigationBarTitleText": "商城",
+				"app-plus": {
+					// #ifdef APP-PLUS
+					"titleNView": {
+						"type": "default"
+					}
+					// #endif
+				}
+			}
+		}
+	],
+	"subPackages": [{ // 模块分包
+			"root": "pages/rent",
+			"name": "rent",
+			"pages": [{
+					"path": "carpay/carDetail",
+					"style": {
+						"navigationBarTitleText": "商品详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "carpay/paySuccess",
+					"style": {
+						"navigationBarTitleText": "支付成功",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "order/orderList",
+					"style": {
+						"navigationBarTitleText": "我的服务",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "order/orderDetail",
+					"style": {
+						"navigationBarTitleText": "服务详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "order/onBindCar",
+					"style": {
+						"navigationBarTitleText": "绑定车辆",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "mycar/index",
+					"style": {
+						"navigationBarTitleText": "我的车辆",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "control/route",
+					"style": {
+						"navigationBarTitleText": "行程记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "control/routeDetail",
+					"style": {
+						"navigationBarTitleText": "路径详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "control/authList",
+					"style": {
+						"navigationBarTitleText": "授权列表",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "control/auth",
+					"style": {
+						"navigationBarTitleText": "车辆授权",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		}, { // 模块分包
+			"root": "pages/extension",
+			"name": "extension",
+			"pages": [{
+					"path": "customer_list/chat",
+					"style": {
+						"navigationBarTitleText": "对话详情",
+						"navigationStyle": "custom",
+						"app-plus": {
+							"scrollIndicator": false //禁用原生导航栏
+								// #ifdef APP-PLUS
+								,
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						},
+						"disableScroll": true
+					}
+				},
+				{
+					"path": "news_list/index",
+					"style": {
+						"navigationBarTitleText": "资讯",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "news_details/index",
+					"style": {
+						"navigationBarTitleText": "资讯详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		}, {
+			"root": "pages/goods",
+			"name": "goods",
+			"pages": [{
+					"path": "goods_list/index",
+					"style": {
+						"navigationBarTitleText": "商品列表",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "goods_search/index",
+					"style": {
+						"navigationBarTitleText": "搜索商品",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "order_pay_status/index",
+					"style": {
+						"navigationBarTitleText": "支付成功",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "admin_order_detail/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/lottery_comment",
+					"style": {
+						"navigationBarTitleText": "订单评价",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "goods_comment_list/index",
+					"style": {
+						"navigationBarTitleText": "商品评分",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "goods_details_store/index",
+					"style": {
+						"navigationBarTitleText": "门店列表",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "goods_logistics/index",
+					"style": {
+						"navigationBarTitleText": "物流信息",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "goods_return/index",
+					"style": {
+						"navigationBarTitleText": "申请退货",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "goods_return_list/index",
+					"style": {
+						"navigationBarTitleText": "退货列表",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "lottery/grids/index",
+					"style": {
+						"navigationBarTitleText": "抽奖活动",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "lottery/grids/record",
+					"style": {
+						"navigationBarTitleText": "中奖记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "order_confirm/index",
+					"style": {
+						"navigationBarTitleText": "提交订单",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "order_details/index",
+					"style": {
+						"navigationBarTitleText": "订单详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "order_list/index",
+					"style": {
+						"navigationBarTitleText": "我的订单",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "order_refund_goods/index",
+					"style": {
+						"navigationBarTitleText": "退回商品",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		}, {
+			"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": {
+						"navigationBarTitleText": "消息中心",
+						"enablePullDownRefresh": true,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "message_center/messageDetail",
+					"style": {
+						"navigationBarTitleText": "消息详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_invoice_order/index",
+					"style": {
+						"navigationBarTitleText": "订单详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "scan_login/index",
+					"style": {
+						"navigationBarTitleText": "授权登录"
+					}
+				},
+				{
+					"path": "user_invoice_list/index",
+					"style": {
+						"navigationBarTitleText": "发票管理",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_invoice_form/index",
+					"style": {
+						"navigationBarTitleText": "添加新发票",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				//#ifdef H5
+				{
+					"path": "alipay_invoke/index",
+					"style": {
+						"navigationBarTitleText": "支付提示"
+					}
+				},
+				//#endif
+				{
+					"path": "wechat_login/index",
+					"style": {
+						"navigationBarTitleText": "账户登录",
+						"navigationStyle": "custom",
+						"app-plus": {
+							"scrollIndicator": false //禁用原生导航栏
+						}
+					}
+				},
+				{
+					"path": "retrievePassword/index",
+					"style": {
+						"navigationBarTitleText": "忘记密码",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_info/index",
+					"style": {
+						"navigationBarTitleText": "个人资料",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_get_coupon/index",
+					"style": {
+						"navigationBarTitleText": "领取优惠券",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "visit_list/index",
+					"style": {
+						"navigationBarTitleText": "浏览记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_goods_collection/index",
+					"style": {
+						"navigationBarTitleText": "收藏商品",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_sgin/index",
+					"style": {
+						"navigationBarTitleText": "签到",
+						// #ifdef MP
+						// "navigationBarTextStyle": "white",
+						// "navigationBarBackgroundColor": "#e93323"
+						// #endif
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_sgin_list/index",
+					"style": {
+						"navigationBarTitleText": "签到记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_money/index",
+					"style": {
+						"navigationBarTitleText": "我的账户",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_bill/index",
+					"style": {
+						"navigationBarTitleText": "账单明细",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_integral/index",
+					"style": {
+						"navigationBarTitleText": "积分详情"
+
+							// #ifdef MP
+							,
+						"navigationBarTextStyle": "black",
+						"navigationBarBackgroundColor": "#FFFFFF"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_coupon/index",
+					"style": {
+						"navigationBarTitleText": "我的优惠券",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_spread_user/index",
+					"style": {
+						"navigationBarTitleText": "我的推广"
+
+							// #ifdef MP
+							,
+						"navigationBarTextStyle": "black",
+						"navigationBarBackgroundColor": "#FFFFFF"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_spread_code/index",
+					"style": {
+						"navigationBarTitleText": "分销海报",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_spread_money/index",
+					"style": {
+						"navigationBarTitleText": "佣金记录"
+
+							// #ifdef MP
+							,
+						"navigationBarTextStyle": "black",
+						"navigationBarBackgroundColor": "#FFFFFF"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_cash/index",
+					"style": {
+						"navigationBarTitleText": "提现",
+						"navigationBarBackgroundColor": "#FFFFFF"
+							// #ifdef MP || APP-PLUS
+							,
+						"navigationBarTextStyle": "black"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_vip/index",
+					"style": {
+						"navigationBarTitleText": "我的等级",
+						"navigationBarBackgroundColor": "#232323"
+							// #ifdef MP || APP-PLUS
+							,
+						"navigationBarTextStyle": "white"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "user_distribution_level/index",
+					"style": {
+						"navigationBarTitleText": "分销等级",
+						"navigationBarBackgroundColor": "#232323"
+							// #ifdef MP || APP-PLUS
+							,
+						"navigationBarTextStyle": "white"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_address_list/index",
+					"style": {
+						"navigationBarTitleText": "地址管理",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_address/index",
+					"style": {
+						"navigationBarTitleText": "添加地址",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_phone/index",
+					"style": {
+						"navigationBarTitleText": "绑定手机",
+
+						// #ifdef MP
+						// "navigationBarTextStyle": "white",
+						// "navigationBarBackgroundColor": "#e93323"
+						// #endif
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_payment/index",
+					"style": {
+						"navigationBarTitleText": "余额充值",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_pwd_edit/index",
+					"style": {
+						"navigationBarTitleText": "修改密码"
+
+							// #ifdef MP
+							// 	,
+							// "navigationBarTextStyle": "white"
+							// "navigationBarBackgroundColor": "#e93323"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "promoter-list/index",
+					"style": {
+						"navigationBarTitleText": "推广人列表"
+							// #ifdef MP
+							,
+						"navigationBarBackgroundColor": "#FFFFFF",
+						"navigationBarTextStyle": "black"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "promoter-order/index",
+					"style": {
+						"navigationBarTitleText": "推广人订单"
+
+							// #ifdef MP
+							,
+						"navigationBarTextStyle": "black",
+						"navigationBarBackgroundColor": "#FFFFFF"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "promoter_rank/index",
+					"style": {
+						"navigationBarTitleText": "推广人排行"
+
+							// #ifdef MP
+							,
+						"navigationBarTextStyle": "black",
+						"navigationBarBackgroundColor": "#FFFFFF"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "commission_rank/index",
+					"style": {
+						"navigationBarTitleText": "佣金排行",
+						"navigationBarBackgroundColor": "#FFFFFF"
+							// #ifdef MP || APP-PLUS
+							,
+						"navigationBarTextStyle": "black"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_return_list/index",
+					"style": {
+						"navigationBarTitleText": "退货列表",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "login/index",
+					"style": {
+						"navigationBarTitleText": "登录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "payment_on_behalf/index",
+					"style": {
+						"navigationBarTitleText": "好友代付",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "payment_on_behalf/pay_status",
+					"style": {
+						"navigationBarTitleText": "代付成功",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "staff_list/index",
+					"style": {
+						"navigationBarTitleText": "员工列表",
+						"navigationBarBackgroundColor": "#e93323"
+							// #ifdef MP
+							,
+						"navigationBarTextStyle": "#fff"
+						// #endif
+					}
+				}
+				// #ifdef H5
+				,
+				{
+					"path": "auth/index",
+					"style": {
+						"navigationBarTitleText": ""
+					}
+				}
+				// #endif
+			],
+			"plugins": {
+				"live-player-plugin": {
+					"version": "1.3.5",
+					"provider": "wx2b03c6e691cd7370"
+				}
+			}
+		},
+		{
+			"root": "pages/goods_details",
+			"name": "goods_details",
+			"pages": [{
+				"path": "index",
+				"style": {
+					"navigationStyle": "custom",
+					"transparentTitle": "auto",
+					"app-plus": {
+						// #ifdef APP-PLUS
+						"titleNView": {
+							"padding-left": "10px",
+							"padding-right": "10px",
+							"type": "transparent",
+							"buttons": [ //原生标题栏按钮配置,
+								{
+									"type": "menu" //原生标题栏增加分享按钮,点击事件可通过页面的 onNavigationBarButtonTap 函数进行监听
+								}
+							]
+						}
+						// #endif
+					}
+				}
+			}]
+		},
+		{
+			"root": "pages/activity",
+			"name": "activity",
+			"pages": [{
+					"path": "goods_bargain/index",
+					"style": {
+						// #ifdef MP
+						// "navigationBarTextStyle": "white",
+						// "navigationBarBackgroundColor": "#E93323",
+						"navigationBarTitleText": "砍价列表",
+						// #endif
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "goods_bargain_details/index",
+					"style": {
+						// #ifdef MP
+						"navigationBarTitleText": "砍价活动",
+						// #endif
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "goods_combination/index",
+					"style": {
+						// #ifdef MP
+						// "navigationBarTextStyle": "white",
+						// "navigationBarBackgroundColor": "#E93323",
+						"navigationBarTitleText": "拼团活动",
+						// #endif
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "goods_combination_details/index",
+					"style": {
+						"navigationStyle": "custom",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"padding-left": "10px",
+								"padding-right": "10px",
+								"type": "transparent",
+								"buttons": [ //原生标题栏按钮配置,
+									{
+										"type": "menu" //原生标题栏增加分享按钮,点击事件可通过页面的 onNavigationBarButtonTap 函数进行监听
+									}
+								]
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "goods_combination_status/index",
+					"style": {
+						"navigationBarTitleText": "拼团",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "goods_seckill/index",
+					"style": {
+						"navigationBarTitleText": "限时秒杀"
+							// #ifdef MP
+							// "navigationBarTextStyle": "white"
+							// "navigationBarBackgroundColor": "#e93323"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "goods_seckill_details/index",
+					"style": {
+						"navigationStyle": "custom"
+							// #ifdef MP
+							,
+						"navigationBarTextStyle": "white"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"padding-left": "10px",
+								"padding-right": "10px",
+								"type": "transparent",
+								"buttons": [ //原生标题栏按钮配置,
+									{
+										"type": "menu" //原生标题栏增加分享按钮,点击事件可通过页面的 onNavigationBarButtonTap 函数进行监听
+									}
+								]
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "poster-poster/index",
+					"style": {
+						"navigationBarTitleText": "砍价海报"
+							// #ifdef MP
+							// "navigationBarTextStyle": "white"
+							// "navigationBarBackgroundColor": "#d22516"
+							// #endif
+							,
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "bargain/index",
+					"style": {
+						"navigationBarTitleText": "砍价记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "presell/index",
+					"style": {
+						"navigationBarTitleText": "预售列表",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/admin",
+			"name": "adminOrder",
+			"pages": [{
+					"path": "custom_date/index",
+					"style": {
+						"navigationBarTitleText": "选择日期"
+					}
+				},
+				{
+					"path": "order/index",
+					"style": {
+						"navigationBarTitleText": "订单统计",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "orderList/index",
+					"style": {
+						"navigationBarTitleText": "订单列表",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "orderDetail/index",
+					"style": {
+						"navigationBarTitleText": "订单详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "delivery/index",
+					"style": {
+						"navigationBarTitleText": "订单发货",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "statistics/index",
+					"style": {
+						"navigationBarTitleText": "订单数据统计",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "order_cancellation/index",
+					"style": {
+						"navigationBarTitleText": "订单核销",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/columnGoods",
+			"name": "columnGoods",
+			"pages": [{
+					"path": "HotNewGoods/index",
+					"style": {
+						"navigationBarTitleText": "精品推荐",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "HotNewGoods/feedback",
+					"style": {
+						"navigationBarTitleText": "我的客服",
+						"navigationBarTextStyle": "white",
+						"navigationBarBackgroundColor": "#3A3A3A",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "live_list/index",
+					"style": {
+						"navigationBarTitleText": "精彩内容"
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/annex",
+			"pages": [{
+					"path": "web_view/index",
+					"style": {
+						"navigationBarTitleText": "",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "vip_paid/index",
+					"style": {
+						"navigationBarTitleText": "SVIP会员",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "vip_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
+						}
+
+					}
+				},
+				{
+					"path": "settled/index",
+					"style": {
+						"navigationBarTitleText": "代理商申请",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/points_mall",
+			"pages": [{
+					"path": "index",
+					"style": {
+						"navigationBarTextStyle": "white",
+						"navigationBarBackgroundColor": "#333333",
+						"navigationBarTitleText": "积分商城",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "integral_goods_list",
+					"style": {
+						"navigationBarTitleText": "商品列表",
+						// "navigationBarTextStyle": "white",
+						// "navigationBarBackgroundColor": "#E93323",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "integral_goods_details",
+					"style": {
+						"navigationStyle": "custom",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"padding-left": "10px",
+								"padding-right": "10px",
+								"type": "transparent",
+								"buttons": [ //原生标题栏按钮配置,
+									{
+										"type": "menu" //原生标题栏增加分享按钮,点击事件可通过页面的 onNavigationBarButtonTap 函数进行监听
+									}
+								]
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "exchange_record",
+					"style": {
+						"navigationBarTitleText": "兑换记录",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "integral_order",
+					"style": {
+						"navigationBarTitleText": "积分订单",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "user_address",
+					"style": {
+						"navigationBarTitleText": "选择地址",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "integral_order_status",
+					"style": {
+						"navigationBarTitleText": "兑换成功",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "integral_order_details",
+					"style": {
+						"navigationBarTitleText": "兑换订单详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}, {
+					"path": "logistics_details",
+					"style": {
+						"navigationBarTitleText": "兑换物流详情",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				}
+			]
+		}
+	],
+	"tabBar": { // 底部菜单
+		"color": "#282828",
+		"selectedColor": "#ff3366",
+		"borderStyle": "white",
+		"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/order_addcart/order_addcart",
+				"iconPath": "static/images/3-001.png",
+				"selectedIconPath": "static/images/3-002.png",
+				"text": "购物车"
+			},
+			{
+				"pagePath": "pages/user/index",
+				"iconPath": "static/images/4-001.png",
+				"selectedIconPath": "static/images/4-002.png",
+				"text": "我的"
+			}
+		]
+	},
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "加载中",
+		"navigationBarBackgroundColor": "#fff",
+		"backgroundColor": "#F8F8F8",
+		"titleNView": false
+	},
+	"condition": { //模式配置,仅开发期间生效
+		"current": 0, //当前激活的模式(list 的索引项)
+		"list": [{
+			"name": "", //模式名称
+			"path": "", //启动页面,必选
+			"query": "" //启动参数,在页面的onLoad函数里面得到
+		}]
+	}
+}

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

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

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


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


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

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

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


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

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

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

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

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


+ 430 - 0
pages/activity/poster-poster/index.vue

@@ -0,0 +1,430 @@
+<template>
+	<view class="posterCon" :style="colorStyle">
+		<view class='poster-poster'>
+			<view class='tip'><text class='iconfont icon-shuoming'></text>{{$t(`提示:点击图片即可保存至手机相册`)}}</view>
+			<view class='pictrue'>
+				<!-- <image :src='image' mode="widthFix"></image> -->
+				<image class="canvas" :src="posterImage" v-if="posterImage" @click="savePosterPathMp(posterImage)">
+				</image>
+				<canvas class="canvas" canvas-id="myCanvas" v-else></canvas>
+			</view>
+		</view>
+		<!-- #ifdef H5 || APP-PLUS -->
+		<zb-code ref="qrcode" :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 -->
+	</view>
+</template>
+
+<script>
+	import zbCode from '@/components/zb-code/zb-code.vue'
+	import {
+		getBargainPoster,
+		getCombinationPoster,
+		getBargainPosterData,
+		getCombinationPosterData
+	} from '@/api/activity.js';
+	import {
+		getUserInfo,
+		imgToBase,
+		routineCode
+	} from '@/api/user.js';
+	// #ifdef APP-PLUS
+	import {
+		TOKENNAME,
+		HTTP_REQUEST_URL
+	} from '@/config/app.js';
+	// #endif
+	import colors from '@/mixins/color.js'
+	export default {
+		components: {
+			zbCode
+		},
+		mixins: [colors],
+		data() {
+			return {
+				canvasStatus: true,
+				posterImage: "",
+				parameter: {
+					'navbar': '1',
+					'return': '1',
+					'title': this.$t(`拼团海报`),
+					'color': true,
+					'class': '0'
+				},
+				type: 0,
+				id: 0,
+				bargain: 0,
+				image: '',
+				from: '',
+				uid: "",
+				//二维码参数
+				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: "",
+				wd: 0,
+				hg: 0,
+				posterBag: "../static/posterBag.png",
+				mpUrl: "",
+			}
+		},
+		onLoad(options) {
+			// #ifdef MP
+			this.from = 'routine'
+			// #endif
+			// #ifdef H5 || APP-PLUS
+			this.from = 'wechat'
+			// #endif
+
+			var that = this;
+			if (options.hasOwnProperty('type') && options.hasOwnProperty('id')) {
+				this.type = options.type
+				this.id = options.id
+				if (options.type == 1) {
+					this.bargain = options.bargain
+					uni.setNavigationBarTitle({
+						title: that.$t(`砍价海报`)
+					})
+				} else {
+					uni.setNavigationBarTitle({
+						title: that.$t(`拼团海报`)
+					})
+				}
+			} else {
+				return app.Tips({
+					title: that.$t(`参数错误`),
+					icon: 'none'
+				}, {
+					tab: 3,
+					url: 1
+				});
+			}
+
+		},
+		onReady() {
+			// #ifdef H5
+			if (this.type == 1) {
+				this.val = window.location.origin + '/pages/activity/goods_bargain_details/index?id=' + this.id +
+					'&bargain=' +
+					this.$store.state.app.uid +
+					'&spread=' +
+					this.$store.state.app.uid
+			} else if (this.type == 2) {
+				this.val = window.location.origin + '/pages/activity/goods_combination_status/index?id=' + this.id +
+					'&spread=' +
+					this.$store.state.app.uid
+			}
+			// #endif
+			// #ifdef APP-PLUS
+			if (this.type == 1) {
+				this.val = HTTP_REQUEST_URL + '/pages/activity/goods_bargain_details/index?id=' + this.id + '&bargain=' +
+					this.$store.state.app.uid +
+					'&spread=' +
+					this.$store.state.app.uid
+			} else if (this.type == 2) {
+				this.val = HTTP_REQUEST_URL + '/pages/activity/goods_combination_status/index?id=' + this.id +
+					'&spread=' +
+					this.$store.state.app.uid
+			}
+			// #endif
+			setTimeout(e => {
+				this.getPosterInfo();
+			}, 200)
+			this.$nextTick(function() {
+				let selector = uni.createSelectorQuery().select('.pictrue');
+				selector.fields({
+					size: true
+				}, data => {
+					this.wd = data.width
+					this.hg = data.height
+				}).exec();
+			})
+			this.routineCode()
+
+
+		},
+		methods: {
+			async getPosterInfo() {
+				var that = this,
+					url = '';
+				let data = {
+					id: that.id,
+					'from': that.from
+				};
+				let userData = await getUserInfo()
+				this.uid = userData.data.uid
+				let goods_img, mp_code, resData, arr, mpUrl
+				// #ifdef MP
+				// #endif
+				uni.showLoading({
+					title: that.$t(`海报生成中`),
+					mask: true
+				});
+				if (that.type == 1) {
+					await getBargainPosterData(that.id).then(res => {
+						resData = res.data
+					}).catch(err => {
+						that.$util.Tips({
+							title: that.$t(`海报图片获取失败`)
+						});
+						return
+					})
+				} else {
+					await getCombinationPosterData(that.id).then(res => {
+						resData = res.data
+					}).catch(err => {
+						that.$util.Tips({
+							title: that.$t(`海报图片获取失败`)
+						});
+						return
+					})
+				}
+
+				// #ifdef H5 || APP-PLUS
+				let imgData = await this.imgToBase(resData.image, resData.url)
+				arr = [this.posterBag, imgData.image, imgData.code || this.codeSrc]
+				// #endif
+				// #ifdef MP
+				mpUrl = resData.url ? await this.downloadFilestoreImage(resData.url) : await this
+					.downloadFilestoreImage(this.mpUrl)
+				arr = [this.posterBag, await this.downloadFilestoreImage(resData.image), mpUrl]
+				// #endif
+				this.$nextTick((e) => {
+					that.$util.bargainPosterCanvas(arr, resData.title, resData.label, resData.msg, resData
+						.price,
+						this.wd,
+						this.hg,
+						(tempFilePath) => {
+							this.posterImage = tempFilePath
+						});
+				})
+			},
+			async routineCode() {
+				let res = await routineCode()
+				this.mpUrl = res.data.url
+			},
+			//图片转符合安全域名路径
+			downloadFilestoreImage(url) {
+				url = this.setDomain(url)
+				return new Promise((resolve, reject) => {
+					let that = this;
+					uni.downloadFile({
+						url: url,
+						success: function(res) {
+							resolve(res.tempFilePath);
+						},
+						fail: function() {
+							return that.$util.Tips({
+								title: ''
+							});
+						}
+					});
+				})
+			},
+			//替换安全域名
+			setDomain: function(image, url) {
+				url = url ? url.toString() : '';
+				//本地调试打开,生产请注销
+				if (url.indexOf('https://') > -1) return url;
+				else return url.replace('http://', 'https://');
+			},
+			async imgToBase(image, url) {
+				let res = await imgToBase({
+					image: image,
+					code: url
+				})
+
+				return res.data
+			},
+			downloadImg() {
+
+			},
+			savePosterPathMp(url) {
+				let that = this;
+				// #ifdef APP-PLUS
+				uni.saveImageToPhotosAlbum({
+					filePath: url,
+					success: function(res) {
+						that.$util.Tips({
+							title: that.$t(`保存成功`),
+							icon: 'success'
+						});
+					},
+					fail: function(res) {
+						that.$util.Tips({
+							title: that.$t(`保存失败`)
+						});
+					}
+				});
+				// #endif
+				// #ifdef MP
+				uni.getSetting({
+					success(res) {
+						if (!res.authSetting['scope.writePhotosAlbum']) {
+							uni.authorize({
+								scope: 'scope.writePhotosAlbum',
+								success() {
+									uni.saveImageToPhotosAlbum({
+										filePath: url,
+										success: function(res) {
+											that.$util.Tips({
+												title: that.$t(`保存成功`),
+												icon: 'success'
+											});
+										},
+										fail: function(res) {
+											that.$util.Tips({
+												title: that.$t(`保存失败`)
+											});
+										}
+									});
+								},
+								fail: function(res) {
+									that.$util.Tips({
+										title: that.$t(`enable_file_access`)
+									});
+								}
+							});
+						} else {
+							uni.saveImageToPhotosAlbum({
+								filePath: url,
+								success: function(res) {
+									that.$util.Tips({
+										title: that.$t(`保存成功`),
+										icon: 'success'
+									});
+								},
+								fail: function(res) {
+									that.$util.Tips({
+										title: that.$t(`保存失败`)
+									});
+								}
+							});
+						}
+					}
+				});
+				// #endif
+				// #ifdef H5
+				// 创建隐藏的可下载链接
+				var eleLink = document.createElement('a');
+				eleLink.download = that.$t(`海报`);
+				eleLink.href = url;
+				// 触发点击
+				document.body.appendChild(eleLink);
+				eleLink.click();
+				// #endif
+			},
+			qrR(res) {
+				this.codeSrc = res
+			},
+			// #ifdef MP
+			savePosterPath: function() {
+				let that = this;
+				uni.getSetting({
+					success(res) {
+						if (!res.authSetting['scope.writePhotosAlbum']) {
+							uni.authorize({
+								scope: 'scope.writePhotosAlbum',
+								success() {
+									uni.saveImageToPhotosAlbum({
+										filePath: that.posterImage,
+										success: function(res) {
+											that.posterImageClose();
+											that.$util.Tips({
+												title: that.$t(`保存成功`),
+												icon: 'success'
+											});
+										},
+										fail: function(res) {
+											that.$util.Tips({
+												title: that.$t(`保存失败`)
+											});
+										}
+									});
+								}
+							});
+						} else {
+							uni.saveImageToPhotosAlbum({
+								filePath: that.posterImage,
+								success: function(res) {
+									that.posterImageClose();
+									that.$util.Tips({
+										title: that.$t(`保存成功`),
+										icon: 'success'
+									});
+								},
+								fail: function(res) {
+									that.$util.Tips({
+										title: that.$t(`保存失败`)
+									});
+								}
+							});
+						}
+					}
+				});
+			},
+			// #endif
+		}
+	}
+</script>
+
+<style>
+	.posterCon {
+		position: fixed;
+		top: 0;
+		width: 100%;
+		left: 0;
+		height: 100%;
+		background-color: var(--view-theme);
+		bottom: 0;
+		overflow-y: auto;
+	}
+
+	.poster-poster .tip {
+		height: 80rpx;
+		font-size: 26rpx;
+		color: #e8c787;
+		text-align: center;
+		line-height: 80rpx;
+		user-select: none;
+	}
+
+	.poster-poster .tip .iconfont {
+		font-size: 36rpx;
+		vertical-align: -4rpx;
+		margin-right: 18rpx;
+	}
+
+	.canvas {
+		width: 100%;
+		height: 1100rpx;
+	}
+
+	.poster-poster .pictrue {
+		width: 700rpx;
+		/* height: 100%; */
+		margin: 0 auto 50rpx auto;
+		display: flex;
+		justify-content: center;
+	}
+
+	.poster-poster .pictrue image {
+		width: 100%;
+		/* height: 100%; */
+
+	}
+</style>

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


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


BIN
pages/activity/static/bargainBg.jpg


BIN
pages/activity/static/buled.png


BIN
pages/activity/static/bulet.jpg


BIN
pages/activity/static/couponBg.png


BIN
pages/activity/static/greend.png


BIN
pages/activity/static/greent.jpg


BIN
pages/activity/static/groupLine.png


BIN
pages/activity/static/lightning.png


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