liujiaxin 4 ヶ月 前
コミット
79a69a381c
100 ファイル変更14126 行追加697 行削除
  1. 3 3
      api/live.js
  2. 55 27
      api/login.js
  3. 45 13
      api/order.js
  4. 133 11
      api/pay.js
  5. 2 1
      common/request.js
  6. 21 0
      components/Loading.vue
  7. 1 1
      components/YEditor/YEditor2.vue
  8. 143 0
      components/evan-switch/evan-switch.vue
  9. 316 0
      components/px-popup-bottom/px-popup-bottom.vue
  10. 868 0
      confirmOrder.vue
  11. 3 1
      core/config/defaultConfig.js
  12. 38 15
      main.js
  13. 6 6
      node_modules/.vite/deps/_metadata.json
  14. 1 1
      node_modules/.vite/deps/chunk-BEIQYKVI.js
  15. 0 0
      node_modules/.vite/deps/chunk-BEIQYKVI.js.map
  16. 1 1
      node_modules/.vite/deps/crypto-js.js
  17. 1 1
      node_modules/.vite/deps/hls_js.js
  18. 28 0
      node_modules/dayjs/CHANGELOG.md
  19. 34 11
      node_modules/dayjs/README.md
  20. 1 1
      node_modules/dayjs/esm/index.d.ts
  21. 1 1
      node_modules/dayjs/esm/locale/bg.js
  22. 1 0
      node_modules/dayjs/esm/locale/da.js
  23. 22 1
      node_modules/dayjs/esm/locale/zh-hk.js
  24. 18 5
      node_modules/dayjs/esm/plugin/customParseFormat/index.js
  25. 15 4
      node_modules/dayjs/esm/plugin/minMax/index.d.ts
  26. 4 0
      node_modules/dayjs/esm/plugin/negativeYear/index.d.ts
  27. 36 0
      node_modules/dayjs/esm/plugin/negativeYear/index.js
  28. 16 7
      node_modules/dayjs/esm/plugin/timezone/index.js
  29. 1 1
      node_modules/dayjs/index.d.ts
  30. 0 0
      node_modules/dayjs/locale.json
  31. 1 1
      node_modules/dayjs/locale/bg.js
  32. 1 1
      node_modules/dayjs/locale/da.js
  33. 1 1
      node_modules/dayjs/locale/zh-hk.js
  34. 12 11
      node_modules/dayjs/package.json
  35. 0 0
      node_modules/dayjs/plugin/customParseFormat.js
  36. 15 4
      node_modules/dayjs/plugin/minMax.d.ts
  37. 4 0
      node_modules/dayjs/plugin/negativeYear.d.ts
  38. 1 0
      node_modules/dayjs/plugin/negativeYear.js
  39. 0 0
      node_modules/dayjs/plugin/timezone.js
  40. 275 0
      node_modules/mescroll-uni/README.md
  41. 55 0
      node_modules/mescroll-uni/components/mescroll-down.css
  42. 47 0
      node_modules/mescroll-uni/components/mescroll-down.vue
  43. 118 0
      node_modules/mescroll-uni/components/mescroll-empty.vue
  44. 83 0
      node_modules/mescroll-uni/components/mescroll-top.vue
  45. 47 0
      node_modules/mescroll-uni/components/mescroll-up.css
  46. 39 0
      node_modules/mescroll-uni/components/mescroll-up.vue
  47. 19 0
      node_modules/mescroll-uni/mescroll-body.css
  48. 403 0
      node_modules/mescroll-uni/mescroll-body.vue
  49. 15 0
      node_modules/mescroll-uni/mescroll-i18n.js
  50. 57 0
      node_modules/mescroll-uni/mescroll-mixins.js
  51. 64 0
      node_modules/mescroll-uni/mescroll-uni-option.js
  52. 36 0
      node_modules/mescroll-uni/mescroll-uni.css
  53. 799 0
      node_modules/mescroll-uni/mescroll-uni.js
  54. 480 0
      node_modules/mescroll-uni/mescroll-uni.vue
  55. 47 0
      node_modules/mescroll-uni/mixins/mescroll-comp.js
  56. 66 0
      node_modules/mescroll-uni/mixins/mescroll-more-item.js
  57. 74 0
      node_modules/mescroll-uni/mixins/mescroll-more.js
  58. 39 0
      node_modules/mescroll-uni/package.json
  59. 109 0
      node_modules/mescroll-uni/wxs/mixins.js
  60. 92 0
      node_modules/mescroll-uni/wxs/renderjs.js
  61. 268 0
      node_modules/mescroll-uni/wxs/wxs.wxs
  62. 8 3
      package-lock.json
  63. 3 2
      package.json
  64. 169 28
      pages.json
  65. 287 0
      pages/auth/findpass.vue
  66. 203 0
      pages/auth/h5WxLogin.vue
  67. 54 126
      pages/auth/login.vue
  68. 303 0
      pages/auth/loginIndex.vue
  69. 399 0
      pages/auth/register.vue
  70. 1 1
      pages/home/index.vue
  71. 1 1
      pages/home/live.vue
  72. 276 358
      pages/home/living.vue
  73. 76 48
      pages/list/index.vue
  74. 342 0
      pages_no/payOrder.vue
  75. 507 0
      pages_shop/cart.vue
  76. 181 0
      pages_shop/components/likeProduct.vue
  77. 1051 0
      pages_shop/confirmCreateOrder.vue
  78. 720 0
      pages_shop/confirmPackageOrder.vue
  79. 1801 0
      pages_shop/goods.vue
  80. 187 0
      pages_shop/order.vue
  81. 892 0
      pages_shop/paymentOrder.vue
  82. 648 0
      pages_shop/store.vue
  83. 203 0
      pages_shop/success.vue
  84. 411 0
      pages_user/addAddress.vue
  85. 322 0
      pages_user/address.vue
  86. BIN
      static/images/account.png
  87. BIN
      static/images/add.png
  88. BIN
      static/images/add26.png
  89. BIN
      static/images/arrow4.png
  90. BIN
      static/images/arrow_gray.png
  91. BIN
      static/images/back_white.png
  92. BIN
      static/images/chu_query.png
  93. BIN
      static/images/coupon1.png
  94. BIN
      static/images/coupon2.png
  95. BIN
      static/images/del1.png
  96. BIN
      static/images/edit.png
  97. BIN
      static/images/googs1.png
  98. BIN
      static/images/googs2.png
  99. BIN
      static/images/googs3.png
  100. BIN
      static/images/googs_service.png

+ 3 - 3
api/live.js

@@ -6,7 +6,7 @@ const api = {
 	follow:(liveId) => `/app/live/liveData/follow/${liveId}`,// 关注/取消关注
 	getRecentLiveViewers:(liveId) =>  `/app/live/liveData/getRecentLiveViewers/${liveId}`,// 获取直播间用户(展示在线用户)
 	// checkSms: 'api/sms/checkSms',
-	getLive:(liveId) =>  `/app/live/${liveId}`,// 获取直播间信息接口
+	getLiveInfo:(liveId) =>  `/app/live/${liveId}`,// 获取直播间信息接口
 	getLiveViewData:(liveId) =>  `/app/live/liveData/getLiveViewData/${liveId}`,// 直播间点赞、关注、在线人数数据
 
 
@@ -72,8 +72,8 @@ export function liveOrderUser(liveId,data={}) {
 
 
 // 直播间
-export function getLive(liveId,data={}) {
-	return request(api.getLive(liveId),data,'GET','application/json;charset=UTF-8')
+export function getLiveInfo(liveId,data={}) {
+	return request(api.getLiveInfo(liveId),data,'GET','application/json;charset=UTF-8')
 }
 
 // 直播间点赞、关注、在线人数数据

+ 55 - 27
api/login.js

@@ -1,4 +1,6 @@
-import request from '@/utils/request'
+// import request from '@/utils/request'
+import Request from '@/common/request.js';
+let request = new Request().http
 const api = {
 	userLoginWX: 'api/login/login',
 	userLloginApp: 'api/login/loginApp',
@@ -7,40 +9,66 @@ const api = {
 	checkSms: 'api/sms/checkSms',
 	resetPassword: 'api/login/resetPassword',
 	// 我写的登录
-	loginByApp: 'app/user/loginByApp',
+	loginByApp: '/app/user/loginByApp',//登录
 	captchaImage: 'captchaImage',
 	
+	checkLogin: '/app/user/checkLogin',//验证是否登录
+	register: '/app/user/register',//注册账号
+	loginByWeChat: '/app/user/loginByWeChat',//微信登录
+	setPhone: '/app/user/setPhone',//绑定手机号码
+	
+
+
 }
-// 登录
-export function userLoginWX(data) {
-	return request.post(api.userLoginWX, data)
-}
-// App登录
-export function userLloginApp(data) {
-	return request.post(api.userLloginApp, data)
-}
-// 登录(H5)
-export function userLoginH5(data) {
-	return request.post(api.userLoginH5, data)
-}
-// 获取验证码
-export function doSmsSend(data) {
-	return request.post(api.doSmsSend, data)
-}
+// // 登录
+// export function userLoginWX(data) {
+// 	return request.post(api.userLoginWX, data)
+// }
+// // App登录
+// export function userLloginApp(data) {
+// 	return request.post(api.userLloginApp, data)
+// }
+// // 登录(H5)
+// export function userLoginH5(data) {
+// 	return request.post(api.userLoginH5, data)
+// }
+// // 获取验证码
+// export function doSmsSend(data) {
+// 	return request.post(api.doSmsSend, data)
+// }
 
 
 // 我写的登录
 // /app/user/loginByApp
+// export function loginByApp(data) {
+// 	return request.post(api.loginByApp, data)
+// }
+
+// 登录
 export function loginByApp(data) {
-	return request.post(api.loginByApp, data)
+	return request(api.loginByApp, data, 'POST', 'application/json;charset=UTF-8');
 }
-// export function loginByApp(data) {
-//  	 return request('/app/user/loginByApp',data,'GET','application/json;charset=UTF-8');
-//  }
-//  export function captchaImage() {
-//   	 return request('/captchaImage','GET','application/json;charset=UTF-8');
-//   }
-export function captchaImage(data) {
-	return request.get(api.captchaImage)
+export function captchaImage() {
+	return request(api.captchaImage, 'GET', 'application/json;charset=UTF-8');
+}
+
+
+//验证是否登录
+export function checkLogin(data) {
+	return request(api.checkLogin, data, 'GET', 'application/json;charset=UTF-8');
+}
+
+//注册账号
+export function register(data) {
+	return request(api.register, data, 'POST', 'application/json;charset=UTF-8');
+}
+
+//微信登录
+export function loginByWeChat(data) {
+	return request(api.loginByWeChat, data, 'POST', 'application/json;charset=UTF-8');
 }
 
+//绑定手机号码
+export function setPhone(data) {
+	return request(api.setPhone, data, 'POST', 'application/json;charset=UTF-8');
+}

+ 45 - 13
api/order.js

@@ -2,32 +2,64 @@ import Request from '@/common/request.js';
 let request = new Request().http
 const api = {
 	// 直播订单
-	liveOrderList: '/app/live/liveOrder/list',// 订单列表
-	createliveOrder: '/app/live/liveOrder/create',// 创建订单
-	updateConfirm:(liveId) =>  `/app/live/liveOrder/updateConfirm/${orderId} `,// 取消/支付订单确认
-	updateLiveOrder: '/app/live/liveOrder/update',// 取消/支付订单
+	liveOrderList: '/app/live/liveOrder/list', // 订单列表
+	createliveOrder: '/app/live/liveOrder/create', // 创建订单
+	updateConfirm: (orderId, type) => `/app/live/liveOrder/updateConfirm/${orderId}/${type} `, // 取消/支付订单确认
+	updateLiveOrder: '/app/live/liveOrder/update', // 取消/支付订单
+	liveOrderKey: '/app/live/liveOrder/confirm', // 生成订单key
+	userAddr: (userId) => `/app/user/getUserAddr/${userId} `, // 获取用户收货地址
+	addAddress: '/app/userAddress/addAddress', // 添加地址
+	editAddress: '/app/userAddress/editAddress', // 编辑地址
+	delAddress: '/app/userAddress/delAddress', // 删除地址
+	getCitys: '/app/common/getCitys', // 获取省市区
+
 }
 
 
 // 直播订单
 
-// 订单列表
-export function liveOrderList(data) {
-	return request(api.liveOrderList,data,'GET','application/json;charset=UTF-8')
-}
-
 // 创建订单
 export function createliveOrder(data) {
-	return request(api.createliveOrder,data,'Post','application/json;charset=UTF-8')
+	return request(api.createliveOrder, data, 'POST', 'application/json;charset=UTF-8')
+}
+// 生成订单key
+export function liveOrderKey(data = {}) {
+	return request(api.liveOrderKey, data, 'POST', 'application/json;charset=UTF-8')
 }
 
-// 取消/支付订单确认
+// 点击取消/支付订单
 export function updateConfirm(data) {
-	return request(api.updateConfirm,data,'GET','application/json;charset=UTF-8')
+	return request(api.updateConfirm(orderId, type), data, 'GET', 'application/json;charset=UTF-8')
 }
 
 // 取消/支付订单
 export function updateLiveOrder(data) {
-	return request(api.updateLiveOrder,data,'Post','application/json;charset=UTF-8')
+	return request(api.updateLiveOrder, data, 'POST', 'application/json;charset=UTF-8')
+}
+// 订单列表
+export function liveOrderList(data) {
+	return request(api.liveOrderList, data, 'GET', 'application/json;charset=UTF-8')
+}
+
+// 获取用户收货地址
+export function userAddr(userId, data = {}) {
+	return request(api.userAddr(userId), data, 'GET', 'application/json;charset=UTF-8')
+}
+
+// 添加地址
+export function addAddress(data) {
+	return request(api.addAddress, data, 'POST', 'application/json;charset=UTF-8')
+}
+// 编辑地址
+export function editAddress(data) {
+	return request(api.editAddress, data, 'POST', 'application/json;charset=UTF-8')
+}
+// 删除地址
+export function delAddress(data) {
+	return request(api.delAddress, data, 'POST', 'application/json;charset=UTF-8')
 }
 
+//获取省市区 
+export function getCitys(data) {
+	return request(api.getCitys, data, 'GET', 'application/json;charset=UTF-8')
+}

+ 133 - 11
api/pay.js

@@ -1,14 +1,136 @@
-import request from '@/utils/request'
-// api地址
+import Request from '@/common/request.js';
+let request = new Request().http
 const api = {
-	prePayment: 'api/Payment/prePayment',
-	getPayList: 'api/payment/getPayList',
+	// 支付
+	zfbPayment: '/app/live/liveOrder/aliPayment', // 支付宝付款
+	weChatPayment: '/app/live/liveOrder/weChatPayment', // 微信付款
+
+
+	// updateConfirm: (orderId, type) => `/app/live/liveOrder/updateConfirm/${orderId}/${type} `, // 取消/支付订单确认
+
+
+
 }
-// 发起支付
-export function prePayment(data) {
-	return request.post(api.prePayment, data)
+
+
+// 支付
+
+// 支付宝付款
+export function zfbPayment(data) {
+	return request(api.zfbPayment, data, 'POST', 'application/json;charset=UTF-8')
 }
-// 支付列表
-export function getPayList(data) {
-	return request.get(api.getPayList, data)
-}
+// 微信付款
+// export function weChatPayment(data) {
+// 	return request(api.weChatPayment, data, 'POST', 'application/json;charset=UTF-8')
+// }
+/**
+ * 微信支付(全平台适配简化版)
+ * @param {String} orderId 订单ID
+ * @param {Number} amount 金额(单位:分)
+ * @returns {Promise}
+ */
+// export function weChatPayment(orderId, amount) {
+export function weChatPayment(data) {
+	return new Promise((resolve, reject) => {
+		// 1. 获取支付参数
+		// totalFee: amount, // platform: getPlatform() // 自动识别平台
+		request(api.weChatPayment, data, 'POST', 'application/json;charset=UTF-8')
+			.then(res => {
+				// 2. 调用平台支付
+				invokePayment(res.data)
+					.then(resolve)
+					.catch(err => {
+						handlePaymentError(err);
+						reject(err);
+					});
+			})
+			.catch(err => {
+				handlePaymentError(err);
+				reject(err);
+			});
+	});
+}
+
+// ==================== 内部方法 ====================
+function getPlatform() {
+	// #ifdef MP-WEIXIN
+	return 'miniprogram';
+	// #endif
+	// #ifdef APP-PLUS
+	return 'app';
+	// #endif
+	// #ifdef H5
+	return 'h5';
+	// #endif
+}
+
+function invokePayment(payData) {
+	return new Promise((resolve, reject) => {
+		// #ifdef MP-WEIXIN
+		uni.requestPayment({
+			provider: 'wxpay',
+			...payData, // 直接展开小程序所需参数
+			success: (res) => {
+				uni.showToast({
+					title: '支付成功'
+				});
+				resolve(res);
+			},
+			fail: (err) => {
+				reject(new Error(formatError(err)));
+			}
+		});
+		// #endif
+
+		// #ifdef APP-PLUS
+		uni.requestPayment({
+			provider: 'wxpay',
+			orderInfo: payData.orderInfo,
+			success: resolve,
+			fail: (err) => {
+				reject(new Error(formatError(err)));
+			}
+		});
+		// #endif
+
+		// #ifdef H5
+		if (typeof WeixinJSBridge === 'undefined') {
+			return reject(new Error('请在微信浏览器中打开'));
+		}
+
+		WeixinJSBridge.invoke(
+			'getBrandWCPayRequest',
+			payData,
+			(res) => {
+				if (res.err_msg === 'get_brand_wcpay_request:ok') {
+					resolve(res);
+				} else {
+					reject(new Error(res.err_msg || '支付失败'));
+				}
+			}
+		);
+		// #endif
+	});
+}
+
+function formatError(err) {
+	if (err.errMsg) {
+		if (err.errMsg.includes('cancel')) return '支付已取消';
+		if (err.errMsg.includes('fail')) return '支付失败';
+	}
+	return err.message || '支付异常';
+}
+
+function handlePaymentError(err) {
+	console.error('[支付错误]', err);
+	uni.showToast({
+		title: err.message,
+		icon: 'none',
+		duration: 3000
+	});
+}
+
+// 微信
+// export function userAddr(userId, data={}) {
+// 	return request(api.userAddr(userId), data, 'GET', 'application/json;charset=UTF-8')
+// }

+ 2 - 1
common/request.js

@@ -2,7 +2,8 @@
 export default class Request {
 	http(router, data = {}, method,contentType) {
 		let that = this;
-		let path = 'http://192.168.10.166:7114'//余红奇
+		let path = 'http://nd383294.natappfree.cc'//余红奇
+		// let path = 'http://v56c9b8e.natappfree.cc'//余红奇
 		// let path = 'http://192.168.10.170:7114'//陈果
 		// let path = 'http://192.168.10.166:7114'
 		// let path = 'http://h5api.wxcourse.cdwjyyh.com'

+ 21 - 0
components/Loading.vue

@@ -0,0 +1,21 @@
+<template>
+  <view class="Loads acea-row row-center-wrapper" v-if="loading || !loaded" style="margin-top: 20rpx;">
+    <template v-if="loading">
+      <view class="iconfont icon-jiazai loading acea-row row-center-wrapper"></view>
+      正在加载中
+    </template>
+    <template v-if="!loading">
+      上拉加载更多
+    </template>
+  </view>
+</template>
+
+<script>
+  export default {
+    name: "Loading",
+    props: {
+      loaded: Boolean,
+      loading: Boolean
+    }
+  };
+</script>

+ 1 - 1
components/YEditor/YEditor2.vue

@@ -51,7 +51,7 @@
 	// 获取屏幕边界到安全区域距离
 	const {
 		safeAreaInsets
-	} = uni.getSystemInfoSync()
+	} = uni.getWindowInfo()
 
 
 	// 弹出层组件

+ 143 - 0
components/evan-switch/evan-switch.vue

@@ -0,0 +1,143 @@
+<template>
+	<!-- <view @click="toggle" class="evan-switch" :class="{'evan-switch--disabled':disabled}" :style="{width:2*size+'px',height:switchHeight,borderRadius:size+'px',backgroundColor:currentValue===activeValue?activeColor:inactiveColor}">
+		<view class="evan-switch__circle" :style="{width:size+'px',height:size+'px',transform:currentValue===activeValue?`translateX(${size}px)`:`translateX(0)`}"></view>
+	</view> -->
+	<view @click="toggle" class="evan-switch" :class="{'evan-switch--disabled':disabled}" :style="{backgroundColor:currentValue===activeValue?activeColor:inactiveColor}">
+		<view class="evan-switch__circle" :style="{transform:currentValue===activeValue?`translateX(${29}px)`:`translateX(0)`}"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'EvanSwitch',
+		props: {
+			value: {
+				type: [String, Number, Boolean],
+				default: false
+			},
+			activeColor: {
+				type: String,
+				default: '#108ee9'
+			},
+			inactiveColor: {
+				type: String,
+				default: '#fff'
+			},
+			size: {
+				type: Number,
+				default: 30
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+			activeValue: {
+				type: [String, Number, Boolean],
+				default: true
+			},
+			inactiveValue: {
+				type: [String, Number, Boolean],
+				default: false
+			},
+			beforeChange: {
+				type: Function,
+				default: null
+			},
+			extraData: null,
+			contextLevel: {
+				type: Number,
+				default: 1
+			}
+		},
+		computed: {
+			switchHeight() {
+				// #ifdef APP-NVUE
+				return this.size + 2 + 'px'
+				// #endif
+				// #ifndef APP-NVUE
+				return this.size + 'px'
+				// #endif
+			}
+		},
+		watch: {
+			value: {
+				immediate: true,
+				handler(value) {
+					this.currentValue = value
+				}
+			}
+		},
+		data() {
+			return {
+				currentValue: false
+			}
+		},
+		methods: {
+			toggle() {
+				if (!this.disabled) {
+					if (this.beforeChange && typeof this.beforeChange === 'function') {
+						let context = this
+						for (let i = 0; i < this.contextLevel; i++) {
+							context = context.$options.parent
+						}
+						const result = this.beforeChange(this.currentValue === this.activeValue ? this.inactiveValue : this.activeValue,
+							this.extraData, context)
+						if (typeof result === 'object') {
+							result.then(() => {
+								this.toggleValue()
+							}).catch(() => {})
+						} else if (typeof result === 'boolean' && result) {
+							this.toggleValue()
+						}
+					} else {
+						this.toggleValue()
+					}
+				}
+			},
+			toggleValue() {
+				this.currentValue = this.currentValue === this.activeValue ? this.inactiveValue : this.activeValue
+				this.$emit('input', this.currentValue)
+				this.$emit('change', this.currentValue)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.evan-switch {
+		position: relative;
+		border-width: 1px;
+		border-color: rgba(0, 0, 0, 0.1);
+		border-style: solid;
+		transition: background-color 0.3s;
+		width: 100upx;
+		height: 36upx;
+		background: #0bb3f2;
+		border-radius: 18upx;
+		/* #ifndef APP-NVUE */
+		box-sizing: content-box;
+		/* #endif */
+	}
+
+	.evan-switch--disabled {
+		opacity: 0.3;
+	}
+
+	.evan-switch__circle {
+		position: absolute;
+		left: -4upx;
+		top: -8upx;
+		width: 50upx;
+		height: 50upx;
+		background: #FFFFFF;
+		box-shadow: 0px 2px 10px 0px rgba(166, 217, 212, 0.49);
+		border-radius: 50%;
+		/* #ifndef APP-NVUE */
+		box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 3px 3px 0 rgba(0, 0, 0, 0.05);
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		box-shadow: 1px 0 0px 0 rgba(0, 0, 0, 0.05);
+		/* #endif */
+		transition: transform 0.3s;
+	}
+</style>

+ 316 - 0
components/px-popup-bottom/px-popup-bottom.vue

@@ -0,0 +1,316 @@
+<template>
+	<view :class="['popup',{'popup-show':show}]" @mousewheel.prevent.stop @touchmove.stop.prevent
+		:style="{'z-index':zindex}">
+		<view class="mask" :style="{'z-index':maskZindex,bottom:bottom+'rpx'}" v-show="show" @click.stop="onClose"
+			@touchmove.prevent.stop></view>
+		<view :class="['content',{show}]" @click.stop @touchmove.prevent.stop :style="{'background-color':bgColor,height:`${height}px`,maxHeight:show ? cotMaxHeight:0,'border-top-right-radius':cotRadius,
+			'border-top-left-radius':cotRadius,transition: `all ${animaTime}s ease-in`,bottom:bottom+'rpx','z-index':zindex}">
+			<view id="title-bar" class="title-bar" v-show="title">
+				<view class="title" :style="{fontWeight:fontweight}">{{title}}</view>
+				<view class="close-wrap" @click.stop="onClose">
+					<!-- <image class="close-icon" :src="closeIcon" mode="widthFix"></image> -->
+					<image class="close-icon" src="" mode="widthFix"></image>
+				</view>
+			</view>
+			<view class="scroll-wrap">
+				<scroll-view enable-flex :class="{'scroll-view':isAnimaStart}" scroll-y="true" style="height:100%;"
+					@scrolltolower="onScrollToLower">
+					<view id="popup_content" class="popup_content">
+						<slot></slot>
+					</view>
+				</scroll-view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	// import iconClose from '@/static/images/close40.png'
+	export default {
+		props: {
+			title: { //标题
+				type: String,
+				default: ''
+			},
+			fontweight: {
+				type: [String, Number],
+				default: 'normal'
+			},
+			visible: { //隐藏显示标识
+				type: Boolean,
+				default: false
+			},
+			maxHeight: { //内容区域最大高度
+				type: [String, Number],
+				default: '75%'
+			},
+			radius: { //顶部圆角
+				type: [String, Number],
+				default: '0'
+			},
+			animaTime: { //弹窗动画时间
+				type: Number,
+				default: 0.2
+			},
+			bottom: { //离底部距离
+				type: [String, Number],
+				default: 0
+			},
+			bgColor: {
+				type: [String],
+				default: '#ffffff'
+			},
+			zindex: {
+				type: [String, Number],
+				default: 1000
+			},
+			maskZindex: {
+				type: [String, Number],
+				default: 999
+			},
+			always: { //是否每次打开都重新计算内容高度
+				type: Boolean,
+				default: false
+			},
+
+		},
+		data() {
+			return {
+				show: false,
+				height: 0,
+				PopHeight: 0,
+				cotMaxHeight: '',
+				isAnimaStart: false,
+				rpxRate: "",
+				cotRadius: 0,
+				// closeIcon: iconClose
+			}
+		},
+		watch: {
+			visible(newval) {
+				this.isAnimaStart = true;
+				setTimeout(() => {
+					this.isAnimaStart = false;
+				}, this.animaTime * 1000)
+
+				if (newval && this.height === 0) {
+					if (this.PopHeight === 0 || this.always) {
+						this.setContViewHeight();
+
+					} else {
+						this.height = this.PopHeight
+					}
+
+					// #ifdef H5 
+					this.setBodyOverFlow('hidden') //阻止滚动穿透
+					//#endif
+					this.$emit('open')
+
+				} else {
+					this.height = 0;
+					// #ifdef H5 
+					this.setBodyOverFlow('visible')
+					//#endif
+
+				}
+
+				this.show = newval
+
+			},
+			maxHeight: {
+				handler(newval) {
+					this.cotMaxHeight = this.unitCheck(newval);
+
+				},
+				immediate: true
+			},
+			radius: {
+				handler(newval) {
+					this.cotRadius = this.unitCheck(newval);
+
+				},
+				immediate: true
+			}
+		},
+		created() {
+			this.rpxRate = this.getRpxRate()
+		},
+		mounted() {
+			this.$nextTick(() => {
+				// #ifdef H5
+				this.preventTouch(document.querySelector(
+					'.scroll-wrap .uni-scroll-view .uni-scroll-view')); //防止浏览器报错
+				//#endif
+			})
+		},
+		methods: {
+			onClose() {
+				this.$emit("update:visible", false);
+				this.$emit('close')
+			},
+			//触底
+			onScrollToLower(e) {
+				this.$emit("reachBottom");
+			},
+			getRpxRate() {
+				let res = uni.getWindowInfo();
+				let width = res.windowWidth;
+				let rate = 750.00 / width;
+				return rate
+			},
+			unitCheck(value) {
+				const val = String(value);
+				if (!val.includes('px') && !val.includes('%')) {
+					return `${val}rpx`;
+				}
+				return val;
+
+			},
+			preventTouch(el) {
+				el.addEventListener('touchmove', function(e) {
+					e.stopPropagation();
+
+				}, {
+					passive: false
+				});
+			},
+			setBodyOverFlow(val) {
+				document.body.style.overflow = val
+			},
+
+			//设置内容区域高度
+			async setContViewHeight() {
+				let data = await this.computeHeight();
+				this.height = data.height + (this.title ? 100 / parseFloat(this.rpxRate) : 0);
+				this.PopHeight = this.height;
+			},
+			//计算内容区域高度
+			computeHeight() {
+				return new Promise(resolve => {
+					this.$nextTick(() => {
+						const query = uni.createSelectorQuery().in(this);
+						query.select('#popup_content').boundingClientRect(data => {
+							resolve(data)
+						}).exec();
+					})
+				})
+			}
+
+		}
+
+
+	}
+</script>
+
+<style lang="scss" scoped>
+	.popup {
+
+		&.popup-show {
+			position: fixed;
+			top: 0;
+			right: 0;
+			left: 0;
+			bottom: 0;
+			overflow: hidden;
+			z-index: 999;
+		}
+
+		.mask {
+			position: fixed;
+			top: 0;
+			right: 0;
+			bottom: 0;
+			left: 0;
+			background-color: rgba($color: #000000, $alpha: 0.5);
+			z-index: 999;
+		}
+
+		.content {
+			position: fixed;
+			bottom: 0;
+			left: 0;
+			right: 0;
+			height: 0;
+			height: auto;
+			background-color: #ffffff;
+			transition: all 0.2s ease-in;
+			z-index: 1000;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			overflow: hidden;
+
+			.title-bar {
+				width: 100%;
+				flex-shrink: 0;
+				text-align: center;
+				position: relative;
+				padding: 10rpx 70rpx 0;
+				box-sizing: border-box;
+				height: 80rpx;
+
+				.title {
+					font-size: 34upx;
+					font-family: PingFang SC;
+					font-weight: bold !important;
+					color: #111111;
+					width: 100%;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
+
+				.close-wrap {
+					position: absolute;
+					top: 20rpx;
+					right: 10rpx;
+					padding: 10rpx 20rpx;
+					box-sizing: border-box;
+				}
+
+				.close-icon {
+					width: 40rpx;
+					height: 40rpx;
+				}
+			}
+
+			.scroll-wrap {
+				flex: 1;
+				height: 0;
+				width: 100%;
+			}
+
+			&.visible {
+				max-height: 75%;
+				overflow-y: hidden;
+				height: auto;
+
+			}
+		}
+	}
+
+	.scroll-view ::-webkit-scrollbar {
+		display: none !important;
+		width: 0 !important;
+		height: 0 !important;
+		-webkit-appearance: none;
+		background: transparent;
+
+	}
+
+	.popup_content {
+		width: 100%;
+		padding: 0rpx 30rpx;
+		box-sizing: border-box;
+
+		&::after {
+			display: block;
+			width: 100%;
+			content: "\00A0";
+			overflow: hidden;
+			opacity: 0;
+			height: 1rpx;
+		}
+
+	}
+</style>

+ 868 - 0
confirmOrder.vue

@@ -0,0 +1,868 @@
+<template>
+	<view>
+		<view class="inner-box">
+			<!-- 收货人 -->
+			<view class="address-box" v-if="address==null" @click="openAddress()">
+				<view class="left">
+					<view class="name-box">
+						<text class="text name">添加收货地址</text>
+					</view>
+				</view>
+				<view class="arrow-box">
+					<image src="/static/images/arrow_gray.png" mode=""></image>
+				</view>
+			</view>
+			<view class="address-box" v-if="address!=null" @click="openAddress()">
+				<view class="left">
+					<view class="name-box">
+						<text class="text name">{{address.realName}}</text>
+						<text class="text" v-if="address.phone!=null">{{utils.parsePhone(address.phone)}}</text>
+					</view>
+					<view class="address">
+						{{address.province}}{{address.city}}{{address.district}}{{address.detail}}
+					</view>
+				</view>
+				<view class="arrow-box">
+					<image src="/static/images/arrow_gray.png" mode=""></image>
+				</view>
+			</view>
+			<!-- 药品列表 -->
+			<view class="shopbox" v-for="(shop,idx) in carts" :key="idx">
+				<view class="shopbox-name" v-if="shop.storeName && shop.storeName != 'null'">
+					<text>{{shop.storeName}}</text>
+				</view>
+				<view class="goods-list">
+					<view v-for="(item,index) in shop.list" :key="index" class="item">
+						<view class="img-box">
+							<image :src="item.productAttrImage || item.productImage" mode="aspectFill"></image>
+						</view>
+						<view class="info-box">
+							<view>
+								<view class="name-box ellipsis2">
+									<view class="tag">{{utils.getDictLabelName("storeProductType",item.productType)}}</view>{{item.productName}}
+								</view>
+								<view class="spec ellipsis2">{{item.productAttrName}}</view>
+							</view>
+							<view class="price-num">
+								<view class="price">
+									<text class="unit">¥</text>
+									<text class="num">{{item.price.toFixed(2)}}</text>
+								</view>
+								<view class="num">x{{item.cartNum}}</view>
+							</view>
+						</view>
+					</view>
+					<!-- 运费 -->
+					<view class="points">
+						<view class="left">
+							<text class="text">运费</text>
+						</view>
+						<view class="right" v-if="price&&price.length > 0">
+							<text class="text">{{price[idx].payPostage==null||price[idx].payPostage==0?'免运费':price[idx].payPostage.toFixed(2)}}</text>
+						</view>
+					</view>
+					<!-- 备注 -->
+					<view class="points">
+						<view class="left">
+							<text class="text">备注</text>
+						</view>
+						<view class="remarks">
+							<input type="text" v-model="shop.markinfo" placeholder="备注留言(选填)" placeholder-class="input" />
+						</view>
+					</view>
+				</view>
+			</view>
+			<!-- 积分 -->
+			<view class="price-info">
+				<view class="price-info-title">价格明细</view>
+				<view class="points">
+					<view class="left">
+						<text class="text">商品总价</text>
+					</view>
+					<view class="right" style="align-items: baseline;">
+						<text class="price-info-unit">¥</text>
+						<text class="price-info-num">{{priceAll.totalPrice.toFixed(2)}}</text>
+					</view>
+				</view>
+				<view class="points">
+					<view class="left">
+						<image src="/static/images/points.png" mode=""></image>
+						<text class="text">可用积分</text>
+					</view>
+					<view class="right">
+						<text class="text">{{priceAll.usedIntegral}}积分</text>
+						<evan-switch @change="integralChange" v-model="checked" activeColor="#0bb3f2" inactiveColor="rgba(0, 0, 0, 0.1)"></evan-switch>
+					</view>
+				</view>
+				<view class="points" @click="openCoupon()">
+					<view class="left">
+						<text class="text">优惠券</text>
+					</view>
+					<view class="right">
+						<text class="text">{{couponText}}</text>
+						<image src="/static/images/arrow4.png" mode=""></image>
+					</view>
+				</view>
+				<view class="points">
+					<view class="left">
+						<text class="text">合计</text>
+					</view>
+					<view class="right" style="align-items: baseline;">
+						<text class="price-info-unit">¥</text>
+						<text class="price-info-num">{{priceAll.payPrice.toFixed(2)}}</text>
+					</view>
+				</view>
+			</view>
+			<!-- <view class="points">
+				<view class="left">
+					<text class="text">运费</text>
+				</view>
+				<view class="right">
+					<text class="text">{{price.payPostage==null||price.payPostage==0?'免运费':price.payPostage.toFixed(2)}}</text>
+				</view>
+			</view> -->
+			<!-- 备注 -->
+			<!-- <view class="remarks">
+				<input type="text" v-model="form.mark" placeholder="备注留言(选填)" placeholder-class="input" />
+			</view> -->
+		</view>
+		<!-- 底部按钮 -->
+		<view class="btn-foot">
+			<view class="right">
+				<view class="total">
+					<text class="label">合计:</text>
+					<view class="price">
+						<text class="unit">¥</text>
+						<text class="num">{{priceAll.payPrice.toFixed(2)}}</text>
+					</view>
+				</view>
+				<view class="btn" @click="submitOrder">提交订单</view>
+			</view>
+		</view>
+		<popupBottom ref="popup" :visible.sync="couponVisible" title=" " bgColor="#f5f5f5" radius="30"    maxHeight="60%">
+		     <view class="coupon" style="height:650rpx;">
+				 <div class="coupon-list" v-if="couponsList.length > 0">
+				   <div class="item acea-row row-center-wrapper"  v-for="(item, index) in couponsList" :key="index">
+				     <div class="money" >
+				       <image v-if="item.status==0" class="img" src="/static/images/coupon1.png" mode="widthFix"></image>
+				 	  <image v-if="item.status!=0" class="img" src="/static/images/coupon2.png" mode="widthFix"></image>
+				 	  <div style="z-index: 999;">
+				         ¥<span class="num">{{ item.couponPrice }}</span>
+				       </div>
+				       <div class="pic-num"  >满{{ item.useMinPrice }}元可用</div>
+				     </div>
+				     <div class="text">
+				       <div class="condition line1">
+				         {{ item.couponTitle }}
+				       </div>
+				       <div class="data acea-row row-between-wrapper">
+							<div >{{ item.limitTime }}到期</div>
+							<div class="bnt bg-color-red" @click="couponSelect(item)"  >选择</div>
+				       </div>
+				     </div>
+				   </div>
+				 </div>
+				 <view v-if="couponsList.length == 0" class="no-data-box" >
+				 	<image src="/static/images/no_data.png" mode="aspectFit"></image>
+				 	<view class="empty-title">暂无数据</view>
+				 </view>
+			 </view>
+			 
+		</popupBottom>
+	</view>
+</template>
+
+<script>
+	// import {getWeixinOrderTemps} from '@/api/common'
+	
+	// import {confirm,computed,create} from '@/api/storeOrder'
+	// import { getMyEnableCouponList } from '@/api/coupon'
+	 
+	import EvanSwitch from '@/components/evan-switch/evan-switch.vue'
+	import popupBottom from '@/components/px-popup-bottom/px-popup-bottom.vue'
+	
+	export default {
+		components: {
+			EvanSwitch,
+			popupBottom
+		},
+		data() {
+			return {
+				temps:[],
+				couponUserId:null,
+				couponText:"请选择",
+				couponsList:[],
+				couponVisible:false,
+				price: [],
+				priceAll:{
+					payPrice:0,
+					totalPostage:0,
+					usedIntegral:0,
+					totalPrice:0.00,
+				},
+				address:null,
+				carts:[],
+				checked: false,
+				type:null,
+				cartIds:null,
+				storeId:null,
+				form:{
+					useIntegral:0,
+					orderKey:null,
+					addressId:null,
+					mark:null,
+					companyId:null,
+					companyUserId:null
+				},
+				confirmParam: []
+			}
+		},
+		onLoad(option) {
+			this.form.companyId=option.companyId;
+			this.form.companyUserId=option.companyUserId;
+			// this.cartIds=option.cartIds;
+			this.type=option.type;
+			this.storeId=option.storeId;
+			this.confirmParam = JSON.parse(decodeURIComponent(option.confirmParam))
+			this.confirm();
+			uni.$on('updateAddress', (e) => {
+				this.address=e;
+				this.form.addressId=e.id;
+			})
+			this.getWeixinOrderTemps();
+		},
+		methods: {
+			getWeixinOrderTemps:function(){
+				getWeixinOrderTemps().then(
+					res => {
+						if(res.code==200){
+							this.temps=res.temp
+						}else{
+							 
+						}
+					},
+					rej => {}
+				);
+			},
+			couponSelect(item){
+				this.couponText="-¥"+item.couponPrice.toFixed(2);
+				this.couponUserId=item.id;
+				this.couponVisible=false;
+				this.computed();
+			},
+			openCoupon(){
+				let that = this;
+				var data={couponType:0,useMinPrice:this.price.payPrice};
+				getMyEnableCouponList(data).then(res => {
+				  this.couponVisible=true;
+				  that.couponsList = res.data
+				})
+			},
+			integralChange(e){
+				this.form.useIntegral=e?1:0
+				this.computed()
+			},
+			confirm(item){
+				// let data = {type:this.type,cartIds:this.cartIds};
+				if(this.confirmParam && this.confirmParam.length > 0) {
+					confirm(this.confirmParam).then(
+						res => {
+							if(res.code==200){
+								 
+								 this.carts=res.carts.map(item=>({
+									 ...item,
+									 markinfo: ""
+								 }));
+								 this.form.orderKey=res.orderKeys;
+								 if(res.address!=null){
+									 this.form.addressId=res.address.id;
+									 this.address=res.address;
+								 }
+								 this.computed()
+							}else{
+								
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+							}
+						},
+						rej => {}
+					);
+				} else {
+					uni.showToast({
+						icon: 'none',
+						title:'订单参数不存在~',
+					});
+				}
+			},
+			computed(item){
+				let data = {
+					couponUserId:this.couponUserId,
+					orderKeys:this.form.orderKey,
+					addressId:this.form.addressId,
+					useIntegral:this.form.useIntegral,
+				};
+				computed(data).then(
+					res => {
+						if(res.code==200){
+							 this.price= res.data && res.data.length > 0 ? res.data : []
+							 this.priceAll = res.data && res.data.length > 0 ? res.data[res.data.length -1] : {
+								 payPrice:0,
+								 totalPostage:0,
+								 usedIntegral:0,
+								 totalPrice:0.00,
+							 }
+						}else{
+							if(res.code==501){
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+								setTimeout(function(){
+									uni.navigateBack({
+										delta:1
+									})
+								},500);
+								return;
+							}
+							else{
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+							}
+							
+						}
+					},
+					rej => {}
+				);
+			},
+			// 提交订单
+			submitOrder() {
+				var that=this;
+				if(this.form.orderKey==null || this.form.orderKey.length == 0){
+					uni.showToast({
+						icon:'none',
+						title: '订单KEY不存在',
+					});
+					return;
+				}
+				if(this.form.addressId==null){
+					uni.showToast({
+						icon:'none',
+						title: '收货地址不能为空',
+					});
+					return;
+				}
+				
+				uni.requestSubscribeMessage({
+					tmplIds: this.temps,
+					success(res) {
+						 that.createOrder();
+					},
+					fail(res) {
+						that.createOrder();
+					}
+				})
+				
+			},
+			createOrder(){
+				const mark = this.carts.map(item => item.markinfo)
+				var that=this;
+				var data=null;
+				var tuiUserId=uni.getStorageSync('tuiUserId');
+				uni.showLoading({
+					title: '正在处理中...'
+				});
+				if(tuiUserId!=null&&tuiUserId!=undefined&&tuiUserId>0){
+					data = {orderCreateType:1,tuiUserId:tuiUserId,companyId:this.form.companyId,companyUserId:this.form.companyUserId,couponUserId:this.couponUserId,mark:mark,orderKeys:this.form.orderKey,addressId:this.form.addressId,useIntegral:this.form.useIntegral,payType:1};
+				}
+				else{
+					data = {orderCreateType:1,companyId:this.form.companyId,companyUserId:this.form.companyUserId,couponUserId:this.couponUserId,mark:mark,orderKeys:this.form.orderKey,addressId:this.form.addressId,useIntegral:this.form.useIntegral,payType:1};
+				}
+				if(this.storeId!=null&& this.storeId>0){
+					data.storeId=this.storeId;
+				}
+				create(data).then(
+					res => {
+						uni.hideLoading()
+						if(!res.code && res.code !== 0){
+							uni.hideLoading()
+							
+							if(res.some(item=> item.order.isPrescribe) == 1) {
+								setTimeout(function(){
+									let orderIds = res.filter(item=> item.order.isPrescribe == 1).map(it=>it.order.id)
+									orderIds = orderIds.join(',')
+									uni.redirectTo({
+										url:"prescribe?orderId="+orderIds+"&combinationOrderId="+encodeURIComponent(res[0].order.combinationOrderId)
+									})
+								},200);
+							} else {
+								setTimeout(function(){
+									uni.redirectTo({
+										url: './paymentOrder?combinationOrderId='+encodeURIComponent(res[0].order.combinationOrderId)
+									})
+								},200);
+							}
+							return;
+						} else{
+							if(res.code==501){
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+								setTimeout(function(){
+									uni.navigateBack({
+										delta:1
+									})
+								},200);
+								return;
+							}
+							else{
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+							}
+						}
+					},
+					rej => {}
+				);
+			},
+			openAddress(){
+				uni.navigateTo({
+					url: '/pages_user/user/address'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.inner-box{
+		padding: 20upx 20upx 140upx;
+		.address-box{
+			box-sizing: border-box;
+			min-height: 171upx;
+			margin-bottom: 20rpx;
+			background: #FFFFFF;
+			border-radius: 16upx;
+			background-image: url(../../static/images/address_bg.png);
+			background-repeat: no-repeat;
+			background-size: 100% 30upx;
+			background-position: left bottom;
+			padding: 38upx 30upx 36upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.left{
+				width: 92%;
+				.name-box{
+					display: flex;
+					align-items: center;
+					.text{
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #111111;
+						line-height: 1;
+						&.name{
+							margin-right: 30upx;
+						}
+					}
+				}
+				.address{
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #666666;
+					line-height: 42upx;
+					text-align:left;
+					margin-top: 23upx;
+				}
+			}
+			.arrow-box{
+				width: 12upx;
+				height: 23upx;
+				display: flex;
+				align-items: cenetr;
+				justify-content: cenetr;
+				image{
+					width: 100%;
+					height: 100%;
+				}
+			}
+		}
+		.shopbox {
+			background: #FFFFFF;
+			border-radius: 16rpx;
+			margin-bottom: 20rpx;
+			.points {
+				padding: 0 !important;
+			}
+			.remarks {
+				padding: 0 !important;
+			}
+		}
+		.shopbox-name {
+			padding: 30rpx 30rpx 0 30rpx;
+			font-family: PingFang SC, PingFang SC;
+			font-weight: 400;
+			font-size: 30rpx;
+			color: #111;
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+		}
+		.goods-list{
+			// margin-top: 20upx;
+			padding: 0 30upx;
+			background-color: #FFFFFF;
+			border-radius: 16upx;
+			.item{
+				padding: 30upx 0;
+				border-bottom: 1px solid #EDEEEF;
+				display: flex;
+				align-items: center;
+				.img-box{
+					width: 160upx;
+					height: 160upx;
+					margin-right: 30upx;
+					image{
+						width: 100%;
+						height: 100%;
+					}
+				}
+				.info-box{
+					width: calc(100% - 190upx);
+					height: 160upx;
+					display: flex;
+					flex-direction: column;
+					justify-content: space-between;
+					.name-box{
+						font-size: 28upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #111111;
+						line-height: 40upx;
+						.tag{
+							display: inline-block;
+							padding: 0 6upx;
+							height: 30upx;
+							background: linear-gradient(90deg, #66b2ef 0%, #0bb3f2 100%);
+							border-radius: 4upx;
+							margin-right: 10upx;
+							font-size: 22upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #FFFFFF;
+							line-height: 30upx;
+							float: left;
+							margin-top: 7upx;
+						}
+					}
+					.spec{
+						margin-top: 10upx;
+						font-size: 24upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #999999;
+						line-height: 1;
+					}
+					.price-num{
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+						.price{
+							display: flex;
+							align-items: flex-end;
+							.unit{
+								font-size: 24upx;
+								font-family: PingFang SC;
+								font-weight: 500;
+								color: #111111;
+								line-height: 1.2;
+								margin-right: 4upx;
+							}
+							.num{
+								font-size: 32upx;
+								font-family: PingFang SC;
+								font-weight: 500;
+								color: #111111;
+								line-height: 1;
+							}
+						}
+						.num{
+							font-size: 24upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #999999;
+							line-height: 1;
+						}
+					}
+				}
+			}
+			.sub-total{
+				height: 88upx;
+				display: flex;
+				align-items: center;
+				justify-content: flex-end;
+				.label{
+					font-size: 24upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+				}
+				.price{
+					display: flex;
+					align-items: flex-end;
+					.unit{
+						font-size: 24upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #FF6633;
+						line-height: 1.2;
+						margin-right: 4upx;
+					}
+					.num{
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+			}
+		}
+		.price-info {
+			background: #FFFFFF;
+			border-radius: 16upx;
+			&-title {
+				    padding: 30rpx 30rpx 20rpx 30rpx;
+				    font-family: PingFang SC, PingFang SC;
+				    font-weight: 500;
+				    font-size: 30rpx;
+				    color: #111;
+			}
+			&-unit {
+				font-size: 24rpx;
+			}
+			&-num {
+				font-size: 28rpx;
+			}
+		}
+		.points{
+			height: 88upx;
+			width: 100%;
+			padding: 0 30upx;
+			box-sizing: border-box;
+			background: #FFFFFF;
+			border-radius: 16upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.left{
+				display: flex;
+				align-items: center;
+				image{
+					width: 28upx;
+					height: 28upx;
+					margin-right: 20upx;
+				}
+				.text{
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #666666;
+				}
+			}
+			.right{
+				display: flex;
+				align-items: center;
+				.text{
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #111111;
+					 
+				}
+				image{
+					margin-left: 15upx;
+					width: 14upx;
+					height: 24upx;
+				}
+			}
+		}
+		.remarks{
+			height: 88upx;
+			padding: 0 30upx;
+			background: #FFFFFF;
+			border-radius: 16upx;
+			display: flex;
+			align-items: center;
+			input{
+				width: 100%;
+				font-size: 28upx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #000000;
+			}
+			.input{
+				font-size: 28upx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #999999;
+			}
+		}
+	}
+	
+	
+	.btn-foot{
+		box-sizing: border-box;
+		width: 100%;
+		height: 121upx;
+		background: #FFFFFF;
+		padding: 16upx 30upx 16upx 60upx;
+		display: flex;
+		align-items: center;
+		justify-content: flex-end;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		z-index: 99;
+		.right{
+			display: flex;
+			align-items: center;
+			.total{
+				display: flex;
+				align-items: flex-end;
+				margin-right: 36upx;
+				.label{
+					font-size: 26upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+					line-height: 1.5;
+				}
+				.price{
+					display: flex;
+					align-items: flex-end;
+					.unit{
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1.2;
+						margin-right: 10upx;
+					}
+					.num{
+						font-size: 50upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+			}
+			.btn{
+				width: 200upx;
+				height: 88upx;
+				line-height: 88upx;
+				text-align: center;
+				font-size: 30upx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				background: #0bb3f2;
+				border-radius: 44upx;
+			}
+		}
+	}
+</style>
+<style lang="less" scoped>
+	.coupon {
+	  height: 100%;
+	}
+	/*优惠券列表公共*/
+	.coupon-list {
+	}
+	.coupon-list .item {
+	  display: flex;
+	  flex-direction: column;
+	  justify-content: center;
+	  align-items: center;
+	  width: 100%;
+	  height: 1.7 * 100rpx;
+	  margin-bottom: 0.16 * 100rpx;
+	}
+	
+	.coupon-list .item .money {
+	  background-size: 100% 100%;
+	  width: 2.4 * 100rpx;
+	  height: 100%;
+	  color: #fff;
+	  font-size: 0.36 * 100rpx;
+	  font-weight: bold;
+	  text-align: center;
+	  display: flex;
+	  flex-direction: column;
+	  align-items: center;
+	  justify-content: center;
+	  position: relative;
+	  
+	}
+	.coupon-list .item .money .img{
+	  position: absolute;
+	  width: 2.4 * 100rpx;
+	  height: 100%;
+	  color: #fff;
+	  
+	}
+	
+	.coupon-list .item .money .num {
+	  font-size: 0.6 * 100rpx;
+	}
+	.coupon-list .item .money .pic-num {
+	  font-size: 20rpx;
+	  z-index: 99;
+	}
+
+	
+	.coupon-list .item .text {
+	  width: 4.5 * 100rpx;
+	  padding: 0 0.17 * 100rpx 0 0.24 * 100rpx;
+	  background-color: #fff;
+	  box-sizing: border-box;
+	}
+	
+	.coupon-list .item .text .condition {
+	  font-size: 0.3 * 100rpx;
+	  color: #282828;
+	  height: 0.93 * 100rpx;
+	  line-height: 0.93 * 100rpx;
+	  border-bottom: 1px solid #f0f0f0;
+	}
+	
+	.coupon-list .item .text .data {
+	  font-size: 0.2 * 100rpx;
+	  color: #999;
+	  height: 0.76 * 100rpx;
+	}
+	
+	.coupon-list .item .text .data .bnt {
+	  width: 1.36 * 100rpx;
+	  height: 0.44 * 100rpx;
+	  border-radius: 0.22 * 100rpx;
+	  font-size: 0.22 * 100rpx;
+	  color: #fff;
+	  text-align: center;
+	  line-height: 0.44 * 100rpx;
+	  background-color: red;
+	}
+	
+	.coupon-list .item .text .data .bnt.gray {
+	  background-color: #ccc;
+	}
+</style>
+

+ 3 - 1
core/config/defaultConfig.js

@@ -14,7 +14,9 @@ const productionUrl = 'https://wanbei.monvkeji.cn/'
 // 测试环境
 const testUrl = 'https://wanbei.monvkeji.cn/'
 // 开发环境
-const developUrl = 'http://192.168.10.166:7114/'//余红奇
+// const developUrl = 'http://192.168.10.166:7114/'//余红奇
+// const developUrl = 'http://v56c9b8e.natappfree.cc/'//余红奇
+const developUrl = 'http://nd383294.natappfree.cc/'//余红奇
 // const developUrl = 'http://192.168.10.170:7114/'//陈果
 export default {
 	// 系统名称

+ 38 - 15
main.js

@@ -4,7 +4,7 @@ import store from '@/store/index.js'
 // uviewPlus导入
 import uviewPlus from '@/uni_modules/uview-plus'
 import bootstrap from './core/bootstrap'
-
+import {isLogin,isEmpty,navTo,getRegistrationID,parsePhone} from '@/utils/util.js'
 // 全局 mixin
 import share from './core/mixins/share.js'
 import mixin from './core/mixins/app'
@@ -13,29 +13,52 @@ import mixin from './core/mixins/app'
 import Vue from 'vue'
 import './uni.promisify.adaptor'
 Vue.config.productionTip = false
+Vue.prototype.$img = {
+  img: '/static/images/img.png', // 默认图片
+  logo: '/static/images/logo.png', // 其他公共图片
+}
+Vue.prototype.$isLogin = isLogin;
+Vue.prototype.$isEmpty = isEmpty;
+Vue.prototype.$navTo = navTo;
+Vue.prototype.$getRegistrationID = getRegistrationID;
+Vue.prototype.$parsePhone = parsePhone;
+
+
 App.mpType = 'app'
 
 const app = new Vue({
-	...App
+  ...App
 })
 app.$mount()
 // #endif
 
 // #ifdef VUE3
-import {
-	createSSRApp
-} from 'vue'
+import { createSSRApp } from 'vue'
 
 export function createApp() {
-	const app = createSSRApp(App)
-	// 注册组件库和vuex
-	app.use(uviewPlus).use(store)
-	app.config.productionTip = false
-	//全局mixin
-	app.mixin(share).mixin(mixin)
-	return {
-		app,
-		created: bootstrap
-	}
+  const app = createSSRApp(App)
+  
+  // 注册组件库和vuex
+  app.use(uviewPlus).use(store)
+  app.config.productionTip = false
+  
+  // 定义全局变量 $img(Vue3 方式)
+  app.config.globalProperties.$img = {
+    img: '/static/images/img.png', // 默认图片
+    logo: '/static/images/logo.png', // 其他公共图片
+  }
+ app.config.globalProperties.$isLogin = isLogin
+ app.config.globalProperties.$isEmpty = isEmpty
+ app.config.globalProperties.$navTo = navTo
+ app.config.globalProperties.$getRegistrationID = getRegistrationID
+ app.config.globalProperties.$parsePhone = parsePhone
+ 
+  // 全局 mixin
+  app.mixin(share).mixin(mixin)
+  
+  return {
+    app,
+    created: bootstrap
+  }
 }
 // #endif

+ 6 - 6
node_modules/.vite/deps/_metadata.json

@@ -1,23 +1,23 @@
 {
-  "hash": "98bf4fc2",
-  "browserHash": "f716e2a6",
+  "hash": "6c905d26",
+  "browserHash": "a9804764",
   "optimized": {
     "hls.js": {
       "src": "../../hls.js/dist/hls.mjs",
       "file": "hls_js.js",
-      "fileHash": "bde2a7e6",
+      "fileHash": "e3f6f66f",
       "needsInterop": false
     },
     "crypto-js": {
       "src": "../../crypto-js/index.js",
       "file": "crypto-js.js",
-      "fileHash": "be885d35",
+      "fileHash": "4dc3d918",
       "needsInterop": true
     }
   },
   "chunks": {
-    "chunk-ON7YJ3LY": {
-      "file": "chunk-ON7YJ3LY.js"
+    "chunk-BEIQYKVI": {
+      "file": "chunk-BEIQYKVI.js"
     }
   }
 }

+ 1 - 1
node_modules/.vite/deps/chunk-ON7YJ3LY.js → node_modules/.vite/deps/chunk-BEIQYKVI.js

@@ -43,4 +43,4 @@ export {
   __toCommonJS,
   init_define_process_env_UNI_STAT_TITLE_JSON
 };
-//# sourceMappingURL=chunk-ON7YJ3LY.js.map
+//# sourceMappingURL=chunk-BEIQYKVI.js.map

+ 0 - 0
node_modules/.vite/deps/chunk-ON7YJ3LY.js.map → node_modules/.vite/deps/chunk-BEIQYKVI.js.map


+ 1 - 1
node_modules/.vite/deps/crypto-js.js

@@ -5,7 +5,7 @@ import {
   __require,
   __toCommonJS,
   init_define_process_env_UNI_STAT_TITLE_JSON
-} from "./chunk-ON7YJ3LY.js";
+} from "./chunk-BEIQYKVI.js";
 
 // browser-external:crypto
 var crypto_exports = {};

+ 1 - 1
node_modules/.vite/deps/hls_js.js

@@ -1,6 +1,6 @@
 import {
   init_define_process_env_UNI_STAT_TITLE_JSON
-} from "./chunk-ON7YJ3LY.js";
+} from "./chunk-BEIQYKVI.js";
 
 // dep:hls_js
 init_define_process_env_UNI_STAT_TITLE_JSON();

+ 28 - 0
node_modules/dayjs/CHANGELOG.md

@@ -1,3 +1,31 @@
+## [1.11.13](https://github.com/iamkun/dayjs/compare/v1.11.12...v1.11.13) (2024-08-20)
+
+
+### Bug Fixes
+
+* customParseFormat supports Q quter / w ww weekOfYear ([#2705](https://github.com/iamkun/dayjs/issues/2705)) ([8ca74f1](https://github.com/iamkun/dayjs/commit/8ca74f178eff4bb4eb686676cf35fe7edb815536))
+
+## [1.11.12](https://github.com/iamkun/dayjs/compare/v1.11.11...v1.11.12) (2024-07-18)
+
+
+### Bug Fixes
+
+* Add NegativeYear Plugin support  ([#2640](https://github.com/iamkun/dayjs/issues/2640)) ([6a42e0d](https://github.com/iamkun/dayjs/commit/6a42e0d7398639238f575d51287daaf4d495a2a3))
+* add UTC support to negativeYear plugin ([#2692](https://github.com/iamkun/dayjs/issues/2692)) ([f3ef705](https://github.com/iamkun/dayjs/commit/f3ef705613af83333fe132b470896a65e12f31b0))
+* Fix zero offset issue when use tz with locale ([#2532](https://github.com/iamkun/dayjs/issues/2532)) ([d0e6738](https://github.com/iamkun/dayjs/commit/d0e6738a66e1b65d3706aad2f9168ebb43d4f887))
+* Improve typing for min/max plugin ([#2573](https://github.com/iamkun/dayjs/issues/2573)) ([4fbe94a](https://github.com/iamkun/dayjs/commit/4fbe94aaba8c815a42cf4d23dabac918ec50e68c))
+* timezone plugin correct parse UTC tz ([#2693](https://github.com/iamkun/dayjs/issues/2693)) ([b575c81](https://github.com/iamkun/dayjs/commit/b575c81a8c9c85c7a0baf6f608a12f9d3ba95bd1))
+
+## [1.11.11](https://github.com/iamkun/dayjs/compare/v1.11.10...v1.11.11) (2024-04-28)
+
+
+### Bug Fixes
+
+* day of week type literal ([#2630](https://github.com/iamkun/dayjs/issues/2630)) ([f68d73e](https://github.com/iamkun/dayjs/commit/f68d73efe562fdedd9e288ecb0ce6565e602f507))
+* improve locale "zh-hk" format and meridiem ([#2419](https://github.com/iamkun/dayjs/issues/2419)) ([a947a51](https://github.com/iamkun/dayjs/commit/a947a5171aad5695eaf593bc95fe073de0f0894a))
+* Update 'da' locale to match correct first week of year ([#2592](https://github.com/iamkun/dayjs/issues/2592)) ([44b0936](https://github.com/iamkun/dayjs/commit/44b0936ad709212b63e48672d8b9c225e2c3b830))
+* update locale Bulgarian monthsShort Jan ([#2538](https://github.com/iamkun/dayjs/issues/2538)) ([f0c9a41](https://github.com/iamkun/dayjs/commit/f0c9a41c6ec91528f3790e442b0c5dff15a4e640))
+
 ## [1.11.10](https://github.com/iamkun/dayjs/compare/v1.11.9...v1.11.10) (2023-09-19)
 
 

+ 34 - 11
node_modules/dayjs/README.md

@@ -5,13 +5,13 @@ English | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/R
                                                                              alt="Day.js" /></a></p>
 <p align="center">Fast <b>2kB</b> alternative to Moment.js with the same modern API</p>
 <p align="center">
-    <a href="https://unpkg.com/dayjs/dayjs.min.js"><img
-            src="https://img.badgesize.io/https://unpkg.com/dayjs/dayjs.min.js?compression=gzip&style=flat-square"
+    <a href="https://bundlephobia.com/package/dayjs"><img
+            src="https://img.shields.io/bundlephobia/minzip/dayjs?style=flat-square&color=%2345cc11"
             alt="Gzip Size"></a>
     <a href="https://www.npmjs.com/package/dayjs"><img src="https://img.shields.io/npm/v/dayjs.svg?style=flat-square&colorB=51C838"
                                                        alt="NPM Version"></a>
-    <a href="https://travis-ci.com/iamkun/dayjs"><img
-            src="https://img.shields.io/travis/iamkun/dayjs/master.svg?style=flat-square" alt="Build Status"></a>
+    <a href="https://github.com/iamkun/dayjs/actions/workflows/check.yml"><img
+            src="https://img.shields.io/github/actions/workflow/status/iamkun/dayjs/check.yml?style=flat-square" alt="Build Status"></a>
     <a href="https://codecov.io/gh/iamkun/dayjs"><img
             src="https://img.shields.io/codecov/c/github/iamkun/dayjs/master.svg?style=flat-square" alt="Codecov"></a>
     <a href="https://github.com/iamkun/dayjs/blob/master/LICENSE"><img
@@ -99,6 +99,12 @@ dayjs().format('Q Do k kk X x') // more available formats
 
 📚[Plugin List](https://day.js.org/docs/en/plugin/plugin)
 
+### Usage Trend
+
+<a href="https://npm-compare.com/moment,dayjs/#timeRange=THREE_YEARS" target="_blank">
+  <img src="https://user-images.githubusercontent.com/3455798/270162667-c7bd2ebe-675e-45c6-a2c9-dc67f3b65d6e.png">
+</a>
+
 ## Sponsors
 
 Support this project by becoming a sponsor. Your logo will show up here with a link to your website.
@@ -109,25 +115,42 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
   <img width="70" src="https://user-images.githubusercontent.com/17680888/197092231-2367b5eb-1e43-467e-a311-23f7cd97b086.png">
 </a>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-<a href="https://github.com/alan-eu" target="_blank">
-  <img width="70" src="https://avatars.githubusercontent.com/u/18175329?s=52&v=4">
+<a href="https://github.com/ken-swyfft" target="_blank">
+  <img width="70" src="https://avatars.githubusercontent.com/u/65305317?v=4">
 </a>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 <a href="https://opencollective.com/sight-and-sound-ministries" target="_blank">
   <img width="70" src="https://user-images.githubusercontent.com/17680888/232316426-cb99b4cf-0ccb-4e73-a6ce-e16dba6aadf4.png">
 </a>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+<a href="https://chudovo.com/" target="_blank">
+  <img width="70" src="https://images.opencollective.com/chudovo/3c866f5/logo/256.png?height=256">
+</a>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+<a href="https://www.honrev.com" target="_blank">
+  <img width="70" src="https://github.com/user-attachments/assets/b3203350-34c1-4637-b8b1-d9b8bab346d3">
+</a>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+<a href="https://github.com/alan-eu" target="_blank">
+  <img width="70" src="https://avatars.githubusercontent.com/u/18175329?s=52&v=4">
+</a>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 <a href="https://www.exoflare.com/open-source/?utm_source=dayjs&utm_campaign=open_source" target="_blank">
   <img width="70" src="https://user-images.githubusercontent.com/17680888/162761622-1407a849-0c41-4591-8aa9-f98114ec2092.png">
 </a>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-<a href="https://rxdb.info/?utm_source=day.js.org&utm_medium=banner&utm_campaign=day.js.org-sponsored" target="_blank"><img width="70" src="https://user-images.githubusercontent.com/17680888/200301812-9c9bd523-5dc4-4cab-b380-543fbcd3802c.svg"></a>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-<a href="https://github.com/vendure-ecommerce" target="_blank"><img width="70" src="https://avatars.githubusercontent.com/u/39629390?s=52&v=4"></a>
+<a href="https://github.com/storyblok" target="_blank">
+  <img width="70" src="https://avatars.githubusercontent.com/u/13880908?s=200&v=4">
+</a>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-<a href="https://opencollective.com/docbot" target="_blank"><img width="70" src="https://images.opencollective.com/docbot/457761e/logo.png"></a>
+<a href="https://bestkru.com/" target="_blank">
+  <img width="70" src="https://avatars.githubusercontent.com/u/159320286" alt="BestKru">
+</a>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-<a href="https://opencollective.com/datawrapper" target="_blank"><img width="70" src="https://images.opencollective.com/datawrapper/c13e229/logo.png"></a>
+<a href="https://route4me.com/" target="_blank">
+  <img width="70" src="https://github.com/user-attachments/assets/3fbc86c5-98a9-49c2-beae-1969026fcd76" alt="Route Optimizer and Route Planner Software">
+</a>
+
 
 ## Contributors
 

+ 1 - 1
node_modules/dayjs/esm/index.d.ts

@@ -114,7 +114,7 @@ declare namespace dayjs {
      * ```
      * Docs: https://day.js.org/docs/en/get-set/day
      */
-    day(): number
+    day(): 0 | 1 | 2 | 3 | 4 | 5 | 6
     /**
      * Set the day of the week.
      *

+ 1 - 1
node_modules/dayjs/esm/locale/bg.js

@@ -6,7 +6,7 @@ var locale = {
   weekdaysShort: 'нед_пон_вто_сря_чет_пет_съб'.split('_'),
   weekdaysMin: 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
   months: 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'),
-  monthsShort: 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),
+  monthsShort: 'яну_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),
   weekStart: 1,
   ordinal: function ordinal(n) {
     var last2Digits = n % 100;

+ 1 - 0
node_modules/dayjs/esm/locale/da.js

@@ -8,6 +8,7 @@ var locale = {
   months: 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),
   monthsShort: 'jan._feb._mar._apr._maj_juni_juli_aug._sept._okt._nov._dec.'.split('_'),
   weekStart: 1,
+  yearStart: 4,
   ordinal: function ordinal(n) {
     return n + ".";
   },

+ 22 - 1
node_modules/dayjs/esm/locale/zh-hk.js

@@ -22,7 +22,11 @@ var locale = {
     L: 'YYYY/MM/DD',
     LL: 'YYYY年M月D日',
     LLL: 'YYYY年M月D日 HH:mm',
-    LLLL: 'YYYY年M月D日dddd HH:mm'
+    LLLL: 'YYYY年M月D日dddd HH:mm',
+    l: 'YYYY/M/D',
+    ll: 'YYYY年M月D日',
+    lll: 'YYYY年M月D日 HH:mm',
+    llll: 'YYYY年M月D日dddd HH:mm'
   },
   relativeTime: {
     future: '%s內',
@@ -38,6 +42,23 @@ var locale = {
     MM: '%d 個月',
     y: '一年',
     yy: '%d 年'
+  },
+  meridiem: function meridiem(hour, minute) {
+    var hm = hour * 100 + minute;
+
+    if (hm < 600) {
+      return '凌晨';
+    } else if (hm < 900) {
+      return '早上';
+    } else if (hm < 1100) {
+      return '上午';
+    } else if (hm < 1300) {
+      return '中午';
+    } else if (hm < 1800) {
+      return '下午';
+    }
+
+    return '晚上';
   }
 };
 dayjs.locale(locale, null, true);

+ 18 - 5
node_modules/dayjs/esm/plugin/customParseFormat/index.js

@@ -1,5 +1,5 @@
 import { u } from '../localizedFormat/utils';
-var formattingTokens = /(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|YYYY|YY?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g;
+var formattingTokens = /(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|Q|YYYY|YY?|ww?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g;
 var match1 = /\d/; // 0 - 9
 
 var match2 = /\d\d/; // 00 - 99
@@ -74,6 +74,9 @@ var expressions = {
   a: [matchWord, function (input) {
     this.afternoon = meridiemMatch(input, true);
   }],
+  Q: [match1, function (input) {
+    this.month = (input - 1) * 3 + 1;
+  }],
   S: [match1, function (input) {
     this.milliseconds = +input * 100;
   }],
@@ -108,6 +111,8 @@ var expressions = {
       }
     }
   }],
+  w: [match1to2, addInput('week')],
+  ww: [match2, addInput('week')],
   M: [match1to2, addInput('month')],
   MM: [match2, addInput('month')],
   MMM: [matchWord, function (input) {
@@ -209,7 +214,7 @@ function makeParser(format) {
   };
 }
 
-var parseFormattedInput = function parseFormattedInput(input, format, utc) {
+var parseFormattedInput = function parseFormattedInput(input, format, utc, dayjs) {
   try {
     if (['x', 'X'].indexOf(format) > -1) return new Date((format === 'X' ? 1000 : 1) * input);
     var parser = makeParser(format);
@@ -222,7 +227,8 @@ var parseFormattedInput = function parseFormattedInput(input, format, utc) {
         minutes = _parser2.minutes,
         seconds = _parser2.seconds,
         milliseconds = _parser2.milliseconds,
-        zone = _parser2.zone;
+        zone = _parser2.zone,
+        week = _parser2.week;
 
     var now = new Date();
     var d = day || (!year && !month ? now.getDate() : 1);
@@ -246,7 +252,14 @@ var parseFormattedInput = function parseFormattedInput(input, format, utc) {
       return new Date(Date.UTC(y, M, d, h, m, s, ms));
     }
 
-    return new Date(y, M, d, h, m, s, ms);
+    var newDate;
+    newDate = new Date(y, M, d, h, m, s, ms);
+
+    if (week) {
+      newDate = dayjs(newDate).week(week).toDate();
+    }
+
+    return newDate;
   } catch (e) {
     return new Date(''); // Invalid Date
   }
@@ -285,7 +298,7 @@ export default (function (o, C, d) {
         locale = d.Ls[pl];
       }
 
-      this.$d = parseFormattedInput(date, format, utc);
+      this.$d = parseFormattedInput(date, format, utc, d);
       this.init();
       if (pl && pl !== true) this.$L = this.locale(pl).$L; // use != to treat
       // input number 1410715640579 and format string '1410715640579' equal

+ 15 - 4
node_modules/dayjs/esm/plugin/minMax/index.d.ts

@@ -4,8 +4,19 @@ declare const plugin: PluginFunc
 export = plugin
 
 declare module 'dayjs/esm' {
-  export function max(dayjs: Dayjs[]): Dayjs | null
-  export function max(...dayjs: Dayjs[]): Dayjs | null
-  export function min(dayjs: Dayjs[]): Dayjs | null
-  export function min(...dayjs: Dayjs[]): Dayjs | null
+  export function max(dayjs: [Dayjs, ...Dayjs[]]): Dayjs
+  export function max(noDates: never[]): null
+  export function max(maybeDates: Dayjs[]): Dayjs | null
+
+  export function max(...dayjs: [Dayjs, ...Dayjs[]]): Dayjs
+  export function max(...noDates: never[]): null
+  export function max(...maybeDates: Dayjs[]): Dayjs | null
+
+  export function min(dayjs: [Dayjs, ...Dayjs[]]): Dayjs
+  export function min(noDates: never[]): null
+  export function min(maybeDates: Dayjs[]): Dayjs | null
+
+  export function min(...dayjs: [Dayjs, ...Dayjs[]]): Dayjs
+  export function min(...noDates: never[]): null
+  export function min(...maybeDates: Dayjs[]): Dayjs | null
 }

+ 4 - 0
node_modules/dayjs/esm/plugin/negativeYear/index.d.ts

@@ -0,0 +1,4 @@
+import {PluginFunc} from 'dayjs/esm'
+
+declare const plugin: PluginFunc
+export = plugin

+ 36 - 0
node_modules/dayjs/esm/plugin/negativeYear/index.js

@@ -0,0 +1,36 @@
+export default (function (_, c, dayjs) {
+  var proto = c.prototype;
+
+  var parseDate = function parseDate(cfg) {
+    var date = cfg.date,
+        utc = cfg.utc;
+
+    if (typeof date === 'string' && date.charAt(0) === '-') {
+      var normalData = date.slice(1);
+      var newDate = dayjs(normalData);
+
+      if (utc) {
+        newDate = dayjs.utc(normalData);
+      } else {
+        newDate = dayjs(normalData);
+      }
+
+      var fullYear = newDate.year();
+
+      if (date.indexOf("-" + fullYear) !== -1) {
+        return dayjs(newDate).subtract(fullYear * 2, 'year').toDate();
+      }
+
+      return date;
+    }
+
+    return date;
+  };
+
+  var oldParse = proto.parse;
+
+  proto.parse = function (cfg) {
+    cfg.date = parseDate.bind(this)(cfg);
+    oldParse.bind(this)(cfg);
+  };
+});

+ 16 - 7
node_modules/dayjs/esm/plugin/timezone/index.js

@@ -120,13 +120,22 @@ export default (function (o, c, d) {
       timeZone: timezone
     });
     var diff = Math.round((date - new Date(target)) / 1000 / 60);
-    var ins = d(target, {
-      locale: this.$L
-    }).$set(MS, this.$ms).utcOffset(-Math.round(date.getTimezoneOffset() / 15) * 15 - diff, true);
-
-    if (keepLocalTime) {
-      var newOffset = ins.utcOffset();
-      ins = ins.add(oldOffset - newOffset, MIN);
+    var offset = -Math.round(date.getTimezoneOffset() / 15) * 15 - diff;
+    var isUTC = !Number(offset);
+    var ins;
+
+    if (isUTC) {
+      // if utcOffset is 0, turn it to UTC mode
+      ins = this.utcOffset(0, keepLocalTime);
+    } else {
+      ins = d(target, {
+        locale: this.$L
+      }).$set(MS, this.$ms).utcOffset(offset, true);
+
+      if (keepLocalTime) {
+        var newOffset = ins.utcOffset();
+        ins = ins.add(oldOffset - newOffset, MIN);
+      }
     }
 
     ins.$x.$timezone = timezone;

+ 1 - 1
node_modules/dayjs/index.d.ts

@@ -114,7 +114,7 @@ declare namespace dayjs {
      * ```
      * Docs: https://day.js.org/docs/en/get-set/day
      */
-    day(): number
+    day(): 0 | 1 | 2 | 3 | 4 | 5 | 6
     /**
      * Set the day of the week.
      *

ファイルの差分が大きいため隠しています
+ 0 - 0
node_modules/dayjs/locale.json


+ 1 - 1
node_modules/dayjs/locale/bg.js

@@ -1 +1 @@
-!function(e,_){"object"==typeof exports&&"undefined"!=typeof module?module.exports=_(require("dayjs")):"function"==typeof define&&define.amd?define(["dayjs"],_):(e="undefined"!=typeof globalThis?globalThis:e||self).dayjs_locale_bg=_(e.dayjs)}(this,(function(e){"use strict";function _(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var t=_(e),d={name:"bg",weekdays:"неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"),weekdaysShort:"нед_пон_вто_сря_чет_пет_съб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),months:"януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"),monthsShort:"янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"),weekStart:1,ordinal:function(e){var _=e%100;if(_>10&&_<20)return e+"-ти";var t=e%10;return 1===t?e+"-ви":2===t?e+"-ри":7===t||8===t?e+"-ми":e+"-ти"},formats:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},relativeTime:{future:"след %s",past:"преди %s",s:"няколко секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",M:"месец",MM:"%d месеца",y:"година",yy:"%d години"}};return t.default.locale(d,null,!0),d}));
+!function(e,_){"object"==typeof exports&&"undefined"!=typeof module?module.exports=_(require("dayjs")):"function"==typeof define&&define.amd?define(["dayjs"],_):(e="undefined"!=typeof globalThis?globalThis:e||self).dayjs_locale_bg=_(e.dayjs)}(this,(function(e){"use strict";function _(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var t=_(e),d={name:"bg",weekdays:"неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"),weekdaysShort:"нед_пон_вто_сря_чет_пет_съб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),months:"януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"),monthsShort:"яну_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"),weekStart:1,ordinal:function(e){var _=e%100;if(_>10&&_<20)return e+"-ти";var t=e%10;return 1===t?e+"-ви":2===t?e+"-ри":7===t||8===t?e+"-ми":e+"-ти"},formats:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},relativeTime:{future:"след %s",past:"преди %s",s:"няколко секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",M:"месец",MM:"%d месеца",y:"година",yy:"%d години"}};return t.default.locale(d,null,!0),d}));

+ 1 - 1
node_modules/dayjs/locale/da.js

@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("dayjs")):"function"==typeof define&&define.amd?define(["dayjs"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).dayjs_locale_da=t(e.dayjs)}(this,(function(e){"use strict";function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var d=t(e),n={name:"da",weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"søn._man._tirs._ons._tors._fre._lør.".split("_"),weekdaysMin:"sø._ma._ti._on._to._fr._lø.".split("_"),months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj_juni_juli_aug._sept._okt._nov._dec.".split("_"),weekStart:1,ordinal:function(e){return e+"."},formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY [kl.] HH:mm"},relativeTime:{future:"om %s",past:"%s siden",s:"få sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en måned",MM:"%d måneder",y:"et år",yy:"%d år"}};return d.default.locale(n,null,!0),n}));
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("dayjs")):"function"==typeof define&&define.amd?define(["dayjs"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).dayjs_locale_da=t(e.dayjs)}(this,(function(e){"use strict";function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var d=t(e),a={name:"da",weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"søn._man._tirs._ons._tors._fre._lør.".split("_"),weekdaysMin:"sø._ma._ti._on._to._fr._lø.".split("_"),months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj_juni_juli_aug._sept._okt._nov._dec.".split("_"),weekStart:1,yearStart:4,ordinal:function(e){return e+"."},formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY [kl.] HH:mm"},relativeTime:{future:"om %s",past:"%s siden",s:"få sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en måned",MM:"%d måneder",y:"et år",yy:"%d år"}};return d.default.locale(a,null,!0),a}));

+ 1 - 1
node_modules/dayjs/locale/zh-hk.js

@@ -1 +1 @@
-!function(_,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("dayjs")):"function"==typeof define&&define.amd?define(["dayjs"],e):(_="undefined"!=typeof globalThis?globalThis:_||self).dayjs_locale_zh_hk=e(_.dayjs)}(this,(function(_){"use strict";function e(_){return _&&"object"==typeof _&&"default"in _?_:{default:_}}var t=e(_),d={name:"zh-hk",months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),ordinal:function(_,e){return"W"===e?_+"週":_+"日"},formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm"},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",m:"一分鐘",mm:"%d 分鐘",h:"一小時",hh:"%d 小時",d:"一天",dd:"%d 天",M:"一個月",MM:"%d 個月",y:"一年",yy:"%d 年"}};return t.default.locale(d,null,!0),d}));
+!function(_,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("dayjs")):"function"==typeof define&&define.amd?define(["dayjs"],e):(_="undefined"!=typeof globalThis?globalThis:_||self).dayjs_locale_zh_hk=e(_.dayjs)}(this,(function(_){"use strict";function e(_){return _&&"object"==typeof _&&"default"in _?_:{default:_}}var d=e(_),t={name:"zh-hk",months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),ordinal:function(_,e){return"W"===e?_+"週":_+"日"},formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",m:"一分鐘",mm:"%d 分鐘",h:"一小時",hh:"%d 小時",d:"一天",dd:"%d 天",M:"一個月",MM:"%d 個月",y:"一年",yy:"%d 年"},meridiem:function(_,e){var d=100*_+e;return d<600?"凌晨":d<900?"早上":d<1100?"上午":d<1300?"中午":d<1800?"下午":"晚上"}};return d.default.locale(t,null,!0),t}));

+ 12 - 11
node_modules/dayjs/package.json

@@ -1,26 +1,27 @@
 {
-  "_from": "dayjs@1.11.10",
-  "_id": "dayjs@1.11.10",
+  "_from": "dayjs@^1.11.10",
+  "_id": "dayjs@1.11.13",
   "_inBundle": false,
-  "_integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==",
+  "_integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
   "_location": "/dayjs",
   "_phantomChildren": {},
   "_requested": {
-    "type": "version",
+    "type": "range",
     "registry": true,
-    "raw": "dayjs@1.11.10",
+    "raw": "dayjs@^1.11.10",
     "name": "dayjs",
     "escapedName": "dayjs",
-    "rawSpec": "1.11.10",
+    "rawSpec": "^1.11.10",
     "saveSpec": null,
-    "fetchSpec": "1.11.10"
+    "fetchSpec": "^1.11.10"
   },
   "_requiredBy": [
+    "#USER",
     "/"
   ],
-  "_resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
-  "_shasum": "68acea85317a6e164457d6d6947564029a6a16a0",
-  "_spec": "dayjs@1.11.10",
+  "_resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+  "_shasum": "92430b0139055c3ebb60150aa13e860a4b5a366c",
+  "_spec": "dayjs@^1.11.10",
   "_where": "C:\\Users\\Administrator\\Desktop\\项目\\直播\\liveH5-v3",
   "author": {
     "name": "iamkun"
@@ -110,5 +111,5 @@
     }
   ],
   "types": "index.d.ts",
-  "version": "1.11.10"
+  "version": "1.11.13"
 }

ファイルの差分が大きいため隠しています
+ 0 - 0
node_modules/dayjs/plugin/customParseFormat.js


+ 15 - 4
node_modules/dayjs/plugin/minMax.d.ts

@@ -4,8 +4,19 @@ declare const plugin: PluginFunc
 export = plugin
 
 declare module 'dayjs' {
-  export function max(dayjs: Dayjs[]): Dayjs | null
-  export function max(...dayjs: Dayjs[]): Dayjs | null
-  export function min(dayjs: Dayjs[]): Dayjs | null
-  export function min(...dayjs: Dayjs[]): Dayjs | null
+  export function max(dayjs: [Dayjs, ...Dayjs[]]): Dayjs
+  export function max(noDates: never[]): null
+  export function max(maybeDates: Dayjs[]): Dayjs | null
+
+  export function max(...dayjs: [Dayjs, ...Dayjs[]]): Dayjs
+  export function max(...noDates: never[]): null
+  export function max(...maybeDates: Dayjs[]): Dayjs | null
+
+  export function min(dayjs: [Dayjs, ...Dayjs[]]): Dayjs
+  export function min(noDates: never[]): null
+  export function min(maybeDates: Dayjs[]): Dayjs | null
+
+  export function min(...dayjs: [Dayjs, ...Dayjs[]]): Dayjs
+  export function min(...noDates: never[]): null
+  export function min(...maybeDates: Dayjs[]): Dayjs | null
 }

+ 4 - 0
node_modules/dayjs/plugin/negativeYear.d.ts

@@ -0,0 +1,4 @@
+import {PluginFunc} from 'dayjs'
+
+declare const plugin: PluginFunc
+export = plugin

+ 1 - 0
node_modules/dayjs/plugin/negativeYear.js

@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).dayjs_plugin_negativeYear=t()}(this,(function(){"use strict";return function(e,t,n){var i=t.prototype,o=function(e){var t=e.date,i=e.utc;if("string"==typeof t&&"-"===t.charAt(0)){var o=t.slice(1),r=n(o),f=(r=i?n.utc(o):n(o)).year();return-1!==t.indexOf("-"+f)?n(r).subtract(2*f,"year").toDate():t}return t},r=i.parse;i.parse=function(e){e.date=o.bind(this)(e),r.bind(this)(e)}}}));

ファイルの差分が大きいため隠しています
+ 0 - 0
node_modules/dayjs/plugin/timezone.js


+ 275 - 0
node_modules/mescroll-uni/README.md

@@ -0,0 +1,275 @@
+## mescroll --【wxs+renderjs实现】高性能的下拉刷新上拉加载组件
+1. mescroll的uni版本 是专门用在uni-app的下拉刷新和上拉加载的组件, 支持一套代码编译到iOS、Android、H5、小程序等多个平台
+
+2. mescroll的uni版本 继承了mescroll.js的实用功能: 自动处理分页, 自动控制无数据, 空布局提示, 回到顶部按钮 ..
+
+3. mescroll的uni版本 丰富的案例, 自由灵活的api, 超详细的注释, 可让您快速自定义真正属于自己的下拉上拉组件
+
+<br/>
+
+
+## 最新文档(1.3.7版本): <a href="http://www.mescroll.com/uni.html">http://www.mescroll.com/uni.html</a>
+2021-04-13 by mescroll (文档可能会有缓存,建议打开时刷新一下)
+
+
+## 近期已更新优化的内容:
+1. 微信小程序, app, h5使用高性能wxs和renderjs, 下拉刷新更流畅丝滑, 尤其能明显解决Android小程序下拉卡顿的问题
+2. 新增国际化`mescroll-i18n.vue`示例, 新增轮播吸顶菜单`mescroll-swiper-sticky.vue`示例,    
+3. 新增 "局部区域滚动" 的案例: mescroll-body-part.vue 和 mescroll-uni-part.vue  
+4. 新增 me-video 视频组件, 解决APP端视频下拉悬浮错位的问题, 参考 mescroll-options.vue 示例  
+5. 新增 me-tabs 组件,tabs支持水平滑动; 优化mescroll-more和mescroll-swiper的案例, 顶部tab支持水平滑动
+6. 吸顶悬浮提供了原生sticky和监听滚动条实现的示例: sticky.vue 和 sticky-scroll.vue (推荐使用sticky样式实现)
+7. mescroll.scrollTo(y)的y支持css选择器, 包括跨自定义组件的后代选择器, 支持滚动到子组件的view (参考 mescroll-options.vue)  
+8. topbar 顶部是否预留状态栏的高度, 默认false; 还可支持设置状态栏背景: 如 '#ffff00', 'url(xxx) 0 0/100% 100%', 'linear-gradient(xx)'
+9. down.bgColor 和 up.bgColor 加载区域的背景,不仅支持色值, 而且还是支持背景图和渐变: 如 'url(xxx) 0 0/100% 100%', 'linear-gradient(xx)'
+10. topbar,bgColor支持一行代码定义background: [https://www.runoob.com/cssref/css3-pr-background.html](https://www.runoob.com/cssref/css3-pr-background.html)
+<br/>
+<br/>
+<a href="https://ext.dcloud.net.cn/plugin?id=343&update_log">查看更多 ... </a>
+
+
+### 更新记录:
+
+---
+#### 1.3.7版本 (2021/04/13)  
+1. 新增`mescroll-swiper-sticky.vue`的示例, 轮播吸顶菜单导航  
+2. 新增`mescroll-empty.vue`的示例, 单独使用空布局组件  
+3. 简化tabs在具体项目中的使用,并简化对应的示例  
+4. mescroll-uni 支持动态禁止滚动的属性 disableScroll (注: mescroll-body不支持)  
+-by 小瑾同学
+
+---
+#### 1.3.5版本 (2021/04/10)  
+1. 新增 `mescroll-i18n.vue` 的示例, 支持国际化的配置  
+2. down的`beforeEndDelay`不再默认配置 // (显示加载成功/失败的时长, android小程序设置此项结束下拉会卡顿, 配置后请注意测试)  
+3. mescroll-body-part.vue 和 mescroll-uni-part.vue 的示例新增参考代码: `异步加载左侧菜单(超简单)`  
+4. mescroll的极简示例新增参考代码: `先请求其他接口,再触发upCallback,无需配置auto为false(超简单)`  
+5. 修复mescroll-swiper的tabs在app或h5错位的问题  
+-by 小瑾同学
+
+---
+#### 1.3.3版本 (2020/09/15)  
+1. 新增下拉刷新成功和失败的文本配置, 可在 mescroll-uni-option.js 配置修改  
+1. 新增 me-video 视频组件, 解决APP端视频下拉悬浮错位的问题, 参考最新的 mescroll-options.vue 示例  
+2. 更新 mescroll-comp.vue 的示例, 支持 mescroll-body 子子..子组件 , 包括 mescroll-more.vue 也支持写在子子..子组件  
+3. mescroll-uni 的 down.offset 由原来的 80 调整为 150 , 避免超快速滑动列表到底部,偶尔出现无法再翻页的问题 (mescroll-body无此问题)  
+4. 修复 mescroll-more.vue 和 mescroll-swiper.vue 的示例在字节跳动小程序2.0.0以上新版编辑器无法正常运行的问题  
+5. 修复淘宝和美团的示例下拉卡顿的问题 ( 案例需重新下载 )  
+-by mescroll  
+
+---
+#### 1.3.2版本 (2020/08/05)
+1. mescroll-body新增sticky属性, 简化吸顶悬浮sticky.vue的示例  
+2. QQ小程序支持wxs,解决QQ小程序卡顿和无法隐藏加载状态的问题  
+3. mescroll.scrollTo(y)的y支持css选择器, 包括跨自定义组件的后代选择器, 支持滚动到子组件的view (参考 mescroll-options.vue)  
+-by 小瑾同学
+
+---
+#### 1.3.1版本 (2020/07/27)
+1. 修复Android小程序下拉刷新时, image 和 swiper 脱离文档流的问题  
+2. 修复H5端, 当配置down.use为false时, 返回其他页面无法滚动的问题  
+3. mescroll-comp.js支持mescroll-body写在子子子...组件中 (以前版本仅支持写在一级子组件) 
+4. 吸顶悬浮提供了sticky样式和监听滚动条实现的示例: sticky.vue 和 sticky-scroll.vue (推荐使用sticky样式实现)  
+-by 小瑾同学
+
+---
+#### 1.3.0版本 (2020/07/10)
+1. 微信小程序, app, h5使用高性能wxs和renderjs, 下拉刷新更流畅丝滑, 尤其能明显解决Android小程序下拉卡顿的问题
+2. 使用wxs和renderjs优化所有案例, 尤其是中高级案例, 建议大家重新下载最新的案例
+3. 废弃down的isBounce配置, 已通过renderjs自动判断, 无需配置mescroll-touch
+4. 废弃down的fps配置, 已通过wxs提高性能, 无需手动节流
+5. 新增 "局部区域滚动" 的案例: mescroll-body-part.vue 和 mescroll-uni-part.vue
+6. 解决swiper切换时,有时会触发下拉刷新的问题, 已避免swiper和下拉刷新相互冲突
+7. 解决钉钉小程序mescroll-uni下拉刷新有时无法触发的问题
+8. 解决上拉加载进度在部分Android手机显示不全的问题
+9. 提高 me-tabs 组件在部分Android手机的兼容性  
+-by 小瑾同学
+
+---
+#### 1.2.8版本 (2020/06/28)
+1. 解决 mescroll-uni 再某些情况下列表数据渲染不完全的问题 ( mescroll-body无此问题 )
+2. 优化 me-tabs 组件, 使用支付宝小程序可隐藏滚动条, 同时修复字节跳动小程序tab切换时渲染延迟的问题
+-by 小瑾同学
+
+---
+#### 1.2.7版本 (2020/06/24)
+1. 上拉加载结束隐藏底部加载区域,避免加载区域占位
+2. h5端的tab页默认偏移TabBar的高度,避免h5端列表被TabBar遮住 (如不想偏移,可通过配置 :bottombar="false" 取消)
+3. 新增 me-tabs 组件,tabs支持水平滑动; 优化mescroll-more和mescroll-swiper的案例, 顶部tab支持水平滑动
+
+---
+#### 1.2.6版本 (2020/06/16)
+1. mescroll-uni 和 mescroll-body 的 scrollTo 正式支持 scroll-into-view (传入的 y 为view的id即可生效)
+2. topbar 顶部是否预留状态栏的高度, 默认false; 这个版本还可支持设置状态栏背景: 如 '#ffff00', 'url(xxx)', 'linear-gradient(xx)'
+3. down.bgColor 和 up.bgColor 加载区域的背景,不仅支持色值, 而且还是支持背景图和渐变: 如 'url(xxx)', 'linear-gradient(xx)'
+4. 通过css方式适配iPhoneX, 比之前通过style方式具有更好的兼容性, 也同时消除了edge浏览器重复设置相同属性的警告
+5. 移除非必须的标签选择器,避免微信小程序提示组件内不可使用标签选择器的警告
+6. 修复当配置up的use为false时,默认的下拉刷新有时候无法自动隐藏的问题
+7. 修复当配置down的native为true时,auto失效的问题
+8. 修复空布局在某些情况下图片和文本错位的问题
+
+---
+#### 1.2.5版本 (2020/03/15)
+1. mescroll-body 的 props 支持 safearea 的配置 (需要适配iPhoneX时,配置为 true 即可, 默认 false)
+2. mescroll-uni 的 scrollTo 支持 scroll-into-view (当传入的 y 为view的id时, 即可生效)
+3. 新增 下拉加载聊天记录的案例 list-msg.vue, 类似微信QQ的聊天记录
+
+---
+#### 1.2.4版本 (2020/03/11)
+1. down和up分别新增 bgColor 的配置: 下拉区域背景颜色,默认"transparent"
+2. down和up分别新增 textColor 的配置: 下拉文本的颜色,默认"gray" (当bgColor配置了颜色,而textColor未配置时,则自动默认为白色)
+3. 调整mescroll-more-item.js, 使mescroll-more的案例支持初始化tabIndex大于0的tab页
+4. mescroll-body支持isBounce的配置, 解决H5下拉刷新失效的问题
+5. 解决mescroll-body在Android真机小程序下拉卡顿的问题 (mescroll-uni无此问题)
+
+---
+#### 1.2.3版本 (2020/02/18)
+新增3个mescroll的mixins, 极大简化了mescroll-comp, mescroll-more, mescroll-swiper的案例
+
+
+#### 1.2.2版本 (2020/02/16)
+1. 调整mescroll-more和mescroll-swiper的案例,确保各小程序平台可正确获取到mescroll对象  
+2. 修复字节跳动小程序初始化时的异常警告: <a href="http://www.mescroll.com/qa.html?v=20200216#q26">详情</a>
+
+
+#### 1.2.1版本 (2020/02/08)
+1. 新增 &lt;mescroll-body&gt; 组件, 用来填补 &lt;mescroll-uni&gt; 的不足.
+2. mescroll-body基于原生页的滚动,支持写入原生组件和fixed元素,不必固定高度,不必配置pages.json,简单性能好.
+3. mescroll-body可配置down的native:true, 可直接代理系统自带的下拉组件, 参考 mescroll-native 示例
+4. 新增mescroll-mixins.js,简化代码,兼容更多小程序平台
+5. 修复字节跳动小程序和支付宝小程序的部分异常警告
+
+#### 1.2.0版本 (2020/01/06)
+1. mescroll-uni.vue的props新增height. // 简单快捷设置mescroll的高度, 此项有值,则不使用fixed. 
+	使用场景: 当在弹窗或浮层中使用fixed固定mescroll高度比较麻烦时, 配置此项就很方便了
+	支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight
+2. mescroll-uni.vue的props新增safearea. // bottom的偏移量是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用,此项值对回到顶部按钮生效)
+3. mescroll-uni.vue的props中,top和bottom不仅仅支持数字, 还支持"20rpx", "20px", "20%"格式的值
+4. 补充锁定上拉加载mescroll.lockUpScroll的方法
+5. down.fps默认值提高至80
+6. 独立出空布局的组件&lt;mescroll-empty&gt;, 以便在不使用mescroll的界面也能统一管理空布局
+```
+<template>
+		<view>
+			// 基本用法
+			<mescroll-empty v-if="list.length==0"></mescroll-empty>
+			// 所有配置项 (option同up.empty的配置一致)
+			<mescroll-empty v-if="isShowEmpty" :option="optEmpty" @emptyclick="emptyClick"></mescroll-empty>
+		</view>
+	</template>
+	
+	<script>
+		import MescrollEmpty from '@/components/mescroll-uni/components/mescroll-empty.vue';
+		export default {
+			components: {
+				MescrollEmpty
+			},
+			...
+		}
+```
+7. 为了更快速自定义回到顶部按钮, up.toTop新增以下配置项:
+```
+	toTop: {
+		zIndex: 9990, // fixed定位z-index值
+		right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
+		bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
+		safearea: false, // bottom的偏移量是否加上底部安全区的距离, 默认false. 需要适配iPhoneX时使用 (具体的界面如果不配置此项,则取mescroll-uni.vue的safearea值)
+		width: 72, // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
+		radius: "50%", // 圆角, 默认"50%" (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
+		left: null, // 到左边的距离, 默认null. 此项有值时,right不生效. (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
+		duration: 300, // 回到顶部的动画时长,默认300ms (当值为0或300则使用系统自带回到顶部,更流畅; 其他值则通过step模拟,部分机型可能不够流畅,所以非特殊情况不建议修改此项)
+		src: null, // (已有配置)
+		offset: 1000 // (已有配置)
+	}
+```
+
+
+---
+#### 1.1.9版本 (2019/12/16)
+1. 解决左右滑动屏幕,某些情况下会触发上拉回调的bug
+2. mescroll-uni.vue的props新增topbar: top的偏移量是否加上状态栏高度 (当fixed为false时不生效; 使用场景:取消原生导航栏时,配置此项可自动加上状态栏高度的偏移量)
+
+---
+#### 1.1.8版本 (2019/11/01)
+1. 解决Android小程序快速上拉可能会导致不断翻页直到没有数据为止的bug
+2. 过滤某些情况下touch的警告输出
+
+---
+#### 1.1.7版本 (2019/10/15)
+1. 重点解决下拉刷新卡顿,特别是Android小程序卡顿的问题
+2. 补充之前版本遗漏的mescroll.lockUpScroll方法
+3. 支持数据不满屏时,仍可触发翻页的回调
+
+---
+#### 1.1.5版本 (2019/07/25)
+1. up新增isBounce的配置, 默认值为false. 目的是解决H5在ios下拉出现灰色背景和android端无法正常下拉的问题. 详见: <a href="http://www.mescroll.com/qa.html?v=190725#q25">http://www.mescroll.com/qa.html?v=190725#q25</a>
+2. 修复setClientHeight某些情况下会提示undefined的问题
+3. 修复在mescroll-uni-option.js配置page会导致分页异常的问题
+
+---
+#### 1.1.2版本 (2019/07/19)
+一. 修复和优化的内容:
+1. 修复列表不满屏时,无法上拉的问题
+2. 修复列表滚动到底部,有时无法上拉的问题
+3. 修复快速滚动到顶部时,滚动条的位置有时不为0的问题
+4. 修复配置page.num不生效的问题
+5. 修复小程序android端下拉卡顿的问题 (可配置down的supply,复杂的列表可适当调大值)
+6. 修复H5多mescroll的情况下回到顶部按钮错位的问题
+7. 优化和简化逻辑,去除冗余代码
+
+二. 完善获取节点信息的方式:
+1. 获取mescroll的唯一元素id: mescroll.viewId (可通过uni.createSelectorQuery进一步获取更多信息)
+2. 获取滚动内容的高度: mescroll.getScrollHeight()
+3. 获取mescroll的高度: mescroll.getClientHeight()
+4. 获取滚动条位置: mescroll.getScrollTop()
+5. 获取到底部的距离: mescroll.getScrollBottom()
+6. 获取滚动的方向: mescroll.isScrollUp // true向上滑; false向下滑
+7. 更多信息详见mescroll-options的示例
+
+---
+#### 1.1.1版本 (2019/07/16)
+1. 修复滚动到顶部,有时无法下拉的问题
+2. 修复禁止上拉时,列表底部有空白区域的问题
+
+---
+#### 1.1.0版本 (重要版本) (2019/07/01)
+一. 简化使用:
+1. **无需**在page.json中配置onReachBottomDistance<br/>
+2. **无需**在页面中注册onReachBottom 和 onPageScroll<br/>
+3. 初始化时@init**不再**是必须配置项<br/>
+4. 极大的**简化** list-mescroll-more.vue 的案例<br/>
+5. 全面**支持swiper**,详见 mescroll-swiper.vue 的案例<br/>
+6. 所有基础案例都有所简化, **建议**重新下载参考. (以前版本向下兼容)<br/> 
+7. 所有中高级案例自定义的部分,改动比较大, **必须**重新下载参考. (不兼容以前版本)
+
+二. 优化性能:
+1. 支持fixed定位,可实现局部**区域滚动**<br/>
+2. 支持swiper,scrollview**嵌套**使用<br/>
+3. 优化下拉逻辑,修复下拉刷新卡顿和抖动的问题<br/>
+4. 优化默认样式,避免某些情况出现双滚动条的问题<br/>
+5. up废弃errDistance配置, 内部已优化处理相关问题
+
+三. 新增配置:
+1. down和up新增fps节流配置.(默认40fps, 值越大每秒刷新频率越高)<br/>
+2. up新增offset配置: 距底部多远时,触发upCallback (默认80, 代替page.json的onReachBottomDistance)<br/>
+3. up新增onScroll配置: 是否监听滚动事件,默认false<br/>
+4. < mescroll-uni 新增 @scroll="scroll" 获取滚动条的位置和滚动方向, 需配置up的onScroll为true, 详见 mescroll-options.vue 的示例<br/>
+5. < mescroll-uni 新增 :fixed="true/false" 是否支持fixed定位, 默认 true. 
+<br/> 当:fixed="true", 此时 :top 和 :bottom 为 fixed 的 top 和 bottom
+<br/> 当:fixed="false", 此时 :top 和 :bottom 为 padding-top 和 padding-bottom
+
+
+---
+#### 1.0.3版本 (2019/06/13)
+1. 默认设置page高度100%,使列表不满屏的时候,仍可下拉刷新<br/>
+2. 加入-webkit-overflow-scrolling: touch, 编译到H5和APP,使iOS列表滚动更流畅<br/>
+3. mescroll-empty加入box-sizing: border-box, 修复图标和文本不居中的问题<br/>
+4. 上拉配置新增errDistance,默认110 // mescroll.endErr()的时候需往上滑动一段距离,使其能再次触发上拉加载 (已在1.1.0版本废弃)<br/>
+5. mescroll.endErr(errDistance) 新增的参数 errDistance; 可单独配置异常往上滑动的距离 (已在1.1.0版本废弃)<br/>
+6. 修改了list-mescroll-more的160行为mescroll.endErr(0);(已在1.1.0版本优化)<br/>
+7. 新增mescroll.scrollTo(y,t) 滚动到指定的位置; 本质调用的是uni.pageScrollTo
+
+---
+#### 1.0.2版本 (2019/05/28)  
+1. 组件根元素加入mescroll-uni的样式,empty新增fixed等配置项; <br/>
+2. 修复list-mescroll-more案例切换tabs,某些情况的page.num会错乱的问题

+ 55 - 0
node_modules/mescroll-uni/components/mescroll-down.css

@@ -0,0 +1,55 @@
+/* 下拉刷新区域 */
+.mescroll-downwarp {
+	position: absolute;
+	top: -100%;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	text-align: center;
+}
+
+/* 下拉刷新--内容区,定位于区域底部 */
+.mescroll-downwarp .downwarp-content {
+	position: absolute;
+	left: 0;
+	bottom: 0;
+	width: 100%;
+	min-height: 60rpx;
+	padding: 20rpx 0;
+	text-align: center;
+}
+
+/* 下拉刷新--提示文本 */
+.mescroll-downwarp .downwarp-tip {
+	display: inline-block;
+	font-size: 28rpx;
+	vertical-align: middle;
+	margin-left: 16rpx;
+	/* color: gray; 已在style设置color,此处删去*/
+}
+
+/* 下拉刷新--旋转进度条 */
+.mescroll-downwarp .downwarp-progress {
+	display: inline-block;
+	width: 32rpx;
+	height: 32rpx;
+	border-radius: 50%;
+	border: 2rpx solid gray;
+	border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/
+	vertical-align: middle;
+}
+
+/* 旋转动画 */
+.mescroll-downwarp .mescroll-rotate {
+	animation: mescrollDownRotate 0.6s linear infinite;
+}
+
+@keyframes mescrollDownRotate {
+	0% {
+		transform: rotate(0deg);
+	}
+
+	100% {
+		transform: rotate(360deg);
+	}
+}

+ 47 - 0
node_modules/mescroll-uni/components/mescroll-down.vue

@@ -0,0 +1,47 @@
+<!-- 下拉刷新区域 -->
+<template>
+	<view v-if="mOption.use" class="mescroll-downwarp" :style="{'background-color':mOption.bgColor,'color':mOption.textColor}">
+		<view class="downwarp-content">
+			<view class="downwarp-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mOption.textColor, 'transform':downRotate}"></view>
+			<view class="downwarp-tip">{{downText}}</view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	props: {
+		option: Object , // down的配置项
+		type: Number, // 下拉状态(inOffset:1, outOffset:2, showLoading:3, endDownScroll:4)
+		rate: Number // 下拉比率 (inOffset: rate<1; outOffset: rate>=1)
+	},
+	computed: {
+		// 支付宝小程序需写成计算属性,prop定义default仍报错
+		mOption(){
+			return this.option || {}
+		},
+		// 是否在加载中
+		isDownLoading(){
+			return this.type === 3
+		},
+		// 旋转的角度
+		downRotate(){
+			return 'rotate(' + 360 * this.rate + 'deg)'
+		},
+		// 文本提示
+		downText(){
+			switch (this.type){
+				case 1: return this.mOption.textInOffset;
+				case 2: return this.mOption.textOutOffset;
+				case 3: return this.mOption.textLoading;
+				case 4: return this.mOption.textLoading;
+				default: return this.mOption.textInOffset;
+			}
+		}
+	}
+};
+</script>
+
+<style>
+@import "./mescroll-down.css";
+</style>

+ 118 - 0
node_modules/mescroll-uni/components/mescroll-empty.vue

@@ -0,0 +1,118 @@
+<!--空布局:
+
+可作为独立的组件, 不使用mescroll的页面也能单独引入, 以便APP全局统一管理:
+import MescrollEmpty from '@/components/mescroll-uni/components/mescroll-empty.vue';
+<mescroll-empty v-if="isShowEmpty" :option="optEmpty" @emptyclick="emptyClick"></mescroll-empty>
+-->
+<template>
+	<view class="mescroll-empty" :class="{ 'empty-fixed': option.fixed }" :style="{ 'z-index': option.zIndex, top: option.top }">
+		<view> <image v-if="icon" class="empty-icon" :src="icon" mode="widthFix" /> </view>
+		<view v-if="tip" class="empty-tip">{{ tip }}</view>
+		<view v-if="btnText" class="empty-btn" @click="emptyClick">{{ btnText }}</view>
+	</view>
+</template>
+
+<script>
+// 引入全局配置
+import GlobalOption from './../mescroll-uni-option.js';
+// 引入国际化工具类
+import mescrollI18n from './../mescroll-i18n.js';
+export default {
+	props: {
+		// empty的配置项: 默认为GlobalOption.up.empty
+		option: {
+			type: Object,
+			default() {
+				return {};
+			}
+		}
+	},
+	// 使用computed获取配置,用于支持option的动态配置
+	computed: {
+		// 图标
+		icon() {
+			if (this.option.icon != null) { // 此处不使用短路求值, 用于支持传空串不显示图标
+				return this.option.icon
+			} else{
+				let i18nType = mescrollI18n.getType() // 国际化配置
+				if (this.option.i18n) {
+					return this.option.i18n[i18nType].icon
+				} else{
+					return GlobalOption.i18n[i18nType].up.empty.icon || GlobalOption.up.empty.icon
+				}
+			}
+		},
+		// 文本提示
+		tip() {
+			if (this.option.tip != null) { // 支持传空串不显示文本提示
+				return this.option.tip
+			} else{
+				let i18nType = mescrollI18n.getType() // 国际化配置
+				if (this.option.i18n) {
+					return this.option.i18n[i18nType].tip
+				} else{
+					return GlobalOption.i18n[i18nType].up.empty.tip || GlobalOption.up.empty.tip
+				}
+			}
+		},
+		// 按钮文本
+		btnText() {
+			if (this.option.i18n) {
+				let i18nType = mescrollI18n.getType() // 国际化配置
+				return this.option.i18n[i18nType].btnText
+			} else{
+				return this.option.btnText
+			}
+		}
+	},
+	methods: {
+		// 点击按钮
+		emptyClick() {
+			this.$emit('emptyclick');
+		}
+	}
+};
+</script>
+
+<style>
+/* 无任何数据的空布局 */
+.mescroll-empty {
+	box-sizing: border-box;
+	width: 100%;
+	padding: 100rpx 50rpx;
+	text-align: center;
+}
+
+.mescroll-empty.empty-fixed {
+	z-index: 99;
+	position: absolute; /*transform会使fixed失效,最终会降级为absolute */
+	top: 100rpx;
+	left: 0;
+}
+
+.mescroll-empty .empty-icon {
+	width: 280rpx;
+	height: 280rpx;
+}
+
+.mescroll-empty .empty-tip {
+	margin-top: 20rpx;
+	font-size: 24rpx;
+	color: gray;
+}
+
+.mescroll-empty .empty-btn {
+	display: inline-block;
+	margin-top: 40rpx;
+	min-width: 200rpx;
+	padding: 18rpx;
+	font-size: 28rpx;
+	border: 1rpx solid #e04b28;
+	border-radius: 60rpx;
+	color: #e04b28;
+}
+
+.mescroll-empty .empty-btn:active {
+	opacity: 0.75;
+}
+</style>

+ 83 - 0
node_modules/mescroll-uni/components/mescroll-top.vue

@@ -0,0 +1,83 @@
+<!-- 回到顶部的按钮 -->
+<template>
+	<image
+		v-if="mOption.src"
+		class="mescroll-totop"
+		:class="[value ? 'mescroll-totop-in' : 'mescroll-totop-out', {'mescroll-totop-safearea': mOption.safearea}]"
+		:style="{'z-index':mOption.zIndex, 'left': left, 'right': right, 'bottom':addUnit(mOption.bottom), 'width':addUnit(mOption.width), 'border-radius':addUnit(mOption.radius)}"
+		:src="mOption.src"
+		mode="widthFix"
+		@click="toTopClick"
+	/>
+</template>
+
+<script>
+export default {
+	props: {
+		// up.toTop的配置项
+		option: Object,
+		// 是否显示
+		value: false
+	},
+	computed: {
+		// 支付宝小程序需写成计算属性,prop定义default仍报错
+		mOption(){
+			return this.option || {}
+		},
+		// 优先显示左边
+		left(){
+			return this.mOption.left ? this.addUnit(this.mOption.left) : 'auto';
+		},
+		// 右边距离 (优先显示左边)
+		right() {
+			return this.mOption.left ? 'auto' : this.addUnit(this.mOption.right);
+		}
+	},
+	methods: {
+		addUnit(num){
+			if(!num) return 0;
+			if(typeof num === 'number') return num + 'rpx';
+			return num
+		},
+		toTopClick() {
+			this.$emit('input', false); // 使v-model生效
+			this.$emit('click'); // 派发点击事件
+		}
+	}
+};
+</script>
+
+<style>
+/* 回到顶部的按钮 */
+.mescroll-totop {
+	z-index: 9990;
+	position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */
+	right: 20rpx;
+	bottom: 120rpx;
+	width: 72rpx;
+	height: auto;
+	border-radius: 50%;
+	opacity: 0;
+	transition: opacity 0.5s; /* 过渡 */
+	margin-bottom: var(--window-bottom); /* css变量 */
+}
+
+/* 适配 iPhoneX */
+@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
+	.mescroll-totop-safearea {
+		margin-bottom: calc(var(--window-bottom) + constant(safe-area-inset-bottom)); /* window-bottom + 适配 iPhoneX */
+		margin-bottom: calc(var(--window-bottom) + env(safe-area-inset-bottom));
+	}
+}
+
+/* 显示 -- 淡入 */
+.mescroll-totop-in {
+	opacity: 1;
+}
+
+/* 隐藏 -- 淡出且不接收事件*/
+.mescroll-totop-out {
+	opacity: 0;
+	pointer-events: none;
+}
+</style>

+ 47 - 0
node_modules/mescroll-uni/components/mescroll-up.css

@@ -0,0 +1,47 @@
+/* 上拉加载区域 */
+.mescroll-upwarp {
+	box-sizing: border-box;
+	min-height: 110rpx;
+	padding: 30rpx 0;
+	text-align: center;
+	clear: both;
+}
+
+/*提示文本 */
+.mescroll-upwarp .upwarp-tip,
+.mescroll-upwarp .upwarp-nodata {
+	display: inline-block;
+	font-size: 28rpx;
+	vertical-align: middle;
+	/* color: gray; 已在style设置color,此处删去*/
+}
+
+.mescroll-upwarp .upwarp-tip {
+	margin-left: 16rpx;
+}
+
+/*旋转进度条 */
+.mescroll-upwarp .upwarp-progress {
+	display: inline-block;
+	width: 32rpx;
+	height: 32rpx;
+	border-radius: 50%;
+	border: 2rpx solid gray;
+	border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/
+	vertical-align: middle;
+}
+
+/* 旋转动画 */
+.mescroll-upwarp .mescroll-rotate {
+	animation: mescrollUpRotate 0.6s linear infinite;
+}
+
+@keyframes mescrollUpRotate {
+	0% {
+		transform: rotate(0deg);
+	}
+
+	100% {
+		transform: rotate(360deg);
+	}
+}

+ 39 - 0
node_modules/mescroll-uni/components/mescroll-up.vue

@@ -0,0 +1,39 @@
+<!-- 上拉加载区域 -->
+<template>
+	<view class="mescroll-upwarp" :style="{'background-color':mOption.bgColor,'color':mOption.textColor}">
+		<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
+		<view v-show="isUpLoading">
+			<view class="upwarp-progress mescroll-rotate" :style="{'border-color':mOption.textColor}"></view>
+			<view class="upwarp-tip">{{ mOption.textLoading }}</view>
+		</view>
+		<!-- 无数据 -->
+		<view v-if="isUpNoMore" class="upwarp-nodata">{{ mOption.textNoMore }}</view>
+	</view>
+</template>
+
+<script>
+export default {
+	props: {
+		option: Object, // up的配置项
+		type: Number // 上拉加载的状态:0(loading前),1(loading中),2(没有更多了)
+	},
+	computed: {
+		// 支付宝小程序需写成计算属性,prop定义default仍报错
+		mOption() {
+			return this.option || {};
+		},
+		// 加载中
+		isUpLoading() {
+			return this.type === 1;
+		},
+		// 没有更多了
+		isUpNoMore() {
+			return this.type === 2;
+		}
+	}
+};
+</script>
+
+<style>
+@import './mescroll-up.css';
+</style>

+ 19 - 0
node_modules/mescroll-uni/mescroll-body.css

@@ -0,0 +1,19 @@
+.mescroll-body {
+	position: relative; /* 下拉刷新区域相对自身定位 */
+	height: auto; /* 不可固定高度,否则overflow:hidden导致无法滑动; 同时使设置的最小高生效,实现列表不满屏仍可下拉*/
+	overflow: hidden; /* 当有元素写在mescroll-body标签前面时,可遮住下拉刷新区域 */
+	box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */
+}
+
+/* 使sticky生效: 父元素不能overflow:hidden或者overflow:auto属性 */
+.mescroll-body.mescorll-sticky{
+	overflow: unset !important
+}
+
+/* 适配 iPhoneX */
+@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
+	.mescroll-safearea {
+		padding-bottom: constant(safe-area-inset-bottom);
+		padding-bottom: env(safe-area-inset-bottom);
+	}
+}

+ 403 - 0
node_modules/mescroll-uni/mescroll-body.vue

@@ -0,0 +1,403 @@
+<template>
+	<view 
+	class="mescroll-body mescroll-render-touch" 
+	:class="{'mescorll-sticky': sticky}"
+	:style="{'minHeight':minHeight, 'padding-top': padTop, 'padding-bottom': padBottom}" 
+	@touchstart="wxsBiz.touchstartEvent" 
+	@touchmove="wxsBiz.touchmoveEvent" 
+	@touchend="wxsBiz.touchendEvent" 
+	@touchcancel="wxsBiz.touchendEvent"
+	:change:prop="wxsBiz.propObserver"
+	:prop="wxsProp"
+	>
+		<!-- 状态栏 -->
+		<view v-if="topbar&&statusBarHeight" class="mescroll-topbar" :style="{height: statusBarHeight+'px', background: topbar}"></view>
+		
+		<view class="mescroll-body-content mescroll-wxs-content" :style="{ transform: translateY, transition: transition }" :change:prop="wxsBiz.callObserver" :prop="callProp">
+			<!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)-->
+			<!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> -->
+			<view v-if="mescroll.optDown.use" class="mescroll-downwarp" :style="{'background':mescroll.optDown.bgColor,'color':mescroll.optDown.textColor}">
+				<view class="downwarp-content">
+					<view class="downwarp-progress mescroll-wxs-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mescroll.optDown.textColor, 'transform': downRotate}"></view>
+					<view class="downwarp-tip">{{downText}}</view>
+				</view>
+			</view>
+	
+			<!-- 列表内容 -->
+			<slot></slot>
+
+			<!-- 空布局 -->
+			<mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty>
+
+			<!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)-->
+			<!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> -->
+			<view v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" class="mescroll-upwarp" :style="{'background':mescroll.optUp.bgColor,'color':mescroll.optUp.textColor}">
+				<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
+				<view v-show="upLoadType===1">
+					<view class="upwarp-progress mescroll-rotate" :style="{'border-color':mescroll.optUp.textColor}"></view>
+					<view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view>
+				</view>
+				<!-- 无数据 -->
+				<view v-if="upLoadType===2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view>
+			</view>
+		</view>
+		
+		<!-- 底部是否偏移TabBar的高度(默认仅在H5端的tab页生效) -->
+		<!-- #ifdef H5 -->
+		<view v-if="bottombar && windowBottom>0" class="mescroll-bottombar" :style="{height: windowBottom+'px'}"></view>
+		<!-- #endif -->
+		
+		<!-- 适配iPhoneX -->
+		<view v-if="safearea" class="mescroll-safearea"></view>
+		
+		<!-- 回到顶部按钮 (fixed元素需写在transform外面,防止降级为absolute)-->
+		<mescroll-top v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick"></mescroll-top>
+		
+		<!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 -->
+		<!-- renderjs的数据载体,不可写在mescroll-downwarp内部,避免use为false时,载体丢失,无法更新数据 -->
+		<view :change:prop="renderBiz.propObserver" :prop="wxsProp"></view>
+		<!-- #endif -->
+	</view>
+</template>
+
+<!-- 微信小程序, QQ小程序, app, h5使用wxs -->
+<!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 -->
+<script src="./wxs/wxs.wxs" module="wxsBiz" lang="wxs"></script>
+<!-- #endif -->
+
+<!-- app, h5使用renderjs -->
+<!-- #ifdef APP-PLUS || H5 -->
+<script module="renderBiz" lang="renderjs">
+	import renderBiz from './wxs/renderjs.js';
+	export default {
+		mixins: [renderBiz]
+	}
+</script>
+<!-- #endif -->
+
+<script>
+	// 引入mescroll-uni.js,处理核心逻辑
+	import MeScroll from './mescroll-uni.js';
+	// 引入全局配置
+	import GlobalOption from './mescroll-uni-option.js';
+	// 引入空布局组件
+	import MescrollEmpty from './components/mescroll-empty.vue';
+	// 引入国际化工具类
+	import mescrollI18n from './mescroll-i18n.js';
+	// 引入回到顶部组件
+	import MescrollTop from './components/mescroll-top.vue';
+	// 引入兼容wxs(含renderjs)写法的mixins
+	import WxsMixin from './wxs/mixins.js';
+	
+	/**
+	 * mescroll-body 基于page滚动的下拉刷新和上拉加载组件, 支持嵌套原生组件, 性能好
+	 * @property {Object} down 下拉刷新的参数配置
+	 * @property {Object} up 上拉加载的参数配置
+	 * @property {Object} i18n 国际化的参数配置
+	 * @property {String, Number} top 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
+	 * @property {Boolean, String} topbar 偏移量top是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可留出状态栏的占位, 支持传入字符串背景,如色值,背景图,渐变)
+	 * @property {String, Number} bottom 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
+	 * @property {Boolean} safearea 偏移量bottom是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用)
+	 * @property {Boolean} fixed 是否通过fixed固定mescroll的高度, 默认true
+	 * @property {String, Number} height 指定mescroll最小高度,默认windowHeight,使列表不满屏仍可下拉
+	 * @property {Boolean} bottombar 底部是否偏移TabBar的高度 (仅在H5端的tab页生效)
+	 * @property {Boolean} sticky 是否支持sticky,默认false; 当值配置true时,需避免在mescroll-body标签前面加非定位的元素,否则下拉区域无法隐藏
+	 * @event {Function} init 初始化完成的回调 
+	 * @event {Function} down 下拉刷新的回调
+	 * @event {Function} up 上拉加载的回调 
+	 * @event {Function} emptyclick 点击empty配置的btnText按钮回调
+	 * @event {Function} topclick 点击回到顶部的按钮回调
+	 * @event {Function} scroll 滚动监听 (需在 up 配置 onScroll:true 才生效)
+	 * @example <mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback"> ... </mescroll-body>
+	 */
+	export default {
+		name: 'mescroll-body',
+		mixins: [WxsMixin],
+		components: {
+			MescrollEmpty,
+			MescrollTop
+		},
+		props: {
+			down: Object,
+			up: Object,
+			i18n: Object,
+			top: [String, Number],
+			topbar: [Boolean, String],
+			bottom: [String, Number],
+			safearea: Boolean,
+			height: [String, Number],
+			bottombar:{
+				type: Boolean,
+				default: true
+			},
+			sticky: Boolean
+		},
+		data() {
+			return {
+				mescroll: {optDown:{},optUp:{}}, // mescroll实例
+				downHight: 0, //下拉刷新: 容器高度
+				downRate: 0, // 下拉比率(inOffset: rate<1; outOffset: rate>=1)
+				downLoadType: 0, // 下拉刷新状态: 0(loading前), 1(inOffset), 2(outOffset), 3(showLoading), 4(endDownScroll)
+				upLoadType: 0, // 上拉加载状态:0(loading前),1(loading中),2(没有更多了,显示END文本提示),3(没有更多了,不显示END文本提示)
+				isShowEmpty: false, // 是否显示空布局
+				isShowToTop: false, // 是否显示回到顶部按钮
+				windowHeight: 0, // 可使用窗口的高度
+				windowBottom: 0, // 可使用窗口的底部位置
+				statusBarHeight: 0 // 状态栏高度
+			};
+		},
+		computed: {
+			// mescroll最小高度,默认windowHeight,使列表不满屏仍可下拉
+			minHeight(){
+				return this.toPx(this.height || '100%') + 'px'
+			},
+			// 下拉布局往下偏移的距离 (px)
+			numTop() {
+				return this.toPx(this.top)
+			},
+			padTop() {
+				return this.numTop + 'px';
+			},
+			// 上拉布局往上偏移 (px)
+			numBottom() {
+				return this.toPx(this.bottom);
+			},
+			padBottom() {
+				return this.numBottom + 'px';
+			},
+			// 是否为重置下拉的状态
+			isDownReset() {
+				return this.downLoadType === 3 || this.downLoadType === 4;
+			},
+			// 过渡
+			transition() {
+				return this.isDownReset ? 'transform 300ms' : '';
+			},
+			translateY() {
+				return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' : ''; // transform会使fixed失效,需注意把fixed元素写在mescroll之外
+			},
+			// 是否在加载中
+			isDownLoading(){
+				return this.downLoadType === 3
+			},
+			// 旋转的角度
+			downRotate(){
+				return 'rotate(' + 360 * this.downRate + 'deg)'
+			},
+			// 文本提示
+			downText(){
+				if(!this.mescroll) return ""; // 避免头条小程序初始化时报错
+				switch (this.downLoadType){
+					case 1: return this.mescroll.optDown.textInOffset;
+					case 2: return this.mescroll.optDown.textOutOffset;
+					case 3: return this.mescroll.optDown.textLoading;
+					case 4: return this.mescroll.isDownEndSuccess ? this.mescroll.optDown.textSuccess : this.mescroll.isDownEndSuccess==false ? this.mescroll.optDown.textErr : this.mescroll.optDown.textInOffset;
+					default: return this.mescroll.optDown.textInOffset;
+				}
+			}
+		},
+		methods: {
+			//number,rpx,upx,px,% --> px的数值
+			toPx(num) {
+				if (typeof num === 'string') {
+					if (num.indexOf('px') !== -1) {
+						if (num.indexOf('rpx') !== -1) {
+							// "10rpx"
+							num = num.replace('rpx', '');
+						} else if (num.indexOf('upx') !== -1) {
+							// "10upx"
+							num = num.replace('upx', '');
+						} else {
+							// "10px"
+							return Number(num.replace('px', ''));
+						}
+					} else if (num.indexOf('%') !== -1) {
+						// 传百分比,则相对于windowHeight,传"10%"则等于windowHeight的10%
+						let rate = Number(num.replace('%', '')) / 100;
+						return this.windowHeight * rate;
+					}
+				}
+				return num ? uni.upx2px(Number(num)) : 0;
+			},
+			// 点击空布局的按钮回调
+			emptyClick() {
+				this.$emit('emptyclick', this.mescroll);
+			},
+			// 点击回到顶部的按钮回调
+			toTopClick() {
+				this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); // 执行回到顶部
+				this.$emit('topclick', this.mescroll); // 派发点击回到顶部按钮的回调
+			}
+		},
+		// 使用created初始化mescroll对象; 如果用mounted部分css样式编译到H5会失效
+		created() {
+			let vm = this;
+
+			let diyOption = {
+				// 下拉刷新的配置
+				down: {
+					inOffset() {
+						vm.downLoadType = 1; // 下拉的距离进入offset范围内那一刻的回调 (自定义mescroll组件时,此行不可删)
+					},
+					outOffset() {
+						vm.downLoadType = 2; // 下拉的距离大于offset那一刻的回调 (自定义mescroll组件时,此行不可删)
+					},
+					onMoving(mescroll, rate, downHight) {
+						// 下拉过程中的回调,滑动过程一直在执行;
+						vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
+						vm.downRate = rate; //下拉比率 (inOffset: rate<1; outOffset: rate>=1)
+					},
+					showLoading(mescroll, downHight) {
+						vm.downLoadType = 3; // 显示下拉刷新进度的回调 (自定义mescroll组件时,此行不可删)
+						vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
+					},
+					beforeEndDownScroll(mescroll){
+						vm.downLoadType = 4; 
+						return mescroll.optDown.beforeEndDelay // 延时结束的时长
+					},
+					endDownScroll() {
+						vm.downLoadType = 4; // 结束下拉 (自定义mescroll组件时,此行不可删)
+						vm.downHight = 0; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
+						if(vm.downResetTimer) {clearTimeout(vm.downResetTimer); vm.downResetTimer = null} // 移除重置倒计时
+						vm.downResetTimer = setTimeout(()=>{ // 过渡动画执行完毕后,需重置为0的状态,避免下次inOffset不及时显示textInOffset
+							if(vm.downLoadType === 4) vm.downLoadType = 0
+						},300)
+					},
+					// 派发下拉刷新的回调
+					callback: function(mescroll) {
+						vm.$emit('down', mescroll);
+					}
+				},
+				// 上拉加载的配置
+				up: {
+					// 显示加载中的回调
+					showLoading() {
+						vm.upLoadType = 1;
+					},
+					// 显示无更多数据的回调
+					showNoMore() {
+						vm.upLoadType = 2;
+					},
+					// 隐藏上拉加载的回调
+					hideUpScroll(mescroll) {
+						vm.upLoadType = mescroll.optUp.hasNext ? 0 : 3;
+					},
+					// 空布局
+					empty: {
+						onShow(isShow) {
+							// 显示隐藏的回调
+							vm.isShowEmpty = isShow;
+						}
+					},
+					// 回到顶部
+					toTop: {
+						onShow(isShow) {
+							// 显示隐藏的回调
+							vm.isShowToTop = isShow;
+						}
+					},
+					// 派发上拉加载的回调
+					callback: function(mescroll) {
+						vm.$emit('up', mescroll);
+					}
+				}
+			};
+			
+			let i18nType = mescrollI18n.getType() // 当前语言类型
+			let i18nOption = {type: i18nType} // 国际化配置
+			MeScroll.extend(i18nOption, vm.i18n) // 具体页面的国际化配置
+			MeScroll.extend(i18nOption, GlobalOption.i18n) // 全局的国际化配置
+			MeScroll.extend(diyOption, i18nOption[i18nType]); // 混入国际化配置
+			MeScroll.extend(diyOption, {down:GlobalOption.down, up:GlobalOption.up}); // 混入全局的配置
+			let myOption = JSON.parse(JSON.stringify({down: vm.down,up: vm.up})); // 深拷贝,避免对props的影响
+			MeScroll.extend(myOption, diyOption); // 混入具体界面的配置
+
+			// 初始化MeScroll对象
+			vm.mescroll = new MeScroll(myOption, true); // 传入true,标记body为滚动区域
+			// 挂载语言包
+			vm.mescroll.i18n = i18nOption;
+			// init回调mescroll对象
+			vm.$emit('init', vm.mescroll);
+
+			// 设置高度
+			const sys = uni.getSystemInfoSync();
+			if (sys.windowHeight) vm.windowHeight = sys.windowHeight;
+			if (sys.windowBottom) vm.windowBottom = sys.windowBottom;
+			if (sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight;
+			// 使down的bottomOffset生效
+			vm.mescroll.setBodyHeight(sys.windowHeight);
+
+			// 因为使用的是page的scroll,这里需自定义scrollTo
+			vm.mescroll.resetScrollTo((y, t) => {
+				if(typeof y === 'string'){
+					// 滚动到指定view (y为css选择器)
+					setTimeout(()=>{ // 延时确保view已渲染; 不使用$nextTick
+						let selector;
+						if(y.indexOf('#')==-1 && y.indexOf('.')==-1){
+							selector = '#'+y // 不带#和. 则默认为id选择器
+						}else{
+							selector = y
+							// #ifdef APP-PLUS || H5 || MP-ALIPAY || MP-DINGTALK
+							if(y.indexOf('>>>')!=-1){ // 不支持跨自定义组件的后代选择器 (转为普通的选择器即可跨组件查询)
+								selector = y.split('>>>')[1].trim()
+							}
+							// #endif
+						}
+						uni.createSelectorQuery().select(selector).boundingClientRect(function(rect){
+							if (rect) {
+								let top = rect.top
+								top += vm.mescroll.getScrollTop()
+								uni.pageScrollTo({
+									scrollTop: top,
+									duration: t
+								})
+							} else{
+								console.error(selector + ' does not exist');
+							}
+						}).exec()
+					},30)
+				} else{
+					// 滚动到指定位置 (y必须为数字)
+					uni.pageScrollTo({
+						scrollTop: y,
+						duration: t
+					})
+				}
+			});
+
+			// 具体的界面如果不配置up.toTop.safearea,则取本vue的safearea值
+			if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {} else {
+				vm.mescroll.optUp.toTop.safearea = vm.safearea;
+			}
+			
+			// 全局配置监听
+			uni.$on("setMescrollGlobalOption", options=>{
+				if(!options) return;
+				let i18nType = options.i18n ? options.i18n.type : null
+				if(i18nType && vm.mescroll.i18n.type != i18nType){
+					vm.mescroll.i18n.type = i18nType
+					mescrollI18n.setType(i18nType)
+					MeScroll.extend(options, vm.mescroll.i18n[i18nType])
+				}
+				if(options.down){
+					let down = MeScroll.extend({}, options.down)
+					vm.mescroll.optDown = MeScroll.extend(down, vm.mescroll.optDown)
+				}
+				if(options.up){
+					let up = MeScroll.extend({}, options.up)
+					vm.mescroll.optUp = MeScroll.extend(up, vm.mescroll.optUp)
+				}
+			})
+		},
+		destroyed() {
+			// 注销全局配置监听
+			uni.$off("setMescrollGlobalOption")
+		}
+	};
+</script>
+
+<style>
+	@import "./mescroll-body.css";
+	@import "./components/mescroll-down.css";
+	@import './components/mescroll-up.css';
+</style>

+ 15 - 0
node_modules/mescroll-uni/mescroll-i18n.js

@@ -0,0 +1,15 @@
+// 国际化工具类
+const mescrollI18n = {
+	// 默认语言
+	def: "zh",
+	// 获取当前语言类型
+	getType(){
+		return uni.getStorageSync("mescroll-i18n") || this.def
+	},
+	// 设置当前语言类型
+	setType(type){
+		uni.setStorageSync("mescroll-i18n", type)
+	}
+}
+
+export default mescrollI18n

+ 57 - 0
node_modules/mescroll-uni/mescroll-mixins.js

@@ -0,0 +1,57 @@
+// mescroll-body 和 mescroll-uni 通用
+const MescrollMixin = {
+	data() {
+		return {
+			mescroll: null //mescroll实例对象
+		}
+	},
+	// 注册系统自带的下拉刷新 (配置down.native为true时生效, 还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)
+	onPullDownRefresh(){
+		this.mescroll && this.mescroll.onPullDownRefresh();
+	},
+	// 注册列表滚动事件,用于判定在顶部可下拉刷新,在指定位置可显示隐藏回到顶部按钮 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效)
+	onPageScroll(e) {
+		this.mescroll && this.mescroll.onPageScroll(e);
+	},
+	// 注册滚动到底部的事件,用于上拉加载 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效)
+	onReachBottom() {
+		this.mescroll && this.mescroll.onReachBottom();
+	},
+	methods: {
+		// mescroll组件初始化的回调,可获取到mescroll对象
+		mescrollInit(mescroll) {
+			this.mescroll = mescroll;
+			this.mescrollInitByRef(); // 兼容字节跳动小程序
+		},
+		// 以ref的方式初始化mescroll对象 (兼容字节跳动小程序)
+		mescrollInitByRef() {
+			if(!this.mescroll || !this.mescroll.resetUpScroll){
+				let mescrollRef = this.$refs.mescrollRef;
+				if(mescrollRef) this.mescroll = mescrollRef.mescroll
+			}
+		},
+		// 下拉刷新的回调 (mixin默认resetUpScroll)
+		downCallback() {
+			if(this.mescroll.optUp.use){
+				this.mescroll.resetUpScroll()
+			}else{
+				setTimeout(()=>{
+					this.mescroll.endSuccess();
+				}, 500)
+			}
+		},
+		// 上拉加载的回调
+		upCallback() {
+			// mixin默认延时500自动结束加载
+			setTimeout(()=>{
+				this.mescroll.endErr();
+			}, 500)
+		}
+	},
+	mounted() {
+		this.mescrollInitByRef(); // 兼容字节跳动小程序, 避免未设置@init或@init此时未能取到ref的情况
+	}
+	
+}
+
+export default MescrollMixin;

+ 64 - 0
node_modules/mescroll-uni/mescroll-uni-option.js

@@ -0,0 +1,64 @@
+// 全局配置
+// mescroll-body 和 mescroll-uni 通用
+const GlobalOption = {
+	down: {
+		// 其他down的配置参数也可以写,这里只展示了常用的配置:
+		offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调
+		native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)
+	},
+	up: {
+		// 其他up的配置参数也可以写,这里只展示了常用的配置:
+		offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance )
+		toTop: {
+			// 回到顶部按钮,需配置src才显示
+			src: "https://www.mescroll.com/img/mescroll-totop.png", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png )
+			offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px
+			right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
+			bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
+			width: 72 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
+		},
+		empty: {
+			use: true, // 是否显示空布局
+			icon: "https://www.mescroll.com/img/mescroll-empty.png" // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png )
+		}
+	},
+	// 国际化配置
+	i18n: {
+		// 中文
+		zh: {
+			down: {
+				textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本
+				textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本
+				textLoading: '加载中 ...', // 加载中的提示文本
+				textSuccess: '加载成功', // 加载成功的文本
+				textErr: '加载失败', // 加载失败的文本
+			},
+			up: {
+				textLoading: '加载中 ...', // 加载中的提示文本
+				textNoMore: '-- END --', // 没有更多数据的提示文本
+				empty: {
+					tip: '~ 空空如也 ~' // 空提示
+				}
+			}
+		},
+		// 英文
+		en: {
+			down: {
+				textInOffset: 'drop down refresh',
+				textOutOffset: 'release updates',
+				textLoading: 'loading ...',
+				textSuccess: 'loaded successfully',
+				textErr: 'loading failed'
+			},
+			up: {
+				textLoading: 'loading ...',
+				textNoMore: '-- END --',
+				empty: {
+					tip: '~ absolutely empty ~'
+				}
+			}
+		}
+	}
+}
+
+export default GlobalOption

+ 36 - 0
node_modules/mescroll-uni/mescroll-uni.css

@@ -0,0 +1,36 @@
+.mescroll-uni-warp{
+	height: 100%;
+}
+
+.mescroll-uni-content{
+	height: 100%;
+}
+
+.mescroll-uni {
+	position: relative;
+	width: 100%;
+	height: 100%;
+	min-height: 200rpx;
+	overflow-y: auto;
+	box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */
+}
+
+/* 定位的方式固定高度 */
+.mescroll-uni-fixed{
+	z-index: 1;
+	position: fixed;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	width: auto; /* 使right生效 */
+	height: auto; /* 使bottom生效 */
+}
+
+/* 适配 iPhoneX */
+@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
+	.mescroll-safearea {
+		padding-bottom: constant(safe-area-inset-bottom);
+		padding-bottom: env(safe-area-inset-bottom);
+	}
+}

+ 799 - 0
node_modules/mescroll-uni/mescroll-uni.js

@@ -0,0 +1,799 @@
+/* mescroll
+ * version 1.3.7
+ * 2021-04-13 wenju
+ * https://www.mescroll.com
+ */
+
+export default function MeScroll(options, isScrollBody) {
+	let me = this;
+	me.version = '1.3.7'; // mescroll版本号
+	me.options = options || {}; // 配置
+	me.isScrollBody = isScrollBody || false; // 滚动区域是否为原生页面滚动; 默认为scroll-view
+
+	me.isDownScrolling = false; // 是否在执行下拉刷新的回调
+	me.isUpScrolling = false; // 是否在执行上拉加载的回调
+	let hasDownCallback = me.options.down && me.options.down.callback; // 是否配置了down的callback
+
+	// 初始化下拉刷新
+	me.initDownScroll();
+	// 初始化上拉加载,则初始化
+	me.initUpScroll();
+
+	// 自动加载
+	setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例
+		// 自动触发下拉刷新 (只有配置了down的callback才自动触发下拉刷新)
+		if ((me.optDown.use || me.optDown.native) && me.optDown.auto && hasDownCallback) {
+			if (me.optDown.autoShowLoading) {
+				me.triggerDownScroll(); // 显示下拉进度,执行下拉回调
+			} else {
+				me.optDown.callback && me.optDown.callback(me); // 不显示下拉进度,直接执行下拉回调
+			}
+		}
+		// 自动触发上拉加载
+		if(!me.isUpAutoLoad){ // 部分小程序(头条小程序)emit是异步, 会导致isUpAutoLoad判断有误, 先延时确保先执行down的callback,再执行up的callback
+			setTimeout(function(){
+				me.optUp.use && me.optUp.auto && !me.isUpAutoLoad && me.triggerUpScroll();
+			},100)
+		}
+	}, 30); // 需让me.optDown.inited和me.optUp.inited先执行
+}
+
+/* 配置参数:下拉刷新 */
+MeScroll.prototype.extendDownScroll = function(optDown) {
+	// 下拉刷新的配置
+	MeScroll.extend(optDown, {
+		use: true, // 是否启用下拉刷新; 默认true
+		auto: true, // 是否在初始化完毕之后自动执行下拉刷新的回调; 默认true
+		native: false, // 是否使用系统自带的下拉刷新; 默认false; 仅mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)
+		autoShowLoading: false, // 如果设置auto=true(在初始化完毕之后自动执行下拉刷新的回调),那么是否显示下拉刷新的进度; 默认false
+		isLock: false, // 是否锁定下拉刷新,默认false;
+		offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调
+		startTop: 100, // scroll-view快速滚动到顶部时,此时的scroll-top可能大于0, 此值用于控制最大的误差
+		inOffsetRate: 1, // 在列表顶部,下拉的距离小于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉
+		outOffsetRate: 0.2, // 在列表顶部,下拉的距离大于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉
+		bottomOffset: 20, // 当手指touchmove位置在距离body底部20px范围内的时候结束上拉刷新,避免Webview嵌套导致touchend事件不执行
+		minAngle: 45, // 向下滑动最少偏移的角度,取值区间  [0,90];默认45度,即向下滑动的角度大于45度则触发下拉;而小于45度,将不触发下拉,避免与左右滑动的轮播等组件冲突;
+		textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本
+		textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本
+		textLoading: '加载中 ...', // 加载中的提示文本
+		textSuccess: '加载成功', // 加载成功的文本
+		textErr: '加载失败', // 加载失败的文本
+		beforeEndDelay: 0, // 延时结束的时长 (显示加载成功/失败的时长, android小程序设置此项结束下拉会卡顿, 配置后请注意测试)
+		bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorTop)
+		textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色)
+		inited: null, // 下拉刷新初始化完毕的回调
+		inOffset: null, // 下拉的距离进入offset范围内那一刻的回调
+		outOffset: null, // 下拉的距离大于offset那一刻的回调
+		onMoving: null, // 下拉过程中的回调,滑动过程一直在执行; rate下拉区域当前高度与指定距离的比值(inOffset: rate<1; outOffset: rate>=1); downHight当前下拉区域的高度
+		beforeLoading: null, // 准备触发下拉刷新的回调: 如果return true,将不触发showLoading和callback回调; 常用来完全自定义下拉刷新, 参考案例【淘宝 v6.8.0】
+		showLoading: null, // 显示下拉刷新进度的回调
+		afterLoading: null, // 显示下拉刷新进度的回调之后,马上要执行的代码 (如: 在wxs中使用)
+		beforeEndDownScroll: null, // 准备结束下拉的回调. 返回结束下拉的延时执行时间,默认0ms; 常用于结束下拉之前再显示另外一小段动画,才去隐藏下拉刷新的场景, 参考案例【dotJump】
+		endDownScroll: null, // 结束下拉刷新的回调
+		afterEndDownScroll: null, // 结束下拉刷新的回调,马上要执行的代码 (如: 在wxs中使用)
+		callback: function(mescroll) {
+			// 下拉刷新的回调;默认重置上拉加载列表为第一页
+			mescroll.resetUpScroll();
+		}
+	})
+}
+
+/* 配置参数:上拉加载 */
+MeScroll.prototype.extendUpScroll = function(optUp) {
+	// 上拉加载的配置
+	MeScroll.extend(optUp, {
+		use: true, // 是否启用上拉加载; 默认true
+		auto: true, // 是否在初始化完毕之后自动执行上拉加载的回调; 默认true
+		isLock: false, // 是否锁定上拉加载,默认false;
+		isBoth: true, // 上拉加载时,如果滑动到列表顶部是否可以同时触发下拉刷新;默认true,两者可同时触发;
+		callback: null, // 上拉加载的回调;function(page,mescroll){ }
+		page: {
+			num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
+			size: 10, // 每页数据的数量
+			time: null // 加载第一页数据服务器返回的时间; 防止用户翻页时,后台新增了数据从而导致下一页数据重复;
+		},
+		noMoreSize: 5, // 如果列表已无数据,可设置列表的总数量要大于等于5条才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看
+		offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance )
+		textLoading: '加载中 ...', // 加载中的提示文本
+		textNoMore: '-- END --', // 没有更多数据的提示文本
+		bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorBottom)
+		textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色)
+		inited: null, // 初始化完毕的回调
+		showLoading: null, // 显示加载中的回调
+		showNoMore: null, // 显示无更多数据的回调
+		hideUpScroll: null, // 隐藏上拉加载的回调
+		errDistance: 60, // endErr的时候需往上滑动一段距离,使其往下滑动时再次触发onReachBottom,仅mescroll-body生效
+		toTop: {
+			// 回到顶部按钮,需配置src才显示
+			src: null, // 图片路径,默认null (绝对路径或网络图)
+			offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000
+			duration: 300, // 回到顶部的动画时长,默认300ms (当值为0或300则使用系统自带回到顶部,更流畅; 其他值则通过step模拟,部分机型可能不够流畅,所以非特殊情况不建议修改此项)
+			btnClick: null, // 点击按钮的回调
+			onShow: null, // 是否显示的回调
+			zIndex: 9990, // fixed定位z-index值
+			left: null, // 到左边的距离, 默认null. 此项有值时,right不生效. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)
+			right: 20, // 到右边的距离, 默认20 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)
+			bottom: 120, // 到底部的距离, 默认120 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)
+			safearea: false, // bottom的偏移量是否加上底部安全区的距离, 默认false, 需要适配iPhoneX时使用 (具体的界面如果不配置此项,则取本vue的safearea值)
+			width: 72, // 回到顶部图标的宽度, 默认72 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)
+			radius: "50%" // 圆角, 默认"50%" (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx)
+		},
+		empty: {
+			use: true, // 是否显示空布局
+			icon: null, // 图标路径
+			tip: '~ 暂无相关数据 ~', // 提示
+			btnText: '', // 按钮
+			btnClick: null, // 点击按钮的回调
+			onShow: null, // 是否显示的回调
+			fixed: false, // 是否使用fixed定位,默认false; 配置fixed为true,以下的top和zIndex才生效 (transform会使fixed失效,最终会降级为absolute)
+			top: "100rpx", // fixed定位的top值 (完整的单位值,如 "10%"; "100rpx")
+			zIndex: 99 // fixed定位z-index值
+		},
+		onScroll: false // 是否监听滚动事件
+	})
+}
+
+/* 配置参数 */
+MeScroll.extend = function(userOption, defaultOption) {
+	if (!userOption) return defaultOption;
+	for (let key in defaultOption) {
+		if (userOption[key] == null) {
+			let def = defaultOption[key];
+			if (def != null && typeof def === 'object') {
+				userOption[key] = MeScroll.extend({}, def); // 深度匹配
+			} else {
+				userOption[key] = def;
+			}
+		} else if (typeof userOption[key] === 'object') {
+			MeScroll.extend(userOption[key], defaultOption[key]); // 深度匹配
+		}
+	}
+	return userOption;
+}
+
+/* 简单判断是否配置了颜色 (非透明,非白色) */
+MeScroll.prototype.hasColor = function(color) {
+	if(!color) return false;
+	let c = color.toLowerCase();
+	return c != "#fff" && c != "#ffffff" && c != "transparent" && c != "white"
+}
+
+/* -------初始化下拉刷新------- */
+MeScroll.prototype.initDownScroll = function() {
+	let me = this;
+	// 配置参数
+	me.optDown = me.options.down || {};
+	if(!me.optDown.textColor && me.hasColor(me.optDown.bgColor)) me.optDown.textColor = "#fff"; // 当bgColor有值且textColor未设置,则textColor默认白色
+	me.extendDownScroll(me.optDown);
+	
+	// 如果是mescroll-body且配置了native,则禁止自定义的下拉刷新
+	if(me.isScrollBody && me.optDown.native){
+		me.optDown.use = false
+	}else{
+		me.optDown.native = false // 仅mescroll-body支持,mescroll-uni不支持
+	}
+	
+	me.downHight = 0; // 下拉区域的高度
+
+	// 在页面中加入下拉布局
+	if (me.optDown.use && me.optDown.inited) {
+		// 初始化完毕的回调
+		setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例
+			me.optDown.inited(me);
+		}, 0)
+	}
+}
+
+/* 列表touchstart事件 */
+MeScroll.prototype.touchstartEvent = function(e) {
+	if (!this.optDown.use) return;
+
+	this.startPoint = this.getPoint(e); // 记录起点
+	this.startTop = this.getScrollTop(); // 记录此时的滚动条位置
+	this.startAngle = 0; // 初始角度
+	this.lastPoint = this.startPoint; // 重置上次move的点
+	this.maxTouchmoveY = this.getBodyHeight() - this.optDown.bottomOffset; // 手指触摸的最大范围(写在touchstart避免body获取高度为0的情况)
+	this.inTouchend = false; // 标记不是touchend
+}
+
+/* 列表touchmove事件 */
+MeScroll.prototype.touchmoveEvent = function(e) {
+	if (!this.optDown.use) return;
+	let me = this;
+
+	let scrollTop = me.getScrollTop(); // 当前滚动条的距离
+	let curPoint = me.getPoint(e); // 当前点
+
+	let moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉
+
+	// 向下拉 && 在顶部
+	// mescroll-body,直接判定在顶部即可
+	// scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove
+	// scroll-view滚动到顶部时,scrollTop不一定为0,也有可能大于0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等
+	if (moveY > 0 && (
+			(me.isScrollBody && scrollTop <= 0)
+			||
+			(!me.isScrollBody && (scrollTop <= 0 || (scrollTop <= me.optDown.startTop && scrollTop === me.startTop)) )
+		)) {
+		// 可下拉的条件
+		if (!me.inTouchend && !me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling &&
+				me.optUp.isBoth))) {
+
+			// 下拉的初始角度是否在配置的范围内
+			if(!me.startAngle) me.startAngle = me.getAngle(me.lastPoint, curPoint); // 两点之间的角度,区间 [0,90]
+			if (me.startAngle < me.optDown.minAngle) return; // 如果小于配置的角度,则不往下执行下拉刷新
+
+			// 如果手指的位置超过配置的距离,则提前结束下拉,避免Webview嵌套导致touchend无法触发
+			if (me.maxTouchmoveY > 0 && curPoint.y >= me.maxTouchmoveY) {
+				me.inTouchend = true; // 标记执行touchend
+				me.touchendEvent(); // 提前触发touchend
+				return;
+			}
+			
+			me.preventDefault(e); // 阻止默认事件
+
+			let diff = curPoint.y - me.lastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上)
+
+			// 下拉距离  < 指定距离
+			if (me.downHight < me.optDown.offset) {
+				if (me.movetype !== 1) {
+					me.movetype = 1; // 加入标记,保证只执行一次
+					me.isDownEndSuccess = null; // 重置是否加载成功的状态 (wxs执行的是wxs.wxs)
+					me.optDown.inOffset && me.optDown.inOffset(me); // 进入指定距离范围内那一刻的回调,只执行一次
+					me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来
+				}
+				me.downHight += diff * me.optDown.inOffsetRate; // 越往下,高度变化越小
+
+				// 指定距离  <= 下拉距离
+			} else {
+				if (me.movetype !== 2) {
+					me.movetype = 2; // 加入标记,保证只执行一次
+					me.optDown.outOffset && me.optDown.outOffset(me); // 下拉超过指定距离那一刻的回调,只执行一次
+					me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来
+				}
+				if (diff > 0) { // 向下拉
+					me.downHight += diff * me.optDown.outOffsetRate; // 越往下,高度变化越小
+				} else { // 向上收
+					me.downHight += diff; // 向上收回高度,则向上滑多少收多少高度
+				}
+			}
+			
+			me.downHight = Math.round(me.downHight) // 取整
+			let rate = me.downHight / me.optDown.offset; // 下拉区域当前高度与指定距离的比值
+			me.optDown.onMoving && me.optDown.onMoving(me, rate, me.downHight); // 下拉过程中的回调,一直在执行
+		}
+	}
+
+	me.lastPoint = curPoint; // 记录本次移动的点
+}
+
+/* 列表touchend事件 */
+MeScroll.prototype.touchendEvent = function(e) {
+	if (!this.optDown.use) return;
+	// 如果下拉区域高度已改变,则需重置回来
+	if (this.isMoveDown) {
+		if (this.downHight >= this.optDown.offset) {
+			// 符合触发刷新的条件
+			this.triggerDownScroll();
+		} else {
+			// 不符合的话 则重置
+			this.downHight = 0;
+			this.endDownScrollCall(this);
+		}
+		this.movetype = 0;
+		this.isMoveDown = false;
+	} else if (!this.isScrollBody && this.getScrollTop() === this.startTop) { // scroll-view到顶/左/右/底的滑动事件
+		let isScrollUp = this.getPoint(e).y - this.startPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉
+		// 上滑
+		if (isScrollUp) {
+			// 需检查滑动的角度
+			let angle = this.getAngle(this.getPoint(e), this.startPoint); // 两点之间的角度,区间 [0,90]
+			if (angle > 80) {
+				// 检查并触发上拉
+				this.triggerUpScroll(true);
+			}
+		}
+	}
+}
+
+/* 根据点击滑动事件获取第一个手指的坐标 */
+MeScroll.prototype.getPoint = function(e) {
+	if (!e) {
+		return {
+			x: 0,
+			y: 0
+		}
+	}
+	if (e.touches && e.touches[0]) {
+		return {
+			x: e.touches[0].pageX,
+			y: e.touches[0].pageY
+		}
+	} else if (e.changedTouches && e.changedTouches[0]) {
+		return {
+			x: e.changedTouches[0].pageX,
+			y: e.changedTouches[0].pageY
+		}
+	} else {
+		return {
+			x: e.clientX,
+			y: e.clientY
+		}
+	}
+}
+
+/* 计算两点之间的角度: 区间 [0,90]*/
+MeScroll.prototype.getAngle = function(p1, p2) {
+	let x = Math.abs(p1.x - p2.x);
+	let y = Math.abs(p1.y - p2.y);
+	let z = Math.sqrt(x * x + y * y);
+	let angle = 0;
+	if (z !== 0) {
+		angle = Math.asin(y / z) / Math.PI * 180;
+	}
+	return angle
+}
+
+/* 触发下拉刷新 */
+MeScroll.prototype.triggerDownScroll = function() {
+	if (this.optDown.beforeLoading && this.optDown.beforeLoading(this)) {
+		//return true则处于完全自定义状态
+	} else {
+		this.showDownScroll(); // 下拉刷新中...
+		!this.optDown.native && this.optDown.callback && this.optDown.callback(this); // 执行回调,联网加载数据
+	}
+}
+
+/* 显示下拉进度布局 */
+MeScroll.prototype.showDownScroll = function() {
+	this.isDownScrolling = true; // 标记下拉中
+	if (this.optDown.native) {
+		uni.startPullDownRefresh(); // 系统自带的下拉刷新
+		this.showDownLoadingCall(0); // 仍触发showLoading,因为上拉加载用到
+	} else{
+		this.downHight = this.optDown.offset; // 更新下拉区域高度
+		this.showDownLoadingCall(this.downHight); // 下拉刷新中...
+	}
+}
+
+MeScroll.prototype.showDownLoadingCall = function(downHight) {
+	this.optDown.showLoading && this.optDown.showLoading(this, downHight); // 下拉刷新中...
+	this.optDown.afterLoading && this.optDown.afterLoading(this, downHight); // 下拉刷新中...触发之后马上要执行的代码
+}
+
+/* 显示系统自带的下拉刷新时需要处理的业务 */
+MeScroll.prototype.onPullDownRefresh = function() {
+	this.isDownScrolling = true; // 标记下拉中
+	this.showDownLoadingCall(0); // 仍触发showLoading,因为上拉加载用到
+	this.optDown.callback && this.optDown.callback(this); // 执行回调,联网加载数据
+}
+
+/* 结束下拉刷新 */
+MeScroll.prototype.endDownScroll = function() {
+	if (this.optDown.native) { // 结束原生下拉刷新
+		this.isDownScrolling = false;
+		this.endDownScrollCall(this);
+		uni.stopPullDownRefresh();
+		return
+	}
+	let me = this;
+	// 结束下拉刷新的方法
+	let endScroll = function() {
+		me.downHight = 0;
+		me.isDownScrolling = false;
+		me.endDownScrollCall(me);
+		if(!me.isScrollBody){
+			me.setScrollHeight(0) // scroll-view重置滚动区域,使数据不满屏时仍可检查触发翻页
+			me.scrollTo(0,0) // scroll-view需重置滚动条到顶部,避免startTop大于0时,对下拉刷新的影响
+		}
+	}
+	// 结束下拉刷新时的回调
+	let delay = 0;
+	if (me.optDown.beforeEndDownScroll) {
+		delay = me.optDown.beforeEndDownScroll(me); // 结束下拉刷新的延时,单位ms
+		if(me.isDownEndSuccess == null) delay = 0; // 没有执行加载中,则不延时
+	}
+	if (typeof delay === 'number' && delay > 0) {
+		setTimeout(endScroll, delay);
+	} else {
+		endScroll();
+	}
+}
+
+MeScroll.prototype.endDownScrollCall = function() {
+	this.optDown.endDownScroll && this.optDown.endDownScroll(this);
+	this.optDown.afterEndDownScroll && this.optDown.afterEndDownScroll(this);
+}
+
+/* 锁定下拉刷新:isLock=ture,null锁定;isLock=false解锁 */
+MeScroll.prototype.lockDownScroll = function(isLock) {
+	if (isLock == null) isLock = true;
+	this.optDown.isLock = isLock;
+}
+
+/* 锁定上拉加载:isLock=ture,null锁定;isLock=false解锁 */
+MeScroll.prototype.lockUpScroll = function(isLock) {
+	if (isLock == null) isLock = true;
+	this.optUp.isLock = isLock;
+}
+
+/* -------初始化上拉加载------- */
+MeScroll.prototype.initUpScroll = function() {
+	let me = this;
+	// 配置参数
+	me.optUp = me.options.up || {use: false}
+	if(!me.optUp.textColor && me.hasColor(me.optUp.bgColor)) me.optUp.textColor = "#fff"; // 当bgColor有值且textColor未设置,则textColor默认白色
+	me.extendUpScroll(me.optUp);
+
+	if (me.optUp.use === false) return; // 配置不使用上拉加载时,则不初始化上拉布局
+	me.optUp.hasNext = true; // 如果使用上拉,则默认有下一页
+	me.startNum = me.optUp.page.num + 1; // 记录page开始的页码
+
+	// 初始化完毕的回调
+	if (me.optUp.inited) {
+		setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例
+			me.optUp.inited(me);
+		}, 0)
+	}
+}
+
+/*滚动到底部的事件 (仅mescroll-body生效)*/
+MeScroll.prototype.onReachBottom = function() {
+	if (this.isScrollBody && !this.isUpScrolling) { // 只能支持下拉刷新的时候同时可以触发上拉加载,否则滚动到底部就需要上滑一点才能触发onReachBottom
+		if (!this.optUp.isLock && this.optUp.hasNext) {
+			this.triggerUpScroll();
+		}
+	}
+}
+
+/*列表滚动事件 (仅mescroll-body生效)*/
+MeScroll.prototype.onPageScroll = function(e) {
+	if (!this.isScrollBody) return;
+	
+	// 更新滚动条的位置 (主要用于判断下拉刷新时,滚动条是否在顶部)
+	this.setScrollTop(e.scrollTop);
+
+	// 顶部按钮的显示隐藏
+	if (e.scrollTop >= this.optUp.toTop.offset) {
+		this.showTopBtn();
+	} else {
+		this.hideTopBtn();
+	}
+}
+
+/*列表滚动事件*/
+MeScroll.prototype.scroll = function(e, onScroll) {
+	// 更新滚动条的位置
+	this.setScrollTop(e.scrollTop);
+	// 更新滚动内容高度
+	this.setScrollHeight(e.scrollHeight);
+
+	// 向上滑还是向下滑动
+	if (this.preScrollY == null) this.preScrollY = 0;
+	this.isScrollUp = e.scrollTop - this.preScrollY > 0;
+	this.preScrollY = e.scrollTop;
+
+	// 上滑 && 检查并触发上拉
+	this.isScrollUp && this.triggerUpScroll(true);
+
+	// 顶部按钮的显示隐藏
+	if (e.scrollTop >= this.optUp.toTop.offset) {
+		this.showTopBtn();
+	} else {
+		this.hideTopBtn();
+	}
+
+	// 滑动监听
+	this.optUp.onScroll && onScroll && onScroll()
+}
+
+/* 触发上拉加载 */
+MeScroll.prototype.triggerUpScroll = function(isCheck) {
+	if (!this.isUpScrolling && this.optUp.use && this.optUp.callback) {
+		// 是否校验在底部; 默认不校验
+		if (isCheck === true) {
+			let canUp = false;
+			// 还有下一页 && 没有锁定 && 不在下拉中
+			if (this.optUp.hasNext && !this.optUp.isLock && !this.isDownScrolling) {
+				if (this.getScrollBottom() <= this.optUp.offset) { // 到底部
+					canUp = true; // 标记可上拉
+				}
+			}
+			if (canUp === false) return;
+		}
+		this.showUpScroll(); // 上拉加载中...
+		this.optUp.page.num++; // 预先加一页,如果失败则减回
+		this.isUpAutoLoad = true; // 标记上拉已经自动执行过,避免初始化时多次触发上拉回调
+		this.num = this.optUp.page.num; // 把最新的页数赋值在mescroll上,避免对page的影响
+		this.size = this.optUp.page.size; // 把最新的页码赋值在mescroll上,避免对page的影响
+		this.time = this.optUp.page.time; // 把最新的页码赋值在mescroll上,避免对page的影响
+		this.optUp.callback(this); // 执行回调,联网加载数据
+	}
+}
+
+/* 显示上拉加载中 */
+MeScroll.prototype.showUpScroll = function() {
+	this.isUpScrolling = true; // 标记上拉加载中
+	this.optUp.showLoading && this.optUp.showLoading(this); // 回调
+}
+
+/* 显示上拉无更多数据 */
+MeScroll.prototype.showNoMore = function() {
+	this.optUp.hasNext = false; // 标记无更多数据
+	this.optUp.showNoMore && this.optUp.showNoMore(this); // 回调
+}
+
+/* 隐藏上拉区域**/
+MeScroll.prototype.hideUpScroll = function() {
+	this.optUp.hideUpScroll && this.optUp.hideUpScroll(this); // 回调
+}
+
+/* 结束上拉加载 */
+MeScroll.prototype.endUpScroll = function(isShowNoMore) {
+	if (isShowNoMore != null) { // isShowNoMore=null,不处理下拉状态,下拉刷新的时候调用
+		if (isShowNoMore) {
+			this.showNoMore(); // isShowNoMore=true,显示无更多数据
+		} else {
+			this.hideUpScroll(); // isShowNoMore=false,隐藏上拉加载
+		}
+	}
+	this.isUpScrolling = false; // 标记结束上拉加载
+}
+
+/* 重置上拉加载列表为第一页
+ *isShowLoading 是否显示进度布局;
+ * 1.默认null,不传参,则显示上拉加载的进度布局
+ * 2.传参true, 则显示下拉刷新的进度布局
+ * 3.传参false,则不显示上拉和下拉的进度 (常用于静默更新列表数据)
+ */
+MeScroll.prototype.resetUpScroll = function(isShowLoading) {
+	if (this.optUp && this.optUp.use) {
+		let page = this.optUp.page;
+		this.prePageNum = page.num; // 缓存重置前的页码,加载失败可退回
+		this.prePageTime = page.time; // 缓存重置前的时间,加载失败可退回
+		page.num = this.startNum; // 重置为第一页
+		page.time = null; // 重置时间为空
+		if (!this.isDownScrolling && isShowLoading !== false) { // 如果不是下拉刷新触发的resetUpScroll并且不配置列表静默更新,则显示进度;
+			if (isShowLoading == null) {
+				this.removeEmpty(); // 移除空布局
+				this.showUpScroll(); // 不传参,默认显示上拉加载的进度布局
+			} else {
+				this.showDownScroll(); // 传true,显示下拉刷新的进度布局,不清空列表
+			}
+		}
+		this.isUpAutoLoad = true; // 标记上拉已经自动执行过,避免初始化时多次触发上拉回调
+		this.num = page.num; // 把最新的页数赋值在mescroll上,避免对page的影响
+		this.size = page.size; // 把最新的页码赋值在mescroll上,避免对page的影响
+		this.time = page.time; // 把最新的页码赋值在mescroll上,避免对page的影响
+		this.optUp.callback && this.optUp.callback(this); // 执行上拉回调
+	}
+}
+
+/* 设置page.num的值 */
+MeScroll.prototype.setPageNum = function(num) {
+	this.optUp.page.num = num - 1;
+}
+
+/* 设置page.size的值 */
+MeScroll.prototype.setPageSize = function(size) {
+	this.optUp.page.size = size;
+}
+
+/* 联网回调成功,结束下拉刷新和上拉加载
+ * dataSize: 当前页的数据量(必传)
+ * totalPage: 总页数(必传)
+ * systime: 服务器时间 (可空)
+ */
+MeScroll.prototype.endByPage = function(dataSize, totalPage, systime) {
+	let hasNext;
+	if (this.optUp.use && totalPage != null) hasNext = this.optUp.page.num < totalPage; // 是否还有下一页
+	this.endSuccess(dataSize, hasNext, systime);
+}
+
+/* 联网回调成功,结束下拉刷新和上拉加载
+ * dataSize: 当前页的数据量(必传)
+ * totalSize: 列表所有数据总数量(必传)
+ * systime: 服务器时间 (可空)
+ */
+MeScroll.prototype.endBySize = function(dataSize, totalSize, systime) {
+	let hasNext;
+	if (this.optUp.use && totalSize != null) {
+		let loadSize = (this.optUp.page.num - 1) * this.optUp.page.size + dataSize; // 已加载的数据总数
+		hasNext = loadSize < totalSize; // 是否还有下一页
+	}
+	this.endSuccess(dataSize, hasNext, systime);
+}
+
+/* 联网回调成功,结束下拉刷新和上拉加载
+ * dataSize: 当前页的数据个数(不是所有页的数据总和),用于上拉加载判断是否还有下一页.如果不传,则会判断还有下一页
+ * hasNext: 是否还有下一页,布尔类型;用来解决这个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据dataSize判断,则需翻到第三页才会知道无更多数据,如果传了hasNext,则翻到第二页即可显示无更多数据.
+ * systime: 服务器时间(可空);用来解决这个小问题:当准备翻下一页时,数据库新增了几条记录,此时翻下一页,前面的几条数据会和上一页的重复;这里传入了systime,那么upCallback的page.time就会有值,把page.time传给服务器,让后台过滤新加入的那几条记录
+ */
+MeScroll.prototype.endSuccess = function(dataSize, hasNext, systime) {
+	let me = this;
+	// 结束下拉刷新
+	if (me.isDownScrolling) {
+		me.isDownEndSuccess = true
+		me.endDownScroll();
+	}
+
+	// 结束上拉加载
+	if (me.optUp.use) {
+		let isShowNoMore; // 是否已无更多数据
+		if (dataSize != null) {
+			let pageNum = me.optUp.page.num; // 当前页码
+			let pageSize = me.optUp.page.size; // 每页长度
+			// 如果是第一页
+			if (pageNum === 1) {
+				if (systime) me.optUp.page.time = systime; // 设置加载列表数据第一页的时间
+			}
+			if (dataSize < pageSize || hasNext === false) {
+				// 返回的数据不满一页时,则说明已无更多数据
+				me.optUp.hasNext = false;
+				if (dataSize === 0 && pageNum === 1) {
+					// 如果第一页无任何数据且配置了空布局
+					isShowNoMore = false;
+					me.showEmpty();
+				} else {
+					// 总列表数少于配置的数量,则不显示无更多数据
+					let allDataSize = (pageNum - 1) * pageSize + dataSize;
+					if (allDataSize < me.optUp.noMoreSize) {
+						isShowNoMore = false;
+					} else {
+						isShowNoMore = true;
+					}
+					me.removeEmpty(); // 移除空布局
+				}
+			} else {
+				// 还有下一页
+				isShowNoMore = false;
+				me.optUp.hasNext = true;
+				me.removeEmpty(); // 移除空布局
+			}
+		}
+
+		// 隐藏上拉
+		me.endUpScroll(isShowNoMore);
+	}
+}
+
+/* 回调失败,结束下拉刷新和上拉加载 */
+MeScroll.prototype.endErr = function(errDistance) {
+	// 结束下拉,回调失败重置回原来的页码和时间
+	if (this.isDownScrolling) {
+		this.isDownEndSuccess = false
+		let page = this.optUp.page;
+		if (page && this.prePageNum) {
+			page.num = this.prePageNum;
+			page.time = this.prePageTime;
+		}
+		this.endDownScroll();
+	}
+	// 结束上拉,回调失败重置回原来的页码
+	if (this.isUpScrolling) {
+		this.optUp.page.num--;
+		this.endUpScroll(false);
+		// 如果是mescroll-body,则需往回滚一定距离
+		if(this.isScrollBody && errDistance !== 0){ // 不处理0
+			if(!errDistance) errDistance = this.optUp.errDistance; // 不传,则取默认
+			this.scrollTo(this.getScrollTop() - errDistance, 0) // 往上回滚的距离
+		}
+	}
+}
+
+/* 显示空布局 */
+MeScroll.prototype.showEmpty = function() {
+	this.optUp.empty.use && this.optUp.empty.onShow && this.optUp.empty.onShow(true)
+}
+
+/* 移除空布局 */
+MeScroll.prototype.removeEmpty = function() {
+	this.optUp.empty.use && this.optUp.empty.onShow && this.optUp.empty.onShow(false)
+}
+
+/* 显示回到顶部的按钮 */
+MeScroll.prototype.showTopBtn = function() {
+	if (!this.topBtnShow) {
+		this.topBtnShow = true;
+		this.optUp.toTop.onShow && this.optUp.toTop.onShow(true);
+	}
+}
+
+/* 隐藏回到顶部的按钮 */
+MeScroll.prototype.hideTopBtn = function() {
+	if (this.topBtnShow) {
+		this.topBtnShow = false;
+		this.optUp.toTop.onShow && this.optUp.toTop.onShow(false);
+	}
+}
+
+/* 获取滚动条的位置 */
+MeScroll.prototype.getScrollTop = function() {
+	return this.scrollTop || 0
+}
+
+/* 记录滚动条的位置 */
+MeScroll.prototype.setScrollTop = function(y) {
+	this.scrollTop = y;
+}
+
+/* 滚动到指定位置 */
+MeScroll.prototype.scrollTo = function(y, t) {
+	this.myScrollTo && this.myScrollTo(y, t) // scrollview需自定义回到顶部方法
+}
+
+/* 自定义scrollTo */
+MeScroll.prototype.resetScrollTo = function(myScrollTo) {
+	this.myScrollTo = myScrollTo
+}
+
+/* 滚动条到底部的距离 */
+MeScroll.prototype.getScrollBottom = function() {
+	return this.getScrollHeight() - this.getClientHeight() - this.getScrollTop()
+}
+
+/* 计步器
+ star: 开始值
+ end: 结束值
+ callback(step,timer): 回调step值,计步器timer,可自行通过window.clearInterval(timer)结束计步器;
+ t: 计步时长,传0则直接回调end值;不传则默认300ms
+ rate: 周期;不传则默认30ms计步一次
+ * */
+MeScroll.prototype.getStep = function(star, end, callback, t, rate) {
+	let diff = end - star; // 差值
+	if (t === 0 || diff === 0) {
+		callback && callback(end);
+		return;
+	}
+	t = t || 300; // 时长 300ms
+	rate = rate || 30; // 周期 30ms
+	let count = t / rate; // 次数
+	let step = diff / count; // 步长
+	let i = 0; // 计数
+	let timer = setInterval(function() {
+		if (i < count - 1) {
+			star += step;
+			callback && callback(star, timer);
+			i++;
+		} else {
+			callback && callback(end, timer); // 最后一次直接设置end,避免计算误差
+			clearInterval(timer);
+		}
+	}, rate);
+}
+
+/* 滚动容器的高度 */
+MeScroll.prototype.getClientHeight = function(isReal) {
+	let h = this.clientHeight || 0
+	if (h === 0 && isReal !== true) { // 未获取到容器的高度,可临时取body的高度 (可能会有误差)
+		h = this.getBodyHeight()
+	}
+	return h
+}
+MeScroll.prototype.setClientHeight = function(h) {
+	this.clientHeight = h;
+}
+
+/* 滚动内容的高度 */
+MeScroll.prototype.getScrollHeight = function() {
+	return this.scrollHeight || 0;
+}
+MeScroll.prototype.setScrollHeight = function(h) {
+	this.scrollHeight = h;
+}
+
+/* body的高度 */
+MeScroll.prototype.getBodyHeight = function() {
+	return this.bodyHeight || 0;
+}
+MeScroll.prototype.setBodyHeight = function(h) {
+	this.bodyHeight = h;
+}
+
+/* 阻止浏览器默认滚动事件 */
+MeScroll.prototype.preventDefault = function(e) {
+	// 小程序不支持e.preventDefault, 已在wxs中禁止
+	// app的bounce只能通过配置pages.json的style.app-plus.bounce为"none"来禁止, 或使用renderjs禁止
+	// cancelable:是否可以被禁用; defaultPrevented:是否已经被禁用
+	if (e && e.cancelable && !e.defaultPrevented) e.preventDefault()
+}

+ 480 - 0
node_modules/mescroll-uni/mescroll-uni.vue

@@ -0,0 +1,480 @@
+<template>
+	<view class="mescroll-uni-warp">
+		<scroll-view :id="viewId" class="mescroll-uni" :class="{'mescroll-uni-fixed':isFixed}" :style="{'height':scrollHeight,'padding-top':padTop,'padding-bottom':padBottom,'top':fixedTop,'bottom':fixedBottom}" :scroll-top="scrollTop" :scroll-with-animation="scrollAnim" @scroll="scroll" :scroll-y='scrollable' :enable-back-to-top="true" :throttle="false">
+			<view class="mescroll-uni-content mescroll-render-touch"
+			@touchstart="wxsBiz.touchstartEvent" 
+			@touchmove="wxsBiz.touchmoveEvent" 
+			@touchend="wxsBiz.touchendEvent" 
+			@touchcancel="wxsBiz.touchendEvent"
+			:change:prop="wxsBiz.propObserver"
+			:prop="wxsProp">
+				<!-- 状态栏 -->
+				<view v-if="topbar&&statusBarHeight" class="mescroll-topbar" :style="{height: statusBarHeight+'px', background: topbar}"></view>
+		
+				<view class="mescroll-wxs-content" :style="{'transform': translateY, 'transition': transition}" :change:prop="wxsBiz.callObserver" :prop="callProp">
+					<!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)-->
+					<!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> -->
+					<view v-if="mescroll.optDown.use" class="mescroll-downwarp" :style="{'background':mescroll.optDown.bgColor,'color':mescroll.optDown.textColor}">
+						<view class="downwarp-content">
+							<view class="downwarp-progress mescroll-wxs-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mescroll.optDown.textColor, 'transform': downRotate}"></view>
+							<view class="downwarp-tip">{{downText}}</view>
+						</view>
+					</view>
+
+					<!-- 列表内容 -->
+					<slot></slot>
+
+					<!-- 空布局 -->
+					<mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty>
+
+					<!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)-->
+					<!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> -->
+					<view v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" class="mescroll-upwarp" :style="{'background':mescroll.optUp.bgColor,'color':mescroll.optUp.textColor}">
+						<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
+						<view v-show="upLoadType===1">
+							<view class="upwarp-progress mescroll-rotate" :style="{'border-color':mescroll.optUp.textColor}"></view>
+							<view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view>
+						</view>
+						<!-- 无数据 -->
+						<view v-if="upLoadType===2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view>
+					</view>
+				</view>
+			
+				<!-- 底部是否偏移TabBar的高度(默认仅在H5端的tab页生效) -->
+				<!-- #ifdef H5 -->
+				<view v-if="bottombar && windowBottom>0" class="mescroll-bottombar" :style="{height: windowBottom+'px'}"></view>
+				<!-- #endif -->
+				
+				<!-- 适配iPhoneX -->
+				<view v-if="safearea" class="mescroll-safearea"></view>
+			</view>
+		</scroll-view>
+
+		<!-- 回到顶部按钮 (fixed元素,需写在scroll-view外面,防止滚动的时候抖动)-->
+		<mescroll-top v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick"></mescroll-top>
+		
+		<!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 -->
+		<!-- renderjs的数据载体,不可写在mescroll-downwarp内部,避免use为false时,载体丢失,无法更新数据 -->
+		<view :change:prop="renderBiz.propObserver" :prop="wxsProp"></view>
+		<!-- #endif -->
+	</view>
+</template>
+
+<!-- 微信小程序, QQ小程序, app, h5使用wxs -->
+<!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 -->
+<script src="./wxs/wxs.wxs" module="wxsBiz" lang="wxs"></script>
+<!-- #endif -->
+
+<!-- app, h5使用renderjs -->
+<!-- #ifdef APP-PLUS || H5 -->
+<script module="renderBiz" lang="renderjs">
+	import renderBiz from './wxs/renderjs.js';
+	export default {
+		mixins:[renderBiz]
+	}
+</script>
+<!-- #endif -->
+
+<script>
+	// 引入mescroll-uni.js,处理核心逻辑
+	import MeScroll from './mescroll-uni.js';
+	// 引入全局配置
+	import GlobalOption from './mescroll-uni-option.js';
+	// 引入空布局组件
+	import MescrollEmpty from './components/mescroll-empty.vue';
+	// 引入国际化工具类
+	import mescrollI18n from './mescroll-i18n.js';
+	// 引入回到顶部组件
+	import MescrollTop from './components/mescroll-top.vue';
+	// 引入兼容wxs(含renderjs)写法的mixins
+	import WxsMixin from './wxs/mixins.js';
+	
+	/**
+	 * mescroll-uni 嵌在页面某个区域的下拉刷新和上拉加载组件, 如嵌在弹窗,浮层,swiper中...
+	 * @property {Object} down 下拉刷新的参数配置
+	 * @property {Object} up 上拉加载的参数配置
+	 * @property {Object} i18n 国际化的参数配置
+	 * @property {String, Number} top 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
+	 * @property {Boolean, String} topbar 偏移量top是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可留出状态栏的占位, 支持传入字符串背景,如色值,背景图,渐变)
+	 * @property {String, Number} bottom 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
+	 * @property {Boolean} safearea 偏移量bottom是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用)
+	 * @property {Boolean} fixed 是否通过fixed固定mescroll的高度, 默认true
+	 * @property {String, Number} height 指定mescroll的高度, 此项有值,则不使用fixed. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
+	 * @property {Boolean} bottombar 底部是否偏移TabBar的高度 (仅在H5端的tab页生效)
+	 * @property {Boolean} disableScroll 是否禁止滚动, 默认false
+	 * @event {Function} init 初始化完成的回调 
+	 * @event {Function} down 下拉刷新的回调
+	 * @event {Function} up 上拉加载的回调 
+	 * @event {Function} emptyclick 点击empty配置的btnText按钮回调
+	 * @event {Function} topclick 点击回到顶部的按钮回调
+	 * @event {Function} scroll 滚动监听 (需在 up 配置 onScroll:true 才生效)
+	 * @example <mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback"> ... </mescroll-uni>
+	 */
+	export default {
+		name: 'mescroll-uni',
+		mixins: [WxsMixin],
+		components: {
+			MescrollEmpty,
+			MescrollTop
+		},
+		props: {
+			down: Object,
+			up: Object,
+			i18n: Object,
+			top: [String, Number],
+			topbar: [Boolean, String],
+			bottom: [String, Number],
+			safearea: Boolean,
+			fixed: {
+				type: Boolean,
+				default: true
+			},
+			height: [String, Number],
+			bottombar:{
+				type: Boolean,
+				default: true
+			},
+			disableScroll: Boolean
+		},
+		data() {
+			return {
+				mescroll: {optDown:{},optUp:{}}, // mescroll实例
+				viewId: 'id_' + Math.random().toString(36).substr(2,16), // 随机生成mescroll的id(不能数字开头,否则找不到元素)
+				downHight: 0, //下拉刷新: 容器高度
+				downRate: 0, // 下拉比率(inOffset: rate<1; outOffset: rate>=1)
+				downLoadType: 0, // 下拉刷新状态: 0(loading前), 1(inOffset), 2(outOffset), 3(showLoading), 4(endDownScroll)
+				upLoadType: 0, // 上拉加载状态: 0(loading前), 1loading中, 2没有更多了,显示END文本提示, 3(没有更多了,不显示END文本提示)
+				isShowEmpty: false, // 是否显示空布局
+				isShowToTop: false, // 是否显示回到顶部按钮
+				scrollTop: 0, // 滚动条的位置
+				scrollAnim: false, // 是否开启滚动动画
+				windowTop: 0, // 可使用窗口的顶部位置
+				windowBottom: 0, // 可使用窗口的底部位置
+				windowHeight: 0, // 可使用窗口的高度
+				statusBarHeight: 0 // 状态栏高度
+			}
+		},
+		computed: {
+			// 是否使用fixed定位 (当height有值,则不使用)
+			isFixed(){
+				return !this.height && this.fixed
+			},
+			// mescroll的高度
+			scrollHeight(){
+				if (this.isFixed) {
+					return "auto"
+				} else if(this.height){
+					return this.toPx(this.height) + 'px'
+				}else{
+					return "100%"
+				}
+			},
+			// 下拉布局往下偏移的距离 (px)
+			numTop() {
+				return this.toPx(this.top)
+			},
+			fixedTop() {
+				return this.isFixed ? (this.numTop + this.windowTop) + 'px' : 0
+			},
+			padTop() {
+				return !this.isFixed ? this.numTop + 'px' : 0
+			},
+			// 上拉布局往上偏移 (px)
+			numBottom() {
+				return this.toPx(this.bottom)
+			},
+			fixedBottom() {
+				return this.isFixed ? (this.numBottom + this.windowBottom) + 'px' : 0
+			},
+			padBottom() {
+				return !this.isFixed ? this.numBottom + 'px' : 0
+			},
+			// 是否为重置下拉的状态
+			isDownReset(){
+				return this.downLoadType===3 || this.downLoadType===4
+			},
+			// 过渡
+			transition() {
+				return this.isDownReset ? 'transform 300ms' : '';
+			},
+			translateY() {
+				return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' : ''; // transform会使fixed失效,需注意把fixed元素写在mescroll之外
+			},
+			// 列表是否可滑动
+			scrollable(){
+				if(this.disableScroll) return false
+				return this.downLoadType===0 || this.isDownReset
+			},
+			// 是否在加载中
+			isDownLoading(){
+				return this.downLoadType === 3
+			},
+			// 旋转的角度
+			downRotate(){
+				return 'rotate(' + 360 * this.downRate + 'deg)'
+			},
+			// 文本提示
+			downText(){
+				if(!this.mescroll) return ""; // 避免头条小程序初始化时报错
+				switch (this.downLoadType){
+					case 1: return this.mescroll.optDown.textInOffset;
+					case 2: return this.mescroll.optDown.textOutOffset;
+					case 3: return this.mescroll.optDown.textLoading;
+					case 4: return this.mescroll.isDownEndSuccess ? this.mescroll.optDown.textSuccess : this.mescroll.isDownEndSuccess==false ? this.mescroll.optDown.textErr : this.mescroll.optDown.textInOffset;
+					default: return this.mescroll.optDown.textInOffset;
+				}
+			}
+		},
+		methods: {
+			//number,rpx,upx,px,% --> px的数值
+			toPx(num){
+				if(typeof num === "string"){
+					if (num.indexOf('px') !== -1) {
+						if(num.indexOf('rpx') !== -1) { // "10rpx"
+							num = num.replace('rpx', '');
+						} else if(num.indexOf('upx') !== -1) { // "10upx"
+							num = num.replace('upx', '');
+						} else { // "10px"
+							return Number(num.replace('px', ''))
+						}
+					}else if (num.indexOf('%') !== -1){
+						// 传百分比,则相对于windowHeight,传"10%"则等于windowHeight的10%
+						let rate = Number(num.replace("%","")) / 100
+						return this.windowHeight * rate
+					}
+				}
+				return num ? uni.upx2px(Number(num)) : 0
+			},
+			//注册列表滚动事件,用于下拉刷新和上拉加载
+			scroll(e) {
+				this.mescroll.scroll(e.detail, () => {
+					this.$emit('scroll', this.mescroll) // 此时可直接通过 this.mescroll.scrollTop获取滚动条位置; this.mescroll.isScrollUp获取是否向上滑动
+				})
+			},
+			// 点击空布局的按钮回调
+			emptyClick() {
+				this.$emit('emptyclick', this.mescroll)
+			},
+			// 点击回到顶部的按钮回调
+			toTopClick() {
+				this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); // 执行回到顶部
+				this.$emit('topclick', this.mescroll); // 派发点击回到顶部按钮的回调
+			},
+			// 更新滚动区域的高度 (使内容不满屏和到底,都可继续翻页)
+			setClientHeight() {
+				if (this.mescroll.getClientHeight(true) === 0 && !this.isExec) {
+					this.isExec = true; // 避免多次获取
+					this.$nextTick(() => { // 确保dom已渲染
+						this.getClientInfo(data=>{
+							this.isExec = false;
+							if (data) {
+								this.mescroll.setClientHeight(data.height);
+							} else if (this.clientNum != 3) { // 极少部分情况,可能dom还未渲染完毕,递归获取,最多重试3次
+								this.clientNum = this.clientNum == null ? 1 : this.clientNum + 1;
+								setTimeout(() => {
+									this.setClientHeight()
+								}, this.clientNum * 100)
+							}
+						})
+					})
+				}
+			},
+			// 获取滚动区域的信息
+			getClientInfo(success){
+				let query = uni.createSelectorQuery();
+				// #ifndef MP-ALIPAY || MP-DINGTALK
+				query = query.in(this) // 支付宝小程序不支持in(this),而字节跳动小程序必须写in(this), 否则都取不到值
+				// #endif
+				let view = query.select('#' + this.viewId);
+				view.boundingClientRect(data => {
+					success(data)
+				}).exec();
+			}
+		},
+		// 使用created初始化mescroll对象; 如果用mounted部分css样式编译到H5会失效
+		created() {
+			let vm = this;
+
+			let diyOption = {
+				// 下拉刷新的配置
+				down: {
+					inOffset() {
+						vm.downLoadType = 1; // 下拉的距离进入offset范围内那一刻的回调 (自定义mescroll组件时,此行不可删)
+					},
+					outOffset() {
+						vm.downLoadType = 2; // 下拉的距离大于offset那一刻的回调 (自定义mescroll组件时,此行不可删)
+					},
+					onMoving(mescroll, rate, downHight) {
+						// 下拉过程中的回调,滑动过程一直在执行;
+						vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
+						vm.downRate = rate; //下拉比率 (inOffset: rate<1; outOffset: rate>=1)
+					},
+					showLoading(mescroll, downHight) {
+						vm.downLoadType = 3; // 显示下拉刷新进度的回调 (自定义mescroll组件时,此行不可删)
+						vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
+					},
+					beforeEndDownScroll(mescroll){
+						vm.downLoadType = 4; 
+						return mescroll.optDown.beforeEndDelay // 延时结束的时长
+					},
+					endDownScroll() {
+						vm.downLoadType = 4; // 结束下拉 (自定义mescroll组件时,此行不可删)
+						vm.downHight = 0; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
+						vm.downResetTimer && clearTimeout(vm.downResetTimer)
+						vm.downResetTimer = setTimeout(()=>{ // 过渡动画执行完毕后,需重置为0的状态,以便置空this.transition,避免iOS小程序列表渲染不完整
+							if(vm.downLoadType===4) vm.downLoadType = 0
+						},300)
+					},
+					// 派发下拉刷新的回调
+					callback: function(mescroll) {
+						vm.$emit('down', mescroll)
+					}
+				},
+				// 上拉加载的配置
+				up: {
+					// 显示加载中的回调
+					showLoading() {
+						vm.upLoadType = 1;
+					},
+					// 显示无更多数据的回调
+					showNoMore() {
+						vm.upLoadType = 2;
+					},
+					// 隐藏上拉加载的回调
+					hideUpScroll(mescroll) {
+						vm.upLoadType = mescroll.optUp.hasNext ? 0 : 3;
+					},
+					// 空布局
+					empty: {
+						onShow(isShow) { // 显示隐藏的回调
+							vm.isShowEmpty = isShow;
+						}
+					},
+					// 回到顶部
+					toTop: {
+						onShow(isShow) { // 显示隐藏的回调
+							vm.isShowToTop = isShow;
+						}
+					},
+					// 派发上拉加载的回调
+					callback: function(mescroll) {
+						vm.$emit('up', mescroll);
+						// 更新容器的高度 (多mescroll的情况)
+						vm.setClientHeight()
+					}
+				}
+			}
+
+			let i18nType = mescrollI18n.getType() // 当前语言类型
+			let i18nOption = {type: i18nType} // 国际化配置
+			MeScroll.extend(i18nOption, vm.i18n) // 具体页面的国际化配置
+			MeScroll.extend(i18nOption, GlobalOption.i18n) // 全局的国际化配置
+			MeScroll.extend(diyOption, i18nOption[i18nType]); // 混入国际化配置
+			MeScroll.extend(diyOption, {down:GlobalOption.down, up:GlobalOption.up}); // 混入全局的配置
+			let myOption = JSON.parse(JSON.stringify({'down': vm.down,'up': vm.up})) // 深拷贝,避免对props的影响
+			MeScroll.extend(myOption, diyOption); // 混入具体界面的配置
+
+			// 初始化MeScroll对象
+			vm.mescroll = new MeScroll(myOption);
+			vm.mescroll.viewId = vm.viewId; // 附带id
+			vm.mescroll.i18n = i18nOption; // 挂载语言包
+			// init回调mescroll对象
+			vm.$emit('init', vm.mescroll);
+			
+			// 设置高度
+			const sys = uni.getSystemInfoSync();
+			if(sys.windowTop) vm.windowTop = sys.windowTop;
+			if(sys.windowBottom) vm.windowBottom = sys.windowBottom;
+			if(sys.windowHeight) vm.windowHeight = sys.windowHeight;
+			if(sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight;
+			// 使down的bottomOffset生效
+			vm.mescroll.setBodyHeight(sys.windowHeight);
+
+			// 因为使用的是scrollview,这里需自定义scrollTo
+			vm.mescroll.resetScrollTo((y, t) => {
+				vm.scrollAnim = (t !== 0); // t为0,则不使用动画过渡
+				if(typeof y === 'string'){
+					// 小程序不支持slot里面的scroll-into-view, 统一使用计算的方式实现
+					vm.getClientInfo(function(rect){
+						let mescrollTop = rect.top // mescroll到顶部的距离
+						let selector;
+						if(y.indexOf('#')==-1 && y.indexOf('.')==-1){
+							selector = '#'+y // 不带#和. 则默认为id选择器
+						}else{
+							selector = y
+							// #ifdef APP-PLUS || H5 || MP-ALIPAY || MP-DINGTALK
+							if(y.indexOf('>>>')!=-1){ // 不支持跨自定义组件的后代选择器 (转为普通的选择器即可跨组件查询)
+								selector = y.split('>>>')[1].trim()
+							}
+							// #endif
+						}
+						uni.createSelectorQuery().select(selector).boundingClientRect(function(rect){
+							if (rect) {
+								let curY = vm.mescroll.getScrollTop()
+								let top = rect.top - mescrollTop
+								top += curY
+								if(!vm.isFixed) top -= vm.numTop
+								vm.scrollTop = curY;
+								vm.$nextTick(function() {
+									vm.scrollTop = top
+								})
+							} else{
+								console.error(selector + ' does not exist');
+							}
+						}).exec()
+					})
+					return;
+				}
+				let curY = vm.mescroll.getScrollTop()
+				if (t === 0 || t === 300) { // 当t使用默认配置的300时,则使用系统自带的动画过渡
+					vm.scrollTop = curY;
+					vm.$nextTick(function() {
+						vm.scrollTop = y
+					})
+				} else {
+					vm.mescroll.getStep(curY, y, step => { // 此写法可支持配置t
+						vm.scrollTop = step
+					}, t)
+				}
+			})
+			
+			// 具体的界面如果不配置up.toTop.safearea,则取本vue的safearea值
+			if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {} else {
+				vm.mescroll.optUp.toTop.safearea = vm.safearea;
+			}
+			
+			// 全局配置监听
+			uni.$on("setMescrollGlobalOption", options=>{
+				if(!options) return;
+				let i18nType = options.i18n ? options.i18n.type : null
+				if(i18nType && vm.mescroll.i18n.type != i18nType){
+					vm.mescroll.i18n.type = i18nType
+					mescrollI18n.setType(i18nType)
+					MeScroll.extend(options, vm.mescroll.i18n[i18nType])
+				}
+				if(options.down){
+					let down = MeScroll.extend({}, options.down)
+					vm.mescroll.optDown = MeScroll.extend(down, vm.mescroll.optDown)
+				}
+				if(options.up){
+					let up = MeScroll.extend({}, options.up)
+					vm.mescroll.optUp = MeScroll.extend(up, vm.mescroll.optUp)
+				}
+			})
+		},
+		mounted() {
+			// 设置容器的高度
+			this.setClientHeight()
+		},
+		destroyed() {
+			// 注销全局配置监听
+			uni.$off("setMescrollGlobalOption")
+		}
+	}
+</script>
+
+<style>
+	@import "./mescroll-uni.css";
+	@import "./components/mescroll-down.css";
+	@import './components/mescroll-up.css';
+</style>

+ 47 - 0
node_modules/mescroll-uni/mixins/mescroll-comp.js

@@ -0,0 +1,47 @@
+/**
+ * mescroll-body写在子组件时,需通过mescroll的mixins补充子组件缺少的生命周期
+ */
+const MescrollCompMixin = {
+	// 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 (一级)
+	onPageScroll(e) {
+		this.handlePageScroll(e)
+	},
+	onReachBottom() {
+		this.handleReachBottom()
+	},
+	// 当down的native: true时, 还需传递此方法进到子组件
+	onPullDownRefresh(){
+		this.handlePullDownRefresh()
+	},
+	data() {
+		return {
+			mescroll: { // mescroll-body写在子子子...组件的情况 (多级)
+				onPageScroll: e=>{
+					this.handlePageScroll(e)
+				},
+				onReachBottom: ()=>{
+					this.handleReachBottom()
+				},
+				onPullDownRefresh: ()=>{
+					this.handlePullDownRefresh()
+				}
+			}
+		}
+	},
+	methods:{
+		handlePageScroll(e){
+			let item = this.$refs["mescrollItem"];
+			if(item && item.mescroll) item.mescroll.onPageScroll(e);
+		},
+		handleReachBottom(){
+			let item = this.$refs["mescrollItem"];
+			if(item && item.mescroll) item.mescroll.onReachBottom();
+		},
+		handlePullDownRefresh(){
+			let item = this.$refs["mescrollItem"];
+			if(item && item.mescroll) item.mescroll.onPullDownRefresh();
+		}
+	}
+}
+
+export default MescrollCompMixin;

+ 66 - 0
node_modules/mescroll-uni/mixins/mescroll-more-item.js

@@ -0,0 +1,66 @@
+/**
+ * mescroll-more-item的mixins, 仅在多个 mescroll-body 写在子组件时使用 (参考 mescroll-more 案例)
+ */
+const MescrollMoreItemMixin = {
+	// 支付宝小程序不支持props的mixin,需写在具体的页面中
+	// #ifndef MP-ALIPAY || MP-DINGTALK
+	props:{
+		i: Number, // 每个tab页的专属下标
+		index: { // 当前tab的下标
+			type: Number,
+			default(){
+				return 0
+			}
+		}
+	},
+	// #endif
+	data() {
+		return {
+			downOption:{
+				auto:false // 不自动加载
+			},
+			upOption:{
+				auto:false // 不自动加载
+			},
+			isInit: false // 当前tab是否已初始化
+		}
+	},
+	watch:{
+		// 监听下标的变化
+		index(val){
+			if (this.i === val && !this.isInit) this.mescrollTrigger()
+		}
+	},
+	methods: {
+		// 以ref的方式初始化mescroll对象 (兼容字节跳动小程序)
+		mescrollInitByRef() {
+			if(!this.mescroll || !this.mescroll.resetUpScroll){
+				// 字节跳动小程序编辑器不支持一个页面存在相同的ref, 多mescroll的ref需动态生成, 格式为'mescrollRef下标'
+				let mescrollRef = this.$refs.mescrollRef || this.$refs['mescrollRef'+this.i];
+				if(mescrollRef) this.mescroll = mescrollRef.mescroll
+			}
+		},
+		// mescroll组件初始化的回调,可获取到mescroll对象 (覆盖mescroll-mixins.js的mescrollInit, 为了标记isInit)
+		mescrollInit(mescroll) {
+			this.mescroll = mescroll;
+			this.mescrollInitByRef && this.mescrollInitByRef(); // 兼容字节跳动小程序
+			// 自动加载当前tab的数据
+			if(this.i === this.index){
+				this.mescrollTrigger()
+			}
+		},
+		// 主动触发加载
+		mescrollTrigger(){
+			this.isInit = true; // 标记为true
+			if (this.mescroll) {
+				if (this.mescroll.optDown.use) {
+					this.mescroll.triggerDownScroll();
+				} else{
+					this.mescroll.triggerUpScroll();
+				}
+			}
+		}
+	}
+}
+
+export default MescrollMoreItemMixin;

+ 74 - 0
node_modules/mescroll-uni/mixins/mescroll-more.js

@@ -0,0 +1,74 @@
+/**
+ * mescroll-body写在子组件时, 需通过mescroll的mixins补充子组件缺少的生命周期
+ */
+const MescrollMoreMixin = {
+	data() {
+		return {
+			tabIndex: 0, // 当前tab下标
+			mescroll: { // mescroll-body写在子子子...组件的情况 (多级)
+				onPageScroll: e=>{
+					this.handlePageScroll(e)
+				},
+				onReachBottom: ()=>{
+					this.handleReachBottom()
+				},
+				onPullDownRefresh: ()=>{
+					this.handlePullDownRefresh()
+				}
+			}
+		}
+	},
+	// 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件
+	onPageScroll(e) {
+		this.handlePageScroll(e)
+	},
+	onReachBottom() {
+		this.handleReachBottom()
+	},
+	// 当down的native: true时, 还需传递此方法进到子组件
+	onPullDownRefresh(){
+		this.handlePullDownRefresh()
+	},
+	methods:{
+		handlePageScroll(e){
+			let mescroll = this.getMescroll(this.tabIndex);
+			mescroll && mescroll.onPageScroll(e);
+		},
+		handleReachBottom(){
+			let mescroll = this.getMescroll(this.tabIndex);
+			mescroll && mescroll.onReachBottom();
+		},
+		handlePullDownRefresh(){
+			let mescroll = this.getMescroll(this.tabIndex);
+			mescroll && mescroll.onPullDownRefresh();
+		},
+		// 根据下标获取对应子组件的mescroll
+		getMescroll(i){
+			if(!this.mescrollItems) this.mescrollItems = [];
+			if(!this.mescrollItems[i]) {
+				// v-for中的refs
+				let vForItem = this.$refs["mescrollItem"];
+				if(vForItem){
+					this.mescrollItems[i] = vForItem[i]
+				}else{
+					// 普通的refs,不可重复
+					this.mescrollItems[i] = this.$refs["mescrollItem"+i];
+				}
+			}
+			let item = this.mescrollItems[i]
+			return item ? item.mescroll : null
+		},
+		// 切换tab,恢复滚动条位置
+		tabChange(i){
+			let mescroll = this.getMescroll(i);
+			if(mescroll){
+				// 延时(比$nextTick靠谱一些),确保元素已渲染
+				setTimeout(()=>{
+					mescroll.scrollTo(mescroll.getScrollTop(),0)
+				},30)
+			}
+		}
+	}
+}
+
+export default MescrollMoreMixin;

+ 39 - 0
node_modules/mescroll-uni/package.json

@@ -0,0 +1,39 @@
+{
+  "_from": "mescroll-uni",
+  "_id": "mescroll-uni@1.3.7",
+  "_inBundle": false,
+  "_integrity": "sha512-1pQMtGA+iVRKhfJZZNXdBx05NnthIk6zm3hRbumswSA54eaKOMgpUDb9AQ2+rRdXmS6kLkEYSbW/fkb7/IyoAg==",
+  "_location": "/mescroll-uni",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "mescroll-uni",
+    "name": "mescroll-uni",
+    "escapedName": "mescroll-uni",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/mescroll-uni/-/mescroll-uni-1.3.7.tgz",
+  "_shasum": "6b31114c92162315dfd2ac2e7809c2eacd15dc91",
+  "_spec": "mescroll-uni",
+  "_where": "C:\\Users\\Administrator\\Desktop\\项目\\直播\\liveH5-v3",
+  "author": {
+    "name": "wenju"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "mescroll的uni-app版本:【wxs+renderjs实现】高性能的下拉刷新上拉加载组件",
+  "license": "MIT",
+  "main": "mescroll-uni.vue",
+  "name": "mescroll-uni",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "version": "1.3.7"
+}

+ 109 - 0
node_modules/mescroll-uni/wxs/mixins.js

@@ -0,0 +1,109 @@
+// 定义在wxs (含renderjs) 逻辑层的数据和方法, 与视图层相互通信
+const WxsMixin = {
+	data() {
+		return {
+			// 传入wxs视图层的数据 (响应式)
+			wxsProp: {
+				optDown:{}, // 下拉刷新的配置
+				scrollTop:0, // 滚动条的距离
+				bodyHeight:0, // body的高度
+				isDownScrolling:false, // 是否正在下拉刷新中
+				isUpScrolling:false, // 是否正在上拉加载中
+				isScrollBody:true, // 是否为mescroll-body滚动
+				isUpBoth:true, // 上拉加载时,是否同时可以下拉刷新
+				t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer)
+			},
+			
+			// 标记调用wxs视图层的方法
+			callProp: {
+				callType: '', // 方法名
+				t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer)
+			},
+			
+			// 不用wxs的平台使用此处的wxsBiz对象,抹平wxs的写法 (微信小程序和APP使用的wxsBiz对象是./wxs/wxs.wxs)
+			// #ifndef MP-WEIXIN || MP-QQ || APP-PLUS || H5
+			wxsBiz: {
+				//注册列表touchstart事件,用于下拉刷新
+				touchstartEvent: e=> {
+					this.mescroll.touchstartEvent(e);
+				},
+				//注册列表touchmove事件,用于下拉刷新
+				touchmoveEvent: e=> {
+					this.mescroll.touchmoveEvent(e);
+				},
+				//注册列表touchend事件,用于下拉刷新
+				touchendEvent: e=> {
+					this.mescroll.touchendEvent(e);
+				},
+				propObserver(){}, // 抹平wxs的写法
+				callObserver(){} // 抹平wxs的写法
+			},
+			// #endif
+			
+			// 不用renderjs的平台使用此处的renderBiz对象,抹平renderjs的写法 (app 和 h5 使用的renderBiz对象是./wxs/renderjs.js)
+			// #ifndef APP-PLUS || H5
+			renderBiz: {
+				propObserver(){} // 抹平renderjs的写法
+			}
+			// #endif
+		}
+	},
+	methods: {
+		// wxs视图层调用逻辑层的回调
+		wxsCall(msg){
+			if(msg.type === 'setWxsProp'){
+				// 更新wxsProp数据 (值改变才触发更新)
+				this.wxsProp = {
+					optDown: this.mescroll.optDown,
+					scrollTop: this.mescroll.getScrollTop(),
+					bodyHeight: this.mescroll.getBodyHeight(),
+					isDownScrolling: this.mescroll.isDownScrolling,
+					isUpScrolling: this.mescroll.isUpScrolling,
+					isUpBoth: this.mescroll.optUp.isBoth,
+					isScrollBody:this.mescroll.isScrollBody,
+					t: Date.now()
+				}
+			}else if(msg.type === 'setLoadType'){
+				// 设置inOffset,outOffset的状态
+				this.downLoadType = msg.downLoadType
+				// 状态挂载到mescroll对象, 以便在其他组件中使用, 比如<me-video>中
+				this.$set(this.mescroll, 'downLoadType', this.downLoadType)
+				// 重置是否加载成功的状态
+				this.$set(this.mescroll, 'isDownEndSuccess', null)
+			}else if(msg.type === 'triggerDownScroll'){
+				// 主动触发下拉刷新
+				this.mescroll.triggerDownScroll();
+			}else if(msg.type === 'endDownScroll'){
+				// 结束下拉刷新
+				this.mescroll.endDownScroll();
+			}else if(msg.type === 'triggerUpScroll'){
+				// 主动触发上拉加载
+				this.mescroll.triggerUpScroll(true);
+			}
+		}
+	},
+	mounted() {
+		// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5
+		// 配置主动触发wxs显示加载进度的回调
+		this.mescroll.optDown.afterLoading = ()=>{
+			this.callProp = {callType: "showLoading", t: Date.now()} // 触发wxs的方法 (值改变才触发更新)
+		}
+		// 配置主动触发wxs隐藏加载进度的回调
+		this.mescroll.optDown.afterEndDownScroll = ()=>{
+			this.callProp = {callType: "endDownScroll", t: Date.now()} // 触发wxs的方法 (值改变才触发更新)
+			let delay = 300 + (this.mescroll.optDown.beforeEndDelay || 0)
+			setTimeout(()=>{
+				if(this.downLoadType === 4 || this.downLoadType === 0){
+					this.callProp = {callType: "clearTransform", t: Date.now()} // 触发wxs的方法 (值改变才触发更新)
+				}
+				// 状态挂载到mescroll对象, 以便在其他组件中使用, 比如<me-video>中
+				this.$set(this.mescroll, 'downLoadType', this.downLoadType)
+			}, delay)
+		}
+		// 初始化wxs的数据
+		this.wxsCall({type: 'setWxsProp'})
+		// #endif
+	}
+}
+
+export default WxsMixin;

+ 92 - 0
node_modules/mescroll-uni/wxs/renderjs.js

@@ -0,0 +1,92 @@
+// 使用renderjs直接操作window对象,实现动态控制app和h5的bounce
+// bounce: iOS橡皮筋,Android半月弧,h5浏览器下拉背景等效果 (下拉刷新时禁止)
+// https://uniapp.dcloud.io/frame?id=renderjs
+
+// 与wxs的me实例一致
+var me = {}
+
+// 初始化window对象的touch事件 (仅初始化一次)
+if(window && !window.$mescrollRenderInit){
+	window.$mescrollRenderInit = true
+	
+	
+	window.addEventListener('touchstart', function(e){
+		if (me.disabled()) return;
+		me.startPoint = me.getPoint(e); // 记录起点
+	}, {passive: true})
+	
+	
+	window.addEventListener('touchmove', function(e){
+		if (me.disabled()) return;
+		if (me.getScrollTop() > 0) return; // 需在顶部下拉,才禁止bounce
+		
+		var curPoint = me.getPoint(e); // 当前点
+		var moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉
+		// 向下拉
+		if (moveY > 0) {
+			// 可下拉的条件
+			if (!me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && me.isUpBoth))) {
+				
+				// 只有touch在mescroll的view上面,才禁止bounce
+				var el = e.target;
+				var isMescrollTouch = false;
+				while (el && el.tagName && el.tagName !== 'UNI-PAGE-BODY' && el.tagName != "BODY") {
+					var cls = el.classList;
+					if (cls && cls.contains('mescroll-render-touch')) {
+						isMescrollTouch = true
+						break;
+					}
+					el = el.parentNode; // 继续检查其父元素
+				}
+				// 禁止bounce (不会对swiper和iOS侧滑返回造成影响)
+				if (isMescrollTouch && e.cancelable && !e.defaultPrevented) e.preventDefault();
+			}
+		}
+	}, {passive: false})
+}
+
+/* 获取滚动条的位置 */
+me.getScrollTop = function() {
+	return me.scrollTop || 0
+}
+
+/* 是否禁用下拉刷新 */
+me.disabled = function(){
+	return !me.optDown || !me.optDown.use || me.optDown.native
+}
+
+/* 根据点击滑动事件获取第一个手指的坐标 */
+me.getPoint = function(e) {
+	if (!e) {
+		return {x: 0,y: 0}
+	}
+	if (e.touches && e.touches[0]) {
+		return {x: e.touches[0].pageX,y: e.touches[0].pageY}
+	} else if (e.changedTouches && e.changedTouches[0]) {
+		return {x: e.changedTouches[0].pageX,y: e.changedTouches[0].pageY}
+	} else {
+		return {x: e.clientX,y: e.clientY}
+	}
+}
+
+/**
+ * 监听逻辑层数据的变化 (实时更新数据)
+ */
+function propObserver(wxsProp) {
+	me.optDown = wxsProp.optDown
+	me.scrollTop = wxsProp.scrollTop
+	me.isDownScrolling = wxsProp.isDownScrolling
+	me.isUpScrolling = wxsProp.isUpScrolling
+	me.isUpBoth = wxsProp.isUpBoth
+}
+
+/* 导出模块 */
+const renderBiz = {
+	data() {
+		return {
+			propObserver: propObserver,
+		}
+	}
+}
+
+export default renderBiz;

+ 268 - 0
node_modules/mescroll-uni/wxs/wxs.wxs

@@ -0,0 +1,268 @@
+// 使用wxs处理交互动画, 提高性能, 同时避免小程序bounce对下拉刷新的影响
+// https://uniapp.dcloud.io/frame?id=wxs
+// https://developers.weixin.qq.com/miniprogram/dev/framework/view/interactive-animation.html 
+
+// 模拟mescroll实例, 与mescroll.js的写法尽量保持一致
+var me = {}
+
+// ------ 自定义下拉刷新动画 start ------
+
+/* 下拉过程中的回调,滑动过程一直在执行 (rate<1为inOffset; rate>1为outOffset) */
+me.onMoving = function (ins, rate, downHight){
+	ins.requestAnimationFrame(function () {
+		ins.selectComponent('.mescroll-wxs-content').setStyle({
+			'will-change': 'transform', // 可解决下拉过程中, image和swiper脱离文档流的问题
+			'transform': 'translateY(' + downHight + 'px)',
+			'transition': ''
+		})
+		// 环形进度条
+		var progress = ins.selectComponent('.mescroll-wxs-progress')
+		progress && progress.setStyle({transform: 'rotate(' + 360 * rate + 'deg)'})
+	})
+}
+
+/* 显示下拉刷新进度 */
+me.showLoading = function (ins){
+	me.downHight = me.optDown.offset
+	ins.requestAnimationFrame(function () {
+		ins.selectComponent('.mescroll-wxs-content').setStyle({
+			'will-change': 'auto',
+			'transform': 'translateY(' + me.downHight + 'px)',
+			'transition': 'transform 300ms'
+		})
+	})
+}
+
+/* 结束下拉 */
+me.endDownScroll = function (ins){
+	me.downHight = 0;
+	me.isDownScrolling = false;
+	ins.requestAnimationFrame(function () {
+		ins.selectComponent('.mescroll-wxs-content').setStyle({
+			'will-change': 'auto',
+			'transform': 'translateY(0)', // 不可以写空串,否则scroll-view渲染不完整 (延时350ms会调clearTransform置空)
+			'transition': 'transform 300ms'
+		})
+	})
+}
+
+/* 结束下拉动画执行完毕后, 清除transform和transition, 避免对列表内容样式造成影响, 如: h5的list-msg示例下拉进度条漏出来等 */
+me.clearTransform = function (ins){
+	ins.requestAnimationFrame(function () {
+		ins.selectComponent('.mescroll-wxs-content').setStyle({
+			'will-change': '',
+			'transform': '',
+			'transition': ''
+		})
+	})
+}
+
+// ------ 自定义下拉刷新动画 end ------
+
+/**
+ * 监听逻辑层数据的变化 (实时更新数据)
+ */
+function propObserver(wxsProp) {
+	me.optDown = wxsProp.optDown
+	me.scrollTop = wxsProp.scrollTop
+	me.bodyHeight = wxsProp.bodyHeight
+	me.isDownScrolling = wxsProp.isDownScrolling
+	me.isUpScrolling = wxsProp.isUpScrolling
+	me.isUpBoth = wxsProp.isUpBoth
+	me.isScrollBody = wxsProp.isScrollBody
+	me.startTop = wxsProp.scrollTop // 及时更新touchstart触发的startTop, 避免scroll-view快速惯性滚动到顶部取值不准确
+}
+
+/**
+ * 监听逻辑层数据的变化 (调用wxs的方法)
+ */
+function callObserver(callProp, oldValue, ins) {
+	if (me.disabled()) return;
+	if(callProp.callType){
+		// 逻辑层(App Service)的style已失效,需在视图层(Webview)设置style
+		if(callProp.callType === 'showLoading'){
+			me.showLoading(ins)
+		}else if(callProp.callType === 'endDownScroll'){
+			me.endDownScroll(ins)
+		}else if(callProp.callType === 'clearTransform'){
+			me.clearTransform(ins)
+		}
+	}
+}
+
+/**
+ * touch事件
+ */
+function touchstartEvent(e, ins) {
+	me.downHight = 0; // 下拉的距离
+	me.startPoint = me.getPoint(e); // 记录起点
+	me.startTop = me.getScrollTop(); // 记录此时的滚动条位置
+	me.startAngle = 0; // 初始角度
+	me.lastPoint = me.startPoint; // 重置上次move的点
+	me.maxTouchmoveY = me.getBodyHeight() - me.optDown.bottomOffset; // 手指触摸的最大范围(写在touchstart避免body获取高度为0的情况)
+	me.inTouchend = false; // 标记不是touchend
+	
+	me.callMethod(ins, {type: 'setWxsProp'}) // 同步更新wxsProp的数据 (小程序是异步的,可能touchmove先执行,才到propObserver; h5和app是同步)
+}
+
+function touchmoveEvent(e, ins) {
+	var isPrevent = true // false表示不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault (对小程序生效, h5和app无效)
+	
+	if (me.disabled()) return isPrevent;
+	
+	var scrollTop = me.getScrollTop(); // 当前滚动条的距离
+	var curPoint = me.getPoint(e); // 当前点
+	
+	var moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉
+	
+	// 向下拉 && 在顶部
+	// mescroll-body,直接判定在顶部即可
+	// scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove
+	// scroll-view滚动到顶部时,scrollTop不一定为0,也有可能大于0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等
+	if (moveY > 0 && (
+			(me.isScrollBody && scrollTop <= 0)
+			||
+			(!me.isScrollBody && (scrollTop <= 0 || (scrollTop <= me.optDown.startTop && scrollTop === me.startTop)) )
+		)) {
+		// 可下拉的条件
+		if (!me.inTouchend && !me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling &&
+				me.isUpBoth))) {
+	
+			// 下拉的角度是否在配置的范围内
+			if(!me.startAngle) me.startAngle = me.getAngle(me.lastPoint, curPoint); // 两点之间的角度,区间 [0,90]
+			if (me.startAngle < me.optDown.minAngle) return isPrevent; // 如果小于配置的角度,则不往下执行下拉刷新
+	
+			// 如果手指的位置超过配置的距离,则提前结束下拉,避免Webview嵌套导致touchend无法触发
+			if (me.maxTouchmoveY > 0 && curPoint.y >= me.maxTouchmoveY) {
+				me.inTouchend = true; // 标记执行touchend
+				touchendEvent(e, ins); // 提前触发touchend
+				return isPrevent;
+			}
+			
+			isPrevent = false // 小程序是return false
+	
+			var diff = curPoint.y - me.lastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上)
+	
+			// 下拉距离  < 指定距离
+			if (me.downHight < me.optDown.offset) {
+				if (me.movetype !== 1) {
+					me.movetype = 1; // 加入标记,保证只执行一次
+					// me.optDown.inOffset && me.optDown.inOffset(me); // 进入指定距离范围内那一刻的回调,只执行一次
+					me.callMethod(ins, {type: 'setLoadType', downLoadType: 1})
+					me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来
+				}
+				me.downHight += diff * me.optDown.inOffsetRate; // 越往下,高度变化越小
+	
+				// 指定距离  <= 下拉距离
+			} else {
+				if (me.movetype !== 2) {
+					me.movetype = 2; // 加入标记,保证只执行一次
+					// me.optDown.outOffset && me.optDown.outOffset(me); // 下拉超过指定距离那一刻的回调,只执行一次
+					me.callMethod(ins, {type: 'setLoadType', downLoadType: 2})
+					me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来
+				}
+				if (diff > 0) { // 向下拉
+					me.downHight += diff * me.optDown.outOffsetRate; // 越往下,高度变化越小
+				} else { // 向上收
+					me.downHight += diff; // 向上收回高度,则向上滑多少收多少高度
+				}
+			}
+			
+			me.downHight = Math.round(me.downHight) // 取整
+			var rate = me.downHight / me.optDown.offset; // 下拉区域当前高度与指定距离的比值
+			// me.optDown.onMoving && me.optDown.onMoving(me, rate, me.downHight); // 下拉过程中的回调,一直在执行
+			me.onMoving(ins, rate, me.downHight)
+		}
+	}
+	
+	me.lastPoint = curPoint; // 记录本次移动的点
+	
+	return isPrevent // false表示不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault (对小程序生效, h5和app无效)
+}
+
+function touchendEvent(e, ins) {
+	// 如果下拉区域高度已改变,则需重置回来
+	if (me.isMoveDown) {
+		if (me.downHight >= me.optDown.offset) {
+			// 符合触发刷新的条件
+			me.downHight = me.optDown.offset; // 更新下拉区域高度
+			// me.triggerDownScroll();
+			me.callMethod(ins, {type: 'triggerDownScroll'})
+		} else {
+			// 不符合的话 则重置
+			me.downHight = 0;
+			// me.optDown.endDownScroll && me.optDown.endDownScroll(me);
+			me.callMethod(ins, {type: 'endDownScroll'})
+		}
+		me.movetype = 0;
+		me.isMoveDown = false;
+	} else if (!me.isScrollBody && me.getScrollTop() === me.startTop) { // scroll-view到顶/左/右/底的滑动事件
+		var isScrollUp = me.getPoint(e).y - me.startPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉
+		// 上滑
+		if (isScrollUp) {
+			// 需检查滑动的角度
+			var angle = me.getAngle(me.getPoint(e), me.startPoint); // 两点之间的角度,区间 [0,90]
+			if (angle > 80) {
+				// 检查并触发上拉
+				// me.triggerUpScroll(true);
+				me.callMethod(ins, {type: 'triggerUpScroll'})
+			}
+		}
+	}
+	me.callMethod(ins, {type: 'setWxsProp'}) // 同步更新wxsProp的数据 (小程序是异步的,可能touchmove先执行,才到propObserver; h5和app是同步)
+}
+
+/* 是否禁用下拉刷新 */
+me.disabled = function(){
+	return !me.optDown || !me.optDown.use || me.optDown.native
+}
+
+/* 根据点击滑动事件获取第一个手指的坐标 */
+me.getPoint = function(e) {
+	if (!e) {
+		return {x: 0,y: 0}
+	}
+	if (e.touches && e.touches[0]) {
+		return {x: e.touches[0].pageX,y: e.touches[0].pageY}
+	} else if (e.changedTouches && e.changedTouches[0]) {
+		return {x: e.changedTouches[0].pageX,y: e.changedTouches[0].pageY}
+	} else {
+		return {x: e.clientX,y: e.clientY}
+	}
+}
+
+/* 计算两点之间的角度: 区间 [0,90]*/
+me.getAngle = function (p1, p2) {
+	var x = Math.abs(p1.x - p2.x);
+	var y = Math.abs(p1.y - p2.y);
+	var z = Math.sqrt(x * x + y * y);
+	var angle = 0;
+	if (z !== 0) {
+		angle = Math.asin(y / z) / Math.PI * 180;
+	}
+	return angle
+}
+
+/* 获取滚动条的位置 */
+me.getScrollTop = function() {
+	return me.scrollTop || 0
+}
+
+/* 获取body的高度 */
+me.getBodyHeight = function() {
+	return me.bodyHeight || 0;
+}
+
+/* 调用逻辑层的方法 */
+me.callMethod = function(ins, param) {
+	if(ins) ins.callMethod('wxsCall', param)
+}
+
+/* 导出模块 */
+module.exports = {
+	propObserver: propObserver,
+	callObserver: callObserver,
+	touchstartEvent: touchstartEvent,
+	touchmoveEvent: touchmoveEvent,
+	touchendEvent: touchendEvent
+}

+ 8 - 3
package-lock.json

@@ -8,14 +8,19 @@
       "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
     },
     "dayjs": {
-      "version": "1.11.10",
-      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
-      "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ=="
+      "version": "1.11.13",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+      "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
     },
     "hls.js": {
       "version": "1.6.7",
       "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.7.tgz",
       "integrity": "sha512-QW2fnwDGKGc9DwQUGLbmMOz8G48UZK7PVNJPcOUql1b8jubKx4/eMHNP5mGqr6tYlJNDG1g10Lx2U/qPzL6zwQ=="
+    },
+    "mescroll-uni": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/mescroll-uni/-/mescroll-uni-1.3.7.tgz",
+      "integrity": "sha512-1pQMtGA+iVRKhfJZZNXdBx05NnthIk6zm3hRbumswSA54eaKOMgpUDb9AQ2+rRdXmS6kLkEYSbW/fkb7/IyoAg=="
     }
   }
 }

+ 3 - 2
package.json

@@ -1,7 +1,8 @@
 {
   "dependencies": {
     "crypto-js": "^4.2.0",
-    "dayjs": "^1.11.10",
-    "hls.js": "^1.6.7"
+    "dayjs": "^1.11.13",
+    "hls.js": "^1.6.7",
+    "mescroll-uni": "^1.3.7"
   }
 }

+ 169 - 28
pages.json

@@ -12,10 +12,21 @@
 				"enablePullDownRefresh": false
 			}
 		}, {
+			"path": "pages/home/living",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationBarTextStyle": "black",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom",
+				"app-plus": {
+					"bounce": "none"
+				}
+			}
+		},
+		{
 			"path": "pages/user/index",
-			"style" :
-			{
-				"navigationBarTitleText" : "",
+			"style": {
+				"navigationBarTitleText": "",
 				"navigationBarTextStyle": "black",
 				"enablePullDownRefresh": false,
 				"navigationStyle": "custom",
@@ -25,24 +36,21 @@
 			}
 
 		},
-	
+
 		{
 			"path": "pages/list/index",
 			"style": {
-				"navigationBarTitleText" : "",
+				"navigationBarTitleText": "直播列表",
 				"navigationBarTextStyle": "black",
-				"enablePullDownRefresh": false,
-				"navigationStyle": "custom",
 				"app-plus": {
 					"bounce": "none"
 				}
 			}
 		},
 		{
-			"path" : "pages/home/live",
-			"style" :
-			{
-				"navigationBarTitleText" : "",
+			"path": "pages/home/live",
+			"style": {
+				"navigationBarTitleText": "",
 				"navigationBarTextStyle": "black",
 				"enablePullDownRefresh": false,
 				"navigationStyle": "custom",
@@ -50,11 +58,10 @@
 					"bounce": "none"
 				}
 			}
-		},	{
-			"path" : "pages/games/index",
-			"style" :
-			{
-				"navigationBarTitleText" : "",
+		}, {
+			"path": "pages/games/index",
+			"style": {
+				"navigationBarTitleText": "",
 				"navigationBarTextStyle": "black",
 				"enablePullDownRefresh": false,
 				"navigationStyle": "custom",
@@ -63,11 +70,11 @@
 				}
 			}
 		},
+
 		{
-			"path" : "pages/home/living",
-			"style" :
-			{
-				"navigationBarTitleText" : "",
+			"path": "pages/auth/login",
+			"style": {
+				"navigationBarTitleText": "",
 				"navigationBarTextStyle": "black",
 				"enablePullDownRefresh": false,
 				"navigationStyle": "custom",
@@ -75,12 +82,43 @@
 					"bounce": "none"
 				}
 			}
-		},
-		{
-			"path" : "pages/login/login",
-			"style" : 
-			{
-				"navigationBarTitleText" : "",
+		},{
+			"path": "pages/auth/findpass",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationBarTextStyle": "black",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom",
+				"app-plus": {
+					"bounce": "none"
+				}
+			}
+		},{
+			"path": "pages/auth/h5WxLogin",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationBarTextStyle": "black",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom",
+				"app-plus": {
+					"bounce": "none"
+				}
+			}
+		},{
+			"path": "pages/auth/loginIndex",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationBarTextStyle": "black",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom",
+				"app-plus": {
+					"bounce": "none"
+				}
+			}
+		},{
+			"path": "pages/auth/register",
+			"style": {
+				"navigationBarTitleText": "",
 				"navigationBarTextStyle": "black",
 				"enablePullDownRefresh": false,
 				"navigationStyle": "custom",
@@ -89,7 +127,111 @@
 				}
 			}
 		}
+
+
 	],
+	"subPackages": [{
+		"root": "pages_shop",
+
+		"pages": [{
+				"path": "cart",
+				"style": {
+					"navigationBarTitleText": "购物车",
+					"app-plus": {
+						"titleNView": false
+					}
+				}
+			}, {
+				"path": "goods",
+				"style": {
+					"navigationBarTitleText": "商品详情",
+					"enablePullDownRefresh": false
+				}
+
+			}, {
+				"path": "store",
+				"style": {
+					"navigationBarTitleText": "",
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+
+			}, {
+				"path": "order",
+				"style": {
+					"navigationBarTitleText": "我的订单",
+					"navigationBarTextStyle": "black",
+					"app-plus": {
+						"bounce": "none"
+					}
+				}
+			}, {
+				"path": "confirmCreateOrder",
+				"style": {
+					"navigationBarTitleText": "确认订单",
+					"navigationBarTextStyle": "black",
+					"app-plus": {
+						"bounce": "none"
+					}
+				}
+			},
+			{
+				"path": "paymentOrder",
+				"style": {
+					"navigationBarTitleText": "支付订单",
+					"navigationBarTextStyle": "black",
+					"app-plus": {
+						"bounce": "none"
+					}
+				}
+			},
+			{
+				"path": "confirmPackageOrder",
+				"style": {
+					"navigationBarTitleText": "确认支付",
+					"navigationBarTextStyle": "black",
+					"app-plus": {
+						"bounce": "none"
+					}
+				}
+			}, {
+				"path": "success",
+				"style": {
+					"navigationBarTitleText": "支付成功",
+					"navigationBarTextStyle": "black",
+					"app-plus": {
+						"bounce": "none"
+					}
+				}
+			}
+		]
+	},{
+		"root": "pages_user",
+
+		"pages": [{
+				"path": "address",
+				"style": {
+					"navigationBarTitleText": "收货地址",
+					"app-plus": {
+						"titleNView": false
+					}
+				}
+			},  {
+				"path": "addAddress",
+				"style": {
+					"navigationBarTitleText": "新建收货地址",
+					"navigationBarTextStyle": "black",
+					"app-plus": {
+						"bounce": "none"
+					}
+				}
+			}
+		]
+	}
+	
+	],
+
+
 	"globalStyle": {
 		"navigationBarTextStyle": "black",
 		"navigationBarTitleText": "【S直播】",
@@ -103,8 +245,7 @@
 		"fontSize": "12px",
 		"borderStyle": "black",
 		"backgroundColor": "#fff",
-		"list": [
-			{
+		"list": [{
 				"pagePath": "pages/list/index",
 				"iconPath": "/static/tabBar/query.png",
 				"selectedIconPath": "/static/tabBar/query_active.png",

+ 287 - 0
pages/auth/findpass.vue

@@ -0,0 +1,287 @@
+<template>
+	<view>
+		 <view class="content">
+			 <view class="pageTop  x-c">
+			    <view class="loginBox">
+					 <view class="login-item">
+						 <view class="input-account">
+							 <input v-model="userName" placeholder="手机号" type="text" />
+						 </view>
+						 <view class="line"></view>
+					 </view> 
+					 
+					 <view class="login-item">
+						 <view class="input-pwd">
+							 <input v-model="password"  placeholder="密码(6-15个字符)" type="password" />
+						 </view>
+						  <view class="line"></view>
+					 </view> 
+					 <view class="login-item">
+						 <view class="input-yzcode x-bc">
+							 <input v-model="yzcode"  placeholder="验证码" type="number" />
+							 <view style="color:#666">获取验证码</view>
+						 </view>
+						  <view class="line"></view>
+					 </view> 
+					 <view class="btns">
+						 <view class="login-btn" @click="login">设置新密码</view>
+					 </view>
+			    </view>
+			 </view>
+		 </view>
+	</view>
+</template>
+
+<script>
+	
+// import { login,getUserInfo } from '@/api/login.js'
+import { loginByApp } from '@/api/login.js'
+
+export default {
+	data() {
+		return {
+			userName:"",
+			password:"",
+			password1:"",
+		    registrationID:"",
+			yzcode:""
+		}
+	},
+	onLoad(option) {
+	    let that=this;
+	    uni.$on('getRegistrationID', function(data) {
+	    	that.registrationID=data;
+	    });   
+		this.$getRegistrationID();
+	},
+	onShow() {
+		
+    },
+	onUnload() {
+		uni.$off('getRegistrationID');
+    },
+    mounted() {
+        
+    },
+    methods: {
+       login(){
+			if (this.$isEmpty(this.userName)) {
+				uni.showToast({
+					title: "请输入帐号",
+					icon: 'none',
+				});
+				return
+			}
+			if (this.$isEmpty(this.password)) {
+				uni.showToast({
+					title: "请输入密码",
+					icon: 'none',
+				});
+				return
+			}
+			var data = {
+				userName:this.userName,
+				password: this.password,
+				jpushId:this.registrationID || uni.getStorageSync("registrationID")
+			};
+			var that=this;
+			uni.showLoading({
+				title:"处理中..."
+			});
+			login(data).then(res => {
+					uni.hideLoading()
+					if(res.code==200){
+						
+						// #ifdef APP-PLUS
+						      //const  jyJPush = uni.requireNativePlugin('JY-JPush');
+							  
+						 // #endif 
+						
+						uni.setStorageSync('AppToken',res.data.token);
+						this.$Router.pushTab({name: 'home'});
+					}
+					else{
+						uni.showToast({title: res.msg,icon: 'none'});
+					}
+				},
+				rej => {}
+			);
+	   
+	   },
+	   goToRegister(){
+		   this.$navTo('./register');
+	   },
+	   goToFindPass(){
+	   	   this.$navTo('./findPass');
+	   },
+	   getRegistrationID(){
+		   // #ifdef APP-PLUS
+		      
+		    // #endif 
+	   }
+    },
+}
+</script>
+
+<style  lang="scss">
+	
+ page{
+ 	background-color: #ffffff;
+ }
+ .content{
+ 	 display: flex;
+ 	 flex-direction: column;
+ 	 align-items: center;
+ 	 height: calc(100vh);
+ 	 width: 100%;
+	 justify-content: space-between;
+ }
+ .pageTop{
+	 display: flex;
+	 flex-direction: column;
+	 width: 100%;
+ }
+ 
+ .content .head{
+ 	text-align: center;
+ 	width: 100%;
+	height: 522rpx;
+	// background:url(/static/image/login/top_bg.png) no-repeat 0 center;
+	background-size: cover;
+    box-sizing: border-box;
+ }
+ 
+ .content .head image{
+ 	width: 150rpx;
+	height: 150rpx;
+ 	border-radius: 10rpx;
+ 	box-shadow:0px 0px 20rpx rgba(0,0,0,0.2);
+	
+ }
+.title{
+ 	color: #141414;
+ 	margin:50upx 0upx 30upx 0rpx;
+ 	font-size: 38rpx;
+	font-weight: 500;
+ }
+ .desc{
+ 	color: #686866;
+ 	padding:0 0 30rpx 0rpx;
+ 	font-size: 28rpx;
+ }
+ 
+ .loginBox{
+ 	padding:10px 10px 30rpx;
+	width: calc(100% - 20px) ;
+	margin-top: 0rpx;
+	background: #FDFDFD;
+	border-radius: 7rpx;
+	
+ }
+ 
+ .login-item p{
+ 	text-align: left;
+ }
+ 
+ .line{
+	 height: 0.5rpx;
+	 background-color: #efefef;
+	 margin-top: 10rpx;
+ }
+ .input-account{
+ 	margin-top: 20rpx;
+ 	margin-bottom: 0rpx;
+ 	border-radius:40rpx;
+ 	border:solid 0rpx #efefef;
+ 	height: 80rpx;	
+ 	width: 100%;
+ 	// background:url(/static/account.png) no-repeat 0 center;
+ 	background-size: 30rpx 30rpx;
+ 	background-position: 30rpx;
+ }
+ 
+ .input-yzcode{
+ 	margin-top: 20rpx;
+ 	margin-bottom: 0rpx;
+ 	border-radius:40rpx;
+ 	border:solid 0rpx #efefef;
+ 	height: 80rpx;	
+ 	width: 100%;
+ 	// background:url(/static/image/login/cz_icon.png) no-repeat 0 center;
+ 	background-size: 30rpx 30rpx;
+ 	background-position: 30rpx;
+ }
+ 
+ .input-pwd{
+ 	margin-top: 40rpx;
+ 	margin-bottom: 20rpx;
+ 	border-radius:40rpx;
+ 	border:solid 0rpx #efefef;
+ 	height: 80rpx;	
+ 	width: 100%;
+ 	// background:url(/static/password.png) no-repeat 0 center;
+ 	background-size: 30rpx 30rpx;
+ 	background-position: 30rpx;
+ }
+ input{
+ 	margin-left: 80rpx;
+ 	height: 80rpx;
+ 	line-height: 80rpx
+ }
+ .footer{
+ 	color: #686866;
+ 	width: 100%;
+	position: fixed;
+ 	text-align: center;
+ 	bottom: 60upx;
+	font-size: 28rpx;
+ }
+ .btns{
+ 	margin: 60rpx 0rpx;
+ }
+ .login-btn {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	width: 100%;
+	height: 80rpx;
+	background: linear-gradient(to right, #FF5C03 0%, #FF5C03 100%);
+	background: -moz-linear-gradient(to right, #FF5C03 0%, #FF5C03 100%);
+	box-shadow: 0px 7rpx 6rpx 0px rgba(229, 138, 0, 0.22);
+	border-radius: 40rpx;
+	font-size: 30rpx;
+	font-family: PingFang SC;
+	font-weight: 500;
+	color: rgba(255, 255, 255, 1);
+ }
+ 
+ .reg-box {
+	 padding-bottom:20rpx;
+	 margin:0 10px;
+	 .reg-btn{
+	 	 font-size:16px ;
+	 	 color: #FF5C03;
+	 }
+ }
+ 
+ .pageBottom{
+	height: 260rpx;
+	width: 75%;
+	display: flex;
+	flex-direction: column;
+ }  
+ 
+ .tips{
+ 	color: #999;	 
+	font-size: 36rpx;
+ }  
+ .menu{
+	 margin-top: 30rpx;
+	 image{
+	 	width: 78rpx;
+	    height: 78rpx;
+	 }
+ }
+  
+ 
+</style>

+ 203 - 0
pages/auth/h5WxLogin.vue

@@ -0,0 +1,203 @@
+<template>
+	<view class="content">
+		<view  class="force-login-wrap">
+			<view class="force-login__content y-f">
+				<view class="logo">
+					<view class="logo-img">
+						<image src="/static/logo.png"></image>
+					</view>
+					<view class="title">直播</view>
+				</view>
+				<view class="login-notice">为了提供更优质的服务,请先登录</view>
+				<view class="btns">
+					<view class="author-btn" @click="loginByMp()">微信授权登录</view>
+					
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+const isWechat = () => {
+	return String(navigator.userAgent.toLowerCase().match(/MicroMessenger/i)) === "micromessenger";
+}
+// import {  loginByMp } from '@/api/user'
+import {  loginByWeChat } from '@/api/login'
+export default {
+	data() {
+		return {
+			code:null,
+		}
+	},
+	onLoad(option) {
+		this.getWechatCode();
+		// setTimeout(()=>{
+		// 	this.goToLanch();
+		// },2000);
+	},
+	onUnload() {
+		
+	},
+	mounted() {
+
+	},
+	methods: {
+		loginByMp(){
+			if(this.code==null){
+				return;
+			}
+			uni.showLoading({
+				title:"处理中..."
+			});
+			let that=this;
+			var data={code:this.code}
+			loginByWeChat(data).then(res => {
+					uni.hideLoading();
+					if(res.code==200){
+						uni.setStorageSync('AppToken',res.token);
+						uni.setStorageSync('userInfo',JSON.stringify(res.user));
+						uni.$emit('refreshIM');
+						that.goToLanch();
+					}
+					else{
+						uni.showToast({title: res.msg,icon: 'none'});
+					}
+				},
+				err => {
+				}
+			);
+		},
+		getWechatCode() {
+			if (isWechat) {
+				let appid = "wx9ea36eecd281bcd3"; //微信APPid
+				let code = this.getUrlCode().code; //是否存在code
+				let local = window.location.href;
+				if (code == null || code === "") {
+				  //不存在就打开上面的地址进行授权
+					window.location.href =
+					"https://open.weixin.qq.com/connect/oauth2/authorize?appid=" +
+					appid +
+					"&redirect_uri=" +
+					encodeURIComponent(local) +
+					"&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
+				} else {
+					this.code = code;
+				}
+			  }
+		},
+		getUrlCode(){
+			// 截取url中的code方法
+			var url = location.search;
+			var theRequest = new Object();
+			if (url.indexOf("?") != -1) {
+				var str = url.substr(1);
+				var strs = str.split("&");
+			    for (var i = 0; i < strs.length; i++) {
+				     theRequest[strs[i].split("=")[0]] = strs[i].split("=")[1];
+				}
+			}
+			console.log(theRequest);
+			return theRequest;
+		},
+		goToLanch(){
+			let beforLoginUrl=uni.getStorageSync('beforLoginPage');
+			console.log("beforLoginUrl:"+beforLoginUrl);
+			uni.reLaunch({
+				url:beforLoginUrl
+			});
+		}
+		 
+	},
+}
+</script>
+
+<style lang="scss">
+.container {
+	flex: 1;
+	display: flex;
+	flex-direction: column;
+	justify-content: flex-start;
+	position: relative;
+	
+}
+
+.force-login-wrap {
+	width: 100%;
+	height: 100%;
+	overflow: hidden;
+	z-index: 11111;
+	top: 0;
+	
+	.force-login__content {
+		position: absolute;
+		left: 50%;
+		top: 40%;
+		transform: translate(-50%, -50%);
+		.logo{
+			display: flex;
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+			.logo-img{
+				border: 4upx solid #FFFFFF;
+				box-shadow: 0px 5px 15px 2px rgba(0,0,0,0.1);
+				border-radius: 50%;
+				width: 80px;
+				height: 80px;
+				image{
+					border-radius: 50%;
+					width: 100%;
+					height: 100%;
+					overflow: hidden;
+				}
+			}
+			
+			.title{
+				margin-top: 20rpx;
+				font-size: 35rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #000;
+				margin-bottom: 30rpx;
+			}
+		}
+		 
+		.login-notice {
+		  font-size: 28rpx;
+		  font-family: PingFang SC;
+		  font-weight: 400;
+		  color: #000;
+		  line-height: 44rpx;
+		  width: 500rpx;
+		  text-align: center;
+		  margin-bottom: 80rpx;
+		}
+		.btns{
+			position: relative;
+			width: 630rpx;
+			height: 80rpx;
+			.author-btn{	
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				z-index:100;
+				position: absolute;
+				width: 630rpx;
+				height: 80rpx;
+				background: linear-gradient(to right, #FF5C03 0%, #E2C99E 100%);
+				background: -moz-linear-gradient(to right, #FF5C03 0%, #E2C99E 100%);
+				// box-shadow: 0px 7rpx 6rpx 0px rgba(229, 138, 0, 0.22);
+				border-radius: 40rpx;
+				font-size: 30rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: rgba(255, 255, 255, 1);
+			}
+		}
+		
+		 
+	}
+}
+ 
+</style>

+ 54 - 126
pages/login/login.vue → pages/auth/login.vue

@@ -1,7 +1,7 @@
 <template>
 	<view>
 		<view class="content x-c">
-			<!-- <image class="backImg" @tap="goBack()" src="../../static/images/icon_close.png"></image> -->
+			<image class="backImg" @tap="goBack()" src="/static/images/icon_close.png"></image>
 			<view class="pageTop  x-c">
 				<view class="head x-c">
 					登录即可体验完整功能
@@ -22,9 +22,6 @@
 					<view class="btns">
 						<view class="login-btn" @click="login">登录</view>
 					</view>
-					<!-- <view class="btns">
-						<view class="login-btn" @click="verificationCode">验证码</view>
-					</view> -->
 					<view class="reg-box x-bc">
 						<view class="reg-btn" @click="goToRegister()">注册账号</view>
 						<!-- <view class="reg-btn" @click="goToFindPass()">忘记密码</view>  -->
@@ -34,20 +31,19 @@
 			<view class="pageBottom" v-if="isApp && isAgreePrivacy">
 				<view class="tips y-f"> — 快捷登录 — </view>
 				<view class="menu x-ac">
-					<!-- <view @tap="loginWeixin" ><image src="/static/image/login/weixin.png"></image></view> -->
+					<view @tap="loginWeixin">
+						<image src="/static/image/login/weixin.png"></image>
+					</view>
 					<view v-if="isIos" @tap="quickAppleLogin">
 						<image src="/static/image/login/apple.png"></image>
 					</view>
-					<!-- <view><image src="/static/image/login/qq.png"></image></view>
-						 <view><image src="/static/image/login/weibo.png"></image></view>  -->
 				</view>
 			</view>
 
 			<view class="checkbox">
 				<view class="checkbox-icon" @tap="handleAgree">
-					<!-- <image src="../../static/image/login/radio_default.png" v-show="!agree"></image>
-					<image src="../../static/image/login/radio_choose.png" v-show="agree"></image>
-				 -->
+					<image src="/static/images/radio_default.png" v-show="!agree"></image>
+					<image src="/static/images/radio_choose.png" v-show="agree"></image>
 				</view>
 				<view>我已阅读并同意<text @tap="goToWeb(0)">《用户协议》</text><text @tap="goToWeb(1)">《隐私政策》</text> 并使用本机号码登录</view>
 			</view>
@@ -58,11 +54,16 @@
 </template>
 
 <script>
+	// import {
+	// 	login,
+	// 	loginByWeChat,
+	// 	getUserInfo,
+	// 	loginByApple
+	// } from '@/api/user'
 	import {
 		loginByApp,
-		captchaImage
+		loginByWeChat
 	} from '@/api/login'
-	// import { login,loginByWeChat,getUserInfo,loginByApple } from '@/api/user'
 	export default {
 		data() {
 			return {
@@ -78,11 +79,7 @@
 				isIos: false,
 				from: '',
 				source: '',
-				appleKey: "",
-				code:{
-					img:'',
-					uuid:''
-				}
+				appleKey: ""
 			}
 		},
 		onLoad(option) {
@@ -104,9 +101,9 @@
 			// } 
 		},
 		onShow() {
-			// if(this.$isLogin()) {
-			// 	this.goPage()
-			// }
+			if (this.$isLogin()) {
+				this.goPage()
+			}
 			// #ifdef APP-PLUS
 			this.isAgreePrivacy = this.isIos ? true : plus.runtime.isAgreePrivacy();
 			if (plus.runtime.isAgreePrivacy()) {
@@ -126,7 +123,7 @@
 					// 获取一键登录弹框协议勾选状态
 					univerifyManager.getCheckBoxState({
 						success(res) {
-							// console.log("getCheckBoxState res: ", res);
+							console.log("getCheckBoxState res: ", res);
 							if (res.state) {
 								// 关闭一键登录弹框
 								univerifyManager.close()
@@ -139,108 +136,48 @@
 				// 取消订阅自定义按钮点击事件
 				univerifyManager.offButtonsClick(callback);
 			},
-
-			verificationCode() {
-				// var data = {
-				// 	uuid: 123,
-				// 	img: 123
-				// };
-				captchaImage().then(res => {
-					if (res.code == 200) {
-						this.code.img=res.img
-						this.code.uuid=res.uuid
-						console.log("qqq",res)
-						// this.livedata = res.data
-					} else {
-						// uni.showToast({
-						// 	title: res.msg,
-						// 	icon: 'none',
-						// 	duration: 2000
-						// });
-					}
-				})
-
-				// captchaImage().then(res => {
-				// 		console.log(res, '444')
-				// 		if (res.code == 200) {
-
-				// 		} else {
-				// 			uni.showToast({
-				// 				title: res.msg,
-				// 				icon: 'none'
-				// 			});
-				// 		}
-				// 	},
-				// 	rej => {
-				// 		console.log("qxj rej:" + JSON.stringify(rej));
-				// 	}
-				// );
-			},
 			login() {
-				// if (this.$isEmpty(this.userName)) {
-				// 	uni.showToast({
-				// 		title: "请输入帐号",
-				// 		icon: 'none',
-				// 	});
-				// 	return
-				// }
-				// if (this.$isEmpty(this.password)) {
-				// 	uni.showToast({
-				// 		title: "请输入密码",
-				// 		icon: 'none',
-				// 	});
-				// 	return
-				// }
-				// if (!this.agree) {
-				// 	uni.showToast({
-				// 		title: "请同意相关协议",
-				// 		icon: 'none'
-				// 	});
-				// 	return
-				// }
+				if (this.$isEmpty(this.userName)) {
+					uni.showToast({
+						title: "请输入帐号",
+						icon: 'none',
+					});
+					return
+				}
+				if (this.$isEmpty(this.password)) {
+					uni.showToast({
+						title: "请输入密码",
+						icon: 'none',
+					});
+					return
+				}
+				if (!this.agree) {
+					uni.showToast({
+						title: "请同意相关协议",
+						icon: 'none'
+					});
+					return
+				}
 				var data = {
-					// jpushId:this.registrationID,
 					phone: this.userName,
-					// password: this.password,
-					// code:this.code,
-					loginType:3,
+					password: this.password,
+					// jpushId: this.registrationID,
+					loginType: 1,
 					// source: this.source
 				};
 				var that = this;
-				// uni.showLoading({
-				// 	title:"处理中..."
-				// });
+				uni.showLoading({
+					title: "处理中..."
+				});
 				loginByApp(data).then(res => {
-						console.log(res, '444')
 						uni.hideLoading();
-						// console.log("qxj res:"+JSON.stringify(res));
+						console.log("qxj res:" + JSON.stringify(res));
 						if (res.code == 200) {
-							console.log("token",res.token)
-							uni.setStorageSync('userInfo', JSON.stringify(res.user));
-							
-							
 							uni.setStorageSync('AppToken', res.token);
-							// uni.setStorageSync('userId', res.user.userId);
-							uni.switchTab({
-								url: "/pages/list/index"
-							})
-							// uni.setStorageSync('userInfo', JSON.stringify(res.user));
-							// uni.$emit('refreshIM');
-							// uni.$emit('showHealthButler');
-							// that.goPage();
-
-							// // #ifdef H5
-							//     this.$navBack();
-							// // #endif
-
-							// // #ifdef APP-PLUS
-							//      this.$navBack();
-							//     // uni.reLaunch({
-							//     // 	url: '../index/index',
-							//     // 	animationType: 'pop-in',
-							//     // 	animationDuration: 100
-							//     // })
-							// // #endif
+							uni.setStorageSync('userInfo', JSON.stringify(res.user));
+							uni.$emit('refreshIM');
+							uni.$emit('showHealthButler');
+							that.goPage();
 						} else {
 							uni.showToast({
 								title: res.msg,
@@ -500,12 +437,9 @@
 							icon: 'none',
 							position: 'bottom'
 						});
-						//setTimeout(function() {
 						uni.navigateTo({
 							url: "/pages/auth/login"
 						});
-						//}, 1800);
-						//}
 						//登录失败
 						console.log("qxj failRes:" + JSON.stringify(res));
 
@@ -634,7 +568,7 @@
 					})
 				} else {
 					uni.reLaunch({
-						url: '../course/index',
+						url: '/pages/list/index',
 						animationType: 'none',
 						animationDuration: 2000
 					});
@@ -642,13 +576,10 @@
 					if (pages.length == 1) {
 						uni.reLaunch({
 							url: '../course/index',
-							//url: '../course/video/living-app',
 							animationType: 'none',
 							animationDuration: 2000
 						});
-					} else {
-						//this.$navBack();
-					}
+					} else {}
 				}
 				this.$updateMsgDot()
 				this.$setSource()
@@ -689,8 +620,6 @@
 		height: calc(100vh);
 		width: 100%;
 		position: relative;
-		// justify-content: space-between;
-		//padding-top: calc(100% - 32vh);
 	}
 
 	.backImg {
@@ -711,7 +640,6 @@
 		text-align: center;
 		width: 100%;
 		height: 100rpx;
-		// background:url(/static/image/login/top_bg.png) no-repeat 0 center;
 		background-size: cover;
 		box-sizing: border-box;
 		font-size: 36rpx;
@@ -763,7 +691,7 @@
 			border: solid 0rpx #efefef;
 			height: 80rpx;
 			width: 100%;
-			// background: url('/static/account.png') no-repeat 0 center;
+			background: url(/static/images/account.png) no-repeat 0 center;
 			background-size: 30rpx 30rpx;
 			background-position: 30rpx;
 		}
@@ -775,7 +703,7 @@
 			border: solid 0rpx #efefef;
 			height: 80rpx;
 			width: 100%;
-			// background: url(/static/password.png) no-repeat 0 center;
+			background: url(/static/images/password.png) no-repeat 0 center;
 			background-size: 30rpx 30rpx;
 			background-position: 30rpx;
 		}

+ 303 - 0
pages/auth/loginIndex.vue

@@ -0,0 +1,303 @@
+<template>
+	<view class="container">
+		<view class="login-title">
+			<view>您好,</view>
+			<view>欢迎来到芳华未来!</view>
+		</view>
+		<!-- <view class="logoimage"><image src="/static/logo.png" mode="aspectFill"></image></view> -->
+		<view class="login-box">
+			<!-- <view class="phone">187****8783</view>
+			<view class="tips">认证服务由中国移动统一认证提供</view> -->
+			<button class="login-btn" style="margin-top: 74rpx;" :loading="btnLoading" :disabled="btnLoading"
+				@click="submit">本机号码一键登录</button>
+			<button class="login-btn other-login-btn" :disabled="btnLoading" @tap="handleOtherLogin">其他方式登录</button>
+		
+			<view class="checkbox">
+				<view class="checkbox-icon" @tap="handleAgree">
+					<image src="/static/imagesradio_default.png" v-show="!agree"></image>
+					<image src="/static/image/radio_choose.png" v-show="agree"></image>
+				</view>
+				<view>我已阅读并同意<text @tap="goToWeb(0)">《用户协议》</text><text @tap="goToWeb(1)">《隐私政策》</text> 并使用本机号码登录</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	// import { navBack } from "../../utils/common";
+	import { navBack } from "@/utils/util";
+import {
+		loginByApp
+	} from "@/api/login.js"
+	export default {
+		data() {
+			return {
+				btnLoading: false,
+				agree: false
+			}
+		},
+		onLoad() {
+			if(!this.$isLogin()) {
+				let pages = getCurrentPages();
+				let url = pages[ pages.length - 3];
+				if(pages.length > 2 &&url&&(url.route=="pages/auth/login" || url.route=="pages/auth/loginIndex"||url.route=="pages/common/launch")) {
+					uni.navigateBack({
+						delta: 2
+					})
+				} else {
+	
+					// #ifdef APP-PLUS
+					this.submit()
+					// #endif
+					// #ifndef APP-PLUS
+					if(String(navigator.userAgent.toLowerCase().match(/MicroMessenger/i)) === "micromessenger"){
+						const pages = getCurrentPages();
+						if(pages.length > 1) {
+							const url = pages[ pages.length - 2];
+							const options = url.options //url中所带的参数
+							//拼接url的参数
+							if(options&&JSON.stringify(options)!='{}') {
+								let allurl = '/'+ url.route + uni.$u.queryParams(options)
+								uni.setStorageSync('beforLoginPage',allurl)
+							} else {
+								uni.setStorageSync('beforLoginPage','/'+url.route);
+							}
+							uni.redirectTo({
+								 url: "/pages/auth/h5WxLogin"
+							});
+						} else {
+							this.submit()
+						}
+					} else {
+						uni.redirectTo({
+							url: "/pages/auth/login"
+						})
+					}
+					// #endif
+				}
+			}
+		},
+		onShow() {
+			if(this.$isLogin()) {
+				uni.reLaunch({
+					url: '../course/index',
+					//url: '../course/video/living-app',
+					animationType: 'none',
+					animationDuration: 2000
+				})
+			}
+		},
+		methods: {
+			goToWeb(index){
+				uni.setStorageSync('url',index==0?"https://userapp.his.cdwjyyh.com/web/userAgreement":"https://userapp.his.cdwjyyh.com/web/privacyPolicy");
+				uni.navigateTo({
+					url:"/pages/index/h5"
+				})
+			},
+			// 同意
+			handleAgree() {
+				this.agree = !this.agree
+			},
+			// login
+			submit() {
+				// if(!this.agree) {
+				// 	this.$refs.popup.open('center')
+				// 	return
+				// }
+				this.$showLoginPage()
+				// uni.preLogin({
+				// 	provider: 'univerify',
+				// 	success() { //预登录成功
+				// 		// 显示一键登录选项
+				// 		uni.showToast({
+				// 			title: "登录成功",
+				// 			icon: "none"
+				// 		})
+				// 		uni.login({
+				// 			provider: 'univerify',
+				// 			univerifyStyle: { // 自定义登录框样式
+				// 				fullScreen: true,
+				// 			},
+				// 			success(res) { // 登录成功 在该回调中请求后端接口,将access_token传给后端
+				// 				console.log(res.authResult); // {openid:'登录授权唯一标识',access_token:'接口返回的 token'} 
+				// 			},
+				// 			fail(res) { // 登录失败
+				// 				console.log(res.errCode)
+				// 				console.log(res.errMsg)
+				// 			}
+				// 		})
+				// 	},
+				// 	fail(res) { // 预登录失败
+				// 		// 跳转到普通登录
+				// 		uni.navigateTo({
+				// 			url: "/pages/login/otherLogin"
+				// 		})
+				// 		// 根据错误信息判断失败原因,如有需要可将错误提交给统计服务器
+				// 		console.log(res.errCode)
+				// 		console.log(res.errMsg)
+				// 	}
+				// })
+			},
+			handleOtherLogin() {
+				uni.redirectTo({
+					url: "/pages/auth/login"
+				})
+			},
+			// 关闭弹窗
+			close(val) {
+				this.$refs.popup.close()
+				if (val == 'agree') {
+					this.agree = true
+					this.submit()
+				}
+			}
+		}
+	}
+</script>
+
+<style>
+	page {
+		background-color: #fff;
+	}
+</style>
+<style scoped lang="scss">
+	@mixin u-flex($flexD, $alignI, $justifyC) {
+		display: flex;
+		flex-direction: $flexD;
+		align-items: $alignI;
+		justify-content: $justifyC;
+	}
+
+	.container {
+		height: 100vh;
+		padding: 0 64rpx;
+		padding-top: calc(var(--status-bar-height) + 88rpx);
+		padding-bottom: calc(var(--window-bottom) + 20rpx);
+		box-sizing: border-box;
+	}
+
+	.popupbox {
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 400;
+		font-size: 30rpx;
+		color: #999999;
+		line-height: 38rpx;
+		background-color: #fff;
+		width: 600rpx;
+		padding: 60rpx 30rpx 10rpx 30rpx;
+		border-radius: 15rpx;
+		box-sizing: border-box;
+
+		text {
+			color:#FF5C03;
+		}
+
+		.popupbox-footer {
+			padding: 30rpx 0;
+			@include u-flex(row, center, center);
+		}
+
+		.popupbox-btn {
+			width: 200rpx;
+			height: 68rpx;
+			background: #fff;
+			font-size: 28rpx;
+			border-radius: 44rpx 44rpx 44rpx 44rpx;
+			text-align: center;
+			line-height: 66rpx;
+			border: 1rpx solid #999;
+			color: #999;
+		}
+
+		.agree-btn {
+			background: linear-gradient(270deg, #FF5C03 0%, #FFAC64 100%);
+			border: none;
+			color: #fff;
+		}
+	}
+
+	.login-title {
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 600;
+		font-size: 56rpx;
+		color: #333333;
+		line-height: 78rpx;
+		padding-top: 40rpx;
+	}
+	.logoimage {
+		@include u-flex(row, center, center);
+		margin-top: 5vh;
+		image {
+			height: 100rpx;
+			width: 100rpx;
+		}
+	}
+	.login-box {
+		margin-top: 20vh;
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 400;
+		font-size: 28rpx;
+		color: #333333;
+		text-align: center;
+
+		.phone {
+			font-weight: 500;
+			font-size: 56rpx;
+		}
+
+		.tips {
+			margin-top: 18rpx;
+			color: #757575;
+		}
+	}
+
+	.checkbox {
+		margin-top: 36rpx;
+		@include u-flex(row, flex-start, flex-start);
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 400;
+		font-size: 26rpx;
+		color: #999999;
+		line-height: 38rpx;
+		text-align: left;
+
+		text {
+			color:#FF5C03;
+		}
+
+		&-icon {
+			flex-shrink: 0;
+			margin-right: 12rpx;
+
+			image {
+				height: 24rpx;
+				width: 24rpx;
+			}
+		}
+		
+	}
+
+	.login-btn {
+		min-width: 622rpx;
+		height: 88rpx;
+		margin-top: 48rpx;
+		line-height: 88rpx;
+		text-align: center;
+		background: linear-gradient(270deg, #FF5C03 0%, #FFAC64 100%);
+		border-radius: 44rpx 44rpx 44rpx 44rpx;
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 600;
+		font-size: 32rpx;
+		color: #FFFFFF !important;
+
+		&::after {
+			border: none;
+		}
+	}
+
+	.other-login-btn {
+		background: #fff;
+		border: 2rpx solid #ECECEC;
+		color: #333333 !important;
+	}
+</style>

+ 399 - 0
pages/auth/register.vue

@@ -0,0 +1,399 @@
+<template>
+	<view class="page">
+		<view class="content">
+			<view class="pageTop  x-c">
+				<view class="loginBox">
+					<view class="login-item">
+						<view class="input-account">
+							<input v-model="userName" placeholder="手机号" type="number" />
+						</view>
+						<view class="line"></view>
+					</view>
+
+					<view class="login-item">
+						<view class="input-pwd">
+							<input v-model="password" placeholder="密码(6-15个字符)" type="password" />
+						</view>
+						<view class="line"></view>
+					</view>
+					<view class="login-item">
+						<view class="input-pwd">
+							<input v-model="password1" placeholder="确认密码" type="password" />
+						</view>
+						<view class="line"></view>
+					</view>
+					<!-- 	 <view class="login-item">
+						 <view class="input-yzcode x-bc">
+							 <input v-model="yzcode"  placeholder="验证码" type="number" ></input>
+							 <view style="color:#666">获取验证码</view>
+						 </view>
+						  <view class="line"></view>
+					 </view> -->
+					<view class="btns">
+						<view class="login-btn" @click="doRegister">注册</view>
+					</view>
+				</view>
+
+				<view class="checkbox">
+					<view class="checkbox-icon" @tap="handleAgree">
+						<image src="/static/images/radio_default.png" v-show="!agree"></image>
+						<image src="/static/images/radio_choose.png" v-show="agree"></image>
+					</view>
+					<view>我已阅读并同意<text @tap="goToWeb(0)">《用户协议》</text><text @tap="goToWeb(1)">《隐私政策》</text> 并使用本机号码登录
+					</view>
+				</view>
+
+
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		register,
+		loginByApp
+	} from '@/api/login'
+	// import { register,login } from '@/api/user'
+	export default {
+		components: {},
+		data() {
+			return {
+				userName: "",
+				password: "",
+				password1: "",
+				registrationID: "",
+				yzcode: "",
+				aback: true,
+				agree: false,
+			}
+		},
+		onLoad(option) {
+			let that = this;
+			uni.$on('getRegistrationID', function(data) {
+				that.registrationID = data;
+			});
+		},
+		onShow() {
+			this.$getRegistrationID();
+		},
+		onUnload() {
+			uni.$off('getRegistrationID');
+		},
+		mounted() {
+
+		},
+		methods: {
+			doRegister() {
+				if (this.$isEmpty(this.userName)) {
+					uni.showToast({
+						title: "请输入帐号",
+						icon: 'none',
+					});
+					return
+				}
+				if (this.$isEmpty(this.password)) {
+					uni.showToast({
+						title: "请输入密码",
+						icon: 'none',
+					});
+					return
+				}
+				if (this.password != this.password1) {
+					uni.showToast({
+						title: "两次密码输入不一致",
+						icon: 'none'
+					});
+				}
+				if (!this.agree) {
+					uni.showToast({
+						title: "请同意相关协议",
+						icon: 'none'
+					});
+					return
+				}
+				var data = {
+					phone: this.userName,
+					password: this.password,
+					// jpushId: this.registrationID || uni.getStorageSync("registrationID"),
+					// loginType: 1
+				};
+				var that = this;
+				uni.showLoading({
+					title: "注册中..."
+				});
+				register(data).then(res => {
+						if (res.code == 200) {
+							console.log("注册好了")
+							// uni.setStorageSync('AppToken',res.data.token);
+							// this.$Router.pushTab({name: 'home'});
+							this.doLogin();
+						} else {
+							uni.hideLoading()
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+
+			},
+
+			doLogin() {
+				var data = {
+					phone: this.userName,
+					password: this.password,
+					// jpushId: this.registrationID || uni.getStorageSync("registrationID"),
+					loginType: 1
+				};
+				var that = this;
+				loginByApp(data).then(res => {
+						uni.hideLoading()
+						if (res.code == 200) {
+							uni.setStorageSync('AppToken', res.token);
+							uni.setStorageSync('userInfo', JSON.stringify(res.user));
+							uni.$emit('refreshIM');
+							uni.$emit('showHealthButler');
+							uni.reLaunch({
+								url: '/pages/list/index',
+								animationType: 'pop-in',
+								animationDuration: 100
+							})
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+
+			},
+
+
+			getRegistrationID() {
+				// #ifdef APP-PLUS
+
+				// #endif 
+			},
+			handleAgree() { // 同意
+				this.agree = !this.agree
+			},
+			goToWeb(index) {
+				uni.setStorageSync('url', index == 0 ? "https://userapp.his.cdwjyyh.com/web/userAgreement" :
+					"https://userapp.his.cdwjyyh.com/web/privacyPolicy");
+				uni.navigateTo({
+					url: "/pages/index/h5"
+				})
+			},
+		},
+	}
+</script>
+
+<style lang="scss">
+	page {
+		background-color: #ffffff;
+	}
+
+	.content {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		height: calc(100vh);
+		width: 100%;
+		justify-content: space-between;
+		//padding-top: calc(100% - 32vh);
+	}
+
+	.pageTop {
+		display: flex;
+		flex-direction: column;
+		width: 100%;
+	}
+
+	.content .head {
+		text-align: center;
+		width: 100%;
+		height: 100rpx;
+		background-size: cover;
+		box-sizing: border-box;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #666;
+	}
+
+
+	.content .head image {
+		width: 150rpx;
+		height: 150rpx;
+		border-radius: 10rpx;
+		box-shadow: 0px 0px 20rpx rgba(0, 0, 0, 0.2);
+	}
+
+	.title {
+		color: #141414;
+		margin: 50upx 0upx 30upx 0rpx;
+		font-size: 38rpx;
+		font-weight: 500;
+	}
+
+	.desc {
+		color: #686866;
+		padding: 0 0 30rpx 0rpx;
+		font-size: 28rpx;
+	}
+
+	.loginBox {
+		padding: 10px 10px 30rpx;
+		width: calc(100% - 20px);
+		margin-top: 0rpx;
+		background: #FDFDFD;
+		//box-shadow: 0rpx 4rpx 27rpx 0rpx rgba(155,155,155,0.25);
+		border-radius: 7rpx;
+	}
+
+	.login-item p {
+		text-align: left;
+	}
+
+	.line {
+		height: 0.5rpx;
+		background-color: #efefef;
+		margin-top: 10rpx;
+	}
+
+	.input-account {
+		margin-top: 20rpx;
+		margin-bottom: 0rpx;
+		border-radius: 40rpx;
+		border: solid 0rpx #efefef;
+		height: 80rpx;
+		width: 100%;
+		// background: url(/static/account.png) no-repeat 0 center;
+		background-size: 30rpx 30rpx;
+		background-position: 30rpx;
+	}
+
+	.input-yzcode {
+		margin-top: 20rpx;
+		margin-bottom: 0rpx;
+		border-radius: 40rpx;
+		border: solid 0rpx #efefef;
+		height: 80rpx;
+		width: 100%;
+		// background: url(/static/image/login/cz_icon.png) no-repeat 0 center;
+		background-size: 30rpx 30rpx;
+		background-position: 30rpx;
+	}
+
+	.input-pwd {
+		margin-top: 40rpx;
+		margin-bottom: 20rpx;
+		border-radius: 40rpx;
+		border: solid 0rpx #efefef;
+		height: 80rpx;
+		width: 100%;
+		// background: url(/static/password.png) no-repeat 0 center;
+		background-size: 30rpx 30rpx;
+		background-position: 30rpx;
+	}
+
+	input {
+		margin-left: 80rpx;
+		height: 80rpx;
+		line-height: 80rpx
+	}
+
+	.footer {
+		color: #686866;
+		width: 100%;
+		position: fixed;
+		text-align: center;
+		bottom: 60upx;
+		font-size: 28rpx;
+	}
+
+	.btns {
+		margin: 50rpx 0rpx;
+		margin-bottom: 0rpx;
+	}
+
+	.login-btn {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		width: 100%;
+		height: 80rpx;
+		background: linear-gradient(to right, #FF5C03 0%, #FF5C03 100%);
+		background: -moz-linear-gradient(to right, #FF5C03 0%, #FF5C03 100%);
+		box-shadow: 0px 7rpx 6rpx 0px rgba(229, 138, 0, 0.22);
+		border-radius: 40rpx;
+		font-size: 30rpx;
+		font-family: PingFang SC;
+		font-weight: 500;
+		color: rgba(255, 255, 255, 1);
+	}
+
+	.reg-box {
+		padding-bottom: 20rpx;
+		margin: 0 10px;
+
+		.reg-btn {
+			font-size: 16px;
+			color: #FF5C03;
+		}
+	}
+
+	.pageBottom {
+		height: 260rpx;
+		width: 75%;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.tips {
+		color: #999;
+		font-size: 36rpx;
+	}
+
+	.menu {
+		margin-top: 30rpx;
+
+		image {
+			width: 78rpx;
+			height: 78rpx;
+		}
+	}
+
+	.checkbox {
+		margin: 20rpx;
+		margin-top: 16rpx;
+		display: flex;
+		flex-direction: row;
+		align-items: flex-start;
+		justify-content: flex-start;
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 400;
+		font-size: 26rpx;
+		color: #999999;
+		line-height: 38rpx;
+		text-align: left;
+
+		text {
+			color: #FF5C03;
+		}
+
+		&-icon {
+			flex-shrink: 0;
+			margin-right: 12rpx;
+
+			image {
+				height: 24rpx;
+				width: 24rpx;
+			}
+		}
+	}
+</style>

+ 1 - 1
pages/home/index.vue

@@ -205,7 +205,7 @@
 						icon: 'none'
 					});
 					uni.navigateTo({
-						url: "/pages/login/login"
+						url: "/pages/auth/login"
 					})
 				}
 				

+ 1 - 1
pages/home/live.vue

@@ -30,7 +30,7 @@
 		<view class="talkbox column flex-1 hidden" style="height: 100%;" v-if="acttab==0">
 			<!-- <u-notice-bar :icon="icon2" :text="text2" mode="closable" bgColor='rgba(254,253,235)' color='#FF5C03'
 				style=" height: 30rpx;line-height: 40rpx;"></u-notice-bar> -->
-			<scroll-view scroll-y="true" class="talk p20 scrolly flex-1 column"
+			<scroll-view enable-flex scroll-y="true" class="talk p20 scrolly flex-1 column"
 				style="width: calc(100% - 40rpx);height: calc(100% - 40rpx);" :scroll-into-view="scrollIntoView">
 				<view class="list justify-start" v-for="(item,index) in talklist" :key="item.index"
 					:id="`list_${index}`" v-show="item.cmd=='sendMsg'">

+ 276 - 358
pages/home/living.vue

@@ -43,7 +43,7 @@
 					<view>{{liveViewData.like}}</view>
 					<!-- <view>{{liveData likeName}}</view> -->
 				</view>
-				<view class="side-item">
+				<view class="side-item" @click="goStore()">
 					<image src="/static/images/live/shop.png"></image>
 					<view>店铺</view>
 				</view>
@@ -80,7 +80,7 @@
 			</view>
 			<view class="pb40  mt90" style="position: fixed;bottom: 0;">
 				<view class="w100 h300 mt20">
-					<scroll-view scroll-y="true" class="talk p20 scrolly flex-1 column"
+					<scroll-view enable-flex scroll-y="true" class="talk p20 scrolly flex-1 column"
 						style="width: calc(100% - 40rpx);height: calc(100% - 40rpx);"
 						:scroll-into-view="scrollIntoView">
 						<view>
@@ -309,7 +309,7 @@
 		<!-- 小黄车弹窗 -->
 		<u-popup :show="shopping" @close="closeshop" @open="open" round='20rpx' bgColor='#f3f5f9'>
 			<view class="shoppop">
-				<view class="u-flex-y-center" style="margin-bottom: 22rpx;">
+				<view class="shoppop-top">
 					<u-avatar :src="livedata.liveImgUrl" size="36" class="ml16"></u-avatar>
 					<view class="search-input u-flex-y-center">
 						<image style="width: 24rpx;height: 24rpx;margin-right: 16rpx;" src="@/static/images/search.png">
@@ -320,39 +320,16 @@
 						<image style="width: 32rpx;height: 32rpx;" src="@/static/images/collect.png"></image>
 						<view>收藏</view>
 					</view>
-					<view class="t-c search-top" @click="getOrderList">
+					<view class="t-c search-top" @click="goOrderList">
 						<image style="width: 32rpx;height: 32rpx;" src="@/static/images/order.png"></image>
 						<view>订单</view>
 					</view>
 				</view>
-				<view class=""></view>
-				<u-list height="350" class="shop-list" @scrolltolower="scrolltolower">
-					<!-- <view class="list-item">
-						<view class="goods-img">
-							<image src="/static/images/a.jpg"></image>
-							<view class="goods-label">1</view>
-						</view>
-						<view class="goods-right">
-							<view class="goods-title">史士昊老师四神汤健脾消食疗法</view>
-							<view class="goods-details">看它来喘口气,小小震撼,</view>
-							<view class="goods-people">45708 人已购</view>
-							<view class="goods-shop">
-								<text class="nummber"><text style="font-size: 20rpx;font-weight: 600;">¥</text><text
-										style="font-size: 36rpx;font-weight: bold;">0</text>.00/日</text>
-								<view class="btn-group  u-flex-y-center">
-									<view class="collect-btn">
-										<image style="width: 32rpx;height: 31rpx;" src="/static/images/collect.png">
-										</image>
-									</view>
-									<view class="shop-btn">去购买</view>
-								</view>
-							</view>
-						</view>
-					</view> -->
 
-					<u-list-item class="list-item " v-for="(item,index) in products" :key="index">
+				<scroll-view enable-flex scroll-y class="shop-list" :style="{ height: boxHeight + 'px' }">
+					<view class="list-item " v-for="(item,index) in products" :key="index">
 						<view class="goods-img">
-							<image :src="item.imgUrl"></image>
+							<image :src="item.imgUrl" mode="widthFix"></image>
 							<view class="goods-label">{{index+1}}</view>
 						</view>
 						<view class="goods-right">
@@ -368,12 +345,15 @@
 											src="/static/images/collect.png">
 										</image>
 									</view>
-									<view class="shop-btn">去购买</view>
+									<view v-if="item.status==1" class="shop-btn" @click="goShop(item.productId)">去购买
+									</view>
+									<view v-else-if="item.status==0" @click="goShop(item.productId)" class="shop-btn">
+										已下架</view>
 								</view>
 							</view>
 						</view>
-					</u-list-item>
-				</u-list>
+					</view>
+				</scroll-view>
 			</view>
 		</u-popup>
 	</view>
@@ -389,9 +369,9 @@
 		getRecentLiveViewers, //获取直播间用户(展示在线用户)
 		// 小黄车
 		liveStore, //店铺展示,
-		liveGoodsDetail, //商品详情,
+		// liveGoodsDetail, //商品详情,
 		liveOrderUser, //正在购买
-		getLive, //获取直播间信息接口
+		getLiveInfo, //获取直播间信息接口
 		getLiveViewData //直播间点赞、关注、在线人数数据
 	} from '@/api/live'
 	import {
@@ -410,7 +390,9 @@
 	} from '@/api/home'
 	// var wsUrl = "ws://192.168.10.166:17114/app/webSocket";
 
-	var wsUrl = "ws://192.168.10.166:7114/app/webSocket"; //余红奇
+	// var wsUrl = "ws://192.168.10.166:7114/app/webSocket"; //余红奇
+	var wsUrl = "ws://nd383294.natappfree.cc/app/webSocket"; //余红奇
+	// var wsUrl = "ws://v56c9b8e.natappfree.cc/app/webSocket"; //余红奇
 	// var wsUrl = "ws://192.168.10.170:7114/app/webSocket"; //陈果
 	// var wsUrl = "ws://live.ylrzcloud.com/socket/app/webSocket";
 	var pingpangTimes = null;
@@ -421,6 +403,7 @@
 	export default {
 		data() {
 			return {
+				boxHeight: 300, //小黄车高度
 				isFollow: true,
 				liveViewData: {},
 				liveViewers: [], //观众
@@ -432,18 +415,19 @@
 				orderUser: {}, //正在购买
 				userType: 0,
 				timestamp: '',
-				liveId: uni.getStorageSync("liveId"),
+				liveId: null,
 				// userId: uni.getStorageSync("userInfo.userId"),
 				livedata: {},
 				codeimg: '',
 				placeholderText: '说点什么...',
 				isZoom: false, //点赞按钮控制是否放大
 				userinfo: '', //用户信息
-				path: 'http://192.168.10.166/dev-api', //余红奇
+				// path: 'http://192.168.10.166/dev-api', //余红奇
+				path: 'http://v56c9b8e.natappfree.cc', //余红奇
 				// path: 'http://192.168.10.170/dev-api', //陈果
 				value: '',
 				talkdisabled: false, //输入框是否禁用
-				autoplay: true, //视频自动播放
+				autoplay: false, //视频自动播放
 				showadd: false,
 				talklist: [],
 				scrollIntoView: '',
@@ -483,23 +467,7 @@
 				// 	title: '史士昊老师四神汤健脾消食疗法',
 				// 	details: '看它来喘口气,小小震撼,',
 				// 	people: '45708 '
-				// }, {
-				// 	title: '史士昊老师四神汤健脾消食疗法',
-				// 	details: '看它来喘口气,小小震撼,',
-				// 	people: '45708 '
-				// }, {
-				// 	title: '史士昊老师四神汤健脾消食疗法',
-				// 	details: '看它来喘口气,小小震撼,',
-				// 	people: '45708 '
-				// }, {
-				// 	title: '史士昊老师四神汤健脾消食疗法',
-				// 	details: '看它来喘口气,小小震撼,',
-				// 	people: '45708 '
-				// }, {
-				// 	title: '史士昊老师四神汤健脾消食疗法',
-				// 	details: '看它来喘口气,小小震撼,',
-				// 	people: '45708 '
-				// }, {
+				// },{
 				// 	title: '史士昊老师四神汤健脾消食疗法',
 				// 	details: '看它来喘口气,小小震撼,',
 				// 	people: '45708 '
@@ -513,12 +481,7 @@
 				// 		lable: '',
 				// 		name: '从芯开始',
 				// 		txt: '来了'
-				// 	},
-				// 	{
-				// 		lable: '',
-				// 		name: '观众2',
-				// 		txt: '已点赞'
-				// 	},
+				// 	}
 				// 	{
 				// 		lable: '',
 				// 		name: '北京的帅小伙:',
@@ -528,36 +491,18 @@
 				// 		lable: '',
 				// 		name: '萍萍',
 				// 		txt: '来了'
-				// 	},
-				// 	{
-				// 		lable: '',
-				// 		name: '豆爱生活:',
-				// 		txt: '试试看有没有效果'
-				// 	},
-				// 	{
-				// 		lable: '达人',
-				// 		name: '锅巴',
-				// 		txt: '中医调节身体确实'
-				// 	},
-				// 	{
-				// 		lable: '达人',
-				// 		name: '锅巴',
-				// 		txt: '中医调节身体确实'
-				// 	},
-				// 	{
-				// 		lable: '达人',
-				// 		name: '锅巴',
-				// 		txt: '中医调节身体确实中医调节身体确实中医调节身体确实中医调节身体确实'
 				// 	}
 				// ]
 
 			};
 		},
 		onLoad(options) {
-			// if (options.liveId) {
-			// 	this.liveId = decodeURIComponent(options.liveId);
-			// 	console.log("接收到的liveId:", this.liveId);
-			// }
+
+			if (options.liveId) {
+				this.liveId = options.liveId;
+				// this.liveId = decodeURIComponent(options.liveId);
+				console.log("接收到的liveId:", this.liveId);
+			}
 
 		},
 		computed: {
@@ -577,10 +522,10 @@
 			this.intervalId = setInterval(() => {
 				this.getliveViewData();
 			}, 60 * 1000);
-			this.getLiveinformation() // 获取直播间信息接口
+			// this.getLiveinformation() // 获取直播间信息接口
 			this.getliveOrder() //正在购买
 			this.getliveStore() // 获取小黄车 店铺展示
-			this.getliveGoods() // 获取小黄车 商品详情
+			// this.getliveGoods() // 获取小黄车 商品详情
 			this.getliveUser() // 获取直播间用户
 			this.initTime()
 			// this.initWebSocket()
@@ -615,22 +560,21 @@
 			}
 		},
 		methods: {
-			//获取订单列表
-			getOrderList() {
-				let data = {
-					page: 1,
-					pageSize: 10
-				}
-				liveOrderList(data).then(res => {
-						console.log("订单列表>>>>", res)
-						this.orderList = res
-
-					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
-				);
+			goStore() {
+				uni.navigateTo({
+					url: '/pages_shop/store?liveId=' + this.liveId
+				})
+				// uni.navigateTo({
+				// 	url: "/pages_shop/store"
+				// })
+			},
+			// 去订单列表
+			goOrderList() {
+				uni.navigateTo({
+					url: "/pages_shop/order"
+				})
 			},
+
 			// 初始化HLS播放器
 			initHlsPlayer() {
 				if (Hls.isSupported() && this.livingUrl) {
@@ -664,7 +608,7 @@
 				getlive(param).then(res => {
 					if (res.code == 200) {
 						this.livedata = res.data
-						this.codeimg = res.data.qwQrCode
+						// this.codeimg = res.data.qwQrCode
 						this.livingUrl = res.data.livingUrl; // 确保设置livingUrl
 
 						// 检查是否是HLS流
@@ -682,9 +626,14 @@
 							});
 						} else {
 							// 非HLS流正常播放
-							if (this.livedata.status == 1) {
+							if (this.livedata.liveType == 1) {
 								this.autoplay = true
+								this.livingUrl=res.videoUrl
 								this.videoContext.seek(this.livedata.nowDuration)
+							} else if(this.livedata.liveType == 2) {
+								this.autoplay = true
+								this.getLiveinformation()
+								// this.livingUrl=res.livingUrl
 							} else {
 								this.autoplay = false
 								this.placeholderText = "直播开始才能发言讨论"
@@ -727,7 +676,7 @@
 			getliveViewData() {
 				getLiveViewData(this.liveId).then(res => {
 						if (res.code == 200) {
-							console.log("直播间点赞、关注、在线人数数据>>>>", res)
+							// console.log("直播间点赞、关注、在线人数数据>>>>", res)
 							this.liveViewData = res
 						} else {
 							uni.showToast({
@@ -736,9 +685,7 @@
 							});
 						}
 					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
+					rej => {}
 				);
 			},
 			//正在购买
@@ -755,9 +702,7 @@
 							});
 						}
 					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
+					rej => {}
 				);
 			},
 			//小黄车 店铺展示
@@ -769,8 +714,8 @@
 				liveStore(this.liveId, data).then(res => {
 						if (res.code == 200) {
 							console.log("小黄车 店铺展示>>>>", res)
-							this.products = res.products
-							this.store = res.store
+							this.products = res.data
+							// this.store = res.store
 						} else {
 							uni.showToast({
 								title: res.msg,
@@ -778,32 +723,12 @@
 							});
 						}
 					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
-				);
-			},
-			//小黄车 商品详情
-			getliveGoods() {
-				liveGoodsDetail(this.products.productId).then(res => {
-						if (res.code == 200) {
-							console.log("小黄车 商品详情>>>>", res)
-							// this.=res.
-						} else {
-							uni.showToast({
-								title: res.msg,
-								icon: 'none'
-							});
-						}
-					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
+					rej => {}
 				);
 			},
 			// 获取直播间信息接口
 			getLiveinformation() {
-				getLive(this.liveId).then(res => {
+				getLiveInfo(this.liveId).then(res => {
 						if (res.code == 200) {
 							console.log("获取直播间信息接口>>>>", res)
 							this.livingUrl = res.livingUrl
@@ -815,9 +740,7 @@
 							});
 						}
 					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
+					rej => {}
 				);
 			},
 
@@ -834,19 +757,17 @@
 							});
 						}
 					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
+					rej => {}
 				);
 			},
 
 			// 点赞
 			onLike() {
-
 				liveDataLike(this.liveId).then(res => {
 						if (res.code == 200) {
 							if (
-								typeof res.msg === 'number' ||(typeof res.msg === 'string' && /^\d+$/.test(res.msg.trim()))
+								typeof res.msg === 'number' || (typeof res.msg === 'string' && /^\d+$/.test(res.msg
+									.trim()))
 							) {
 								this.liveData++
 							} else {
@@ -862,15 +783,22 @@
 							});
 						}
 					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
+					rej => {}
 				);
 
 			},
+			// 去购买,跳商品详情
+			goShop(item) {
+				console.log("去购买,跳商品详情", item)
+				uni.navigateTo({
+					url: '/pages_shop/goods?productId=' + item + '&liveId=' + this.liveId
+				})
+			},
+
 			// 收藏
 			onCollect(item) {
 				console.log("item>>>", item.productId)
+				uni.setStorageSync("storeId", storeId);
 				let data = {
 					liveId: this.liveId,
 					productId: item.productId,
@@ -886,11 +814,8 @@
 							});
 						}
 					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
+					rej => {}
 				);
-
 			},
 			// 关注
 			onFollow() {
@@ -901,14 +826,8 @@
 							icon: 'none'
 						});
 					},
-					rej => {
-						console.log("qxj rej:" + JSON.stringify(rej));
-					}
+					rej => {}
 				);
-			},
-			// 店铺
-			onShop() {
-
 			},
 			initTime() {
 				const now = new Date();
@@ -934,10 +853,7 @@
 				this.old.scrollTop = e.detail.scrollTop
 			},
 
-			// 小黄车
-			scrolltolower() {
-				this.loadmore();
-			},
+
 			loadmore() {
 				// for (let i = 0; i < 30; i++) {
 				//   this.indexList.push({
@@ -1120,33 +1036,33 @@
 			handleTouchEnd() {
 				this.isZoom = false; // 恢复原状
 			},
-			getliving() {
-				const param = {
-					id: this.liveId
-				}
-				getlive(param).then(res => {
-					if (res.code == 200) {
-						this.livedata = res.data
-						this.codeimg = res.data.qwQrCode
-						if (this.livedata.status == 1) {
-							this.autoplay = true
-							this.videoContext.seek(this.livedata.nowDuration)
-							// console.log(this.autoplay)
-						} else {
-							this.autoplay = false
-							this.placeholderText = "直播开始才能发言讨论"
-							this.talkdisabled = true
-						}
-						console.log(this.autoplay)
-					} else {
-						uni.showToast({
-							title: res.msg,
-							icon: 'none',
-							duration: 2000
-						});
-					}
-				})
-			},
+			// getliving() {
+			// 	const param = {
+			// 		id: this.liveId
+			// 	}
+			// 	getlive(param).then(res => {
+			// 		if (res.code == 200) {
+			// 			this.livedata = res.data
+			// 			this.codeimg = res.data.qwQrCode
+			// 			if (this.livedata.status == 1) {
+			// 				this.autoplay = true
+			// 				this.videoContext.seek(this.livedata.nowDuration)
+			// 				// console.log(this.autoplay)
+			// 			} else {
+			// 				this.autoplay = false
+			// 				this.placeholderText = "直播开始才能发言讨论"
+			// 				this.talkdisabled = true
+			// 			}
+			// 			console.log(this.autoplay)
+			// 		} else {
+			// 			uni.showToast({
+			// 				title: res.msg,
+			// 				icon: 'none',
+			// 				duration: 2000
+			// 			});
+			// 		}
+			// 	})
+			// },
 			getEWechatSdk() {
 				// 只在H5平台执行
 				// #ifdef H5
@@ -1209,9 +1125,7 @@
 					success: res => {
 						//先确保清除了之前的心跳定时器
 						clearInterval(pingpangTimes)
-
 						uni.onSocketMessage((res) => {
-
 							if (res.data.code == 500) {
 								uni.showToast({
 									title: res.data.msg,
@@ -1221,13 +1135,10 @@
 							}
 							const redata = JSON.parse(res.data);
 							console.log("WebSocket拿到的东西", redata)
-							// console.log(111,this.talklist)
 							this.talklist.push(redata.data)
 							this.$nextTick(() => {
 								this.scrollIntoView = `list_${this.talklist.length-1}`
 							})
-							// console.log(222,this.talklist)
-							// console.info(redata)
 							if (redata.cmd == 'deleteId') {
 								uni.$emit('deleteId');
 							} else if (redata.cmd == 'init') {
@@ -1300,7 +1211,6 @@
 				})
 			},
 			sendMsg() {
-
 				// this.userinfo = JSON.parse(uni.getStorageSync("userInfo"))
 				if (isSocketOpen) {
 					const data = {
@@ -1338,148 +1248,149 @@
 </script>
 
 <style scoped lang="scss">
-	.answerpop {
-		background: linear-gradient(to right, #fff7f8, #fee1e2);
-		margin-top: 30rpx;
-		padding: 10rpx 20rpx;
-		width: calc(100% - 40rpx);
-		border-radius: 20rpx;
-		display: flex;
-		align-items: center;
-		justify-content: space-between;
-		box-shadow: 2px 2px 4px 0 rgba(255, 124, 126, 0.1);
-
-		.answera {
-			display: flex;
-			justify-content: center;
-			background-color: #fff;
-			padding: 20rpx 0;
-			width: 35%;
-			border-radius: 40rpx;
-			align-items: center;
-			margin: 10rpx 0;
-			box-shadow: 2px 2px 4px 0 rgba(72, 72, 72, 0.1);
-
-			image {
-				width: 40rpx;
-				height: 40rpx;
-				margin-right: 10rpx;
-			}
-		}
-	}
-
-	.submitbtn {
-		width: 260rpx;
-		margin: 0 auto;
-		text-align: center;
-		border-radius: 80rpx;
-		padding: 20rpx 0;
-		color: #fff;
-		background-color: #ff5c03;
-	}
-
-	.itemanswer {
-		padding: 20rpx 20rpx;
-		text-align: center;
-		border-radius: 80rpx;
-		border: 2rpx solid #dddddd;
-		margin: 12rpx 0;
-		color: #555;
-		width: calc(100% - 40rpx);
-	}
-
-	.answeract {
-		background-color: rgba(0, 202, 166, 1);
-		color: #fff;
-	}
-
-	.answerbox {
-		width: 600rpx;
-		border-radius: 20rpx;
-	}
-
-	.welcome-message {
-		position: fixed;
-		width: 100%;
-		bottom: 120rpx;
-		left: 50%;
-		transform: translateX(-50%);
-		color: white;
-		padding: 10px 20px;
-		border-radius: 20px;
-		animation: fadeOut 1s ease 1s forwards;
-		z-index: 1000;
-	}
-
-	@keyframes fadeOut {
-		from {
-			opacity: 1;
-		}
-
-		to {
-			opacity: 0;
-		}
-	}
-
-	.container {
-		position: relative;
-		width: 100%;
-		height: 100vh;
-		overflow: hidden;
-	}
-
-	.talktext {
-		border-radius: 8rpx;
-		background-color: rgba(255, 255, 255, 0.1);
-
-		view {
-			width: 100%;
-		}
-	}
-
-	.talk-list {
-		border-radius: 30rpx;
-		background-color: rgba(255, 255, 255, 0.1);
-		padding: 10rpx 30rpx;
-	}
-
-	.zoom-button-active {
-		transform: scale(1.5);
-	}
-
-	.background-image {
-		position: absolute;
-		top: 0;
-		left: -40rpx;
-		width: 110%;
-		height: 110%;
-		object-fit: cover;
-		filter: blur(20px);
-		z-index: 0;
-	}
-
-	.background-images {
-		position: absolute;
-		top: 0;
-		left: -40rpx;
-		width: 110%;
-		height: 110%;
-		object-fit: cover;
-		filter: blur(20px);
-		z-index: 6;
-	}
-
-	.blackbg {
-		position: absolute;
-		top: 0;
-		left: 0;
-		width: 100%;
-		height: 100%;
-		background: rgba(0, 0, 0, 0.7);
-		object-fit: cover;
-		filter: blur(10px);
-		z-index: 1;
-	}
+	// 抽奖
+	// .answerpop {
+	// 	background: linear-gradient(to right, #fff7f8, #fee1e2);
+	// 	margin-top: 30rpx;
+	// 	padding: 10rpx 20rpx;
+	// 	width: calc(100% - 40rpx);
+	// 	border-radius: 20rpx;
+	// 	display: flex;
+	// 	align-items: center;
+	// 	justify-content: space-between;
+	// 	box-shadow: 2px 2px 4px 0 rgba(255, 124, 126, 0.1);
+
+	// 	.answera {
+	// 		display: flex;
+	// 		justify-content: center;
+	// 		background-color: #fff;
+	// 		padding: 20rpx 0;
+	// 		width: 35%;
+	// 		border-radius: 40rpx;
+	// 		align-items: center;
+	// 		margin: 10rpx 0;
+	// 		box-shadow: 2px 2px 4px 0 rgba(72, 72, 72, 0.1);
+
+	// 		image {
+	// 			width: 40rpx;
+	// 			height: 40rpx;
+	// 			margin-right: 10rpx;
+	// 		}
+	// 	}
+	// }
+
+	// .submitbtn {
+	// 	width: 260rpx;
+	// 	margin: 0 auto;
+	// 	text-align: center;
+	// 	border-radius: 80rpx;
+	// 	padding: 20rpx 0;
+	// 	color: #fff;
+	// 	background-color: #ff5c03;
+	// }
+
+	// .itemanswer {
+	// 	padding: 20rpx 20rpx;
+	// 	text-align: center;
+	// 	border-radius: 80rpx;
+	// 	border: 2rpx solid #dddddd;
+	// 	margin: 12rpx 0;
+	// 	color: #555;
+	// 	width: calc(100% - 40rpx);
+	// }
+
+	// .answeract {
+	// 	background-color: rgba(0, 202, 166, 1);
+	// 	color: #fff;
+	// }
+
+	// .answerbox {
+	// 	width: 600rpx;
+	// 	border-radius: 20rpx;
+	// }
+
+	// .welcome-message {
+	// 	position: fixed;
+	// 	width: 100%;
+	// 	bottom: 120rpx;
+	// 	left: 50%;
+	// 	transform: translateX(-50%);
+	// 	color: white;
+	// 	padding: 10px 20px;
+	// 	border-radius: 20px;
+	// 	animation: fadeOut 1s ease 1s forwards;
+	// 	z-index: 1000;
+	// }
+
+	// @keyframes fadeOut {
+	// 	from {
+	// 		opacity: 1;
+	// 	}
+
+	// 	to {
+	// 		opacity: 0;
+	// 	}
+	// }
+
+	// .container {
+	// 	position: relative;
+	// 	width: 100%;
+	// 	height: 100vh;
+	// 	overflow: hidden;
+	// }
+
+	// .talktext {
+	// 	border-radius: 8rpx;
+	// 	background-color: rgba(255, 255, 255, 0.1);
+
+	// 	view {
+	// 		width: 100%;
+	// 	}
+	// }
+
+	// .talk-list {
+	// 	border-radius: 30rpx;
+	// 	background-color: rgba(255, 255, 255, 0.1);
+	// 	padding: 10rpx 30rpx;
+	// }
+
+	// .zoom-button-active {
+	// 	transform: scale(1.5);
+	// }
+
+	// .background-image {
+	// 	position: absolute;
+	// 	top: 0;
+	// 	left: -40rpx;
+	// 	width: 110%;
+	// 	height: 110%;
+	// 	object-fit: cover;
+	// 	filter: blur(20px);
+	// 	z-index: 0;
+	// }
+
+	// .background-images {
+	// 	position: absolute;
+	// 	top: 0;
+	// 	left: -40rpx;
+	// 	width: 110%;
+	// 	height: 110%;
+	// 	object-fit: cover;
+	// 	filter: blur(20px);
+	// 	z-index: 6;
+	// }
+
+	// .blackbg {
+	// 	position: absolute;
+	// 	top: 0;
+	// 	left: 0;
+	// 	width: 100%;
+	// 	height: 100%;
+	// 	background: rgba(0, 0, 0, 0.7);
+	// 	object-fit: cover;
+	// 	filter: blur(10px);
+	// 	z-index: 1;
+	// }
 
 	.content {
 		position: relative;
@@ -1494,7 +1405,7 @@
 
 		.content-top {
 			width: 100%;
-			margin-top: 300rpx;
+			margin-top: 150rpx;
 			display: flex;
 			align-items: center;
 			justify-content: space-between;
@@ -1633,45 +1544,54 @@
 	.shoppop {
 		padding: 22rpx 16rpx;
 
-		.search-input {
-			width: 414rpx;
-			height: 76rpx;
-			background: #FFFFFF;
-			border-radius: 36rpx;
-			margin-left: 20rpx;
-			padding: 0 32rpx;
-			box-sizing: border-box;
-			font-size: 24rpx;
-			margin-right: 24rpx;
+		.shoppop-top {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 0 16rpx 22rpx;
 
-		}
+			.search-input {
+				width: 414rpx;
+				height: 76rpx;
+				background: #FFFFFF;
+				border-radius: 36rpx;
+				margin-left: 20rpx;
+				padding: 0 32rpx;
+				box-sizing: border-box;
+				font-size: 24rpx;
+				margin-right: 24rpx;
 
-		.search-top {
-			font-size: 18rpx;
-			color: #222222;
+			}
+
+			.search-top {
+				font-size: 18rpx;
+				color: #222222;
+			}
 		}
 
+
 		.shop-list {
+			overflow: hidden;
 
 			.list-item {
 				display: flex;
 				align-items: center;
 				padding: 20rpx 16rpx;
 				background: #FFFFFF;
-				border-radius: 16rpx 16rpx 16rpx 16rpx;
+				border-radius: 16rpx;
 				margin-bottom: 16rpx;
 
 				.goods-img {
 					width: 200rpx;
 					height: 200rpx;
-					border-radius: 16rpx 16rpx 16rpx 16rpx;
+					border-radius: 16rpx;
 					overflow: hidden;
 					position: relative;
 					margin-right: 24rpx;
 
 					image {
-						width: 200rpx;
-						height: 200rpx;
+						width: 100%;
+						height: 100%;
 					}
 
 					.goods-label {
@@ -1743,8 +1663,6 @@
 						}
 					}
 				}
-
-
 			}
 		}
 	}

+ 76 - 48
pages/list/index.vue

@@ -1,16 +1,17 @@
 <template>
-	<view class=" column">
-		<view class="u-flex-y-center">
+	<view class=" content ">
+		<view class="list">
 			<view class="list-item" @click="goLive(item)" v-for="(item,index) in list" :key="index">
-				{{index}}
+				<image :src="item.liveImgUrl"></image>
+				<view class="info">
+					<text>{{item.liveName}}</text>
+				</view>
 			</view>
+
 		</view>
-		<!-- <view class="list-item">
-		</view>
-		<view class="list-item">
-		</view> -->
+
 	</view>
-	
+
 </template>
 <script>
 	import {
@@ -23,6 +24,7 @@
 		data() {
 			return {
 				list: null,
+				liveId:null
 			}
 		},
 		onLoad(option) {
@@ -30,53 +32,79 @@
 		},
 		methods: {
 			goLive(item) {
-				var liveId=item.liveId
-				uni.setStorageSync('liveId', liveId);
-				
-				console.log("要传的liveId",liveId)
-			  uni.navigateTo({
-				  url:'/pages/home/living'
-			    // url: `/pages/home/living?liveId=${encodeURIComponent(JSON.stringify(liveId))}`
-			  });
+				this.liveId = item.liveId
+				console.log("要传的liveId", this.liveId)
+				uni.navigateTo({
+					url: '/pages/home/living?liveId='+this.liveId
+					// url: `/pages/home/living?liveId=${encodeURIComponent(JSON.stringify(liveId))}`
+				});
 			},
-			  getList() {
-			    const data = {
-			      page: 1,
-			      page_size: 10,
-			    };
-			    uni.showLoading({ title: "处理中..." });
-			    liveList(data)
-			      .then(res => {
-			        if (res.code == 200) {
-			          this.list = res.rows; // 直接赋值给 this.list
-			          console.log("list>>", this.list); // ✅ 打印已定义的 this.list
-			        } else {
-			          uni.showToast({ title: res.msg, icon: 'none' });
-			        }
-			      })
-			      .catch(rej => {
-			        console.log("请求失败:", JSON.stringify(rej));
-			      })
-			      .finally(() => {
-			        uni.hideLoading();
-			      });
-			  }
+			getList() {
+				const data = {
+					page: 1,
+					page_size: 10,
+				};
+				uni.showLoading({
+					title: "处理中..."
+				});
+				liveList(data)
+					.then(res => {
+						if (res.code == 200) {
+							this.list = res.rows; // 直接赋值给 this.list
+							console.log("list>>", this.list); // ✅ 打印已定义的 this.list
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					})
+					.catch(rej => {
+						console.log("请求失败:", JSON.stringify(rej));
+					})
+					.finally(() => {
+						uni.hideLoading();
+					});
+			}
 		}
 	}
 </script>
 
 <style lang="scss" scoped>
-	.list-item {
-		width: 100rpx;
-		height: 100rpx;
-		background-color: #0082f4;
-		margin-right: 10rpx;
-		color: #111;
+	.content {
+		background-color: #111;
+		min-height: 100vh;
+		padding: 24rpx;
 
-		image {
-			width: 100%;
-			height: 100%;
+		.list {
+			display: flex;
+			justify-content: space-between;
+			flex-wrap: wrap;
+
+			.list-item {
+				border-radius: 16rpx;
+				width: 340rpx;
+				height: 600rpx;
+				background-color: #0082f4;
+				margin-right: 10rpx;
+				margin-bottom: 24rpx;
+				overflow: hidden;
+				position: relative;
+
+				.info {
+					position: absolute;
+					left: 20rpx;
+					bottom: 14rpx;
+					color: #ffffff;
+				}
+
+				image {
+					width: 100%;
+					height: 100%;
+				}
+
+			}
 		}
 
 	}
-</style>
+</style>

+ 342 - 0
pages_no/payOrder.vue

@@ -0,0 +1,342 @@
+<template>
+	<view class="content">
+		<view class="inner">
+			<!-- 时间、价格 -->
+			<view class="time-price">
+				<text class="time">请在{{payLimitTime}}前完成支付</text>
+				<view class="price-box">
+					<text class="unit">¥</text>
+					<text class="num">{{order.payPrice}}</text>
+				</view>
+			</view>
+			<!-- 支付方式 -->
+			<view class="pay-type">
+				<view class="title">支付方式</view>
+				<view class="item">
+					<view class="left">
+						<image src="/static/images/wecha_pay.png" mode=""></image>
+						<text class="text">微信支付</text>
+					</view>
+					<label>
+						<checkbox disabled value="" :checked="wxPay" />
+					</label>
+				</view>
+			</view>
+			<!-- 订单详情查看 -->
+			<view class="order-info">
+				<view class="title">订单信息</view>
+				<view class="item">
+					<text class="label">订单编号</text>
+					<view class="sn-box">
+						<text class="text">{{order.orderCode}}</text>
+						<view class="copy-btn" @click="copyOrderSn(order.orderCode)">复制</view>
+					</view>
+				</view>
+				<view class="item">
+					<text class="label">下单时间</text>
+					<text class="text">{{order.createTime}}</text>
+				</view>
+				<view class="item">
+					<text class="label">支付方式</text>
+					<text class="text">微信支付</text>
+				</view>
+				 
+			</view>
+			
+		</view>
+		<view class="btn-box">
+			<view class="btn" @click="payOrder()">去支付</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	// import {pay,getStoreOrderById} from '@/api/storeOrder'
+	export default {
+		data() {
+			return {
+				payLimitTime:null,
+				order:null,
+				// 默认选中微信支付
+				wxPay: true,
+			}
+		},
+		onLoad: function(options) {
+		    if (options.hasOwnProperty('q') && options.q) {
+				// 通过下面这步解码,可以拿到url的值
+				const url = decodeURIComponent(options.q)
+				this.url=url;
+				// // 对url中携带的参数提取处理
+				const obj = this.utils.urlToObj(url)
+				this.orderId=obj.orderId;
+		    }
+			else if(options!=null&&options.orderId!=null){
+				this.orderId=options.orderId;
+			}
+		},
+		onShow() {
+			this.getStoreOrderById();
+		},
+		methods: {
+			copyOrderSn(text) {
+				// 复制方法
+				uni.setClipboardData({
+					data:text,
+					success:()=>{
+						uni.showToast({
+							title:'内容已成功复制到剪切板',
+							icon:'none'
+						})
+					}
+				});
+			},
+			getStoreOrderById(){
+				var data = {orderId:this.orderId};
+				var that=this;
+				uni.showLoading();
+				getStoreOrderById(data).then(
+					res => {
+						if(res.code==200){
+							 console.log(res);
+							  uni.hideLoading();
+							  that.order=res.order;
+							  that.payLimitTime=res.payLimitTime;
+						}else{
+							uni.showToast({
+								icon:'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+				
+			},
+			payOrder(){
+				var data = {orderId:this.order.id};
+				var that=this;
+				uni.showLoading();
+				pay(data).then(
+					res => {
+						if(res.code==200){
+							 console.log(res);
+							 uni.requestPayment({
+							 	provider: 'wxpay',
+							 	timeStamp: res.result.timeStamp,
+							 	nonceStr: res.result.nonceStr,
+							 	package: res.result.packageValue,
+							 	signType: res.result.signType,
+							 	paySign: res.result.paySign,
+							 	success: function(res) {
+							 		 uni.hideLoading();
+									 if(that.order.isPrescribe){
+										 //如果是处方订单开处方
+										uni.redirectTo({
+										 	url:"prescribe?orderId="+that.order.id
+										})
+									 }
+									 else{
+										//如果是普通订单
+										uni.redirectTo({
+											url:"success?order="+JSON.stringify(that.order)
+										}) 
+									 }
+							 	},
+							 	fail: function(err) {
+							 		console.log('fail:' + JSON.stringify(err));
+							 		uni.hideLoading();
+							 	}
+							 });
+						}else{
+							uni.showToast({
+								icon:'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+				
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page{
+		height: 100%;
+		background-color: #F2F5F9;
+	}
+	.content{
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+		.inner{
+			padding: 20upx;
+			.time-price{
+				box-sizing: border-box;
+				height: 200upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				padding-top: 50upx;
+				.time{
+					font-size: 26upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+					line-height: 1;
+					text-align: center;
+				}
+				.price-box{
+					display: flex;
+					align-items: flex-end;
+					margin-top: 28upx;
+					.unit{
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1.3;
+						margin-right: 10upx;
+					}
+					.num{
+						font-size: 56upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+			}
+			.pay-type{
+				box-sizing: border-box;
+				height: 192upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				margin-top: 20upx;
+				padding: 40upx 30upx;
+				display: flex;
+				flex-direction: column;
+				justify-content: space-between;
+				.title{
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+					line-height: 1;
+				}
+				.item{
+					display: flex;
+					align-items: center;
+					justify-content: space-between;
+					.left{
+						display: flex;
+						align-items: center;
+						image{
+							width: 44upx;
+							height: 44upx;
+							margin-right: 20upx;
+						}
+						.text{
+							font-size: 30upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #222222;
+							line-height: 1;
+						}
+					}
+				}
+			}
+			.order-info{
+				margin-top: 20upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				padding: 40upx 30upx;
+				.title{
+					font-size: 30upx;
+					font-family: PingFang SC;
+					font-weight: bold;
+					color: #222222;
+					line-height: 1;
+				}
+				.item{
+					margin-top: 40upx;
+					display: flex;
+					align-items: center;
+					justify-content: space-between;
+					.label{
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #666666;
+						line-height: 1;
+					}
+					.text{
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #222222;
+						line-height: 32upx;
+					}
+					.cont-text{
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #666666;
+						.bold{
+							color: #111111;
+						}
+					}
+					.sn-box{
+						display: flex;
+						align-items: center;
+						.copy-btn{
+							width: 58upx;
+							height: 32upx;
+							line-height: 32upx;
+							text-align: center;
+							font-size: 22upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #222222;
+							background: #F5F5F5;
+							border-radius: 4upx;
+							margin-left: 24upx;
+						}
+					}
+					 
+				}
+				.line{
+					width: 100%;
+					height: 1px;
+					background: #F0F0F0;
+					margin-top: 30upx;
+				}
+			}
+		}
+		.btn-box{
+			height: 121upx;
+			background: #FFFFFF;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			.btn{
+				width: 91.73%;
+				height: 88upx;
+				line-height: 88upx;
+				font-size: 30upx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				text-align: center;
+				background: #0bb3f2;
+				border-radius: 44upx;
+			}
+		}
+	}
+	
+</style>

+ 507 - 0
pages_shop/cart.vue

@@ -0,0 +1,507 @@
+<template>
+	<view class="content">
+		<!-- 商品列表 -->
+		<view class="shopbox" v-for="(shop,idx) in carts" :key="idx">
+			<view class="shopbox-name" v-if="shop.storeName && shop.storeName != 'null'">
+				<label style="margin-right: 30upx;">
+					<checkbox :value="shop.checked" :checked="shop.checked" @click="checkShopChange(shop)" />
+				</label>
+				<text>{{shop.storeName}}</text>
+			</view>
+			<view class="goods-list">
+				<view class="item" v-for="(item,index) in shop.list" :key="index">
+					<label style="margin-right: 30upx;">
+						<checkbox :value="item.checked"  :checked="item.checked" @click="checkChange(item,shop)" />
+					</label>
+					<image class="goods-img" :src="item.productAttrImage==null||item.productAttrImage==''?item.productImage:item.productAttrImage" mode="aspectFit"></image>
+					<view class="info-box">
+						<view>
+							<view class="title-box">
+								<view class="tag">{{utils.getDictLabelName("storeProductType",item.productType)}}</view>
+								<view class="title ellipsis">{{ item.productName }}</view>
+							</view>
+							<view class="intro ellipsis">{{item.productAttrName}}</view>
+						</view>
+						<view class="price-num">
+							<view class="price">
+								<text class="unit">¥</text>
+								<text class="text">{{item.price}}</text>
+							</view>
+							<view class="num-box">
+								<view class="img-box" @click="delNum(item)">
+									<image v-if="item.cartNum <= 1" src="/static/images/jian.png" mode=""></image>
+									<image v-else src="/static/images/jian2.png" mode=""></image>
+								</view>
+								<input  type="number" @change="changeNum($event,item)" :value="item.cartNum"   />
+								<view class="img-box" @click="addNum(item)">
+									<image src="/static/images/add.png" mode=""></image>
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view v-if="carts.length == 0" class="no-data-box">
+			<image src="/static/images/no_data.png" mode="aspectFit"></image>
+			<view class="empty-title">暂无数据</view>
+		</view>
+		<!-- 猜你喜欢 -->
+		 
+		<view class="like-product">
+			<likeProduct  ref="product" />
+		</view>
+		<!-- 底部按钮 -->
+		<view class="btn-foot">
+			<view class="left">
+				<label>
+					<checkbox  :checked="checkAll" @click="handleCheckAll()" />
+				</label>
+				<text class="text">全选</text>
+				<text class="text" @click="delCart()">删除</text>
+			</view>
+			<view class="right">
+				<view class="total">
+					<text class="label">合计:</text>
+					<view class="price">
+						<text class="unit">¥</text>
+						<text class="num">{{totalMoney.toFixed(2)}}</text>
+					</view>
+				</view>
+				<view class="btn" @click="submit">结算</view>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	// import {getCarts,cartNum,delCart} from '@/api/product'
+	import likeProduct from './components/likeProduct.vue'
+	export default {
+		components: {
+			likeProduct
+		},	
+		data() {
+			return {
+				 
+				totalMoney:0.00,
+				carts:[],
+				checkAll:false,
+			}	
+		},
+		onLoad() {
+			// this.getCarts();
+ 
+		},
+		onShow() {
+			this.getCarts();
+		},
+		onReachBottom() {
+			// this.$refs.product.getGoodsProducts();
+		},
+		methods: {
+			delCart(){			
+				var selectCarts = this.carts.flatMap(item => item.list.filter(listItem => listItem.checked === true)).map(el => el.id);
+				
+				if(selectCarts.length==0){
+					uni.showToast({
+						icon:'none',
+						title: "请选择商品删除",
+					});
+					return;
+				}
+				let data = {ids:selectCarts};
+				delCart(data).then(
+					res => {
+						if(res.code==200){
+							uni.showToast({
+								icon:'success',
+								title: "操作成功",
+							});
+							this.getCarts()
+						}else{
+							
+							uni.showToast({
+								icon:'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+				console.log(selectCarts)
+			},
+			computedMoney(){
+				var money=0;
+				var that=this;
+				this.carts.forEach((item,index,arr)=>{
+					item.list.forEach(it => {
+						if(it.checked){
+							money+=it.price*it.cartNum;
+						}
+					});
+				})
+				console.log(money);
+				this.totalMoney=money;
+			},
+			handleCheckAll(){
+				this.checkAll=!this.checkAll;
+				var that=this;
+				this.carts.forEach((item,index,arr)=>{
+				     item.checked=that.checkAll;
+					 item.list.forEach(it => {
+					 	it.checked=that.checkAll;
+					 });
+				})
+				this.computedMoney();
+			},
+			checkShopChange(item) {
+				item.checked = !item.checked;
+				item.list.forEach(it => {
+					it.checked= item.checked;
+				});
+				this.computedMoney();
+			},
+			checkChange(item,shop){
+				item.checked=!item.checked;
+				shop.checked = shop.list.every(it => it.checked == true);
+				this.computedMoney();
+			},
+			changeNum(e,item) {
+				item.cartNum = e.detail.value.replace(/\D/g, '')
+				if (item.cartNum <= 1) {
+				  uni.showToast({
+				    title: "已经是底线啦!",
+				    icon: "none",
+				    duration: 2000
+				  });
+				  return;
+				}
+				if(item.cartNum < 1) {
+					item.cartNum = 1
+				}
+				if(item.cartNum>=item.stock){
+					item.cartNum=item.stock;
+				}
+				this.changeCartNum(item)
+			},
+			changeCartNum(item){
+				let data = {number:item.cartNum,id:item.id};
+				cartNum(data).then(
+					res => {
+						if(res.code==200){
+							uni.showToast({
+								icon:'none',
+								title: "操作成功",
+							});
+							this.computedMoney();
+							
+						}else{
+							
+							uni.showToast({
+								icon:'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			getCarts(){
+				getCarts().then(
+					res => {
+						if(res.code==200){
+							 this.carts=res.carts;
+							 this.carts.forEach(item => {
+							   item.checked = false;
+							   item.list.forEach(it => {
+							     it.checked = false;
+							   });
+							 });
+							 this.computedMoney();
+						}else{
+							uni.showToast({
+								icon:'none',
+								title: "请求失败",
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			// 购物车减法
+			delNum(item) {
+				if (item.cartNum <= 1) {
+				  uni.showToast({
+				    title: "已经是底线啦!",
+				    icon: "none",
+				    duration: 2000
+				  });
+				  return;
+				}
+				item.cartNum --
+				if(item.cartNum < 1) {
+					item.cartNum = 1
+				}
+				 
+				this.changeCartNum(item)
+			},
+			// 购物车加法
+			addNum(item) {
+				console.log(item)
+				item.cartNum++
+				if(item.cartNum>=item.stock){
+					item.cartNum=item.stock;
+				}
+				this.changeCartNum(item)
+			},
+			// 结算
+			submit() {
+				let selectCarts = this.carts
+				  .filter(item => item.list.some(listItem => listItem.checked === true))
+				  .map(item => ({
+				    storeId: item.list[0].storeId || "",
+				    data: {
+				      type: "cart",
+				      cartIds: item.list.filter(it=>it.checked == true).map(it => it.id).join(","),
+				    }
+				  }));
+				if(selectCarts.length==0){
+					uni.showToast({
+						icon:'none',
+						title: "请选择商品",
+					});
+					return;
+				}
+				uni.navigateTo({
+					url: './confirmOrder?type=cart&confirmParam='+ encodeURIComponent(JSON.stringify(selectCarts))
+				})
+			},
+			showProduct(item){
+				uni.navigateTo({
+					url: '../shopping/productDetails?productId='+item.productId
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	page {
+		height: 100%;
+	}
+	.content{
+		height: 100%;
+		padding: 20upx;
+		.shopbox {
+			background: #FFFFFF;
+			border-radius: 16rpx;
+			margin-bottom: 20rpx;
+		}
+		.shopbox-name {
+			padding: 30rpx 30rpx 0 30rpx;
+			font-family: PingFang SC, PingFang SC;
+			font-weight: 400;
+			font-size: 30rpx;
+			color: #111;
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+		}
+		.goods-list{
+			.item{
+				box-sizing: border-box;
+				height: 221upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				margin-bottom: 20upx;
+				padding: 30upx;
+				display: flex;
+				align-items: center;
+				&:last-child{
+					margin-bottom: 0;
+				}
+				.goods-img{
+					width: 160upx;
+					height: 160upx;
+					background: #FFFFFF;
+					margin-right: 30upx;
+					flex-shrink: 0;
+				}
+				.info-box{
+					height: 160upx;
+					display: flex;
+					flex-direction: column;
+					justify-content: space-between;
+					width: calc(100% - 255upx);
+					.title-box{
+						width: 100%;
+						display: flex;
+						align-items: center;
+						.tag{
+							padding: 0 6upx;
+							height: 30upx;
+							line-height: 30upx;
+							font-size: 22upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #FFFFFF;
+							background: linear-gradient(90deg, #66b2ef 0%, #0bb3f2 100%);
+							border-radius: 4upx;
+							margin-right: 10upx;
+							flex-shrink: 0;
+						}
+						.title{
+							flex: 1;
+							font-size: 28upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #111111;
+							line-height: 1;
+						}
+					}
+					.intro{
+						font-size: 24upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #999999;
+						margin-top: 22upx;
+						line-height: 1;
+					}
+					.price-num{
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+						.price{
+							display: flex;
+							align-items: flex-end;
+							.unit{
+								font-size: 24upx;
+								font-family: PingFang SC;
+								font-weight: 500;
+								color: #FF6633;
+								line-height: 1.2;
+								margin-right: 4upx;
+							}
+							.text{
+								font-size: 32upx;
+								font-family: PingFang SC;
+								font-weight: bold;
+								color: #FF6633;
+								line-height: 1;
+							}
+						}
+						.num-box{
+							display: flex;
+							align-items: center;
+							.img-box{
+								width: 60upx;
+								height: 60upx;
+								// border-radius: 4upx;
+								border: 1px solid #dddddd;
+								display: flex;
+								align-items: center;
+								justify-content: center;
+								image{
+									width: 25rpx;
+									height: 25rpx;
+								}
+							}
+							input{
+								width: 60upx;
+								height: 60upx;
+								line-height: 60upx;
+								font-size: 28upx;
+								font-family: PingFang SC;
+								font-weight: 500;
+								color: #111111;
+								// border-radius: 4upx;
+								border-top: 1px solid #dddddd;
+								border-bottom: 1px solid #dddddd;
+								text-align: center;
+								// margin: 0 16upx;
+							}
+						}
+					}
+				}
+			}
+		}
+		.like-product{
+			padding-bottom: 120upx;
+		}
+		.btn-foot{
+			box-sizing: border-box;
+			width: 100%;
+			height: 121upx;
+			background: #FFFFFF;
+			padding: 16upx 30upx 16upx 60upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			position: fixed;
+			left: 0;
+			bottom: 0;
+			z-index: 99;
+			.left{
+				display: flex;
+				align-items: center;
+				.text{
+					margin-left: 14upx;
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #666666;
+					line-height: 1;
+				}
+			}
+			.right{
+				display: flex;
+				align-items: center;
+				.total{
+					display: flex;
+					align-items: flex-end;
+					margin-right: 36upx;
+					.label{
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #999999;
+						line-height: 1.5;
+					}
+					.price{
+						display: flex;
+						align-items: flex-end;
+						.unit{
+							font-size: 32upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #FF6633;
+							line-height: 1.2;
+							margin-right: 10upx;
+						}
+						.num{
+							font-size: 30upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #FF6633;
+							line-height: 1;
+						}
+					}
+				}
+				.btn{
+					width: 200upx;
+					height: 88upx;
+					line-height: 88upx;
+					text-align: center;
+					font-size: 30upx;
+					font-family: PingFang SC;
+					font-weight: bold;
+					color: #FFFFFF;
+					background: #0bb3f2;
+					border-radius: 44upx;
+				}
+			}
+		}
+	}
+</style>

+ 181 - 0
pages_shop/components/likeProduct.vue

@@ -0,0 +1,181 @@
+<template>
+   <view>
+		<view class="like-title">
+			<image src="/static/images/like.png" mode=""></image>
+			<text class="text">猜你喜欢</text>
+		</view>
+		<view class="like-list">
+			<view class="item" v-for="(item,index) in list" :key="index" @click="showProduct(item)">
+				<view class="img-box">
+					<image :src="item.image" mode=""></image>
+				</view>
+				<view class="info-box">
+					<view class="title ellipsis2">{{ item.productName }}</view>
+					<view class="price-box">
+						<view class="now">
+							<text class="unit">¥</text>
+							<text class="num">{{item.price.toFixed(2)}}</text>
+						</view>
+						<view class="old">¥{{item.otPrice.toFixed(2)}}</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<Loading :loaded="loaded" :loading="loading"></Loading>
+   </view>
+</template>
+
+<script>
+  // import {getGoodsProducts} from '@/api/product'
+  import Loading from "@/components/Loading";
+  export default {
+	components: {Loading },
+    name: "likeProduct",
+	data() {
+		return {
+			page:{
+				page: 1,
+				pageSize: 10
+			},
+			total:0,
+			list:[],
+			loaded: false,
+			loading: false
+		};
+	},
+	created() {
+	},
+	mounted() {
+		this.getGoodsProducts();
+	},
+	
+	methods: {
+		getGoodsProducts(){
+			console.log(1)
+			var that=this;
+			if (that.loaded == true || that.loading == true) return;
+			that.loading = true;
+			uni.showLoading({
+				title:"加载中..."
+			})
+			getGoodsProducts(that.page).then(
+				res => {
+					if(res.code==200){
+						that.total=res.data.total;
+						that.list.push.apply(that.list, res.data.list);
+						that.loading = false;
+						that.loaded = that.list.length<that.total?false:true;
+						that.page.page = that.page.page + 1;
+						uni.hideLoading()
+					}
+				},
+				err => {
+					uni.hideLoading()
+					uni.showToast({
+						title: err.msg ,
+						icon: 'none',
+						duration: 2000
+					});
+				}
+			);
+		},
+		showProduct(item){
+			uni.navigateTo({
+				url: '/pages/shopping/productDetails?productId='+item.productId
+			})
+		},
+	}
+ 
+  };
+</script>
+<style lang="scss">
+	.like-title{
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		padding: 30upx 0;
+		image{
+			width: 37upx;
+			height: 37upx;
+			margin-right: 20upx;
+		}
+		.text{
+			font-size: 36upx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #111111;
+			line-height: 1;
+		}
+	}
+	.like-list{
+		display: flex;
+		flex-wrap: wrap;
+		.item{
+			margin-right: 20rpx;
+			margin-bottom: 20rpx;
+			width: 345rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 0px 10rpx 4rpx rgba(199, 199, 199, 0.22);
+			border-radius: 20rpx;
+			overflow: hidden;
+			&:nth-child(2n) {
+				margin-right: 0;
+			}
+			.img-box{
+				width: 100%;
+				height: 334upx;
+				image{
+					width: 100%;
+					height: 100%;
+				}
+			}
+			.info-box{
+				box-sizing: border-box;
+				height: 182upx;
+				padding: 20upx 20upx 30upx;
+				display: flex;
+				flex-direction: column;
+				justify-content: space-between;
+				.title{
+					font-size: 26upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #111111;
+					line-height: 40upx;
+				}
+				.price-box{
+					display: flex;
+					align-items: flex-end;
+					.now{
+						display: flex;
+						align-items: flex-end;
+						margin-right: 20upx;
+						.unit{
+							font-size: 24upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #FF6633;
+							line-height: 1.2;
+							margin-right: 4upx;
+						}
+						.num{
+							font-size: 36upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #FF6633;
+							line-height: 1;
+						}
+					}
+					.old{
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						text-decoration: line-through;
+						color: #BBBBBB;
+						line-height: 1.1;
+					}
+				}
+			}
+		}
+	}
+</style>

+ 1051 - 0
pages_shop/confirmCreateOrder.vue

@@ -0,0 +1,1051 @@
+<template>
+	<view>
+		<view class="inner-box">
+			<!-- 收货人 -->
+			<view class="address-box" v-if="address==null" @click="openAddress()">
+				<view class="left">
+					<view class="name-box">
+						<text class="text name">添加收货地址</text>
+					</view>
+				</view>
+				<view class="arrow-box">
+					<image src="/static/images/arrow_gray.png" mode=""></image>
+				</view>
+			</view>
+			<view class="address-box" v-if="address!=null" @click="openAddress()">
+				<view class="left">
+					<view class="name-box">
+						<text class="text name">{{address.realName}}</text>
+						<text class="text" v-if="address.phone!=null">{{$parsePhone(address.phone)}}</text>
+					</view>
+					<view class="address">
+						{{address.province}}{{address.city}}{{address.district}}{{address.detail}}
+					</view>
+				</view>
+				<view class="arrow-box">
+					<image src="/static/images/arrow_gray.png" mode=""></image>
+				</view>
+			</view>
+			<!-- 药品列表 -->
+			<view class="shopbox" v-for="(shop,idx) in carts" :key="idx">
+				<view class="shopbox-name" v-if="shop.storeName && shop.storeName != 'null'">
+					<text>{{shop.storeName}}</text>
+				</view>
+				<view class="goods-list">
+					<view v-for="(item,index) in shop.list" :key="index" class="item">
+						<view class="img-box">
+							<image :src="item.productAttrImage?item.productAttrImage:item.productImage"
+								mode="aspectFill"></image>
+						</view>
+						<view class="info-box">
+							<view>
+								<view class="name-box ellipsis2">
+									<view class="tag">{{utils.getDictLabelName("storeProductType",item.productType)}}
+									</view>{{item.productName}}
+								</view>
+								<view class="spec ellipsis2">{{item.productAttrName}}</view>
+							</view>
+							<view class="price-num">
+								<view class="price">
+									<text class="unit">¥</text>
+									<text class="num">{{item.price?.toFixed(2)}}</text>
+								</view>
+								<view class="num">x{{item.cartNum}}</view>
+							</view>
+						</view>
+					</view>
+					<!-- 运费 -->
+					<view class="points">
+						<view class="left">
+							<text class="text">运费</text>
+						</view>
+						<view class="right" v-if="price&&price.length > 0">
+							<text
+								class="text">{{price[idx].payPostage==null||price[idx].payPostage==0?'免运费':price[idx].payPostage.toFixed(2)}}</text>
+						</view>
+					</view>
+					<!-- 备注 -->
+					<view class="points">
+						<view class="left">
+							<text class="text">备注</text>
+						</view>
+						<view class="remarks">
+							<input type="text" v-model="shop.markinfo" placeholder="备注留言(选填)"
+								placeholder-class="input" />
+						</view>
+					</view>
+				</view>
+			</view>
+			<!-- 积分 -->
+			<view class="price-info">
+				<view class="price-info-title">价格明细</view>
+				<view class="points">
+					<view class="left">
+						<text class="text">商品总价</text>
+					</view>
+					<view class="right" style="align-items: baseline;">
+						<text class="price-info-unit">¥</text>
+						<text class="price-info-num">{{price?.toFixed(2)}}</text>
+					</view>
+				</view>
+				<!-- <view class="points">
+					<view class="left">
+						<image src="/static/images/points.png" mode=""></image>
+						<text class="text">可用积分</text>
+					</view>
+					<view class="right">
+						<text class="text">{{priceAll.usedIntegral}}积分</text>
+						<evan-switch @change="integralChange" v-model="checked" activeColor="#0bb3f2"
+							inactiveColor="rgba(0, 0, 0, 0.1)"></evan-switch>
+					</view>
+				</view> -->
+				<!-- <view class="points" @click="openCoupon()">
+					<view class="left">
+						<text class="text">优惠券</text>
+					</view>
+					<view class="right">
+						<text class="text">{{couponText}}</text>
+						<image src="/static/images/arrow4.png" mode=""></image>
+					</view>
+				</view> -->
+				<view class="points">
+					<view class="left">
+						<text class="text">合计</text>
+					</view>
+					<view class="right" style="align-items: baseline;">
+						<text class="price-info-unit">¥</text>
+						<text class="price-info-num">{{priceSum?.toFixed(2)}}</text>
+					</view>
+				</view>
+			</view>
+			<!-- <view class="points">
+				<view class="left">
+					<text class="text">运费</text>
+				</view>
+				<view class="right">
+					<text class="text">{{price.payPostage==null||price.payPostage==0?'免运费':price.payPostage.toFixed(2)}}</text>
+				</view>
+			</view> -->
+			<!-- 备注 -->
+			<!-- <view class="remarks">
+				<input type="text" v-model="form.mark" placeholder="备注留言(选填)" placeholder-class="input" />
+			</view> -->
+		</view>
+		<!-- 底部按钮 -->
+		<view class="btn-foot">
+			<view class="right">
+				<view class="total">
+					<text class="label">合计:</text>
+					<view class="price">
+						<text class="unit">¥</text>
+						<text class="num">{{priceSum?.toFixed(2)}}</text>
+					</view>
+				</view>
+				<view class="btn" @click="submitOrder">提交订单</view>
+			</view>
+		</view>
+		<popupBottom ref="popup" :visible.sync="couponVisible" title=" " bgColor="#f5f5f5" radius="30" maxHeight="60%">
+			<view class="coupon" style="height:650rpx;">
+				<div class="coupon-list" v-if="couponsList.length > 0">
+					<div class="item acea-row row-center-wrapper" v-for="(item, index) in couponsList" :key="index">
+						<div class="money">
+							<image v-if="item.status==0" class="img" src="/static/images/coupon1.png" mode="widthFix">
+							</image>
+							<image v-if="item.status!=0" class="img" src="/static/images/coupon2.png" mode="widthFix">
+							</image>
+							<div style="z-index: 999;">
+								¥<span class="num">{{ item.couponPrice }}</span>
+							</div>
+							<div class="pic-num">满{{ item.useMinPrice }}元可用</div>
+						</div>
+						<div class="text">
+							<div class="condition line1">
+								{{ item.couponTitle }}
+							</div>
+							<div class="data acea-row row-between-wrapper">
+								<div>{{ item.limitTime }}到期</div>
+								<div class="bnt bg-color-red" @click="couponSelect(item)">选择</div>
+							</div>
+						</div>
+					</div>
+				</div>
+				<view v-if="couponsList.length == 0" class="no-data-box">
+					<image src="/static/images/no_data.png" mode="aspectFit"></image>
+					<view class="empty-title">暂无数据</view>
+				</view>
+			</view>
+
+		</popupBottom>
+	</view>
+</template>
+
+<script>
+	// import {getWeixinOrderTemps} from '@/api/common'
+
+	// import {confirm,computed,create} from '@/api/storeOrder'
+	// import { getMyEnableCouponList } from '@/api/coupon'
+	import {
+		createliveOrder, // 创建订单
+	} from "@/api/order.js"
+	import EvanSwitch from '@/components/evan-switch/evan-switch.vue'
+	import popupBottom from '@/components/px-popup-bottom/px-popup-bottom.vue'
+
+	export default {
+		components: {
+			EvanSwitch,
+			popupBottom
+		},
+		data() {
+			return {
+				address: null,
+				addressId: null,
+				totalNum: null,
+				orderKey: null,
+				price: null,
+				liveId: null,
+				orderList: [],
+				userInfo: null,
+				userAddrLiat: [], //用户地址
+				temps: [],
+				couponUserId: null,
+				couponText: "请选择",
+				couponsList: [],
+				couponVisible: false,
+				priceAll: {
+					payPrice: 0,
+					totalPostage: 0,
+					usedIntegral: 0,
+					totalPrice: 0.00,
+				},
+				address: null,
+				carts: [],
+				checked: false,
+				type: null,
+				cartIds: null,
+				// form:{
+				// 	useIntegral:0,
+				// 	orderKey:null,
+				// 	addressId:null,
+				// 	mark:null,
+				// 	companyId:null,
+				// 	companyUserId:null,
+				// 	createOrderKey:null,
+				// },
+				confirmParam: []
+			}
+		},
+		computed: {
+			priceSum() {
+				return this.price * this.totalNum;
+			}
+		},
+		onLoad(options) {
+			console.log("确认订单", options)
+			this.orderKey = options.orderKey;
+			this.liveId = options.liveId
+			this.productId = options.productId
+			this.totalNum = Number(options.totalNum)
+			this.price = Number(options.price)
+
+
+			// this.confirmParam = JSON.parse(decodeURIComponent(option.confirmParam))
+			// this.form.createOrderKey=option.createOrderKey;
+			// this.form.companyId= option.companyId;
+			// this.form.companyUserId=option.companyUserId;
+			// this.cartIds=option.cartIds;
+			// this.type=option.type;
+			// this.confirm();
+			// uni.$on('updateAddress', (e) => {
+			// 	console.log("e",e)
+			// 	this.address=e;
+			// 	this.addressId=e.id;
+			// })
+			// this.getWeixinOrderTemps();
+		},
+		mounted() {
+			uni.$on('updateAddress', (e) => {
+					this.address = e;
+					this.addressId = e.addressId;
+			});
+		},
+		beforeDestroy() {
+			// 移除事件监听,避免内存泄漏
+			uni.$off('updateAddress');
+		},
+		methods: {
+
+			// 创建订单
+			createLiveOrder() {
+				let data = {
+					liveId: this.liveId,
+					orderKey: this.orderKey,
+					// storeId:this.storeId,,
+					userName: "没名字",
+					userPhone: "1234568",
+					userAddress: "随便住",
+					// cartId:"5",
+					productId: this.productId,
+					totalNum: this.totalNum,
+					// totalPrice:999,
+					// remark:"随便备注",
+
+				}
+				return createliveOrder(data).then(res => { // 添加 return
+					if (res.code == 200) {
+						this.orderList = res.order;
+						return res.order; // 返回订单数据供后续使用
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+						throw new Error(res.msg); // 抛出错误以便 submitOrder 捕获
+					}
+				});
+			},
+			getWeixinOrderTemps: function() {
+				getWeixinOrderTemps().then(
+					res => {
+						if (res.code == 200) {
+							this.temps = res.temp
+						} else {
+
+						}
+					},
+					rej => {}
+				);
+			},
+			couponSelect(item) {
+				this.couponText = "-¥" + item.couponPrice.toFixed(2);
+				this.couponUserId = item.id;
+				this.couponVisible = false;
+				this.computed();
+			},
+			openCoupon() {
+				let that = this;
+				var data = {
+					couponType: 2,
+					useMinPrice: this.price.payPrice
+				};
+				getMyEnableCouponList(data).then(res => {
+					this.couponVisible = true;
+					that.couponsList = res.data
+				})
+			},
+			integralChange(e) {
+				this.form.useIntegral = e ? 1 : 0
+				this.computed()
+			},
+			// confirm(item) {
+			// 	// let data = {type:this.type,cartIds:this.cartIds};
+			// 	confirm(this.confirmParam).then(
+			// 		res => {
+			// 			if (res.code == 200) {
+
+			// 				this.carts = res.carts.map(item => ({
+			// 					...item,
+			// 					markinfo: ""
+			// 				}));
+			// 				this.form.orderKey = res.orderKeys;
+			// 				if (res.address != null) {
+			// 					this.form.addressId = res.address.id;
+			// 					this.address = res.address;
+			// 				}
+			// 				this.computed()
+			// 			} else {
+
+			// 				uni.showToast({
+			// 					icon: 'none',
+			// 					title: res.msg,
+			// 				});
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+			// computed(item) {
+			// 	let data = {
+			// 		createOrderKey: this.form.createOrderKey,
+			// 		couponUserId: this.couponUserId,
+			// 		orderKeys: this.form.orderKey,
+			// 		addressId: this.form.addressId,
+			// 		useIntegral: this.form.useIntegral
+			// 	};
+			// 	computed(data).then(
+			// 		res => {
+			// 			if (res.code == 200) {
+			// 				// this.price=res.data
+			// 				this.price = res.data && res.data.length > 0 ? res.data : []
+			// 				this.priceAll = res.data && res.data.length > 0 ? res.data[res.data.length - 1] : {
+			// 					payPrice: 0,
+			// 					totalPostage: 0,
+			// 					usedIntegral: 0,
+			// 					totalPrice: 0.00,
+			// 				}
+			// 			} else {
+			// 				if (res.code == 501) {
+			// 					uni.showToast({
+			// 						icon: 'none',
+			// 						title: res.msg,
+			// 					});
+			// 					setTimeout(function() {
+			// 						uni.navigateBack({
+			// 							delta: 1
+			// 						})
+			// 					}, 500);
+			// 					return;
+			// 				} else {
+			// 					uni.showToast({
+			// 						icon: 'none',
+			// 						title: res.msg,
+			// 					});
+			// 				}
+
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+			// 提交订单
+			async submitOrder() {
+					try {
+						if (this.orderKey == null) {
+							uni.showToast({
+								icon: 'none',
+								title: '订单KEY不存在',
+							});
+							return;
+						}
+						if (this.address == null) {
+							uni.showToast({
+								icon: 'none',
+								title: '收货地址不能为空',
+							});
+							return;
+						}
+						const orderList = await this.createLiveOrder(); // 等待订单数据返回
+						const orderListStr = encodeURIComponent(JSON.stringify(orderList));
+						uni.navigateTo({
+							url: `/pages_shop/paymentOrder?orderList=${orderListStr}`
+						});
+					} catch (error) {
+						console.error('订单创建失败:', error);
+						uni.showToast({
+							title: '提交失败',
+							icon: 'none'
+						});
+					}
+				}
+				// var that=this;
+				// if(this.form.orderKey==null){
+				// 	uni.showToast({
+				// 		icon:'none',
+				// 		title: '订单KEY不存在',
+				// 	});
+				// 	return;
+				// }
+				// if(this.form.addressId==null){
+				// 	uni.showToast({
+				// 		icon:'none',
+				// 		title: '收货地址不能为空',
+				// 	});
+				// 	return;
+				// }
+
+				// uni.requestSubscribeMessage({
+				// 	tmplIds: this.temps,
+				// 	success(res) {
+				// 		 that.createOrder();
+				// 	},
+				// 	fail(res) {
+				// 		that.createOrder();
+				// 	}
+				// })
+
+				,
+			// createOrder() {
+			// 	const mark = this.carts.map(item => item.markinfo)
+			// 	var that = this;
+			// 	var data = null;
+			// 	var tuiUserId = uni.getStorageSync('tuiUserId');
+			// 	uni.showLoading({
+			// 		title: '正在处理中...'
+			// 	});
+			// 	if (tuiUserId != null && tuiUserId != undefined && tuiUserId > 0) {
+			// 		data = {
+			// 			createOrderKey: this.form.createOrderKey,
+			// 			orderCreateType: 3,
+			// 			tuiUserId: tuiUserId,
+			// 			companyId: this.form.companyId,
+			// 			companyUserId: this.form.companyUserId,
+			// 			couponUserId: this.couponUserId,
+			// 			mark: mark,
+			// 			orderKeys: this.form.orderKey,
+			// 			addressId: this.form.addressId,
+			// 			useIntegral: this.form.useIntegral,
+			// 			payType: 1
+			// 		};
+			// 	} else {
+			// 		data = {
+			// 			createOrderKey: this.form.createOrderKey,
+			// 			orderCreateType: 3,
+			// 			companyId: this.form.companyId,
+			// 			companyUserId: this.form.companyUserId,
+			// 			couponUserId: this.couponUserId,
+			// 			mark: mark,
+			// 			orderKeys: this.form.orderKey,
+			// 			addressId: this.form.addressId,
+			// 			useIntegral: this.form.useIntegral,
+			// 			payType: 1
+			// 		};
+			// 	}
+			// 	create(data).then(
+			// 		res => {
+			// 			uni.hideLoading()
+			// 			if (!res.code && res.code !== 0) {
+			// 				uni.hideLoading()
+			// 				// if(res.order.isPrescribe==1){
+			// 				// 	setTimeout(function(){
+			// 				// 		uni.redirectTo({
+			// 				// 			url:"prescribe?orderId="+res.order.id
+			// 				// 		})
+			// 				// 	},200);
+			// 				// }
+			// 				// else{
+			// 				// 	setTimeout(function(){
+			// 				// 		uni.redirectTo({
+			// 				// 			url: './paymentOrder?orderId='+res.order.id
+			// 				// 		})
+			// 				// 	},200);
+			// 				// }
+			// 				if (res.some(item => item.order.isPrescribe) == 1) {
+			// 					setTimeout(function() {
+			// 						let orderIds = res.filter(item => item.order.isPrescribe == 1).map(it => it
+			// 							.order.id)
+			// 						orderIds = orderIds.join(',')
+			// 						uni.redirectTo({
+			// 							url: "prescribe?orderId=" + orderIds + "&combinationOrderId=" +
+			// 								encodeURIComponent(res[0].order.combinationOrderId)
+			// 						})
+			// 					}, 200);
+			// 				} else {
+			// 					setTimeout(function() {
+			// 						uni.redirectTo({
+			// 							url: './paymentOrder?combinationOrderId=' + encodeURIComponent(
+			// 								res[0].order.combinationOrderId)
+			// 						})
+			// 					}, 200);
+			// 				}
+			// 				return;
+			// 			} else {
+			// 				if (res.code == 501) {
+			// 					uni.showToast({
+			// 						icon: 'none',
+			// 						title: res.msg,
+			// 					});
+			// 					setTimeout(function() {
+			// 						uni.navigateBack({
+			// 							delta: 1
+			// 						})
+			// 					}, 200);
+			// 					return;
+			// 				} else {
+			// 					uni.showToast({
+			// 						icon: 'none',
+			// 						title: res.msg,
+			// 					});
+			// 				}
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+			openAddress() {
+				uni.navigateTo({
+					url: '/pages_user/address'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.inner-box {
+		padding: 20upx 20upx 140upx;
+
+		.address-box {
+			margin-bottom: 20rpx;
+			box-sizing: border-box;
+			min-height: 171upx;
+			background: #FFFFFF;
+			border-radius: 16upx;
+			// background-image: url(../../static/images/address_bg.png);
+			background-repeat: no-repeat;
+			background-size: 100% 30upx;
+			background-position: left bottom;
+			padding: 38upx 30upx 36upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.left {
+				width: 92%;
+
+				.name-box {
+					display: flex;
+					align-items: center;
+
+					.text {
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #111111;
+						line-height: 1;
+
+						&.name {
+							margin-right: 30upx;
+						}
+					}
+				}
+
+				.address {
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #666666;
+					line-height: 42upx;
+					text-align: left;
+					margin-top: 23upx;
+				}
+			}
+
+			.arrow-box {
+				width: 12upx;
+				height: 23upx;
+				display: flex;
+				align-items: cenetr;
+				justify-content: cenetr;
+
+				image {
+					width: 100%;
+					height: 100%;
+				}
+			}
+		}
+
+		.shopbox {
+			background: #FFFFFF;
+			border-radius: 16rpx;
+			margin-bottom: 20rpx;
+
+			.points {
+				padding: 0 !important;
+			}
+
+			.remarks {
+				padding: 0 !important;
+			}
+		}
+
+		.shopbox-name {
+			padding: 30rpx 30rpx 0 30rpx;
+			font-family: PingFang SC, PingFang SC;
+			font-weight: 400;
+			font-size: 30rpx;
+			color: #111;
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+		}
+
+		.goods-list {
+			// margin-top: 20upx;
+			padding: 0 30upx;
+			background-color: #FFFFFF;
+			border-radius: 16upx;
+
+			.item {
+				padding: 30upx 0;
+				border-bottom: 1px solid #EDEEEF;
+				display: flex;
+				align-items: center;
+
+				.img-box {
+					width: 160upx;
+					height: 160upx;
+					margin-right: 30upx;
+
+					image {
+						width: 100%;
+						height: 100%;
+					}
+				}
+
+				.info-box {
+					width: calc(100% - 190upx);
+					height: 160upx;
+					display: flex;
+					flex-direction: column;
+					justify-content: space-between;
+
+					.name-box {
+						font-size: 28upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #111111;
+						line-height: 40upx;
+
+						.tag {
+							display: inline-block;
+							padding: 0 6upx;
+							height: 30upx;
+							background: linear-gradient(90deg, #66b2ef 0%, #0bb3f2 100%);
+							border-radius: 4upx;
+							margin-right: 10upx;
+							font-size: 22upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #FFFFFF;
+							line-height: 30upx;
+							float: left;
+							margin-top: 7upx;
+						}
+					}
+
+					.spec {
+						margin-top: 10upx;
+						font-size: 24upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #999999;
+						line-height: 1;
+					}
+
+					.price-num {
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+
+						.price {
+							display: flex;
+							align-items: flex-end;
+
+							.unit {
+								font-size: 24upx;
+								font-family: PingFang SC;
+								font-weight: 500;
+								color: #111111;
+								line-height: 1.2;
+								margin-right: 4upx;
+							}
+
+							.num {
+								font-size: 32upx;
+								font-family: PingFang SC;
+								font-weight: 500;
+								color: #111111;
+								line-height: 1;
+							}
+						}
+
+						.num {
+							font-size: 24upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #999999;
+							line-height: 1;
+						}
+					}
+				}
+			}
+
+			.sub-total {
+				height: 88upx;
+				display: flex;
+				align-items: center;
+				justify-content: flex-end;
+
+				.label {
+					font-size: 24upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+				}
+
+				.price {
+					display: flex;
+					align-items: flex-end;
+
+					.unit {
+						font-size: 24upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #FF6633;
+						line-height: 1.2;
+						margin-right: 4upx;
+					}
+
+					.num {
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+			}
+		}
+
+		.price-info {
+			background: #FFFFFF;
+			border-radius: 16upx;
+
+			&-title {
+				padding: 30rpx 30rpx 20rpx 30rpx;
+				font-family: PingFang SC, PingFang SC;
+				font-weight: 500;
+				font-size: 30rpx;
+				color: #111;
+			}
+
+			&-unit {
+				font-size: 24rpx;
+			}
+
+			&-num {
+				font-size: 28rpx;
+			}
+		}
+
+		.points {
+			height: 88upx;
+			padding: 0 30upx;
+			background: #FFFFFF;
+			border-radius: 16upx;
+
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.left {
+				display: flex;
+				align-items: center;
+
+				image {
+					width: 28upx;
+					height: 28upx;
+					margin-right: 20upx;
+				}
+
+				.text {
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #666666;
+				}
+			}
+
+			.right {
+				display: flex;
+				align-items: center;
+
+				.text {
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #111111;
+
+				}
+
+				image {
+					margin-left: 15upx;
+					width: 14upx;
+					height: 24upx;
+				}
+			}
+		}
+
+		.remarks {
+			// height: 88upx;
+			padding: 0 30upx;
+			background: #FFFFFF;
+			border-radius: 16upx;
+			margin-top: 20upx;
+			display: flex;
+			align-items: center;
+
+			input {
+				width: 100%;
+				font-size: 28upx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #000000;
+			}
+
+			.input {
+				font-size: 28upx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #999999;
+			}
+		}
+	}
+
+
+	.btn-foot {
+		box-sizing: border-box;
+		width: 100%;
+		height: 121upx;
+		background: #FFFFFF;
+		padding: 16upx 30upx 16upx 60upx;
+		display: flex;
+		align-items: center;
+		justify-content: flex-end;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		z-index: 99;
+
+		.right {
+			display: flex;
+			align-items: center;
+
+			.total {
+				display: flex;
+				align-items: flex-end;
+				margin-right: 36upx;
+
+				.label {
+					font-size: 26upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+					line-height: 1.5;
+				}
+
+				.price {
+					display: flex;
+					align-items: flex-end;
+
+					.unit {
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1.2;
+						margin-right: 10upx;
+					}
+
+					.num {
+						font-size: 50upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+			}
+
+			.btn {
+				width: 200upx;
+				height: 88upx;
+				line-height: 88upx;
+				text-align: center;
+				font-size: 30upx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				background: #0bb3f2;
+				border-radius: 44upx;
+			}
+		}
+	}
+</style>
+<style lang="less" scoped>
+	.coupon {
+		height: 100%;
+	}
+
+	/*优惠券列表公共*/
+	.coupon-list {}
+
+	.coupon-list .item {
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		width: 100%;
+		height: 1.7 * 100rpx;
+		margin-bottom: 0.16 * 100rpx;
+	}
+
+	.coupon-list .item .money {
+		background-size: 100% 100%;
+		width: 2.4 * 100rpx;
+		height: 100%;
+		color: #fff;
+		font-size: 0.36 * 100rpx;
+		font-weight: bold;
+		text-align: center;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		position: relative;
+
+	}
+
+	.coupon-list .item .money .img {
+		position: absolute;
+		width: 2.4 * 100rpx;
+		height: 100%;
+		color: #fff;
+
+	}
+
+	.coupon-list .item .money .num {
+		font-size: 0.6 * 100rpx;
+	}
+
+	.coupon-list .item .money .pic-num {
+		font-size: 20rpx;
+		z-index: 99;
+	}
+
+
+	.coupon-list .item .text {
+		width: 4.5 * 100rpx;
+		padding: 0 0.17 * 100rpx 0 0.24 * 100rpx;
+		background-color: #fff;
+		box-sizing: border-box;
+	}
+
+	.coupon-list .item .text .condition {
+		font-size: 0.3 * 100rpx;
+		color: #282828;
+		height: 0.93 * 100rpx;
+		line-height: 0.93 * 100rpx;
+		border-bottom: 1px solid #f0f0f0;
+	}
+
+	.coupon-list .item .text .data {
+		font-size: 0.2 * 100rpx;
+		color: #999;
+		height: 0.76 * 100rpx;
+	}
+
+	.coupon-list .item .text .data .bnt {
+		width: 1.36 * 100rpx;
+		height: 0.44 * 100rpx;
+		border-radius: 0.22 * 100rpx;
+		font-size: 0.22 * 100rpx;
+		color: #fff;
+		text-align: center;
+		line-height: 0.44 * 100rpx;
+		background-color: red;
+	}
+
+	.coupon-list .item .text .data .bnt.gray {
+		background-color: #ccc;
+	}
+</style>

+ 720 - 0
pages_shop/confirmPackageOrder.vue

@@ -0,0 +1,720 @@
+<template>
+	<view>
+		<view class="inner-box">
+			<!-- 收货人 -->
+			<view class="address-box" v-if="address==null" @click="openAddress()">
+				<view class="left">
+					<view class="name-box">
+						<text class="text name">添加收货地址</text>
+					</view>
+				</view>
+				<view class="arrow-box">
+					<image src="/static/images/arrow_gray.png" mode=""></image>
+				</view>
+			</view>
+			<view class="address-box" v-if="address!=null" @click="openAddress()">
+				<view class="left">
+					<view class="name-box">
+						<text class="text name">{{address.realName}}</text>
+						<text class="text" v-if="address.phone!=null">{{utils.parsePhone(address.phone)}}</text>
+					</view>
+					<view class="address">
+						{{address.province}}{{address.city}}{{address.district}}{{address.detail}}
+					</view>
+				</view>
+				<view class="arrow-box">
+					<image src="/static/images/arrow_gray.png" mode=""></image>
+				</view>
+			</view>
+			<!-- 药品列表 -->
+			<view class="goods-list">
+				<view  class="item">
+					<view class="img-box">
+						<image :src="package.imgUrl" mode="aspectFill"></image>
+					</view>
+					<view class="info-box">
+						<view>
+							<view class="name-box ellipsis2">
+								{{package.title}}
+							</view>
+							<view class="spec ellipsis2">{{package.descs}}</view>
+						</view>
+						
+						<view class="price-num">
+							<view class="price">
+								<text class="unit">¥</text>
+								<text class="num" v-if="package.payMoney!=null">{{package.payMoney.toFixed(2)}}</text>
+							</view>
+						</view>
+					</view>
+				</view>
+				<!-- 小计 -->
+				<view class="sub-total">
+					<text class="label">合计:</text>
+					<view class="price">
+						<text class="unit">¥</text>
+						<text class="num" v-if="package.payMoney!=null">{{package.payMoney.toFixed(2)}}</text>
+					</view>
+				</view>
+			</view>
+			 
+			<view class="points" @click="openCoupon()">
+				<view class="left">
+					<text class="text">优惠券</text>
+				</view>
+				<view class="right">
+					<text class="text">{{couponText}}</text>
+					<image src="/static/images/arrow4.png" mode=""></image>
+				</view>
+			</view>
+			<!-- 备注 -->
+			<view class="remarks">
+				<input type="text" v-model="form.mark" placeholder="备注留言(选填)" placeholder-class="input" />
+			</view>
+		</view>
+		<!-- 底部按钮 -->
+		<view class="btn-foot">
+			<view class="right">
+				<view class="total">
+					<text class="label">应付金额:</text>
+					<view class="price">
+						<text class="unit">¥</text>
+						<text class="num" v-if="totalMoney!=null">{{totalMoney.toFixed(2)}}</text>
+					</view>
+				</view>
+				<view class="btn" @click="submitOrder">提交订单</view>
+			</view>
+		</view>
+		<popupBottom ref="popup" :visible.sync="couponVisible" title=" " bgColor="#f5f5f5"  radius="30"    maxHeight="60%">
+		     <view class="coupon" style="height:650rpx;">
+				 <div class="coupon-list" v-if="couponsList.length > 0">
+				   <div class="item acea-row row-center-wrapper"  v-for="(item, index) in couponsList" :key="index">
+				     <div class="money" >
+				       <image v-if="item.status==0" class="img" src="/static/images/coupon1.png" mode="widthFix"></image>
+				 	  <image v-if="item.status!=0" class="img" src="/static/images/coupon2.png" mode="widthFix"></image>
+				 	  <div style="z-index: 999;">
+				         ¥<span class="num">{{ item.couponPrice }}</span>
+				       </div>
+				       <div class="pic-num"  >满{{ item.useMinPrice }}元可用</div>
+				     </div>
+				     <div class="text">
+				       <div class="condition line1">
+				         {{ item.couponTitle }}
+				       </div>
+				       <div class="data acea-row row-between-wrapper">
+							<div >{{ item.limitTime }}到期</div>
+							<div class="bnt bg-color-red" @click="couponSelect(item)"  >选择</div>
+				       </div>
+				     </div>
+				   </div>
+				 </div>
+				 <view v-if="couponsList.length == 0" class="no-data-box" >
+				 	<image src="/static/images/no_data.png" mode="aspectFit"></image>
+				 	<view class="empty-title">暂无数据</view>
+				 </view>
+			 </view>
+			 
+		</popupBottom>
+	</view>
+</template>
+
+<script>
+	// import {getWeixinTemps} from '@/api/common'
+	// import {confirmPackageOrder,computedPackageOrder,createPackageOrder} from '@/api/storeOrder'
+	// import { getMyEnableCouponList } from '@/api/coupon'
+	 
+	import EvanSwitch from '@/components/evan-switch/evan-switch.vue'
+	import popupBottom from '@/components/px-popup-bottom/px-popup-bottom.vue'
+	export default {
+		components: {
+			EvanSwitch,
+			popupBottom
+		},
+		data() {
+			return {
+				liveId:null,
+				temps:[],
+				totalMoney:0,
+				couponUserId:null,
+				couponText:"请选择",
+				couponsList:[],
+				couponVisible:false,
+				companyUserId:null,
+				packageId:null,
+				address:null,
+				package:{},
+				// checked: false,
+				// type:null,
+				// cartIds:null,
+				form:{
+					// useIntegral:0,
+					orderKey:null,
+					addressId:null,
+					mark:null,
+				}
+				
+			}
+		},
+		onLoad(option) {
+			// this.liveId=otion.liveId
+			
+			
+			// this.packageId=option.packageId;
+			// this.companyUserId=option.companyUserId;
+			// this.confirmPackageOrder();
+			// uni.$on('updateAddress', (e) => {
+			// 	this.address=e;
+			// 	this.form.addressId=e.id;
+			// })
+			// this.getWeixinTemps();
+		},
+		onShow() {
+			
+		},
+		methods: {
+			getWeixinTemps:function(){
+				getWeixinTemps().then(
+					res => {
+						if(res.code==200){
+							this.temps=res.temp
+						}else{
+							 
+						}
+					},
+					rej => {}
+				);
+			},
+			couponSelect(item){
+				this.couponText="-¥"+item.couponPrice.toFixed(2);
+				this.couponUserId=item.id;
+				this.couponVisible=false;
+				this.computedPackageOrder();
+			},
+			openCoupon(){
+				let that = this;
+				var data={packageCateId:this.package.cateId,couponType:1,useMinPrice:this.totalMoney};
+				getMyEnableCouponList(data).then(res => {
+				  this.couponVisible=true;
+				  that.couponsList = res.data
+				})
+			},
+			confirmPackageOrder(){
+				let data = {packageId:this.packageId,couponUserId:this.couponUserId};
+				confirmPackageOrder(data).then(
+					res => {
+						if(res.code==200){
+							 this.form.orderKey=res.orderKey;
+							 this.address=res.address;
+							 this.package=res.package;
+							 if(res.address!=null){
+								 this.form.addressId=res.address.id;
+							 }
+							 this.totalMoney=res.totalMoney;
+							 
+						}else{
+							
+							uni.showToast({
+								icon:'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			computedPackageOrder(){
+				let data = {packageId:this.packageId,couponUserId:this.couponUserId};
+				computedPackageOrder(data).then(
+					res => {
+						if(res.code==200){
+							 this.totalMoney=res.totalMoney;
+							 
+						}else{
+							
+							uni.showToast({
+								icon:'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+		 
+			// 提交订单
+			submitOrder() {
+				var that=this;
+				if(this.form.orderKey==null){
+					uni.showToast({
+						icon:'none',
+						title: '订单KEY不存在',
+					});
+					return;
+				}
+				if(this.form.addressId==null){
+					uni.showToast({
+						icon:'none',
+						title: '收货地址不能为空',
+					});
+					return;
+				}
+				
+				uni.requestSubscribeMessage({
+					tmplIds: this.temps,
+					success(res) {
+						 that.createPackageOrder();
+					},
+					fail(res) {
+						that.createPackageOrder();
+					}
+				})
+				
+				
+			},
+			createPackageOrder(){
+				var that=this;
+				uni.showLoading({
+					title: '正在处理中...'
+				});
+				let data = {couponUserId:this.couponUserId,mark:this.form.mark,orderKey:this.form.orderKey,addressId:this.form.addressId,packageId:this.packageId,companyUserId:this.companyUserId};
+				createPackageOrder(data).then(
+					res => {
+						uni.hideLoading()
+						if(res.code==200){
+							if(res.order.isPrescribe==1){
+								setTimeout(function(){
+									uni.redirectTo({
+										url:"prescribe?orderId="+res.order.id
+									})
+								},200);
+							}
+							else{
+								setTimeout(function(){
+									uni.redirectTo({
+										url: './paymentOrder?orderId='+res.order.id
+									})
+								},200);
+							}
+							return;
+						}
+						else{
+							if(res.code==501){
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+								setTimeout(function(){
+									uni.navigateBack({
+										delta:1
+									})
+								},200);
+								return;
+							}
+							else{
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+							}
+						}
+					},
+					rej => {}
+				);
+			},
+			openAddress(){
+				uni.navigateTo({
+					url: '/pages_user/user/address'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.inner-box{
+		padding: 20upx 20upx 140upx;
+		.address-box{
+			box-sizing: border-box;
+			min-height: 171upx;
+			background: #FFFFFF;
+			border-radius: 16upx;
+			background-image: url(../../static/images/address_bg.png);
+			background-repeat: no-repeat;
+			background-size: 100% 30upx;
+			background-position: left bottom;
+			padding: 38upx 30upx 36upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.left{
+				width: 92%;
+				.name-box{
+					display: flex;
+					align-items: center;
+					.text{
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #111111;
+						line-height: 1;
+						&.name{
+							margin-right: 30upx;
+						}
+					}
+				}
+				.address{
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #666666;
+					line-height: 42upx;
+					text-align:left;
+					margin-top: 23upx;
+				}
+			}
+			.arrow-box{
+				width: 12upx;
+				height: 23upx;
+				display: flex;
+				align-items: cenetr;
+				justify-content: cenetr;
+				image{
+					width: 100%;
+					height: 100%;
+				}
+			}
+		}
+		.goods-list{
+			margin-top: 20upx;
+			padding: 0 30upx;
+			background-color: #FFFFFF;
+			border-radius: 16upx;
+			.item{
+				padding: 30upx 0;
+				border-bottom: 1px solid #EDEEEF;
+				display: flex;
+				align-items: center;
+				.img-box{
+					width: 160upx;
+					height: 160upx;
+					margin-right: 30upx;
+					image{
+						width: 100%;
+						height: 100%;
+					}
+				}
+				.info-box{
+					width: calc(100% - 190upx);
+					height: 160upx;
+					display: flex;
+					flex-direction: column;
+					justify-content: space-between;
+					.name-box{
+						font-size: 28upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #111111;
+						line-height: 40upx;
+						.tag{
+							display: inline-block;
+							padding: 0 6upx;
+							height: 30upx;
+							background: linear-gradient(90deg, #66b2ef 0%, #0bb3f2 100%);
+							border-radius: 4upx;
+							margin-right: 10upx;
+							font-size: 22upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #FFFFFF;
+							line-height: 30upx;
+							float: left;
+							margin-top: 7upx;
+						}
+					}
+					.spec{
+						margin-top: 10upx;
+						font-size: 24upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #999999;
+						line-height: 1;
+					}
+					.price-num{
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+						.price{
+							display: flex;
+							align-items: flex-end;
+							.unit{
+								font-size: 24upx;
+								font-family: PingFang SC;
+								font-weight: 500;
+								color: #111111;
+								line-height: 1.2;
+								margin-right: 4upx;
+							}
+							.num{
+								font-size: 32upx;
+								font-family: PingFang SC;
+								font-weight: 500;
+								color: #111111;
+								line-height: 1;
+							}
+						}
+						.num{
+							font-size: 24upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #999999;
+							line-height: 1;
+						}
+					}
+				}
+			}
+			.sub-total{
+				height: 88upx;
+				display: flex;
+				align-items: center;
+				justify-content: flex-end;
+				.label{
+					font-size: 24upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+				}
+				.price{
+					display: flex;
+					align-items: flex-end;
+					.unit{
+						font-size: 24upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #FF6633;
+						line-height: 1.2;
+						margin-right: 4upx;
+					}
+					.num{
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+			}
+		}
+		.points{
+			height: 88upx;
+			padding: 0 30upx;
+			background: #FFFFFF;
+			border-radius: 16upx;
+			margin-top: 20upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.left{
+				display: flex;
+				align-items: center;
+				image{
+					width: 28upx;
+					height: 28upx;
+					margin-right: 20upx;
+				}
+				.text{
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #666666;
+				}
+			}
+			.right{
+				display: flex;
+				align-items: center;
+				.text{
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #111111;
+					 
+				}
+				image{
+					margin-left: 15upx;
+					width: 14upx;
+					height: 24upx;
+				}
+			}
+		}
+		.remarks{
+			height: 88upx;
+			padding: 0 30upx;
+			background: #FFFFFF;
+			border-radius: 16upx;
+			margin-top: 20upx;
+			display: flex;
+			align-items: center;
+			input{
+				width: 100%;
+				font-size: 28upx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #000000;
+			}
+			.input{
+				font-size: 28upx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #999999;
+			}
+		}
+	}
+	
+	
+	.btn-foot{
+		box-sizing: border-box;
+		width: 100%;
+		height: 121upx;
+		background: #FFFFFF;
+		padding: 16upx 30upx 16upx 60upx;
+		display: flex;
+		align-items: center;
+		justify-content: flex-end;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		z-index: 99;
+		.right{
+			display: flex;
+			align-items: center;
+			.total{
+				display: flex;
+				align-items: flex-end;
+				margin-right: 36upx;
+				.label{
+					font-size: 26upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+					line-height: 1.5;
+				}
+				.price{
+					display: flex;
+					align-items: flex-end;
+					.unit{
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1.2;
+						margin-right: 10upx;
+					}
+					.num{
+						font-size: 50upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+			}
+			.btn{
+				width: 200upx;
+				height: 88upx;
+				line-height: 88upx;
+				text-align: center;
+				font-size: 30upx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				background: #0bb3f2;
+				border-radius: 44upx;
+			}
+		}
+	}
+	 
+</style>
+<style lang="less" scoped>
+	.coupon {
+	  height: 100%;
+	}
+	/*优惠券列表公共*/
+	.coupon-list {
+	}
+	.coupon-list .item {
+	  display: flex;
+	  flex-direction: column;
+	  justify-content: center;
+	  align-items: center;
+	  width: 100%;
+	  height: 1.7 * 100rpx;
+	  margin-bottom: 0.16 * 100rpx;
+	}
+	
+	.coupon-list .item .money {
+	  background-size: 100% 100%;
+	  width: 2.4 * 100rpx;
+	  height: 100%;
+	  color: #fff;
+	  font-size: 0.36 * 100rpx;
+	  font-weight: bold;
+	  text-align: center;
+	  display: flex;
+	  flex-direction: column;
+	  align-items: center;
+	  justify-content: center;
+	  position: relative;
+	  
+	}
+	.coupon-list .item .money .img{
+	  position: absolute;
+	  width: 2.4 * 100rpx;
+	  height: 100%;
+	  color: #fff;
+	  
+	}
+	
+	.coupon-list .item .money .num {
+	  font-size: 0.6 * 100rpx;
+	}
+	.coupon-list .item .money .pic-num {
+	  font-size: 20rpx;
+	  z-index: 99;
+	}
+
+	
+	.coupon-list .item .text {
+	  width: 4.5 * 100rpx;
+	  padding: 0 0.17 * 100rpx 0 0.24 * 100rpx;
+	  background-color: #fff;
+	  box-sizing: border-box;
+	}
+	
+	.coupon-list .item .text .condition {
+	  font-size: 0.3 * 100rpx;
+	  color: #282828;
+	  height: 0.93 * 100rpx;
+	  line-height: 0.93 * 100rpx;
+	  border-bottom: 1px solid #f0f0f0;
+	}
+	
+	.coupon-list .item .text .data {
+	  font-size: 0.2 * 100rpx;
+	  color: #999;
+	  height: 0.76 * 100rpx;
+	}
+	
+	.coupon-list .item .text .data .bnt {
+	  width: 1.36 * 100rpx;
+	  height: 0.44 * 100rpx;
+	  border-radius: 0.22 * 100rpx;
+	  font-size: 0.22 * 100rpx;
+	  color: #fff;
+	  text-align: center;
+	  line-height: 0.44 * 100rpx;
+	  background-color: red;
+	}
+	
+	.coupon-list .item .text .data .bnt.gray {
+	  background-color: #ccc;
+	}
+</style>

+ 1801 - 0
pages_shop/goods.vue

@@ -0,0 +1,1801 @@
+<template>
+	<view class="">
+		<view class="content">
+			<!-- <view class="share-box centerV ">
+			<image class="w48 h48 " src="" mode=""></image>
+			<text class="color-text mt8 weight-500 fs20">微信分享</text>
+		</view> -->
+			<!-- 商品轮播图片 -->
+			<!-- 	<view class="shop-banner" @click="showImg()">
+			商品轮播图
+			<swiper class="swiper" :indicator-dots="false" :circular="true" :autoplay="true" :interval="3000"
+				:duration="1000" indicator-color="rgba(255, 255, 255, 0.6)" indicator-active-color="#ffffff" @change="">
+				<swiper-item class="swiper-item" v-for="(item,index) in  banner" :key="index">
+					<image :src="item" mode="aspectFill"></image>
+					<view class="cf-box" v-if="product.productType==2">
+						<view class="title">处方药</view>
+						<view class="subTitle">请在医师指导下使用</view>
+					</view>
+				</swiper-item>
+			</swiper>
+			
+			底部遮罩
+			<view class="banner-mask"></view>
+			数量
+			<view class="num-box"><text class="weight-500">{{ activeBanner }}</text>/{{ banner.length }}</view>
+		</view> -->
+
+			<view class="shop-banner">
+				<view class="swiper">
+					<view class="swiper-item">
+						<image :src="goosDetail.imgUrl" mode="aspectFill"></image>
+						<view class="cf-box" v-if="product.productType==2">
+							<view class="title">处方药</view>
+							<view class="subTitle">请在医师指导下使用</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<!-- 详细信息 -->
+			<view class="det-info">
+				<view class="price-box">
+					<view class="price">
+						<text class="label">会员价</text>
+						<text class="unit">¥</text>
+						<text class="num">{{goosDetail.price}}</text>
+						<text class="fs24 color-text2">零售价</text>
+						<text class="old">¥{{goosDetail.otPrice}}</text>
+					</view>
+					<text class="fs24 color-text2">月售{{goosDetail.sales}}件</text>
+				</view>
+				<!-- <view class="name-box">
+				<view class="tag"></view>
+				{{product.productName}}
+			</view> -->
+				<!-- <view class="intro" v-if="product.productInfo!=null" v-html="product.productInfo.replace(/\n/g,'<br>')"> -->
+			</view>
+		</view>
+		<view class="guige">
+			<view class="guige-gg">
+				<text class="gg-text">规格</text>
+				<text class="gg-text2">云南白药气雾剂 85g+30g *1 、说明书*1</text>
+			</view>
+			<view class="safe-box">
+				<text class="text">服务</text>
+				<view class="box">
+					<view v-for="(item,index) in serviceList" :key="index">
+						<image src="/static/images/googs_service.png" mode=""></image>
+						<text>{{item}}</text>
+					</view>
+					<view @click="openEditMoney()">
+						<image class='w48 h48' src="/static/images/right_arrow.png"></image>
+					</view>
+				</view>
+			</view>
+
+			<!-- 点击服务,出现弹窗-->
+			<view class="popup-box" v-if="editShow">
+				<view class="info-mask" @tap="cancelEditMoney()"></view>
+				<view class="info-form">
+					<view class="top">
+						<view class="title">服务</view>
+						<view class="close" @click="cancelEditMoney()">
+							<image class='w48 h48' src="" mode=""></image>
+						</view>
+					</view>
+					<view class="line"></view>
+					<view class="form-box">
+						<view class="form-item2">
+							<view class="form-item-box">
+								<image class='w28 h28' src="" mode=""></image>
+								<text>免邮发货</text>
+							</view>
+							<view class="form-content">
+								订单支付成功后48小时内发货,若未在48小时内发货,平台审核后消费者将会收到至少3元无门槛红包(特殊商品及不可抗力因素除外)
+							</view>
+						</view>
+						<view class="form-item2">
+							<view class="form-item-box">
+								<image class='w28 h28' src="" mode=""></image>
+								<text>药师服务</text>
+							</view>
+							<view class="form-content">
+								用药关怀认证药师,24小时专业用药咨询
+							</view>
+						</view>
+						<view class="form-item2">
+							<view class="form-item-box">
+								<image class='w28 h28' src="" mode=""></image>
+								<text>隐私保护</text>
+							</view>
+							<view class="form-content">
+								除患者本人或其授权的代理人外,其他人员未经允许不得随意查阅患者的医疗记录
+							</view>
+						</view>
+					</view>
+					<view class="btns">
+						<view class="sub-btn" @click="cancelEditMoney()">确定</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<!-- 购买人数、库存 -->
+		<view class="shop-box">
+			<view class=""
+				style="flex: 1;overflow: hidden; display: flex; justify-content: space-between; align-items: center;">
+				<!-- 店铺图片logo -->
+				<!-- <view class="logo">
+				<image src="" mode="aspectFill"></image>
+			</view> -->
+				<view class="txtBox">
+					<view class="name">南泉达路店</view>
+					<view class="desc">24小时营业 · 月售{{}} · 支持预订</view>
+				</view>
+			</view>
+			<button class="goShop"
+				@click="navgetTo('/pages_shop/store?liveId='+liveId)">进店</button>
+		</view>
+
+		<!-- 图文详情 -->
+		<view class="det-box">
+			<view class="title">药品详情</view>
+			<view class="det-title">
+				<view class="tt">说明书</view>
+				<view class="det-right">
+					<text>查看详情</text>
+					<image class='w48 h48' src=""></image>
+				</view>
+			</view>
+			<view class="det-table">
+				<view class="row">
+					<text class="cell cell-1">通用名称</text>
+					<text class="cell cell-2">云南白药气雾剂</text>
+				</view>
+				<view class="row">
+					<text class="cell cell-1">成份</text>
+					<text class="cell cell-2">国家保密方,本品含草乌(制)、雪上一枝蒿(制),其余成份略。</text>
+				</view>
+				<view class="row">
+					<text class="cell cell-1">性状</text>
+					<text class="cell cell-2">云南白药气雾剂为非定量阀门气雾剂,在耐压容器中的药液为淡黄...</text>
+				</view>
+			</view>
+			<view class="inner">
+				<view v-html="product.description" style="font-size:0"></view>
+			</view>
+		</view>
+		<!-- 底部按钮 -->
+		<view class="btn-foot">
+			<view class="menu-box">
+				<view class="item" @click="navgetTo('./store')">
+					<image src="/static/images/googs1.png" mode=""></image>
+					<text class="label">店铺</text>
+				</view>
+				<!-- 	<view class="item"  @click="navgetTo('pages/home/living')" style="position: relative;">
+					<image src="/static/images/googs2.png" mode=""></image>
+					<text class="label">直播间</text>
+					<button class="contact-btn" open-type="contact"></button>
+				</view> -->
+				<!-- <view class="item" style="position: relative;">
+					<image src="/static/images/googs2.png" mode=""></image>
+					<text class="label">咨询</text>
+					<button class="contact-btn" open-type="contact"></button>
+				</view> -->
+				<view class="item" @click="navgetTo('./cart')">
+					<uni-badge size="small" :text="cartCount" absolute="rightTop" type="error">
+						<image src="/static/images/googs3.png" mode=""></image>
+					</uni-badge>
+					<text class="label">购物车</text>
+				</view>
+			</view>
+			<view class="btn-box">
+				<view class="btn cart" @click="addCart('cart')">加入购物车</view>
+				<view class="btn buy" @click="addCart('buy')">{{buyText}}</view>
+			</view>
+		</view>
+
+		<!-- 选择药品规格弹窗 -->
+		<popupBottom ref="popup" :visible.sync="specVisible" title=" " radius="32" maxHeight="800">
+			<view class="product-spec">
+				<view class="pro-info">
+					<view class="img-box">
+						<image :src="goosDetail?.imgUrl ||$img.img " mode="aspectFill"></image>
+					</view>
+					<view class="info-text">
+						<view class="info-title">{{goosDetail.productName}}</view>
+						<view class="price">
+							<view class="label">会员价</view>
+							<text class="unit">¥</text>
+							<text class="num">{{ goosDetail.price ? goosDetail.price.toFixed(2) : '0.00' }}</text>
+						</view>
+						<view class="desc-box">
+							<text class="text">月售{{goosDetail.sales}}件</text>
+						</view>
+					</view>
+				</view>
+				<!-- 选择健康管理师 -->
+				<!-- <view class="tech-pBox" style="margin-top: 20rpx;">
+					<view class="label">选择健康管理师</view>
+					<view v-for="(item,index) in storePriceList.slice(0,2)" :key="index"
+						:class="productValueSelect.storeId ==  item.storeId ? 'item hover':'item'"
+						@click="storeChange(item,index)">
+
+						<image mode="aspectFill"
+							:src="productValueSelect.image==null||productValueSelect.image==''?product.image:productValueSelect.image">
+						</image>
+						<view class="tech-right">
+							<view class="tech-right-top">
+								<text class="title-1">秦宇</text>
+								<text class="title-2">健康管理师/执业药师</text>
+							</view>
+							<view class="tech-right-bottom">{{item.storeName}}</view>
+						</view>
+					</view>
+				</view> -->
+
+				<u-popup :show="showStorePicker" :round="16" mode="bottom">
+					<view class="storepopup">
+						<view class="storepopup-title">
+							选择店铺
+							<image class="close-icon" src="" mode="widthFix"></image>
+						</view>
+						<scroll-view enable-flex class="shop-pBox storepopup-box" scroll-y="true">
+							<view v-for="(item,index) in storePriceList" :key="index"
+								:class="productValueSelect.storeId ==  item.storeId ? 'item hover':'item'"
+								@click="pickerStore(item,index)">
+								<view class="top x-bc">
+									<view class="price"><text class="strong">¥</text>{{ item.price.toFixed(2) }}</view>
+									<view class="num">销售{{utils.formatSalesNum(item.sales) }}</view>
+								</view>
+								<view class="bot x-bc shop-pBox-name">
+									<view class="name">{{item.storeName}}</view>
+									<u-icon name="arrow-right" color="#000" size="14"></u-icon>
+								</view>
+							</view>
+						</scroll-view>
+					</view>
+				</u-popup>
+				<!-- <view class="spec-box">
+				<view v-for="(item,index) in attrs">
+					<view class="title">{{item.attrName}}</view>
+					<view class="spec-list">
+						<view v-for="(subItem,subindex) in item.values" :key="subindex"
+							:class="subindex==item.index?'item active':'item'">
+							{{ subItem }}
+						</view>
+					</view>
+				</view>
+			</view> -->
+				<view class="price-num">
+					<view class="label">数量</view>
+					<u-number-box bgColor="#ececec" v-model="goodsNum" @change="goodsNumChange"></u-number-box>
+				</view>
+				<view class="sub-btn" @click="submit">确定</view>
+			</view>
+		</popupBottom>
+		<!-- <view class="loadding" v-if="loadding==true">
+			<image src=""></image>
+			<text class="text">加载中...</text>
+		</view> -->
+		<!-- <u-modal :show="showModal" title="温馨提示" content="处方药须凭处方在药师指导下购买和使用" @confirm="hideModal()"></u-modal> -->
+		<!-- 	<view>
+			<view @click="operateOrder(0)" style="background-color: aqua; padding: 100rpx;">取消</view>
+			<view @click="operateOrder(1)" style="background-color: #ff0004;padding: 150rpx;">确认</view>
+		</view> -->
+	</view>
+</template>
+
+<script>
+	import {
+		updateConfirm, // 点击取消/支付订单
+		updateLiveOrder, // 取消/支付订单
+		liveOrderKey // 生成订单key
+	} from "@/api/order.js"
+	import popupBottom from '@/components/px-popup-bottom/px-popup-bottom.vue'
+	import {
+		liveGoodsDetail
+	} from "@/api/live.js"
+	export default {
+		components: {
+			popupBottom
+		},
+		data() {
+			return {
+				totalNum: 1,
+				orderKey: null,
+				type: null,
+				liveOrderList: [], //下订单的 不在这个页面
+				liveId: null,
+				// storeId:uni.setStorageSync("storeId"),
+				serviceList: ['免邮发货', '药师服务', '隐私保护'],
+				editShow: false,
+				productId: null,
+				goosDetail: {}, //商品详情
+				loadding: true,
+				buyText: "立即购买",
+				showStorePicker: false,
+				goodsNum: 0, //商品选择数量
+				productValueSelect: {
+					price: 0,
+					serviceFee: 0
+				},
+				attrs: [],
+				values: [],
+				stores: [],
+				storeNames: [],
+				storeIdx: 0,
+				storeName: "",
+				product: {
+					price: 0,
+					otPrice: 0,
+				},
+				showModal: false,
+				// 当前轮播的图片
+				activeBanner: 1,
+				// 购物车数量
+				cartCount: 0,
+				// 规格弹窗
+				specVisible: false,
+				// 规格数量
+				specNum: 1,
+				config: null,
+				showServiceFee: false,
+				selectVal: "",
+				// 链接带的storeId
+				urlStoreId: undefined,
+				// 所选规格门店店铺价格
+				storePriceList: [],
+				// 所选店铺
+				storeSelectInfo: {},
+				// 保存选的规格
+				choseSpecSubIndex: 0,
+				choseSpecIndex: 0,
+			};
+		},
+		onLoad(options) {
+			if (options.productId) {
+				this.productId = options.productId;
+				// this.productId = decodeURIComponent(options.productId);
+				console.log("接收到的productId:", this.productId);
+			}
+			this.liveId = options.liveId
+			// console.log("options", JSON.stringify(options))
+			// if (options.param) {
+			// 	console.log("param", JSON.stringify(param))
+			// 	this.productId = options.param.productId;
+			// 	this.liveId = options.param.liveId;
+			// 	this.storeId = options.param.storeId;
+			// 	// this.productId = decodeURIComponent(options.productId);
+			// 	console.log("接收到的productId:", this.productId);
+			// }
+
+		},
+		mounted() {
+
+			this.getliveGoods()
+			var userInfo = uni.getStorageSync("userInfo")
+			console.log("之前的数据在这里", userInfo)
+		},
+		onShow() {
+
+		},
+
+		methods: {
+
+			// 获得key
+			getKey() {
+				liveOrderKey().then(res => {
+						if (res.code == 200) {
+							console.log("下订单的key>>>>", res)
+							this.orderKey = res.orderKey
+							console.log("key>>>>", this.orderKey)
+							uni.navigateTo({
+								url: '/pages_shop/confirmCreateOrder?orderKey=' + this.orderKey + '&liveId=' +
+									this.liveId + '&productId=' + this.productId + '&totalNum=' + this
+									.totalNum + '&price=' + this.goosDetail.price
+							})
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+
+
+
+			// 点击取消/支付订单
+			operateOrder(type) {
+				// console.log("this.liveOrderList" ,JSON.parse( this.liveOrderList.orderId));
+				let orderId = this.liveOrderList
+				console.log("orderId>>", orderId)
+				// updateConfirm(orderId, type).then(res => {
+				// 		if (res.code == 200) {
+				// 			console.log("点击取消/支付订单>>>>", res)
+				// 		} else {
+				// 			uni.showToast({
+				// 				title: res.msg,
+				// 				icon: 'none'
+				// 			});
+				// 		}
+				// 	},
+				// 	rej => {}
+				// );
+			},
+
+			// 选择商品数量
+			goodsNumChange(e) {
+				console.log('当前选择商品数量为: ' + e.value)
+				this.totalNum = e.value
+			},
+			// 提交
+			submit() {
+				this.specVisible = false
+				this.getKey()
+				// this.doAddCart(this.type);
+			},
+			// 加入购物车
+			addCart(type) {
+				this.type = type;
+				this.specVisible = true
+
+
+			},
+			// doAddCart(type) {
+			// 	if (this.specNum == 0) {
+			// 		uni.showToast({
+			// 			icon: 'none',
+			// 			title: "库存不足",
+			// 		});
+			// 		return;
+			// 	}
+			// 	var isBuy = type == "buy" ? 1 : 0;
+			// 	let data = {
+			// 		isBuy: isBuy,
+			// 		cartNum: this.specNum,
+			// 		productId: this.productValueSelect.productId,
+			// 		attrValueId: this.productValueSelect.id
+			// 	};
+			// 	addCart(data).then(
+			// 		res => {
+			// 			if (res.code == 200) {
+			// 				if (type == "buy") {
+			// 					const selectCarts = [{
+			// 						storeId: this.storeId,
+			// 						data: {
+			// 							type: this.type,
+			// 							cartIds: res.id,
+			// 						}
+			// 					}]
+			// 					uni.navigateTo({
+			// 						url: '/pages/shopping/confirmOrder?type=' + this.type + '&orderType=' +
+			// 							this.orderType + '&confirmParam=' + encodeURIComponent(JSON.stringify(
+			// 								selectCarts))
+			// 					})
+			// 				} else {
+			// 					this.getCartCount()
+			// 					uni.showToast({
+			// 						icon: 'success',
+			// 						title: "添加成功",
+			// 					});
+			// 				}
+			// 			} else {
+			// 				uni.showToast({
+			// 					icon: 'none',
+			// 					title: res.msg,
+			// 				});
+			// 				this.getProductDetails()
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+
+			// 跳转页面
+			navgetTo(url) {
+				console.log("跳转")
+				uni.navigateTo({
+					url: url
+				})
+			},
+			openEditMoney() {
+				this.editShow = true;
+			},
+			//商品详情
+			getliveGoods() {
+				liveGoodsDetail(this.productId).then(res => {
+						if (res.code == 200) {
+							console.log("小黄车 商品详情>>>>", res)
+							this.goosDetail = res.data
+
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content {
+		font-family: PingFang SC;
+	}
+
+	.share-box {
+		position: fixed;
+		right: 24rpx;
+		top: 70%;
+		z-index: 99;
+		width: 112rpx;
+		height: 112rpx;
+		border-radius: 16rpx 16rpx 16rpx 16rpx;
+		border: 1rpx solid #EFF3F7;
+		background-color: #FFFFFF;
+	}
+
+	.shop-banner {
+		height: 756rpx;
+		background-color: #FFFFFF;
+		position: relative;
+
+		.swiper-item {
+			box-sizing: border-box;
+			position: relative;
+		}
+
+		.swiper,
+		.swiper-item,
+		.swiper-item image {
+			width: 100%;
+			height: 100%;
+		}
+
+		.banner-mask {
+			width: 100%;
+			height: 44rpx;
+			position: absolute;
+			left: 0;
+			bottom: 0;
+			z-index: 9;
+			// background-image: url(../../static/images/black_mask.png);
+			background-size: 20rpx 44rpx;
+			background-repeat: repeat-x;
+		}
+
+		.num-box {
+			width: 80rpx;
+			height: 40rpx;
+			line-height: 40rpx;
+			text-align: center;
+			font-size: 24rpx;
+			color: #FFFFFF;
+			background: rgba(0, 0, 0, .7);
+			border-radius: 20rpx;
+			position: absolute;
+			right: 40rpx;
+			bottom: 34rpx;
+			z-index: 10;
+		}
+
+		.cf-box {
+			position: absolute;
+			z-index: 10;
+			left: 0;
+			right: 0;
+			top: calc(50% - 200rpx);
+			bottom: calc(50% - 200rpx);
+			background-color: rgba(0, 0, 0, 0.3);
+			backdrop-filter: blur(2rpx);
+			/* 背景模糊度 */
+			display: flex;
+			flex-direction: column;
+			flex: 1;
+			justify-content: center;
+			align-items: center;
+			color: #EDEEEF;
+
+			.title {
+				font-size: 40rpx;
+				font-weight: bold;
+			}
+
+			.subTitle {
+				font-size: 28rpx;
+				font-weight: bold;
+				margin-top: 10rpx;
+			}
+		}
+
+
+	}
+
+	.guige {
+		padding: 24rpx;
+		border-radius: 16rpx;
+		background: #fff;
+		width: auto;
+		font-size: 24rpx;
+		color: #222426;
+		margin: 24rpx;
+
+		.guige-gg {
+			.gg-text {
+				color: #898E91;
+				margin-right: 40rpx;
+			}
+		}
+
+		.safe-box {
+			display: flex;
+			align-items: center;
+			padding-top: 24rpx;
+			font-size: 24rpx;
+			color: #222426;
+
+			.text {
+				color: #999999;
+				margin-right: 40rpx;
+			}
+
+			.box {
+				display: flex;
+				align-items: center;
+
+				image {
+					width: 28rpx;
+					height: 28rpx;
+					margin-right: 10rpx;
+				}
+
+				view {
+					display: flex;
+					align-items: center;
+					margin-right: 40rpx;
+
+					&:last-child {
+						margin-right: 0;
+
+						image {
+							margin-right: 0;
+						}
+					}
+				}
+			}
+
+		}
+
+		.popup-box {
+			position: fixed;
+			top: 0;
+			right: 0;
+			left: 0;
+			bottom: 0;
+			z-index: 999;
+			display: flex;
+			justify-content: center;
+			align-items: flex-end;
+
+			.info-mask {
+				position: fixed;
+				top: 0;
+				right: 0;
+				bottom: 0;
+				left: 0;
+				background-color: rgba($color: #000000, $alpha: 0.5);
+				z-index: 999;
+			}
+
+			.info-form {
+				z-index: 1000;
+				width: 100%;
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
+				align-items: center;
+				padding: 0 30rpx 60rpx;
+				background: #FFFFFF;
+				border-radius: 40rpx;
+
+				.top {
+					display: flex;
+				}
+
+				.line {
+					border-top: 1px solid #F1F1F1;
+					width: 100%;
+				}
+
+				.title {
+					padding: 30rpx;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+					font-size: 36rpx;
+					font-weight: bold;
+					line-height: 44rpx;
+					color: #222222;
+				}
+
+				.close {
+					padding-top: 30rpx;
+					position: absolute;
+					right: 30rpx;
+				}
+
+				.form-box {
+					width: 100%;
+					padding-top: 30rpx;
+
+					.form-item2 {
+						padding-bottom: 30rpx;
+
+						// display: flex;
+						// align-items: flex-start;
+						// border-bottom: 1px solid #F1F1F1;
+						.form-item-box {
+							display: flex;
+							align-items: center;
+
+							text {
+								font-size: 28rpx;
+								color: #222426;
+								margin-left: 10rpx;
+								font-weight: bold;
+							}
+						}
+
+						.form-content {
+							font-size: 24rpx;
+							text-align: left;
+							color: #626468;
+							margin-top: 20rpx;
+							line-height: 40rpx;
+						}
+					}
+				}
+
+				.btns {
+					width: 100%;
+					height: 120rpx;
+					padding: 20rpx 30rpx;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+
+					.sub-btn {
+						width: 100%;
+						height: 88rpx;
+						line-height: 88rpx;
+						text-align: center;
+						font-size: 36rpx;
+						font-weight: bold;
+						color: #FFFFFF;
+						background: #008FD3;
+						border-radius: 44rpx;
+					}
+				}
+
+			}
+		}
+	}
+
+	.det-info {
+		// background: #FFFFFF;
+		// padding: 36rpx 30rpx 25rpx;
+		background: #FFFFFF;
+		padding: 24rpx;
+		margin: 24rpx;
+		border-radius: 16rpx;
+
+		.price-box {
+			display: flex;
+			align-items: flex-end;
+			justify-content: space-between;
+
+			.price {
+				display: flex;
+				align-items: flex-end;
+
+				.label {
+					font-weight: 500;
+					font-size: 24rpx;
+					color: #FF5030;
+					line-height: 1.3;
+					margin-right: 10rpx;
+				}
+
+				.unit {
+					font-size: 26rpx;
+					font-weight: bold;
+					color: #FF6633;
+					line-height: 1.3;
+				}
+
+				.num {
+					font-size: 48rpx;
+					font-weight: bold;
+					color: #FF5030;
+					margin-right: 20rpx;
+					line-height: 1;
+				}
+
+				.old {
+					font-size: 24rpx;
+					font-family: PingFang SC;
+					font-weight: 400;
+					// text-decoration: line-through;
+					color: #898E91;
+					margin-left: 10rpx;
+					// line-height: 1.3;
+				}
+			}
+
+			// .share-box{
+			// 	width: 120rpx;
+			// 	height: 46rpx;
+			// 	border: 1px solid #0bb3f2;
+			// 	border-radius: 23rpx;
+			// 	display: flex;
+			// 	align-items: center;
+			// 	justify-content: center;
+			// 	position: relative;
+			// 	.text{
+			// 		font-size: 26rpx;
+			// 		font-family: PingFang SC;
+			// 		font-weight: 500;
+			// 		color: #0bb3f2;
+			// 	}
+			// 	image{
+			// 		margin-left: 2rpx;
+			// 		width: 25rpx;
+			// 		height: 24rpx;
+			// 	}
+			// 	.share{
+			// 		display: inline-block;
+			// 		position: absolute;
+			// 		top: 0;
+			// 		left: 0;
+			// 		width: 100%;
+			// 		height: 100%;
+			// 		opacity: 0;
+			// 	}
+			// }
+
+			.spec {
+				font-size: 24rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #999999;
+				line-height: 36rpx;
+			}
+		}
+
+		// .name-box {
+		// 	font-size: 32rpx;
+		// 	font-family: PingFang SC;
+		// 	font-weight: bold;
+		// 	color: #111111;
+		// 	line-height: 44rpx;
+		// 	margin-top: 32rpx;
+
+		// 	.tag {
+		// 		display: inline-block;
+		// 		padding: 2rpx 8rpx;
+		// 		height: 32rpx;
+		// 		background: #F5A623;
+		// 		border-radius: 4rpx;
+		// 		margin-right: 10rpx;
+		// 		font-weight: 400;
+		// 		font-size: 20rpx;
+		// 		color: #FFFFFF;
+		// 		line-height: 30rpx;
+		// 		float: left;
+		// 		margin-top: 7rpx;
+		// 	}
+		// }
+
+		.intro {
+			font-size: 26rpx;
+			font-weight: 500;
+			color: #999999;
+			line-height: 36rpx;
+			padding: 18rpx 0 23rpx;
+		}
+
+		.intro-box {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 20rpx;
+			border-radius: 16rpx;
+			background: #F5F7FA;
+			width: auto;
+
+			.title-1 {
+				font-size: 24rpx;
+				color: #222426;
+				font-weight: bold;
+				width: 40%;
+				text-align: center;
+			}
+
+			.title-2 {
+				font-size: 24rpx;
+				color: #222426;
+				font-weight: bold;
+				display: block;
+			}
+
+			.intro-text {
+				// padding: 0 20rpx;
+			}
+
+			.intro-text2 {
+				width: 50%;
+			}
+
+			.intro-content {
+				color: #898E91;
+				font-size: 24rpx;
+			}
+
+			.line {
+				width: 1px;
+				height: 40rpx;
+				background: #EDEEEF;
+				margin: 0 20rpx;
+			}
+		}
+
+		.safe-box {
+			display: flex;
+			align-items: center;
+			padding-top: 24rpx;
+
+			image {
+				width: 20rpx;
+				height: 24rpx;
+				margin-right: 20rpx;
+			}
+
+			.text {
+				font-size: 22rpx;
+				font-weight: 500;
+				color: #999999;
+				line-height: 1;
+			}
+
+			.line {
+				width: 1px;
+				height: 23rpx;
+				background: #EDEEEF;
+				margin: 0 20rpx;
+			}
+		}
+	}
+
+	.inventor {
+		height: 88rpx;
+		padding: 0 39rpx 0 30rpx;
+		margin-top: 10rpx;
+		background: #FFFFFF;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.left {
+			display: flex;
+			align-items: center;
+
+			.head-box {
+				margin-right: 27rpx;
+				display: flex;
+				align-items: center;
+
+				.head {
+					width: 48rpx;
+					height: 48rpx;
+					border-radius: 50%;
+					overflow: hidden;
+					box-shadow: 0 0 0 1px #fff;
+					margin-right: -10rpx;
+
+					image {
+						width: 100%;
+						height: 100%;
+					}
+				}
+			}
+
+			.num-box {
+				font-size: 24rpx;
+				font-weight: 500;
+				color: #999999;
+
+				.text {
+					font-size: 24rpx;
+					font-weight: 500;
+					color: #999999;
+				}
+			}
+		}
+
+		.right {
+			font-size: 24rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #999999;
+
+			.text {
+				font-size: 24rpx;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+	}
+
+	.effect {
+		box-sizing: border-box;
+		padding: 20rpx 30rpx;
+		background: #FFFFFF;
+		font-size: 28rpx;
+		font-weight: 500;
+		color: #666666;
+		line-height: 1.8;
+		margin-top: 10rpx;
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+
+		.label {
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #111111;
+			line-height: 1.8;
+		}
+	}
+
+
+	.shop-box {
+		// box-sizing: border-box;
+		// padding: 20rpx 30rpx;
+		// background: #FFFFFF;
+		// font-size: 28rpx;
+		// font-family: PingFang SC;
+		// font-weight: 500;
+		// color: #666666;
+		// line-height: 1.8;
+		// margin-top: 10rpx;
+		// background: url(../../static/images/chu_query.png) no-repeat  center center / cover;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		background: #FFFFFF;
+		font-size: 28rpx;
+		font-weight: 500;
+		color: #666666;
+		line-height: 1.8;
+		padding: 24rpx;
+		margin: 24rpx;
+		border-radius: 16rpx;
+
+		.logo {
+			flex-shrink: 0;
+			width: 100rpx;
+			height: 100rpx;
+			border-radius: 16rpx;
+			overflow: hidden;
+
+			image {
+				width: 100%;
+				height: 100%;
+			}
+		}
+
+		.txtBox {
+			flex: 1;
+			overflow: hidden;
+			margin: 0 30rpx;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+		}
+
+		.name {
+			font-size: 32rpx;
+			font-weight: 600;
+			color: #333;
+			text-align: left;
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+		}
+
+		.desc {
+			font-size: 24rpx;
+			font-weight: normal;
+			color: #222426;
+			text-align: left;
+		}
+
+
+		.goShop {
+			flex-shrink: 0;
+			width: 96rpx;
+			height: 56rpx;
+			background: #fff;
+			border-radius: 30rpx;
+			color: #008FD3;
+			font-size: 24rpx;
+			margin: 0;
+			border: 1px solid #008FD3;
+			padding: 0;
+			line-height: 56rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
+	}
+
+	.tech-pBox {
+		box-sizing: border-box;
+		padding: 0rpx 0rpx;
+		background: #FFFFFF;
+		font-size: 28rpx;
+		font-family: PingFang SC;
+		font-weight: 500;
+		color: #666666;
+
+		.label {
+			font-weight: bold;
+			font-size: 26rpx;
+			color: #222426;
+			text-align: left;
+			padding: 24rpx 0;
+		}
+
+		.item {
+			border: 1px solid #fff;
+			border-radius: 12rpx;
+			padding: 30rpx;
+			border: 1px solid #EFF3F7;
+			display: flex;
+			align-items: center;
+			margin-bottom: 20rpx;
+
+			.price {
+				font-size: 42rpx;
+				font-weight: bold;
+				color: #FF6633;
+				display: flex;
+				flex: 1;
+
+				b {
+					font-size: 30rpx;
+					line-height: 46rpx;
+					margin-top: 14rpx;
+				}
+			}
+
+			.num {
+				font-size: 28rpx;
+				font-weight: normal;
+				color: #999;
+				width: 200rpx;
+				text-align: right;
+			}
+
+			.name {
+				max-width: 60%;
+				margin-right: 10rpx;
+				font-size: 28rpx;
+				font-weight: normal;
+				color: #333;
+				text-align: left;
+				overflow: hidden;
+				white-space: nowrap;
+				text-overflow: ellipsis;
+			}
+
+			image {
+				width: 100rpx;
+				height: 100rpx;
+				border-radius: 50%;
+				margin-right: 30rpx;
+			}
+
+			.tech-right {
+				flex: 1;
+
+				&-bottom {
+					color: #898E91;
+					font-size: 24rpx;
+				}
+
+				&-top {
+					display: flex;
+					align-items: flex-end;
+					margin-bottom: 10rpx;
+
+					.title-1 {
+						font-size: 32rpx;
+						color: #222426;
+						margin-right: 14rpx;
+					}
+
+					.title-2 {
+						font-weight: 400;
+						font-size: 24rpx;
+						color: #222426;
+					}
+				}
+			}
+
+		}
+
+		.hover {
+			border: 1rpx solid #008FD3;
+			background: #F0FAFF;
+		}
+
+		.shop-morebtn {
+			margin-top: 14rpx;
+			box-sizing: border-box;
+			padding: 12rpx 30rpx;
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #111111;
+			background: #F7F7F7;
+			border-radius: 32rpx;
+			text-align: center;
+
+			text {
+				color: #999;
+			}
+		}
+	}
+
+	.shop-pBox {
+		box-sizing: border-box;
+		padding: 0rpx 0rpx;
+		background: #FFFFFF;
+		font-size: 28rpx;
+		font-family: PingFang SC;
+		font-weight: 500;
+		color: #666666;
+
+		.item {
+			border: 1px solid #fff;
+			border-radius: 12rpx;
+			padding: 18rpx 20rpx 24rpx;
+
+			.price {
+				font-size: 42rpx;
+				font-weight: bold;
+				color: #FF6633;
+				display: flex;
+				flex: 1;
+
+				.strong {
+					font-size: 30rpx;
+					line-height: 46rpx;
+					margin-top: 14rpx;
+				}
+			}
+
+			.num {
+				font-size: 28rpx;
+				font-weight: normal;
+				color: #999;
+				width: 200rpx;
+				text-align: right;
+			}
+
+			.name {
+				max-width: 60%;
+				margin-right: 10rpx;
+				font-size: 28rpx;
+				font-weight: normal;
+				color: #333;
+				text-align: left;
+				overflow: hidden;
+				white-space: nowrap;
+				text-overflow: ellipsis;
+			}
+
+		}
+
+		.hover {
+			border: 1rpx solid #FF6633;
+		}
+
+		.shop-morebtn {
+			margin-top: 14rpx;
+			box-sizing: border-box;
+			padding: 12rpx 30rpx;
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #111111;
+			background: #F7F7F7;
+			border-radius: 32rpx;
+			text-align: center;
+
+			text {
+				color: #999;
+			}
+		}
+	}
+
+	.shop-pBox-name {
+		display: flex;
+		align-items: center;
+		justify-content: flex-start;
+	}
+
+	.storepopup {
+		padding: 40rpx 20rpx 20rpx 20rpx;
+
+		.storepopup-title {
+			text-align: center;
+			margin-bottom: 30rpx;
+			position: relative;
+
+			.close-icon {
+				width: 40rpx;
+				height: 40rpx;
+				position: absolute;
+				right: 0;
+				top: 50%;
+				transform: translate(0, -50%);
+			}
+		}
+
+		.storepopup-box {
+			height: 60vh;
+		}
+	}
+
+	.det-box {
+		// margin-top: 10rpx;
+		// padding: 40rpx 30rpx 130rpx 30rpx;
+		// background-color: #FFFFFF;
+		margin-top: 10rpx;
+		background-color: #FFFFFF;
+		padding: 24rpx;
+		margin: 24rpx 24rpx 175rpx 24rpx;
+		border-radius: 16rpx;
+
+		.title {
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333333;
+			line-height: 60rpx;
+			margin-bottom: 30rpx;
+			padding-bottom: 24rpx;
+			border-bottom: 1px solid #ECECEC;
+		}
+
+		.det-title {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.tt {
+				font-size: 28rpx;
+				font-weight: bold;
+				color: #222426;
+			}
+		}
+
+		.det-right {
+			display: flex;
+			font-size: 24rpx;
+			color: #898E91;
+			align-items: center;
+		}
+
+		.det-table {
+			width: 100%;
+			margin: 24rpx 0;
+			background: #FFFFFF;
+			border-radius: 16rpx 16rpx 16rpx 16rpx;
+			border: 1rpx solid #ECECEC;
+			overflow: hidden;
+			font-size: 24rpx;
+
+			.row {
+				display: table-row;
+
+			}
+
+			.row:last-child .cell-1,
+			.row:last-child .cell-2 {
+				border-bottom: 0;
+			}
+
+			.cell {
+				display: table-cell;
+				padding: 24rpx;
+
+				&.cell-1 {
+					width: 30%;
+					text-align: center;
+					color: #626468;
+					background: #F5F7FA;
+					border-right: 1rpx solid #ECECEC;
+					border-bottom: 1rpx solid #ECECEC;
+				}
+
+				&.cell-2 {
+					color: #222426;
+					text-align: center;
+					border-bottom: 1rpx solid #ECECEC;
+				}
+			}
+		}
+	}
+
+	.btn-foot {
+		box-sizing: border-box;
+		width: 100%;
+		height: 151rpx;
+		background: #FFFFFF;
+		padding: 0 24rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		position: fixed;
+		left: 0;
+		bottom: 0;
+		z-index: 99;
+
+		.menu-box {
+			display: flex;
+			align-items: center;
+
+			.item {
+				display: flex;
+				align-items: center;
+				flex-direction: column;
+				margin-right: 48rpx;
+
+				&:last-child {
+					margin-right: 0;
+				}
+
+				image {
+					width: 40rpx;
+					height: 40rpx;
+					margin-bottom: 10rpx;
+				}
+
+				.label {
+					font-size: 20rpx;
+					font-weight: 500;
+					color: #626468;
+					text-align: center;
+				}
+			}
+		}
+
+		.btn-box {
+			display: flex;
+			align-items: center;
+
+			.btn {
+				width: 200rpx;
+				height: 88rpx;
+				line-height: 88rpx;
+				text-align: center;
+				border-radius: 44rpx;
+				margin-left: 20rpx;
+				font-size: 28rpx;
+				font-weight: bold;
+				color: #FFFFFF;
+
+				&:first-child {
+					margin-left: 0;
+				}
+
+				&.cart {
+					background: #FF5030;
+				}
+
+				&.buy {
+					background: #008FD3;
+				}
+			}
+		}
+	}
+
+	.product-spec {
+		padding-bottom: 30rpx;
+
+		.pro-info {
+			display: flex;
+			align-items: center;
+
+			.img-box {
+				width: 200rpx;
+				height: 200rpx;
+				background: #FFFFFF;
+				border-radius: 16rpx;
+				overflow: hidden;
+				margin-right: 30rpx;
+
+				image {
+					width: 100%;
+					height: 100%;
+				}
+			}
+
+			.info-text {
+				height: 200rpx;
+				display: flex;
+				flex-direction: column;
+				justify-content: space-between;
+
+				.info-title {
+					font-family: PingFang SC;
+					font-weight: 600;
+					font-size: 28rpx;
+					color: #222426;
+					text-align: left;
+				}
+
+				.price {
+					display: flex;
+					align-items: flex-end;
+
+					.label {
+						font-weight: 500;
+						font-size: 24rpx;
+						color: #FF5030;
+						line-height: 1.3;
+						margin-right: 10rpx;
+					}
+
+					.unit {
+						font-size: 32rpx;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1.2;
+						margin-right: 10rpx;
+					}
+
+					.num {
+						font-size: 50rpx;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+
+				.desc-box {
+					display: flex;
+					flex-direction: column;
+					padding-bottom: 9rpx;
+
+					.text {
+						font-size: 26rpx;
+						font-weight: 500;
+						color: #999999;
+						margin-top: 27rpx;
+						line-height: 1;
+
+						&:first-child {
+							margin-top: 0;
+						}
+					}
+				}
+			}
+		}
+
+		.spec-box {
+			padding-top: 50rpx;
+
+			.title {
+				font-size: 26rpx;
+				font-weight: bold;
+				color: #111111;
+				line-height: 1;
+			}
+
+			.spec-list {
+				display: flex;
+				flex-wrap: wrap;
+				margin-top: 30rpx;
+
+				.item {
+					box-sizing: border-box;
+					height: 64rpx;
+					padding: 0 30rpx;
+					line-height: 64rpx;
+					font-size: 24rpx;
+					font-weight: 500;
+					color: #111111;
+					background: #F7F7F7;
+					border: 1px solid #F7F7F7;
+					border-radius: 32rpx;
+					margin-right: 20rpx;
+					margin-bottom: 30rpx;
+
+					&.active {
+						background: #F1FFFE;
+						border: 1px solid #008FD3;
+						color: #008FD3;
+					}
+				}
+			}
+		}
+
+		.price-num {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			margin-top: 14rpx;
+
+			.label {
+				font-size: 26rpx;
+				font-weight: bold;
+				color: #111111;
+			}
+
+			// .num-box {
+			// 	display: flex;
+			// 	align-items: center;
+
+			// 	.img-box {
+			// 		width: 60rpx;
+			// 		height: 60rpx;
+			// 		border: 1px solid #dddddd;
+			// 		display: flex;
+			// 		align-items: center;
+			// 		justify-content: center;
+
+			// 		image {
+			// 			width: 25rpx;
+			// 			height: 25rpx;
+			// 		}
+			// 	}
+
+			// 	input {
+			// 		width: 60rpx;
+			// 		height: 60rpx;
+			// 		line-height: 60rpx;
+			// 		font-size: 28rpx;
+			// 		font-weight: 500;
+			// 		color: #111111;
+			// 		// border-radius: 4rpx;
+			// 		border-top: 1px solid #dddddd;
+			// 		border-bottom: 1px solid #dddddd;
+			// 		text-align: center;
+			// 		// margin: 0 16rpx;
+			// 	}
+			// }
+		}
+
+		.sub-btn {
+			width: 100%;
+			height: 88rpx;
+			line-height: 88rpx;
+			text-align: center;
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #FFFFFF;
+			background: #008FD3;
+			border-radius: 44rpx;
+			margin-top: 30rpx;
+			// margin-bottom: 30rpx;
+
+		}
+	}
+
+	.contact-btn {
+		display: inline-block;
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		opacity: 0;
+		z-index: 9999;
+	}
+
+	.loadding {
+		background-color: #fff;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		z-index: 9999;
+
+		image {
+			border-radius: 50%;
+			animation: load linear 1s infinite;
+			width: 120rpx;
+			height: 120rpx;
+		}
+
+		.text {
+			font-size: 28rpx;
+			margin-top: 20rpx;
+		}
+	}
+
+	.form-item {
+		padding: 30rpx 0;
+		display: flex;
+		align-items: flex-start;
+		border-bottom: 1px solid #F1F1F1;
+
+		&:last-child {
+			border-bottom: none;
+		}
+
+		.label {
+			width: 180rpx;
+			text-align: left;
+			font-size: 30rpx;
+			line-height: 44rpx;
+			font-weight: 500;
+			color: #222222;
+			flex-shrink: 0;
+		}
+
+		input {
+			text-align: left;
+		}
+
+		.form-input {
+			font-size: 30rpx;
+			font-weight: 500;
+			color: #999999;
+			text-align: left;
+		}
+
+		.form-textarea {
+			font-size: 30rpx;
+			color: #999999;
+			height: 100rpx;
+			padding: 4rpx 0;
+		}
+
+		.birth-picker {
+			flex: 1;
+			display: flex;
+			align-items: center;
+
+			.right-box {
+				width: 100%;
+				display: flex;
+				align-items: center;
+
+				.input-box {
+					width: 470rpx;
+				}
+
+				.arrow {
+					width: 13rpx;
+					height: 23rpx;
+					margin-left: 20rpx;
+				}
+			}
+		}
+	}
+</style>

+ 187 - 0
pages_shop/order.vue

@@ -0,0 +1,187 @@
+<template>
+	<view>
+		<view class=""></view>
+		<view class="content">
+			<u-tabs class="tabs" itemStyle="width:33%;height:100rpx;" :list="tabList" @click="tabsClick"
+				lineColor="#FF5C03"></u-tabs>
+			<view class="order-list">
+				<view class="order-item" v-for="(item,index) in orderList" :key="index">
+					<view class="order-num">
+						<!-- {{item.}} -->
+						<text>订单号:{{item.orderCode}}</text>
+						<text v-if="item.status==-1">申请退款</text>
+						<text v-else-if="item.status==-2">退货成功</text>
+						<text v-else-if="item.status==1">待支付</text>
+						<text v-else-if="item.status==2">待发货</text>
+						<text v-else-if="item.status==3">待收货</text>
+						<text v-else-if="item.status==4">待评价</text>
+						<text v-else-if="item.status==5">已完成</text>
+					</view>
+					<view class="order-main">
+						<view class="img-box">
+							<image src="/static/images/a.jpg"></image>
+						</view>
+						<view class="order-text">
+							<view class="title">{{item.orderName}}</view>
+							<view class="txt">适用于乏力、头晕等人群,通过问诊可明确诊断给予专业性指导意见。</view>
+							<view class="num">
+								<text>45708 人已购</text>
+								<text class="grey">x{{item.totalNum}}</text>
+							</view>
+						</view>
+					</view>
+					<view class="order-money">
+						<text class="title">订单金额:</text>
+						<text class="num">¥<text class="bold">{{item.totalPrice}}</text>.00</text>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		liveOrderList
+	} from '@/api/order.js'
+	export default {
+		data() {
+			return {
+				orderList: [],
+				tabList: [{
+					name: '全部'
+				}, {
+					name: '待付款'
+				}, {
+					name: '已付款'
+				}]
+			}
+		},
+		mounted() {
+			this.getliveOrderList()
+		},
+		methods: {
+			tabsClick(item) {
+				console.log('item', item);
+			},
+
+			// 订单列表
+			getliveOrderList() {
+				let data = {
+					pageSize: 10,
+					page: 1
+				}
+				liveOrderList(data).then(res => {
+						if (res.code == 200) {
+							console.log("订单列表数据>>>>", res)
+							this.orderList = res.rows
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {
+						console.log("rej:" + JSON.stringify(rej));
+					}
+				);
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	:deep(.u-tabs) {
+		background-color: #FFFFFF;
+	}
+
+	.content {
+
+		.order-list {
+			background: #F5F7FA;
+			padding: 0 24rpx;
+
+			.order-item {
+				background: #FFFFFF;
+				border-radius: 16rpx;
+				padding: 30rpx 24rpx;
+				margin-top: 24rpx;
+
+				.order-num {
+					display: flex;
+					justify-content: space-between;
+					font-size: 26rpx;
+					color: #999999;
+				}
+
+				.order-main {
+					display: flex;
+					margin: 26rpx 0 30rpx;
+
+					.img-box {
+						width: 180rpx;
+						height: 180rpx;
+						border-radius: 16rpx;
+						flex-shrink: 0;
+						overflow: hidden;
+						margin-right: 26rpx;
+
+						image {
+							width: 100%;
+							height: 100%;
+						}
+					}
+
+					.order-text {
+						.title {
+							font-weight: 500;
+							font-size: 28rpx;
+							color: #222222;
+						}
+
+						.txt {
+							font-size: 24rpx;
+							color: #999999;
+							margin: 8rpx 0 18rpx 0;
+						}
+
+						.num {
+
+							display: flex;
+							justify-content: space-between;
+							font-size: 22rpx;
+							color: #E69A22;
+
+							.grey {
+								margin-top: 12rpx;
+								font-size: 24rpx;
+								color: #999999;
+
+							}
+						}
+					}
+
+				}
+
+				.order-money {
+					.title {
+						font-size: 24rpx;
+						color: #757575;
+					}
+
+					.num {
+						font-weight: 600;
+						font-size: 20rpx;
+						color: #FF5C03;
+
+						.bold {
+							font-weight: bold;
+							font-size: 36rpx;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 892 - 0
pages_shop/paymentOrder.vue

@@ -0,0 +1,892 @@
+<template>
+	<view class="content">
+		<view class="inner">
+			<!-- 时间、价格 -->
+			<view class="time-price">
+				<text class="time">请在{{payLimitTime}}前完成支付</text>
+				<view class="price-box">
+					<text class="unit">¥</text>
+					<text class="num">{{order ? (Number(order.totalPrice) || 0).toFixed(2) : "0.00"}}</text>
+				</view>
+				<!-- <text class="desc" v-if="payType==2">代收金额{{payDelivery.toFixed(2)}},请您在收到快递后支付尾款给快递人员。</text>
+				<text class="desc" v-if="payType==3">货到付款金额{{payDelivery.toFixed(2)}},请您在收到快递后支付给快递人员。</text> -->
+			</view>
+			<!-- 支付方式 -->
+			<view class="pay-type">
+				<view class="title">支付方式</view>
+				<!-- 改价订单只能选择微信支付和物流代收 -->
+				<!-- <radio-group  @change="payTypeChange" v-if="order.isEditMoney!=null&&order.isEditMoney==1">
+					<view class="item"  >
+						<view class="left"  >
+							<image src="/static/images/wecha_pay.png" mode=""></image>
+							<text class="text">微信支付</text>
+						</view>
+						<label>
+							<radio :value="1" :checked="order.payType=='1'" />
+						</label>
+					</view>
+					<view class="item"  >
+						<view class="left">
+							<image src="/static/images/pay_de.png" mode=""></image>
+							<text class="text">物流代收</text>
+						</view>
+						<label>
+							<radio  :value="2" :checked="order.payType=='2'" />
+						</label>
+					</view>
+				</radio-group> -->
+
+				<!-- <radio-group @change="payTypeChange" v-else-if="order.orderCreateType!=null&& order.orderCreateType==3">
+					<view class="item"  >
+						<view class="left" >
+							<image src="/static/images/wecha_pay.png" mode=""></image>
+							<text class="text">微信支付</text>
+						</view>
+						<label>
+							<radio :value="1" :checked="order.payType=='1'" />
+						</label>
+					</view>
+					<view class="item" >
+						<view class="left">
+							<image src="/static/images/pay_de.png" mode=""></image>
+							<text class="text">物流代收</text>
+						</view>
+						<label>
+							<radio  :value="2" :checked="order.payType=='2'" />
+						</label>
+					</view>
+					<view class="item" v-if="user!=null&&user.level==1 ">
+						<view class="left">
+							<image src="/static/images/pay_1.png" mode=""></image>
+							<text class="text">货到付款</text>
+						</view>
+						<label>
+							<radio  :value="3" :checked="order.payType=='3'" />
+						</label>
+					</view>
+				</radio-group>
+				<radio-group @change="payTypeChange" v-else-if="order.orderCreateType!=null&& order.orderCreateType==2">
+					<view class="item" v-if="payType==1||payType==4" >
+						<view class="left" >
+							<image src="/static/images/wecha_pay.png" mode=""></image>
+							<text class="text">微信支付</text>
+						</view>
+						<label>
+							<radio :value="1" :checked="order.payType=='1'" />
+						</label>
+					</view>
+					<view class="item" v-if="payType==2||payType==4">
+						<view class="left" >
+							<image src="/static/images/pay_de.png" mode=""></image>
+							<text class="text">物流代收</text>
+						</view>
+						<label>
+							<radio  :value="2" :checked="order.payType=='2'" />
+						</label>
+					</view>
+					<view class="item" v-if="user!=null&&user.level==1 ">
+						<view class="left">
+							<image src="/static/images/pay_1.png" mode=""></image>
+							<text class="text">货到付款</text>
+						</view>
+						<label>
+							<radio  :value="3" :checked="order.payType=='3'" />
+						</label>
+					</view>
+				</radio-group> -->
+				<!-- <radio-group @change="payTypeChange" v-else-if="order.orderCreateType!=null&&(order.orderCreateType==1)">
+					<view class="item"  >
+						<view class="left" >
+							<image src="/static/images/wecha_pay.png" mode=""></image>
+							<text class="text">微信支付</text>
+						</view>
+						<label>
+							<radio :value="1" checked />
+						</label>
+					</view>
+				</radio-group> -->
+				<radio-group @change="handlePayTypeChange">
+					<view class="item">
+						<view class="left">
+							<image src="/static/images/wecha_pay.png" mode=""></image>
+							<text class="text">微信支付</text>
+						</view>
+						<label>
+							<radio :value="1" :checked="payType === 1" />
+						</label>
+					</view>
+					<!-- #ifdef APP-PLUS||H5 -->
+					<view class="item">
+						<view class="left">
+							<image src="/static/images/zfb.png" mode=""></image>
+							<text class="text">支付宝</text>
+						</view>
+						<label>
+							<radio :value="2" :checked="payType === 2" />
+						</label>
+					</view>
+					<!-- #endif -->
+				</radio-group>
+			</view>
+			<!-- 订单详情查看 -->
+			<view class="order-info">
+				<view class="title">订单信息</view>
+				<view class="item">
+					<text class="label">订单编号</text>
+					<view class="sn-box">
+						<view>
+							<view class="text">{{order?.orderCode}}</view>
+						</view>
+						<view class="copy-btn" @click="copyOrderSn(orderCode)">复制</view>
+					</view>
+				</view>
+				<view class="item">
+					<text class="label">下单时间</text>
+					<text class="text">{{ formattedDate}} </text>
+				</view>
+				<view class="item">
+					<text class="label">订单金额</text>
+					<text class="text" v-if="order!=null">{{order ? (Number(order.totalPrice) || 0).toFixed(2) : "0.00"}}</text>
+				</view>
+
+				<!-- <view class="item">
+					<text class="label">支付方式</text>
+					<text class="text">微信支付</text>
+				</view> -->
+
+			</view>
+
+		</view>
+		<view class="btn-box">
+			<view class="btn" @click="payOrder()">去支付</view>
+			<!-- <view class="other-btn">
+				亲友代付
+				<button class="share" data-name="shareBtn" open-type="share">分享</button>
+			</view> -->
+		</view>
+	</view>
+</template>
+
+<script>
+	import dayjs from 'dayjs';
+	import {
+		zfbPayment,
+		weChatPayment
+	} from '@/api/pay'
+
+	// const isoDate = "2025-08-07T17:08:33.450+0800";
+	// const formatted = dayjs(isoDate).format('YYYY-MM-DD HH:mm:ss');
+
+	// import {getUserInfo} from '@/api/user'
+
+	// import {getStoreConfig} from '@/api/common'
+	// import {editPayType,pay,getStoreOrderById,payByCombinationId,getStoreOrderByCombinationId,editPayTypeByCombinationId} from '@/api/storeOrder'
+	export default {
+		data() {
+			return {
+				payType: 2,
+				order: null,
+				// formattedDate: '',
+				orderId: null,
+				payDelivery: 0,
+				payMoney: 0,
+				config: null,
+				payType: 1,
+				// payLimitTime: null,
+				user: null,
+				combinationOrderId: '',
+				// 需要开处方的订单id
+				prescribeOrder: ""
+			}
+		},
+		computed:{
+			 formattedDate() {
+			    return this.order?.createTime? dayjs(this.order.createTime).format('YYYY-MM-DD HH:mm:ss'): '';
+			  },
+			  payLimitTime() {
+			    return this.order?.updateTime? dayjs(this.order.updateTime).format('YYYY-MM-DD HH:mm:ss'): '';
+			  }
+		},
+		onLoad(options) {
+			console.log("支付订单是>>",options)
+			// this.orderKey = options.orderKey;
+			// this.liveId = options.liveId
+			// this.productId=options.productId
+			// console.log("支付订单",options)
+		if (options.orderList) {
+		    try {
+		      const decoded = decodeURIComponent(options.orderList);
+		      this.order = JSON.parse(decoded) || {}; // 默认空对象
+		    } catch (e) {
+		      console.error('参数解析失败:', e);
+		      this.order = {}; // 显式赋默认值
+		    }
+		  }
+			// console.log("支付订单是>>",options)
+
+			// this.combinationOrderId = option.combinationOrderId ? decodeURIComponent(option.combinationOrderId) : ''
+			// this.orderId=option.orderId ? JSON.parse(option.orderId) : '';
+			// if(this.combinationOrderId) {
+			// 	this.getStoreOrderByCombinationId()
+			// } else {
+			// 	this.getStoreOrderById();
+			// }
+			// this.getStoreConfig();
+			// this.getUserInfo();
+			// uni.showShareMenu({
+			// 	withShareTicket:true,
+			// 	//小程序的原生菜单中显示分享按钮,才能够让发送给朋友与分享到朋友圈两个按钮可以点击
+			// 	menus:["shareAppMessage"] //不设置默认发送给朋友
+			// })
+		},
+		//发送给朋友
+		onShareAppMessage(res) {
+			const combinationOrderId = this.combinationOrderId ?
+				`&combinationOrderId=${encodeURIComponent(this.combinationOrderId)}` : ''
+			return {
+				title: "帮TA支付",
+				path: '/pages_user/user/otherPaymentOrder?orderId=' + this.orderId + combinationOrderId,
+				imageUrl: '/static/images/logo.png' //分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
+			}
+
+		},
+		methods: {
+			payOrder() {
+				if (this.payType == 1) {
+					this.doWechatPay()
+				} else if(this.payType == 2) {
+					this.doAlipay()
+				}else{
+					uni.showToast({
+						title: "暂时无可用支付",
+						icon: 'none'
+					})
+				}
+			},
+			
+			// 选微信支付或者支付宝支付
+			handlePayTypeChange(e) {
+				this.payType = e.detail.value; // 获取选中的 value
+				console.log('当前选中:', this.payType);
+				// 根据值执行不同逻辑
+				// if (this.payType === 1) {
+				// 	this.doWechatPay();
+				// } else if (this.payType === 2) {
+				// 	this.doAlipay();
+				// }
+			},
+			
+			
+			 async doWechatPay() {
+			      try {
+			        uni.showLoading({ title: '发起支付中...', mask: true });
+					let data={
+						orderId:this.order.orderId
+					}
+					// await weChatPayment(this.order.orderId, Number(this.order.totalPrice)); 
+			        await weChatPayment(data); 
+			        uni.redirectTo({ url: '/pages_shop/success' });
+			        
+			      } catch (err) {
+			        console.error('支付流程异常:', err);
+			      } finally {
+			        uni.hideLoading();
+			      }
+			    },
+			
+			
+			
+			// doWechatPay(){
+			// 	weChatPayment(data).then(res => {
+			// 		if (res.code == 200) {
+						
+			// 		}
+			// 	})
+			// },
+			// 支付宝支付
+			doAlipay() {
+				var data = {
+					orderId: this.order.orderId
+				};
+				console.log("orderId>>", this.order.orderId)
+				let that = this;
+				// #ifdef H5||APP-PLUS
+				// #ifdef APP-PLUS
+				const tzCashier = uni.requireNativePlugin("TZBank-Cashier");
+				// #endif
+				uni.showLoading();
+				zfbPayment(data).then(res => {
+						console.log("支付开始",res)
+						uni.hideLoading();
+						if (res.code == 200) {
+							console.log("支付在这里", res)
+							if (res.type == "tz") {
+								//console.log("qxj orderFlowNo:"+res.data.body.orderFlowNo+" businessCstNo:"+res.data.body.orderNo+" platMerCstNo:"+res.data.body.platMerCstNo);
+								const match = res.data.body.url.match(/[\?&]businessCstNo=([^&]+)/);
+								const businessCstNo = match ? match[1] : null;
+								console.log("qxj tzCashier:" + tzCashier + " businessCstNo:" + businessCstNo);
+								tzCashier.pay({
+									env: 0,
+									wxMiniProgramType: 0,
+									// wxAppId: 'wx703c4bd07bbd1695',
+									wxAppId: 'wx9ea36eecd281bcd3',
+									wxUniversalLink: "https://yjf.runtzh.com/",
+									orderFlowNo: res.data.body.orderFlowNo,
+									businessCstNo: businessCstNo,
+									platMerCstNo: res.data.body.platMerCstNo
+								}, (res) => {
+									// uni.showToast({
+									// 	title:'收银台回调:'+JSON.stringify(res),
+									// 	icon:'none'
+									// })
+									uni.$emit('closePrivilege', {});
+									that.showPayTips = true;
+								});
+							} else if (res.type == 'hf') {
+								if (uni.getWindowInfo().platform == 'android') {
+									var alipayScheme = 'alipays://platformapi/startApp?&saId=10000007&qrcode=' + res
+										.data.qr_code;
+								} else {
+									var alipayScheme = 'alipay://platformapi/startApp?&saId=10000007&qrcode=' + res
+										.data.qr_code;
+								}
+								// 在uni-app中使用plus.runtime.openURL打开URL
+								plus.runtime.openURL(alipayScheme, function(error) {
+
+								});
+								uni.$emit('closePrivilege', {});
+								that.showPayTips = true;
+							}
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							})
+						}
+					},
+					rej => {}
+				);
+				// #endif
+			},
+
+
+
+
+
+
+
+
+
+
+
+
+
+			getUserInfo() {
+				getUserInfo().then(
+					res => {
+						if (res.code == 200) {
+							if (res.user != null) {
+								this.user = res.user;
+							}
+						} else {
+							uni.showToast({
+								icon: 'none',
+								title: "请求失败",
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			getStoreConfig() {
+				getStoreConfig().then(
+					res => {
+						if (res.code == 200) {
+							this.config = res.data
+							console.log(this.config);
+						}
+					},
+					rej => {}
+				);
+			},
+			payTypeChange(e) {
+				if (this.combinationOrderId) {
+					this.editPayTypeByCombinationId(e.detail.value)
+				} else {
+					this.editPayType(e.detail.value)
+				}
+			},
+			copyOrderSn(text) {
+				// 复制方法
+				uni.setClipboardData({
+					data: text,
+					success: () => {
+						uni.showToast({
+							title: '内容已成功复制到剪切板',
+							icon: 'none'
+						})
+					}
+				});
+			},
+			// getStoreOrderById(){
+			// 	var data = {orderId:this.orderId};
+			// 	var that=this;
+			// 	uni.showLoading();
+			// 	getStoreOrderById(data).then(
+			// 		res => {
+			// 			if(res.code==200){
+			// 				console.log(res);
+			// 				uni.hideLoading();
+			// 				that.order=res.order;
+			// 				that.order.orderCodes = that.order.orderCode ? [that.order.orderCode]:[]
+			// 				that.orderCode = that.order.orderCode
+			// 				that.payLimitTime=res.payLimitTime;
+			// 				//套餐订单处理
+			// 				if(res.productPackage!=null){
+			// 					this.payType=res.productPackage.payType;
+			// 					console.log(this.payType)
+			// 					if(this.order.payType==4){
+			// 						this.order.payType=1;
+			// 					}
+			// 				}
+			// 				this.editPayType(this.order.payType)
+
+			// 			}else{
+			// 				uni.showToast({
+			// 					icon:'none',
+			// 					title: res.msg,
+			// 				});
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+
+			// },
+			editPayType(payType) {
+				var data = {
+					orderId: this.orderId,
+					payType: payType
+				};
+				var that = this;
+				uni.showLoading();
+				editPayType(data).then(
+					res => {
+						if (res.code == 200) {
+							console.log(res);
+							uni.hideLoading();
+							that.order = res.order;
+							that.order.orderCodes = that.order.orderCode ? [that.order.orderCode] : []
+							that.orderCode = that.order.orderCode
+							// this.payType=this.order.payType
+							this.payMoney = this.order.payMoney;
+							this.payDelivery = this.order.payDelivery;
+						} else {
+							uni.showToast({
+								icon: 'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+
+			},
+			// getStoreOrderByCombinationId() {
+			// 	var data = {combinationId:this.combinationOrderId};
+			// 	var that=this;
+			// 	uni.showLoading();
+			// 	getStoreOrderByCombinationId(data).then(
+			// 		res => {
+			// 			if(res.code==200){
+			// 				console.log(res);
+			// 				uni.hideLoading();
+			// 				that.order=res.order;
+			// 				that.orderCode = res.order.orderCodes ? res.order.orderCodes.join(',') : "";
+			// 				that.payLimitTime=res.payLimitTime;
+			// 				//套餐订单处理
+			// 				if(res.productPackage!=null){
+			// 					this.payType=res.productPackage.payType;
+			// 					console.log(this.payType)
+			// 					if(this.order.payType==4){
+			// 						this.order.payType=1;
+			// 					}
+			// 				}
+			// 				that.prescribeOrder = res.prescribeOrder;
+			// 				this.editPayTypeByCombinationId(this.order.payType)
+
+			// 			}else{
+			// 				uni.showToast({
+			// 					icon:'none',
+			// 					title: res.msg,
+			// 				});
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+			// editPayTypeByCombinationId(payType){
+			// 	var data = {combinationOrderId:this.combinationOrderId,payType:payType};
+			// 	var that=this;
+			// 	uni.showLoading();
+			// 	editPayTypeByCombinationId(data).then(
+			// 		res => {
+			// 			if(res.code==200){
+			// 				console.log(res);
+			// 				uni.hideLoading();
+			// 				that.order=res.order;
+			// 				that.orderCode = res.order.orderCodes ? res.order.orderCodes.join(',') : "";
+			// 				//this.payType=this.order.payType
+			// 				this.payMoney=this.order.payMoney;
+			// 				this.payDelivery=this.order.payDelivery;
+			// 				that.prescribeOrder = res.prescribeOrder;
+			// 			}else{
+			// 				uni.showToast({
+			// 					icon:'none',
+			// 					title: res.msg,
+			// 				});
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+
+			// },
+			otherPayOrder() {
+				// uni.navigateTo({
+				// 	url: '/pages_user/user/otherPaymentOrder?orderId='+this.orderId
+				// })
+				uni.navigateTo({
+					url: '/pages_user/user/otherPaymentOrder?combinationOrderId=' + encodeURIComponent(this
+						.combinationOrderId)
+				})
+			},
+
+			// payOrder() {
+			// 	if (this.combinationOrderId) {
+			// 		let data = {
+			// 			combinationOrderId: this.combinationOrderId,
+			// 			payType: this.order.payType
+			// 		};
+			// 		let that = this;
+			// 		uni.showLoading();
+			// 		payByCombinationId(data).then(
+			// 			res => {
+			// 				if (res.code == 200) {
+			// 					this.payfun(res)
+			// 				} else {
+			// 					uni.showToast({
+			// 						icon: 'none',
+			// 						title: res.msg,
+			// 					});
+			// 				}
+			// 			},
+			// 			rej => {}
+			// 		);
+			// 	} else {
+			// 		let data = {
+			// 			orderId: this.order.id,
+			// 			payType: this.order.payType
+			// 		};
+			// 		let that = this;
+			// 		uni.showLoading();
+			// 		pay(data).then(
+			// 			res => {
+			// 				if (res.code == 200) {
+			// 					this.payfun(res)
+			// 				} else {
+			// 					uni.showToast({
+			// 						icon: 'none',
+			// 						title: res.msg,
+			// 					});
+			// 				}
+			// 			},
+			// 			rej => {}
+			// 		);
+			// 	}
+			// },
+			payfun(res) {
+				const that = this
+				console.log(res.result);
+				if (res.payType == 1 || res.payType == 2) {
+					uni.requestPayment({
+						provider: 'wxpay',
+						timeStamp: res.result.timeStamp,
+						nonceStr: res.result.nonceStr,
+						// package: res.result.packageValue,
+						package: res.result.packageStr,
+						signType: res.result.signType,
+						paySign: res.result.paySign,
+						success: function(res) {
+							uni.hideLoading();
+							uni.redirectTo({
+								url: "success?order=" + JSON.stringify(that.order)
+							})
+						},
+						fail: function(err) {
+							uni.showToast({
+								icon: 'none',
+								title: 'fail:' + JSON.stringify(err),
+							});
+							console.log('fail:' + JSON.stringify(err));
+							uni.hideLoading();
+						}
+					});
+				} else if (res.payType == 3) {
+					uni.hideLoading();
+					if (that.order.isPrescribe) {
+						//如果是处方订单开处方
+						// uni.redirectTo({
+						// 	url:"prescribe?orderId="+that.order.id
+						// })
+						uni.redirectTo({
+							url: "prescribe?orderId=" + that.prescribeOrder + "&combinationOrderId=" +
+								encodeURIComponent(that.order.combinationOrderId)
+						})
+					} else {
+						//如果是普通订单
+						uni.redirectTo({
+							url: "success?order=" + JSON.stringify(that.order)
+						})
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page {
+		height: 100%;
+	}
+
+	.content {
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+
+		.inner {
+			padding: 20upx;
+
+			.time-price {
+				box-sizing: border-box;
+				padding: 50upx 0upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+
+				.time {
+					font-size: 32upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #222222;
+					line-height: 1;
+					text-align: center;
+				}
+
+				.desc {
+					margin: 30upx 0upx 15upx;
+					font-size: 26upx;
+					font-family: PingFang SC;
+					color: #999999;
+					line-height: 1;
+					text-align: center;
+				}
+
+				.price-box {
+					display: flex;
+					align-items: flex-end;
+					margin-top: 28upx;
+
+					.unit {
+						font-size: 32upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1.3;
+						margin-right: 10upx;
+					}
+
+					.num {
+						font-size: 56upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #FF6633;
+						line-height: 1;
+					}
+				}
+			}
+
+			.pay-type {
+				box-sizing: border-box;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				margin-top: 20upx;
+				padding: 40upx 30upx;
+				display: flex;
+				flex-direction: column;
+				justify-content: space-between;
+
+				.title {
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+					line-height: 1;
+					margin-bottom: 10upx;
+				}
+
+				.item {
+					padding: 15upx 0upx;
+					display: flex;
+					align-items: center;
+					justify-content: space-between;
+
+					.left {
+						display: flex;
+						align-items: center;
+
+						image {
+							width: 44upx;
+							height: 44upx;
+							margin-right: 20upx;
+						}
+
+						.text {
+							font-size: 30upx;
+							font-family: PingFang SC;
+							font-weight: bold;
+							color: #222222;
+							line-height: 1;
+						}
+					}
+				}
+			}
+
+			.order-info {
+				margin-top: 20upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				padding: 40upx 30upx;
+
+				.title {
+					font-size: 30upx;
+					font-family: PingFang SC;
+					font-weight: bold;
+					color: #222222;
+					line-height: 1;
+				}
+
+				.item {
+					margin-top: 40upx;
+					display: flex;
+					align-items: center;
+					justify-content: space-between;
+
+					.label {
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #666666;
+						line-height: 1;
+					}
+
+					.text {
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #222222;
+						line-height: 32upx;
+					}
+
+					.cont-text {
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #666666;
+
+						.bold {
+							color: #111111;
+						}
+					}
+
+					.sn-box {
+						display: flex;
+						align-items: center;
+
+						.copy-btn {
+							width: 58upx;
+							height: 32upx;
+							line-height: 32upx;
+							text-align: center;
+							font-size: 22upx;
+							font-weight: 500;
+							color: #222222;
+							background: #F5F5F5;
+							border-radius: 4upx;
+							margin-left: 24upx;
+						}
+					}
+
+				}
+
+				.line {
+					width: 100%;
+					height: 1px;
+					background: #F0F0F0;
+					margin-top: 30upx;
+				}
+			}
+		}
+
+		.btn-box {
+			height: 242upx;
+			background: #FFFFFF;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+
+			.btn {
+				width: 91.73%;
+				height: 88upx;
+				line-height: 88upx;
+				font-size: 30upx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				text-align: center;
+				background: #0bb3f2;
+				border-radius: 44upx;
+				margin-bottom: 10rpx;
+			}
+
+			.other-btn {
+				width: 91.73%;
+				height: 88upx;
+				line-height: 88upx;
+				font-size: 30upx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #0bb3f2;
+				border: 1rpx solid #0bb3f2;
+				text-align: center;
+				background: #FFFFFF;
+				border-radius: 44upx;
+				margin-bottom: 10rpx;
+				position: relative;
+
+				.share {
+					display: inline-block;
+					position: absolute;
+					top: 0;
+					left: 0;
+					width: 100%;
+					height: 100%;
+					opacity: 0;
+				}
+			}
+		}
+	}
+</style>

+ 648 - 0
pages_shop/store.vue

@@ -0,0 +1,648 @@
+<template>
+	<!-- v-show="liveId" -->
+	<view class="content" >
+		<view class="uni-nav-bar" :style="{backgroundColor: `rgba(58, 17, 1,${opacity})`}">
+			<view :style="{height: statusBarHeight + 'px',width: '100%'}"></view>
+			<view class="uni-nav-barbox">
+				<view class="uni-nav-back">
+					<u-icon name="arrow-left" color="#333" size="20" @click="rightClick"></u-icon>
+				</view>
+				<view class="uni-nav-title"
+					:style="{opacity: 1,width:`calc(100vw - 100rpx - ${menuRight} - ${menuWidth})`}">
+					<view class="inputbox" :style="{background: opacity >= 0.6 ? '#f7f7f7':'#fff'}" @click="toSearch">
+						<image class="icon-search" src="/static/images/search.png" mode=""></image>
+						<view>搜索店内药品</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="bg"></view>
+		<!-- <image class="bg" src="/static/images/chu_query.png" mode="widthFix"></image> -->
+		<view class="content-body">
+			<view class="store-head" v-show="storeInfo.storeName">
+				<view class="store-head-top">
+					<view class="store-head-logo">
+						<u-image shape="square" :src="storeInfo.logoUrl || logoUrl" width="100rpx" height="100rpx"
+							radius="6"></u-image>
+					</view>
+					<view class="store-head-name">{{storeInfo.storeName || ''}}</view>
+				</view>
+				<view class="store-head-desc">
+					<view>销售{{storeInfo.salesCount }}</view>
+					<view>24小时营业</view>
+					<view>支持预订</view>
+				</view>
+			</view>
+			<view class="storebox">
+				<u-sticky bgColor="#fff" :offset-top="statusBarHeight + 44">
+					<u-tabs :list="tabbar" :current="current" @click="clickTab" class="u-tabs"></u-tabs>
+				</u-sticky>
+				<!-- 商品 -->
+				<view :style="{height: divHeight,display: current == 0 ? 'flex' : 'none'}" class="medic-box">
+					<view class="cate-list">
+						<view v-for="(item,index) in cates" :key="index" :class="cateSelect == item.cateId?'item active':'item'" @click="choseCate(item)">
+							{{item.cateName }}</view>
+					</view>
+					<view class="medic">
+						<!-- 轮播图 -->
+						<view class="banner-box">
+							<swiper class="swiper" :indicator-dots="true" :circular="true" :autoplay="true"
+								:interval="3000" :duration="1000" indicator-color="rgba(255, 255, 255, 0.6)"
+								indicator-active-color="#ffffff">
+								<swiper-item class="swiper-item" v-for="(item,index) in advs" :key="index" @click="handleAdvClick(item)">
+									<image :src="item.imageUrl" mode=""></image>
+								</swiper-item>
+							</swiper>
+						</view>
+						<!-- 药品列表 -->
+						<view class="medic-list">
+							<view class="inner-list">
+								<view class="definite" v-for="(subItem,index) in products" :key="index"	@click="showProductList(subItem)">
+									<view class="img-box">
+										<image :src="subItem.imgUrl" mode="aspectFit"></image>
+									</view>
+									<view class="name ellipsis">{{subItem.productName}}</view>
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+				<!-- 商家信息 -->
+				<view class="storebox-info" :style="{height: divHeight}" v-show="current == 1">
+					<view class="storebox-map">
+						<u-icon name="map" color="#ccc" size="18"></u-icon>
+						<view style="margin-left: 10rpx;">{{storeInfo.address || "--"}}</view>
+					</view>
+					<view class="storebox-map" v-if="storeInfo.phone">
+						<u-icon name="phone" color="#ccc" size="18"></u-icon>
+						<view style="margin-left: 10rpx;">{{storeInfo.phone || "--"}}</view>
+					</view>
+					<view class="storebox-qualifications" v-if="storeInfo.descs">
+						<u-icon name="volume" color="#ccc" size="18"></u-icon>
+						<view style="margin-left: 10rpx;">{{storeInfo.descs || "--"}}</view>
+					</view>
+					<view class="storebox-qualifications">
+						<u-icon name="file-text" color="#ccc" size="18"></u-icon>
+						<view style="margin-left: 10rpx;">商家资质</view>
+					</view>
+					<view class="qualifications">
+						<view v-for="(img,i) in licenseImagesList" :key="i">
+							<u-image shape="square" lazyLoad :src="img" width="100%" mode="widthFix" radius="6"
+								@click="previewImage(i)"></u-image>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		// 小黄车
+		liveStore, //店铺展示,
+	} from '@/api/live'
+	// import {getProductCate} from '@/api/product';
+	// import {getAdv} from '@/api/adv';
+	// import { getStoreById } from "@/api/store.js";
+
+	export default {
+		data() {
+			return {
+				products:[],
+				liveId:null,
+				statusBarHeight: uni.getWindowInfo().statusBarHeight,
+				// 右侧的胶囊距离右侧屏幕距离-px
+				menuRight: uni.getStorageSync('menuInfo').menuRight,
+				// 右侧的胶囊宽度-px
+				menuWidth: uni.getStorageSync('menuInfo').menuWidth,
+				opacity: 0,
+				opacityTxt: 0,
+				// storeId: "",
+				tabbar: [{
+					name: '商品',
+				}, {
+					name: '商家',
+				}],
+				current: 0,
+				storeInfo: {},
+				// logoUrl: "/static/images/adfd21c004854c9b8997d371d7a0ce8c.jpg",
+				// 商家资质图片
+				// licenseImagesList: ["/static/images/sjzz.jpg"],
+				divHeight: '0px',
+				allCates: [],
+				cates: [],
+				subCates: [],
+				// 选中药品分类
+				cateSelect: 0,
+				// 轮播图
+				advs: [],
+				// 'company'表示销售管理的进来的
+				from: ""
+			}
+		},
+		onLoad(options) {
+			if (options.liveId) {
+				this.liveId = options.liveId;
+				console.log("接收到的liveId:", this.liveId);
+			}
+			
+			
+			
+			
+			this.storeId = options.storeId || ""
+			this.from = options.from || ''
+			if (this.storeId) {
+				this.getStoreInfo()
+				this.getProductCate();
+			} else {
+				uni.showToast({
+					title: "storeId不存在~",
+					icon: "none"
+				})
+			}
+		},
+		mounted() {
+			this.getliveStore() // 获取小黄车 店铺展示
+		},
+		onShow() {
+			this.divHeight = `calc(100vh - 44px - 88rpx - ${this.statusBarHeight}px)`
+			// this.getAdv();
+		},
+		onPageScroll(e) {
+			if (e.scrollTop <= 44) {
+				this.opacityTxt = 0
+				this.opacity = e.scrollTop > this.statusBarHeight ? 0.6 : 0
+			} else if (e.scrollTop > 50) {
+				this.opacity = 1
+				this.opacityTxt = 1
+			}
+
+		},
+		methods: {
+			
+			//小黄车 店铺展示
+			getliveStore() {
+				let data = {
+					pageSize: 10,
+					page: 1
+				}
+				liveStore(this.liveId, data).then(res => {
+						if (res.code == 200) {
+							console.log("小黄车 店铺展示>>>>", res)
+							this.products = res.data
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			
+			
+			
+			
+			
+			
+			rightClick() {
+				uni.navigateBack()
+			},
+			clickTab(item) {
+				this.current = item.index
+			},
+			// 预览图片
+			previewImage(index) {
+				uni.previewImage({
+					current: index,
+					urls: this.licenseImagesList
+				});
+			},
+			getStoreInfo() {
+				getStoreById({
+					storeId: this.storeId
+				}).then(
+					res => {
+						if (res.code == 200) {
+							this.storeInfo = res.data || {}
+							// this.licenseImagesList = this.storeInfo.licenseImages ? this.storeInfo.licenseImages.split(',') : []
+
+						} else {
+							uni.showToast({
+								icon: 'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			toSearch() {
+				if (this.from == 'company') {
+					uni.navigateTo({
+						url: '/pages_company/order/productList?storeId=' + this.storeId || ''
+					})
+				} else {
+					uni.navigateTo({
+						url: '/pages/home/productSearch?storeId=' + this.storeId || ''
+					})
+				}
+			},
+			handleAdvClick(item) {
+				if (item.showType == 1) {
+					uni.setStorageSync('url', item.advUrl);
+					uni.navigateTo({
+						url: "/pages/home/h5?storeId=" + this.storeId || ""
+					})
+				} else if (item.showType == 2) {
+					uni.navigateTo({
+						url: item.advUrl
+					})
+				} else if (item.showType == 3) {
+					uni.setStorageSync('content', item.content);
+					uni.navigateTo({
+						url: "/pages/home/content?storeId=" + this.storeId || ""
+					})
+				}
+
+			},
+			// getAdv() {
+			// 	let data = {
+			// 		advType: 2
+			// 	};
+			// 	getAdv(data).then(
+			// 		res => {
+			// 			if (res.code == 200) {
+			// 				this.advs = res.data;
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+			getProductCate() {
+				let data = {};
+				getProductCate(data).then(
+					res => {
+						if (res.code == 200) {
+							this.allCates = res.data;
+							this.cates = this.allCates.filter(function(item) {
+								return item.pid == 0
+							});
+							if (this.cates != null && this.cates.length > 0) {
+								this.cateSelect = this.cates[0].cateId;
+								this.getSubCate()
+							}
+						} else {
+							uni.showToast({
+								icon: 'none',
+								title: "请求失败",
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			// 药品分类选择
+			choseCate(item) {
+				this.cateSelect = item.cateId;
+				this.getSubCate()
+
+			},
+			getSubCate() {
+				var that = this;
+				this.subCates = this.allCates.filter(function(item) {
+					// let subList = that.allCates.filter(child => {
+					// 	//返回每一项的子级数组
+					// 	return child.pid === item.cateId
+					// });
+					// subList.length > 0 ? item.children = subList : [];
+					return item.pid == that.cateSelect
+				});
+
+			},
+			// 查看药品详情
+			showProductList(item) {
+				uni.navigateTo({
+					url: '/pages/shopping/productList?cateId=' + item.cateId + "&pid=" + item.pid + '&storeId=' +
+						this.storeId + '&from=' + this.from
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@mixin u-flex($flexD, $alignI, $justifyC) {
+		display: flex;
+		flex-direction: $flexD;
+		align-items: $alignI;
+		justify-content: $justifyC;
+	}
+
+	.inputbox {
+		height: 60rpx;
+		padding: 0 20rpx;
+		@include u-flex(row, center, flex-start);
+		border-radius: 40rpx;
+		line-height: 60rpx;
+		font-size: 28rpx;
+		color: #999;
+
+		.icon-search {
+			width: 28rpx;
+			height: 28rpx;
+			margin-right: 20rpx;
+		}
+	}
+
+	.uni-nav-bar {
+		position: fixed;
+		top: 0;
+		left: 0;
+		width: 100%;
+		z-index: 999;
+		overflow: hidden;
+		font-weight: 500;
+
+		.uni-nav-barbox {
+			width: 100%;
+			height: 88rpx;
+			@include u-flex(row, center, flex-start);
+			position: relative;
+			font-size: 24rpx;
+		}
+
+		.uni-nav-title {
+			/* #ifdef APP-PLUS */
+			font-size: 34rpx;
+			/* #endif */
+			/* #ifndef APP-PLUS */
+			font-size: 14px;
+			/* #endif */
+			overflow: hidden;
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+		}
+
+		.uni-nav-back {
+			margin-left: 20rpx;
+			margin-right: 20rpx;
+			height: 88rpx;
+			@include u-flex(row, center, flex-start);
+		}
+	}
+
+	.content {
+		width: 100%;
+		position: relative;
+
+		.bg {
+			width: 100%;
+			height: auto;
+			position: absolute;
+			top: 0;
+			left: 0;
+			height: 388rpx;
+			background: #3A1101;
+
+		}
+
+		&-body {
+			position: relative;
+			padding-top: calc(var(--status-bar-height) + 88rpx);
+		}
+	}
+
+	.store-head {
+		position: relative;
+		z-index: 9;
+		margin: 0 24rpx 0 24rpx;
+		padding: 24rpx;
+		background: #FFFFFF;
+		border-radius: 16rpx 16rpx 16rpx 16rpx;
+		font-family: PingFang SC, PingFang SC;
+		color: #222222;
+		box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
+
+		&-top {
+			display: flex;
+			align-items: center;
+		}
+
+		&-logo {
+			flex-shrink: 0;
+			margin-right: 24rpx;
+		}
+
+		&-name {
+			font-weight: 600;
+			font-size: 32rpx;
+		}
+
+		&-desc {
+			margin-top: 16rpx;
+			display: flex;
+			align-items: center;
+			flex-wrap: wrap;
+			gap: 20rpx;
+			position: relative;
+			z-index: 2;
+
+			view {
+				padding-right: 20rpx;
+				font-size: 26rpx;
+				position: relative;
+
+				&::after {
+					content: "";
+					width: 0;
+					height: 28rpx;
+					border-right: 1rpx solid #eee;
+					position: absolute;
+					right: 0;
+					top: 50%;
+					transform: translate(0, -50%);
+				}
+
+				&:last-child::after {
+					border: none;
+				}
+			}
+		}
+	}
+
+	.border_bottom_line {
+		position: relative;
+
+		&::after {
+			content: "";
+			position: absolute;
+			bottom: 0;
+			left: 0;
+			border-bottom: 1px solid #F5F7FA;
+			width: 100%;
+			transform: scaleY(0.5);
+			border-top-color: #F5F7FA;
+			border-right-color: #F5F7FA;
+			border-left-color: #F5F7FA;
+		}
+	}
+
+	.storebox {
+		width: 100%;
+		margin-top: -60rpx;
+		padding-top: 80rpx;
+		background-color: #fff;
+		box-shadow: 0 -20rpx 16rpx #fff;
+		position: relative;
+		z-index: 1;
+
+		&-info {
+			padding: 24rpx 24rpx 0 24rpx;
+			background-color: #fff;
+			font-family: PingFang SC, PingFang SC;
+			font-size: 28rpx;
+			color: #333333;
+			position: relative;
+			border-top: 4px solid #F5F7FA;
+		}
+
+		&-map {
+			display: flex;
+			align-items: center;
+			word-break: break-all;
+			padding: 24rpx 0;
+		}
+
+		&-qualifications {
+			display: flex;
+			align-items: center;
+			padding: 24rpx 0;
+		}
+
+		.qualifications {
+			padding: 24rpx 0;
+		}
+	}
+
+	.medic-box {
+		display: flex;
+
+		.cate-list {
+			box-sizing: border-box;
+			width: 200upx;
+			background: #F2F5F9;
+			display: flex;
+			flex-direction: column;
+			padding: 20upx 0;
+			overflow-y: scroll;
+
+			.item {
+				height: 100upx;
+				line-height: 100upx;
+				padding-left: 30upx;
+				font-size: 28upx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #333333;
+				position: relative;
+
+				&.active {
+					color: #0bb3f2;
+
+					&::after {
+						content: "";
+						width: 8upx;
+						height: 50upx;
+						background: #0bb3f2;
+						position: absolute;
+						top: 25upx;
+						left: 0;
+					}
+				}
+			}
+		}
+
+		.medic {
+			box-sizing: border-box;
+			width: calc(100% - 200upx);
+			height: 100%;
+			padding: 0 30upx;
+
+			.banner-box {
+				margin-top: 30rpx;
+				width: 100%;
+				height: 160upx;
+				border-radius: 10upx;
+				overflow: hidden;
+
+				.swiper,
+				.swiper-item,
+				.swiper-item image {
+					width: 100%;
+					height: 100%;
+				}
+			}
+
+			.medic-list {
+				box-sizing: border-box;
+				padding: 30upx 0;
+				overflow-y: auto;
+				height: calc(100% - 220upx);
+				position: relative;
+				// .item{
+				// 	.title{
+				// 		font-size: 28upx;
+				// 		font-family: PingFang SC;
+				// 		font-weight: bold;
+				// 		color: #333333;
+				// 		padding-top: 20upx;
+				// 		margin-bottom: 30upx;
+				// 	}
+
+				// }
+				.inner-list {
+					display: flex;
+					flex-wrap: wrap;
+
+					.definite {
+						width: calc(33% - 20upx);
+						margin-right: 30upx;
+						margin-bottom: 30upx;
+
+						.img-box {
+							width: 100%;
+							height: 144upx;
+							background: #F5F5F5;
+							border-radius: 8upx;
+							overflow: hidden;
+							display: flex;
+							align-items: center;
+
+							image {
+								max-width: 100%;
+							}
+						}
+
+						.name {
+							width: 100%;
+							margin-top: 20upx;
+							font-size: 24upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #666666;
+							text-align: center;
+						}
+
+						&:nth-child(3n) {
+							margin-right: 0;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 203 - 0
pages_shop/success.vue

@@ -0,0 +1,203 @@
+<template>
+	<view class="content">
+		<view class="inner">
+			<view class="top">
+				<text class="title">支付成功</text>
+				 <image class="icon" src="/static/images/success.png" ></image>
+				 <view   class="btn-box">
+				 	<view class="btn cancel" @click="goOrderDetails(order.id)"> 查看订单</view>
+				 </view>
+			</view>
+			<!-- 订单详情查看 -->
+			<view class="order-info">
+				<view class="title">订单信息</view>
+				<view class="item">
+					<text class="label">订单编号</text>
+					<view class="sn-box">
+						<view>
+							<view class="text" v-for="item in order.orderCodes" :key="item">{{item}}</view>
+						</view>
+						<view class="copy-btn" @click="copyOrderSn(orderCode)">复制</view>
+					</view>
+				</view>
+				<view class="item">
+					<text class="label">下单时间</text>
+					<text class="text">{{order.createTime}}</text>
+				</view>
+				 
+			</view>
+			
+		</view>
+		 
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				order:null,
+				orderCode: "",
+				ids: []
+			}
+		},
+		onLoad(option) {
+			this.order=JSON.parse(decodeURIComponent(option.order))
+			// orderCodes和ids字段表示店铺订单
+			this.orderCode = this.order && this.order.orderCodes ? this.order.orderCodes.join(',') : this.order.orderCode || '';
+			this.ids = this.order && this.order.ids ? this.order.ids : this.order.id ?  [this.order.id] : [];
+		},
+		methods: {
+			copyOrderSn(text) {
+				// 复制方法
+				uni.setClipboardData({
+					data:text,
+					success:()=>{
+						uni.showToast({
+							title:'内容已成功复制到剪切板',
+							icon:'none'
+						})
+					}
+				});
+			},
+			goOrderDetails(id){
+				if(this.ids && this.ids.length > 1) {
+					uni.navigateTo({
+						url: '/pages_user/user/storeOrder?status='
+					})
+				} else {
+					uni.redirectTo({
+						url: "/pages_user/user/storeOrderDetail?id="+this.ids[0]
+					}) 
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page{
+		height: 100%;
+	}
+	.content{
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+		.inner{
+			padding: 20upx;
+			.top{
+				box-sizing: border-box;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				padding: 50upx 0upx;
+				.title{
+					font-size: 40upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #222222;
+					line-height: 1;
+					text-align: center;
+				}
+				.icon{
+					margin: 60upx 0upx;
+					width: 100upx;
+					height: 100upx;
+				}
+				 
+			}
+			 
+			.order-info{
+				margin-top: 20upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				padding: 40upx 30upx;
+				.title{
+					font-size: 30upx;
+					font-family: PingFang SC;
+					font-weight: bold;
+					color: #222222;
+					line-height: 1;
+				}
+				.item{
+					margin-top: 40upx;
+					display: flex;
+					align-items: center;
+					justify-content: space-between;
+					.label{
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #666666;
+						line-height: 1;
+					}
+					.text{
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #222222;
+						line-height: 32upx;
+					}
+					.cont-text{
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #666666;
+						.bold{
+							color: #111111;
+						}
+					}
+					.sn-box{
+						display: flex;
+						align-items: center;
+						.copy-btn{
+							width: 58upx;
+							height: 32upx;
+							line-height: 32upx;
+							text-align: center;
+							font-size: 22upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #222222;
+							background: #F5F5F5;
+							border-radius: 4upx;
+							margin-left: 24upx;
+						}
+					}
+					 
+				}
+				.line{
+					width: 100%;
+					height: 1px;
+					background: #F0F0F0;
+					margin-top: 30upx;
+				}
+			}
+		}
+		.btn-box{
+			margin-top: 20upx;
+			box-sizing: border-box;
+			display: flex;
+			align-items: center;
+			.btn{
+				width: 155upx;
+				height: 64upx;
+				line-height: 64upx;
+				font-size: 26upx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				text-align: center;
+				border-radius: 32upx;
+				&.cancel{
+					border: 1px solid #DDDDDD;
+					color: #666666;
+				}
+				 
+			}
+		}
+	}
+	
+</style>

+ 411 - 0
pages_user/addAddress.vue

@@ -0,0 +1,411 @@
+<template>
+	<view class="content">
+		<view class="inner">
+			<view class="address-box">
+				<textarea class="textarea" v-model="content"  placeholder="请粘贴或输入文本,点击'识别'自动识别姓名、电话、地址,格式:深圳市龙岗区坂田街道长坑路西2巷2号202 黄大大 18888888888"   />
+				<view  class="btns" >
+					<view  class="btn parse" @click="parseAddress()">识别</view>
+				</view>
+			</view>
+			<view class="form-box">
+				
+				<view class="form-item">
+					<text class="label">联系人</text>
+					<input type="text" v-model="form.realName" maxlength="10" placeholder="姓名" class="form-input" />
+				</view>
+				<view class="form-item">
+					<text class="label">手机号</text>
+					<input type="number" v-model="form.phone" maxlength="11"  placeholder="手机号" class="form-input" />
+				</view>
+				<view class="form-item">
+					<text class="label">所在地区</text>
+					<picker :value="multiIndex"  class="birth-picker"  mode="multiSelector" range-key="n" :range="addressList" @change="pickerChange"  @columnchange="pickerColumnchange">
+						<view class="right-box">
+							<view class="input-box">
+								<input type="text" v-model="form.address" placeholder="请选择" class="form-input" disabled="disabled" />
+							</view>
+							<image class="arrow" src="/static/images/arrow_gray.png" mode=""></image>
+						</view>
+					</picker>
+				</view>
+				<view class="form-item">
+					<text class="label">详细地址</text>
+					<textarea class="form-textarea" v-model="form.detail" placeholder="请输入详细地址"   />
+				</view>
+			</view>
+			<!-- 设为默认地址 -->
+			<view class="setting-box">
+				<text class="label">设为默认地址</text>
+				<evan-switch v-model="isDefault" activeColor="#0bb3f2" inactiveColor="rgba(0, 0, 0, 0.1)"></evan-switch>
+			</view>
+		</view>
+		<view class="btn-box">
+			<view class="sub-btn" @click="submit()">保存地址</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		addAddress, // 添加地址
+		editAddress, // 编辑地址
+		getCitys//获取省市区
+	} from "@/api/order.js"
+	// import {parseAddress,getCity,getCitys,getAddressById,addAddress,editAddress} from '@/api/address'
+	import EvanSwitch from '@/components/evan-switch/evan-switch.vue'
+	export default {
+		components: {
+			EvanSwitch
+		},
+		data() {
+			return {
+				content:null,
+				type:null,
+				addressId:null,
+				isDefault: false,
+				addressList:[[],[],[]],
+				multiIndex:[0,0,0],
+				address:[],
+				form: {
+					realName:null,
+					phone:null,
+					detail:null,
+					address: null,
+					isDefault: 0,
+				}
+			}
+		},
+		onLoad(option) {
+			console.log("option",option)
+			this.type=option.type;
+			if(this.type=='edit'){
+				uni.setNavigationBarTitle({
+				  title:"修改收货地址"
+				})
+				this.addressId=option.addressId;
+				// this.getAddressById();
+			}
+			else{
+				uni.setNavigationBarTitle({
+				  title:"新增收货地址"
+				})
+			}
+			this.getCitys()
+		},
+		methods: {
+			// parseAddress(){
+			// 	if(this.content==null||this.content==""){
+			// 		uni.showToast({	icon:'none',title: '请输入地址信息'});
+			// 		return;
+			// 	}
+			// 	var data={content:this.content};
+			// 	parseAddress(data).then(
+			// 		res => {
+			// 			if(res.code==200){
+			// 				this.form.realName=res.data.name
+			// 				this.form.phone=res.data.mobile
+			// 				this.form.address=res.data.provinceName+res.data.cityName+res.data.expAreaName
+			// 				this.form.province=res.data.provinceName
+			// 				this.form.city=res.data.cityName
+			// 				this.form.district=res.data.expAreaName
+			// 				this.form.detail=res.data.streetName+res.data.address
+			// 			}else{
+			// 				uni.showToast({
+			// 					icon:'none',
+			// 					title: res.msg,
+			// 				});
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+			// getAddressById(){
+			// 	var data={id:this.id};
+			// 	getAddressById(data).then(
+			// 		res => {
+			// 			if(res.code==200){
+			// 				  this.form=res.data;
+			// 				  this.isDefault=this.form.isDefault==1?true:false;
+			// 				  this.form.address=this.form.province+this.form.city+this.form.district
+			// 			}else{
+			// 				uni.showToast({
+			// 					icon:'none',
+			// 					title: res.msg,
+			// 				});
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+			submit(){
+				if(this.type=="add"){
+					this.addAddress()
+				}
+				else if(this.type=="edit"){
+					this.editAddress()
+				}
+				
+			},
+			editAddress(){
+				this.form.isDefault=this.isDefault?1:0
+				editAddress(this.form).then(
+					res => {
+						if(res.code==200){
+							 uni.showToast({
+							 	icon:'success',
+							 	title: "操作成功",
+							 });
+							 setTimeout(function() {
+								 uni.$emit('refreshAddress');
+								 uni.navigateBack({
+									 delta: 1
+								 })
+							 }, 500);
+						}else{
+							uni.showToast({
+								icon:'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			addAddress(){
+				this.form.isDefault=this.isDefault?1:0
+				addAddress(this.form).then(
+					res => {
+						if(res.code==200){
+							 uni.showToast({
+							 	icon:'success',
+							 	title: "操作成功",
+							 });
+							 setTimeout(function() {
+								 uni.$emit('refreshAddress');
+								 uni.navigateBack({
+									 delta: 1
+								 })
+							 }, 500);
+						}else{
+							uni.showToast({
+								icon:'none',
+								title: res.msg,
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			// 地区选择
+			pickerChange(e) {
+				this.multiIndex = e.detail.value;
+				// 数组内的下标
+				// 获取一级类目
+				// 获取二级类目
+				// 获取三级类目
+				this.form.address=this.addressList[0][this.multiIndex[0]].n+this.addressList[1][this.multiIndex[1]].n+this.addressList[2][this.multiIndex[2]].n
+				this.form.province=this.addressList[0][this.multiIndex[0]].n
+				this.form.city=this.addressList[1][this.multiIndex[1]].n
+				this.form.district=this.addressList[2][this.multiIndex[2]].n
+				this.form.cityId=this.addressList[1][this.multiIndex[1]].v;
+				
+				 
+			},
+			pickerColumnchange(e){
+				// 第一列滑动
+				if(e.detail.column === 0){
+					this.multiIndex[0] =  e.detail.value
+					// console.log('第一列滑动');
+					this.addressList[1] = this.address[this.multiIndex[0]].c;
+					this.addressList[2] = this.address[this.multiIndex[0]].c[0].c
+					// 第一列滑动  第二列 和第三列 都变为第一个
+					this.multiIndex.splice(1, 1, 0)
+					this.multiIndex.splice(2, 1, 0)
+				}
+				// 第二列滑动
+				if(e.detail.column === 1){
+					this.multiIndex[1] =  e.detail.value
+					// console.log('第二列滑动');
+					// console.log(this.multiIndex)
+					this.addressList[2] = this.address[this.multiIndex[0]].c[this.multiIndex[1]].c
+					// 第二列 滑动 第三列 变成第一个
+					this.multiIndex.splice(2, 1, 0)
+				}
+				// 第三列滑动
+				if(e.detail.column === 2){
+					this.multiIndex[2] =  e.detail.value
+				}
+			},
+			getCitys(){
+				getCitys().then(
+					res => {
+						if(res.code==200){
+							this.address=res.data
+							for(var i=0; i<this.address.length; i++){
+								this.addressList[0].push(this.address[i])
+							}
+							for(var i=0; i<this.address[0].c.length; i++){
+								this.addressList[1].push(this.address[0].c[i])
+							}
+							for(var i=0; i<this.address[0].c[0].c.length; i++){
+								this.addressList[2].push(this.address[0].c[0].c[i])
+							}
+						}else{
+							uni.showToast({
+								icon:'none',
+								title: "请求失败",
+							});
+						}
+					},
+					rej => {}
+				);
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page{
+		height: 100%;
+	}
+	.content{
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+		
+		.inner{
+			height: calc(100% - 120upx);
+			padding: 20upx;
+			.address-box{
+				padding: 30upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				margin-bottom: 20upx;
+				position: relative;
+				.textarea{
+					width: 100%;
+					height: 200upx;
+					font-size: 30upx;
+					color: #999999;
+					padding-bottom:100rpx;
+				}
+				.btns{
+					right:10rpx;
+					bottom:10rpx;
+					position: absolute;
+					.btn{
+						width: 155upx;
+						height: 64upx;
+						line-height: 64upx;
+						font-size: 26upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						text-align: center;
+						border-radius: 32upx;
+						&.parse{
+							background: #0bb3f2;
+							color: #FFFFFF;
+						}
+					}
+				}
+			}
+			.form-box{
+				padding: 0 30upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				.form-item{
+					padding: 30upx 0;
+					display: flex;
+					align-items: flex-start;
+					border-bottom: 1px solid #F1F1F1;
+					&:last-child{
+						border-bottom: none;
+					}
+					.label{
+						width: 180upx;
+						text-align: left;
+						font-size: 30upx;
+						line-height: 44upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #222222;
+						flex-shrink: 0;
+					}
+					input{
+						text-align: left;
+					}
+					.form-input{
+						font-size: 30upx;
+						font-family: PingFang SC;
+						font-weight: 500;
+						color: #999999;
+						text-align: left;
+					}
+					.form-textarea{
+						font-size: 30upx;
+						color: #999999;
+						height: 100upx;
+						padding: 4upx 0;
+					}
+					 
+					.birth-picker {
+						flex: 1;
+						display: flex;
+						align-items: center;
+						
+						.right-box{
+							width: 100%;
+							display: flex;
+							align-items: center;
+							.input-box{
+								width: 470upx;
+							}
+							.arrow{
+								width: 13upx;
+								height: 23upx;
+								margin-left: 20upx;
+							}
+						}
+					}
+				}
+			}
+			.setting-box{
+				height: 88upx;
+				background: #FFFFFF;
+				border-radius: 16upx;
+				margin-top: 20upx;
+				padding: 0 30upx;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				.label{
+					font-size: 28upx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #111111;
+				}
+			}
+		}
+		.btn-box{
+			height: 120upx;
+			padding: 0 30upx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			background: #FFFFFF;
+			.sub-btn{
+				width: 100%;
+				height: 88upx;
+				line-height: 88upx;
+				text-align: center;
+				font-size: 30upx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				background: #0bb3f2;
+				border-radius: 44upx;
+			}
+		}
+	}
+</style>

+ 322 - 0
pages_user/address.vue

@@ -0,0 +1,322 @@
+<template>
+	<view class="content">
+		<view class="inner">
+			<!-- <view class="top">
+				<view class="del" @click="delAllAddress">清空地址</view>
+			</view> -->
+			<view v-for="(item,index) in address" :key="index" class="address-item">
+				<view class="info" @click="selectAddress(item)">
+					<view class="title">
+						<view v-if="item.isDefault == 1" class="tag">默认</view>
+						{{item.province}}{{item.city}}{{item.district}}{{item.detail}}
+					</view>
+					<view class="name-phone">
+						<text class="text">{{item.realName}}</text>
+						<text class="text">{{$parsePhone(item.phone)}}</text>
+					</view>
+				</view>
+				<view class="operat-box">
+					<image src="/static/images/del1.png" mode="" @click="delAddress(item)"></image>
+					<image src="/static/images/edit.png" mode="" @click="editAddress(item)"></image>
+				</view>
+			</view>
+			<view v-if="address.length == 0" class="no-data-box" @click="getAddressList()">
+				<image src="/static/images/no_data.png" mode="aspectFit"></image>
+				<view class="empty-title">暂无数据</view>
+			</view>
+
+		</view>
+		<view class="btn-box">
+
+			<view class="sub-btn" @click="addAdress">新建收货地址</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		userAddr, // 获取用户收货地址
+		delAddress ,// 删除地址
+	} from "@/api/order.js"
+	// import {getAddressList,delAddress,delAllAddress} from '@/api/address'
+	export default {
+		data() {
+			return {
+				address: [],
+			}
+		},
+		onLoad() {
+				this.getUserAddr()
+			uni.$on('refreshAddress', () => {
+				this.getUserAddr()
+			})
+
+		},
+		// mounted() {
+		// 	this.getUserAddr()
+		// },
+		methods: {
+			// 获取用户收货地址
+			getUserAddr() {
+				this.userInfo = JSON.parse(uni.getStorageSync("userInfo"))
+				userAddr(this.userInfo.userId).then(res => {
+						if (res.code == 200) {
+							console.log("用户收货地址>>>>", res.data)
+							// this.userAddrLiat = res
+							this.address = res.data;
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+
+			// 选地址
+			selectAddress(item) {
+				uni.$emit('updateAddress', item);
+				uni.navigateBack({
+					delta: 1
+				});
+			},
+			// 编辑地址
+			editAddress(item) {
+				uni.navigateTo({
+					url: './addAddress?type=edit&addressId=' + item.addressId
+				})
+			},
+			// 删除所有地址(暂无)
+			// delAllAddress(item) {
+			// 	uni.showModal({
+			// 		title: "提示",
+			// 		content: "确认删除所有地址吗?",
+			// 		showCancel: true,
+			// 		cancelText: '取消',
+			// 		confirmText: '确定',
+			// 		success: res => {
+			// 			if (res.confirm) {
+			// 				var data = {}
+			// 				delAllAddress(data).then(
+			// 					res => {
+			// 						if (res.code == 200) {
+			// 							uni.showToast({
+			// 								icon: 'success',
+			// 								title: "操作成功",
+			// 							});
+			// 							this.getAddressList()
+			// 						} else {
+			// 							uni.showToast({
+			// 								icon: 'none',
+			// 								title: "请求失败",
+			// 							});
+			// 						}
+			// 					},
+			// 					rej => {}
+			// 				);
+
+			// 			} else {
+			// 				// 否则点击了取消  
+			// 			}
+			// 		}
+			// 	})
+			// },
+
+			// 删除地址
+			delAddress(item) {
+				uni.showModal({
+					title: "提示",
+					content: "确认删除此地址吗?",
+					showCancel: true,
+					cancelText: '取消',
+					confirmText: '确定',
+					success: res => {
+						if (res.confirm) {
+							// 用户点击确定
+							var data = {
+								addressId: item.addressId
+							}
+							delAddress(data).then(
+								res => {
+									if (res.code == 200) {
+										uni.showToast({
+											icon: 'success',
+											title: "操作成功",
+										});
+										this.getUserAddr()
+									} else {
+										uni.showToast({
+											icon: 'none',
+											title: "请求失败",
+										});
+									}
+								},
+								rej => {}
+							);
+
+						} else {
+							// 否则点击了取消  
+						}
+					}
+				})
+			},
+			// getAddressList(){
+			// 	uni.showLoading({
+			// 		title:"正在加载中"
+			// 	})
+			// 	getAddressList().then(
+			// 		res => {
+			// 			uni.hideLoading()
+			// 			if(res.code==200){
+			// 				this.address=res.data;
+			// 			}else{
+			// 				uni.showToast({
+			// 					icon:'none',
+			// 					title: "请求失败",
+			// 				});
+			// 			}
+			// 		},
+			// 		rej => {}
+			// 	);
+			// },
+			// 新建收货地址
+			addAdress() {
+				uni.navigateTo({
+					url: './addAddress?type=add'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page {
+		height: 100%;
+	}
+
+	.content {
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+
+		.inner {
+			flex: 1;
+			padding: 20upx 20upx 160upx;
+
+			.top {
+				padding: 0upx 20upx 20upx;
+				text-align: right;
+
+				.del {
+					font-size: 28upx;
+					font-family: PingFang SC;
+					color: #999999;
+				}
+			}
+
+			.address-item {
+				background: #FFFFFF;
+				border-radius: 16upx;
+				padding: 46upx 40upx 50upx 24upx;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				margin-bottom: 20upx;
+
+				.info {
+					width: 75%;
+
+					.title {
+						font-size: 30upx;
+						font-family: PingFang SC;
+						font-weight: bold;
+						color: #111111;
+						line-height: 42upx;
+						word-break: break-all;
+
+						.tag {
+							padding: 0 6upx;
+							height: 32upx;
+							line-height: 32upx;
+							font-size: 22upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #FFFFFF;
+							background: #0bb3f2;
+							border-radius: 4upx;
+							float: left;
+							margin-right: 10upx;
+							margin-top: 5upx;
+						}
+					}
+
+					.name-phone {
+						margin-top: 30upx;
+						display: flex;
+						align-items: center;
+
+						.text {
+							font-size: 26upx;
+							font-family: PingFang SC;
+							font-weight: 500;
+							color: #999999;
+							margin-right: 22upx;
+
+							&:last-child {
+								margin-right: 0;
+							}
+						}
+					}
+				}
+
+				.operat-box {
+					display: flex;
+					align-items: center;
+
+					image {
+						width: 30upx;
+						height: 30upx;
+						margin-left: 38upx;
+
+						&:first-child {
+							margin-left: 0;
+						}
+					}
+				}
+			}
+		}
+
+		.no-data-box {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+		}
+
+		.btn-box {
+			z-index: 9999;
+			width: 100%;
+			padding: 30upx;
+			position: fixed;
+			bottom: 0;
+			left: 0;
+			box-sizing: border-box;
+			background: #FFFFFF;
+
+			.sub-btn {
+
+				height: 88upx;
+				line-height: 88upx;
+				text-align: center;
+				font-size: 30upx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				background: #0bb3f2;
+				border-radius: 44upx;
+			}
+		}
+	}
+</style>

BIN
static/images/account.png


BIN
static/images/add.png


BIN
static/images/add26.png


BIN
static/images/arrow4.png


BIN
static/images/arrow_gray.png


BIN
static/images/back_white.png


BIN
static/images/chu_query.png


BIN
static/images/coupon1.png


BIN
static/images/coupon2.png


BIN
static/images/del1.png


BIN
static/images/edit.png


BIN
static/images/googs1.png


BIN
static/images/googs2.png


BIN
static/images/googs3.png


BIN
static/images/googs_service.png


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません