cmy il y a 1 an
Parent
commit
58d6313bd0
100 fichiers modifiés avec 20831 ajouts et 3538 suppressions
  1. 5 6
      .gitignore
  2. 361 265
      App.vue
  3. 28 0
      androidPrivacy.json
  4. 196 164
      api/activity.js
  5. 187 0
      api/admin.js
  6. 453 0
      api/api.js
  7. 0 66
      api/functionalUnit.js
  8. 0 65
      api/index.js
  9. 162 0
      api/kefu.js
  10. 0 64
      api/login.js
  11. 43 0
      api/lottery.js
  12. 349 111
      api/order.js
  13. 18 0
      api/points_mall.js
  14. 0 186
      api/product.js
  15. 280 0
      api/public.js
  16. 0 36
      api/set.js
  17. 0 196
      api/shop.js
  18. 277 0
      api/store.js
  19. 660 211
      api/user.js
  20. 0 140
      api/wallet.js
  21. 0 37
      api/wx.js
  22. 248 0
      components/Authorize.vue
  23. 57 0
      components/Loading/index.vue
  24. 186 0
      components/addressWindow/index.vue
  25. 237 0
      components/cartList/index.vue
  26. 199 0
      components/catGoodList/index.vue
  27. 128 0
      components/countDown/index.vue
  28. 286 0
      components/couponListWindow/index.vue
  29. 243 0
      components/couponWindow/index.vue
  30. 160 0
      components/cusPreviewImg/index.vue
  31. 150 0
      components/cusPreviewImg/swiperPrevie.vue
  32. 222 0
      components/easy-loadimage/easy-loadimage.vue
  33. 313 0
      components/eidtUserModal/index.vue
  34. 0 18
      components/empty/empty.vue
  35. 42 0
      components/emptyPage.vue
  36. 230 0
      components/goodClass/index.vue
  37. 171 0
      components/goodList/index.vue
  38. 142 0
      components/guide/index.vue
  39. 131 0
      components/home/index.vue
  40. 196 0
      components/homeList/index.vue
  41. 189 0
      components/indexGoods/index.vue
  42. 807 0
      components/jyf-parser/jyf-parser.vue
  43. 102 0
      components/jyf-parser/libs/CssHandler.js
  44. 577 0
      components/jyf-parser/libs/MpHtmlParser.js
  45. 80 0
      components/jyf-parser/libs/config.js
  46. 35 0
      components/jyf-parser/libs/handler.sjs
  47. 44 0
      components/jyf-parser/libs/handler.wxs
  48. 468 0
      components/jyf-parser/libs/trees.vue
  49. 84 0
      components/kefuIcon/index.vue
  50. 300 0
      components/menuIcon.vue
  51. 160 0
      components/numberScroll.vue
  52. 352 0
      components/orderGoods/index.vue
  53. 233 0
      components/pageFooter/index.vue
  54. 33 0
      components/pageLoading.vue
  55. 103 0
      components/parabolaBall/ParabolaBall.vue
  56. 558 0
      components/payment/index.vue
  57. 206 0
      components/privacyAgreementPopup/index.vue
  58. 195 0
      components/productConSwiper/index.vue
  59. 429 0
      components/productWindow/index.vue
  60. 120 0
      components/promotionGood/index.vue
  61. 160 0
      components/recommend/index.vue
  62. 158 0
      components/shareRedPackets/index.vue
  63. 190 0
      components/skeleton/index.vue
  64. 52 0
      components/swipers/index.vue
  65. 185 0
      components/tabNav.vue
  66. 324 0
      components/tuiDrawer/index.vue
  67. 427 0
      components/update/app-update.vue
  68. BIN
      components/update/images/close.png
  69. BIN
      components/update/images/img.png
  70. BIN
      components/update/images/round.png
  71. BIN
      components/update/images/update-img.png
  72. 147 0
      components/userEvaluation/index.vue
  73. 0 1355
      components/wangding-pickerAddress/data.js
  74. 0 103
      components/wangding-pickerAddress/wangding-pickerAddress.vue
  75. 923 0
      components/zb-code/qrcode.js
  76. 210 0
      components/zb-code/zb-code.vue
  77. 38 0
      config/app.js
  78. 42 0
      config/cache.js
  79. 18 0
      config/socket.js
  80. 77 0
      libs/chat.js
  81. 0 39
      libs/log.js
  82. 127 0
      libs/login.js
  83. 99 0
      libs/new_chat.js
  84. 42 0
      libs/order.js
  85. 251 0
      libs/routine.js
  86. 352 0
      libs/uniApi.js
  87. 328 0
      libs/wechat.js
  88. 84 5
      main.js
  89. 142 92
      manifest.json
  90. 41 0
      mixins/SendVerifyCode.js
  91. 26 0
      mixins/color.js
  92. 273 0
      mixins/sharePoster.js
  93. 399 0
      package-lock.json
  94. 0 19
      package.json
  95. 1515 360
      pages.json
  96. 262 0
      pages/activity/bargain/index.vue
  97. 81 0
      pages/activity/goods_bargain/index.vue
  98. 370 0
      pages/activity/goods_bargain_details/index.vue
  99. 367 0
      pages/activity/goods_combination/index.vue
  100. 1686 0
      pages/activity/goods_combination_details/index.vue

+ 5 - 6
.gitignore

@@ -1,6 +1,5 @@
-.DS_Store
-unpackage/dist
-unpackage/release
-unpackage/debug
-unpackage/cache
-.hbuilderx
+/unpackage/dist
+/unpackage/chart
+/unpackage
+/.hbuilderx
+/node_modules

+ 361 - 265
App.vue

@@ -1,288 +1,384 @@
 <script>
-/**
- * vuex管理登陆状态,具体可以参考官方登陆模板示例
- */
-import { mapMutations } from 'vuex';
-// #ifdef H5
-import { weixindata, setRouter } from './utils/wxAuthorized';
-// #endif
-// #ifdef APP-PLUS
-import { getUpApp } from './utils/upApp.js';
-// #endif
-export default {
-	data() {
-		return {
-			/* 保存微信信息 */
-			appData: {}
-		};
-	},
-	methods: {
-		...mapMutations('user', ['setUserInfo', 'login', 'hasLogin']),
-		...mapMutations('shop', ['setShopInfo','setShopAction']),
-		...mapMutations(['setFirstUse'])
-	},
-	onLaunch: function(urlObj) {
-		console.log('开始升级');
-		const obj = this;
-		// 加载缓存中的用户信息
-		const userInfo = uni.getStorageSync('userInfo') || '';
-		// 判断是否拥有用户信息
-		if (userInfo.uid) {
-			//更新登陆状态
-			uni.getStorage({
-				key: 'userInfo',
-				success: res => {
-					obj.setUserInfo(res.data);
-					obj.login();
+	import {
+		checkLogin
+	} from './libs/login';
+	import {
+		HTTP_REQUEST_URL,
+		SYSTEM_VERSION
+	} from './config/app';
+	import {
+		getShopConfig,
+		silenceAuth,
+		getSystemVersion,
+		basicConfig
+	} from '@/api/public';
+	import Auth from '@/libs/wechat.js';
+	import Routine from './libs/routine.js';
+	import {
+		silenceBindingSpread
+	} from "@/utils";
+	import {
+		colorChange,
+		getCrmebCopyRight,
+	} from '@/api/api.js';
+	import {
+		getLangJson,
+		getLangVersion
+	} 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);--view-op-point-eight: rgba(66,202,77, 0.8);--view-linear:linear-gradient(180deg, rgba(66,202,77,0.2) 0%, rgba(255,255,255,0) 100%);'
+	let red =
+		'--view-theme: rgba(233,51,35,1);--view-theme-16: #e93323;--view-priceColor:#e93323;--view-minorColor:rgba(233, 51, 35, 0.5);--view-minorColorT:rgba(233, 51, 35, 0.1);--view-bntColor:#FE960F;--view-op-ten: rgba(233,51,35, 0.1);--view-main-start:#FF6151; --view-main-over:#e93323;--view-op-point-four: rgba(233,51,35, 0.04);--view-op-point-eight: rgba(233,51,35, 0.8);--view-linear:linear-gradient(180deg, rgba(232,58,35,0.2) 0%, rgba(255,255,255,0) 100%)'
+	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);--view-op-point-eight: rgba(29,176,252, 0.8);--view-linear:linear-gradient(180deg, rgba(29,176,252,0.2) 0%, rgba(255,255,255,0) 100%);'
+	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);--view-op-point-eight: rgba(255,68,143, 0.8);--view-linear:linear-gradient(180deg, rgba(255,68,143,0.2) 0%, rgba(255,255,255,0) 100%);'
+	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);--view-op-point-eight: rgba(254,92,45, 0.8);--view-linear:linear-gradient(180deg, rgba(254,92,45,0.2) 0%, rgba(255,255,255,0) 100%);'
+
+	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', '')
+					}
 				}
-			});
-		}
-		// 获取当前位置附近商店数据
-		const shopDetail = uni.getStorageSync('shopDetail') ||'';
-		if(shopDetail){
-			uni.getStorage({
-				key: 'shopDetail',
-				success: res => {
-					obj.setShopInfo(res.data);
+			},
+			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
+					})
 				}
-			});
-		}
-		// 获取商家用户数据
-		const shopDetailAction = uni.getStorageSync('shopDetailAction') ||'';
-		if(shopDetailAction){
-			uni.getStorage({
-				key: 'shopDetailAction',
-				success: res => {
-					obj.setShopAction(res.data);
+			}
+		},
+		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) {
+				let param = this.$util.getUrlParams(decodeURIComponent(queryData.query.scene))
+				if (param.pid) {
+					this.$Cache.set('spread', param.pid);
+					this.globalData.spid = param.pid;
+					this.globalData.pid = param.pid;
+				} else {
+					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;
+			// #ifdef H5
+			if (option.query.hasOwnProperty('mdType') && option.query.mdType == "iframeWindow") {
+				this.globalData.isIframe = true;
+			} else {
+				this.globalData.isIframe = false;
+			}
+			// #endif
+			basicConfig().then(res => {
+				uni.setStorageSync('BASIC_CONFIG', res.data);
+			})
+			colorChange('color_change').then(res => {
+				uni.setStorageSync('is_diy', res.data.is_diy)
+				uni.$emit('is_diy', res.data.is_diy)
+				uni.setStorageSync('color_status', res.data.status)
+				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
 				}
 			});
-		}
-		// 获取是否已经在如果引导图
-		const guideMap = uni.getStorageSync('guideMap') ||false;
-		// 判断是否已经加载过数据
-		if(guideMap){
-			this.setFirstUse(true)
-		}
-		// #ifdef H5
-		// 保存路由对象
-		setRouter(this.$router);
-		//判断是否已经缓存浏览器
-		let bool = uni.getStorageSync('weichatBrowser') || '';
-		if (bool === '') {
-			//判断是否为微信浏览
-			bool = navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger';
-			// 保存当前是否为微信内核浏览器
-			uni.setStorageSync('weichatBrowser', bool);
-		}
-		if (bool) {
-			// 加载微信信息
-			weixindata();
-		}
-		// #endif
-		// #ifdef APP-PLUS
-		// 判断是否升级
-		getUpApp();
-		// 获取当前运行系统
-		let system = uni.getStorageSync('platform') || '';
-		if (!system) {
-			uni.setStorage({
-				key: 'platform',
-				data: uni.getSystemInfoSync().platform
+			getLangVersion().then(res => {
+				let version = res.data.version
+				if (version != uni.getStorageSync('LANG_VERSION')) {
+					getLangJson().then(res => {
+						let value = Object.keys(res.data)[0]
+						Cache.set('locale', Object.keys(res.data)[0])
+						this.$i18n.setLocaleMessage(value, res.data[value]);
+						uni.setStorageSync('localeJson', res.data);
+					})
+				}
+				uni.setStorageSync('LANG_VERSION', version)
+			})
+
+			// #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
-	},
-	onShow: function() {
-		// 加载拦截
-		// console.log('App Show');
-	},
-	onHide: function() {
-		// console.log('App Hide');
-	}
-};
-</script>
+			// #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;
+			}
 
-<style lang="scss">
-/*全局公共样式和字体图标*/
-@import '/static/css/cmy.css';
-view,
-scroll-view,
-swiper,
-swiper-item,
-cover-view,
-cover-image,
-icon,
-text,
-rich-text,
-progress,
-button,
-checkbox,
-form,
-input,
-label,
-radio,
-slider,
-switch,
-textarea,
-navigator,
-audio,
-camera,
-image,
-video {
-	box-sizing: border-box;
-}
-/* 骨架屏替代方案 */
-.Skeleton {
-	background: #f3f3f3;
-	padding: 20rpx 0;
-	border-radius: 8rpx;
-}
+			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
 
-/* 图片载入替代方案 */
-.image-wrapper {
-	font-size: 0;
-	background: #f3f3f3;
-	border-radius: 4px;
-	image {
-		width: 100%;
-		height: 100%;
-		transition: 0.6s;
-		opacity: 0;
-		&.loaded {
-			opacity: 1;
-		}
-	}
-}
+			// 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
 
-// 设置富文本中图片最大宽度
-uni-rich-text img {
-	max-width: 100% !important;
-}
-/*边框*/
-.b-b:after,
-.b-t:after {
-	position: absolute;
-	z-index: 3;
-	left: 0;
-	right: 0;
-	height: 0;
-	content: '';
-	transform: scaleY(0.5);
-	border-bottom: 1px solid $border-color-base;
-}
 
-.b-b:after {
-	bottom: 0;
-}
+			// #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 MP
+			getSystemVersion().then(res => {
+				if (res.data.version_code < SYSTEM_VERSION) {
+					uni.showModal({
+						title: '提示',
+						content: '请重新打包并上传小程序',
+						success: function(res) {
+							if (res.confirm) {}
+						}
+					});
+				}
+			})
+			// #endif
+		},
+		// #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 => {});
+			// },
+		},
 
-.b-t:after {
-	top: 0;
-}
+	};
+</script>
 
-/* input 样式 */
-.input-placeholder {
-	color: #999999;
-}
+<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';
 
-.placeholder {
-	color: #999999;
-}
-// 边距样式
-@for $i from 1 to 5 {
-	.margin-l-#{$i * 10} {
-		margin-left: $i * 10rpx !important;
-	}
-	.margin-r-#{$i * 10} {
-		margin-right: $i * 10rpx !important;
-	}
-	.margin-t-#{$i * 10} {
-		margin-top: $i * 10rpx !important;
+	view {
+		box-sizing: border-box;
 	}
-	.margin-b-#{$i * 10} {
-		margin-bottom: $i * 10rpx !important;
-	}
-	.margin-#{$i * 10} {
-		margin: $i * 10rpx !important;
-	}
-	.margin-v-#{$i * 10} {
-		margin-top: $i * 10rpx !important;
-		margin-bottom: $i * 10rpx !important;
-	}
-	.margin-c-#{$i * 10} {
-		margin-left: $i * 10rpx !important;
-		margin-right: $i * 10rpx !important;
+
+	page {
+		font-family: PingFang SC;
 	}
-	.padding-l-#{$i * 10} {
-		padding-left: $i * 10rpx !important;
+
+	.bg-color-red {
+		background-color: var(--view-theme) !important;
 	}
-	.padding-r-#{$i * 10} {
-		padding-right: $i * 10rpx !important;
+
+	.syspadding {
+		padding-top: var(--status-bar-height);
 	}
-	.padding-t-#{$i * 10} {
-		padding-top: $i * 10rpx !important;
+
+	.flex {
+		display: flex;
 	}
-	.padding-b-#{$i * 10} {
-		padding-bottom: $i * 10rpx !important;
+
+	.uni-scroll-view::-webkit-scrollbar {
+		/* 隐藏滚动条,但依旧具备可以滚动的功能 */
+		display: none;
 	}
-	.padding-#{$i * 10} {
-		padding: $i * 10rpx !important;
+
+	::-webkit-scrollbar {
+		width: 0;
+		height: 0;
+		color: transparent;
 	}
-	.padding-v-#{$i * 10} {
-		padding-top: $i * 10rpx !important;
-		padding-bottom: $i * 10rpx !important;
+
+	.uni-system-open-location .map-content.fix-position {
+		height: 100vh;
+		top: 0;
+		bottom: 0;
 	}
-	.padding-c-#{$i * 10} {
-		padding-left: $i * 10rpx !important;
-		padding-right: $i * 10rpx !important;
+
+	.open-location {
+		width: 100%;
+		height: 100vh;
 	}
-}
-// 字体大小
-.font-size-sm {
-	font-size: $font-sm;
-}
-.font-size-base {
-	font-size: $font-base;
-}
-.font-size-lg {
-	font-size: $font-lg;
-}
-// 字体颜色
-.font-color-yellow {
-	color: $color-yellow !important;
-}
-.font-color-gray {
-	color: $color-gray !important;
-}
-.font-color-red {
-	color: $color-red !important;
-}
-.font-color-greed {
-	color: $color-green !important;
-}
-// 边框颜色
-.border-color-yellow {
-	border: 1rpx solid $color-yellow;
-}
-// 基础按钮
-.base-buttom {
-	background-color: $color-green;
-	font-size: 32rpx;
-	padding: 30rpx;
-	color: #FFFFFF;
-	margin: 0 50rpx;
-	border-radius: 100rpx;
-	margin-top: 100rpx;
-	text-align: center;
-	z-index: 95;
-}
-// 修改默认背景颜色
-uni-page-wrapper {
-	background-color: $page-color-base;
-}
-page {
-	background-color: $page-color-base;
-	// 设置默认字体
-	font-family: PingFang SC, STHeitiSC-Light, Helvetica-Light, arial, sans-serif, Droid Sans Fallback;
-	min-height: 100%;
-}
 </style>

+ 28 - 0
androidPrivacy.json

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

+ 196 - 164
api/activity.js

@@ -1,276 +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 getBargainDetail(data,id) {
-	return request({
-		url: '/api/bargain/detail/' + id,
-		method: 'get',
-		data
+ */
+
+/**
+ * 拼团列表
+ * 
+ */
+export function getCombinationList(data) {
+	return request.get('combination/list', data, {
+		noAuth: true
 	});
 }
 
 /**
- * 砍价产品详情
+ * 拼团详情
+ * 
  */
-// export function getBargainDetail(id) {
-//   return request.get("bargain/detail/" + id);
-// }
+export function getCombinationDetail(id) {
+	return request.get('combination/detail/' + id);
+}
 
-//砍价 砍价帮总人数、剩余金额、进度条、已经砍掉的价格
-export function postBargainHelpCount(data) {
-	return request({
-		url: '/api/bargain/help/count',
-		method: 'post',
-		data
-	});
+/**
+ * 拼团 开团
+ */
+export function getCombinationPink(id) {
+	return request.get("combination/pink/" + id);
 }
 
 /**
- * 砍价 砍价帮总人数、剩余金额、进度条、已经砍掉的价格
+ * 拼团 取消开团
  */
-// export function postBargainHelpCount(data) {
-//   return request.post("bargain/help/count", data);
-// }
+export function postCombinationRemove(data) {
+	return request.post("combination/remove", data);
+}
 
-//砍价 开启砍价用户信息
-export function postBargainStartUser(data) {
-	return request({
-		url: '/api/bargain/start/user',
-		method: 'post',
-		data
+/**
+ * 砍价列表
+ */
+export function getBargainList(data) {
+	return request.get("bargain/list", data, {
+		noAuth: true
 	});
 }
 
 /**
- * 砍价 开启砍价用户信息
+ * 拼团轮播
+ * 
  */
-// export function postBargainStartUser(data) {
-//   return request.post("bargain/start/user", data);
-// }
+export function getCombinationBannerList(data) {
+	return request.get('combination/banner_list', data, {
+		noAuth: true
+	});
+}
 
-//砍价开启
-export function postBargainStart(data) {
-	return request({
-		url: '/api/bargain/start',
-		method: 'post',
-		data
+/**
+ * 拼团人数
+ * 
+ */
+export function getPink(data) {
+	return request.get('pink', data, {
+		noAuth: true
 	});
 }
 
 /**
- * 砍价开启
+ * 
+ * 砍价列表(已参与)
+ * @param object data
  */
-// export function postBargainStart(bargainId) {
-//   return request.post("bargain/start", { bargainId: bargainId});
-// }
+export function getBargainUserList(data) {
+	return request.get('bargain/user/list', data);
+}
 
-// 砍价 砍掉金额
-export function postBargainHelpPrice(data) {
-	return request({
-		url: '/api/bargain/help/price',
-		method: 'post',
-		data
-	});
+
+/**
+ * 砍价产品详情
+ */
+export function getBargainDetail(id, uid) {
+	return request.get(`bargain/detail/${id}?bargainUid=${uid}`);
 }
 
 /**
- * 砍价 砍掉金额
+ * 砍价 开启砍价用户信息
  */
-// export function postBargainHelpPrice(data) {
-//   return request.post("bargain/help/price", data);
-// }
+export function postBargainStartUser(data) {
+	return request.post("bargain/start/user", data);
+}
 
-// 砍价 帮助好友砍价
-export function postBargainHelp(data) {
-	return request({
-		url: '/api/bargain/help',
-		method: 'post',
-		data
+/**
+ * 砍价开启
+ */
+export function postBargainStart(bargainId) {
+	return request.post("bargain/start", {
+		bargainId: bargainId
 	});
 }
 
 /**
  * 砍价 帮助好友砍价
  */
-// export function postBargainHelp(data) {
-//   return request.post("bargain/help", data);
-// }
-
-// 砍价 砍价帮
-export function postBargainHelpList(data) {
-	return request({
-		url: '/api/bargain/help/list',
-		method: 'post',
-		data
-	});
+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 postBargainHelpList(data) {
+	return request.post("bargain/help/list", data);
+}
 
-// 砍价 观看/分享/参与次数
-export function postBargainShare(data) {
-	return request({
-		url: '/api/bargain/share',
-		method: 'post',
-		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 getBargainUserList(data) {
-	return request({
-		url: '/api/bargain/user/list',
-		method: 'get',
-		data
+export function postBargainShare(bargainId) {
+	return request.post("bargain/share", {
+		bargainId: bargainId
 	});
 }
 
 /**
+ * 秒杀产品时间区间
  * 
- * 砍价列表(已参与)
- * @param object data
-*/
-// export function getBargainUserList(data){
-//   return request.get('bargain/user/list',data);
-// }
-
-// 砍价取消
-export function getBargainUserCancel(data) {
-	return request({
-		url: '/api/bargain/user/cancel',
-		method: 'post',
-		data
+ */
+export function getSeckillIndexTime() {
+	return request.get('seckill/index', {}, {
+		noAuth: true
 	});
 }
 
 /**
- * 砍价取消
+ * 秒杀产品列表
+ * @param int time
+ * @param object data
  */
-// export function getBargainUserCancel(data) {
-//   return request.post("/bargain/user/cancel", 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 getCombinationList(data) {
-  return request.get('combination/list', data,{noAuth:true});
+ */
+export function getBargainPoster(data) {
+	return request.post('bargain/poster', data)
 }
 
 /**
- * 拼团详情
+ * 拼团海报
+ * @param object data
  * 
-*/
-export function getCombinationDetail(id) {
-  return request.get('combination/detail/'+id);
+ */
+export function getCombinationPoster(data) {
+	return request.post('combination/poster', data)
 }
 
 /**
- * 拼团 开团
+ * 砍价取消
  */
-export function getCombinationPink(id) {
-  return request.get("combination/pink/" + id);
+export function getBargainUserCancel(data) {
+	return request.post("bargain/user/cancel", data);
 }
 
 /**
- * 拼团 取消开团
+ * 获取秒杀小程序二维码
  */
-export function postCombinationRemove(data) {
-  return request.post("combination/remove",data);
+export function seckillCode(id, data) {
+	return request.get("seckill/code/" + id, data);
 }
 
 /**
- * 砍价列表
+ * 获取拼团小程序二维码
  */
-export function getBargainList(data) {
-  return request.get("bargain/list", data,{noAuth:true});
+export function scombinationCode(id) {
+	return request.get("combination/code/" + id);
+}
+
+/**
+ * 获取砍价海报详细信息
+ */
+export function getCombinationPosterData(id) {
+	return request.get("combination/poster_info/" + id);
 }
 
 
 /**
- * 
- * 取消砍价
- * @param int bargainId
-*/
-export function bargainUserCancel(bargainId){
-  return request.post('bargain/user/cancel', { bargainId: bargainId})
+ * 获取砍价海报详细信息
+ */
+export function getBargainPosterData(id) {
+	return request.get("bargain/poster_info/" + id);
 }
 
 /**
- * 秒杀产品时间区间
- * 
-*/
-export function getSeckillIndexTime(){
-  return request.get('seckill/index',{},{noAuth:true});
+ * 获取积分订单详细信息
+ */
+export function integralOrderConfirm(data) {
+	return request.post('store_integral/order/confirm', data);
 }
 
 /**
- * 秒杀产品列表
- * @param int time
- * @param object data
-*/
-export function getSeckillList(time,data){
-  return request.get('seckill/list/'+time,data,{noAuth:true});
+ * 获取积分订单创建
+ */
+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 getSeckillDetail(id){
-  return request.get('seckill/detail/'+id);
+ * 
+ */
+export function getIntegralProductDetail(id) {
+	return request.get('store_integral/detail/' + id, {}, {
+		noAuth: true
+	});
 }
 
 /**
- * 砍价海报
+ * 积分商城商品列表
  * @param object data
- * 
-*/
-export function getBargainPoster(data){
-  return request.post('bargain/poster',data)
+ */
+export function getStoreIntegralList(data) {
+	return request.get('store_integral/list', data, );
 }
 
 /**
- * 拼团海报
+ * 积分兑换列表
  * @param object data
- * 
-*/
-export function getCombinationPoster(data){
-  return request.post('combination/poster',data)
+ */
+export function getIntegralOrderList(data) {
+	return request.get('store_integral/order/list', data);
 }
 
 /**
- * 获取秒杀小程序二维码
+ * 积分兑换详情
  */
-export function seckillCode(id,data) {
-  return request.get("seckill/code/"+id,data);
+export function getLogisticsDetails(orderId) {
+	return request.get(`store_integral/order/express/${orderId}`);
 }
 
 /**
- * 获取拼团小程序二维码
+ * 积分兑换订单确认收货
+ * @param object data
  */
-export function scombinationCode(id) {
-  return request.get("combination/code/"+id);
+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
+	})
+}

+ 0 - 66
api/functionalUnit.js

@@ -1,66 +0,0 @@
-import request from '@/utils/request'
-
-//获取优惠券列表
-export function getCouponsList(data,types) {
-	//优惠券状态 0全部 1未使用 2已使用
-	return request({
-		url: '/api/coupons/user/'+types,
-		method: 'get',
-		data
-	});
-}
-
-//领取优惠券
-export function setCoupons(data) {
-	return request({
-		url: '/api/coupon/receive',
-		method: 'post',
-		data
-	});
-}
-
-//获取可使用优惠券
-export function couponsOrder(data,price) {
-	return request({
-		url: '/api/coupons/order/'+price,
-		method: 'get',
-		data
-	});
-}
-
-
-//	积分列表
-export function integrallist(data) {
-	return request({
-		url: '/api/integral/list',
-		method: 'get',
-		data
-	});
-}
-
-
-// 获取签到列表
-export function signList(data) {
-	return request({
-		url: '/api/sign/list',
-		method: 'get',
-		data
-	});
-}
-// 点击签到
-export function integral(data) {
-	return request({
-		url: '/api/sign/integral',
-		method: 'post',
-		data
-	});
-}
-
-// 签到信息
-export function signUser(data) {
-	return request({
-		url: '/api/sign/user',
-		method: 'post',
-		data
-	});
-}

+ 0 - 65
api/index.js

@@ -1,65 +0,0 @@
-import request from '@/utils/request'
-
-// 获取首页信息
-export function loadIndexs(data) {
-	return request({
-		url: '/api/new_index',
-		method: 'get',
-		data
-	});
-}
-// 获取版本号信息
-// #ifdef APP || H5
-export function getAppBBH(data) {
-	return request({
-		url: '/api/version',
-		method: 'get',
-		data
-	});
-}
-// #endif
-
-
-// 消息通知
-export function articleList(data, id) {
-	return request({
-		url: '/api/article/list/' + id,
-		method: 'get',
-		data
-	});
-}
-
-// 文章详细
-export function details(data, id) {
-	return request({
-		url: '/api/article/details/' + id,
-		method: 'get',
-		data
-	});
-}
-// 是否已读
-export function notify_read(data) {
-	return request({
-		url: '/api/car/notify_read',
-		method: 'post',
-		data
-	});
-}
-// 报警信息
-export function notify(data) {
-	return request({
-		url: '/api/car/notify',
-		method: 'post',
-		data
-	});
-}
-// 获取首页引导图
-export function guide_map(data) {
-	return request({
-		url: '/api/guide_map',
-		method: 'get',
-		data
-	});
-}
-
-

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

+ 0 - 64
api/login.js

@@ -1,64 +0,0 @@
-import request from '@/utils/request'
-
-// 登录
-export function login(data) {
-	return request({
-		url: '/api/login',
-		method: 'post',
-		data
-	});
-}
-// 注册
-export function register(data) {
-	return request({
-		url: '/api/register',
-		method: 'post',
-		data
-	});
-}
-// 验证码
-export function verify(data) {
-	// type=register为注册
-	// type=login为登录
-	return request({
-		url: '/api/register/verify',
-		method: 'post',
-		data
-	});
-}
-
-// 获取用户信息
-export function getUserInfo(data) {
-	return request({
-		url: '/api/userinfo',
-		method: 'get',
-		data
-	});
-}
-
-// 短信登录
-export function loginMobile(data) {
-	return request({
-		url: '/api/login/mobile',
-		method: 'post',
-		data
-	});
-}
-// #ifdef APP-PLUS
-// 微信授权登录
-export function loginWx(data) {
-	return request({
-		url: '/api/wechat/appauth',
-		method: 'get',
-		data
-	});
-}
-//苹果生成账户
-export function applelogin(data) {
-	return request({
-		url: '/api/applelogin',
-		method: 'post',
-		data
-	});
-}
-// #endif

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

+ 349 - 111
api/order.js

@@ -1,146 +1,384 @@
-import request from '@/utils/request'
-import {upFilse} from '@/utils/request'
-// 订单确认
-export function confirm(data) {
-	return request({
-		url: '/api/order/confirm',
-		method: 'post',
-		data
+// +----------------------------------------------------------------------
+// | 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 couponsOrder(data,price) {
-	return request({
-		url: '/api/coupons/order/'+price,
-		method: 'get',
-		data
-	});
+/**
+ * 获取购物车列表
+ * 
+ */
+export function getCartList(data) {
+	return request.get("cart/list", data);
 }
-//获取优惠券列表
-export function getCouponsList(data,types) {
-	//优惠券状态 0全部 1未使用 2已使用
-	return request({
-		url: '/api/coupons/user/'+types,
-		method: 'get',
-		data
-	});
+
+/**
+ * 修改购物车
+ * 
+ */
+export function getResetCart(data) {
+	return request.post("v2/reset_cart", data);
 }
-//提交评论
-export function order_comment(data) {
-	return request({
-		url: '/api/order/comment',
-		method: 'post',
-		data
+
+/**
+ * 修改购物车数量
+ * @param int cartId  购物车id
+ * @param int number 修改数量
+ */
+export function changeCartNum(cartId, number) {
+	return request.post("cart/num", {
+		id: cartId,
+		number: number
 	});
 }
-//订单产品信息
-export function product(data) {
-	return request({
-		url: '/api/order/product',
-		method: 'post',
-		data
+/**
+ * 清除购物车
+ * @param object ids join(',') 切割成字符串
+ */
+export function cartDel(ids) {
+	if (typeof ids === 'object')
+		ids = ids.join(',');
+	return request.post('cart/del', {
+		ids: ids
 	});
 }
-// 快递查询
-export function express_query(data) {
-	return request({
-		url: '/api/order/express_query',
-		method: 'get',
-		data
-	});
+/**
+ * 订单列表
+ * @param object data
+ */
+export function getOrderList(data) {
+	return request.get('order/list', data);
 }
-//上传图片
-export function upload(data) {
-	return upFilse({
-		url: '/api/upload/image',
-		method: 'post',
-		data
+
+/**
+ * 订单产品信息
+ * @param string unique 
+ */
+export function orderProduct(unique) {
+	return request.post('order/product', {
+		unique: unique
 	});
 }
-// 订单列表
-export function orderList(data) {
-	return request({
-		url: '/api/order/list',
-		method: 'get',
-		data
-	});
+
+/**
+ * 订单评价
+ * @param object data
+ * 
+ */
+export function orderComment(data) {
+	return request.post('order/comment', data);
 }
-// 订单详细
-export function orderDetail(data,orderid) {
-	return request({
-		url: '/api/order/detail/'+orderid,
-		method: 'get',
-		data
-	});
+
+/**
+ * 订单支付
+ * @param object data
+ */
+export function orderPay(data) {
+	return request.post('order/pay', data);
 }
 
-// 取消订单
-export function orderCancel(data) {
-	return request({
-		url: '/api/order/cancel',
-		method: 'post',
-		data
-	});
+/**
+ * 删除已退款和拒绝退款的订单
+ * @param string uni
+ * 
+ */
+export function refundOrderDel(uni) {
+	return request.get('order/refund/del/' + uni, {});
+}
+
+/**
+ * 订单统计数据
+ */
+export function orderData() {
+	return request.get('order/data')
 }
 
-// 删除订单
-export function orderDel(data) {
-	return request({
-		url: '/api/order/del',
-		method: 'post',
-		data
+/**
+ * 订单取消
+ * @param string id
+ * 
+ */
+export function orderCancel(id) {
+	return request.post('order/cancel', {
+		id: id
 	});
 }
-// 申请退款
-export function refund(data) {
-	return request({
-		url: '/api/order/refund/verify',
-		method: 'post',
-		data
+
+/**
+ * 删除已完成订单
+ * @param string uni
+ * 
+ */
+export function orderDel(uni) {
+	return request.post('order/del', {
+		uni: uni
 	});
 }
-// 退款理由列表
-export function refundReason(data) {
-	return request({
-		url: '/api/order/refund/reason',
-		method: 'get',
-		data
+
+/**
+ * 订单详情
+ * @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
 	});
 }
 
-// 确认收货
-export function orderTake(data) {
-	return request({
-		url: '/api/order/take',
-		method: 'post',
-		data
+/**
+ * 订单收货
+ * @param string uni
+ * 
+ */
+export function orderTake(uni) {
+	return request.post('order/take', {
+		uni: uni
 	});
 }
 
-// 订单支付
-export function orderPay(data) {
-	return request({
-		url: '/api/order/pay',
-		method: 'post',
-		data
+/**
+ * 订单查询物流信息
+ * @returns {*}
+ */
+export function express(uni, type) {
+	return request.get("order/express/" + uni + `${type?'/refund':''}`);
+}
+/**
+ * 订单查询物流信息
+ * @returns {*}
+ */
+export function adminExpress(uni, type) {
+	return request.get("admin/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
 	});
 }
 
-// 创建订单
-export function createOrderkey(data,key) {
-	return request({
-		url: '/api/order/create/'+key,
-		method: 'post',
-		data
+/**
+ * 获取确认订单页面是否展示快递配送和到店自提
+ * @param string cartId
+ */
+export function checkShipping(cartId, news) {
+	return request.post('order/check_shipping', {
+		cartId,
+		'new': news
 	});
 }
 
-// 统计订单金额
-export function computedOrderkey(data) {
-	return request({
-		url: '/api/order/computed/'+data.orderkey,
-		method: 'post',
-		data
+/**
+ * 获取当前金额能使用的优惠卷
+ * @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);
+}
+
+/**
+ * 收银台订单信息
+ * @param object data
+ */
+export function getCashierOrder(orderId, type) {
+	return request.get(`order/cashier/${orderId}/${type}`);
+}

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

+ 0 - 186
api/product.js

@@ -1,186 +0,0 @@
-import request from '@/utils/request'
-
-// 获取商品列表
-export function getProducts(data) {
-	// 	{
-	// 参数名称	是否必须	示例	备注
-	// sid			否			二级分类编号
-	// cid			否			一级分类编号(!)
-	// keyword		否			搜索
-	// priceOrder	否			价格排序
-	// salesOrder	否			销量排序
-	// news			否			是否新品
-	// page			否			分页参数起始值
-	// limit		否			分页数步长值
-	// }
-	return request({
-		url: '/api/products',
-		method: 'get',
-		data
-	});
-}
-// 获取商品详情
-export function goodsDetail(data, id) {
-	return request({
-		url: '/api/product/detail/' + id,
-		method: 'get',
-		data
-	});
-}
-
-// 砍价列表
-export function getBargainList(data) {
-	return request({
-		url: '/api/bargain/list',
-		method: 'get',
-		data
-	});
-}
-// 加入购物车
-export function cartAdd(data) {
-	return request({
-		url: '/api/cart/add',
-		method: 'post',
-		data
-	});
-}
-
-// 收藏商品
-export function collectAdd(data) {
-	return request({
-		url: '/api/collect/add',
-		method: 'post',
-		data
-	});
-}
-
-// 取消收藏商品
-export function collectDel(data) {
-	return request({
-		url: '/api/collect/del',
-		method: 'post',
-		data
-	});
-}
-
-// 获取搜搜关键字
-export function searchKeyword(data) {
-	return request({
-		url: '/api/search/keyword',
-		method: 'get',
-		data
-	});
-}
-
-// 获取热门分类信息
-export function groomList(data,type) {
-	// 获取产品类型 1 精品推荐 2 热门榜单 3首发新品 4促销单品
-	return request({
-		url: '/api/groom/list/'+type,
-		method: 'get',
-		data
-	});
-}
-
-
-// 获取秒杀商品详细
-export function seckillGoods(data,id) {
-	return request({
-		url: '/api/seckill/detail/'+id,
-		method: 'get',
-		data
-	});
-}
-
-// 获取拼团商品详细
-export function groupGoods(data,id) {
-	return request({
-		url: '/api/combination/detail/'+id,
-		method: 'get',
-		data
-	});
-}
-
-
-// 获取商品分类
-export function getCategoryList(data) {
-	return request({
-		url: '/api/category',
-		method: 'get',
-		data
-	});
-}
-
-
-// 获取拼团列表
-export function getCombinationList(data) {
-	return request({
-		url: '/api/combination/list',
-		method: 'get',
-		data
-	});
-}
-
-//取消拼团
-export function getCombinationLisRemove(data,id) {
-	return request({
-		url: '/api/combination/remove'+id,
-		method: 'get',
-		data
-	});
-}
-
-//拼团开团页面数据
-export function getCombinationLisPink(data,id) {
-	return request({
-		url: '/api/combination/pink/'+id,
-		method: 'get',
-		data
-	});
-}
-
-// 获取拼团海报
-export function getCombinationPoster(data) {
-	return request({
-		url: '/api/combination/poster',
-		method: 'post',
-		data
-	});
-}
-
-
-// 获取秒杀分类
-export function getSeckillClass(data) {
-	return request({
-		url: '/api/seckill/index',
-		method: 'get',
-		data
-	});
-}
-// 获取秒杀列表
-export function getSeckillList(data,id) {
-	return request({
-		url: '/api/seckill/list/'+id,
-		method: 'get',
-		data
-	});
-}
-
-
-// 产品评价数量和好评度
-export function reply_config(data,id) {
-	return request({
-		url: '/api/reply/config/'+id,
-		method: 'get',
-		data
-	});
-}
-// 获取产品评论
-export function reply_list(data,id) {
-	return request({
-		url: '/api/reply/list/'+id,
-		method: 'get',
-		data
-	});
-}
-

+ 280 - 0
api/public.js

@@ -0,0 +1,280 @@
+// +----------------------------------------------------------------------
+// | 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/auth_type", data, {
+		noAuth: true
+	});
+	//#endif
+}
+
+/**
+ * 分享
+ * @returns {*}
+ */
+export function getShare() {
+	return request.get("share", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 公众号登录
+ * @returns {*}
+ */
+export function wechatAuthLogin(data) {
+	return request.get("v2/wechat/auth_login", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取关注海报
+ * @returns {*}
+ */
+export function follow() {
+	return request.get("wechat/follow", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * code生成用户
+ * @returns {*}
+ */
+export function authType(data) {
+	return request.get("v2/routine/auth_type", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 授权登录
+ * @returns {*}
+ */
+export function authLogin(data) {
+	return request.get("v2/routine/auth_login", data, {
+		noAuth: true
+	});
+}
+
+
+/**
+ * 获取图片base64
+ * @retins {*}
+ * */
+export function imageBase64(image, code) {
+	return request.post(
+		"image_base64", {
+			image: image,
+			code: code
+		}, {
+			noAuth: true
+		}
+	);
+}
+
+/**
+ * 自动复制口令功能
+ * @returns {*}
+ */
+export function copyWords() {
+	return request.get("copy_words", {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取商城是否强制绑定手机号
+ */
+export function getShopConfig() {
+	return request.get('v2/bind_status', {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 小程序绑定手机号
+ * @param {Object} data
+ */
+export function routineBindingPhone(data) {
+	return request.post('v2/routine/auth_binding_phone', data, {
+		noAuth: true
+	});
+}
+/**
+ * 小程序绑定手机号
+ * @param {Object} data
+ */
+export function wechatBindingPhone(data) {
+	return request.post('v2/wechat/auth_binding_phone', data, {
+		noAuth: true
+	});
+}
+/**
+ * 小程序手机号登录
+ * @param {Object} data
+ */
+export function phoneLogin(data) {
+	return request.post('v2/routine/phone_login', data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 小程序用户登录
+ * @param data object 小程序用户登陆信息
+ */
+export function routineLogin(data) {
+	return request.get("v2/wechat/routine_auth", data, {
+		noAuth: true
+	});
+}
+
+/**
+ * 获取微信sdk配置
+ * @returns {*}
+ */
+export function wechatAuthV2(code, 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
+	});
+}
+
+/**
+ * 获取首页DIY数据版本号
+ * 
+ */
+export function getVersion(name) {
+	return request.get(`v2/diy/get_version/${name}`, {}, {
+		noAuth: true
+	});
+}
+/**
+ * 获取商品分类版本号
+ * 
+ */
+export function getCategoryVersion(name) {
+	return request.get(`category_version`, {}, {
+		noAuth: true
+	});
+}
+
+/**
+ * 配置信息
+ * 
+ */
+export function basicConfig(name) {
+	return request.get(`basic_config`, {}, {
+		noAuth: true
+	});
+}
+/**
+ * 后台版本信息
+ * 
+ */
+export function getSystemVersion() {
+	return request.get(`version`, {}, {
+		noAuth: true
+	});
+}

+ 0 - 36
api/set.js

@@ -1,36 +0,0 @@
-import request from '@/utils/request'
-
-// 修改用户信息
-export function userEdit(data) {
-	return request({
-		url: '/api/user/edit',
-		method: 'post',
-		data
-	});
-}
-
-//退出登录
-export function logout(data) {
-	return request({
-		url: '/api/logout',
-		method: 'get',
-		data
-	});
-}
-//修改密码
-export function registerReset(data) {
-	return request({
-		url: '/api/register/reset',
-		method: 'post',
-		data
-	});
-}
-
-//绑定手机
-export function binding(data) {
-	return request({
-		url: '/api/binding',
-		method: 'post',
-		data
-	});
-}

+ 0 - 196
api/shop.js

@@ -1,196 +0,0 @@
-import request from '@/utils/request'
-
-
-// 获取首页信息
-export function storeList(data) {
-	return request({
-		url: '/api/store_list',
-		method: 'get',
-		data
-	});
-}
-
-// 订单数据统计
-export function statistics(data) {
-	return request({
-		url: '/api/admin/order/statistics',
-		method: 'get',
-		data
-	});
-}
-
-
-// 订单列表
-export function shopOrderList(data) {
-	return request({
-		url: '/api/admin/order/list',
-		method: 'get',
-		data
-	});
-}
-
-
-// 订单详情
-export function shopOrderDetai(data,orderid) {
-	return request({
-		url: '/api/admin/order/detai/'+orderid,
-		method: 'get',
-		data
-	});
-}
-
-
-// 订单发货(普通商品)
-export function deliveryGain(data,orderid) {
-	return request({
-		url: '/api/admin/order/delivery/gain/'+orderid,
-		method: 'get',
-		data
-	});
-}
-
-
-
-// 订单发货
-export function delivery(data) {
-	return request({
-		url: '/api/admin/order/delivery/keep',
-		method: 'get',
-		data
-	});
-}
-
-// 订单退款(普通商品)
-export function refund(data) {
-	return request({
-		url: '/api/admin/order/refund',
-		method: 'get',
-		data
-	});
-}
-
-
-// 订单核销(普通商品)
-export function order_verific(data) {
-	return request({
-		url: '/api/order/order_verific',
-		method: 'get',
-		data
-	});
-}
-
-
-// 门店资金
-export function funds(data) {
-	return request({
-		url: '/api/admin/funds',
-		method: 'get',
-		data
-	});
-}
-
-// 车辆报修
-export function question(data) {
-	return request({
-		url: '/api/admin/car/question',
-		method: 'post',
-		data
-	});
-}
-// 车辆报修详情
-export function questionInfo(data) {
-	return request({
-		url: '/api/admin/question/info',
-		method: 'get',
-		data
-	});
-}
-// 车辆发货
-export function set_car_number(data) {
-	return request({
-		url: '/api/admin/car/set_car_number',
-		method: 'post',
-		data
-	});
-}
-// 订单查询
-export function orderDetail(data,id) {
-	return request({
-		url: '/api/admin/order/detail/'+id,
-		method: 'get',
-		data
-	});
-}
-
-// 车辆批次
-export function batch(data) {
-	return request({
-		url: '/api/car/batch',
-		method: 'get',
-		data
-	});
-}
-// 车辆类型
-export function carType(data) {
-	return request({
-		url: '/api/car/type',
-		method: 'get',
-		data
-	});
-}
-
-// 获取自己所属的门店信息
-export function adminStore(data) {
-	return request({
-		url: '/api/admin/store',
-		method: 'get',
-		data
-	});
-}
-
-
-// 维修人员列表
-export function adminKf(data) {
-	return request({
-		url: '/api/admin/kf',
-		method: 'get',
-		data
-	});
-}
-// 安排维修人员
-export function schedule_task(data) {
-	return request({
-		url: '/api/admin/schedule_task',
-		method: 'post',
-		data
-	});
-}
-
-// 员工我的任务
-export function task(data) {
-	return request({
-		url: '/api/admin/task',
-		method: 'post',
-		data
-	});
-}
-// 处理任务
-export function tasksave(data) {
-	return request({
-		url: '/api/admin/tasksave',
-		method: 'post',
-		data
-	});
-}
-
-// 处理任务
-export function detail(data,id) {
-	return request({
-		url: '/api/admin/order/detail/'+id,
-		method: 'get',
-		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)
+}

+ 660 - 211
api/user.js

@@ -1,272 +1,721 @@
-import request from '@/utils/request'
-
-// 订单统计信息
-export function orderData(data) {
-	return request({
-		url: '/api/order/data',
-		method: 'get',
-		data
-	});
+// +----------------------------------------------------------------------
+// | 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 real_name(data) {
-	return request({
-		url: '/api/real_name',
-		method: 'post',
-		data
-	});
+
+/**
+ * 设置用户分享
+ * 
+ */
+export function userShare() {
+	return request.post('user/share');
 }
 
-// 获取用户信息
-export function getUserInfo(data) {
-	return request({
-		url: '/api/userinfo',
-		method: 'get',
-		data
+/**
+ * h5用户登录
+ * @param data object 用户账号密码
+ */
+export function loginH5(data) {
+	return request.post("login", data, {
+		noAuth: true
 	});
 }
-// 个人中心页数据
-export function getUser(data) {
-	return request({
-		url: '/api/user',
-		method: 'get',
-		data
+
+/**
+ * h5用户手机号登录
+ * @param data object 用户手机号 也只能
+ */
+export function loginMobile(data) {
+	return request.post("login/mobile", data, {
+		noAuth: true
 	});
 }
 
-// 用户分享图
-export function spreadBanner(data) {
-	return request({
-		url: '/api/spread/banner',
-		method: 'get',
-		data
+/**
+ * 验证码key
+ */
+export function getCodeApi() {
+	return request.get("verify_code", {}, {
+		noAuth: true
 	});
 }
 
-// 获取地址列表
-export function getAddressList(data) {
-	return request({
-		url: '/api/address/list',
-		method: 'get',
-		data
+/**
+ * h5用户发送验证码
+ * @param data object 用户手机号
+ */
+export function registerVerify(data) {
+	return request.post("register/verify", data, {
+		noAuth: true
 	});
 }
-// 修改地址
-export function addressEdit(data) {
-	return request({
-		url: '/api/address/edit',
-		method: 'post',
-		data
+
+/**
+ * h5用户手机号注册
+ * @param data object 用户手机号 验证码 密码
+ */
+export function register(data) {
+	return request.post("register", data, {
+		noAuth: true
 	});
 }
-// 删除地址
-export function addressDel(data) {
-	return request({
-		url: '/api/address/del',
-		method: 'post',
-		data
+
+/**
+ * 用户手机号修改密码
+ * @param data object 用户手机号 验证码 密码
+ */
+export function registerReset(data) {
+	return request.post("register/reset", data, {
+		noAuth: true
 	});
 }
-// 设为默认地址
-export function setAddressDefault(data) {
-	return request({
-		url: '/api/address/default/set',
-		method: 'post',
-		data
+
+/**
+ * 获取用户中心菜单
+ *
+ */
+export function getMenuList() {
+	return request.get("menu/user", {}, {
+		noAuth: true
 	});
 }
-// 购物车列表
-export function getCartList(data) {
-	return request({
-		url: '/api/cart/list',
-		method: 'get',
-		data
-	});
+
+/*
+ * 签到用户信息
+ * */
+export function postSignUser(sign) {
+	return request.post("sign/user", sign);
 }
 
-// 修改购物车数量
-export function getCartNum(data) {
-	return request({
-		url: '/api/cart/num',
-		method: 'post',
-		data
-	});
+/**
+ * 获取签到配置
+ * 
+ */
+export function getSignConfig() {
+	return request.get('sign/config')
 }
-//删除购物车
-export function cartDel(data) {
-	return request({
-		url: '/api/cart/del',
-		method: 'post',
-		data
-	});
+
+/**
+ * 获取签到列表
+ * @param object data
+ */
+export function getSignList(data) {
+	return request.get('sign/list', data);
 }
-//获取收藏夹列表
-export function getcollectList(data) {
-	return request({
-		url: '/api/collect/user',
-		method: 'get',
-		data
-	});
+
+/**
+ * 用户签到
+ */
+export function setSignIntegral() {
+	return request.post('sign/integral')
 }
-// 取消收藏
-export function delcollect(data) {
-	return request({
-		url: '/api/collect/del',
-		method: 'post',
-		data
-	});
+
+/**
+ * 签到列表(年月)
+ * @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({
-		url: '/api/spread/people',
-		method: 'post',
-		data
-	});
+	return request.post('spread/people', data);
 }
-// 获取我的所有车辆包含被授权车辆
-export function mycar(data) {
-	return request({
-		url: '/api/car/mycar',
-		method: 'get',
-		data
-	});
+
+/**
+ * 
+ * 推广佣金/提现总和
+ * @param int type
+ */
+export function spreadCount(type) {
+	return request.get('spread/count/' + type);
 }
-// 获取我的车辆
-export function carList(data) {
-	return request({
-		url: '/api/car/lst',
-		method: 'get',
-		data
-	});
+
+/*
+ * 推广数据
+ * */
+export function getSpreadInfo() {
+	return request.get("commission");
 }
-// 获取授权车辆
-export function get_touid_car(data) {
-	return request({
-		url: '/api/car/get_touid_car',
-		method: 'post',
-		data
-	});
+
+
+/**
+ * 
+ * 推广订单
+ * @param object data
+ */
+export function spreadOrder(data) {
+	return request.post('spread/order', data);
 }
-// 获取车辆详情
-export function getCarInfo(data) {
-	return request({
-		url: '/api/car/info',
-		method: 'get',
-		data
-	});
+
+/**
+ * 
+ * 事业部/推广订单
+ * @param object data
+ */
+export function divisionOrder(data) {
+	return request.post('division/order', data);
 }
-// 获取车辆行程记录列表
-export function car_record(data) {
-	return request({
-		url: '/api/car/car_record',
-		method: 'post',
-		data
-	});
+
+/*
+ * 获取推广人排行
+ * */
+export function getRankList(q) {
+	return request.get("rank", q);
 }
-// 获取车辆行程记录详细
-export function record_info(data) {
-	return request({
-		url: '/api/car/record_info',
-		method: 'get',
-		data
-	});
+
+/*
+ * 获取佣金排名
+ * */
+export function getBrokerageRank(q) {
+	return request.get("brokerage_rank", q);
 }
-// 车锁开关
-export function car_switch(data) {
-	return request({
-		url: '/api/car/car_switch',
-		method: 'post',
-		data
-	});
+
+/**
+ * 提现申请
+ * @param object data
+ */
+export function extractCash(data) {
+	return request.post('extract/cash', data)
 }
 
-// 车辆授权
-export function add_auth_car(data) {
-	return request({
-		url: '/api/car/add_auth_car',
-		method: 'post',
-		data
-	});
+/**
+ * 提现银行/提现最低金额
+ * 
+ */
+export function extractBank() {
+	return request.get('extract/bank');
 }
-// 删除授权
-export function del_auth_car(data) {
-	return request({
-		url: '/api/car/del_auth_car',
-		method: 'post',
-		data
-	});
+
+/**
+ * 会员等级列表
+ * 
+ */
+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 recharge(data) {
+	return request.post("recharge/recharge", data);
+}
+/**
+ * 获取默认地址
+ * 
+ */
+export function getAddressDefault() {
+	return request.get('address/default');
+}
+
+/**
+ * 充值金额选择
+ */
+export function getRechargeApi() {
+	return request.get("recharge/index");
 }
 
-// 车辆授权列表
-export function get_auth(data) {
-	return request({
-		url: '/api/car/get_auth',
-		method: 'post',
-		data
+/**
+ * 登陆记录
+ */
+export function setVisit(data) {
+	return request.post('user/set_visit', {
+		...data
+	}, {
+		noAuth: true
 	});
 }
 
-// 车辆报修
-export function create_question(data) {
-	return request({
-		url: '/api/car/create_question',
-		method: 'post',
-		data
+/**
+ * 客服列表
+ */
+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);
+}
+
+
+/**
+ * 微信直接手机号登录
+ */
+export function phoneWxSilenceAuth(data) {
+	return request.post('v2/phone_wx_silence_auth', data, {
+		noAuth: true
 	});
 }
 
-// 车辆报修详情
-export function question_info(data) {
-	return request({
-		url: '/api/car/question_info',
-		method: 'post',
-		data
+/**
+ * 小程序直接手机号登录
+ */
+export function phoneSilenceAuth(data) {
+	return request.post('v2/phone_silence_auth', data, {
+		noAuth: true
 	});
 }
 
-// 车辆报修历史
-export function question(data) {
-	return request({
-		url: '/api/car/question',
-		method: 'post',
-		data
+/**
+ * 用户发票列表
+ * @param {Object} data
+ */
+export function invoiceList(data) {
+	return request.get('v2/invoice', data, {
+		noAuth: true
 	});
 }
-// 车辆报修评价
-export function question_score(data) {
-	return request({
-		url: '/api/car/question_score',
-		method: 'post',
-		data
+
+/**
+ * 用户添加|修改发票
+ * @param {Object} data
+ */
+export function invoiceSave(data) {
+	return request.post('v2/invoice/save', data, {
+		noAuth: true
 	});
 }
 
-// 撤销报修
-export function cancel_question(data) {
-	return request({
-		url: '/api/car/cancel_question',
-		method: 'get',
-		data
+/**
+ * 用户删除发票
+ * @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 prepayment(data) {
-	return request({
-		url: '/api/car/prepayment',
-		method: 'post',
-		data
+/*
+ * 获取隐私协议
+ * */
+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');
+}
 
-// 提前还款
-export function getcar_status(data) {
-	return request({
-		url: '/api/car/getcar_status',
-		method: 'get',
-		data
-	});
+/**
+ * 获取分销任务列表
+ * @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
+	})
+}
+
+/**
+ * 获取多语言是否切换
+ */
+
+export function getLangVersion() {
+	return request.get('lang_version', {}, {
+		noAuth: true
+	})
+}
+
+/**
+ * 
+ * 小程序绑定手机号
+ * @param object data
+ */
+export function mpBindingPhone(data) {
+	return request.post('v2/routine/binding_phone', data);
+}
+
+/**
+ *  签到提醒切换
+ */
+
+export function changeRemindStatus(status) {
+	return request.get(`sign/remind/${status}`, {}, {
+		noAuth: true
+	})
+}

+ 0 - 140
api/wallet.js

@@ -1,140 +0,0 @@
-import request from '@/utils/request'
-
-// 获取用户消费记录
-export function spreadCommission(data,state) {
-	return request({
-		url: '/api/spread/commission/'+state,
-		method: 'get',
-		data
-	});
-}
-
-// 获取账户余额
-export function userBalance(data) {
-	return request({
-		url: '/api/user/balance',
-		method: 'get',
-		data
-	});
-}
-
-// 提现
-export function extractCash(data) {
-	return request({
-		url: '/api/extract/cash',
-		method: 'post',
-		data
-	});
-}
-
-// 提现信息
-export function extractBank(data) {
-	return request({
-		url: '/api/extract/bank',
-		method: 'get',
-		data
-	});
-}
-// #ifdef H5
-// 公众号充值
-export function rechargeWechat(data) {
-	return request({
-		url: '/api/recharge/wechat',
-		method: 'post',
-		data
-	});
-}
-// #endif
-// #ifdef MP
-// 小程序充值
-export function rechargeRoutine(data) {
-	return request({
-		url: '/api/recharge/routine',
-		method: 'post',
-		data
-	});
-}
-// #endif
-// #ifdef APP
-// 支付宝支付
-export function aliPay(data) {
-	return request({
-		url: '/api/recharge/ali',
-		method: 'post',
-		data
-	});
-}
-// 微信支付
-export function wxPay(data) {
-	return request({
-		url: '/api/recharge/wxapp',
-		method: 'post',
-		data
-	});
-}
-// #endif
-// 佣金充值余额
-export function commissionPay(data) {
-	return request({
-		url: '/api/recharge/brokerage',
-		method: 'post',
-		data
-	});
-}
-// 获取提现支付宝账号
-export function aliInfo(data) {
-	return request({
-		url: '/api/ali/info',
-		method: 'get',
-		data
-	});
-}
-//获取默认银行卡账号
-export function bankInfo(data) {
-	return request({
-		url: '/api/bank/info',
-		method: 'get',
-		data
-	});
-}
-// 保存提现支付宝账号
-export function setAliInfo(data) {
-	return request({
-		url: '/api/ali/edit',
-		method: 'post',
-		data
-	});
-}
-//保存默认银行卡账号
-export function setBankInfo(data) {
-	return request({
-		url: '/api/bank/edit',
-		method: 'post',
-		data
-	});
-}
-
-
-// 账户余额
-export function balance(data) {
-	return request({
-		url: '/api/user/balance',
-		method: 'get',
-		data
-	});
-}
-
-
-// 充值分类金额
-export function rechargeIndex(data) {
-	return request({
-		url: '/api/recharge/index',
-		method: 'get',
-		data
-	});
-}
-
-
-
-
-

+ 0 - 37
api/wx.js

@@ -1,37 +0,0 @@
-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, routineBindingPhone } 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) {
+			routineBindingPhone({
+				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>

+ 237 - 0
components/cartList/index.vue

@@ -0,0 +1,237 @@
+<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>

+ 199 - 0
components/catGoodList/index.vue

@@ -0,0 +1,199 @@
+<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: 'catGoodList',
+		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;
+				padding-top: 40%;
+
+				image {
+					border-radius: 10rpx;
+					position: absolute;
+					top: 0;
+					left: 0;
+					width: 100%;
+					height: 100%;
+					object-fit: cover;
+				}
+			}
+
+			.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>

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

+ 150 - 0
components/cusPreviewImg/swiperPrevie.vue

@@ -0,0 +1,150 @@
+<template>
+	<view class="previewImg" v-if="showBox" @touchmove.stop.prevent>
+		<view class="mask" @click="close">
+			<swiper @change="changeSwiper" class="mask-swiper" :current="currentIndex" :circular="circular"
+				:duration="duration">
+				<swiper-item v-for="(src, i) in list" :key="i" class="flex flex-column justify-center align-center">
+					<image class="mask-swiper-img" :src="src" mode="widthFix" />
+				</swiper-item>
+			</swiper>
+		</view>
+		<view class="pagebox" v-if="list.length>0">{{ Number(currentIndex) + 1 }} / {{ list.length }}</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: '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 (!this.list.length) return;
+				this.currentIndex = current;
+				this.showBox = true;
+			},
+			close() {
+				this.showBox = false;
+			},
+		}
+	}
+</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>

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

@@ -0,0 +1,222 @@
+<template>
+	<view class="easy-loadimage" :id="uid">
+		<image class="origin-img" :src="imageSrc" mode="" 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) {
+				this.showImg = true;
+				setTimeout(() => {
+					this.showTransition = true
+				}, 50)
+			},
+			handleImgError(e) {
+				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>

+ 313 - 0
components/eidtUserModal/index.vue

@@ -0,0 +1,313 @@
+<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) {
+				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>

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 18
components/empty/empty.vue


+ 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: #999;
+		}
+	}
+</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>

+ 171 - 0
components/goodList/index.vue

@@ -0,0 +1,171 @@
+<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: 64rpx;
+		height: 26rpx;
+		margin-right: 8rpx;
+		margin-left: 8rpx;
+	}
+
+	.goodList .item .text .vip-money .num {
+		font-size: 22rpx;
+		color: #aaa;
+		font-weight: normal;
+		margin-top: -2rpx;
+		white-space: nowrap;
+
+		text {
+			white-space: nowrap;
+		}
+
+		~.num {
+			margin-left: 22rpx;
+		}
+	}
+
+	.goodList .item .iconfont {
+		position: absolute;
+		right: 30rpx;
+		width: 50rpx;
+		height: 50rpx;
+		border-radius: 50%;
+		font-size: 30rpx;
+		bottom: 38rpx;
+	}
+</style>

+ 142 - 0
components/guide/index.vue

@@ -0,0 +1,142 @@
+<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: true,
+				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)
+					this.$util.JumpPath(url);
+				}
+			},
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	page,
+	.content {
+		width: 100%;
+		height: 100%;
+		background-size: 100% auto;
+		padding: 0;
+	}
+
+	.swiper {
+		width: 100%;
+		height: 100vh;
+		background: #FFFFFF;
+	}
+
+	.swiper-item {
+		width: 100%;
+		height: 100%;
+		text-align: center;
+		position: relative;
+		display: flex;
+		/* justify-content: center; */
+		align-items: flex-end;
+		flex-direction: column-reverse
+	}
+
+	.swiper-item-img {
+		width: 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>

+ 189 - 0
components/indexGoods/index.vue

@@ -0,0 +1,189 @@
+<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;
+					line-height: 38rpx;
+				}
+
+				.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>

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

@@ -0,0 +1,807 @@
+<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.style.height = 'auto';
+					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;
+	}
+}

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

@@ -0,0 +1,468 @@
+<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>

+ 160 - 0
components/numberScroll.vue

@@ -0,0 +1,160 @@
+<template>
+	<view class="number-box">
+		<block v-for="(myIndex, index) in indexArr" :key="index">
+			<swiper class="swiper" vertical="true" :current="myIndex" circular="true"
+				v-bind:style="{color:color,width:myIndex == 10  ? '14rpx' : myIndex == 1 ? '22rpx' : width+'rpx',height:height+'rpx',lineHeight:fontSize+'rpx',fontSize:fontSize+'rpx',fontWeight: fontWeight}">
+				<swiper-item>
+					<view class="swiper-item">0</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">1</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">2</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">3</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">4</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">5</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">6</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">7</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">8</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">9</view>
+				</swiper-item>
+				<swiper-item>
+					<view class="swiper-item">.</view>
+				</swiper-item>
+			</swiper>
+		</block>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			num: [String, Number],
+			color: {
+				type: String,
+				default: '#000000'
+			},
+			width: {
+				type: String,
+				default: '30'
+			},
+			height: {
+				type: String,
+				default: '30'
+			},
+			fontSize: {
+				type: String,
+				default: '30'
+			},
+			fontWeight: {
+				type: [String, Number],
+				default: 500
+			}
+		},
+		data() {
+			return {
+				indexArr: []
+			};
+		},
+		created() {
+			let {
+				num
+			} = this;
+			let arr = new Array(num.toString().length);
+			arr.fill(0);
+			this.indexArr = arr;
+		},
+		watch: {
+			num: function(val, oldVal) {
+				// 处理新老数据长度不一样的情况
+				let arr = Array.prototype.slice.apply(this.indexArr);
+				let newLen = val.toString().length;
+				let oldLen = oldVal.toString().length;
+				if (newLen > oldLen) {
+					for (let i = 0; i < newLen - oldLen; i++) {
+						arr.push(0);
+					}
+					this.indexArr = arr;
+				}
+				if (newLen < oldLen) {
+					for (let i = 0; i < oldLen - newLen; i++) {
+						arr.pop();
+					}
+					this.indexArr = arr;
+				}
+				this.numChange(val);
+			}
+		},
+		mounted() {
+			//定时器作用:app显示数字滚动
+			this._time = setTimeout(() => {
+				this.numChange(this.num);
+				clearTimeout(this._time);
+			}, 50);
+		},
+		methods: {
+			/**
+			 * 数字改变
+			 * @value 数字
+			 */
+			numChange(num) {
+				this.$nextTick(() => {
+					let {
+						indexArr
+					} = this;
+					let copyIndexArr = Array.prototype.slice.apply(indexArr);
+					let _num = num.toString();
+					for (let i = 0; i < _num.length; i++) {
+						if (_num[i] === '.') {
+							copyIndexArr[i] = 10;
+						} else {
+							copyIndexArr[i] = Number(_num[i]);
+						}
+					}
+					this.indexArr = copyIndexArr;
+				})
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	.number-box {
+		display: flex;
+		flex-wrap: wrap;
+		justify-content: center;
+	}
+
+	.swiper {
+		position: relative;
+		// 	line-height: 30upx;
+		// 	width: 30upx;
+		// 	height: 30upx;
+		// 	font-size: 30upx;
+		// 	background: red;
+	}
+
+	.swiper:after {
+		content: '';
+		position: absolute;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+	}
+</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 line2'>{{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 || (virtualType > 0 && statusType == 1))"
+						@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>

+ 233 - 0
components/pageFooter/index.vue

@@ -0,0 +1,233 @@
+<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) {},
+				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);
+			uni.$on('uploadFooter', () => {
+				let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
+				let curRoute = routes[routes.length - 1].route //获取当前页面路由
+				this.$store.commit('ACTIVITYTAB', '/' + curRoute);
+			})
+		},
+		onShow() {
+
+		},
+		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()
+			}
+		},
+		onHide() {
+			uni.$off(['uploadFooter'])
+		},
+		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>

+ 558 - 0
components/payment/index.vue

@@ -0,0 +1,558 @@
+<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)
+			},
+			formpost(url, postData) {
+				let tempform = document.createElement("form");
+				tempform.action = url;
+				tempform.method = "post";
+				tempform.target = "_self";
+				tempform.style.display = "none";
+				for (let x in postData) {
+					let opt = document.createElement("input");
+					opt.name = x;
+					opt.value = postData[x];
+					tempform.appendChild(opt);
+				}
+				document.body.appendChild(tempform);
+				this.$nextTick(e => {
+					tempform.submit();
+				})
+			},
+			close: function() {
+				this.$emit('onChangeFun', {
+					action: 'payClose'
+				});
+			},
+			goPay: function(number, paytype) {
+				if (this.isCall) {
+					return this.$emit('onChangeFun', {
+						action: 'payCheck',
+						value: paytype
+					});
+				}
+				let that = this;
+				if (!that.order_id) return that.$util.Tips({
+					title: 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: () => {}
+					});
+				}
+				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;
+					if (res.data.status == 'ALLINPAY_PAY') {
+						uni.hideLoading();
+						// #ifdef MP
+						wx.openEmbeddedMiniProgram({
+							appId: 'wxef277996acc166c3',
+							extraData: {
+								cusid: jsConfig.cusid,
+								appid: jsConfig.appid,
+								version: jsConfig.version,
+								trxamt: jsConfig.trxamt,
+								reqsn: jsConfig.reqsn,
+								notify_url: jsConfig.notify_url,
+								body: jsConfig.body,
+								remark: jsConfig.remark,
+								validtime: jsConfig.validtime,
+								randomstr: jsConfig.randomstr,
+								paytype: jsConfig.paytype,
+								sign: jsConfig.sign,
+								signtype: jsConfig.signtype
+							}
+						})
+						this.jumpData = {
+							orderId: res.data.result.orderId,
+							msg: res.msg,
+						}
+						// #endif
+						// #ifdef APP-PLUS
+						plus.runtime.openURL(jsConfig.payinfo);
+						// #endif
+						// #ifdef H5
+						this.formpost(res.data.result.pay_url, jsConfig)
+						// #endif
+					} else {
+						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.h5_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>

+ 206 - 0
components/privacyAgreementPopup/index.vue

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

+ 195 - 0
components/productConSwiper/index.vue

@@ -0,0 +1,195 @@
+<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='encodeURI(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" @click.stop="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" @click.stop="openImage(index)" />
+				</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.$set(this, 'controls', false)
+				this.videoContext.play();
+				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);
+			},
+			// 查看图片详情
+			openImage(index) {
+				this.$emit('showSwiperImg', index)
+			}
+		}
+	}
+</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>

+ 429 - 0
components/productWindow/index.vue

@@ -0,0 +1,429 @@
+<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="line2 store-name">
+						{{ 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 + unitName }}</text>
+						<text class='stock' v-if="limitNum && type">{{$t(`库存`) }}:{{attr.productSelect.quota}}</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">
+						<text class='stock' v-if="limitNum && !type">{{$t(`限购`)}}{{limitNum + unitName}}</text>
+						<text class='stock line' v-if='limitNum && !type && minQty > 1'> | </text>
+						<text class="stock" v-if='minQty > 1'>{{$t(`起购`)}}{{ minQty + unitName }}</text>
+						<view class="item reduce acea-row row-center-wrapper"
+							:class="attr.productSelect.cart_num <= minQty ? 'on' : ''"
+							v-if="attr.productSelect.cart_num <= minQty">
+							<text class="iconfont icon-shangpinshuliang-jian"></text>
+						</view>
+						<view class="item reduce acea-row row-center-wrapper"
+							:class="attr.productSelect.cart_num <= minQty ? '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
+			},
+			minQty: {
+				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', e);
+			},
+			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 80rpx 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: 470rpx;
+		font-size: 28rpx;
+		color: #202020;
+	}
+
+	.product-window .textpic .text .money {
+		font-size: 24rpx;
+		margin-top: 10rpx;
+	}
+
+	.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;
+		align-items: center;
+	}
+
+	.product-window .cart .title {
+		font-size: 30rpx;
+		color: #999;
+	}
+
+	.product-window .cart .carnum {
+		height: 54rpx;
+
+		.stock {
+			font-size: 20rpx;
+			line-height: 54rpx;
+			color: #aaa;
+		}
+
+		.line {
+			padding: 0 6rpx;
+		}
+	}
+
+	.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>

+ 160 - 0
components/recommend/index.vue

@@ -0,0 +1,160 @@
+<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 line2'>{{item.store_name}}</view>
+				<view class='money font-color'>{{$t(`¥`)}}<text class='num'>{{item.price}}</text></view>
+				<!-- <view class='vip-money' v-if="item.vip_price && item.vip_price > 0 && item.base">
+					{{$t(`¥`)}}{{item.vip_price}}
+					<image src='/static/images/jvip.png' class="jvip"></image>
+				</view>
+				<view class='vip-money' v-if="item.vip_price && item.vip_price > 0 && item.is_vip">
+					{{$t(`¥`)}}{{item.vip_price}}
+					<image src='/static/images/vip.png'></image>
+				</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);
+		padding-bottom: 10rpx;
+	}
+
+	.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;
+		line-height: 34rpx;
+		height: 68rpx;
+	}
+
+	.recommend .recommendList .item .money {
+		font-size: 20rpx;
+		margin-top: 8rpx;
+		padding: 0 10rpx 0rpx 10rpx;
+	}
+
+	.recommend .vip-money {
+		font-size: 24rpx;
+		color: #282828;
+		font-weight: bold;
+		display: flex;
+		align-items: center;
+		padding: 0rpx 0 0 10rpx;
+
+		image {
+			width: 46rpx;
+			height: 21rpx;
+			margin-left: 4rpx;
+		}
+	}
+
+	.recommend .recommendList .item .money .num {
+		font-size: 28rpx;
+	}
+</style>

+ 158 - 0
components/shareRedPackets/index.vue

@@ -0,0 +1,158 @@
+<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;
+		line-height: 30rpx;
+		width: 100%;
+		text-align: center;
+	}
+
+	.sharing-packets .sharing-con .text .money {
+		font-size: 32rpx;
+		line-height: 42rpx;
+		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;
+		line-height: 18rpx;
+		color: #999;
+		margin-top: 5rpx;
+	}
+
+	.sharing-packets .sharing-con .text .shareBut {
+		font-size: 22rpx;
+		line-height: 48rpx;
+		color: #fff;
+		/* #ifdef H5 */
+		margin-top: 28rpx;
+		/* #endif */
+
+		/* #ifndef H5 */
+		margin-top: 26rpx;
+		/* #endif */
+
+	}
+</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>

+ 0 - 1355
components/wangding-pickerAddress/data.js

@@ -1,1355 +0,0 @@
-export default [{
-	"name": "北京",
-	"city": [{
-		"name": "北京市",
-		"area": ["东城区", "西城区", "朝阳区", "丰台区", "石景山区", "海淀区", "门头沟区", "房山区", "通州区", "顺义区", "昌平区", "大兴区",
-			"怀柔区", "平谷区", "密云区", "延庆区"
-		]
-	}]
-}, {
-	"name": "天津",
-	"city": [{
-		"name": "天津市",
-		"area": ["和平区", "河东区", "河西区", "南开区", "河北区", "红桥区", "东丽区", "西青区", "津南区", "北辰区", "武清区", "宝坻区", "滨海新区",
-			"宁河区", "静海区", "蓟州区"
-		]
-	}]
-}, {
-	"name": "河北",
-	"city": [{
-		"name": "石家庄市",
-		"area": ["市辖区", "长安区", "桥西区", "新华区", "井陉矿区", "裕华区", "藁城区", "鹿泉区", "栾城区", "井陉县", "正定县", "行唐县", "灵寿县",
-			"高邑县", "深泽县", "赞皇县", "无极县", "平山县", "元氏县", "赵县", "晋州市", "新乐市"
-		]
-	}, {
-		"name": "唐山市",
-		"area": ["市辖区", "路南区", "路北区", "古冶区", "开平区", "丰南区", "丰润区", "曹妃甸区", "滦县", "滦南县", "乐亭县", "迁西县", "玉田县",
-			"遵化市", "迁安市"
-		]
-	}, {
-		"name": "秦皇岛市",
-		"area": ["市辖区", "海港区", "山海关区", "北戴河区", "抚宁区", "青龙满族自治县", "昌黎县", "卢龙县"]
-	}, {
-		"name": "邯郸市",
-		"area": ["市辖区", "邯山区", "丛台区", "复兴区", "峰峰矿区", "邯郸县", "临漳县", "成安县", "大名县", "涉县", "磁县", "肥乡县", "永年县",
-			"邱县", "鸡泽县", "广平县", "馆陶县", "魏县", "曲周县", "武安市"
-		]
-	}, {
-		"name": "邢台市",
-		"area": ["市辖区", "桥东区", "桥西区", "邢台县", "临城县", "内丘县", "柏乡县", "隆尧县", "任县", "南和县", "宁晋县", "巨鹿县", "新河县",
-			"广宗县", "平乡县", "威县", "清河县", "临西县", "南宫市", "沙河市"
-		]
-	}, {
-		"name": "保定市",
-		"area": ["市辖区", "竞秀区", "莲池区", "满城区", "清苑区", "徐水区", "涞水县", "阜平县", "定兴县", "唐县", "高阳县", "容城县", "涞源县",
-			"望都县", "安新县", "易县", "曲阳县", "蠡县", "顺平县", "博野县", "雄县", "涿州市", "安国市", "高碑店市"
-		]
-	}, {
-		"name": "张家口市",
-		"area": ["市辖区", "桥东区", "桥西区", "宣化区", "下花园区", "万全区", "崇礼区", "张北县", "康保县", "沽源县", "尚义县", "蔚县", "阳原县",
-			"怀安县", "怀来县", "涿鹿县", "赤城县"
-		]
-	}, {
-		"name": "承德市",
-		"area": ["市辖区", "双桥区", "双滦区", "鹰手营子矿区", "承德县", "兴隆县", "平泉县", "滦平县", "隆化县", "丰宁满族自治县", "宽城满族自治县",
-			"围场满族蒙古族自治县"
-		]
-	}, {
-		"name": "沧州市",
-		"area": ["市辖区", "新华区", "运河区", "沧县", "青县", "东光县", "海兴县", "盐山县", "肃宁县", "南皮县", "吴桥县", "献县", "孟村回族自治县",
-			"泊头市", "任丘市", "黄骅市", "河间市"
-		]
-	}, {
-		"name": "廊坊市",
-		"area": ["市辖区", "安次区", "广阳区", "固安县", "永清县", "香河县", "大城县", "文安县", "大厂回族自治县", "霸州市", "三河市"]
-	}, {
-		"name": "衡水市",
-		"area": ["市辖区", "桃城区", "冀州区", "枣强县", "武邑县", "武强县", "饶阳县", "安平县", "故城县", "景县", "阜城县", "深州市"]
-	}, {
-		"name": "直辖县",
-		"area": ["定州市", "辛集市"]
-	}]
-}, {
-	"name": "山西",
-	"city": [{
-		"name": "太原市",
-		"area": ["市辖区", "小店区", "迎泽区", "杏花岭区", "尖草坪区", "万柏林区", "晋源区", "清徐县", "阳曲县", "娄烦县", "古交市"]
-	}, {
-		"name": "大同市",
-		"area": ["市辖区", "城区", "矿区", "南郊区", "新荣区", "阳高县", "天镇县", "广灵县", "灵丘县", "浑源县", "左云县", "大同县"]
-	}, {
-		"name": "阳泉市",
-		"area": ["市辖区", "城区", "矿区", "郊区", "平定县", "盂县"]
-	}, {
-		"name": "长治市",
-		"area": ["市辖区", "城区", "郊区", "长治县", "襄垣县", "屯留县", "平顺县", "黎城县", "壶关县", "长子县", "武乡县", "沁县", "沁源县",
-			"潞城市"
-		]
-	}, {
-		"name": "晋城市",
-		"area": ["市辖区", "城区", "沁水县", "阳城县", "陵川县", "泽州县", "高平市"]
-	}, {
-		"name": "朔州市",
-		"area": ["市辖区", "朔城区", "平鲁区", "山阴县", "应县", "右玉县", "怀仁县"]
-	}, {
-		"name": "晋中市",
-		"area": ["市辖区", "榆次区", "榆社县", "左权县", "和顺县", "昔阳县", "寿阳县", "太谷县", "祁县", "平遥县", "灵石县", "介休市"]
-	}, {
-		"name": "运城市",
-		"area": ["市辖区", "盐湖区", "临猗县", "万荣县", "闻喜县", "稷山县", "新绛县", "绛县", "垣曲县", "夏县", "平陆县", "芮城县", "永济市",
-			"河津市"
-		]
-	}, {
-		"name": "忻州市",
-		"area": ["市辖区", "忻府区", "定襄县", "五台县", "代县", "繁峙县", "宁武县", "静乐县", "神池县", "五寨县", "岢岚县", "河曲县", "保德县",
-			"偏关县", "原平市"
-		]
-	}, {
-		"name": "临汾市",
-		"area": ["市辖区", "尧都区", "曲沃县", "翼城县", "襄汾县", "洪洞县", "古县", "安泽县", "浮山县", "吉县", "乡宁县", "大宁县", "隰县",
-			"永和县", "蒲县", "汾西县", "侯马市", "霍州市"
-		]
-	}, {
-		"name": "吕梁市",
-		"area": ["市辖区", "离石区", "文水县", "交城县", "兴县", "临县", "柳林县", "石楼县", "岚县", "方山县", "中阳县", "交口县", "孝义市",
-			"汾阳市"
-		]
-	}]
-}, {
-	"name": "内蒙古",
-	"city": [{
-		"name": "呼和浩特市",
-		"area": ["市辖区", "新城区", "回民区", "玉泉区", "赛罕区", "土默特左旗", "托克托县", "和林格尔县", "清水河县", "武川县"]
-	}, {
-		"name": "包头市",
-		"area": ["市辖区", "东河区", "昆都仑区", "青山区", "石拐区", "白云鄂博矿区", "九原区", "土默特右旗", "固阳县", "达尔罕茂明安联合旗"]
-	}, {
-		"name": "乌海市",
-		"area": ["市辖区", "海勃湾区", "海南区", "乌达区"]
-	}, {
-		"name": "赤峰市",
-		"area": ["市辖区", "红山区", "元宝山区", "松山区", "阿鲁科尔沁旗", "巴林左旗", "巴林右旗", "林西县", "克什克腾旗", "翁牛特旗", "喀喇沁旗",
-			"宁城县", "敖汉旗"
-		]
-	}, {
-		"name": "通辽市",
-		"area": ["市辖区", "科尔沁区", "科尔沁左翼中旗", "科尔沁左翼后旗", "开鲁县", "库伦旗", "奈曼旗", "扎鲁特旗", "霍林郭勒市"]
-	}, {
-		"name": "鄂尔多斯市",
-		"area": ["市辖区", "东胜区", "康巴什区", "达拉特旗", "准格尔旗", "鄂托克前旗", "鄂托克旗", "杭锦旗", "乌审旗", "伊金霍洛旗"]
-	}, {
-		"name": "呼伦贝尔市",
-		"area": ["市辖区", "海拉尔区", "扎赉诺尔区", "阿荣旗", "莫力达瓦达斡尔族自治旗", "鄂伦春自治旗", "鄂温克族自治旗", "陈巴尔虎旗", "新巴尔虎左旗",
-			"新巴尔虎右旗", "满洲里市", "牙克石市", "扎兰屯市", "额尔古纳市", "根河市"
-		]
-	}, {
-		"name": "巴彦淖尔市",
-		"area": ["市辖区", "临河区", "五原县", "磴口县", "乌拉特前旗", "乌拉特中旗", "乌拉特后旗", "杭锦后旗"]
-	}, {
-		"name": "乌兰察布市",
-		"area": ["市辖区", "集宁区", "卓资县", "化德县", "商都县", "兴和县", "凉城县", "察哈尔右翼前旗", "察哈尔右翼中旗", "察哈尔右翼后旗", "四子王旗",
-			"丰镇市"
-		]
-	}, {
-		"name": "兴安盟",
-		"area": ["乌兰浩特市", "阿尔山市", "科尔沁右翼前旗", "科尔沁右翼中旗", "扎赉特旗", "突泉县"]
-	}, {
-		"name": "锡林郭勒盟",
-		"area": ["二连浩特市", "锡林浩特市", "阿巴嘎旗", "苏尼特左旗", "苏尼特右旗", "东乌珠穆沁旗", "西乌珠穆沁旗", "太仆寺旗", "镶黄旗", "正镶白旗",
-			"正蓝旗", "多伦县"
-		]
-	}, {
-		"name": "阿拉善盟",
-		"area": ["阿拉善左旗", "阿拉善右旗", "额济纳旗"]
-	}]
-}, {
-	"name": "辽宁",
-	"city": [{
-		"name": "沈阳市",
-		"area": ["市辖区", "和平区", "沈河区", "大东区", "皇姑区", "铁西区", "苏家屯区", "浑南区", "沈北新区", "于洪区", "辽中区", "康平县",
-			"法库县", "新民市"
-		]
-	}, {
-		"name": "大连市",
-		"area": ["市辖区", "中山区", "西岗区", "沙河口区", "甘井子区", "旅顺口区", "金州区", "普兰店区", "长海县", "瓦房店市", "庄河市"]
-	}, {
-		"name": "鞍山市",
-		"area": ["市辖区", "铁东区", "铁西区", "立山区", "千山区", "台安县", "岫岩满族自治县", "海城市"]
-	}, {
-		"name": "抚顺市",
-		"area": ["市辖区", "新抚区", "东洲区", "望花区", "顺城区", "抚顺县", "新宾满族自治县", "清原满族自治县"]
-	}, {
-		"name": "本溪市",
-		"area": ["市辖区", "平山区", "溪湖区", "明山区", "南芬区", "本溪满族自治县", "桓仁满族自治县"]
-	}, {
-		"name": "丹东市",
-		"area": ["市辖区", "元宝区", "振兴区", "振安区", "宽甸满族自治县", "东港市", "凤城市"]
-	}, {
-		"name": "锦州市",
-		"area": ["市辖区", "古塔区", "凌河区", "太和区", "黑山县", "义县", "凌海市", "北镇市"]
-	}, {
-		"name": "营口市",
-		"area": ["市辖区", "站前区", "西市区", "鲅鱼圈区", "老边区", "盖州市", "大石桥市"]
-	}, {
-		"name": "阜新市",
-		"area": ["市辖区", "海州区", "新邱区", "太平区", "清河门区", "细河区", "阜新蒙古族自治县", "彰武县"]
-	}, {
-		"name": "辽阳市",
-		"area": ["市辖区", "白塔区", "文圣区", "宏伟区", "弓长岭区", "太子河区", "辽阳县", "灯塔市"]
-	}, {
-		"name": "盘锦市",
-		"area": ["市辖区", "双台子区", "兴隆台区", "大洼区", "盘山县"]
-	}, {
-		"name": "铁岭市",
-		"area": ["市辖区", "银州区", "清河区", "铁岭县", "西丰县", "昌图县", "调兵山市", "开原市"]
-	}, {
-		"name": "朝阳市",
-		"area": ["市辖区", "双塔区", "龙城区", "朝阳县", "建平县", "喀喇沁左翼蒙古族自治县", "北票市", "凌源市"]
-	}, {
-		"name": "葫芦岛市",
-		"area": ["市辖区", "连山区", "龙港区", "南票区", "绥中县", "建昌县", "兴城市"]
-	}]
-}, {
-	"name": "吉林",
-	"city": [{
-		"name": "长春市",
-		"area": ["市辖区", "南关区", "宽城区", "朝阳区", "二道区", "绿园区", "双阳区", "九台区", "农安县", "榆树市", "德惠市"]
-	}, {
-		"name": "吉林市",
-		"area": ["市辖区", "昌邑区", "龙潭区", "船营区", "丰满区", "永吉县", "蛟河市", "桦甸市", "舒兰市", "磐石市"]
-	}, {
-		"name": "四平市",
-		"area": ["市辖区", "铁西区", "铁东区", "梨树县", "伊通满族自治县", "公主岭市", "双辽市"]
-	}, {
-		"name": "辽源市",
-		"area": ["市辖区", "龙山区", "西安区", "东丰县", "东辽县"]
-	}, {
-		"name": "通化市",
-		"area": ["市辖区", "东昌区", "二道江区", "通化县", "辉南县", "柳河县", "梅河口市", "集安市"]
-	}, {
-		"name": "白山市",
-		"area": ["市辖区", "浑江区", "江源区", "抚松县", "靖宇县", "长白朝鲜族自治县", "临江市"]
-	}, {
-		"name": "松原市",
-		"area": ["市辖区", "宁江区", "前郭尔罗斯蒙古族自治县", "长岭县", "乾安县", "扶余市"]
-	}, {
-		"name": "白城市",
-		"area": ["市辖区", "洮北区", "镇赉县", "通榆县", "洮南市", "大安市"]
-	}, {
-		"name": "延边朝鲜族自治州",
-		"area": ["延吉市", "图们市", "敦化市", "珲春市", "龙井市", "和龙市", "汪清县", "安图县"]
-	}]
-}, {
-	"name": "黑龙江",
-	"city": [{
-		"name": "哈尔滨市",
-		"area": ["市辖区", "道里区", "南岗区", "道外区", "平房区", "松北区", "香坊区", "呼兰区", "阿城区", "双城区", "依兰县", "方正县", "宾县",
-			"巴彦县", "木兰县", "通河县", "延寿县", "尚志市", "五常市"
-		]
-	}, {
-		"name": "齐齐哈尔市",
-		"area": ["市辖区", "龙沙区", "建华区", "铁锋区", "昂昂溪区", "富拉尔基区", "碾子山区", "梅里斯达斡尔族区", "龙江县", "依安县", "泰来县",
-			"甘南县", "富裕县", "克山县", "克东县", "拜泉县", "讷河市"
-		]
-	}, {
-		"name": "鸡西市",
-		"area": ["市辖区", "鸡冠区", "恒山区", "滴道区", "梨树区", "城子河区", "麻山区", "鸡东县", "虎林市", "密山市"]
-	}, {
-		"name": "鹤岗市",
-		"area": ["市辖区", "向阳区", "工农区", "南山区", "兴安区", "东山区", "兴山区", "萝北县", "绥滨县"]
-	}, {
-		"name": "双鸭山市",
-		"area": ["市辖区", "尖山区", "岭东区", "四方台区", "宝山区", "集贤县", "友谊县", "宝清县", "饶河县"]
-	}, {
-		"name": "大庆市",
-		"area": ["市辖区", "萨尔图区", "龙凤区", "让胡路区", "红岗区", "大同区", "肇州县", "肇源县", "林甸县", "杜尔伯特蒙古族自治县"]
-	}, {
-		"name": "伊春市",
-		"area": ["市辖区", "伊春区", "南岔区", "友好区", "西林区", "翠峦区", "新青区", "美溪区", "金山屯区", "五营区", "乌马河区", "汤旺河区",
-			"带岭区", "乌伊岭区", "红星区", "上甘岭区", "嘉荫县", "铁力市"
-		]
-	}, {
-		"name": "佳木斯市",
-		"area": ["市辖区", "向阳区", "前进区", "东风区", "郊区", "桦南县", "桦川县", "汤原县", "同江市", "富锦市", "抚远市"]
-	}, {
-		"name": "七台河市",
-		"area": ["市辖区", "新兴区", "桃山区", "茄子河区", "勃利县"]
-	}, {
-		"name": "牡丹江市",
-		"area": ["市辖区", "东安区", "阳明区", "爱民区", "西安区", "林口县", "绥芬河市", "海林市", "宁安市", "穆棱市", "东宁市"]
-	}, {
-		"name": "黑河市",
-		"area": ["市辖区", "爱辉区", "嫩江县", "逊克县", "孙吴县", "北安市", "五大连池市"]
-	}, {
-		"name": "绥化市",
-		"area": ["市辖区", "北林区", "望奎县", "兰西县", "青冈县", "庆安县", "明水县", "绥棱县", "安达市", "肇东市", "海伦市"]
-	}, {
-		"name": "大兴安岭地区",
-		"area": ["呼玛县", "塔河县", "漠河县"]
-	}]
-}, {
-	"name": "上海",
-	"city": [{
-		"name": "上海市",
-		"area": ["黄浦区", "徐汇区", "长宁区", "静安区", "普陀区", "虹口区", "杨浦区", "闵行区", "宝山区", "嘉定区", "浦东新区", "金山区", "松江区",
-			"青浦区", "奉贤区", "崇明区"
-		]
-	}]
-}, {
-	"name": "江苏",
-	"city": [{
-		"name": "南京市",
-		"area": ["市辖区", "玄武区", "秦淮区", "建邺区", "鼓楼区", "浦口区", "栖霞区", "雨花台区", "江宁区", "六合区", "溧水区", "高淳区"]
-	}, {
-		"name": "无锡市",
-		"area": ["市辖区", "锡山区", "惠山区", "滨湖区", "梁溪区", "新吴区", "江阴市", "宜兴市"]
-	}, {
-		"name": "徐州市",
-		"area": ["市辖区", "鼓楼区", "云龙区", "贾汪区", "泉山区", "铜山区", "丰县", "沛县", "睢宁县", "新沂市", "邳州市"]
-	}, {
-		"name": "常州市",
-		"area": ["市辖区", "天宁区", "钟楼区", "新北区", "武进区", "金坛区", "溧阳市"]
-	}, {
-		"name": "苏州市",
-		"area": ["市辖区", "虎丘区", "吴中区", "相城区", "姑苏区", "吴江区", "常熟市", "张家港市", "昆山市", "太仓市"]
-	}, {
-		"name": "南通市",
-		"area": ["市辖区", "崇川区", "港闸区", "通州区", "海安县", "如东县", "启东市", "如皋市", "海门市"]
-	}, {
-		"name": "连云港市",
-		"area": ["市辖区", "连云区", "海州区", "赣榆区", "东海县", "灌云县", "灌南县"]
-	}, {
-		"name": "淮安市",
-		"area": ["市辖区", "淮安区", "淮阴区", "清江浦区", "洪泽区", "涟水县", "盱眙县", "金湖县"]
-	}, {
-		"name": "盐城市",
-		"area": ["市辖区", "亭湖区", "盐都区", "大丰区", "响水县", "滨海县", "阜宁县", "射阳县", "建湖县", "东台市"]
-	}, {
-		"name": "扬州市",
-		"area": ["市辖区", "广陵区", "邗江区", "江都区", "宝应县", "仪征市", "高邮市"]
-	}, {
-		"name": "镇江市",
-		"area": ["市辖区", "京口区", "润州区", "丹徒区", "丹阳市", "扬中市", "句容市"]
-	}, {
-		"name": "泰州市",
-		"area": ["市辖区", "海陵区", "高港区", "姜堰区", "兴化市", "靖江市", "泰兴市"]
-	}, {
-		"name": "宿迁市",
-		"area": ["市辖区", "宿城区", "宿豫区", "沭阳县", "泗阳县", "泗洪县"]
-	}]
-}, {
-	"name": "浙江",
-	"city": [{
-		"name": "杭州市",
-		"area": ["市辖区", "上城区", "下城区", "江干区", "拱墅区", "西湖区", "滨江区", "萧山区", "余杭区", "富阳区", "桐庐县", "淳安县", "建德市",
-			"临安市"
-		]
-	}, {
-		"name": "宁波市",
-		"area": ["市辖区", "海曙区", "江东区", "江北区", "北仑区", "镇海区", "鄞州区", "象山县", "宁海县", "余姚市", "慈溪市", "奉化市"]
-	}, {
-		"name": "温州市",
-		"area": ["市辖区", "鹿城区", "龙湾区", "瓯海区", "洞头区", "永嘉县", "平阳县", "苍南县", "文成县", "泰顺县", "瑞安市", "乐清市"]
-	}, {
-		"name": "嘉兴市",
-		"area": ["市辖区", "南湖区", "秀洲区", "嘉善县", "海盐县", "海宁市", "平湖市", "桐乡市"]
-	}, {
-		"name": "湖州市",
-		"area": ["市辖区", "吴兴区", "南浔区", "德清县", "长兴县", "安吉县"]
-	}, {
-		"name": "绍兴市",
-		"area": ["市辖区", "越城区", "柯桥区", "上虞区", "新昌县", "诸暨市", "嵊州市"]
-	}, {
-		"name": "金华市",
-		"area": ["市辖区", "婺城区", "金东区", "武义县", "浦江县", "磐安县", "兰溪市", "义乌市", "东阳市", "永康市"]
-	}, {
-		"name": "衢州市",
-		"area": ["市辖区", "柯城区", "衢江区", "常山县", "开化县", "龙游县", "江山市"]
-	}, {
-		"name": "舟山市",
-		"area": ["市辖区", "定海区", "普陀区", "岱山县", "嵊泗县"]
-	}, {
-		"name": "台州市",
-		"area": ["市辖区", "椒江区", "黄岩区", "路桥区", "玉环县", "三门县", "天台县", "仙居县", "温岭市", "临海市"]
-	}, {
-		"name": "丽水市",
-		"area": ["市辖区", "莲都区", "青田县", "缙云县", "遂昌县", "松阳县", "云和县", "庆元县", "景宁畲族自治县", "龙泉市"]
-	}]
-}, {
-	"name": "安徽",
-	"city": [{
-		"name": "合肥市",
-		"area": ["市辖区", "瑶海区", "庐阳区", "蜀山区", "包河区", "长丰县", "肥东县", "肥西县", "庐江县", "巢湖市"]
-	}, {
-		"name": "芜湖市",
-		"area": ["市辖区", "镜湖区", "弋江区", "鸠江区", "三山区", "芜湖县", "繁昌县", "南陵县", "无为县"]
-	}, {
-		"name": "蚌埠市",
-		"area": ["市辖区", "龙子湖区", "蚌山区", "禹会区", "淮上区", "怀远县", "五河县", "固镇县"]
-	}, {
-		"name": "淮南市",
-		"area": ["市辖区", "大通区", "田家庵区", "谢家集区", "八公山区", "潘集区", "凤台县", "寿县"]
-	}, {
-		"name": "马鞍山市",
-		"area": ["市辖区", "花山区", "雨山区", "博望区", "当涂县", "含山县", "和县"]
-	}, {
-		"name": "淮北市",
-		"area": ["市辖区", "杜集区", "相山区", "烈山区", "濉溪县"]
-	}, {
-		"name": "铜陵市",
-		"area": ["市辖区", "铜官区", "义安区", "郊区", "枞阳县"]
-	}, {
-		"name": "安庆市",
-		"area": ["市辖区", "迎江区", "大观区", "宜秀区", "怀宁县", "潜山县", "太湖县", "宿松县", "望江县", "岳西县", "桐城市"]
-	}, {
-		"name": "黄山市",
-		"area": ["市辖区", "屯溪区", "黄山区", "徽州区", "歙县", "休宁县", "黟县", "祁门县"]
-	}, {
-		"name": "滁州市",
-		"area": ["市辖区", "琅琊区", "南谯区", "来安县", "全椒县", "定远县", "凤阳县", "天长市", "明光市"]
-	}, {
-		"name": "阜阳市",
-		"area": ["市辖区", "颍州区", "颍东区", "颍泉区", "临泉县", "太和县", "阜南县", "颍上县", "界首市"]
-	}, {
-		"name": "宿州市",
-		"area": ["市辖区", "埇桥区", "砀山县", "萧县", "灵璧县", "泗县"]
-	}, {
-		"name": "六安市",
-		"area": ["市辖区", "金安区", "裕安区", "叶集区", "霍邱县", "舒城县", "金寨县", "霍山县"]
-	}, {
-		"name": "亳州市",
-		"area": ["市辖区", "谯城区", "涡阳县", "蒙城县", "利辛县"]
-	}, {
-		"name": "池州市",
-		"area": ["市辖区", "贵池区", "东至县", "石台县", "青阳县"]
-	}, {
-		"name": "宣城市",
-		"area": ["市辖区", "宣州区", "郎溪县", "广德县", "泾县", "绩溪县", "旌德县", "宁国市"]
-	}]
-}, {
-	"name": "福建",
-	"city": [{
-		"name": "福州市",
-		"area": ["市辖区", "鼓楼区", "台江区", "仓山区", "马尾区", "晋安区", "闽侯县", "连江县", "罗源县", "闽清县", "永泰县", "平潭县", "福清市",
-			"长乐市"
-		]
-	}, {
-		"name": "厦门市",
-		"area": ["市辖区", "思明区", "海沧区", "湖里区", "集美区", "同安区", "翔安区"]
-	}, {
-		"name": "莆田市",
-		"area": ["市辖区", "城厢区", "涵江区", "荔城区", "秀屿区", "仙游县"]
-	}, {
-		"name": "三明市",
-		"area": ["市辖区", "梅列区", "三元区", "明溪县", "清流县", "宁化县", "大田县", "尤溪县", "沙县", "将乐县", "泰宁县", "建宁县", "永安市"]
-	}, {
-		"name": "泉州市",
-		"area": ["市辖区", "鲤城区", "丰泽区", "洛江区", "泉港区", "惠安县", "安溪县", "永春县", "德化县", "金门县", "石狮市", "晋江市", "南安市"]
-	}, {
-		"name": "漳州市",
-		"area": ["市辖区", "芗城区", "龙文区", "云霄县", "漳浦县", "诏安县", "长泰县", "东山县", "南靖县", "平和县", "华安县", "龙海市"]
-	}, {
-		"name": "南平市",
-		"area": ["市辖区", "延平区", "建阳区", "顺昌县", "浦城县", "光泽县", "松溪县", "政和县", "邵武市", "武夷山市", "建瓯市"]
-	}, {
-		"name": "龙岩市",
-		"area": ["市辖区", "新罗区", "永定区", "长汀县", "上杭县", "武平县", "连城县", "漳平市"]
-	}, {
-		"name": "宁德市",
-		"area": ["市辖区", "蕉城区", "霞浦县", "古田县", "屏南县", "寿宁县", "周宁县", "柘荣县", "福安市", "福鼎市"]
-	}]
-}, {
-	"name": "江西",
-	"city": [{
-		"name": "南昌市",
-		"area": ["市辖区", "东湖区", "西湖区", "青云谱区", "湾里区", "青山湖区", "新建区", "南昌县", "安义县", "进贤县"]
-	}, {
-		"name": "景德镇市",
-		"area": ["市辖区", "昌江区", "珠山区", "浮梁县", "乐平市"]
-	}, {
-		"name": "萍乡市",
-		"area": ["市辖区", "安源区", "湘东区", "莲花县", "上栗县", "芦溪县"]
-	}, {
-		"name": "九江市",
-		"area": ["市辖区", "濂溪区", "浔阳区", "九江县", "武宁县", "修水县", "永修县", "德安县", "都昌县", "湖口县", "彭泽县", "瑞昌市", "共青城市",
-			"庐山市"
-		]
-	}, {
-		"name": "新余市",
-		"area": ["市辖区", "渝水区", "分宜县"]
-	}, {
-		"name": "鹰潭市",
-		"area": ["市辖区", "月湖区", "余江县", "贵溪市"]
-	}, {
-		"name": "赣州市",
-		"area": ["市辖区", "章贡区", "南康区", "赣县", "信丰县", "大余县", "上犹县", "崇义县", "安远县", "龙南县", "定南县", "全南县", "宁都县",
-			"于都县", "兴国县", "会昌县", "寻乌县", "石城县", "瑞金市"
-		]
-	}, {
-		"name": "吉安市",
-		"area": ["市辖区", "吉州区", "青原区", "吉安县", "吉水县", "峡江县", "新干县", "永丰县", "泰和县", "遂川县", "万安县", "安福县", "永新县",
-			"井冈山市"
-		]
-	}, {
-		"name": "宜春市",
-		"area": ["市辖区", "袁州区", "奉新县", "万载县", "上高县", "宜丰县", "靖安县", "铜鼓县", "丰城市", "樟树市", "高安市"]
-	}, {
-		"name": "抚州市",
-		"area": ["市辖区", "临川区", "南城县", "黎川县", "南丰县", "崇仁县", "乐安县", "宜黄县", "金溪县", "资溪县", "东乡县", "广昌县"]
-	}, {
-		"name": "上饶市",
-		"area": ["市辖区", "信州区", "广丰区", "上饶县", "玉山县", "铅山县", "横峰县", "弋阳县", "余干县", "鄱阳县", "万年县", "婺源县", "德兴市"]
-	}]
-}, {
-	"name": "山东",
-	"city": [{
-		"name": "济南市",
-		"area": ["市辖区", "历下区", "市中区", "槐荫区", "天桥区", "历城区", "长清区", "平阴县", "济阳县", "商河县", "章丘市"]
-	}, {
-		"name": "青岛市",
-		"area": ["市辖区", "市南区", "市北区", "黄岛区", "崂山区", "李沧区", "城阳区", "胶州市", "即墨市", "平度市", "莱西市"]
-	}, {
-		"name": "淄博市",
-		"area": ["市辖区", "淄川区", "张店区", "博山区", "临淄区", "周村区", "桓台县", "高青县", "沂源县"]
-	}, {
-		"name": "枣庄市",
-		"area": ["市辖区", "市中区", "薛城区", "峄城区", "台儿庄区", "山亭区", "滕州市"]
-	}, {
-		"name": "东营市",
-		"area": ["市辖区", "东营区", "河口区", "垦利区", "利津县", "广饶县"]
-	}, {
-		"name": "烟台市",
-		"area": ["市辖区", "芝罘区", "福山区", "牟平区", "莱山区", "长岛县", "龙口市", "莱阳市", "莱州市", "蓬莱市", "招远市", "栖霞市", "海阳市"]
-	}, {
-		"name": "潍坊市",
-		"area": ["市辖区", "潍城区", "寒亭区", "坊子区", "奎文区", "临朐县", "昌乐县", "青州市", "诸城市", "寿光市", "安丘市", "高密市", "昌邑市"]
-	}, {
-		"name": "济宁市",
-		"area": ["市辖区", "任城区", "兖州区", "微山县", "鱼台县", "金乡县", "嘉祥县", "汶上县", "泗水县", "梁山县", "曲阜市", "邹城市"]
-	}, {
-		"name": "泰安市",
-		"area": ["市辖区", "泰山区", "岱岳区", "宁阳县", "东平县", "新泰市", "肥城市"]
-	}, {
-		"name": "威海市",
-		"area": ["市辖区", "环翠区", "文登区", "荣成市", "乳山市"]
-	}, {
-		"name": "日照市",
-		"area": ["市辖区", "东港区", "岚山区", "五莲县", "莒县"]
-	}, {
-		"name": "莱芜市",
-		"area": ["市辖区", "莱城区", "钢城区"]
-	}, {
-		"name": "临沂市",
-		"area": ["市辖区", "兰山区", "罗庄区", "河东区", "沂南县", "郯城县", "沂水县", "兰陵县", "费县", "平邑县", "莒南县", "蒙阴县", "临沭县"]
-	}, {
-		"name": "德州市",
-		"area": ["市辖区", "德城区", "陵城区", "宁津县", "庆云县", "临邑县", "齐河县", "平原县", "夏津县", "武城县", "乐陵市", "禹城市"]
-	}, {
-		"name": "聊城市",
-		"area": ["市辖区", "东昌府区", "阳谷县", "莘县", "茌平县", "东阿县", "冠县", "高唐县", "临清市"]
-	}, {
-		"name": "滨州市",
-		"area": ["市辖区", "滨城区", "沾化区", "惠民县", "阳信县", "无棣县", "博兴县", "邹平县"]
-	}, {
-		"name": "菏泽市",
-		"area": ["市辖区", "牡丹区", "定陶区", "曹县", "单县", "成武县", "巨野县", "郓城县", "鄄城县", "东明县"]
-	}]
-}, {
-	"name": "河南",
-	"city": [{
-		"name": "郑州市",
-		"area": ["市辖区", "中原区", "二七区", "管城回族区", "金水区", "上街区", "惠济区", "中牟县", "巩义市", "荥阳市", "新密市", "新郑市",
-			"登封市"]
-	}, {
-		"name": "开封市",
-		"area": ["市辖区", "龙亭区", "顺河回族区", "鼓楼区", "禹王台区", "金明区", "祥符区", "杞县", "通许县", "尉氏县", "兰考县"]
-	}, {
-		"name": "洛阳市",
-		"area": ["市辖区", "老城区", "西工区", "瀍河回族区", "涧西区", "吉利区", "洛龙区", "孟津县", "新安县", "栾川县", "嵩县", "汝阳县", "宜阳县",
-			"洛宁县", "伊川县", "偃师市"
-		]
-	}, {
-		"name": "平顶山市",
-		"area": ["市辖区", "新华区", "卫东区", "石龙区", "湛河区", "宝丰县", "叶县", "鲁山县", "郏县", "舞钢市", "汝州市"]
-	}, {
-		"name": "安阳市",
-		"area": ["市辖区", "文峰区", "北关区", "殷都区", "龙安区", "安阳县", "汤阴县", "滑县", "内黄县", "林州市"]
-	}, {
-		"name": "鹤壁市",
-		"area": ["市辖区", "鹤山区", "山城区", "淇滨区", "浚县", "淇县"]
-	}, {
-		"name": "新乡市",
-		"area": ["市辖区", "红旗区", "卫滨区", "凤泉区", "牧野区", "新乡县", "获嘉县", "原阳县", "延津县", "封丘县", "长垣县", "卫辉市", "辉县市"]
-	}, {
-		"name": "焦作市",
-		"area": ["市辖区", "解放区", "中站区", "马村区", "山阳区", "修武县", "博爱县", "武陟县", "温县", "沁阳市", "孟州市"]
-	}, {
-		"name": "濮阳市",
-		"area": ["市辖区", "华龙区", "清丰县", "南乐县", "范县", "台前县", "濮阳县"]
-	}, {
-		"name": "许昌市",
-		"area": ["市辖区", "魏都区", "许昌县", "鄢陵县", "襄城县", "禹州市", "长葛市"]
-	}, {
-		"name": "漯河市",
-		"area": ["市辖区", "源汇区", "郾城区", "召陵区", "舞阳县", "临颍县"]
-	}, {
-		"name": "三门峡市",
-		"area": ["市辖区", "湖滨区", "陕州区", "渑池县", "卢氏县", "义马市", "灵宝市"]
-	}, {
-		"name": "南阳市",
-		"area": ["市辖区", "宛城区", "卧龙区", "南召县", "方城县", "西峡县", "镇平县", "内乡县", "淅川县", "社旗县", "唐河县", "新野县", "桐柏县",
-			"邓州市"
-		]
-	}, {
-		"name": "商丘市",
-		"area": ["市辖区", "梁园区", "睢阳区", "民权县", "睢县", "宁陵县", "柘城县", "虞城县", "夏邑县", "永城市"]
-	}, {
-		"name": "信阳市",
-		"area": ["市辖区", "浉河区", "平桥区", "罗山县", "光山县", "新县", "商城县", "固始县", "潢川县", "淮滨县", "息县"]
-	}, {
-		"name": "周口市",
-		"area": ["市辖区", "川汇区", "扶沟县", "西华县", "商水县", "沈丘县", "郸城县", "淮阳县", "太康县", "鹿邑县", "项城市"]
-	}, {
-		"name": "驻马店市",
-		"area": ["市辖区", "驿城区", "西平县", "上蔡县", "平舆县", "正阳县", "确山县", "泌阳县", "汝南县", "遂平县", "新蔡县"]
-	}, {
-		"name": "直辖县",
-		"area": ["济源市"]
-	}]
-}, {
-	"name": "湖北",
-	"city": [{
-		"name": "武汉市",
-		"area": ["市辖区", "江岸区", "江汉区", "硚口区", "汉阳区", "武昌区", "青山区", "洪山区", "东西湖区", "汉南区", "蔡甸区", "江夏区", "黄陂区",
-			"新洲区"
-		]
-	}, {
-		"name": "黄石市",
-		"area": ["市辖区", "黄石港区", "西塞山区", "下陆区", "铁山区", "阳新县", "大冶市"]
-	}, {
-		"name": "十堰市",
-		"area": ["市辖区", "茅箭区", "张湾区", "郧阳区", "郧西县", "竹山县", "竹溪县", "房县", "丹江口市"]
-	}, {
-		"name": "宜昌市",
-		"area": ["市辖区", "西陵区", "伍家岗区", "点军区", "猇亭区", "夷陵区", "远安县", "兴山县", "秭归县", "长阳土家族自治县", "五峰土家族自治县",
-			"宜都市", "当阳市", "枝江市"
-		]
-	}, {
-		"name": "襄阳市",
-		"area": ["市辖区", "襄城区", "樊城区", "襄州区", "南漳县", "谷城县", "保康县", "老河口市", "枣阳市", "宜城市"]
-	}, {
-		"name": "鄂州市",
-		"area": ["市辖区", "梁子湖区", "华容区", "鄂城区"]
-	}, {
-		"name": "荆门市",
-		"area": ["市辖区", "东宝区", "掇刀区", "京山县", "沙洋县", "钟祥市"]
-	}, {
-		"name": "孝感市",
-		"area": ["市辖区", "孝南区", "孝昌县", "大悟县", "云梦县", "应城市", "安陆市", "汉川市"]
-	}, {
-		"name": "荆州市",
-		"area": ["市辖区", "沙市区", "荆州区", "公安县", "监利县", "江陵县", "石首市", "洪湖市", "松滋市"]
-	}, {
-		"name": "黄冈市",
-		"area": ["市辖区", "黄州区", "团风县", "红安县", "罗田县", "英山县", "浠水县", "蕲春县", "黄梅县", "麻城市", "武穴市"]
-	}, {
-		"name": "咸宁市",
-		"area": ["市辖区", "咸安区", "嘉鱼县", "通城县", "崇阳县", "通山县", "赤壁市"]
-	}, {
-		"name": "随州市",
-		"area": ["市辖区", "曾都区", "随县", "广水市"]
-	}, {
-		"name": "恩施土家族苗族自治州",
-		"area": ["恩施市", "利川市", "建始县", "巴东县", "宣恩县", "咸丰县", "来凤县", "鹤峰县"]
-	}, {
-		"name": "直辖县",
-		"area": ["仙桃市", "潜江市", "天门市", "神农架林区"]
-	}]
-}, {
-	"name": "湖南",
-	"city": [{
-		"name": "长沙市",
-		"area": ["市辖区", "芙蓉区", "天心区", "岳麓区", "开福区", "雨花区", "望城区", "长沙县", "宁乡县", "浏阳市"]
-	}, {
-		"name": "株洲市",
-		"area": ["市辖区", "荷塘区", "芦淞区", "石峰区", "天元区", "株洲县", "攸县", "茶陵县", "炎陵县", "醴陵市"]
-	}, {
-		"name": "湘潭市",
-		"area": ["市辖区", "雨湖区", "岳塘区", "湘潭县", "湘乡市", "韶山市"]
-	}, {
-		"name": "衡阳市",
-		"area": ["市辖区", "珠晖区", "雁峰区", "石鼓区", "蒸湘区", "南岳区", "衡阳县", "衡南县", "衡山县", "衡东县", "祁东县", "耒阳市", "常宁市"]
-	}, {
-		"name": "邵阳市",
-		"area": ["市辖区", "双清区", "大祥区", "北塔区", "邵东县", "新邵县", "邵阳县", "隆回县", "洞口县", "绥宁县", "新宁县", "城步苗族自治县",
-			"武冈市"
-		]
-	}, {
-		"name": "岳阳市",
-		"area": ["市辖区", "岳阳楼区", "云溪区", "君山区", "岳阳县", "华容县", "湘阴县", "平江县", "汨罗市", "临湘市"]
-	}, {
-		"name": "常德市",
-		"area": ["市辖区", "武陵区", "鼎城区", "安乡县", "汉寿县", "澧县", "临澧县", "桃源县", "石门县", "津市市"]
-	}, {
-		"name": "张家界市",
-		"area": ["市辖区", "永定区", "武陵源区", "慈利县", "桑植县"]
-	}, {
-		"name": "益阳市",
-		"area": ["市辖区", "资阳区", "赫山区", "南县", "桃江县", "安化县", "沅江市"]
-	}, {
-		"name": "郴州市",
-		"area": ["市辖区", "北湖区", "苏仙区", "桂阳县", "宜章县", "永兴县", "嘉禾县", "临武县", "汝城县", "桂东县", "安仁县", "资兴市"]
-	}, {
-		"name": "永州市",
-		"area": ["市辖区", "零陵区", "冷水滩区", "祁阳县", "东安县", "双牌县", "道县", "江永县", "宁远县", "蓝山县", "新田县", "江华瑶族自治县"]
-	}, {
-		"name": "怀化市",
-		"area": ["市辖区", "鹤城区", "中方县", "沅陵县", "辰溪县", "溆浦县", "会同县", "麻阳苗族自治县", "新晃侗族自治县", "芷江侗族自治县",
-			"靖州苗族侗族自治县", "通道侗族自治县", "洪江市"
-		]
-	}, {
-		"name": "娄底市",
-		"area": ["市辖区", "娄星区", "双峰县", "新化县", "冷水江市", "涟源市"]
-	}, {
-		"name": "湘西土家族苗族自治州",
-		"area": ["吉首市", "泸溪县", "凤凰县", "花垣县", "保靖县", "古丈县", "永顺县", "龙山县"]
-	}]
-}, {
-	"name": "广东",
-	"city": [{
-		"name": "广州市",
-		"area": ["市辖区", "荔湾区", "越秀区", "海珠区", "天河区", "白云区", "黄埔区", "番禺区", "花都区", "南沙区", "从化区", "增城区"]
-	}, {
-		"name": "韶关市",
-		"area": ["市辖区", "武江区", "浈江区", "曲江区", "始兴县", "仁化县", "翁源县", "乳源瑶族自治县", "新丰县", "乐昌市", "南雄市"]
-	}, {
-		"name": "深圳市",
-		"area": ["市辖区", "罗湖区", "福田区", "南山区", "宝安区", "龙岗区", "盐田区"]
-	}, {
-		"name": "珠海市",
-		"area": ["市辖区", "香洲区", "斗门区", "金湾区"]
-	}, {
-		"name": "汕头市",
-		"area": ["市辖区", "龙湖区", "金平区", "濠江区", "潮阳区", "潮南区", "澄海区", "南澳县"]
-	}, {
-		"name": "佛山市",
-		"area": ["市辖区", "禅城区", "南海区", "顺德区", "三水区", "高明区"]
-	}, {
-		"name": "江门市",
-		"area": ["市辖区", "蓬江区", "江海区", "新会区", "台山市", "开平市", "鹤山市", "恩平市"]
-	}, {
-		"name": "湛江市",
-		"area": ["市辖区", "赤坎区", "霞山区", "坡头区", "麻章区", "遂溪县", "徐闻县", "廉江市", "雷州市", "吴川市"]
-	}, {
-		"name": "茂名市",
-		"area": ["市辖区", "茂南区", "电白区", "高州市", "化州市", "信宜市"]
-	}, {
-		"name": "肇庆市",
-		"area": ["市辖区", "端州区", "鼎湖区", "高要区", "广宁县", "怀集县", "封开县", "德庆县", "四会市"]
-	}, {
-		"name": "惠州市",
-		"area": ["市辖区", "惠城区", "惠阳区", "博罗县", "惠东县", "龙门县"]
-	}, {
-		"name": "梅州市",
-		"area": ["市辖区", "梅江区", "梅县区", "大埔县", "丰顺县", "五华县", "平远县", "蕉岭县", "兴宁市"]
-	}, {
-		"name": "汕尾市",
-		"area": ["市辖区", "城区", "海丰县", "陆河县", "陆丰市"]
-	}, {
-		"name": "河源市",
-		"area": ["市辖区", "源城区", "紫金县", "龙川县", "连平县", "和平县", "东源县"]
-	}, {
-		"name": "阳江市",
-		"area": ["市辖区", "江城区", "阳东区", "阳西县", "阳春市"]
-	}, {
-		"name": "清远市",
-		"area": ["市辖区", "清城区", "清新区", "佛冈县", "阳山县", "连山壮族瑶族自治县", "连南瑶族自治县", "英德市", "连州市"]
-	}, {
-		"name": "东莞市",
-		"area": ["东城街道办事处", "南城街道办事处", "万江街道办事处", "莞城街道办事处", "石碣镇", "石龙镇", "茶山镇", "石排镇", "企石镇", "横沥镇",
-			"桥头镇", "谢岗镇", "东坑镇", "常平镇", "寮步镇", "樟木头镇", "大朗镇", "黄江镇", "清溪镇", "塘厦镇", "凤岗镇", "大岭山镇", "长安镇",
-			"虎门镇", "厚街镇", "沙田镇", "道滘镇", "洪梅镇", "麻涌镇", "望牛墩镇", "中堂镇", "高埗镇", "松山湖管委会", "虎门港管委会", "东莞生态园"
-		]
-	}, {
-		"name": "中山市",
-		"area": ["石岐区街道办事处", "东区街道办事处", "火炬开发区街道办事处", "西区街道办事处", "南区街道办事处", "五桂山街道办事处", "小榄镇", "黄圃镇", "民众镇",
-			"东凤镇", "东升镇", "古镇镇", "沙溪镇", "坦洲镇", "港口镇", "三角镇", "横栏镇", "南头镇", "阜沙镇", "南朗镇", "三乡镇", "板芙镇",
-			"大涌镇", "神湾镇"
-		]
-	}, {
-		"name": "潮州市",
-		"area": ["市辖区", "湘桥区", "潮安区", "饶平县"]
-	}, {
-		"name": "揭阳市",
-		"area": ["市辖区", "榕城区", "揭东区", "揭西县", "惠来县", "普宁市"]
-	}, {
-		"name": "云浮市",
-		"area": ["市辖区", "云城区", "云安区", "新兴县", "郁南县", "罗定市"]
-	}]
-}, {
-	"name": "广西",
-	"city": [{
-		"name": "南宁市",
-		"area": ["市辖区", "兴宁区", "青秀区", "江南区", "西乡塘区", "良庆区", "邕宁区", "武鸣区", "隆安县", "马山县", "上林县", "宾阳县", "横县"]
-	}, {
-		"name": "柳州市",
-		"area": ["市辖区", "城中区", "鱼峰区", "柳南区", "柳北区", "柳江区", "柳城县", "鹿寨县", "融安县", "融水苗族自治县", "三江侗族自治县"]
-	}, {
-		"name": "桂林市",
-		"area": ["市辖区", "秀峰区", "叠彩区", "象山区", "七星区", "雁山区", "临桂区", "阳朔县", "灵川县", "全州县", "兴安县", "永福县", "灌阳县",
-			"龙胜各族自治县", "资源县", "平乐县", "荔浦县", "恭城瑶族自治县"
-		]
-	}, {
-		"name": "梧州市",
-		"area": ["市辖区", "万秀区", "长洲区", "龙圩区", "苍梧县", "藤县", "蒙山县", "岑溪市"]
-	}, {
-		"name": "北海市",
-		"area": ["市辖区", "海城区", "银海区", "铁山港区", "合浦县"]
-	}, {
-		"name": "防城港市",
-		"area": ["市辖区", "港口区", "防城区", "上思县", "东兴市"]
-	}, {
-		"name": "钦州市",
-		"area": ["市辖区", "钦南区", "钦北区", "灵山县", "浦北县"]
-	}, {
-		"name": "贵港市",
-		"area": ["市辖区", "港北区", "港南区", "覃塘区", "平南县", "桂平市"]
-	}, {
-		"name": "玉林市",
-		"area": ["市辖区", "玉州区", "福绵区", "容县", "陆川县", "博白县", "兴业县", "北流市"]
-	}, {
-		"name": "百色市",
-		"area": ["市辖区", "右江区", "田阳县", "田东县", "平果县", "德保县", "那坡县", "凌云县", "乐业县", "田林县", "西林县", "隆林各族自治县",
-			"靖西市"
-		]
-	}, {
-		"name": "贺州市",
-		"area": ["市辖区", "八步区", "平桂区", "昭平县", "钟山县", "富川瑶族自治县"]
-	}, {
-		"name": "河池市",
-		"area": ["市辖区", "金城江区", "南丹县", "天峨县", "凤山县", "东兰县", "罗城仫佬族自治县", "环江毛南族自治县", "巴马瑶族自治县", "都安瑶族自治县",
-			"大化瑶族自治县", "宜州市"
-		]
-	}, {
-		"name": "来宾市",
-		"area": ["市辖区", "兴宾区", "忻城县", "象州县", "武宣县", "金秀瑶族自治县", "合山市"]
-	}, {
-		"name": "崇左市",
-		"area": ["市辖区", "江州区", "扶绥县", "宁明县", "龙州县", "大新县", "天等县", "凭祥市"]
-	}]
-}, {
-	"name": "海南",
-	"city": [{
-		"name": "海口市",
-		"area": ["市辖区", "秀英区", "龙华区", "琼山区", "美兰区"]
-	}, {
-		"name": "三亚市",
-		"area": ["市辖区", "海棠区", "吉阳区", "天涯区", "崖州区"]
-	}, {
-		"name": "三沙市",
-		"area": ["西沙群岛", "南沙群岛", "中沙群岛的岛礁及其海域"]
-	}, {
-		"name": "儋州市",
-		"area": ["那大镇", "和庆镇", "南丰镇", "大成镇", "雅星镇", "兰洋镇", "光村镇", "木棠镇", "海头镇", "峨蔓镇", "三都镇", "王五镇", "白马井镇",
-			"中和镇", "排浦镇", "东成镇", "新州镇", "国营西培农场", "国营西联农场", "国营蓝洋农场", "国营八一农场", "洋浦经济开发区", "华南热作学院"
-		]
-	}, {
-		"name": "省直辖县级行政区域",
-		"area": ["五指山市", "琼海市", "文昌市", "万宁市", "东方市", "定安县", "屯昌县", "澄迈县", "临高县", "白沙黎族自治县", "昌江黎族自治县",
-			"乐东黎族自治县", "陵水黎族自治县", "保亭黎族苗族自治县", "琼中黎族苗族自治县"
-		]
-	}]
-}, {
-	"name": "重庆",
-	"city": [{
-		"name": "重庆市",
-		"area": ["万州区", "涪陵区", "渝中区", "大渡口区", "江北区", "沙坪坝区", "九龙坡区", "南岸区", "北碚区", "綦江区", "大足区", "渝北区",
-			"巴南区", "黔江区", "长寿区", "江津区", "合川区", "永川区", "南川区", "璧山区", "铜梁区", "潼南区", "荣昌区", "开州区"
-		]
-	}, {
-		"name": "县",
-		"area": ["梁平县", "城口县", "丰都县", "垫江县", "武隆县", "忠县", "云阳县", "奉节县", "巫山县", "巫溪县", "石柱土家族自治县",
-			"秀山土家族苗族自治县", "酉阳土家族苗族自治县", "彭水苗族土家族自治县"
-		]
-	}]
-}, {
-	"name": "四川",
-	"city": [{
-		"name": "成都市",
-		"area": ["市辖区", "锦江区", "青羊区", "金牛区", "武侯区", "成华区", "龙泉驿区", "青白江区", "新都区", "温江区", "双流区", "金堂县", "郫县",
-			"大邑县", "蒲江县", "新津县", "都江堰市", "彭州市", "邛崃市", "崇州市", "简阳市"
-		]
-	}, {
-		"name": "自贡市",
-		"area": ["市辖区", "自流井区", "贡井区", "大安区", "沿滩区", "荣县", "富顺县"]
-	}, {
-		"name": "攀枝花市",
-		"area": ["市辖区", "东区", "西区", "仁和区", "米易县", "盐边县"]
-	}, {
-		"name": "泸州市",
-		"area": ["市辖区", "江阳区", "纳溪区", "龙马潭区", "泸县", "合江县", "叙永县", "古蔺县"]
-	}, {
-		"name": "德阳市",
-		"area": ["市辖区", "旌阳区", "中江县", "罗江县", "广汉市", "什邡市", "绵竹市"]
-	}, {
-		"name": "绵阳市",
-		"area": ["市辖区", "涪城区", "游仙区", "安州区", "三台县", "盐亭县", "梓潼县", "北川羌族自治县", "平武县", "江油市"]
-	}, {
-		"name": "广元市",
-		"area": ["市辖区", "利州区", "昭化区", "朝天区", "旺苍县", "青川县", "剑阁县", "苍溪县"]
-	}, {
-		"name": "遂宁市",
-		"area": ["市辖区", "船山区", "安居区", "蓬溪县", "射洪县", "大英县"]
-	}, {
-		"name": "内江市",
-		"area": ["市辖区", "市中区", "东兴区", "威远县", "资中县", "隆昌县"]
-	}, {
-		"name": "乐山市",
-		"area": ["市辖区", "市中区", "沙湾区", "五通桥区", "金口河区", "犍为县", "井研县", "夹江县", "沐川县", "峨边彝族自治县", "马边彝族自治县",
-			"峨眉山市"
-		]
-	}, {
-		"name": "南充市",
-		"area": ["市辖区", "顺庆区", "高坪区", "嘉陵区", "南部县", "营山县", "蓬安县", "仪陇县", "西充县", "阆中市"]
-	}, {
-		"name": "眉山市",
-		"area": ["市辖区", "东坡区", "彭山区", "仁寿县", "洪雅县", "丹棱县", "青神县"]
-	}, {
-		"name": "宜宾市",
-		"area": ["市辖区", "翠屏区", "南溪区", "宜宾县", "江安县", "长宁县", "高县", "珙县", "筠连县", "兴文县", "屏山县"]
-	}, {
-		"name": "广安市",
-		"area": ["市辖区", "广安区", "前锋区", "岳池县", "武胜县", "邻水县", "华蓥市"]
-	}, {
-		"name": "达州市",
-		"area": ["市辖区", "通川区", "达川区", "宣汉县", "开江县", "大竹县", "渠县", "万源市"]
-	}, {
-		"name": "雅安市",
-		"area": ["市辖区", "雨城区", "名山区", "荥经县", "汉源县", "石棉县", "天全县", "芦山县", "宝兴县"]
-	}, {
-		"name": "巴中市",
-		"area": ["市辖区", "巴州区", "恩阳区", "通江县", "南江县", "平昌县"]
-	}, {
-		"name": "资阳市",
-		"area": ["市辖区", "雁江区", "安岳县", "乐至县"]
-	}, {
-		"name": "阿坝藏族羌族自治州",
-		"area": ["马尔康市", "汶川县", "理县", "茂县", "松潘县", "九寨沟县", "金川县", "小金县", "黑水县", "壤塘县", "阿坝县", "若尔盖县", "红原县"]
-	}, {
-		"name": "甘孜藏族自治州",
-		"area": ["康定市", "泸定县", "丹巴县", "九龙县", "雅江县", "道孚县", "炉霍县", "甘孜县", "新龙县", "德格县", "白玉县", "石渠县", "色达县",
-			"理塘县", "巴塘县", "乡城县", "稻城县", "得荣县"
-		]
-	}, {
-		"name": "凉山彝族自治州",
-		"area": ["西昌市", "木里藏族自治县", "盐源县", "德昌县", "会理县", "会东县", "宁南县", "普格县", "布拖县", "金阳县", "昭觉县", "喜德县",
-			"冕宁县", "越西县", "甘洛县", "美姑县", "雷波县"
-		]
-	}]
-}, {
-	"name": "贵州",
-	"city": [{
-		"name": "贵阳市",
-		"area": ["市辖区", "南明区", "云岩区", "花溪区", "乌当区", "白云区", "观山湖区", "开阳县", "息烽县", "修文县", "清镇市"]
-	}, {
-		"name": "六盘水市",
-		"area": ["钟山区", "六枝特区", "水城县", "盘县"]
-	}, {
-		"name": "遵义市",
-		"area": ["市辖区", "红花岗区", "汇川区", "播州区", "桐梓县", "绥阳县", "正安县", "道真仡佬族苗族自治县", "务川仡佬族苗族自治县", "凤冈县", "湄潭县",
-			"余庆县", "习水县", "赤水市", "仁怀市"
-		]
-	}, {
-		"name": "安顺市",
-		"area": ["市辖区", "西秀区", "平坝区", "普定县", "镇宁布依族苗族自治县", "关岭布依族苗族自治县", "紫云苗族布依族自治县"]
-	}, {
-		"name": "毕节市",
-		"area": ["市辖区", "七星关区", "大方县", "黔西县", "金沙县", "织金县", "纳雍县", "威宁彝族回族苗族自治县", "赫章县"]
-	}, {
-		"name": "铜仁市",
-		"area": ["市辖区", "碧江区", "万山区", "江口县", "玉屏侗族自治县", "石阡县", "思南县", "印江土家族苗族自治县", "德江县", "沿河土家族自治县",
-			"松桃苗族自治县"
-		]
-	}, {
-		"name": "黔西南布依族苗族自治州",
-		"area": ["兴义市", "兴仁县", "普安县", "晴隆县", "贞丰县", "望谟县", "册亨县", "安龙县"]
-	}, {
-		"name": "黔东南苗族侗族自治州",
-		"area": ["凯里市", "黄平县", "施秉县", "三穗县", "镇远县", "岑巩县", "天柱县", "锦屏县", "剑河县", "台江县", "黎平县", "榕江县", "从江县",
-			"雷山县", "麻江县", "丹寨县"
-		]
-	}, {
-		"name": "黔南布依族苗族自治州",
-		"area": ["都匀市", "福泉市", "荔波县", "贵定县", "瓮安县", "独山县", "平塘县", "罗甸县", "长顺县", "龙里县", "惠水县", "三都水族自治县"]
-	}]
-}, {
-	"name": "云南",
-	"city": [{
-		"name": "昆明市",
-		"area": ["市辖区", "五华区", "盘龙区", "官渡区", "西山区", "东川区", "呈贡区", "晋宁县", "富民县", "宜良县", "石林彝族自治县", "嵩明县",
-			"禄劝彝族苗族自治县", "寻甸回族彝族自治县", "安宁市"
-		]
-	}, {
-		"name": "曲靖市",
-		"area": ["市辖区", "麒麟区", "沾益区", "马龙县", "陆良县", "师宗县", "罗平县", "富源县", "会泽县", "宣威市"]
-	}, {
-		"name": "玉溪市",
-		"area": ["市辖区", "红塔区", "江川区", "澄江县", "通海县", "华宁县", "易门县", "峨山彝族自治县", "新平彝族傣族自治县", "元江哈尼族彝族傣族自治县"]
-	}, {
-		"name": "保山市",
-		"area": ["市辖区", "隆阳区", "施甸县", "龙陵县", "昌宁县", "腾冲市"]
-	}, {
-		"name": "昭通市",
-		"area": ["市辖区", "昭阳区", "鲁甸县", "巧家县", "盐津县", "大关县", "永善县", "绥江县", "镇雄县", "彝良县", "威信县", "水富县"]
-	}, {
-		"name": "丽江市",
-		"area": ["市辖区", "古城区", "玉龙纳西族自治县", "永胜县", "华坪县", "宁蒗彝族自治县"]
-	}, {
-		"name": "普洱市",
-		"area": ["市辖区", "思茅区", "宁洱哈尼族彝族自治县", "墨江哈尼族自治县", "景东彝族自治县", "景谷傣族彝族自治县", "镇沅彝族哈尼族拉祜族自治县",
-			"江城哈尼族彝族自治县", "孟连傣族拉祜族佤族自治县", "澜沧拉祜族自治县", "西盟佤族自治县"
-		]
-	}, {
-		"name": "临沧市",
-		"area": ["市辖区", "临翔区", "凤庆县", "云县", "永德县", "镇康县", "双江拉祜族佤族布朗族傣族自治县", "耿马傣族佤族自治县", "沧源佤族自治县"]
-	}, {
-		"name": "楚雄彝族自治州",
-		"area": ["楚雄市", "双柏县", "牟定县", "南华县", "姚安县", "大姚县", "永仁县", "元谋县", "武定县", "禄丰县"]
-	}, {
-		"name": "红河哈尼族彝族自治州",
-		"area": ["个旧市", "开远市", "蒙自市", "弥勒市", "屏边苗族自治县", "建水县", "石屏县", "泸西县", "元阳县", "红河县", "金平苗族瑶族傣族自治县",
-			"绿春县", "河口瑶族自治县"
-		]
-	}, {
-		"name": "文山壮族苗族自治州",
-		"area": ["文山市", "砚山县", "西畴县", "麻栗坡县", "马关县", "丘北县", "广南县", "富宁县"]
-	}, {
-		"name": "西双版纳傣族自治州",
-		"area": ["景洪市", "勐海县", "勐腊县"]
-	}, {
-		"name": "大理白族自治州",
-		"area": ["大理市", "漾濞彝族自治县", "祥云县", "宾川县", "弥渡县", "南涧彝族自治县", "巍山彝族回族自治县", "永平县", "云龙县", "洱源县", "剑川县",
-			"鹤庆县"
-		]
-	}, {
-		"name": "德宏傣族景颇族自治州",
-		"area": ["瑞丽市", "芒市", "梁河县", "盈江县", "陇川县"]
-	}, {
-		"name": "怒江傈僳族自治州",
-		"area": ["泸水市", "福贡县", "贡山独龙族怒族自治县", "兰坪白族普米族自治县"]
-	}, {
-		"name": "迪庆藏族自治州",
-		"area": ["香格里拉市", "德钦县", "维西傈僳族自治县"]
-	}]
-}, {
-	"name": "西藏",
-	"city": [{
-		"name": "拉萨市",
-		"area": ["市辖区", "城关区", "堆龙德庆区", "林周县", "当雄县", "尼木县", "曲水县", "达孜县", "墨竹工卡县"]
-	}, {
-		"name": "日喀则市",
-		"area": ["桑珠孜区", "南木林县", "江孜县", "定日县", "萨迦县", "拉孜县", "昂仁县", "谢通门县", "白朗县", "仁布县", "康马县", "定结县",
-			"仲巴县", "亚东县", "吉隆县", "聂拉木县", "萨嘎县", "岗巴县"
-		]
-	}, {
-		"name": "昌都市",
-		"area": ["卡若区", "江达县", "贡觉县", "类乌齐县", "丁青县", "察雅县", "八宿县", "左贡县", "芒康县", "洛隆县", "边坝县"]
-	}, {
-		"name": "林芝市",
-		"area": ["巴宜区", "工布江达县", "米林县", "墨脱县", "波密县", "察隅县", "朗县"]
-	}, {
-		"name": "山南市",
-		"area": ["市辖区", "乃东区", "扎囊县", "贡嘎县", "桑日县", "琼结县", "曲松县", "措美县", "洛扎县", "加查县", "隆子县", "错那县", "浪卡子县"]
-	}, {
-		"name": "那曲地区",
-		"area": ["那曲县", "嘉黎县", "比如县", "聂荣县", "安多县", "申扎县", "索县", "班戈县", "巴青县", "尼玛县", "双湖县"]
-	}, {
-		"name": "阿里地区",
-		"area": ["普兰县", "札达县", "噶尔县", "日土县", "革吉县", "改则县", "措勤县"]
-	}]
-}, {
-	"name": "陕西",
-	"city": [{
-		"name": "西安市",
-		"area": ["市辖区", "新城区", "碑林区", "莲湖区", "灞桥区", "未央区", "雁塔区", "阎良区", "临潼区", "长安区", "高陵区", "蓝田县", "周至县",
-			"户县"
-		]
-	}, {
-		"name": "铜川市",
-		"area": ["市辖区", "王益区", "印台区", "耀州区", "宜君县"]
-	}, {
-		"name": "宝鸡市",
-		"area": ["市辖区", "渭滨区", "金台区", "陈仓区", "凤翔县", "岐山县", "扶风县", "眉县", "陇县", "千阳县", "麟游县", "凤县", "太白县"]
-	}, {
-		"name": "咸阳市",
-		"area": ["市辖区", "秦都区", "杨陵区", "渭城区", "三原县", "泾阳县", "乾县", "礼泉县", "永寿县", "彬县", "长武县", "旬邑县", "淳化县",
-			"武功县", "兴平市"
-		]
-	}, {
-		"name": "渭南市",
-		"area": ["市辖区", "临渭区", "华州区", "潼关县", "大荔县", "合阳县", "澄城县", "蒲城县", "白水县", "富平县", "韩城市", "华阴市"]
-	}, {
-		"name": "延安市",
-		"area": ["市辖区", "宝塔区", "安塞区", "延长县", "延川县", "子长县", "志丹县", "吴起县", "甘泉县", "富县", "洛川县", "宜川县", "黄龙县",
-			"黄陵县"
-		]
-	}, {
-		"name": "汉中市",
-		"area": ["市辖区", "汉台区", "南郑县", "城固县", "洋县", "西乡县", "勉县", "宁强县", "略阳县", "镇巴县", "留坝县", "佛坪县"]
-	}, {
-		"name": "榆林市",
-		"area": ["市辖区", "榆阳区", "横山区", "神木县", "府谷县", "靖边县", "定边县", "绥德县", "米脂县", "佳县", "吴堡县", "清涧县", "子洲县"]
-	}, {
-		"name": "安康市",
-		"area": ["市辖区", "汉滨区", "汉阴县", "石泉县", "宁陕县", "紫阳县", "岚皋县", "平利县", "镇坪县", "旬阳县", "白河县"]
-	}, {
-		"name": "商洛市",
-		"area": ["市辖区", "商州区", "洛南县", "丹凤县", "商南县", "山阳县", "镇安县", "柞水县"]
-	}]
-}, {
-	"name": "甘肃",
-	"city": [{
-		"name": "兰州市",
-		"area": ["市辖区", "城关区", "七里河区", "西固区", "安宁区", "红古区", "永登县", "皋兰县", "榆中县"]
-	}, {
-		"name": "嘉峪关市",
-		"area": ["市辖区"]
-	}, {
-		"name": "金昌市",
-		"area": ["市辖区", "金川区", "永昌县"]
-	}, {
-		"name": "白银市",
-		"area": ["市辖区", "白银区", "平川区", "靖远县", "会宁县", "景泰县"]
-	}, {
-		"name": "天水市",
-		"area": ["市辖区", "秦州区", "麦积区", "清水县", "秦安县", "甘谷县", "武山县", "张家川回族自治县"]
-	}, {
-		"name": "武威市",
-		"area": ["市辖区", "凉州区", "民勤县", "古浪县", "天祝藏族自治县"]
-	}, {
-		"name": "张掖市",
-		"area": ["市辖区", "甘州区", "肃南裕固族自治县", "民乐县", "临泽县", "高台县", "山丹县"]
-	}, {
-		"name": "平凉市",
-		"area": ["市辖区", "崆峒区", "泾川县", "灵台县", "崇信县", "华亭县", "庄浪县", "静宁县"]
-	}, {
-		"name": "酒泉市",
-		"area": ["市辖区", "肃州区", "金塔县", "瓜州县", "肃北蒙古族自治县", "阿克塞哈萨克族自治县", "玉门市", "敦煌市"]
-	}, {
-		"name": "庆阳市",
-		"area": ["市辖区", "西峰区", "庆城县", "环县", "华池县", "合水县", "正宁县", "宁县", "镇原县"]
-	}, {
-		"name": "定西市",
-		"area": ["市辖区", "安定区", "通渭县", "陇西县", "渭源县", "临洮县", "漳县", "岷县"]
-	}, {
-		"name": "陇南市",
-		"area": ["市辖区", "武都区", "成县", "文县", "宕昌县", "康县", "西和县", "礼县", "徽县", "两当县"]
-	}, {
-		"name": "临夏回族自治州",
-		"area": ["临夏市", "临夏县", "康乐县", "永靖县", "广河县", "和政县", "东乡族自治县", "积石山保安族东乡族撒拉族自治县"]
-	}, {
-		"name": "甘南藏族自治州",
-		"area": ["合作市", "临潭县", "卓尼县", "舟曲县", "迭部县", "玛曲县", "碌曲县", "夏河县"]
-	}]
-}, {
-	"name": "青海",
-	"city": [{
-		"name": "西宁市",
-		"area": ["市辖区", "城东区", "城中区", "城西区", "城北区", "大通回族土族自治县", "湟中县", "湟源县"]
-	}, {
-		"name": "海东市",
-		"area": ["乐都区", "平安区", "民和回族土族自治县", "互助土族自治县", "化隆回族自治县", "循化撒拉族自治县"]
-	}, {
-		"name": "海北藏族自治州",
-		"area": ["门源回族自治县", "祁连县", "海晏县", "刚察县"]
-	}, {
-		"name": "黄南藏族自治州",
-		"area": ["同仁县", "尖扎县", "泽库县", "河南蒙古族自治县"]
-	}, {
-		"name": "海南藏族自治州",
-		"area": ["共和县", "同德县", "贵德县", "兴海县", "贵南县"]
-	}, {
-		"name": "果洛藏族自治州",
-		"area": ["玛沁县", "班玛县", "甘德县", "达日县", "久治县", "玛多县"]
-	}, {
-		"name": "玉树藏族自治州",
-		"area": ["玉树市", "杂多县", "称多县", "治多县", "囊谦县", "曲麻莱县"]
-	}, {
-		"name": "海西蒙古族藏族自治州",
-		"area": ["格尔木市", "德令哈市", "乌兰县", "都兰县", "天峻县"]
-	}]
-}, {
-	"name": "宁夏",
-	"city": [{
-		"name": "银川市",
-		"area": ["市辖区", "兴庆区", "西夏区", "金凤区", "永宁县", "贺兰县", "灵武市"]
-	}, {
-		"name": "石嘴山市",
-		"area": ["市辖区", "大武口区", "惠农区", "平罗县"]
-	}, {
-		"name": "吴忠市",
-		"area": ["市辖区", "利通区", "红寺堡区", "盐池县", "同心县", "青铜峡市"]
-	}, {
-		"name": "固原市",
-		"area": ["市辖区", "原州区", "西吉县", "隆德县", "泾源县", "彭阳县"]
-	}, {
-		"name": "中卫市",
-		"area": ["市辖区", "沙坡头区", "中宁县", "海原县"]
-	}]
-}, {
-	"name": "新疆",
-	"city": [{
-		"name": "乌鲁木齐市",
-		"area": ["市辖区", "天山区", "沙依巴克区", "新市区", "水磨沟区", "头屯河区", "达坂城区", "米东区", "乌鲁木齐县"]
-	}, {
-		"name": "克拉玛依市",
-		"area": ["市辖区", "独山子区", "克拉玛依区", "白碱滩区", "乌尔禾区"]
-	}, {
-		"name": "吐鲁番市",
-		"area": ["高昌区", "鄯善县", "托克逊县"]
-	}, {
-		"name": "哈密市",
-		"area": ["伊州区", "巴里坤哈萨克自治县", "伊吾县"]
-	}, {
-		"name": "昌吉回族自治州",
-		"area": ["昌吉市", "阜康市", "呼图壁县", "玛纳斯县", "奇台县", "吉木萨尔县", "木垒哈萨克自治县"]
-	}, {
-		"name": "博尔塔拉蒙古自治州",
-		"area": ["博乐市", "阿拉山口市", "精河县", "温泉县"]
-	}, {
-		"name": "巴音郭楞蒙古自治州",
-		"area": ["库尔勒市", "轮台县", "尉犁县", "若羌县", "且末县", "焉耆回族自治县", "和静县", "和硕县", "博湖县"]
-	}, {
-		"name": "阿克苏地区",
-		"area": ["阿克苏市", "温宿县", "库车县", "沙雅县", "新和县", "拜城县", "乌什县", "阿瓦提县", "柯坪县"]
-	}, {
-		"name": "克孜勒苏柯尔克孜自治州",
-		"area": ["阿图什市", "阿克陶县", "阿合奇县", "乌恰县"]
-	}, {
-		"name": "喀什地区",
-		"area": ["喀什市", "疏附县", "疏勒县", "英吉沙县", "泽普县", "莎车县", "叶城县", "麦盖提县", "岳普湖县", "伽师县", "巴楚县",
-			"塔什库尔干塔吉克自治县"
-		]
-	}, {
-		"name": "和田地区",
-		"area": ["和田市", "和田县", "墨玉县", "皮山县", "洛浦县", "策勒县", "于田县", "民丰县"]
-	}, {
-		"name": "伊犁哈萨克自治州",
-		"area": ["伊宁市", "奎屯市", "霍尔果斯市", "伊宁县", "察布查尔锡伯自治县", "霍城县", "巩留县", "新源县", "昭苏县", "特克斯县", "尼勒克县"]
-	}, {
-		"name": "塔城地区",
-		"area": ["塔城市", "乌苏市", "额敏县", "沙湾县", "托里县", "裕民县", "和布克赛尔蒙古自治县"]
-	}, {
-		"name": "阿勒泰地区",
-		"area": ["阿勒泰市", "布尔津县", "富蕴县", "福海县", "哈巴河县", "青河县", "吉木乃县"]
-	}, {
-		"name": "直辖县",
-		"area": ["石河子市", "阿拉尔市", "图木舒克市", "五家渠市", "铁门关市"]
-	}]
-}, {
-	"name": "香港",
-	"city": [{
-		"name": "香港特别行政区",
-		"area": ["中西区", "东区", "九龙城区", "观塘区", "南区", "深水埗区", "湾仔区", "黄大仙区", "油尖旺区", "离岛区", "葵青区", "北区", "西贡区",
-			"沙田区", "屯门区", "大埔区", "荃湾区", "元朗区"
-		]
-	}]
-}, {
-	"name": "澳门",
-	"city": [{
-		"name": "澳门特别行政区",
-		"area": ["澳门半岛", "凼仔", "路凼城", "路环"]
-	}]
-}, {
-	"name": "台湾",
-	"city": [{
-		"name": "彰化县",
-		"area": ["芳苑乡", "芬园乡", "福兴乡", "和美镇", "花坛乡", "鹿港镇", "埤头乡", "埔心乡", "埔盐乡", "伸港乡", "社头乡", "田尾乡", "田中镇",
-			"线西乡", "溪湖镇", "秀水乡", "溪州乡", "永靖乡", "员林市", "竹塘乡"
-		]
-	}, {
-		"name": "新北市",
-		"area": ["八里区", "板桥区", "贡寮区", "金山区", "林口区", "芦洲区", "坪林区", "平溪区", "瑞芳区", "三重区", "三峡区", "三芝区", "深坑区",
-			"石碇区", "石门区", "双溪区", "树林区", "泰山区", "淡水区", "土城区"
-		]
-	}, {
-		"name": "澎湖县",
-		"area": ["白沙乡", "湖西乡", "马公市", "七美乡", "望安乡", "西屿乡"]
-	}, {
-		"name": "屏东县",
-		"area": ["三地门乡", "狮子乡", "泰武乡", "万丹乡", "万峦乡", "雾臺乡", "新埤乡", "新园乡", "盐埔乡", "竹田乡", "长治乡", "潮州镇", "车城乡",
-			"春日乡", "东港镇", "枋寮乡", "枋山乡", "高树乡", "恆春镇", "佳冬乡"
-		]
-	}, {
-		"name": "臺中市",
-		"area": ["梧栖区", "乌日区", "新社区", "西屯区", "北屯区", "中区", "大肚区", "大甲区", "大里区", "大雅区", "大安区", "东势区", "东区",
-			"丰原区", "和平区", "后里区", "龙井区", "南屯区", "北区", "清水区"
-		]
-	}, {
-		"name": "臺南市",
-		"area": ["佳里区", "将军区", "六甲区", "柳营区", "龙崎区", "麻豆区", "南化区", "楠西区", "北区", "七股区", "仁德区", "善化区", "山上区",
-			"南区", "中西区", "下营区", "西港区", "新化区", "新市区", "新营区"
-		]
-	}, {
-		"name": "臺北市",
-		"area": ["北投区", "大同区", "大安区", "南港区", "内湖区", "士林区", "松山区", "万华区", "文山区", "信义区", "中山区", "中正区"]
-	}, {
-		"name": "臺东县",
-		"area": ["卑南乡", "长滨乡", "成功镇", "池上乡", "达仁乡", "大武乡", "东河乡", "关山镇", "海端乡", "金峰乡", "兰屿乡", "绿岛乡", "鹿野乡",
-			"太麻里乡", "臺东市", "延平乡"
-		]
-	}, {
-		"name": "桃园市",
-		"area": ["八德区", "大溪区", "大园区", "復兴区", "观音区", "龟山区", "龙潭区", "芦竹区", "平镇区", "桃园区", "新屋区", "杨梅区", "中坜区"]
-	}, {
-		"name": "宜兰县",
-		"area": ["大同乡", "钓鱼臺", "冬山乡", "礁溪乡", "罗东镇", "南澳乡", "三星乡", "苏澳镇", "头城镇", "五结乡", "宜兰市", "员山乡", "壮围乡"]
-	}, {
-		"name": "南投县",
-		"area": ["草屯镇", "国姓乡", "集集镇", "鹿谷乡", "名间乡", "南投市", "埔里镇", "仁爱乡", "水里乡", "信义乡", "鱼池乡", "中寮乡", "竹山镇"]
-	}, {
-		"name": "南海岛",
-		"area": ["东沙群岛", "南沙群岛"]
-	}, {
-		"name": "苗栗县",
-		"area": ["头屋乡", "西湖乡", "苑里镇", "造桥乡", "竹南镇", "卓兰镇", "大湖乡", "公馆乡", "后龙镇", "苗栗市", "南庄乡", "三湾乡", "三义乡",
-			"狮潭乡", "泰安乡", "铜锣乡", "通霄镇", "头份市"
-		]
-	}, {
-		"name": "嘉义市",
-		"area": ["东区", "西区"]
-	}, {
-		"name": "嘉义县",
-		"area": ["阿里山乡", "布袋镇", "大林镇", "大埔乡", "东石乡", "番路乡", "六脚乡", "鹿草乡", "梅山乡", "民雄乡", "朴子市", "水上乡", "太保市",
-			"溪口乡", "新港乡", "义竹乡", "中埔乡", "竹崎乡"
-		]
-	}, {
-		"name": "新竹市",
-		"area": ["东区", "北区"]
-	}, {
-		"name": "新竹县",
-		"area": ["峨眉乡", "关西镇", "横山乡", "湖口乡", "尖石乡", "芎林乡", "五峰乡", "新丰乡", "新埔镇", "竹北市", "竹东镇", "宝山乡", "北埔乡"]
-	}, {
-		"name": "花莲县",
-		"area": ["卓溪乡", "丰滨乡", "凤林镇", "富里乡", "光復乡", "花莲市", "吉安乡", "瑞穗乡", "寿丰乡", "万荣乡", "新城乡", "秀林乡", "玉里镇"]
-	}, {
-		"name": "高雄市",
-		"area": ["阿莲区", "大寮区", "大社区", "大树区", "凤山区", "冈山区", "鼓山区", "湖内区", "甲仙区", "苓雅区", "林园区", "六龟区", "路竹区",
-			"茂林区", "美浓区", "弥陀区", "那玛夏区", "楠梓区", "内门区", "鸟松区"
-		]
-	}, {
-		"name": "基隆市",
-		"area": ["安乐区", "暖暖区", "七堵区", "仁爱区", "信义区", "中山区", "中正区"]
-	}, {
-		"name": "金门县",
-		"area": ["金城镇", "金湖镇", "金宁乡", "金沙镇", "烈屿乡", "乌坵乡"]
-	}, {
-		"name": "连江县",
-		"area": ["北竿乡", "东引乡", "莒光乡", "南竿乡"]
-	}, {
-		"name": "云林县",
-		"area": ["褒忠乡", "北港镇", "莿桐乡", "大埤乡", "东势乡", "斗六市", "斗南镇", "二崙乡", "古坑乡", "虎尾镇", "口湖乡", "林内乡", "崙背乡",
-			"麦寮乡", "水林乡", "四湖乡", "臺西乡", "土库镇", "西螺镇", "元长乡"
-		]
-	}]
-}]

+ 0 - 103
components/wangding-pickerAddress/wangding-pickerAddress.vue

@@ -1,103 +0,0 @@
-<template>
-	<picker @change="bindPickerChange" @columnchange="columnchange" :range="array" range-key="name" :value="value" mode="multiSelector">
-		<slot></slot>
-	</picker>
-</template>
-
-<script>
-	import AllAddress from './data.js'
-	let selectVal = ['','',''];
-	
-	export default {
-		data() {
-			return{
-				value: [0,0,0],
-				array: [],
-				index: 0
-			}
-		},
-		created() {
-			this.initSelect()
-		},
-		methods:{
-			// 初始化地址选项
-			initSelect() {
-				this.updateSourceDate() // 更新源数据
-				.updateAddressDate() // 更新结果数据
-				.$forceUpdate()  // 触发双向绑定
-			},
-			// 地址控件改变控件
-			columnchange(d) {
-				this.updateSelectIndex(d.detail.column, d.detail.value) // 更新选择索引
-				.updateSourceDate() // 更新源数据
-				.updateAddressDate() // 更新结果数据
-				.$forceUpdate()  // 触发双向绑定
-			},
-			
-			/**
-			 * 更新源数据
-			 * */
-			updateSourceDate() {
-				this.array = []
-				this.array[0] = AllAddress.map(obj => {
-					return {
-						name: obj.name
-					}
-				})
-				this.array[1] = AllAddress[this.value[0]].city.map(obj => {
-					return {
-						name: obj.name
-					}
-				})
-				this.array[2] = AllAddress[this.value[0]].city[this.value[1]].area.map(obj => { 
-					return {
-						name: obj
-					}
-				})
-				return this
-			},
-			
-			/**
-			 * 更新索引
-			 * */
-			updateSelectIndex(column, value){
-				let arr = JSON.parse(JSON.stringify(this.value)) 
-				arr[column] = value
-				if(column === 0 ) {
-					arr[1] = 0
-					arr[2] = 0
-				}
-				if(column === 1 ) {
-					arr[2] = 0
-				}
-				this.value = arr
-				return this
-			},
-			
-			/**
-			 * 更新结果数据 
-			 * */
-			updateAddressDate() {
-				selectVal[0] = this.array[0][this.value[0]].name
-				selectVal[1] = this.array[1][this.value[1]].name 
-				selectVal[2] = this.array[2][this.value[2]].name 
-				return this
-			},
-			
-			/**
-			 * 点击确定
-			 * */
-			bindPickerChange(e) {
-				this.$emit('change', {
-					index: this.value,
-					data: selectVal
-				})
-				return this
-			}
-			
-		}
-	}
-</script>
-
-<style>
-</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>

+ 38 - 0
config/app.js

@@ -0,0 +1,38 @@
+module.exports = {
+	// 小程序配置
+	// #ifdef MP || APP-PLUS
+	// 请求域名 格式: https://您的域名
+	HTTP_REQUEST_URL: `https://demo.crmeb.com`,
+	// #endif
+
+	// H5配置
+	// #ifdef H5
+	//H5接口是浏览器地址,非单独部署不用修改
+	HTTP_REQUEST_URL: window.location.protocol + "//" + window.location.host,
+	// #endif 
+
+
+	// 后台版本号
+	SYSTEM_VERSION: 520,
+	
+	// 以下配置在不做二开的前提下,不需要做任何的修改
+	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;

+ 0 - 39
libs/log.js

@@ -1,39 +0,0 @@
-
-const logLength=100;//缓存存储上限
-const name = 'log';//缓存名字
-export function addLog (data,content='') {
-	let log = uni.getStorageSync(name)||[];
-	log.unshift({
-		title:data,
-		content:content
-	});
-	uni.setStorageSync(name,log);
-	initLog(log);
-}
-
-
-export function delLog () {
-	return uni.setStorageSync(name,'');
-}
-
-export function getLog () {
-	return uni.getStorageSync(name);
-}
-
-export function initLog (log) {
-	if(log.length>logLength){
-		const newarr = log.slice(log.length-logLength);
-		uni.setStorageSync(name,newarr);
-	}
-}
-export function showLog (log) {
-	
-	let str = '';
-	uni.getStorageSync(name).forEach((e) => {
-		str+=e.title+':'+JSON.stringify(e.content)
-	})
-	uni.showModal({
-		title:"日志",
-		content:str
-	})
-}

+ 127 - 0
libs/login.js

@@ -0,0 +1,127 @@
+// +----------------------------------------------------------------------
+// | 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
+	const BASIC_CONFIG = Cache.get('BASIC_CONFIG')
+	if (!pathLogin)
+		pathLogin = '/page/users/login/index'
+	Cache.set('login_back_url', path);
+	console.log(BASIC_CONFIG, 'BASIC_CONFIG.wechat_status')
+	// #ifdef H5
+	if (isWeixin() && BASIC_CONFIG.wechat_status) {
+		uni.navigateTo({
+			url: '/pages/users/wechat_login/index',
+		});
+
+	} else {
+		uni.navigateTo({
+			url: '/pages/users/login/index'
+		})
+	}
+	// #endif
+
+	// #ifdef MP
+	let url
+	if (!BASIC_CONFIG.wechat_auth_switch) {
+		url = '/pages/users/binding_phone/index?pageType=0'
+	} else {
+		url = '/pages/users/wechat_login/index'
+	}
+	uni.navigateTo({
+		url
+	})
+	// #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;
+}

+ 328 - 0
libs/wechat.js

@@ -0,0 +1,328 @@
+// +----------------------------------------------------------------------
+// | 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(location.href);
+		const state = Cache.get('login_back_url') || '/pages/user/index';
+		// uni.setStorageSync(STATE_KEY, state);
+		uni.removeStorageSync(BACK_URL);
+		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

+ 84 - 5
main.js

@@ -1,13 +1,92 @@
+// +----------------------------------------------------------------------
+// | 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 store from './store'
 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
-Vue.prototype.$fire = new Vue();
-Vue.prototype.$store = store;
+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
+	...App,
+	store,
+	Cache,
+	i18n,
 })
-app.$mount()
+app.$mount();

+ 142 - 92
manifest.json

@@ -1,40 +1,51 @@
 {
-    "name" : "绿津",
-    "appid" : "__UNI__1E38A9C",
-    "description" : "",
-    "versionName" : "1.0.19",
-    "versionCode" : 122,
+    "name" : "CRMEB标准版-发行",
+    "appid" : "__UNI__A3F1ED4",
+    "description" : "CRMEB标准版",
+    "versionName" : "5.1.0",
+    "versionCode" : 510,
     "transformPx" : false,
+    /* 5+App特有相关 */
     "app-plus" : {
-        /* 5+App特有相关 */
         "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
         "splashscreen" : {
-            "alwaysShowBeforeRender" : true,
-            "waiting" : true,
+            "alwaysShowBeforeRender" : false,
+            "waiting" : false,
             "autoclose" : true,
             "delay" : 0
         },
+        "screenOrientation" : [
+            "portrait-primary",
+            "portrait-secondary",
+            "landscape-primary",
+            "landscape-secondary"
+        ],
+        /* 模块配置 */
         "modules" : {
-            "Maps" : {},
-            "Geolocation" : {},
-            "OAuth" : {},
             "Payment" : {},
-            "Share" : {}
+            "Share" : {},
+            "VideoPlayer" : {},
+            "OAuth" : {},
+            "Barcode" : {},
+            "Camera" : {}
         },
-        /* 模块配置 */
+        "safearea" : {
+            "bottom" : {
+                "offset" : "none"
+            }
+        },
+        /* 应用发布信息 */
         "distribute" : {
-            /* 应用发布信息 */
+            /* android打包配置 */
             "android" : {
-                /* android打包配置 */
                 "permissions" : [
-                    "<uses-feature android:name=\"android.hardware.camera\"/>",
-                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
                     "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
                     "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
                     "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
                     "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
                     "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
-                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.CAPTURE_AUDIO_OUTPUT\"/>",
                     "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
                     "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
                     "<uses-permission android:name=\"android.permission.INTERNET\"/>",
@@ -47,77 +58,90 @@
                     "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
                     "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
                 ],
-                "abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
+                "abiFilters" : [ "armeabi-v7a", "arm64-v8a" ],
+                "permissionExternalStorage" : {
+                    "request" : "none",
+                    "prompt" : "应用保存运行状态等信息,需要获取读写手机存储(系统提示为访问设备上的照片、媒体内容和文件)权限,请允许。"
+                },
+                "permissionPhoneState" : {
+                    "request" : "none" //拨打电话权限关闭
+                }
             },
+            /* ios打包配置 */
             "ios" : {
-                "idfa" : false,
+                "capabilities" : {
+                    "entitlements" : {
+                        "com.apple.developer.associated-domains" : [
+                            "applinks:",
+                            "applinks:",
+                            "applinks:",
+                            "applinks:static-679f0930-8f60-425c-9033-8c135f397ea5.bspapp.com"
+                        ]
+                    }
+                },
                 "privacyDescription" : {
-                    "NSPhotoLibraryUsageDescription" : "用于提交审核认证",
-                    "NSLocationWhenInUseUsageDescription" : "该应用需要持续获取用户地理位置,以便为你进行导航",
-                    "NSLocationAlwaysUsageDescription" : "该应用需要你的地理位置,以便为你提供当前位置信息",
-                    "NSPhotoLibraryAddUsageDescription" : "该应用需要读取你的相册,以便为你编辑个人信息",
-                    "NSCameraUsageDescription" : "该应用需要你的相机,以便你完成信息认证",
-                    "NSLocationAlwaysAndWhenInUseUsageDescription" : "该应用需要你的地理位置,以便为你提供当前位置信息"
+                    "NSLocationWhenInUseUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSPhotoLibraryUsageDescription" : "上传用户头像保存分享海报",
+                    "NSPhotoLibraryAddUsageDescription" : "上传用户头像保存分享海报",
+                    "NSLocationAlwaysAndWhenInUseUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSLocationAlwaysUsageDescription" : "根据客户地理位置推荐最近门店",
+                    "NSCameraUsageDescription" : "上传用户头像保存分享海报"
                 },
+                "idfa" : false,
                 "dSYMs" : false
             },
-            /* ios打包配置 */
+            /* 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" : {},
                 "maps" : {
                     "amap" : {
-                        "appkey_ios" : "7e8fabcd781f77afbd37eaf98dd54498",
-                        "appkey_android" : "605c71799909b1b96fbc15dbe161cca0"
+                        "appkey_ios" : "aeb768547b9d752891e37e1ca0a2b66d",
+                        "appkey_android" : "41ec5c3f4d110ce02a326210fe147be8"
                     }
                 },
                 "oauth" : {
+                    "apple" : {},
                     "weixin" : {
-                        "appid" : "wx016c3a0056b79c15",
-                        "appsecret" : "ab387ea25d15ad1f6d91d72ddc64bf96",
-                        "UniversalLinks" : "https://www.zjljzn.com/uni-universallinks/__UNI__F0EBD91/"
-                    },
-                    "apple" : {}
+                        "appid" : "wx277a269f3d736d67",
+                        "appsecret" : "bd08741a055c2ecac5826ff1c048464b",
+                        "UniversalLinks" : "https://bzapp.crmeb.net/uni-universallinks/__UNI__A3F1ED4/"
+                    }
                 },
                 "ad" : {},
                 "geolocation" : {
                     "amap" : {
                         "__platform__" : [ "ios", "android" ],
-                        "appkey_ios" : "7e8fabcd781f77afbd37eaf98dd54498",
-                        "appkey_android" : "605c71799909b1b96fbc15dbe161cca0"
-                    },
-                    "system" : {
-                        "__platform__" : [ "ios", "android" ]
-                    }
-                },
-                "payment" : {
-                    "alipay" : {
-                        "__platform__" : [ "ios", "android" ]
-                    },
-                    "weixin" : {
-                        "__platform__" : [ "ios", "android" ],
-                        "appid" : "wx016c3a0056b79c15",
-                        "UniversalLinks" : "https://www.zjljzn.com/uni-universallinks/__UNI__F0EBD91/"
+                        "appkey_ios" : "aeb768547b9d752891e37e1ca0a2b66d",
+                        "appkey_android" : "41ec5c3f4d110ce02a326210fe147be8"
                     }
                 },
-                "push" : {},
-                "share" : {
-                    "weixin" : {
-                        "appid" : "wx016c3a0056b79c15",
-                        "UniversalLinks" : "https://www.zjljzn.com/uni-universallinks/__UNI__F0EBD91/"
+                "statics" : {
+                    "google" : {
+                        "config_ios" : "",
+                        "config_android" : ""
                     }
-                },
-                "statics" : {}
+                }
             },
             "splashscreen" : {
                 "androidStyle" : "common",
                 "iosStyle" : "common",
-                "android" : {
-                    "hdpi" : "unpackage/启动图/安卓/482.9.png",
-                    "xhdpi" : "unpackage/启动图/安卓/722.9.png",
-                    "xxhdpi" : "unpackage/启动图/安卓/1082.9.png"
-                },
-                "ios" : {
-                    "storyboard" : "unpackage/启动图/ios/CustomStoryboard.zip"
-                }
+                "useOriginalMsgbox" : true
             },
             "icons" : {
                 "android" : {
@@ -153,51 +177,77 @@
             }
         }
     },
-    /* SDK配置 */
-    "quickapp" : {},
     /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
     "mp-weixin" : {
-        /* 小程序特有相关 */
-        "usingComponents" : true,
-        "appid" : "wx1af9ca9ccd6ca98b",
+        "appid" : "wx3b82801238ca1b57",
         "setting" : {
-            "urlCheck" : true,
-            "minified" : true
+            "urlCheck" : false,
+            "minified" : true,
+            "postcss" : true,
+            "es6" : true
         },
         "permission" : {
             "scope.userLocation" : {
-                "desc" : "为了定位车辆位置需要获取定位信息"
+                "desc" : "你的位置信息将用于和门店的距离长度"
             }
         },
-        "lazyCodeLoading" : "requiredComponents",
-        "requiredBackgroundModes" : [ "location" ]
+        "optimization" : {
+            "subPackages" : true
+        },
+        "usingComponents" : true,
+        "requiredPrivateInfos" : [
+            "getLocation",
+            "onLocationChange",
+            "startLocationUpdateBackground",
+            "chooseAddress"
+        ],
+        "__usePrivacyCheck__" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
     },
     "h5" : {
-        "title" : "绿津",
-        "domain" : "",
-        "router" : {
-            "base" : "/index/",
-            "mode" : "history"
-        },
         "devServer" : {
-            "proxy" : {
-                "/api" : {
-                    "target" : "https://www.zjljzn.com/api",
-                    // "changeOrigin": true,
-                    "pathRewrite" : {
-                        "/api" : "" // rewrite path
-                    }
-                }
-            },
-            "https" : true
+            "https" : false
         },
+        "router" : {
+            "mode" : "history",
+            "base" : ""
+        },
+        "domain" : "",
         "sdkConfigs" : {
             "maps" : {
                 "qqmap" : {
-                    "key" : "VYZBZ-P2TRG-RMIQ3-ITAIN-2DKBK-CKFQQ"
+                    "key" : "NO7BZ-APDKP-UCBD7-VT7CX-R5UZK-JBF2W"
                 }
             }
+        },
+        "optimization" : {
+            "treeShaking" : {
+                "enable" : true
+            },
+            "subPackages" : true
+        },
+        "async" : {
+            "timeout" : 200000
+        },
+        "title" : "加载中"
+    },
+    "plus" : {
+        "statusbar" : {
+            "immersed" : true
         }
     },
-    "_spaceID" : "364f3115-6ed2-4e8f-913f-836cbd3f34fa"
+    "_spaceID" : "679f0930-8f60-425c-9033-8c135f397ea5",
+    "lazyCodeLoading" : "requiredComponents"
 }
+/* ios打包配置 */
+

+ 41 - 0
mixins/SendVerifyCode.js

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

+ 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: {}
+};

+ 273 - 0
mixins/sharePoster.js

@@ -0,0 +1,273 @@
+// +----------------------------------------------------------------------
+// | 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];
+			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"
+			}
+		}
+	}
+}

+ 0 - 19
package.json

@@ -1,19 +0,0 @@
-{
-    "id": "alger-simg",
-    "name": "图片预览(使用简单 长按可保存分享 插件)",
-    "version": "1.1.0",
-    "description": "图片预览(使用简单) 可以双指缩放 可以保存分享",
-    "keywords": [
-        "图片",
-        "image",
-        "img",
-        "图片预览",
-        "大图"
-    ],
-    "dcloudext": {
-        "category": [
-            "前端组件",
-            "通用组件"
-        ]
-    }
-}

Fichier diff supprimé car celui-ci est trop grand
+ 1515 - 360
pages.json


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

@@ -0,0 +1,262 @@
+<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-if="item.status === 3">{{$t(`砍价成功`)}}</div>
+						<div class="end" v-if="item.status === 2">{{$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>
+						<div class="acea-row row-middle row-right success"  v-if="item.status === 3">
+							{{item.success_time}}
+						</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>

Fichier diff supprimé car celui-ci est trop grand
+ 81 - 0
pages/activity/goods_bargain/index.vue


Fichier diff supprimé car celui-ci est trop grand
+ 370 - 0
pages/activity/goods_bargain_details/index.vue


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

@@ -0,0 +1,367 @@
+<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" v-if="combinationList.length">
+			<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;
+				this.$util.JumpPath(url);
+			},
+			openSubcribe: function(item) {
+				let page = item;
+				// #ifndef MP
+				uni.navigateTo({
+					url: `/pages/activity/goods_combination_details/index?id=${item.id}`
+				});
+				// #endif
+				// #ifdef MP
+				uni.showLoading({
+					title: 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;
+						line-height: 38rpx;
+						height: 70rpx;
+					}
+
+					.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>

Fichier diff supprimé car celui-ci est trop grand
+ 1686 - 0
pages/activity/goods_combination_details/index.vue


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff