Prechádzať zdrojové kódy

Merge branch 'develop' of chelingzhu-web/zxyj-mini-html into master

lilei 4 rokov pred
rodič
commit
f41eee9bf0
100 zmenil súbory, kde vykonal 9784 pridanie a 1920 odobranie
  1. 9 32
      App.vue
  2. 10 0
      api/banner.js
  3. 29 0
      api/data.js
  4. 10 0
      api/deliveryRecord.js
  5. 27 0
      api/goods.js
  6. 1 3
      api/login.js
  7. 64 9
      api/order.js
  8. 35 0
      api/receiveAddress.js
  9. 36 0
      api/shoppingCart.js
  10. 24 0
      api/station.js
  11. 60 0
      api/user.js
  12. 442 0
      components/address.vue
  13. 157 0
      components/drag-button/drag-button.vue
  14. 645 0
      components/jyf-parser/jyf-parser.vue
  15. 100 0
      components/jyf-parser/libs/CssHandler.js
  16. 580 0
      components/jyf-parser/libs/MpHtmlParser.js
  17. 80 0
      components/jyf-parser/libs/config.js
  18. 22 0
      components/jyf-parser/libs/handler.wxs
  19. 505 0
      components/jyf-parser/libs/trees.vue
  20. 74 0
      components/uni-cart-fix/uni-cart-fix.vue
  21. 182 0
      components/uni-coods/uni-coods.vue
  22. 0 224
      components/uni-nav-bar/uni-nav-bar.vue
  23. 178 0
      components/uni-numbers-box/uni-numbers-box.vue
  24. 122 0
      components/uni-popup/image-txt-popup.vue
  25. 96 0
      components/uni-popup/popup-con.vue
  26. 1 0
      components/uni-popup/uni-popup.vue
  27. 0 25
      components/uni-status-bar/uni-status-bar.vue
  28. 0 243
      components/uni-steps/uni-steps.vue
  29. 10 31
      libs/axios.js
  30. 85 0
      libs/getDate.js
  31. 14 0
      libs/tools.js
  32. 5 0
      libs/validate.js
  33. 1 11
      main.js
  34. 3 3
      manifest.json
  35. 22 4
      package-lock.json
  36. 3 1
      package.json
  37. 188 18
      pages.json
  38. 83 295
      pages/agreement/agreement.vue
  39. 623 0
      pages/cart/cart.vue
  40. 84 0
      pages/checkOut/checkFinish.vue
  41. 274 0
      pages/checkOut/checkOut.vue
  42. 0 665
      pages/getOrder/getOrder.vue
  43. 116 0
      pages/goods/goods.vue
  44. 279 0
      pages/goods/goodsDetail.vue
  45. 155 0
      pages/goods/index.vue
  46. 361 26
      pages/index/index.vue
  47. 85 0
      pages/login/login.scss
  48. 75 49
      pages/login/login.vue
  49. 186 0
      pages/login/phoneLogin.vue
  50. 292 0
      pages/order/LogList.vue
  51. 571 129
      pages/order/order.vue
  52. 357 114
      pages/order/orderDetail.vue
  53. 231 0
      pages/store/store.vue
  54. 157 0
      pages/toOrder/editAddress.vue
  55. 465 0
      pages/toOrder/index.vue
  56. 75 0
      pages/toOrder/payFinish.vue
  57. 62 0
      pages/userCenter/aboutUs.vue
  58. 155 0
      pages/userCenter/deliveryRecord.vue
  59. 35 0
      pages/userCenter/fenlei.vue
  60. 119 38
      pages/userCenter/index.vue
  61. 229 0
      pages/userCenter/ldDetailed.vue
  62. 58 0
      pages/userCenter/myCode/myCode.vue
  63. 61 0
      pages/userCenter/question.vue
  64. 101 0
      pages/userCenter/userInfo/changePayPwd.vue
  65. 173 0
      pages/userCenter/userInfo/paymentPwd.vue
  66. 210 0
      pages/userCenter/userInfo/smsVerification.vue
  67. 132 0
      pages/userCenter/userInfo/userInfo.vue
  68. 160 0
      pages/userCenter/zhinan.vue
  69. BIN
      static/CLOTHES.png
  70. BIN
      static/GLASS.png
  71. BIN
      static/HARM.png
  72. BIN
      static/METAL.png
  73. BIN
      static/MET_PLA.png
  74. BIN
      static/PAPER.png
  75. BIN
      static/PLASTIC.png
  76. BIN
      static/RECYCLING.png
  77. BIN
      static/add-cart.png
  78. BIN
      static/addCart.png
  79. BIN
      static/bued.png
  80. BIN
      static/cart.png
  81. BIN
      static/checked.png
  82. BIN
      static/dz-icon.png
  83. BIN
      static/edit.png
  84. BIN
      static/full-bg.png
  85. BIN
      static/hexiao.png
  86. BIN
      static/imgError.png
  87. BIN
      static/ledou.png
  88. BIN
      static/liucheng.png
  89. BIN
      static/loading.gif
  90. BIN
      static/logo.png
  91. BIN
      static/md-big-pic.png
  92. BIN
      static/md-icon.png
  93. BIN
      static/position.png
  94. BIN
      static/shouyi.png
  95. BIN
      static/store.png
  96. BIN
      static/t1.png
  97. BIN
      static/tabbar/home-active.png
  98. BIN
      static/tabbar/home.png
  99. BIN
      static/tabbar/shop-active.png
  100. BIN
      static/tabbar/shop.png

+ 9 - 32
App.vue

@@ -1,13 +1,17 @@
 <script>
-	const uat_URL = 'https://carwash.test.zyucgj.com/cw-wechat/' // 预发布
-	// const uat_URL = 'http://192.168.16.103:8103/cw-wechat/' // 本地
-	const pro_URL = 'https://carwash.zyucgj.com/cw-wechat/'  // 生产
-	const buildType = 0 // 打包环境对应类型,1 生产 0 预发布
+	// const uat_domain = 'https://lese.test.sxzxyj.net' // 预发布
+	const uat_domain = 'http://192.168.16.102:8302' // 本地
+	const pro_domain = 'https://lese.sxzxyj.net' // 生产
+	const uat_URL = uat_domain+'/gc-shop/' // 预发布
+	const pro_URL = pro_domain+'/gc-shop/'  // 生产
+	const buildType = 1 // 打包环境对应类型,1 生产 0 预发布
 	const buildURL = buildType ? pro_URL : uat_URL // 打包后实际对应的url
 	const envText = ['预发布环境','生产环境']
 	const envTips = process.env.NODE_ENV == 'development' ? envText[0] : envText[buildType]
+	console.log(process.env.NODE_ENV)
 	export default {
 		globalData: {  
+			baseDomain: process.env.NODE_ENV == 'development' ? uat_domain : pro_domain,
 			baseUrl: process.env.NODE_ENV == 'development' ? uat_URL : buildURL,
 			token: '',
 			version: '', // 当前版本号
@@ -41,36 +45,9 @@
 	page {
 		min-height: 100%;
 		display: flex;
-		background: #fff;
+		background-color: #F8F8F8;
 	}
-	
-	/* #ifdef MP-BAIDU */
-	page {
-		width: 100%;
-		height: 100%;
-		display: block;
-	}
-	/* #endif */
-	
-	/* #ifdef MP-ALIPAY */
-	page {
-		min-height: 100vh;
-	}
-	
-	/* #endif */
-	
-	/* 原生组件模式下需要注意组件外部样式 */
-	m-input {
-		width: 100%;
-		min-height: 100%;
-		display: flex;
-	}
-	
 	.content {
-		display: flex;
-		flex: 1;
-		flex-direction: column;
-		background-color: #fff;
 		padding: 20upx;
 	}
 </style>

+ 10 - 0
api/banner.js

@@ -0,0 +1,10 @@
+import axios from '@/libs/axios.js';
+
+// 轮播图
+export const bannerList = params => {
+  return axios.request({
+    url: `advert/findByType/${params.type}/${params.location}`,
+    method: 'get',
+	data: {}
+  })
+};

+ 29 - 0
api/data.js

@@ -5,4 +5,33 @@ export const getLookUpDatas = (params) => {
     url: `lookup/findByLookup/${params.type}`,
     method: 'get'
   })
+}
+// 开箱操作
+export const openDevice = (params) => {
+  return axios.request({
+    url: `device/ctl/open`,
+    method: 'post',
+	data: params
+  })
+}
+//查询省
+export const  getProvince = () => {
+  return axios.request({
+    url: `area/PROVINCE`,
+    method: 'get'
+  })
+}
+//查询市
+export const  getCityByPro = params => {
+  return axios.request({
+    url: `area/CITY/${params.id}`,
+    method: 'get'
+  })
+}
+//查询区
+export const  getDistrictByCity = params => {
+  return axios.request({
+    url: `area/DISTRICT/${params.id}`,
+    method: 'get'
+  })
 }

+ 10 - 0
api/deliveryRecord.js

@@ -0,0 +1,10 @@
+import axios from '@/libs/axios.js';
+
+// 列表
+export const getDeliveryLogList = params => {
+  return axios.request({
+    url: `deliveryLog/query/${params.pageNo}/${params.pageSize}`,
+    method: 'post',
+	data: params
+  })
+};

+ 27 - 0
api/goods.js

@@ -0,0 +1,27 @@
+import axios from '@/libs/axios.js';
+
+// 获取商品分类
+export const getGoodsClass = params => {
+  return axios.request({
+    url: `goodsType/queryList`,
+    method: 'post',
+	data: params
+  })
+};
+
+// 获取商品列表
+export const getGoodsList = params => {
+  return axios.request({
+    url: `goods/query/${params.pageNo}/${params.pageSize}`,
+    method: 'post',
+	data: params
+  })
+};
+
+// 获取商品详情
+export const getGoodsDetail = params => {
+  return axios.request({
+    url: `goods/findById/${params.id}`,
+    method: 'get',
+  })
+};

+ 1 - 3
api/login.js

@@ -4,7 +4,6 @@ export const login = params => {
   return axios.request({
     url: `login`,
     method: 'post',
-	header: { 'Content-Type': 'application/x-www-form-urlencoded' },
 	data: params
   },true)
 };
@@ -37,8 +36,7 @@ export const checkLogin = () => {
 // 获取登录用户信息
 export const getUserInfo = params => {
   return axios.request({
-    url: `customer/getDetail`,
-    data: params,
+    url: `customer/detail`,
     method: 'get'
   })
 };

+ 64 - 9
api/order.js

@@ -7,11 +7,51 @@ export const getStoreItems = params => {
     method: 'get',
   })
 };
+// 查看用户是否设置过支付密码
+export const existPayPwd = params => {
+  return axios.request({
+    url: `customer/existPayPwd`,
+    method: 'get',
+  })
+};
+// 校验短信验证码是否正确
+export const checkCode = params => {
+  return axios.request({
+    url: `customer/checkVerificationCode`,
+	data: params,
+    method: 'post',
+  })
+};
+// 设置支付密码
+export const setPayPwd = params => {
+  return axios.request({
+    url: `customer/setPayPassword`,
+	data: params,
+    method: 'post',
+  })
+};
+// 校验原密码是否正确
+export const checkPayPwd = params => {
+  return axios.request({
+    url: `customer/checkPayPwd`,
+	data: params,
+    method: 'post',
+  })
+};
+
+// 修改支付密码
+export const changePayPwd = params => {
+  return axios.request({
+    url: `customer/updatePayPwd`,
+	data: params,
+    method: 'post',
+  })
+};
 
 // 下单 保存订单
 export const saveOrder = params => {
   return axios.request({
-    url: `order/save`,
+    url: `order/addOrder`,
     method: 'post',
 	data: params
   })
@@ -20,14 +60,15 @@ export const saveOrder = params => {
 // 下单 预支付
 export const signPay  = params => {
   return axios.request({
-    url: `order/pay?orderId=${params.orderId}`,
-    method: 'get',
+    url: `order/payOrder`,
+    method: 'post',
+    data: params
   })
 };
 
 // 我的订单
 export const getOrderList = params => {
-	let url = `order/query/${params.pageNo}/${params.pageSize}`
+	let url = `order/queryPage/${params.pageNo}/${params.pageSize}`
 	delete params.pageNo
 	delete params.pageSize
 	return axios.request({
@@ -39,19 +80,33 @@ export const getOrderList = params => {
 // 订单详情
 export const orderDetail = params => {
   return axios.request({
-    url: `order/find/${params.id}`,
+    url: `order/findById/${params.id}`,
     method: 'get',
   })
 };
 
-// 查询当前是否有未完成的订单
-export const getUnFinishedOrder = params => {
+// 查询物流
+export const queryOrderExpress = params => {
 	return axios.request({
-	  url: `order/unFinishedOrderRunStatus`,
+	  url: `orderExpress/findByOrderNo/${params.orderSn}`,
+	  method: 'get',
+	})
+}
+// 确认收货
+export const finishOrder = params => {
+	return axios.request({
+	  url: `orderExpress/finishOrderExpress`,
+	  method: 'post',
+	  data: params
+	})
+}
+// 查物流下商品信息
+export const queryOrderGoods = params => {
+	return axios.request({
+	  url: `orderGoods/findByExpressNo/${params.id}`,
 	  method: 'get',
 	})
 }
-
 // 取消订单
 export const cancleOrder = params => {
 	return axios.request({

+ 35 - 0
api/receiveAddress.js

@@ -0,0 +1,35 @@
+import axios from '@/libs/axios.js';
+
+// 根据客户编号查找收货地址
+export const findAddressBycustomerNo = params => {
+  return axios.request({
+    url: `receiveaddress/findBycustomerNo`,
+    method: 'get'
+  })
+};
+
+// 收货地址删除
+export const deleteAddress = params => {
+  return axios.request({
+    url: `receiveaddress/delete/${params.id}`,
+    method: 'get'
+  })
+};
+
+// 收货地址列表查询(不分页)
+export const getAddressList = params => {
+  return axios.request({
+    url: `receiveaddress/querylist`,
+    method: 'post',
+	data: params
+  })
+};
+
+// 收货地址保存
+export const saveAddress = params => {
+  return axios.request({
+    url: `receiveaddress/save`,
+    method: 'post',
+	data: params
+  })
+};

+ 36 - 0
api/shoppingCart.js

@@ -0,0 +1,36 @@
+import axios from '@/libs/axios.js';
+
+// 添加商品到购物车
+export const addGoodsToCart = params => {
+  return axios.request({
+    url: `shoppingCart/addGoods`,
+    method: 'post',
+	data: params
+  })
+};
+
+// 从购物车删除商品
+export const deleteGoodsFormCart = params => {
+  return axios.request({
+    url: `shoppingCart/deleteGoods`,
+    method: 'post',
+	data: params
+  })
+};
+
+// 查询购物车列表
+export const getCartList = params => {
+  return axios.request({
+    url: `shoppingCart/queryList`,
+    method: 'post',
+	data: params
+  })
+};
+
+// 更新商品购买数量
+export const updateGoodsBuyQty = params => {
+  return axios.request({
+    url: `shoppingCart/updateGoodsBuyQty/${params.id}/${params.buyQty}`,
+    method: 'get'
+  })
+};

+ 24 - 0
api/station.js

@@ -0,0 +1,24 @@
+import axios from '@/libs/axios.js';
+
+// 获取首页网点列表
+export const stationList = params => {
+  return axios.request({
+    url: `station/query`,
+    method: 'post',
+	data: params
+  })
+}
+// 网点详情
+export const stationDetail = params => {
+  return axios.request({
+    url: `station/findById/${params.id}`,
+    method: 'get'
+  })
+}
+// 查询网点的设备列表
+export const stationDevice = params => {
+  return axios.request({
+    url: `device/findById/${params.stationNo}`,
+    method: 'get'
+  })
+}

+ 60 - 0
api/user.js

@@ -0,0 +1,60 @@
+import axios from '@/libs/axios.js'
+ 
+// 获取图片验证码
+export const getCaptcha = randomCode => {
+  return axios.request({
+    url: `captcha/create/${randomCode}`,
+    method: 'get',
+    responseType: 'blob',
+  }, true)
+}
+// 发送短信验证码
+export const sendVerifyCode = params => {
+  return axios.request({
+    url: 'sendVerifiCode',
+    method: 'post',
+    data: params
+  }, true)
+}
+export const loginPhone = params => {
+  return axios.request({
+    url: `loginPhone`,
+    method: 'post',
+	data: params
+  },true)
+};
+// 乐豆使用明细
+export const ldUsedQuery = params => { 
+  let url = `customerGoldLog/queryByMonth`
+  return axios.request({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+
+// 核销
+export const sellerReceive = params => { 
+  let url = `seller/receive`
+  return axios.request({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+// 查询销售商信息
+export const sellerFindByPartnerNo = params => { 
+  let url = `seller/findByPartnerNo?encryptedPartnerNo=${params.officialPartnerNo}`
+  return axios.request({
+    url: url,
+    method: 'get'
+  })
+}
+// 手机号登录 校验用户账号状态
+export const checkCustomerState = params => { 
+  let url = `checkCustomerState/${params.phone}`
+  return axios.request({
+    url: url,
+    method: 'get'
+  })
+}

+ 442 - 0
components/address.vue

@@ -0,0 +1,442 @@
+<template>
+	<view class="simple-address" v-if="showPopup">
+		<!-- 遮罩层 -->
+		<view
+			class="simple-address-mask"
+			v-if="maskClick"
+			:class="[ani + '-mask', animation ? 'mask-ani' : '']"
+			:style="{
+				'background-color': maskBgColor
+			}"
+			@tap="hideMask(true)"
+		></view>
+		
+		<!-- 省市区 -->
+		<view class="simple-address-content simple-address--fixed" :class="[type, ani + '-content', animation ? 'content-ani' : '']">
+			<view class="simple-address__header">
+				<view class="simple-address__header-btn-box" @click="pickerCancel">
+					<text class="simple-address__header-text" :style="{ color: cancelColor, fontSize: btnFontSize }">取消</text>
+				</view>
+				<view class="simple-address__header-btn-box" @click="pickerConfirm">
+					<text class="simple-address__header-text" :style="{ color: confirmColor, fontSize: btnFontSize }">确定</text>
+				</view>
+			</view>
+			<view class="simple-address__box">
+				<picker-view indicator-style="height: 70rpx;" class="simple-address-view" :value="pickerValue" @change="pickerChange">
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+				</picker-view>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	import { getProvince, getCityByPro, getDistrictByCity } from '@/api/data.js'
+	export default{
+		name: 'Address',
+		props: {
+			// 是否允许点击遮罩层关闭
+			maskClick: {
+				type: Boolean,
+				default: true
+			},
+			// 是否开启动画
+			animation: {
+				type: Boolean,
+				default: true
+			},
+			//  遮罩层背景颜色
+			maskBgColor: {
+				type: String,
+				default: 'rgba(0, 0, 0, 0.4)' //背景颜色 rgba(0, 0, 0, 0.4) 为空则调用 uni.scss
+			},
+			/* 弹出层类型,可选值;  暂时只支持底部弹出
+					bottom:底部弹出层
+				*/
+			type: {
+				type: String,
+				default: 'bottom'
+			},
+			cancelColor: {
+				type: String,
+				default: '' // 取消按钮颜色
+			},
+			confirmColor: {
+				type: String,
+				default: '' // 确认按钮颜色
+			},
+			fontSize: {
+				type: String,
+				default: '28rpx' // picker-item字体大小
+			},
+			btnFontSize: {
+				type: String,
+				default: '' // 按钮的字体大小
+			},
+		},
+		data(){
+			return{
+				showPopup: false,  //  是否显示省市区选择
+				ani: '',
+				pickerValue: [0, 0, 0],  //  默认值下标
+				pickerId: [],  //  省市区默认值id
+				provinceDataList: [],  //  省数据列表
+				cityDataList: [],  //  市数据列表
+				areaDataList: [],  //  区数据列表
+				isFirst: false,  //  是否首次进入组件
+			}
+		},
+		methods: {
+			//  初始化
+			init(){
+				this.provinceDataList = []
+				this.cityDataList = []
+				this.areaDataList = []
+				this.isFirst = false
+			},
+			//  点击遮罩层关闭选择省市区
+			hideMask() {
+				this._$emit('onCancel')
+				this.close()
+			},
+			//  打开省市区picker
+			open(idArr) {
+				//  初始化数据
+				this.init()
+				this.pickerId = idArr
+				//  idArr 省市区默认id
+				if(this.pickerId && this.pickerId.length > 0){
+					//  获取省下拉
+					this.getProvinceList(idArr)
+				}else{
+					//  获取省下拉
+					this.getProvinceList()
+				}
+				this.showPopup = true
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.ani = 'simple-' + this.type
+					}, 100)
+				});
+			},
+			//  关闭省市区picker
+			close(type) {
+				if (!this.maskClick && type) return
+				this.ani = ''
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.showPopup = false
+					}, 300)
+				})
+			},
+			//  取消按钮
+			pickerCancel() {
+				this._$emit('onCancel')
+				this.close()
+			},
+			//  确定按钮
+			pickerConfirm() {
+				this._$emit('onConfirm')
+				if(!this.isFirst){
+					//  首次
+					this.isFirst = true
+				}
+				this.close()
+			},
+			//  省市区  change
+			pickerChange(e) {
+				const _this = this
+				let changePickerValue = e.detail.value
+				
+				if (this.pickerValue[0] !== changePickerValue[0]) {
+					if(this.pickerId && this.pickerId.length > 0 && this.isFirst){
+						//  获取市下拉
+						this.getCityList(this.pickerId[0], this.pickerId)
+					}else{
+						// 第一级发生滚动,省 change重置市区下拉数据
+						this.getCityList(this.provinceDataList[changePickerValue[0]].id)
+						changePickerValue[1] = 0
+						changePickerValue[2] = 0
+					}
+				} else if (this.pickerValue[1] !== changePickerValue[1]) {
+					if(this.pickerId && this.pickerId.length > 0 && this.isFirst){
+						//  获取市下拉
+						this.getAreaList(this.pickerId[1], this.pickerId)
+					}else{
+						// 第二级滚动,市 change重置区县下拉数据
+						this.getAreaList(this.cityDataList[changePickerValue[1]].id)
+						changePickerValue[2] = 0
+					}
+				}
+				this.pickerValue = changePickerValue
+				//  setTimeout解决由于省市区接口请求数据有延缓导致获值报错
+				setTimeout(()=>{
+					_this._$emit('onChange')
+				},1000)
+			},
+			_$emit(emitName) {
+				let pickObj = {
+					label: this._getLabel(),
+					value: this.pickerValue,
+					cityCode: this._getCityCode(),
+					areaCode: this._getAreaCode(),
+					provinceCode: this._getProvinceCode(),
+					labelArr: this._getLabel().split('-')
+				}
+				this.$emit(emitName, pickObj)
+			},
+			_getLabel() {
+				//  name报错未发现页面影响(由于省市区接口请求数据延缓)
+				let pcikerLabel =
+					this.provinceDataList[this.pickerValue[0]].name + '-' + this.cityDataList[this.pickerValue[1]].name + '-' + this.areaDataList[this.pickerValue[2]].name
+				return pcikerLabel
+			},
+			_getCityCode() {
+				return this.cityDataList[this.pickerValue[1]].id
+			},
+			_getProvinceCode() {
+				return this.provinceDataList[this.pickerValue[0]].id
+			},
+			_getAreaCode() {
+				return this.areaDataList[this.pickerValue[2]].id
+			},
+			//  获取省下拉数据
+			getProvinceList(idArr){
+				const _this = this
+				getProvince().then(res => {
+				  if (res.code == 200 || res.status == 204 || res.status == 200) {
+				    _this.provinceDataList = res.data || []  //  省下拉数据
+					//  判断是否有默认值
+					if(idArr){
+						_this.getCityList(idArr[0], idArr)
+						_this.getAreaIndArr(idArr)
+					}else{
+						//  默认省数据第一条下的市下拉数据
+						_this.getCityList(_this.provinceDataList[0].id)
+					}
+					
+				  } else {
+				    _this.provinceDataList = []
+				  }
+				})
+			},
+			// 获取城市列表
+			getCityList (val, idArr) {
+				const _this = this
+				_this.cityDataList = []
+				_this.areaDataList = []
+				if (val != null && val != '') {
+					getCityByPro({id: val}).then(res => {
+						if (res.code == 200 || res.status == 204 || res.status == 200) {
+							_this.cityDataList = res.data || []  //  市下拉数据
+							//  判断是否有默认值
+							if(idArr){
+								_this.getAreaList(idArr[1], idArr)
+								_this.getAreaIndArr(idArr)
+							}else{
+								//  默认市数据第一条下的区县下拉数据
+								_this.getAreaList(_this.cityDataList[0].id)
+							}
+						} else {
+							_this.cityDataList = []
+						}
+					})
+				}
+			},
+			// 获取区县列表
+			getAreaList (val, idArr) {
+				const _this = this
+				this.areaDataList = []
+				if (val != null && val != '') {
+					getDistrictByCity({id: val}).then(res => {
+						if (res.code == 200 || res.status == 204 || res.status == 200) {
+							_this.areaDataList = res.data || []
+							//  判断是否有默认值
+							if(idArr){ _this.getAreaIndArr(idArr) }
+						} else {
+							_this.areaDataList = []
+						}
+					})
+				}
+			},
+			//  根据id 获取省市区 下标值
+			getAreaIndArr(idArr){
+				const _this = this
+				const provinceInd = _this.provinceDataList.findIndex(res => res['id'] == idArr[0])
+				const cityInd = _this.cityDataList.findIndex(res => res['id'] == idArr[1])
+				const districtInd = _this.areaDataList.findIndex(res => res['id'] == idArr[2])
+				setTimeout(()=>{
+					_this.pickerValue = [provinceInd, cityInd, districtInd]
+				},100)
+				// console.log(_this.pickerValue,'_this.pickerValue')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+.simple-address {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: column;
+}
+
+.simple-address-mask {
+	position: fixed;
+	bottom: 0;
+	top: 0;
+	left: 0;
+	right: 0;
+
+	transition-property: opacity;
+	transition-duration: 0.3s;
+	opacity: 0;
+	/* #ifndef APP-NVUE */
+	z-index: 99;
+	/* #endif */
+}
+
+.mask-ani {
+	transition-property: opacity;
+	transition-duration: 0.2s;
+}
+
+.simple-bottom-mask {
+	opacity: 1;
+}
+
+.simple-center-mask {
+	opacity: 1;
+}
+
+.simple-address--fixed {
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	transition-property: transform;
+	transition-duration: 0.3s;
+	transform: translateY(460rpx);
+	/* #ifndef APP-NVUE */
+	z-index: 99;
+	/* #endif */
+}
+
+.simple-address-content {
+	background-color: #ffffff;
+}
+
+.simple-content-bottom {
+	bottom: 0;
+	left: 0;
+	right: 0;
+	transform: translateY(500rpx);
+}
+
+.content-ani {
+	transition-property: transform, opacity;
+	transition-duration: 0.2s;
+}
+
+.simple-bottom-content {
+	transform: translateY(0);
+}
+
+.simple-center-content {
+	transform: scale(1);
+	opacity: 1;
+}
+
+.simple-address__header {
+	position: relative;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	flex-wrap: nowrap;
+	justify-content: space-between;
+	border-bottom-color: #f2f2f2;
+	border-bottom-style: solid;
+	border-bottom-width: 1rpx;
+}
+
+.simple-address--fixed-top {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	justify-content: space-between;
+	border-top-color: $uni-border-color;
+	border-top-style: solid;
+	border-top-width: 1rpx;
+}
+
+.simple-address__header-btn-box {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	align-items: center;
+	justify-content: center;
+	height: 70rpx;
+}
+
+.simple-address__header-text {
+	text-align: center;
+	font-size: $uni-font-size-base;
+	color: #1aad19;
+	line-height: 70rpx;
+	padding-left: 40rpx;
+	padding-right: 40rpx;
+}
+
+.simple-address__box {
+	position: relative;
+}
+
+.simple-address-view {
+	position: relative;
+	bottom: 0;
+	left: 0;
+	/* #ifndef APP-NVUE */
+	width: 100%;
+	/* #endif */
+	/* #ifdef APP-NVUE */
+	width: 750rpx;
+	/* #endif */
+	height: 408rpx;
+	background-color: rgba(255, 255, 255, 1);
+}
+
+.picker-item {
+	text-align: center;
+	line-height: 70rpx;
+	text-overflow: ellipsis;
+	font-size: 28rpx;
+}
+</style>

+ 157 - 0
components/drag-button/drag-button.vue

@@ -0,0 +1,157 @@
+<template>
+	<view>
+		<view
+			id="_drag_button"
+			class="drag"
+			:style="'left: ' + left + 'px; top:' + top + 'px;'"
+			@touchstart="touchstart"
+			@touchmove.stop.prevent="touchmove"
+			@touchend="touchend"
+			@click.stop.prevent="click"
+			:class="{transition: isDock && !isMove }"
+		>
+			<!-- <text>{{ text }}</text> -->
+			<view>
+				<u-badge absolute :offset="[15,10]" type="error" :count="badge"></u-badge>
+				<u-image width="70rpx" height="70rpx" :src="dragPic"></u-image>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'drag-button',
+		props: {
+			isDock:{  //  是否启用自动停靠
+				type: Boolean,
+				default: false
+			},
+			existTabBar:{  //  当前页面是否包含tabbar
+				type: Boolean,
+				default: false
+			},
+			dragPic: {  //  图标显示时,图标链接
+				type: String,
+				default: ''
+			},
+			badge: {  //  图标显示时,角标数字
+				type: [Number, String],
+				default: ''
+			}
+		},
+		data() {
+			return {
+				top:0,
+				left:0,
+				width: 0,
+				height: 0,
+				offsetWidth: 0,
+				offsetHeight: 0,
+				windowWidth: 0,
+				windowHeight: 0,
+				isMove: true,
+				edge: 10,
+				text: '按钮'
+			}
+		},
+		mounted() {
+			const sys = uni.getSystemInfoSync();
+			
+			this.windowWidth = sys.windowWidth;
+			this.windowHeight = sys.windowHeight;
+			
+			// #ifdef APP-PLUS
+				this.existTabBar && (this.windowHeight -= 50);
+			// #endif
+			if (sys.windowTop) {
+				this.windowHeight += sys.windowTop;
+			}
+			console.log(sys)
+			
+			const query = uni.createSelectorQuery().in(this);
+			query.select('#_drag_button').boundingClientRect(data => {
+				// console.log(data,'--------data')
+				this.width = data.width;
+				this.height = data.height;
+				this.offsetWidth = data.width / 2;
+				this.offsetHeight = data.height / 2;
+				this.left = this.windowWidth - this.width - this.edge;
+				// this.top = this.windowHeight - this.height - this.edge;
+				this.top = this.windowHeight * 0.65;
+			}).exec();
+		},
+		methods: {
+			click() {
+				this.$emit('btnClick');
+			},
+			touchstart(e) {
+				this.$emit('btnTouchstart');
+			},
+			touchmove(e) {
+				// 单指触摸
+				if (e.touches.length !== 1) {
+					return false;
+				}
+				
+				this.isMove = true;
+				
+				this.left = e.touches[0].clientX - this.offsetWidth;
+				
+				let clientY = e.touches[0].clientY - this.offsetHeight;
+				// #ifdef H5
+					clientY += this.height;
+				// #endif
+				let edgeBottom = this.windowHeight - this.height - this.edge;
+
+				// 上下触及边界
+				if (clientY < this.edge) {
+					this.top = this.edge;
+				} else if (clientY > edgeBottom) {
+					this.top = edgeBottom;
+				} else {
+					this.top = clientY
+				}
+				
+			},
+			touchend(e) {
+				if (this.isDock) {
+					let edgeRigth = this.windowWidth - this.width - this.edge;
+					
+					if (this.left < this.windowWidth / 2 - this.offsetWidth) {
+						this.left = this.edge;
+					} else {
+						this.left = edgeRigth;
+					}
+					
+				}
+				
+				this.isMove = false;
+				
+				this.$emit('btnTouchend');
+			},
+		}}
+</script>
+
+<style lang="scss">
+	.drag {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		// background-color: rgba(0, 0, 0, 0.5);
+		background-color: #fff;
+		box-shadow: 0 0 6upx rgba(0, 0, 0, 0.4);
+		color: $uni-text-color-inverse;
+		width: 80upx;
+		height: 80upx;
+		border-radius: 50%;
+		font-size: $uni-font-size-sm;
+		position: fixed;
+		z-index: 999999;
+		
+		&.transition {
+			transition: left .3s ease,top .3s ease;
+		}
+	}
+	
+</style>

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

@@ -0,0 +1,645 @@
+<template>
+	<view>
+		<slot v-if="!nodes.length" />
+		<!--#ifdef APP-PLUS-NVUE-->
+		<web-view id="_top" ref="web" :style="'margin-top:-2px;height:'+height+'px'" @onPostMessage="_message" />
+		<!--#endif-->
+		<!--#ifndef APP-PLUS-NVUE-->
+		<view id="_top" :style="showAm+(selectable?';user-select:text;-webkit-user-select:text':'')">
+			<!--#ifdef H5 || MP-360-->
+			<div :id="'rtf'+uid"></div>
+			<!--#endif-->
+			<!--#ifndef H5 || MP-360-->
+			<trees :nodes="nodes" :lazyLoad="lazyLoad" :loading="loadingImg" />
+			<!--#endif-->
+		</view>
+		<!--#endif-->
+	</view>
+</template>
+
+<script>
+	var search;
+	// #ifndef H5 || APP-PLUS-NVUE || MP-360
+	import trees from './libs/trees';
+	var cache = {},
+		// #ifdef MP-WEIXIN || MP-TOUTIAO
+		fs = uni.getFileSystemManager ? uni.getFileSystemManager() : null,
+		// #endif
+		Parser = require('./libs/MpHtmlParser.js');
+	var dom;
+	// 计算 cache 的 key
+	function hash(str) {
+		for (var i = str.length, val = 5381; i--;)
+			val += (val << 5) + str.charCodeAt(i);
+		return val;
+	}
+	// #endif
+	// #ifdef H5 || APP-PLUS-NVUE || MP-360
+	var {
+		windowWidth,
+		platform
+	} = uni.getSystemInfoSync(),
+		cfg = require('./libs/config.js');
+	// #endif
+	// #ifdef APP-PLUS-NVUE
+	var weexDom = weex.requireModule('dom');
+	// #endif
+	/**
+	 * Parser 富文本组件
+	 * @tutorial https://github.com/jin-yufeng/Parser
+	 * @property {String} html 富文本数据
+	 * @property {Boolean} autopause 是否在播放一个视频时自动暂停其他视频
+	 * @property {Boolean} autoscroll 是否自动给所有表格添加一个滚动层
+	 * @property {Boolean} autosetTitle 是否自动将 title 标签中的内容设置到页面标题
+	 * @property {Number} compress 压缩等级
+	 * @property {String} domain 图片、视频等链接的主域名
+	 * @property {Boolean} lazyLoad 是否开启图片懒加载
+	 * @property {String} loadingImg 图片加载完成前的占位图
+	 * @property {Boolean} selectable 是否开启长按复制
+	 * @property {Object} tagStyle 标签的默认样式
+	 * @property {Boolean} showWithAnimation 是否使用渐显动画
+	 * @property {Boolean} useAnchor 是否使用锚点
+	 * @property {Boolean} useCache 是否缓存解析结果
+	 * @event {Function} parse 解析完成事件
+	 * @event {Function} load dom 加载完成事件
+	 * @event {Function} ready 所有图片加载完毕事件
+	 * @event {Function} error 错误事件
+	 * @event {Function} imgtap 图片点击事件
+	 * @event {Function} linkpress 链接点击事件
+	 * @author JinYufeng
+	 * @version 20201029
+	 * @listens MIT
+	 */
+	export default {
+		name: 'parser',
+		data() {
+			return {
+				// #ifdef H5 || MP-360
+				uid: this._uid,
+				// #endif
+				// #ifdef APP-PLUS-NVUE
+				height: 1,
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				showAm: '',
+				// #endif
+				nodes: []
+			}
+		},
+		// #ifndef H5 || APP-PLUS-NVUE || MP-360
+		components: {
+			trees
+		},
+		// #endif
+		props: {
+			html: String,
+			autopause: {
+				type: Boolean,
+				default: true
+			},
+			autoscroll: Boolean,
+			autosetTitle: {
+				type: Boolean,
+				default: true
+			},
+			// #ifndef H5 || APP-PLUS-NVUE || MP-360
+			compress: Number,
+			loadingImg: String,
+			useCache: Boolean,
+			// #endif
+			domain: String,
+			lazyLoad: Boolean,
+			selectable: Boolean,
+			tagStyle: Object,
+			showWithAnimation: Boolean,
+			useAnchor: Boolean
+		},
+		watch: {
+			html(html) {
+				this.setContent(html);
+			}
+		},
+		created() {
+			// 图片数组
+			this.imgList = [];
+			this.imgList.each = function(f) {
+				for (var i = 0, len = this.length; i < len; i++)
+					this.setItem(i, f(this[i], i, this));
+			}
+			this.imgList.setItem = function(i, src) {
+				if (i == void 0 || !src) return;
+				// #ifndef MP-ALIPAY || APP-PLUS
+				// 去重
+				if (src.indexOf('http') == 0 && this.includes(src)) {
+					var newSrc = src.split('://')[0];
+					for (var j = newSrc.length, c; c = src[j]; j++) {
+						if (c == '/' && src[j - 1] != '/' && src[j + 1] != '/') break;
+						newSrc += Math.random() > 0.5 ? c.toUpperCase() : c;
+					}
+					newSrc += src.substr(j);
+					return this[i] = newSrc;
+				}
+				// #endif
+				this[i] = src;
+				// 暂存 data src
+				if (src.includes('data:image')) {
+					var filePath, info = src.match(/data:image\/(\S+?);(\S+?),(.+)/);
+					if (!info) return;
+					// #ifdef MP-WEIXIN || MP-TOUTIAO
+					filePath = `${wx.env.USER_DATA_PATH}/${Date.now()}.${info[1]}`;
+					fs && fs.writeFile({
+						filePath,
+						data: info[3],
+						encoding: info[2],
+						success: () => this[i] = filePath
+					})
+					// #endif
+					// #ifdef APP-PLUS
+					filePath = `_doc/parser_tmp/${Date.now()}.${info[1]}`;
+					var bitmap = new plus.nativeObj.Bitmap();
+					bitmap.loadBase64Data(src, () => {
+						bitmap.save(filePath, {}, () => {
+							bitmap.clear()
+							this[i] = filePath;
+						})
+					})
+					// #endif
+				}
+			}
+		},
+		mounted() {
+			// #ifdef H5 || MP-360
+			this.document = document.getElementById('rtf' + this._uid);
+			// #endif
+			// #ifndef H5 || APP-PLUS-NVUE || MP-360
+			if (dom) this.document = new dom(this);
+			// #endif
+			if (search) this.search = args => search(this, args);
+			// #ifdef APP-PLUS-NVUE
+			this.document = this.$refs.web;
+			setTimeout(() => {
+				// #endif
+				if (this.html) this.setContent(this.html);
+				// #ifdef APP-PLUS-NVUE
+			}, 30)
+			// #endif
+		},
+		beforeDestroy() {
+			// #ifdef H5 || MP-360
+			if (this._observer) this._observer.disconnect();
+			// #endif
+			this.imgList.each(src => {
+				// #ifdef APP-PLUS
+				if (src && src.includes('_doc')) {
+					plus.io.resolveLocalFileSystemURL(src, entry => {
+						entry.remove();
+					});
+				}
+				// #endif
+				// #ifdef MP-WEIXIN || MP-TOUTIAO
+				if (src && src.includes(uni.env.USER_DATA_PATH))
+					fs && fs.unlink({
+						filePath: src
+					})
+				// #endif
+			})
+			clearInterval(this._timer);
+		},
+		methods: {
+			// 设置富文本内容
+			setContent(html, append) {
+				// #ifdef APP-PLUS-NVUE
+				if (!html)
+					return this.height = 1;
+				if (append)
+					this.$refs.web.evalJs("var b=document.createElement('div');b.innerHTML='" + html.replace(/'/g, "\\'") +
+						"';document.getElementById('parser').appendChild(b)");
+				else {
+					html =
+						'<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><style>html,body{width:100%;height:100%;overflow:hidden}body{margin:0}</style><base href="' +
+						this.domain + '"><div id="parser"' + (this.selectable ? '>' : ' style="user-select:none">') + this._handleHtml(html).replace(/\n/g, '\\n') +
+						'</div><script>"use strict";function e(e){if(window.__dcloud_weex_postMessage||window.__dcloud_weex_){var t={data:[e]};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(t):window.__dcloud_weex_.postMessage(JSON.stringify(t))}}document.body.onclick=function(){e({action:"click"})},' +
+						(this.showWithAnimation ? 'document.body.style.animation="_show .5s",' : '') +
+						'setTimeout(function(){e({action:"load",text:document.body.innerText,height:document.getElementById("parser").scrollHeight})},50);\x3c/script>';
+					if (platform == 'android') html = html.replace(/%/g, '%25');
+					this.$refs.web.evalJs("document.write('" + html.replace(/'/g, "\\'") + "');document.close()");
+				}
+				this.$refs.web.evalJs(
+					'var t=document.getElementsByTagName("title");t.length&&e({action:"getTitle",title:t[0].innerText});for(var o,n=document.getElementsByTagName("style"),r=1;o=n[r++];)o.innerHTML=o.innerHTML.replace(/body/g,"#parser");for(var a,c=document.getElementsByTagName("img"),s=[],i=0==c.length,d=0,l=0,g=0;a=c[l];l++)parseInt(a.style.width||a.getAttribute("width"))>' +
+					windowWidth + '&&(a.style.height="auto"),a.onload=function(){++d==c.length&&(i=!0)},a.onerror=function(){++d==c.length&&(i=!0),' + (cfg.errorImg ? 'this.src="' + cfg.errorImg + '",' : '') +
+					'e({action:"error",source:"img",target:this})},a.hasAttribute("ignore")||"A"==a.parentElement.nodeName||(a.i=g++,s.push(a.getAttribute("original-src")||a.src||a.getAttribute("data-src")),a.onclick=function(t){t.stopPropagation(),e({action:"preview",img:{i:this.i,src:this.src}})});e({action:"getImgList",imgList:s});for(var u,m=document.getElementsByTagName("a"),f=0;u=m[f];f++)u.onclick=function(m){m.stopPropagation();var t,o=this.getAttribute("href");if("#"==o[0]){var n=document.getElementById(o.substr(1));n&&(t=n.offsetTop)}return e({action:"linkpress",href:o,offset:t}),!1};for(var h,y=document.getElementsByTagName("video"),v=0;h=y[v];v++)h.style.maxWidth="100%",h.onerror=function(){e({action:"error",source:"video",target:this})}' +
+					(this.autopause ? ',h.onplay=function(){for(var e,t=0;e=y[t];t++)e!=this&&e.pause()}' : '') +
+					';for(var _,p=document.getElementsByTagName("audio"),w=0;_=p[w];w++)_.onerror=function(){e({action:"error",source:"audio",target:this})};' +
+					(this.autoscroll ? 'for(var T,E=document.getElementsByTagName("table"),B=0;T=E[B];B++){var N=document.createElement("div");N.style.overflow="scroll",T.parentNode.replaceChild(N,T),N.appendChild(T)}' : '') +
+					'var x=document.getElementById("parser");clearInterval(window.timer),window.timer=setInterval(function(){i&&clearInterval(window.timer),e({action:"ready",ready:i,height:x.scrollHeight})},350)'
+				)
+				this.nodes = [1];
+				// #endif
+				// #ifdef H5 || MP-360
+				if (!html) {
+					if (this.rtf && !append) this.rtf.parentNode.removeChild(this.rtf);
+					return;
+				}
+				var div = document.createElement('div');
+				if (!append) {
+					if (this.rtf) this.rtf.parentNode.removeChild(this.rtf);
+					this.rtf = div;
+				} else {
+					if (!this.rtf) this.rtf = div;
+					else this.rtf.appendChild(div);
+				}
+				div.innerHTML = this._handleHtml(html, append);
+				for (var styles = this.rtf.getElementsByTagName('style'), i = 0, style; style = styles[i++];) {
+					style.innerHTML = style.innerHTML.replace(/body/g, '#rtf' + this._uid);
+					style.setAttribute('scoped', 'true');
+				}
+				// 懒加载
+				if (!this._observer && this.lazyLoad && IntersectionObserver) {
+					this._observer = new IntersectionObserver(changes => {
+						for (let item, i = 0; item = changes[i++];) {
+							if (item.isIntersecting) {
+								item.target.src = item.target.getAttribute('data-src');
+								item.target.removeAttribute('data-src');
+								this._observer.unobserve(item.target);
+							}
+						}
+					}, {
+						rootMargin: '500px 0px 500px 0px'
+					})
+				}
+				var _ts = this;
+				// 获取标题
+				var title = this.rtf.getElementsByTagName('title');
+				if (title.length && this.autosetTitle)
+					uni.setNavigationBarTitle({
+						title: title[0].innerText
+					})
+				// 填充 domain
+				var fill = target => {
+					var src = target.getAttribute('src');
+					if (this.domain && src) {
+						if (src[0] == '/') {
+							if (src[1] == '/')
+								target.src = (this.domain.includes('://') ? this.domain.split('://')[0] : '') + ':' + src;
+							else target.src = this.domain + src;
+						} else if (!src.includes('://') && src.indexOf('data:') != 0) target.src = this.domain + '/' + src;
+					}
+				}
+				// 图片处理
+				this.imgList.length = 0;
+				var imgs = this.rtf.getElementsByTagName('img');
+				for (let i = 0, j = 0, img; img = imgs[i]; i++) {
+					if (parseInt(img.style.width || img.getAttribute('width')) > windowWidth)
+						img.style.height = 'auto';
+					fill(img);
+					if (!img.hasAttribute('ignore') && img.parentElement.nodeName != 'A') {
+						img.i = j++;
+						_ts.imgList.push(img.getAttribute('original-src') || img.src || img.getAttribute('data-src'));
+						img.onclick = function(e) {
+							e.stopPropagation();
+							var preview = true;
+							this.ignore = () => preview = false;
+							_ts.$emit('imgtap', this);
+							if (preview) {
+								uni.previewImage({
+									current: this.i,
+									urls: _ts.imgList
+								});
+							}
+						}
+					}
+					img.onerror = function() {
+						if (cfg.errorImg)
+							_ts.imgList[this.i] = this.src = cfg.errorImg;
+						_ts.$emit('error', {
+							source: 'img',
+							target: this
+						});
+					}
+					if (_ts.lazyLoad && this._observer && img.src && img.i != 0) {
+						img.setAttribute('data-src', img.src);
+						img.removeAttribute('src');
+						this._observer.observe(img);
+					}
+				}
+				// 链接处理
+				var links = this.rtf.getElementsByTagName('a');
+				for (var link of links) {
+					link.onclick = function(e) {
+						e.stopPropagation();
+						var jump = true,
+							href = this.getAttribute('href');
+						_ts.$emit('linkpress', {
+							href,
+							ignore: () => jump = false
+						});
+						if (jump && href) {
+							if (href[0] == '#') {
+								if (_ts.useAnchor) {
+									_ts.navigateTo({
+										id: href.substr(1)
+									})
+								}
+							} else if (href.indexOf('http') == 0 || href.indexOf('//') == 0)
+								return true;
+							else
+								uni.navigateTo({
+									url: href
+								})
+						}
+						return false;
+					}
+				}
+				// 视频处理
+				var videos = this.rtf.getElementsByTagName('video');
+				_ts.videoContexts = videos;
+				for (let video, i = 0; video = videos[i++];) {
+					fill(video);
+					video.style.maxWidth = '100%';
+					video.onerror = function() {
+						_ts.$emit('error', {
+							source: 'video',
+							target: this
+						});
+					}
+					video.onplay = function() {
+						if (_ts.autopause)
+							for (let item, i = 0; item = _ts.videoContexts[i++];)
+								if (item != this) item.pause();
+					}
+				}
+				// 音频处理
+				var audios = this.rtf.getElementsByTagName('audio');
+				for (var audio of audios) {
+					fill(audio);
+					audio.onerror = function() {
+						_ts.$emit('error', {
+							source: 'audio',
+							target: this
+						});
+					}
+				}
+				// 表格处理
+				if (this.autoscroll) {
+					var tables = this.rtf.getElementsByTagName('table');
+					for (var table of tables) {
+						let div = document.createElement('div');
+						div.style.overflow = 'scroll';
+						table.parentNode.replaceChild(div, table);
+						div.appendChild(table);
+					}
+				}
+				if (!append) this.document.appendChild(this.rtf);
+				this.$nextTick(() => {
+					this.nodes = [1];
+					this.$emit('load');
+				});
+				setTimeout(() => this.showAm = '', 500);
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				// #ifndef H5 || MP-360
+				var nodes;
+				if (!html) return this.nodes = [];
+				var parser = new Parser(html, this);
+				// 缓存读取
+				if (this.useCache) {
+					var hashVal = hash(html);
+					if (cache[hashVal])
+						nodes = cache[hashVal];
+					else {
+						nodes = parser.parse();
+						cache[hashVal] = nodes;
+					}
+				} else nodes = parser.parse();
+				this.$emit('parse', nodes);
+				if (append) this.nodes = this.nodes.concat(nodes);
+				else this.nodes = nodes;
+				if (nodes.length && nodes.title && this.autosetTitle)
+					uni.setNavigationBarTitle({
+						title: nodes.title
+					})
+				if (this.imgList) this.imgList.length = 0;
+				this.videoContexts = [];
+				this.$nextTick(() => {
+					(function f(cs) {
+						for (var i = cs.length; i--;) {
+							if (cs[i].top) {
+								cs[i].controls = [];
+								cs[i].init();
+								f(cs[i].$children);
+							}
+						}
+					})(this.$children)
+					this.$emit('load');
+				})
+				// #endif
+				var height;
+				clearInterval(this._timer);
+				this._timer = setInterval(() => {
+					// #ifdef H5 || MP-360
+					this.rect = this.rtf.getBoundingClientRect();
+					// #endif
+					// #ifndef H5 || MP-360
+					uni.createSelectorQuery().in(this)
+						.select('#_top').boundingClientRect().exec(res => {
+							if (!res) return;
+							this.rect = res[0];
+							// #endif
+							if (this.rect.height == height) {
+								this.$emit('ready', this.rect)
+								clearInterval(this._timer);
+							}
+							height = this.rect.height;
+							// #ifndef H5 || MP-360
+						});
+					// #endif
+				}, 350);
+				if (this.showWithAnimation && !append) this.showAm = 'animation:_show .5s';
+				// #endif
+			},
+			// 获取文本内容
+			getText(ns = this.nodes) {
+				var txt = '';
+				// #ifdef APP-PLUS-NVUE
+				txt = this._text;
+				// #endif
+				// #ifdef H5 || MP-360
+				txt = this.rtf.innerText;
+				// #endif
+				// #ifndef H5 || APP-PLUS-NVUE || MP-360
+				for (var i = 0, n; n = ns[i++];) {
+					if (n.type == 'text') txt += n.text.replace(/&nbsp;/g, '\u00A0').replace(/&lt;/g, '<').replace(/&gt;/g, '>')
+						.replace(/&amp;/g, '&');
+					else if (n.type == 'br') txt += '\n';
+					else {
+						// 块级标签前后加换行
+						var block = n.name == 'p' || n.name == 'div' || n.name == 'tr' || n.name == 'li' || (n.name[0] == 'h' && n.name[1] >
+							'0' && n.name[1] < '7');
+						if (block && txt && txt[txt.length - 1] != '\n') txt += '\n';
+						if (n.children) txt += this.getText(n.children);
+						if (block && txt[txt.length - 1] != '\n') txt += '\n';
+						else if (n.name == 'td' || n.name == 'th') txt += '\t';
+					}
+				}
+				// #endif
+				return txt;
+			},
+			// 锚点跳转
+			in (obj) {
+				if (obj.page && obj.selector && obj.scrollTop) this._in = obj;
+			},
+			navigateTo(obj) {
+				if (!this.useAnchor) return obj.fail && obj.fail('Anchor is disabled');
+				// #ifdef APP-PLUS-NVUE
+				if (!obj.id)
+					weexDom.scrollToElement(this.$refs.web);
+				else
+					this.$refs.web.evalJs('var pos=document.getElementById("' + obj.id +
+						'");if(pos)post({action:"linkpress",href:"#",offset:pos.offsetTop+' + (obj.offset || 0) + '})');
+				obj.success && obj.success();
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				var d = ' ';
+				// #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
+				d = '>>>';
+				// #endif
+				var selector = uni.createSelectorQuery().in(this._in ? this._in.page : this).select((this._in ? this._in.selector :
+					'#_top') + (obj.id ? `${d}#${obj.id},${this._in?this._in.selector:'#_top'}${d}.${obj.id}` : '')).boundingClientRect();
+				if (this._in) selector.select(this._in.selector).scrollOffset().select(this._in.selector).boundingClientRect();
+				else selector.selectViewport().scrollOffset();
+				selector.exec(res => {
+					if (!res[0]) return obj.fail && obj.fail('Label not found')
+					var scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + (obj.offset || 0);
+					if (this._in) this._in.page[this._in.scrollTop] = scrollTop;
+					else uni.pageScrollTo({
+						scrollTop,
+						duration: 300
+					})
+					obj.success && obj.success();
+				})
+				// #endif
+			},
+			// 获取视频对象
+			getVideoContext(id) {
+				// #ifndef APP-PLUS-NVUE
+				if (!id) return this.videoContexts;
+				else
+					for (var i = this.videoContexts.length; i--;)
+						if (this.videoContexts[i].id == id) return this.videoContexts[i];
+				// #endif
+			},
+			// #ifdef H5 || APP-PLUS-NVUE || MP-360
+			_handleHtml(html, append) {
+				if (!append) {
+					// 处理 tag-style 和 userAgentStyles
+					var style = '<style>@keyframes _show{0%{opacity:0}100%{opacity:1}}img{max-width:100%}';
+					for (var item in cfg.userAgentStyles)
+						style += `${item}{${cfg.userAgentStyles[item]}}`;
+					for (item in this.tagStyle)
+						style += `${item}{${this.tagStyle[item]}}`;
+					style += '</style>';
+					html = style + html;
+				}
+				// 处理 rpx
+				if (html.includes('rpx'))
+					html = html.replace(/[0-9.]+\s*rpx/g, $ => (parseFloat($) * windowWidth / 750) + 'px');
+				return html;
+			},
+			// #endif
+			// #ifdef APP-PLUS-NVUE
+			_message(e) {
+				// 接收 web-view 消息
+				var d = e.detail.data[0];
+				switch (d.action) {
+					case 'load':
+						this.$emit('load');
+						this.height = d.height;
+						this._text = d.text;
+						break;
+					case 'getTitle':
+						if (this.autosetTitle)
+							uni.setNavigationBarTitle({
+								title: d.title
+							})
+						break;
+					case 'getImgList':
+						this.imgList.length = 0;
+						for (var i = d.imgList.length; i--;)
+							this.imgList.setItem(i, d.imgList[i]);
+						break;
+					case 'preview':
+						var preview = true;
+						d.img.ignore = () => preview = false;
+						this.$emit('imgtap', d.img);
+						if (preview)
+							uni.previewImage({
+								current: d.img.i,
+								urls: this.imgList
+							})
+						break;
+					case 'linkpress':
+						var jump = true,
+							href = d.href;
+						this.$emit('linkpress', {
+							href,
+							ignore: () => jump = false
+						})
+						if (jump && href) {
+							if (href[0] == '#') {
+								if (this.useAnchor)
+									weexDom.scrollToElement(this.$refs.web, {
+										offset: d.offset
+									})
+							} else if (href.includes('://'))
+								plus.runtime.openWeb(href);
+							else
+								uni.navigateTo({
+									url: href
+								})
+						}
+						break;
+					case 'error':
+						if (d.source == 'img' && cfg.errorImg)
+							this.imgList.setItem(d.target.i, cfg.errorImg);
+						this.$emit('error', {
+							source: d.source,
+							target: d.target
+						})
+						break;
+					case 'ready':
+						this.height = d.height;
+						if (d.ready) uni.createSelectorQuery().in(this).select('#_top').boundingClientRect().exec(res => {
+							this.rect = res[0];
+							this.$emit('ready', res[0]);
+						})
+						break;
+					case 'click':
+						this.$emit('click');
+						this.$emit('tap');
+				}
+			},
+			// #endif
+		}
+	}
+</script>
+
+<style>
+	@keyframes _show {
+		0% {
+			opacity: 0;
+		}
+
+		100% {
+			opacity: 1;
+		}
+	}
+
+	/* #ifdef MP-WEIXIN */
+	:host {
+		display: block;
+		overflow: auto;
+		-webkit-overflow-scrolling: touch;
+	}
+
+	/* #endif */
+</style>

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

@@ -0,0 +1,100 @@
+const cfg = require('./config.js'),
+	isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+
+function CssHandler(tagStyle) {
+	var styles = Object.assign(Object.create(null), cfg.userAgentStyles);
+	for (var item in tagStyle)
+		styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item];
+	this.styles = styles;
+}
+CssHandler.prototype.getStyle = function(data) {
+	this.styles = new parser(data, this.styles).parse();
+}
+CssHandler.prototype.match = function(name, attrs) {
+	var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : '';
+	if (attrs.class) {
+		var items = attrs.class.split(' ');
+		for (var i = 0, item; item = items[i]; i++)
+			if (tmp = this.styles['.' + item])
+				matched += tmp + ';';
+	}
+	if (tmp = this.styles['#' + attrs.id])
+		matched += tmp + ';';
+	return matched;
+}
+module.exports = CssHandler;
+
+function parser(data, init) {
+	this.data = data;
+	this.floor = 0;
+	this.i = 0;
+	this.list = [];
+	this.res = init;
+	this.state = this.Space;
+}
+parser.prototype.parse = function() {
+	for (var c; c = this.data[this.i]; this.i++)
+		this.state(c);
+	return this.res;
+}
+parser.prototype.section = function() {
+	return this.data.substring(this.start, this.i);
+}
+// 状态机
+parser.prototype.Space = function(c) {
+	if (c == '.' || c == '#' || isLetter(c)) {
+		this.start = this.i;
+		this.state = this.Name;
+	} else if (c == '/' && this.data[this.i + 1] == '*')
+		this.Comment();
+	else if (!cfg.blankChar[c] && c != ';')
+		this.state = this.Ignore;
+}
+parser.prototype.Comment = function() {
+	this.i = this.data.indexOf('*/', this.i) + 1;
+	if (!this.i) this.i = this.data.length;
+	this.state = this.Space;
+}
+parser.prototype.Ignore = function(c) {
+	if (c == '{') this.floor++;
+	else if (c == '}' && !--this.floor) {
+		this.list = [];
+		this.state = this.Space;
+	}
+}
+parser.prototype.Name = function(c) {
+	if (cfg.blankChar[c]) {
+		this.list.push(this.section());
+		this.state = this.NameSpace;
+	} else if (c == '{') {
+		this.list.push(this.section());
+		this.Content();
+	} else if (c == ',') {
+		this.list.push(this.section());
+		this.Comma();
+	} else if (!isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_')
+		this.state = this.Ignore;
+}
+parser.prototype.NameSpace = function(c) {
+	if (c == '{') this.Content();
+	else if (c == ',') this.Comma();
+	else if (!cfg.blankChar[c]) this.state = this.Ignore;
+}
+parser.prototype.Comma = function() {
+	while (cfg.blankChar[this.data[++this.i]]);
+	if (this.data[this.i] == '{') this.Content();
+	else {
+		this.start = this.i--;
+		this.state = this.Name;
+	}
+}
+parser.prototype.Content = function() {
+	this.start = ++this.i;
+	if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length;
+	var content = this.section();
+	for (var i = 0, item; item = this.list[i++];)
+		if (this.res[item]) this.res[item] += ';' + content;
+		else this.res[item] = content;
+	this.list = [];
+	this.state = this.Space;
+}

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

@@ -0,0 +1,580 @@
+/**
+ * html 解析器
+ * @tutorial https://github.com/jin-yufeng/Parser
+ * @version 20201029
+ * @author JinYufeng
+ * @listens MIT
+ */
+const cfg = require('./config.js'),
+	blankChar = cfg.blankChar,
+	CssHandler = require('./CssHandler.js'),
+	windowWidth = uni.getSystemInfoSync().windowWidth;
+var emoji;
+
+function MpHtmlParser(data, options = {}) {
+	this.attrs = {};
+	this.CssHandler = new CssHandler(options.tagStyle, windowWidth);
+	this.data = data;
+	this.domain = options.domain;
+	this.DOM = [];
+	this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0;
+	options.prot = (this.domain || '').includes('://') ? this.domain.split('://')[0] : 'http';
+	this.options = options;
+	this.state = this.Text;
+	this.STACK = [];
+	// 工具函数
+	this.bubble = () => {
+		for (var i = this.STACK.length, item; item = this.STACK[--i];) {
+			if (cfg.richOnlyTags[item.name]) return false;
+			item.c = 1;
+		}
+		return true;
+	}
+	this.decode = (val, amp) => {
+		var i = -1,
+			j, en;
+		while (1) {
+			if ((i = val.indexOf('&', i + 1)) == -1) break;
+			if ((j = val.indexOf(';', i + 2)) == -1) break;
+			if (val[i + 1] == '#') {
+				en = parseInt((val[i + 2] == 'x' ? '0' : '') + val.substring(i + 2, j));
+				if (!isNaN(en)) val = val.substr(0, i) + String.fromCharCode(en) + val.substr(j + 1);
+			} else {
+				en = val.substring(i + 1, j);
+				if (cfg.entities[en] || en == amp)
+					val = val.substr(0, i) + (cfg.entities[en] || '&') + val.substr(j + 1);
+			}
+		}
+		return val;
+	}
+	this.getUrl = url => {
+		if (url[0] == '/') {
+			if (url[1] == '/') url = this.options.prot + ':' + url;
+			else if (this.domain) url = this.domain + url;
+		} else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://'))
+			url = this.domain + '/' + url;
+		return url;
+	}
+	this.isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>');
+	this.section = () => this.data.substring(this.start, this.i);
+	this.parent = () => this.STACK[this.STACK.length - 1];
+	this.siblings = () => this.STACK.length ? this.parent().children : this.DOM;
+}
+MpHtmlParser.prototype.parse = function() {
+	if (emoji) this.data = emoji.parseEmoji(this.data);
+	for (var c; c = this.data[this.i]; this.i++)
+		this.state(c);
+	if (this.state == this.Text) this.setText();
+	while (this.STACK.length) this.popNode(this.STACK.pop());
+	return this.DOM;
+}
+// 设置属性
+MpHtmlParser.prototype.setAttr = function() {
+	var name = this.attrName.toLowerCase(),
+		val = this.attrVal;
+	if (cfg.boolAttrs[name]) this.attrs[name] = 'T';
+	else if (val) {
+		if (name == 'src' || (name == 'data-src' && !this.attrs.src)) this.attrs.src = this.getUrl(this.decode(val, 'amp'));
+		else if (name == 'href' || name == 'style') this.attrs[name] = this.decode(val, 'amp');
+		else if (name.substr(0, 5) != 'data-') this.attrs[name] = val;
+	}
+	this.attrVal = '';
+	while (blankChar[this.data[this.i]]) this.i++;
+	if (this.isClose()) this.setNode();
+	else {
+		this.start = this.i;
+		this.state = this.AttrName;
+	}
+}
+// 设置文本节点
+MpHtmlParser.prototype.setText = function() {
+	var back, text = this.section();
+	if (!text) return;
+	text = (cfg.onText && cfg.onText(text, () => back = true)) || text;
+	if (back) {
+		this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i);
+		let j = this.start + text.length;
+		for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]);
+		return;
+	}
+	if (!this.pre) {
+		// 合并空白符
+		var flag, tmp = [];
+		for (let i = text.length, c; c = text[--i];)
+			if (!blankChar[c]) {
+				tmp.unshift(c);
+				if (!flag) flag = 1;
+			} else {
+				if (tmp[0] != ' ') tmp.unshift(' ');
+				if (c == '\n' && flag == void 0) flag = 0;
+			}
+		if (flag == 0) return;
+		text = tmp.join('');
+	}
+	this.siblings().push({
+		type: 'text',
+		text: this.decode(text)
+	});
+}
+// 设置元素节点
+MpHtmlParser.prototype.setNode = function() {
+	var node = {
+			name: this.tagName.toLowerCase(),
+			attrs: this.attrs
+		},
+		close = cfg.selfClosingTags[node.name];
+	if (this.options.nodes.length) node.type = 'node';
+	this.attrs = {};
+	if (!cfg.ignoreTags[node.name]) {
+		// 处理属性
+		var attrs = node.attrs,
+			style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''),
+			styleObj = {};
+		if (attrs.id) {
+			if (this.options.compress & 1) attrs.id = void 0;
+			else if (this.options.useAnchor) this.bubble();
+		}
+		if ((this.options.compress & 2) && attrs.class) attrs.class = void 0;
+		switch (node.name) {
+			case 'a':
+			case 'ad': // #ifdef APP-PLUS
+			case 'iframe':
+				// #endif
+				this.bubble();
+				break;
+			case 'font':
+				if (attrs.color) {
+					styleObj['color'] = attrs.color;
+					attrs.color = void 0;
+				}
+				if (attrs.face) {
+					styleObj['font-family'] = attrs.face;
+					attrs.face = void 0;
+				}
+				if (attrs.size) {
+					var size = parseInt(attrs.size);
+					if (size < 1) size = 1;
+					else if (size > 7) size = 7;
+					var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
+					styleObj['font-size'] = map[size - 1];
+					attrs.size = void 0;
+				}
+				break;
+			case 'embed':
+				// #ifndef APP-PLUS
+				var src = node.attrs.src || '',
+					type = node.attrs.type || '';
+				if (type.includes('video') || src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8'))
+					node.name = 'video';
+				else if (type.includes('audio') || src.includes('.m4a') || src.includes('.wav') || src.includes('.mp3') || src.includes(
+						'.aac'))
+					node.name = 'audio';
+				else break;
+				if (node.attrs.autostart)
+					node.attrs.autoplay = 'T';
+				node.attrs.controls = 'T';
+				// #endif
+				// #ifdef APP-PLUS
+				this.bubble();
+				break;
+				// #endif
+			case 'video':
+			case 'audio':
+				if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]);
+				else this[`${node.name}Num`]++;
+				if (node.name == 'video') {
+					if (this.videoNum > 3)
+						node.lazyLoad = 1;
+					if (attrs.width) {
+						styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px');
+						attrs.width = void 0;
+					}
+					if (attrs.height) {
+						styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px');
+						attrs.height = void 0;
+					}
+				}
+				if (!attrs.controls && !attrs.autoplay) attrs.controls = 'T';
+				attrs.source = [];
+				if (attrs.src) {
+					attrs.source.push(attrs.src);
+					attrs.src = void 0;
+				}
+				this.bubble();
+				break;
+			case 'td':
+			case 'th':
+				if (attrs.colspan || attrs.rowspan)
+					for (var k = this.STACK.length, item; item = this.STACK[--k];)
+						if (item.name == 'table') {
+							item.flag = 1;
+							break;
+						}
+		}
+		if (attrs.align) {
+			if (node.name == 'table') {
+				if (attrs.align == 'center') styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto';
+				else styleObj['float'] = attrs.align;
+			} else styleObj['text-align'] = attrs.align;
+			attrs.align = void 0;
+		}
+		// 压缩 style
+		var styles = style.split(';');
+		style = '';
+		for (var i = 0, len = styles.length; i < len; i++) {
+			var info = styles[i].split(':');
+			if (info.length < 2) continue;
+			let key = info[0].trim().toLowerCase(),
+				value = info.slice(1).join(':').trim();
+			if (value[0] == '-' || value.includes('safe'))
+				style += `;${key}:${value}`;
+			else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
+				styleObj[key] = value;
+		}
+		if (node.name == 'img') {
+			if (attrs.src && !attrs.ignore) {
+				if (this.bubble())
+					attrs.i = (this.imgNum++).toString();
+				else attrs.ignore = 'T';
+			}
+			if (attrs.ignore) {
+				style += ';-webkit-touch-callout:none';
+				styleObj['max-width'] = '100%';
+			}
+			var width;
+			if (styleObj.width) width = styleObj.width;
+			else if (attrs.width) width = attrs.width.includes('%') ? attrs.width : parseFloat(attrs.width) + 'px';
+			if (width) {
+				styleObj.width = width;
+				attrs.width = '100%';
+				if (parseInt(width) > windowWidth) {
+					styleObj.height = '';
+					if (attrs.height) attrs.height = void 0;
+				}
+			}
+			if (styleObj.height) {
+				attrs.height = styleObj.height;
+				styleObj.height = '';
+			} else if (attrs.height && !attrs.height.includes('%'))
+				attrs.height = parseFloat(attrs.height) + 'px';
+		}
+		for (var key in styleObj) {
+			var value = styleObj[key];
+			if (!value) continue;
+			if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1;
+			// 填充链接
+			if (value.includes('url')) {
+				var j = value.indexOf('(');
+				if (j++ != -1) {
+					while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++;
+					value = value.substr(0, j) + this.getUrl(value.substr(j));
+				}
+			}
+			// 转换 rpx
+			else if (value.includes('rpx'))
+				value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px');
+			else if (key == 'white-space' && value.includes('pre') && !close)
+				this.pre = node.pre = true;
+			style += `;${key}:${value}`;
+		}
+		style = style.substr(1);
+		if (style) attrs.style = style;
+		if (!close) {
+			node.children = [];
+			if (node.name == 'pre' && cfg.highlight) {
+				this.remove(node);
+				this.pre = node.pre = true;
+			}
+			this.siblings().push(node);
+			this.STACK.push(node);
+		} else if (!cfg.filter || cfg.filter(node, this) != false)
+			this.siblings().push(node);
+	} else {
+		if (!close) this.remove(node);
+		else if (node.name == 'source') {
+			var parent = this.parent();
+			if (parent && (parent.name == 'video' || parent.name == 'audio') && node.attrs.src)
+				parent.attrs.source.push(node.attrs.src);
+		} else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href;
+	}
+	if (this.data[this.i] == '/') this.i++;
+	this.start = this.i + 1;
+	this.state = this.Text;
+}
+// 移除标签
+MpHtmlParser.prototype.remove = function(node) {
+	var name = node.name,
+		j = this.i;
+	// 处理 svg
+	var handleSvg = () => {
+		var src = this.data.substring(j, this.i + 1);
+		node.attrs.xmlns = 'http://www.w3.org/2000/svg';
+		for (var key in node.attrs) {
+			if (key == 'viewbox') src = ` viewBox="${node.attrs.viewbox}"` + src;
+			else if (key != 'style') src = ` ${key}="${node.attrs[key]}"` + src;
+		}
+		src = '<svg' + src;
+		var parent = this.parent();
+		if (node.attrs.width == '100%' && parent && (parent.attrs.style || '').includes('inline'))
+			parent.attrs.style = 'width:300px;max-width:100%;' + parent.attrs.style;
+		this.siblings().push({
+			name: 'img',
+			attrs: {
+				src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
+				style: node.attrs.style,
+				ignore: 'T'
+			}
+		})
+	}
+	if (node.name == 'svg' && this.data[j] == '/') return handleSvg(this.i++);
+	while (1) {
+		if ((this.i = this.data.indexOf('</', this.i + 1)) == -1) {
+			if (name == 'pre' || name == 'svg') this.i = j;
+			else this.i = this.data.length;
+			return;
+		}
+		this.start = (this.i += 2);
+		while (!blankChar[this.data[this.i]] && !this.isClose()) this.i++;
+		if (this.section().toLowerCase() == name) {
+			// 代码块高亮
+			if (name == 'pre') {
+				this.data = this.data.substr(0, j + 1) + cfg.highlight(this.data.substring(j + 1, this.i - 5), node.attrs) + this.data
+					.substr(this.i - 5);
+				return this.i = j;
+			} else if (name == 'style')
+				this.CssHandler.getStyle(this.data.substring(j + 1, this.i - 7));
+			else if (name == 'title')
+				this.DOM.title = this.data.substring(j + 1, this.i - 7);
+			if ((this.i = this.data.indexOf('>', this.i)) == -1) this.i = this.data.length;
+			if (name == 'svg') handleSvg();
+			return;
+		}
+	}
+}
+// 节点出栈处理
+MpHtmlParser.prototype.popNode = function(node) {
+	// 空白符处理
+	if (node.pre) {
+		node.pre = this.pre = void 0;
+		for (let i = this.STACK.length; i--;)
+			if (this.STACK[i].pre)
+				this.pre = true;
+	}
+	var siblings = this.siblings(),
+		len = siblings.length,
+		childs = node.children;
+	if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false))
+		return siblings.pop();
+	var attrs = node.attrs;
+	// 替换一些标签名
+	if (cfg.blockTags[node.name]) node.name = 'div';
+	else if (!cfg.trustTags[node.name]) node.name = 'span';
+	// 处理列表
+	if (node.c && (node.name == 'ul' || node.name == 'ol')) {
+		if ((node.attrs.style || '').includes('list-style:none')) {
+			for (let i = 0, child; child = childs[i++];)
+				if (child.name == 'li')
+					child.name = 'div';
+		} else if (node.name == 'ul') {
+			var floor = 1;
+			for (let i = this.STACK.length; i--;)
+				if (this.STACK[i].name == 'ul') floor++;
+			if (floor != 1)
+				for (let i = childs.length; i--;)
+					childs[i].floor = floor;
+		} else {
+			for (let i = 0, num = 1, child; child = childs[i++];)
+				if (child.name == 'li') {
+					child.type = 'ol';
+					child.num = ((num, type) => {
+						if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26);
+						if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26);
+						if (type == 'i' || type == 'I') {
+							num = (num - 1) % 99 + 1;
+							var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
+								ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
+								res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || '');
+							if (type == 'i') return res.toLowerCase();
+							return res;
+						}
+						return num;
+					})(num++, attrs.type) + '.';
+				}
+		}
+	}
+	// 处理表格
+	if (node.name == 'table') {
+		var padding = parseFloat(attrs.cellpadding),
+			spacing = parseFloat(attrs.cellspacing),
+			border = parseFloat(attrs.border);
+		if (node.c) {
+			if (isNaN(padding)) padding = 2;
+			if (isNaN(spacing)) spacing = 2;
+		}
+		if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`;
+		if (node.flag && node.c) {
+			// 有 colspan 或 rowspan 且含有链接的表格转为 grid 布局实现
+			attrs.style = `${attrs.style || ''};${spacing ? `;grid-gap:${spacing}px` : ';border-left:0;border-top:0'}`;
+			var row = 1,
+				col = 1,
+				colNum,
+				trs = [],
+				children = [],
+				map = {};
+			(function f(ns) {
+				for (var i = 0; i < ns.length; i++) {
+					if (ns[i].name == 'tr') trs.push(ns[i]);
+					else f(ns[i].children || []);
+				}
+			})(node.children)
+			for (let i = 0; i < trs.length; i++) {
+				for (let j = 0, td; td = trs[i].children[j]; j++) {
+					if (td.name == 'td' || td.name == 'th') {
+						while (map[row + '.' + col]) col++;
+						var cell = {
+							name: 'div',
+							c: 1,
+							attrs: {
+								style: (td.attrs.style || '') + (border ? `;border:${border}px solid gray` + (spacing ? '' :
+									';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '')
+							},
+							children: td.children
+						}
+						if (td.attrs.colspan) {
+							cell.attrs.style += ';grid-column-start:' + col + ';grid-column-end:' + (col + parseInt(td.attrs.colspan));
+							if (!td.attrs.rowspan) cell.attrs.style += ';grid-row-start:' + row + ';grid-row-end:' + (row + 1);
+							col += parseInt(td.attrs.colspan) - 1;
+						}
+						if (td.attrs.rowspan) {
+							cell.attrs.style += ';grid-row-start:' + row + ';grid-row-end:' + (row + parseInt(td.attrs.rowspan));
+							if (!td.attrs.colspan) cell.attrs.style += ';grid-column-start:' + col + ';grid-column-end:' + (col + 1);
+							for (var k = 1; k < td.attrs.rowspan; k++) map[(row + k) + '.' + col] = 1;
+						}
+						children.push(cell);
+						col++;
+					}
+				}
+				if (!colNum) {
+					colNum = col - 1;
+					attrs.style += `;grid-template-columns:repeat(${colNum},auto)`
+				}
+				col = 1;
+				row++;
+			}
+			node.children = children;
+		} else {
+			attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`;
+			if (border || padding)
+				(function f(ns) {
+					for (var i = 0, n; n = ns[i]; i++) {
+						if (n.name == 'th' || n.name == 'td') {
+							if (border) n.attrs.style = `border:${border}px solid gray;${n.attrs.style || ''}`;
+							if (padding) n.attrs.style = `padding:${padding}px;${n.attrs.style || ''}`;
+						} else f(n.children || []);
+					}
+				})(childs)
+		}
+		if (this.options.autoscroll) {
+			var table = Object.assign({}, node);
+			node.name = 'div';
+			node.attrs = {
+				style: 'overflow:scroll'
+			}
+			node.children = [table];
+		}
+	}
+	this.CssHandler.pop && this.CssHandler.pop(node);
+	// 自动压缩
+	if (node.name == 'div' && !Object.keys(attrs).length && childs.length == 1 && childs[0].name == 'div')
+		siblings[len - 1] = childs[0];
+}
+// 状态机
+MpHtmlParser.prototype.Text = function(c) {
+	if (c == '<') {
+		var next = this.data[this.i + 1],
+			isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+		if (isLetter(next)) {
+			this.setText();
+			this.start = this.i + 1;
+			this.state = this.TagName;
+		} else if (next == '/') {
+			this.setText();
+			if (isLetter(this.data[++this.i + 1])) {
+				this.start = this.i + 1;
+				this.state = this.EndTag;
+			} else this.Comment();
+		} else if (next == '!' || next == '?') {
+			this.setText();
+			this.Comment();
+		}
+	}
+}
+MpHtmlParser.prototype.Comment = function() {
+	var key;
+	if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->';
+	else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>';
+	else key = '>';
+	if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length;
+	else this.i += key.length - 1;
+	this.start = this.i + 1;
+	this.state = this.Text;
+}
+MpHtmlParser.prototype.TagName = function(c) {
+	if (blankChar[c]) {
+		this.tagName = this.section();
+		while (blankChar[this.data[this.i]]) this.i++;
+		if (this.isClose()) this.setNode();
+		else {
+			this.start = this.i;
+			this.state = this.AttrName;
+		}
+	} else if (this.isClose()) {
+		this.tagName = this.section();
+		this.setNode();
+	}
+}
+MpHtmlParser.prototype.AttrName = function(c) {
+	if (c == '=' || blankChar[c] || this.isClose()) {
+		this.attrName = this.section();
+		if (blankChar[c])
+			while (blankChar[this.data[++this.i]]);
+		if (this.data[this.i] == '=') {
+			while (blankChar[this.data[++this.i]]);
+			this.start = this.i--;
+			this.state = this.AttrValue;
+		} else this.setAttr();
+	}
+}
+MpHtmlParser.prototype.AttrValue = function(c) {
+	if (c == '"' || c == "'") {
+		this.start++;
+		if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length;
+		this.attrVal = this.section();
+		this.i++;
+	} else {
+		for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++);
+		this.attrVal = this.section();
+	}
+	this.setAttr();
+}
+MpHtmlParser.prototype.EndTag = function(c) {
+	if (blankChar[c] || c == '>' || c == '/') {
+		var name = this.section().toLowerCase();
+		for (var i = this.STACK.length; i--;)
+			if (this.STACK[i].name == name) break;
+		if (i != -1) {
+			var node;
+			while ((node = this.STACK.pop()).name != name) this.popNode(node);
+			this.popNode(node);
+		} else if (name == 'p' || name == 'br')
+			this.siblings().push({
+				name,
+				attrs: {}
+			});
+		this.i = this.data.indexOf('>', this.i);
+		this.start = this.i + 1;
+		if (this.i == -1) this.i = this.data.length;
+		else this.state = this.Text;
+	}
+}
+module.exports = MpHtmlParser;

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

@@ -0,0 +1,80 @@
+/* 配置文件 */
+var cfg = {
+	// 出错占位图
+	errorImg: null,
+	// 过滤器函数
+	filter: null,
+	// 代码高亮函数
+	highlight: null,
+	// 文本处理函数
+	onText: null,
+	// 实体编码列表
+	entities: {
+		quot: '"',
+		apos: "'",
+		semi: ';',
+		nbsp: '\xA0',
+		ensp: '\u2002',
+		emsp: '\u2003',
+		ndash: '–',
+		mdash: '—',
+		middot: '·',
+		lsquo: '‘',
+		rsquo: '’',
+		ldquo: '“',
+		rdquo: '”',
+		bull: '•',
+		hellip: '…'
+	},
+	blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
+	boolAttrs: makeMap('allowfullscreen,autoplay,autostart,controls,ignore,loop,muted'),
+	// 块级标签,将被转为 div
+	blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
+	// 将被移除的标签
+	ignoreTags: makeMap('area,base,canvas,frame,iframe,input,link,map,meta,param,script,source,style,svg,textarea,title,track,wbr'),
+	// 只能被 rich-text 显示的标签
+	richOnlyTags: makeMap('a,colgroup,fieldset,legend'),
+	// 自闭合的标签
+	selfClosingTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
+	// 信任的标签
+	trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
+	// 默认的标签样式
+	userAgentStyles: {
+		address: 'font-style:italic',
+		big: 'display:inline;font-size:1.2em',
+		blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px',
+		caption: 'display:table-caption;text-align:center',
+		center: 'text-align:center',
+		cite: 'font-style:italic',
+		dd: 'margin-left:40px',
+		mark: 'background-color:yellow',
+		pre: 'font-family:monospace;white-space:pre;overflow:scroll',
+		s: 'text-decoration:line-through',
+		small: 'display:inline;font-size:0.8em',
+		u: 'text-decoration:underline'
+	}
+}
+
+function makeMap(str) {
+	var map = Object.create(null),
+		list = str.split(',');
+	for (var i = list.length; i--;)
+		map[list[i]] = true;
+	return map;
+}
+
+// #ifdef MP-WEIXIN
+if (wx.canIUse('editor')) {
+	cfg.blockTags.pre = void 0;
+	cfg.ignoreTags.rp = true;
+	Object.assign(cfg.richOnlyTags, makeMap('bdi,bdo,caption,rt,ruby'));
+	Object.assign(cfg.trustTags, makeMap('bdi,bdo,caption,pre,rt,ruby'));
+}
+// #endif
+
+// #ifdef APP-PLUS
+cfg.ignoreTags.iframe = void 0;
+Object.assign(cfg.trustTags, makeMap('embed,iframe'));
+// #endif
+
+module.exports = cfg;

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

@@ -0,0 +1,22 @@
+var inline = {
+	abbr: 1,
+	b: 1,
+	big: 1,
+	code: 1,
+	del: 1,
+	em: 1,
+	i: 1,
+	ins: 1,
+	label: 1,
+	q: 1,
+	small: 1,
+	span: 1,
+	strong: 1,
+	sub: 1,
+	sup: 1
+}
+module.exports = {
+	use: function(item) {
+		return !item.c && !inline[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1
+	}
+}

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

@@ -0,0 +1,505 @@
+<template>
+	<view :class="'interlayer '+(c||'')" :style="s">
+		<block v-for="(n, i) in nodes" v-bind:key="i">
+			<!--图片-->
+			<view v-if="n.name=='img'" :class="'_img '+n.attrs.class" :style="n.attrs.style" :data-attrs="n.attrs" @click.stop="imgtap">
+				<rich-text v-if="ctrl[i]!=0" :nodes="[{attrs:{src:loading&&(ctrl[i]||0)<2?loading:(lazyLoad&&!ctrl[i]?placeholder:(ctrl[i]==3?errorImg:n.attrs.src||'')),alt:n.attrs.alt||'',width:n.attrs.width||'',style:'-webkit-touch-callout:none;max-width:100%;display:block'+(n.attrs.height?';height:'+n.attrs.height:'')},name:'img'}]" />
+				<image class="_image" :src="lazyLoad&&!ctrl[i]?placeholder:n.attrs.src" :lazy-load="lazyLoad"
+				 :show-menu-by-longpress="!n.attrs.ignore" :data-i="i" :data-index="n.attrs.i" data-source="img" @load="loadImg"
+				 @error="error" />
+			</view>
+			<!--文本-->
+			<text v-else-if="n.type=='text'" decode>{{n.text}}</text>
+			<!--#ifndef MP-BAIDU-->
+			<text v-else-if="n.name=='br'">\n</text>
+			<!--#endif-->
+			<!--视频-->
+			<view v-else-if="((n.lazyLoad&&!n.attrs.autoplay)||(n.name=='video'&&!loadVideo))&&ctrl[i]==undefined" :id="n.attrs.id"
+			 :class="'_video '+(n.attrs.class||'')" :style="n.attrs.style" :data-i="i" @click.stop="_loadVideo" />
+			<video v-else-if="n.name=='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||ctrl[i]==0"
+			 :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[ctrl[i]||0]"
+			 :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" :data-i="i" data-source="video" @error="error" @play="play" />
+			<!--音频-->
+			<audio v-else-if="n.name=='audio'" :ref="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author"
+			 :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster"
+			 :src="n.attrs.source[ctrl[i]||0]" :data-i="i" :data-id="n.attrs.id" data-source="audio" @error.native="error"
+			 @play.native="play" />
+			<!--链接-->
+			<view v-else-if="n.name=='a'" :id="n.attrs.id" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style"
+			 :data-attrs="n.attrs" @click.stop="linkpress">
+				<trees class="_span" c="_span" :nodes="n.children" />
+			</view>
+			<!--广告-->
+			<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']" :appid="n.attrs.appid" :apid="n.attrs.apid" :type="n.attrs.type" :adpid="n.attrs.adpid" data-source="ad" @error="error" />-->
+			<!--列表-->
+			<view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex;flex-direction:row'">
+				<view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view>
+				<view v-else class="_ul-bef">
+					<view v-if="n.floor%3==0" class="_ul-p1">█</view>
+					<view v-else-if="n.floor%3==2" class="_ul-p2" />
+					<view v-else class="_ul-p1" style="border-radius:50%">█</view>
+				</view>
+				<trees class="_li" c="_li" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" />
+			</view>
+			<!--表格-->
+			<view v-else-if="n.name=='table'&&n.c&&n.flag" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:grid'">
+				<trees v-for="(cell,n) in n.children" v-bind:key="n" :class="cell.attrs.class" :c="cell.attrs.class" :style="cell.attrs.style"
+				 :s="cell.attrs.style" :nodes="cell.children" />
+			</view>
+			<view v-else-if="n.name=='table'&&n.c" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:table'">
+				<view v-for="(tbody, o) in n.children" v-bind:key="o" :class="tbody.attrs.class" :style="(tbody.attrs.style||'')+(tbody.name[0]=='t'?';display:table-'+(tbody.name=='tr'?'row':'row-group'):'')">
+					<view v-for="(tr, p) in tbody.children" v-bind:key="p" :class="tr.attrs.class" :style="(tr.attrs.style||'')+(tr.name[0]=='t'?';display:table-'+(tr.name=='tr'?'row':'cell'):'')">
+						<trees v-if="tr.name=='td'" :nodes="tr.children" />
+						<trees v-else v-for="(td, q) in tr.children" v-bind:key="q" :class="td.attrs.class" :c="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')"
+						 :s="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')" :nodes="td.children" />
+					</view>
+				</view>
+			</view>
+			<!--#ifdef APP-PLUS-->
+			<iframe v-else-if="n.name=='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder"
+			 :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
+			<embed v-else-if="n.name=='embed'" :style="n.attrs.style" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
+			<!--#endif-->
+			<!--富文本-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
+			<rich-text v-else-if="handler.use(n)" :id="n.attrs.id" :class="'_p __'+n.name" :nodes="[n]" />
+			<!--#endif-->
+			<!--#ifndef MP-WEIXIN || MP-QQ || APP-PLUS-->
+			<rich-text v-else-if="!n.c" :id="n.attrs.id" :nodes="[n]" style="display:inline" />
+			<!--#endif-->
+			<trees v-else :class="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :c="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')"
+			 :style="n.attrs.style" :s="n.attrs.style" :nodes="n.children" :lazyLoad="lazyLoad" :loading="loading" />
+		</block>
+	</view>
+</template>
+<script module="handler" lang="wxs" src="./handler.wxs"></script>
+<script>
+	global.Parser = {};
+	import trees from './trees'
+	const errorImg = require('../libs/config.js').errorImg;
+	export default {
+		components: {
+			trees
+		},
+		name: 'trees',
+		data() {
+			return {
+				ctrl: [],
+				placeholder: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="225"/>',
+				errorImg,
+				loadVideo: typeof plus == 'undefined',
+				// #ifndef MP-ALIPAY
+				c: '',
+				s: ''
+				// #endif
+			}
+		},
+		props: {
+			nodes: Array,
+			lazyLoad: Boolean,
+			loading: String,
+			// #ifdef MP-ALIPAY
+			c: String,
+			s: String
+			// #endif
+		},
+		mounted() {
+			for (this.top = this.$parent; this.top.$options.name != 'parser'; this.top = this.top.$parent);
+			this.init();
+		},
+		// #ifdef APP-PLUS
+		beforeDestroy() {
+			this.observer && this.observer.disconnect();
+		},
+		// #endif
+		methods: {
+			init() {
+				for (var i = this.nodes.length, n; n = this.nodes[--i];) {
+					if (n.name == 'img') {
+						this.top.imgList.setItem(n.attrs.i, n.attrs['original-src'] || n.attrs.src);
+						// #ifdef APP-PLUS
+						if (this.lazyLoad && !this.observer) {
+							this.observer = uni.createIntersectionObserver(this).relativeToViewport({
+								top: 500,
+								bottom: 500
+							});
+							setTimeout(() => {
+								this.observer.observe('._img', res => {
+									if (res.intersectionRatio) {
+										for (var j = this.nodes.length; j--;)
+											if (this.nodes[j].name == 'img')
+												this.$set(this.ctrl, j, 1);
+										this.observer.disconnect();
+									}
+								})
+							}, 0)
+						}
+						// #endif
+					} else if (n.name == 'video' || n.name == 'audio') {
+						var ctx;
+						if (n.name == 'video') {
+							ctx = uni.createVideoContext(n.attrs.id
+								// #ifndef MP-BAIDU
+								, this
+								// #endif
+							);
+						} else if (this.$refs[n.attrs.id])
+							ctx = this.$refs[n.attrs.id][0];
+						if (ctx) {
+							ctx.id = n.attrs.id;
+							this.top.videoContexts.push(ctx);
+						}
+					}
+				}
+				// #ifdef APP-PLUS
+				// APP 上避免 video 错位需要延时渲染
+				setTimeout(() => {
+					this.loadVideo = true;
+				}, 1000)
+				// #endif
+			},
+			play(e) {
+				var contexts = this.top.videoContexts;
+				if (contexts.length > 1 && this.top.autopause)
+					for (var i = contexts.length; i--;)
+						if (contexts[i].id != e.currentTarget.dataset.id)
+							contexts[i].pause();
+			},
+			imgtap(e) {
+				var attrs = e.currentTarget.dataset.attrs;
+				if (!attrs.ignore) {
+					var preview = true,
+						data = {
+							id: e.target.id,
+							src: attrs.src,
+							ignore: () => preview = false
+						};
+					global.Parser.onImgtap && global.Parser.onImgtap(data);
+					this.top.$emit('imgtap', data);
+					if (preview) {
+						var urls = this.top.imgList,
+							current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0);
+						uni.previewImage({
+							current,
+							urls
+						})
+					}
+				}
+			},
+			loadImg(e) {
+				var i = e.currentTarget.dataset.i;
+				if (this.lazyLoad && !this.ctrl[i]) {
+					// #ifdef QUICKAPP-WEBVIEW
+					this.$set(this.ctrl, i, 0);
+					this.$nextTick(function() {
+						// #endif
+						// #ifndef APP-PLUS
+						this.$set(this.ctrl, i, 1);
+						// #endif
+						// #ifdef QUICKAPP-WEBVIEW
+					})
+					// #endif
+				} else if (this.loading && this.ctrl[i] != 2) {
+					// #ifdef QUICKAPP-WEBVIEW
+					this.$set(this.ctrl, i, 0);
+					this.$nextTick(function() {
+						// #endif
+						this.$set(this.ctrl, i, 2);
+						// #ifdef QUICKAPP-WEBVIEW
+					})
+					// #endif
+				}
+			},
+			linkpress(e) {
+				var jump = true,
+					attrs = e.currentTarget.dataset.attrs;
+				attrs.ignore = () => jump = false;
+				global.Parser.onLinkpress && global.Parser.onLinkpress(attrs);
+				this.top.$emit('linkpress', attrs);
+				if (jump) {
+					// #ifdef MP
+					if (attrs['app-id']) {
+						return uni.navigateToMiniProgram({
+							appId: attrs['app-id'],
+							path: attrs.path
+						})
+					}
+					// #endif
+					if (attrs.href) {
+						if (attrs.href[0] == '#') {
+							if (this.top.useAnchor)
+								this.top.navigateTo({
+									id: attrs.href.substring(1)
+								})
+						} else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0) {
+							// #ifdef APP-PLUS
+							plus.runtime.openWeb(attrs.href);
+							// #endif
+							// #ifndef APP-PLUS
+							uni.setClipboardData({
+								data: attrs.href,
+								success: () =>
+									uni.showToast({
+										title: '链接已复制'
+									})
+							})
+							// #endif
+						} else
+							uni.navigateTo({
+								url: attrs.href,
+								fail() {
+									uni.switchTab({
+										url: attrs.href,
+									})
+								}
+							})
+					}
+				}
+			},
+			error(e) {
+				var target = e.currentTarget,
+					source = target.dataset.source,
+					i = target.dataset.i;
+				if (source == 'video' || source == 'audio') {
+					// 加载其他 source
+					var index = this.ctrl[i] ? this.ctrl[i].i + 1 : 1;
+					if (index < this.nodes[i].attrs.source.length)
+						this.$set(this.ctrl, i, index);
+					if (e.detail.__args__)
+						e.detail = e.detail.__args__[0];
+				} else if (errorImg && source == 'img') {
+					this.top.imgList.setItem(target.dataset.index, errorImg);
+					this.$set(this.ctrl, i, 3);
+				}
+				this.top && this.top.$emit('error', {
+					source,
+					target,
+					errMsg: e.detail.errMsg
+				});
+			},
+			_loadVideo(e) {
+				this.$set(this.ctrl, e.target.dataset.i, 0);
+			}
+		}
+	}
+</script>
+
+<style>
+	/* 在这里引入自定义样式 */
+
+	/* 链接和图片效果 */
+	._a {
+		display: inline;
+		padding: 1.5px 0 1.5px 0;
+		color: #366092;
+		word-break: break-all;
+	}
+
+	._hover {
+		text-decoration: underline;
+		opacity: 0.7;
+	}
+
+	._img {
+		display: inline-block;
+		max-width: 100%;
+		overflow: hidden;
+	}
+
+	/* #ifdef MP-WEIXIN */
+	:host {
+		display: inline;
+	}
+
+	/* #endif */
+
+	/* #ifndef MP-ALIPAY || APP-PLUS */
+	.interlayer {
+		display: inherit;
+		flex-direction: inherit;
+		flex-wrap: inherit;
+		align-content: inherit;
+		align-items: inherit;
+		justify-content: inherit;
+		width: 100%;
+		white-space: inherit;
+	}
+
+	/* #endif */
+
+	._b,
+	._strong {
+		font-weight: bold;
+	}
+
+	/* #ifndef MP-ALIPAY */
+	._blockquote,
+	._div,
+	._p,
+	._ol,
+	._ul,
+	._li {
+		display: block;
+	}
+
+	/* #endif */
+
+	._code {
+		font-family: monospace;
+	}
+
+	._del {
+		text-decoration: line-through;
+	}
+
+	._em,
+	._i {
+		font-style: italic;
+	}
+
+	._h1 {
+		font-size: 2em;
+	}
+
+	._h2 {
+		font-size: 1.5em;
+	}
+
+	._h3 {
+		font-size: 1.17em;
+	}
+
+	._h5 {
+		font-size: 0.83em;
+	}
+
+	._h6 {
+		font-size: 0.67em;
+	}
+
+	._h1,
+	._h2,
+	._h3,
+	._h4,
+	._h5,
+	._h6 {
+		display: block;
+		font-weight: bold;
+	}
+
+	._image {
+		display: block;
+		width: 100%;
+		height: 360px;
+		margin-top: -360px;
+		opacity: 0;
+	}
+
+	._ins {
+		text-decoration: underline;
+	}
+
+	._li {
+		flex: 1;
+		width: 0;
+	}
+
+	._ol-bef {
+		width: 36px;
+		margin-right: 5px;
+		text-align: right;
+	}
+
+	._ul-bef {
+		display: block;
+		margin: 0 12px 0 23px;
+		line-height: normal;
+	}
+
+	._ol-bef,
+	._ul-bef {
+		flex: none;
+		user-select: none;
+	}
+
+	._ul-p1 {
+		display: inline-block;
+		width: 0.3em;
+		height: 0.3em;
+		overflow: hidden;
+		line-height: 0.3em;
+	}
+
+	._ul-p2 {
+		display: inline-block;
+		width: 0.23em;
+		height: 0.23em;
+		border: 0.05em solid black;
+		border-radius: 50%;
+	}
+
+	._q::before {
+		content: '"';
+	}
+
+	._q::after {
+		content: '"';
+	}
+
+	._sub {
+		font-size: smaller;
+		vertical-align: sub;
+	}
+
+	._sup {
+		font-size: smaller;
+		vertical-align: super;
+	}
+
+	/* #ifdef MP-ALIPAY || APP-PLUS || QUICKAPP-WEBVIEW */
+	._abbr,
+	._b,
+	._code,
+	._del,
+	._em,
+	._i,
+	._ins,
+	._label,
+	._q,
+	._span,
+	._strong,
+	._sub,
+	._sup {
+		display: inline;
+	}
+
+	/* #endif */
+
+	/* #ifdef MP-WEIXIN || MP-QQ */
+	.__bdo,
+	.__bdi,
+	.__ruby,
+	.__rt {
+		display: inline-block;
+	}
+
+	/* #endif */
+	._video {
+		position: relative;
+		display: inline-block;
+		width: 300px;
+		height: 225px;
+		background-color: black;
+	}
+
+	._video::after {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		margin: -15px 0 0 -15px;
+		content: '';
+		border-color: transparent transparent transparent white;
+		border-style: solid;
+		border-width: 15px 0 15px 30px;
+	}
+</style>

+ 74 - 0
components/uni-cart-fix/uni-cart-fix.vue

@@ -0,0 +1,74 @@
+<template>
+	 <view class="cart-fix" @click="toCart">
+	 	<!-- <u-image width="70rpx" height="70rpx" src="/static/cart.png"></u-image>
+	 	<u-badge absolute :offset="[15,10]" type="error" :count="count"></u-badge> -->
+		<drag-button
+			:isDock="true"
+			:existTabBar="true"
+			:dragPic="dragPic"
+			:badge="count"
+			@btnClick="toCart"
+			@btnTouchstart="btnTouchstart"
+			@btnTouchend="btnTouchend"
+		/>
+	 </view>
+</template>
+	<script>
+		import dragButton from "@/components/drag-button/drag-button.vue";
+		export default {
+			components: {
+			    dragButton
+			},
+			props:{
+				closeCurPage:{
+					type: Boolean,
+					default: false
+				},
+				dragPic: {
+					type: String,
+					default: ''
+				}
+			},
+			computed: {
+				count() {
+					return this.$store.state.vuex_cartNums
+				},
+			},
+			methods: {
+				toCart() {
+					let _this = this
+					if(_this.closeCurPage){
+						uni.redirectTo({
+							url:"/pages/cart/cart"
+						})
+					}else{
+						uni.navigateTo({
+							url:"/pages/cart/cart"
+						})
+					}
+				},
+				btnClick() {
+					console.log('btnClick');
+				},
+				btnTouchstart() {
+					console.log('btnTouchstart');
+				},
+				btnTouchend() {
+					console.log('btnTouchend');
+				},
+			},
+		}
+	</script>
+
+<style lang="scss">
+	.cart-fix{
+		position: fixed;
+		z-index: 100000;
+		// background: rgba($color: #ffffff, $alpha: 0.7);
+		// padding: 10upx;
+		// border-radius: 100%;
+		bottom: 40%;
+		right: 2%;
+		// box-shadow: 3upx 3upx 8upx #ccc;
+	}
+</style>

+ 182 - 0
components/uni-coods/uni-coods.vue

@@ -0,0 +1,182 @@
+<template>
+	<view class="goods-list">
+		<view class="goods-item" v-for="item in list" :key="item.id">
+			<view>
+				<view class="goods-imgs"  @click="toDetail(item)">
+					<view v-if="item.inventoryQty == 0&&item.state == 1" class="goods-staus">已售罄</view>
+					<view v-if="item.state == 0" class="goods-staus">已下架</view>
+					<u-lazy-load 
+					img-mode="scaleToFill" 
+					:height="imgHeight" 
+					:image="item.homeImage+'?x-oss-process=image/resize,m_pad,h_252,w_325,color_ffffff'" 
+					:loading-img="loadingImg" 
+					:error-img="errorImg">
+					</u-lazy-load>
+				</view>
+				<view class="name ellipsis-two" @click="toDetail(item)">{{item.name}}</view>
+			</view>
+			<view class="price">
+				<view>
+					<text>{{item.sellGold}}</text>
+					<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+				</view>
+				<view v-if="item.inventoryQty > 0 && item.state == 1 ">
+					<!-- <u-image mode="scaleToFill" width="45rpx" height="45rpx" src="/static/addCart.png"></u-image> -->
+					<u-button size="mini" type="error" :custom-style="customStyle" @click="addCart(item)">
+						+
+					</u-button>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		addGoodsToCart
+	} from '@/api/shoppingCart.js'
+	export default {
+		props: {
+			imgHeight: {
+				type: Number,
+				default: 250
+			},
+			goldLimit: {
+				type: [Number,String],
+				default: 0
+			},
+			list:{
+				type: Array,
+				default: function(){
+					return []
+				}
+			}
+		},
+		data() {
+			return {
+				customStyle:{
+					color: '#fff',
+					borderRadius: '150rpx',
+					border: 0,
+					width: '50rpx',
+					height: '50rpx',
+					lineHeight: '50rpx',
+					fontSize: '25px'
+				},
+				loadingImg: '/static/loading.gif',
+				errorImg: '/static/imgError.png',
+				timer: null,
+				finger: {x:0,y:0},
+				linePos: null,
+			}
+		},
+		methods: {
+			// 添加购物车
+			addGoodToCart(item){
+				uni.showLoading({
+					mask: true,
+					title: "正在加入购物车..."
+				})
+				addGoodsToCart(item).then(res => {
+					if(res.status == 200){
+						// 刷新购物车数量
+						if(!item.hasCunzai){
+							this.$store.state.vuex_cartNums = this.$store.state.vuex_cartNums + 1
+						}
+						setTimeout(()=>{
+							uni.showToast({
+								icon: 'none',
+								title:'添加成功'
+							})
+							// 刷新购物车数据
+							uni.$emit('getCartList')
+						},50)
+					}
+				})
+			},
+			// 判断当前商品是否已存在购物车中
+			hasCunzai(data){
+				let list = this.$store.state.vuex_cartList
+				let row = list.find(item=> item.goodsTypeNo == data.goodsTypeNo)
+				return row
+			},
+			// 加入购物车
+			addCart(item) {
+				this.addGoodToCart({goodsNo:item.goodsNo,buyQty:1,hasCunzai:this.hasCunzai(item)})
+			},
+			// 商品详情
+			toDetail(item){
+				uni.navigateTo({
+					url:"/pages/goods/goodsDetail?id="+item.id + "&goldLimit="+this.goldLimit
+				})
+			}
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+.goods-list{
+	display: flex;
+	flex-wrap: wrap;
+	justify-content: space-between;
+	padding-top: 20upx;
+	.goods-item{
+		background: #FFFFFF;
+		width: 48%;
+		margin-bottom: 20upx;
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+		.goods-imgs{
+			position: relative;
+			border-radius: 28upx 28upx 0 0;
+			border: 1px solid #eee;
+			overflow: hidden;
+			.goods-staus{
+				width: 100%;
+				height: 100%;
+				position: absolute;
+				z-index: 100;
+				border-radius: 15rpx 15rpx 0 0;
+				background: rgba($color: #000000, $alpha: 0.4);
+				text-align: center;
+				line-height: 250rpx;
+				left: 0;
+				top: 0;
+				color: #eee;
+				font-size: 30upx;
+				font-weight: bold;
+			}
+		}
+		.name{
+			padding: 10upx 0;
+			font-weight: bold;
+			font-size: 30rpx;
+		}
+		.price{
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			text{
+				color: #d42a26;
+				font-size: 36upx;
+				margin-right: 6upx;
+				font-weight: bold;
+			}
+			>view{
+				&:first-child{
+					font-size: 22upx;
+					display: flex;
+					align-items: center;
+				}
+				&:last-child{
+					&:active{
+						opacity: 0.5;
+					}
+				}
+			}
+		}
+	}
+}
+
+</style>

+ 0 - 224
components/uni-nav-bar/uni-nav-bar.vue

@@ -1,224 +0,0 @@
-<template>
-	<view class="uni-navbar">
-		<view :class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }" :style="{ 'background-color': backgroundColor }"
-		 class="uni-navbar__content">
-			<uni-status-bar v-if="statusBar" />
-			<view :style="{ color: color,backgroundColor: backgroundColor }" class="uni-navbar__header uni-navbar__content_view">
-				<view @tap="onClickLeft" class="uni-navbar__header-btns uni-navbar__header-btns-left uni-navbar__content_view">
-					<view class="uni-navbar__content_view" v-if="leftIcon.length">
-						<uni-icons :color="color" :type="leftIcon" size="24" />
-					</view>
-					<view :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length }" class="uni-navbar-btn-text uni-navbar__content_view"
-					 v-if="leftText.length">
-						<text :style="{ color: color, fontSize: '14px' }">{{ leftText }}</text>
-					</view>
-					<slot name="left" />
-				</view>
-				<view class="uni-navbar__header-container uni-navbar__content_view">
-					<view class="uni-navbar__header-container-inner uni-navbar__content_view" v-if="title.length">
-						<text class="uni-nav-bar-text" :style="{color: color }">{{ title }}</text>
-					</view>
-					<!-- 标题插槽 -->
-					<slot />
-				</view>
-				<view :class="title.length ? 'uni-navbar__header-btns-right' : ''" @tap="onClickRight" class="uni-navbar__header-btns uni-navbar__content_view">
-					<view class="uni-navbar__content_view" v-if="rightIcon.length">
-						<uni-icons :color="color" :type="rightIcon" size="24" />
-					</view>
-					<!-- 优先显示图标 -->
-					<view class="uni-navbar-btn-text uni-navbar__content_view" v-if="rightText.length && !rightIcon.length">
-						<text class="uni-nav-bar-right-text">{{ rightText }}</text>
-					</view>
-					<slot name="right" />
-				</view>
-			</view>
-		</view>
-		<view class="uni-navbar__placeholder" v-if="fixed">
-			<uni-status-bar v-if="statusBar" />
-			<view class="uni-navbar__placeholder-view" />
-		</view>
-	</view>
-</template>
-
-<script>
-	import uniStatusBar from "../uni-status-bar/uni-status-bar.vue";
-	import uniIcons from "../uni-icons/uni-icons.vue";
-
-	export default {
-		name: "UniNavBar",
-		components: {
-			uniStatusBar,
-			uniIcons
-		},
-		props: {
-			title: {
-				type: String,
-				default: ""
-			},
-			leftText: {
-				type: String,
-				default: ""
-			},
-			rightText: {
-				type: String,
-				default: ""
-			},
-			leftIcon: {
-				type: String,
-				default: ""
-			},
-			rightIcon: {
-				type: String,
-				default: ""
-			},
-			fixed: {
-				type: [Boolean, String],
-				default: false
-			},
-			color: {
-				type: String,
-				default: "#000000"
-			},
-			backgroundColor: {
-				type: String,
-				default: "#FFFFFF"
-			},
-			statusBar: {
-				type: [Boolean, String],
-				default: false
-			},
-			shadow: {
-				type: [String, Boolean],
-				default: false
-			},
-			border: {
-				type: [String, Boolean],
-				default: true
-			}
-		},
-        mounted() {
-          if(uni.report && this.title !== '') {
-              uni.report('title', this.title)
-          }
-        },
-		methods: {
-			onClickLeft() {
-				this.$emit("clickLeft");
-			},
-			onClickRight() {
-				this.$emit("clickRight");
-			}
-		}
-	};
-</script>
-
-<style lang="scss" scoped>
-	$nav-height: 44px;
-	.uni-nav-bar-text {
-		/* #ifdef APP-PLUS */
-		font-size: 34rpx;
-		/* #endif */
-		/* #ifndef APP-PLUS */
-		font-size: $uni-font-size-lg;
-		/* #endif */
-	}
-	.uni-nav-bar-right-text {
-		font-size: $uni-font-size-base;
-	}
-
-	.uni-navbar {
-		width: 750rpx;
-	}
-
-	.uni-navbar__content {
-		position: relative;
-		width: 750rpx;
-		background-color: $uni-bg-color;
-		overflow: hidden;
-	}
-
-	.uni-navbar__content_view {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		align-items: center;
-		flex-direction: row;
-		// background-color: #FFFFFF;
-	}
-
-	.uni-navbar__header {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-direction: row;
-		width: 750rpx;
-		height: $nav-height;
-		line-height: $nav-height;
-		font-size: 14px;
-		// background-color: #ffffff;
-	}
-
-	.uni-navbar__header-btns {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-wrap: nowrap;
-		width: 120rpx;
-		padding: 0 6px;
-		justify-content: center;
-		align-items: center;
-	}
-
-	.uni-navbar__header-btns-left {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		// width: 300rpx;
-		justify-content: flex-start;
-	}
-
-	.uni-navbar__header-btns-right {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		width: 150rpx;
-		padding-right: 30rpx;
-		justify-content: flex-end;
-	}
-
-	.uni-navbar__header-container {
-		flex: 1;
-	}
-
-	.uni-navbar__header-container-inner {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex: 1;
-		align-items: center;
-		justify-content: center;
-		font-size: $uni-font-size-base;
-	}
-
-
-	.uni-navbar__placeholder-view {
-		height: $nav-height;
-	}
-
-	.uni-navbar--fixed {
-		position: fixed;
-		z-index: 998;
-	}
-
-	.uni-navbar--shadow {
-		/* #ifndef APP-NVUE */
-		box-shadow: 0 1px 6px #ccc;
-		/* #endif */
-	}
-
-	.uni-navbar--border {
-		border-bottom-width: 1rpx;
-		border-bottom-style: solid;
-		border-bottom-color: $uni-border-color;
-	}
-</style>

+ 178 - 0
components/uni-numbers-box/uni-numbers-box.vue

@@ -0,0 +1,178 @@
+<template>
+	<view class="uni-numbox">
+		<view @click="_calcValue('minus')" class="uni-numbox__minus">
+			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }">-</text>
+		</view>
+		<input :disabled="disabled" @blur="_onBlur" class="uni-numbox__value" type="number" v-model="inputValue" />
+		<view @click="_calcValue('plus')" class="uni-numbox__plus">
+			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }">+</text>
+		</view>
+	</view>
+</template>
+<script>
+	export default {
+		name: "UniNumbersBox",
+		props: {
+			index:{
+				type: String,
+				default: ''
+			},
+			value: {
+				type: [Number, String],
+				default: 1
+			},
+			min: {
+				type: Number,
+				default: 0
+			},
+			max: {
+				type: Number,
+				default: 100
+			},
+			step: {
+				type: Number,
+				default: 1
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				inputValue: this.value
+			};
+		},
+		watch: {
+			value(newVal,oldVal) {
+				console.log(newVal,oldVal,'000')
+				this.inputValue = +newVal;
+			},
+			inputValue(newVal, oldVal) {
+				if (+newVal !== +oldVal && this.max >= +newVal && this.min <= +newVal) {
+					this.$emit("change", newVal, this.index);
+				}
+			}
+		},
+		created() {
+			this.inputValue = +this.value;
+		},
+		methods: {
+			_calcValue(type) {
+				if (this.disabled) {
+					return;
+				}
+				const scale = this._getDecimalScale();
+				let value = this.inputValue * scale;
+				let step = this.step * scale;
+				if (type === "minus") {
+					value -= step;
+					if (value < this.min) {
+						return;
+					}
+					if(value > this.max){
+						value = this.max
+					}
+				} else if (type === "plus") {
+					value += step;
+					if (value > this.max) {
+						return;
+					}
+					if(value < this.min){
+						value = this.min
+					}
+				}
+
+				this.inputValue = String(value / scale);
+				this.$emit('input',this.inputValue)
+			},
+			_getDecimalScale() {
+				let scale = 1;
+				// 浮点型
+				if (~~this.step !== this.step) {
+					scale = Math.pow(10, (this.step + "").split(".")[1].length);
+				}
+				return scale;
+			},
+			_onBlur(event) {
+				let value = event.detail.value;
+				if (!value) {
+					this.inputValue = this.min;
+				}
+				value = +value;
+				if (value > this.max) {
+					value = this.max;
+				} else if (value < this.min) {
+					value = this.min;
+				}
+				this.inputValue = value;
+				this.$emit('input',this.inputValue)
+			},
+		}
+	};
+</script>
+<style lang="scss" scoped>
+	$box-height: 30px;
+	/* #ifdef APP-NVUE */
+	$box-line-height: 30px;
+	/* #endif */
+	$box-line-height: 26px;
+	$box-width: 30px;
+
+	.uni-numbox {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		width: 120px;
+	}
+
+	.uni-numbox__value {
+		background-color: $uni-bg-color;
+		width: 40px;
+		height: $box-height;
+		line-height: $box-height;
+		text-align: center;
+		font-size: $uni-font-size-lg;
+		margin: 0 10px;
+	}
+
+	.uni-numbox__minus {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		width: $box-width;
+		height: $box-height;
+		line-height: $box-height;
+		font-size: 20px;
+		color: $uni-text-color;
+		background-color: $uni-bg-color-grey;
+		border-radius: $box-width;
+	}
+
+	.uni-numbox__plus {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		width: $box-width;
+		height: $box-height;
+		line-height: $box-height;
+		background-color: $uni-bg-color-grey;
+		border-radius: $box-width;
+	}
+
+	.uni-numbox--text {
+		font-size: 36rpx;
+		color: $uni-text-color;
+	}
+
+	.uni-numbox--disabled {
+		color: $uni-text-color-disable;
+	}
+</style>

+ 122 - 0
components/uni-popup/image-txt-popup.vue

@@ -0,0 +1,122 @@
+<template>
+	<view class="image-txt-wrap">
+		<image :src="captchaBase" class="image" @click="getCode"></image>
+		<text class="tip-txt">* 点击图片即可切换验证码</text>
+		<input v-model="captcha" @input="inpChange" class="item-inp" name="captcha" type="text" maxlength="4" placeholder="请输入上方的图形验证码" />
+		<button :type="btnType" size="mini" class="popup-button-yz" @click="verify">验证</button>
+	</view>
+</template>
+
+<script>
+	import { getCaptcha } from '@/api/user.js'
+	export default{
+		name: 'ImageTxtPopup',
+		props: {
+			changeImg: {
+				type: Boolean,
+				default: false
+			},
+			//  applyImageTxt申请试用   forgetImageTxt忘记密码
+			type: {
+				type: String,
+				default: ''
+			},
+		},
+		watch: {
+			changeImg(newV, oldV){
+				if(newV === true){
+					this.getCode()
+				}
+			}
+		},
+		data(){
+			return{
+				captchaBase: '',  //  图片验证码base64
+				captcha: '',  //  图文验证码
+				nowRandomCode: '',  // 当前随机码
+				btnType: 'default',  //  验证按钮type
+			}
+		},
+		created() {
+			// this.getCode()
+		},
+		methods: {
+			//  获取验证码
+			getCode(){
+			  const _this = this
+			  //  6位随机数
+			  this.nowRandomCode = Math.random().toString().slice(-6)
+			  getCaptcha(this.nowRandomCode).then(res => {
+				// console.log(res.data)
+			    //  获取图片路径
+			    _this.captchaBase = 'data:image/png;base64,' + res.data
+			    // 显示图文验证码弹框
+			    _this.captcha = ''  //  清空图文输入内容
+			  })
+			},
+			//  验证码输入监听
+			inpChange(){
+				if(this.captcha.length == 4){
+					this.btnType = 'primary'
+				}else{
+					this.btnType = 'default'
+				}
+			},
+			//  验证
+			verify(){
+				if(!this.captcha){
+					uni.showToast({icon: 'none',title: '请输入上方的图形验证码'})
+					return
+				}else{
+					if(this.captcha.length != 4){
+						uni.showToast({icon: 'none',title: '请输入4位图形验证码'})
+						return
+					}
+					this.$emit('captchaImg', this.captcha, this.nowRandomCode)
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.image-txt-wrap{
+		line-height: 1.8;
+		.tip-txt{
+			display: block;
+			font-size: 24upx;
+			color: #999;
+			margin-bottom: 40upx;
+			text-align: center;
+		}
+		.item-inp{
+			background-color: #fff;
+			border: 2upx solid #dcdee2;
+			border-radius: 8upx;
+			color: #666;
+			display: inline-block;
+			font-size: 24upx;
+			height: 64upx;
+			line-height: 1.5;
+			padding: 8upx 14upx;
+			width: 100%;
+			box-sizing: border-box;
+		}
+		.image{
+			max-width: 100%;
+			width: 400upx;
+			height: 160upx;
+			margin: 30upx auto 20upx;
+			display: block;
+			img{
+				max-width: 100%;
+			}
+		}
+		.popup-button-yz{
+			display: block;
+			margin: 40upx auto 50upx;
+			width: 30%;
+			line-height: 2.8;
+		}
+	}
+</style>

+ 96 - 0
components/uni-popup/popup-con.vue

@@ -0,0 +1,96 @@
+<template>
+	<view class="popup-con">
+		<text class="popup-header">{{title}}</text>
+		<view class="popup-content">
+			<image-txt-popup :type="type" :changeImg="changeImg" @captchaImg="captchaImg"></image-txt-popup>
+		</view>
+		<view class="popup-footer">
+			<text class="popup-button" v-for="(item, index) in popBtn" :key="index" :style="{ color: item.color }">{{item.name}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	import imageTxtPopup from '@/components/uni-popup/image-txt-popup.vue'
+	export default{
+		name: 'PopupCon',
+		props: {
+			//  applyImageTxt申请试用   forgetImageTxt忘记密码
+			type: {
+				type: String,
+				default: ''
+			},
+			title: {
+				type: String,
+				default: '标题'
+			},
+			//  操作按钮
+			popBtn: {
+				type: Array,
+				default: function (){
+				  return []
+				}
+			},
+			changeImg: {
+				type: Boolean,
+				default: false
+			}
+		},
+		components: {
+			imageTxtPopup
+		},
+		data(){
+			return{}
+		},
+		methods: {
+			captchaImg(captcha, nowRandomCode){
+				this.$emit('captchaImg', captcha, nowRandomCode)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.popup-con{
+		box-sizing: border-box;
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		box-shadow: 0 8upx 24upx rgba(0,0,0,.15);
+		display: flex;
+		flex-direction: column;
+		padding: 30upx;
+		width: 600upx;
+		background-color: #fff;
+		border-radius: 20upx;
+		.popup-header{
+			margin-bottom: 20upx;
+			text-align: center;
+			font-weight: 700;
+			font-size: 32upx;
+			color: #333;
+			line-height: 1.8;
+		}
+		.popup-content{
+			font-size: 28upx;
+			color: #666;
+		}
+		.popup-footer{
+			display: flex;
+			flex-direction: row;
+			margin-top: 40upx;
+			.popup-button{
+				flex: 1;
+				text-align: center;
+				font-size: 28upx;
+				color: #3b4144;
+				line-height: 1.8;
+			}
+			.popup-confirm{
+				color: #57a3f3;
+			}
+		}
+	}
+	
+</style>

+ 1 - 0
components/uni-popup/uni-popup.vue

@@ -74,6 +74,7 @@
 			 */
 			maskClick(val) {
 				this.mkclick = val
+				this.$emit("close")
 			}
 		},
 		data() {

+ 0 - 25
components/uni-status-bar/uni-status-bar.vue

@@ -1,25 +0,0 @@
-<template>
-	<view :style="{ height: statusBarHeight }" class="uni-status-bar">
-		<slot />
-	</view>
-</template>
-
-<script>
-	var statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px'
-	export default {
-		name: 'UniStatusBar',
-		data() {
-			return {
-				statusBarHeight: statusBarHeight
-			}
-		}
-	}
-</script>
-
-<style lang="scss" scoped>
-	.uni-status-bar {
-		width: 750rpx;
-		height: 20px;
-		// height: var(--status-bar-height);
-	}
-</style>

+ 0 - 243
components/uni-steps/uni-steps.vue

@@ -1,243 +0,0 @@
-<template>
-	<view class="uni-steps">
-		<view :class="[direction==='column'?'uni-steps__column':'uni-steps__row']">
-			<view :class="[direction==='column'?'uni-steps__column-text-container':'uni-steps__row-text-container']">
-				<view v-for="(item,index) in options" :key="index" :class="[direction==='column'?'uni-steps__column-text':'uni-steps__row-text']">
-					<text :style="{color:index<=active?activeColor:deactiveColor}" :class="[direction==='column'?'uni-steps__column-title':'uni-steps__row-title']">{{item.title}}</text>
-					<text :style="{color:index<=active?activeColor:deactiveColor}" :class="[direction==='column'?'uni-steps__column-desc':'uni-steps__row-desc']">{{item.desc}}</text>
-				</view>
-			</view>
-			<view :class="[direction==='column'?'uni-steps__column-container':'uni-steps__row-container']">
-				<view :class="[direction==='column'?'uni-steps__column-line-item':'uni-steps__row-line-item']" v-for="(item,index) in options"
-				 :key="index">
-					<view :class="[direction==='column'?'uni-steps__column-line':'uni-steps__row-line',direction==='column'?'uni-steps__column-line--before':'uni-steps__row-line--before']"
-					 :style="{backgroundColor:index<=active&&index!==0?activeColor:index===0?'transparent':deactiveColor}"></view>
-					<view :class="[direction==='column'?'uni-steps__column-check':'uni-steps__row-check']" v-if="index === active">
-						<uni-icons :color="activeColor" type="checkbox-filled" size="14"></uni-icons>
-					</view>
-					<view :class="[direction==='column'?'uni-steps__column-circle':'uni-steps__row-circle']" v-else :style="{backgroundColor:index<active?activeColor:deactiveColor}"></view>
-					<view :class="[direction==='column'?'uni-steps__column-line':'uni-steps__row-line',direction==='column'?'uni-steps__column-line--after':'uni-steps__row-line--after']"
-					 :style="{backgroundColor:index<active&&index!==options.length-1?activeColor:index===options.length-1?'transparent':deactiveColor}"></view>
-				</view>
-			</view>
-		</view>
-	</view>
-</template>
-
-<script>
-	import uniIcons from '../uni-icons/uni-icons.vue'
-	export default {
-		name: 'UniSteps',
-		components: {
-			uniIcons
-		},
-		props: {
-			direction: {
-				// 排列方向 row column
-				type: String,
-				default: 'row'
-			},
-			activeColor: {
-				// 激活状态颜色
-				type: String,
-				default: '#1aad19'
-			},
-			deactiveColor: {
-				// 未激活状态颜色
-				type: String,
-				default: '#999999'
-			},
-			active: {
-				// 当前步骤
-				type: Number,
-				default: 0
-			},
-			options: {
-				type: Array,
-				default () {
-					return []
-				}
-			} // 数据
-		},
-		data() {
-			return {}
-		}
-	}
-</script>
-
-<style lang="scss" scoped>
-	.uni-steps {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		width: 100%;
-		/* #endif */
-		/* #ifdef APP-NVUE */
-		flex: 1;
-		/* #endif */
-		flex-direction: column;
-	}
-
-	.uni-steps__row {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-direction: column;
-	}
-
-	.uni-steps__column {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-direction: row-reverse;
-	}
-
-	.uni-steps__row-text-container {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-direction: row;
-	}
-
-	.uni-steps__column-text-container {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-direction: column;
-		flex: 1;
-	}
-
-	.uni-steps__row-text {
-		/* #ifndef APP-NVUE */
-		display: inline-flex;
-		/* #endif */
-		flex: 1;
-		flex-direction: column;
-	}
-
-	.uni-steps__column-text {
-		padding: 6px 0px;
-		border-bottom-style: solid;
-		border-bottom-width: 1px;
-		border-bottom-color: $uni-border-color;
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-direction: column;
-	}
-
-	.uni-steps__row-title {
-		font-size: $uni-font-size-base;
-		line-height: 16px;
-		text-align: center;
-	}
-
-	.uni-steps__column-title {
-		font-size: $uni-font-size-base;
-		text-align: left;
-		line-height: 18px;
-	}
-
-	.uni-steps__row-desc {
-		font-size: 12px;
-		line-height: 14px;
-		text-align: center;
-	}
-
-	.uni-steps__column-desc {
-		font-size: $uni-font-size-sm;
-		text-align: left;
-		line-height: 18px;
-	}
-
-	.uni-steps__row-container {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-direction: row;
-	}
-
-	.uni-steps__column-container {
-		/* #ifndef APP-NVUE */
-		display: inline-flex;
-		/* #endif */
-		width: 30px;
-		flex-direction: column;
-	}
-
-	.uni-steps__row-line-item {
-		/* #ifndef APP-NVUE */
-		display: inline-flex;
-		/* #endif */
-		flex-direction: row;
-		flex: 1;
-		height: 14px;
-		line-height: 14px;
-		align-items: center;
-		justify-content: center;
-	}
-
-	.uni-steps__column-line-item {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		flex-direction: column;
-		flex: 1;
-		align-items: center;
-		justify-content: center;
-	}
-
-	.uni-steps__row-line {
-		flex: 1;
-		height: 1px;
-		background-color: $uni-text-color-grey;
-	}
-
-	.uni-steps__column-line {
-		width: 1px;
-		background-color: $uni-text-color-grey;
-	}
-
-	.uni-steps__row-line--after {
-		transform: translateX(1px);
-	}
-
-	.uni-steps__column-line--after {
-		flex: 1;
-		transform: translate(0px, 1px);
-	}
-
-	.uni-steps__row-line--before {
-		transform: translateX(-1px);
-	}
-
-	.uni-steps__column-line--before {
-		height: 6px;
-		transform: translate(0px, -1px);
-	}
-
-	.uni-steps__row-circle {
-		width: 5px;
-		height: 5px;
-		border-radius: 100px;
-		background-color: $uni-text-color-grey;
-		margin: 0px 3px;
-	}
-
-	.uni-steps__column-circle {
-		width: 5px;
-		height: 5px;
-		border-radius: 100px;
-		background-color: $uni-text-color-grey;
-		margin: 4px 0px 5px 0px;
-	}
-
-	.uni-steps__row-check {
-		margin: 0px 6px;
-	}
-
-	.uni-steps__column-check {
-		height: 14px;
-		line-height: 14px;
-		margin: 2px 0px;
-	}
-</style>

+ 10 - 31
libs/axios.js

@@ -6,9 +6,9 @@ const request = (opts, hasToken) => {
 	// console.log(authorization,'authorization')
 	//  hasToken是否传入token,为true则不传token
 	const header = {
-			'Content-Type': 'application/json;charset=UTF-8'
+			'content-Type': 'application/json;charset=UTF-8'
 		}
-	if(!hasToken){
+	if(!hasToken&&authorization){
 		header['X-AUTH-TOKEN'] = authorization
 	}	
 	//此token是登录成功后后台返回保存在storage中的
@@ -21,9 +21,7 @@ const request = (opts, hasToken) => {
 	let promise = new Promise(function(resolve, reject) {
 		uni.request(DefaultOpts).then(
 			(res) => {
-				console.log(res,opts.url)
-				// 是否超时已跳转
-				let loginTimeOut = uni.getStorageSync('loginTimeOut');
+				console.log(res,'pppp')
 				if(res[0]&&res[0].errMsg.indexOf('request:fail')>=0){
 					resolve({
 						status: 6000,
@@ -39,32 +37,13 @@ const request = (opts, hasToken) => {
 				if(ret.status == '200'){
 					resolve(ret)
 				}else{
-					if(ret.status == '401'){  //  未登录或登录过期
-					    // 除过查询未完成订单的请求
-						if(opts.url.indexOf("order/unFinishedOrderRunStatus")<0){
-							uni.showToast({
-								icon:'none',
-								title: '未登录或登录已过期,请重新登录',
-								duration: 5000 
-							})
-							setTimeout(function() {
-							  const currentRoute = getRoutePath();
-							  const url = `/pages/login/login?lanuch=${currentRoute.lanuch}&path=` + encodeURIComponent(currentRoute.url);
-							  uni.redirectTo({ url });
-							}, 1000);
-						}
-					}
-					else{
-						if(ret.status == 500){
-							if(opts.url.indexOf("store/validateStoreAndDevice")<0&&opts.url.indexOf("couponReceives/findUsableCoupon")<0){
-								uni.showToast({
-									icon:'none',
-									title: ret.message,
-									mask: true,
-									duration: 3000 
-								})
-							}
-						}
+					if(ret.status != '401'){
+						uni.showToast({
+							icon:'none',
+							title: ret.message,
+							mask: true,
+							duration: 5000 
+						})
 					}
 					resolve(ret)
 				}

+ 85 - 0
libs/getDate.js

@@ -0,0 +1,85 @@
+// 引入 moment 时间插件
+import moment from 'moment'
+// 获取今日/昨日/本周/上周/本月/上月 时间
+export default {
+  // 获取今日的开始结束时间
+  getToday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().startOf('day').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取昨日的开始结束时间
+  getYesterday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().add(-1, 'days').startOf('day').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().add(-1, 'days').endOf('day').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取当前周的开始到当天结束时间
+  getCurrWeekDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().week(moment().week()).startOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取上一周的开始结束时间
+  getLastWeekDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().week(moment().week() - 1).startOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().week(moment().week() - 1).endOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取当前月的开始到当天结束时间
+  getCurrMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month()).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取上一个月的开始结束时间
+  getLastMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month() - 1).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().month(moment().month() - 1).endOf('month').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取上2个月的开始结束时间
+  getLastTwoMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month() - 2).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().month(moment().month() - 2).endOf('month').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取近3个月到今天的开始结束时间
+  getThreeMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month() - 2).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  }
+}

+ 14 - 0
libs/tools.js

@@ -10,6 +10,20 @@ export function objToUrl(obj) {
   return uri;
 }
 
+export function parseQueryString(url) {
+    var obj = {};
+    var keyvalue = [];
+    var key = "",
+        value = "";
+    var paraString = url.substring(url.indexOf("?") + 1, url.length).split("&");
+    for (var i in paraString) {
+        keyvalue = paraString[i].split("=");
+        key = keyvalue[0];
+        value = keyvalue[1];
+        obj[key] = value;
+    }
+    return obj;
+}
 
 
   

+ 5 - 0
libs/validate.js

@@ -0,0 +1,5 @@
+//  正则有效手机号码
+export const isvalidPhone = function (str) {
+  const reg = /^1[0-9]{10}$/
+  return reg.test(str)
+}

+ 1 - 11
main.js

@@ -9,17 +9,7 @@ Vue.use(uView)
 
 let vuexStore = require("@/store/$u.mixin.js")
 Vue.mixin(vuexStore)
-/*
-* 提示信息
-*/ 
-Vue.prototype.toashMsg = function (title) {
-	title = title == undefined ? "系统繁忙" : title;
-	uni.showToast({
-		title:title,
-		icon:'none',
-		duration: 2000
-	})
-}
+
 const app = new Vue({
 	store,
     ...App

+ 3 - 3
manifest.json

@@ -1,7 +1,7 @@
 {
-    "name" : "智享亿家",
+    "name" : "乐色管家",
     "appid" : "__UNI__CFE91AD",
-    "description" : "智享亿家小程序",
+    "description" : "智享亿家乐色管家小程序",
     "versionName" : "1.0.0",
     "versionCode" : "100",
     "transformPx" : false,
@@ -57,7 +57,7 @@
     "quickapp" : {},
     /* 小程序特有相关 */
     "mp-weixin" : {
-        "appid" : "wx3c26d022890f7c2b",
+        "appid" : "wx623b3d89df212494",
         "setting" : {
             "urlCheck" : false,
             "es6" : true,

+ 22 - 4
package-lock.json

@@ -1,13 +1,31 @@
 {
-  "name": "qhsxKx-mini-html",
+  "name": "zxyj-mini-html",
   "version": "1.0.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+    },
+    "moment": {
+      "version": "2.29.1",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+      "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+    },
     "uview-ui": {
-      "version": "1.5.7",
-      "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.5.7.tgz",
-      "integrity": "sha512-brNsxtXYNRFVISCehLXT+ZXmtaWh7gydrOokokYXvJUy5MkuZozMu+TdwA4mIo9y40FqKz6iO5gGWJuXyCSE5w=="
+      "version": "1.7.9",
+      "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.7.9.tgz",
+      "integrity": "sha512-YSZvz69Yt/7qoJohc9+tWVQsb4fUiE30OnvTZhUA0H+SkxhQXK6MgNsmL/lZ7RVqFLwawQBzDths2ReluvFOcA=="
+    },
+    "weapp-qrcode": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/weapp-qrcode/-/weapp-qrcode-1.0.0.tgz",
+      "integrity": "sha512-4sa3W0rGDVJ9QaeZpAKlAuUxVyjhDwiUqHyGK/jJMsRMXnhb4yO8qWU/pZruMo+iT5J6CraS67lDMFb1VY+RaA==",
+      "requires": {
+        "extend": "^3.0.2"
+      }
     }
   }
 }

+ 3 - 1
package.json

@@ -14,6 +14,8 @@
   "author": "",
   "license": "ISC",
   "dependencies": {
-    "uview-ui": "^1.5.7"
+    "moment": "^2.29.1",
+    "uview-ui": "^1.7.9",
+    "weapp-qrcode": "^1.0.0"
   }
 }

+ 188 - 18
pages.json

@@ -6,7 +6,7 @@
 		{
 			"path": "pages/index/index", // 首页
 			"style": {
-				"navigationBarTitleText": "智享亿家",
+				"navigationBarTitleText": "乐色管家",
 				"enablePullDownRefresh": false
 			}
 		},
@@ -16,16 +16,92 @@
 				"navigationBarTitleText": "授权登录"
 			}
 		},
+		{
+			"path": "pages/goods/index", // 商城
+			"style": {
+				"navigationBarTitleText": "乐色商城",
+				"enablePullDownRefresh": true
+			}
+		},
+		{
+			"path": "pages/login/phoneLogin",
+			"style": {
+				"navigationBarTitleText": "手机号登录"
+			}
+		},
 		{
 			"path": "pages/userCenter/index",
 			"style": {
-				"navigationBarTitleText": "个人中心"
+				"navigationBarTitleText": "个人中心",
+				"navigationBarBackgroundColor": "#01c9b2",
+				"navigationBarTextStyle": "white"
 			}
-		}, 
+		},
+		{
+			"path": "pages/userCenter/ldDetailed",
+			"style": {
+				"navigationBarTitleText": "乐豆明细"
+			}
+		},
+		{
+			"path": "pages/userCenter/deliveryRecord",
+			"style": {
+				"navigationBarTitleText": "投递记录"
+			}
+		},
+		{
+			"path": "pages/userCenter/userInfo/userInfo",
+			"style": {
+				"navigationBarTitleText": "个人信息"
+			}
+		},
+		{
+			"path": "pages/userCenter/userInfo/smsVerification",
+			"style": {
+				"navigationBarTitleText": "短信验证"
+			}
+		},
+		{
+			"path": "pages/userCenter/userInfo/paymentPwd",
+			"style": {
+				"navigationBarTitleText": "支付密码"
+			}
+		},
+		{
+			"path": "pages/userCenter/userInfo/changePayPwd",
+			"style": {
+				"navigationBarTitleText": "修改支付密码"
+			}
+		},
+		{
+			"path": "pages/userCenter/aboutUs",
+			"style": {
+				"navigationBarTitleText": "关于我们"
+			}
+		},
+		{
+			"path": "pages/userCenter/question",
+			"style": {
+				"navigationBarTitleText": "常见问题"
+			}
+		},
+		{
+			"path": "pages/userCenter/zhinan",
+			"style": {
+				"navigationBarTitleText": "使用指南"
+			}
+		},
+		{
+			"path": "pages/userCenter/fenlei",
+			"style": {
+				"navigationBarTitleText": "回收分类"
+			}
+		},
 		{
 			"path": "pages/order/order",
 			"style": {
-				"navigationBarTitleText": "我的订单"
+				"navigationBarTitleText": "我的订单",
+				"enablePullDownRefresh": true
 			}
 		}, {
 			"path": "pages/order/orderDetail",
@@ -33,18 +109,110 @@
 				"navigationBarTitleText": "订单详情"
 			}
 		}, 
+		{
+			"path": "pages/order/LogList",
+			"style": {
+				"navigationBarTitleText": "物流信息"
+			}
+		}, 
 		{
 			"path": "pages/agreement/agreement",
 			"style": {
 				"navigationBarTitleText": "注意事项及服务协议"
 			}
 		}
-	],
+        ,{
+            "path" : "pages/cart/cart",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "购物车",
+                "enablePullDownRefresh": false
+            }
+        }
+		,{
+		    "path" : "pages/toOrder/index",
+		    "style" :                                                                                    
+		    {
+		        "navigationBarTitleText": "提交订单",
+		        "enablePullDownRefresh": false
+		    }
+		}
+		,{
+		    "path" : "pages/toOrder/editAddress",
+		    "style" :                                                                                    
+		    {
+		        "navigationBarTitleText": "修改地址",
+		        "enablePullDownRefresh": false
+		    }
+		}
+        ,{
+            "path" : "pages/goods/goods",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "商品",
+                "enablePullDownRefresh": true
+            }
+            
+        },
+		{
+            "path" : "pages/goods/goodsDetail",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "商品详情",
+                "enablePullDownRefresh": false
+            }
+        }
+        ,{
+            "path" : "pages/store/store",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "网点详情",
+                "enablePullDownRefresh": false
+            }
+            
+        },
+		{
+		    "path" : "pages/checkOut/checkOut",
+		    "style" :                                                                                    
+		    {
+		        "navigationBarTitleText": "核销",
+		        "enablePullDownRefresh": false
+		    }
+		    
+		},
+		{
+		    "path" : "pages/toOrder/payFinish",
+		    "style" :                                                                                    
+		    {
+		        "navigationBarTitleText": "支付完成",
+		        "enablePullDownRefresh": false
+		    }
+		    
+		},
+		{
+		    "path" : "pages/checkOut/checkFinish",
+		    "style" :                                                                                    
+		    {
+		        "navigationBarTitleText": "核销完成",
+		        "enablePullDownRefresh": false
+		    }
+		    
+		}
+        ,{
+            "path" : "pages/userCenter/myCode/myCode",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "我的投递码",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+    ],
 	"globalStyle": {
-		"navigationBarTextStyle": "white",
+		"navigationBarTextStyle": "black",
 		"navigationBarTitleText": "uni-app",
-		"navigationBarBackgroundColor": "#22bf11",
-		"backgroundColor": "#F8F8F8",
+		"navigationBarBackgroundColor": "#FFFFFF",
+		"backgroundColor": "#f2f2f2",
 		"app-plus": {
 			// 将回弹属性关掉
 			"bounce": "none",
@@ -53,22 +221,24 @@
 	},
 	"tabBar": {
 		"color": "#7A7E83",
-		"selectedColor": "#00aa00",
-		"borderStyle": "#eee",
+		"selectedColor": "#01c9b2",
 		"backgroundColor": "#ffffff",
 		"fontSize": "14px",
-		"list": [{
+		"list": [
+		{
 			"pagePath": "pages/index/index",
 			"iconPath": "static/tabbar/home.png",
 			"selectedIconPath": "static/tabbar/home-active.png",
 			"text": "首页"
-		}, {
-			"pagePath": "pages/work/work",
-			"iconPath": "static/tabbar/work.png",
-			"selectedIconPath": "static/tabbar/work-active.png",
-			"text": "工作台"
-		}, {
-			"pagePath": "pages/userCenter/userCenter",
+		}, 
+		{
+			"pagePath": "pages/goods/index",
+			"iconPath": "static/tabbar/shop.png",
+			"selectedIconPath": "static/tabbar/shop-active.png",
+			"text": "商城"
+		}, 
+		{
+			"pagePath": "pages/userCenter/index",
 			"iconPath": "static/tabbar/user.png",
 			"selectedIconPath": "static/tabbar/user-active.png",
 			"text": "我的"

+ 83 - 295
pages/agreement/agreement.vue

@@ -1,357 +1,157 @@
 <template>
 	<view class="content">
 		<view class="page-content">
-			<view class="page-care" v-if="!hideZysx">
-				<u-image width="750rpx" height="1200rpx" mode="aspectFit" src="/static/img/zysx.png"></u-image>
-			</view>
 			<view class="page-care agreement">
-				<view class="title">-服务协议-</view>
+				<view class="title">-乐色管家用户服务协议(声明)-</view>
 				<view class="xy-cons">
 					<view class="MsoNormal">
-						欢迎您使用智能快洗!
-					</view>
-					<view class="MsoNormal">
-						<text>本《智能快洗平台用户服务协议》(以下简称</text>“本服务协议”)是您与智能快洗平台之间就登录注册智能快洗用户账号及使用智能快洗的各项服务等相关事宜所订立的协议。为更好的体验智能快洗的服务,您应当仔细阅读并遵守本服务协议下的全部内容,特别是涉及免除或者责任限制的条款,该类条款可能以黑体加粗或加下划线的形式提示您重点注意。除非您已阅读并接受本服务协议所有条款,否则您将不能注册智能快洗账号或使用智能快洗的服务,如您不同意本服务条款的任意内容,请勿注册或使用智能快洗的服务,并应立即停止注册程序。如您对本服务协议的内容(特别是涉及免除或者责任限制的条款)有任何疑义,可随时按照本服务协议中列明的联系方式与我们联系,我们将根据您的要求为您进一步解释和说明相关内容。如您点击“同意、继续服务”等并通过登录注册程序或其他任何方式使用或接受智能快洗的任何服务,即视为您已阅读并同意本服务协议,自愿接受本服务协议的所有内容的约束。请您在决定注册或使用服务前再次确认您已知悉并完全理解本服务协议的所有内容。
-					</view>
-					<view class="MsoNormal">
-						<text>如果您未满</text>18<text>周岁,请务必在家长或其他法定监护人的陪同下阅读本服务协议,并在进行注册、下单、支付等任何行为或使用智能快洗的其他任何服务前,应事先征得您的家长或其他法定监护人的同意。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>本服务协议所述</text>“服务”指您使用智能快洗用户账号接受智能快洗平台所提供的服务。无论“服务”属于上述何种情形,本《智能快洗平台用户服务协议》都将予以适用。
-					</view>
-					<view class="MsoNormal">
-						一、协议的主体与范围
-					</view>
-					<view class="MsoNormal">
-						<text>【签约主体】</text> <text>视您所使用的具体服务而定,</text>“智能快洗”是指陕西山海高科信息技术有限公司旗下运营或提供您所使用的相关具体服务的相关主体的统称,您可在相关服务的具体服务条款或说明文件中查看上述主体的名称和信息。 “用户”是指使用智能快洗相关服务的使用人,在本服务协议中更多称呼为“您”。
-					</view>
-					<view class="MsoNormal">
-						【协议内容】本服务协议内容同时包括:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)本《智能快洗平台用户服务协议》文本;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)《智能快洗平台隐私政策》:智能快洗非常重视您的个人信息和隐私的保护,将按照《智能快洗平台隐私政策》中所公布的政策在具体服务中进行隐私及个人信息的收集、存储、使用、披露等活动。您在注册智能快洗账号前,应仔细阅读《智能快洗平台隐私政策》;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)专项商品或服务规则。为更好地提升用户体验,智能快洗在若干具体专项商品或服务中特别制定了详细的规则,供各方遵守。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>4<text>)第三方服务相关的用户授权协议。为方便您在使用智能快洗平台服务的同时,根据您自身需要,通过智能快洗平台进行跳转等方式,自愿选择接受独立第三方服务商及部分关联第三方服务商所提供的服务,您将在使用该等第三方服务前对相应的用户授权协议予以同意确认,以作为您和智能快洗平台之间就该等第三方服务的使用所涉及的相关事项的权利义务依据。</text>
-					</view>
-					<view class="MsoNormal">
-						上述各项内容之间如存在不一致之处,以时间上最新发布的内容为准,发布时间相同的,以本款【协议内容】中所包含的组成部分的序号倒序排列为准。
-					</view>
-					<view class="MsoNormal">
-						【协议遵守】您理解并同意:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)上述【协议内容】中所述的协议、政策、条款与规则构成本服务协议不可分割的组成部分,共同适用于您所使用的智能快洗平台服务。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)根据国家法律法规变化、运营需要或为提升服务质量的目的,智能快洗将在必要的时候对上述各项协议、条款与规则不时地进行修改更新,并通过在网页或移动客户端上发出公告、站内信等合理、醒目的方式向您进行提前通知,上述修改更新内容将在相关更新说明中指定的日期开始实施,通常情况下不短于发布之日后八个自然日。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)您应当及时查阅并了解相关更新修改内容,如您不同意相关更新修改内容,可停止使用相关更新修改内容所涉及的服务,此情形下,变更事项对您不产生效力;如您在上述更新修改内容实施后继续使用所涉及的服务,将视为您已同意各项更新修改内容。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>【适用平台】本服务协议适用于网页端、移动客户端(包括</text>IOS<text>、安卓及已有或未来将新增的任何其他移动客户端)等各类平台或媒介中智能快洗所提供的各项服务。您知悉并理解,为享受上述相关服务,您必须自行提供相关上网设备(如:个人电脑、手机、平板电脑或其他设备)并自行负担相关网络使用和商品服务支付所产生的有关费用。</text>
-					</view>
-					<view class="MsoNormal">
-						二、账号的注册
-					</view>
-					<view class="MsoNormal">
-						【注册资料】您应遵循诚实信用、合法善意的原则,向智能快洗提交相关注册资料,相关注册资料应当遵守法律法规、社会主义制度、国家利益、公民合法权益、公序良俗、信息真实等原则,不应提交任何违法或不良信息,相关资料如有变动,您应及时更新。如果因您所提供的注册资料不合法、不真实、不准确或未及时更新,从而导致相关法律责任或不利后果的,您将承担相应的法律责任及不利后果。
-					</view>
-					<view class="MsoNormal">
-						您已知悉,在智能快洗账号注册过程中,因安全性、内部管理等原因,部分初始注册资料可能将无法再次更改。因此,您应谨慎核查此部分注册资料,确保正确填写。
-					</view>
-					<view class="MsoNormal">
-						【民事行为能力】您知悉并承诺,您具有完全民事权利能力和行为能力或虽不具有完全民事权利能力和行为能力但已经过您的家长和其他法定监护人同意并由您的家长和其他法定监护人代理注册及使用智能快洗的各项服务。若您不具备前述相适应的民事行为能力即进行账号注册的,则您及您的家长和其他法定监护人应依照法律规定承担因此而导致的一切后果。
-					</view>
-					<view class="MsoNormal">
-						【真实身份】因国家法律法规、监管要求及特定门类的服务(如金融服务等)需要,您有可能需要在注册或使用该等服务的特定环节中填写真实的身份信息,并需通过相关验证流程后方可使用服务,如您填写的身份信息不完整、不真实或未通过验证,将导致您无法使用该服务、损害自身、他人利益或造成其他不利后果,该等后果将由您予以承担。
-					</view>
-					<view class="MsoNormal">
-						【注册信息保护】智能快洗将对您所提交的注册信息予以保护,不会将其披露给任何非关联的第三方,除非:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)相关法律法规或国家机关要求;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)智能快洗发生相关合并、分立、收购或资产转移;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)为提供相关服务所必须的</text>
-					</view>
-					<view class="MsoNormal">
-						对于您所提交的注册信息中涉及个人信息的内容,智能快洗将严格按照《智能快洗平台隐私政策》的规定进行收集、处理和使用。
-					</view>
-					<view class="MsoNormal">
-						【账号数量】除因历史原因、业务整合等智能快洗所认可的特殊情况外,智能快洗原则上只允许您使用一个智能快洗用户账号。如有证据证明或智能快洗有理由相信您存在不当注册或不当使用多个智能快洗账号的情形,智能快洗可将相关账号信息进行合并或采取其他合理措施,如因您不当注册或不当使用给智能快洗及相关方造成损失的,您还应承担相应的赔偿责任。此外,出于相关业务需要,智能快洗也可对同一用户的多个账号或相关信息进行合并,如该等合并将对您的权益产生实质影响,智能快洗将在进行上述合并前事先征得您的同意。
-					</view>
-					<view class="MsoNormal">
-						三、账号的使用
-					</view>
-					<view class="MsoNormal">
-						【账号登录】您可以使用注册账号时填写登记的并获得系统审核通过的账号密码登录智能快洗洗车平台。为了您的使用便利,智能快洗未来可能将适时提供指纹识别、人脸识别等更为安全便捷的登录方式,智能快洗可根据相关法律法规、监管要求、用户体验、风险控制等因素对登录方式予以适时调整或增减,或在具体业务门类的用户服务条款等规定中予以进一步细化或调整。
-					</view>
-					<view class="MsoNormal">
-						【账号使用】您应对您账号项下的所有行为(包括但不限于在线签署任何协议,浏览、购买、支付、点评、上传、发布、输入任何内容)所产生的一切后果负责,通过您的账号所发生的上述各项行为将视为您本人的真实意思表示。
-					</view>
-					<view class="MsoNormal">
-						智能快洗提示您,您通过自身账号在接受智能快洗的各项服务中所上传、发送的任何内容都应具有合法来源,如相关内容涉及任何第三方的合法权益,应事先获得相应的许可。如智能快洗收到涉及您的相关举报或投诉,智能快洗可采取相关法律法规所要求或允许的方式,向相关争议方、相关部门提供包括账号在内的必要的信息,以便解决纠纷争议,保护正当权利人的合法权益。
-					</view>
-					<view class="MsoNormal">
-						【账号借用】为保证相关账号安全,未经智能快洗的书面同意,您不应将智能快洗平台上所注册的账号借给他人使用,否则您应当承担由此产生的全部责任,智能快洗平台保留拒绝提供相应服务、冻结或收回注册账号或终止本服务协议的权利,并可要求您对智能快洗所承受的损失予以赔偿。
-					</view>
-					<view class="MsoNormal">
-						【安全义务】如您发现账号存在安全问题,请您立即联系智能快洗予以调查处理,否则智能快洗对潜在损失的产生或扩大不承担任何责任。
-					</view>
-					<view class="MsoNormal">
-						智能快洗特别提示您,您应该妥善保管您的账号和密码,当您使用完毕智能快洗的服务后,您应安全退出。此外,您不应轻信借款、索要密码或其他涉及财产的网络信息。涉及财产操作的,请一定先核实对方身份,并请经常留意智能快洗有关防范诈骗犯罪的提示。您知悉并同意,如您在账号信息的保管上、相关上网设备的网络安全维护上存在任何过失导致账号丢失、泄露,您应对此所产生的任何后果负责,智能快洗对此不负任何责任,如智能快洗因此产生相关支出,智能快洗将有权向您予以追偿。
-					</view>
-					<view class="MsoNormal">
-						【限制冻结】您知悉并同意,在符合法律法规的规定,或经国家机关要求的前提下,智能快洗有权对您的注册账号进行限制或冻结,在该等情况下,您可能无法继续登陆或使用您的注册账号。
-					</view>
-					<view class="MsoNormal">
-						四、服务说明、用户行为规范与责任承担
-					</view>
-					<view class="MsoNormal">
-						【服务说明】您应在享受智能洗车服务的过程中应按照下列操作进行:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)您每次使用都需严格按照要求把车停到洗车机器人指定区域,可以通过洗车机器人两侧辅助镜查看,确保车辆在黄线内,车头到达绿色区域,严禁在未按要求停好车的情况下启动智能快洗洗车机器人。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>) 您应按语言提示缓慢驶入或驶离洗车机器人,保持小心安全驾驶。并按要求停车后回正方向盘、挂</text><text>P</text><text>档、拉手刹、收后视镜、关车窗、关雨刮、收天线等超长加装件,保证车辆在洗车服务中安全。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>) 智能快洗洗车机器人仅能服务低于</text><text>2</text><text>米高的普通轿车,您不能驾驶超过高</text><text>2</text><text>米、宽</text><text>2</text><text>米、长</text><text>5.3</text><text>米的车辆和货车等特殊车辆,强行使用智能快洗洗车机器人。</text>
+						“乐色管家用户小程序”(以下简称“用户小程序”)由陕西智享亿家环保科技有限公司(以下简称“本公司”)提供。用户在登录用户小程序时,均被视为已经仔细阅读本条款并完全同意。凡以任何方式登录本用户小程序,包括但不限于接受用户小程序服务、直接或间接使用本用户小程序资料、第三方链接等,均被视为自愿接受本用户小程序相关声明和用户服务协议的约束。
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>4<text>)在智能快洗洗车机器人服务过程中,用户应始终保持车辆静止,不得移动车辆,严禁上下车或伸出窗外张望,也不能在洗车机内部走动。</text>
+						一、用户小程序使用
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>5<text>) 车龄比较老的车,因为部件老化松动等情况,清洗有可能会损坏,不建议您使用洗车机服务。</text>
+						本用户小程序之设计、信息内容等任何组成部分均不得被复制、抄袭或被任何未经本公司允许的任何商业目的所使用。若本公司怀疑或确定用户行为违法或有损本公司利益,则本公司保留采取相关法律措施的权利,包括但不限于拒绝提供服务、冻结或删除用户帐户等。
 					</view>
 					<view class="MsoNormal">
-						【用户义务】您知悉并承诺,在使用智能快洗所提供的服务的过程中,您应遵守相关法律法规,不应从事如下违反法律法规的规定,影响正常服务提供或损害他人合法利益的行为:
+						二、链接
 					</view>
+						<view class="MsoNormal">(一) 本用户小程序对第三方网站的链接</view>
+						<view class="MsoNormal">
+							本用户小程序必要时将提供第三方经营的其他网站的超级链接或指引服务,或者通过帧联及其他方式在本用户小程序上提供第三方网站相关内容,此“内容”包括但不限于本用户小程序上包含或可获得的任何软件、资料、音频、信息以及本用户小程序上提供的其他任何信息
+						</view>
+						<view class="MsoNormal">
+							对于第三方网站的超级链接或指引服务,仅限于方便之用。本公司保留任何时段终止对第三方网站超级链接的权利。所链接的网站、网站之内容及其网站所提供的产品与服务均不受本公司的控制,因此本公司不对任何该等网站及其内容、产品或服务(包括对第三方网站的进一步链接)负责,并且不对其作出任何认可、建议、批准或介绍。若您一旦登录或使用任何所链接网站,请仔细阅读该网站免责条款,同时自行采取防护措施。由于您自行登录或使用所链接的第三方网站所产生的任何风险和损失,责任自担 ; 除非本公司另行明确规定或同意,否则,本公司将不是您和任何所链网站提供者之间达成的任何协议的当事方。
+						</view>
 					<view class="MsoNormal">
-						<text>(</text>1<text>)不应利用智能快洗平台或相关服务危害国家安全、破坏政治稳定、泄露国家秘密,不侵犯国家、社会、集体利益和第三方的合法权益,不从事违法犯罪活动,不设立用于实施诈骗,传授犯罪方法,制作或者销售违禁物品、管制物品等违法犯罪活动的网站、通讯群组,不利用网络发布涉及实施诈骗,制作或者销售违禁物品、管制物品以及其他违法犯罪活动的信息;</text>
+						本用户小程序上出现对第三方网站的链接并不表示本公司或本用户小程序与其相关联,或已获得合法授权使用,包括但不限于被链接网站中显示的或可通过其链接到的任何商标、商号、标识或著作权等。
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>2<text>)不应制作、发布、复制、查阅和传播、存储、链接下列信息:反对宪法所确定的基本原则的;危害国家安全,泄露国家秘密,颠覆国家政权,推翻社会主义制度,煽动分裂国家,破坏国家统一的;损害国家荣誉和利益的;煽动民族仇恨、民族歧视,破坏民族团结的;破坏国家宗教政策,宣扬邪教和封建迷信的;煽动非法集会、结社、游行、示威、聚众扰乱社会秩序的;捏造、散布谣言,侵犯他人权利,扰乱经济、社会秩序,破坏社会稳定的;散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的;侮辱或者诽谤他人,侵害他人合法权益的;宣扬恐怖主义、极端主义的;违背当地风俗习惯的;含有法律、行政法规禁止的其他内容的;</text>
+						<view class="MsoNormal">(二) 第三方网站对本用户小程序的链接</view>
+						<view class="MsoNormal">
+							第三方网站对本用户小程序的链接,并不必然表示本公司对第三方作出了某种认可、授权、赞助,或表明其属于本公司的关联企业、合资企业、合作企业或业务伙伴。多数情况下,本公司并未意识到或授权第三方提供对本用户小程序的链接。
+						</view>
+						
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>3<text>)不应从事下列危害计算机信息网络安全的活动:对网络服务及相关软硬件设施进行破解、破坏、删除、修改或者增加的;对计算机信息网络中存储或者传输的数据和应用程序进行删除、修改或者增加的;使用软件或硬件等方式窃取他人口令、非法入侵他人计算机系统;故意制作、传播计算机病毒等破坏性程序的;其他危害计算机信息网络安全的活动;</text>
+						三、前瞻性陈述
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>4<text>)不应擅自复制和使用网络上未公开和未授权的文件。除相关著作权人明示同意,不应在网络中擅自破解、传播、下载或复制第三人享有著作权的软件或进行其他任何侵害他人知识产权的活动;</text>
+						本用户小程序可能包含某些前瞻性陈述。这类前瞻性陈述包括但不限于:关于本公司业务经营策略的陈述;关于供应链服务网络扩建计划(包括与之有关的拟作出的资本投资)的陈述;关于计划发展的供应链服务及其相关应用的陈述;关于费用变动对本公司经营业绩的预期影响的陈述;关于竞争对本公司经营业绩的影响的陈述;关于供应链行业未来发展(包括行业结构调整及政府政策的变化)的陈述;以及与本公司未来业务发展、经营及业绩有关的其他陈述。本公司在使用“预期”、“相信”、“预测”、“期望”、“打算”及其他类似词语进行陈述时,旨在表明相关陈述属于前瞻性陈述
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>5<text>)不应私自传播广告信息或以“刷单”等不正当方式帮助他人提升评价或利用评价权利对其他用户、商户实施威胁、敲诈勒索;</text>
+						这些前瞻性陈述本质上具有相当风险和不确定性。本公司不能保证会及时或不断地更新这类前瞻性陈述。这类前瞻性陈述反映的是本公司当前状态下对未来事件的预见或规划,并不属于对未来本公司经营和业务的保证。未来本公司的实际经营和业务很有可能会因诸多客观因素而与某些前瞻性陈述有重大差异,这些因素包括但不限于:供应链行业结构的进一步调整;所需政府批准及许可条件、政策、资本投资的优先程度等监管政策的变化;行业竞争对本公司服务的需求或价格的影响;以及中国内地的政治、经济、文化、法律以及社会各方面情况的变化(包括经济增长、通货膨胀、外汇及可动用的信用额度等政策的变化)
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>6<text>)不应因对智能快洗相关服务的使用行为导致智能快洗卷入政治和公共事件;</text>
+						此外,本公司未来往来供应链的扩建或收缩、资金投资、发展计划和规划,均取决于诸多种因素,包括但不限于是否能以可接受的条款获得足够融资;我们的发展和获得新技术及其应用的能力;是否有合格的管理及技术人员等诸多因素
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>7<text>)不应通过侵犯第三人合法权益、作弊、扰乱系统、实施网络攻击、恶意套现、刷信誉、批量注册、用机器注册智能快洗平台账户、用机器模拟客户端等手段进行交易或参加智能快洗或其所授权的第三方发布的任何活动;</text>
+						四、用户隐私权的保护
 					</view>
+						<view class="MsoNormal">(一) 用户资料的收集</view>
+						<view class="MsoNormal">
+							本用户小程序用户在匿名的状态下即可访问并获取相关信息,本用户小程序请求用户提供相关用户信息之前,本用户小程序会释明用户相关信息用途。本公司承诺仅在与本公司经营活动和经营业务有关的合法目的下,并经用户同意以合法的方式收集必要的用户信息。
+						</view>
+						<view class="MsoNormal">
+							用户使用本用户小程序需注册后方提供的服务,用户需同意以下事项:依本用户小程序注册表之提示提供用户本人真实有效、正确、完整及最新的用户信息,并保证个人信息和资料的适时更新;本企业因用户所提供的不准确、不完整或未及时更新的用户信息给用户造成的任何损害,本公司不承担任何法律和赔偿责任。本公司因用户提供的不准确、不完整或未及时更新的用户信息给本公司造成损害的,本公司保留法律追责权利。
+						</view>
+						<view class="MsoNormal">(二) 用户资料的使用</view>
+						<view class="MsoNormal">
+							本公司有权为内部业务目的使用由您提供的用户信息,这类内部业务目的包括但不限于:促进本公司业务或本公司提供给客户的服务、产品的日常管理和运营;监测本用户小程序的使用及安全情况,实施内部控制、制备数据统计、进行规划和研究等;优化设计、服务和产品;市场调研和推广;记录、核对、确认及维护用户或其他相关人员的联络名单;解决争议、排除问题和执行本法律声明;服务本公司所涉及的任何经营活动或日常业务;或与上述任何一项目的直接相关的其它目的
+						</view>
+						<view class="MsoNormal">
+							基于以上目的,对用户信息有使用权的人,除本公司外,还包括经本公司合法授权、与本公司业务和经营活动有关的本公司的任何附属公司、联营公司、业务伙伴和专业顾问,以及向本公司提供或与本公司业务和经营活动有关的行政管理、电信服务、收付款服务、计算机信息服务或其它服务的任何代理人、承包商或第三方服务提供者。
+						</view>
+						<view class="MsoNormal">(三) 用户资料的披露</view>
+						<view class="MsoNormal">本用户小程序将采取合理有效的安全手段保护用户所提供的用户信息,在未经得用户许可前,本公司承诺并保证绝不将用户的任何个人信息和资料提供给任何无关第三方,但有下列情形之一的除外:</view>
+						<view class="MsoNormal">
+							<text>(</text>1<text>)根据法律、行政法规的规定,有权机关要求提供的</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>2<text>)由于用户对自身信息保密不当,导致用户非公开信息泄露的</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>3<text>)由于网络线路、黑客攻击、计算机病毒等原因造成的用户信息和资料泄露、丢失、被盗用或被篡改的</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>4<text>)为了保护本用户小程序用户的权利或财产</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>5<text>)在紧急的情况下,为了保护本用户小程序及其用户本人或公众安全的</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>6<text>)其他特殊或紧急情况</text>
+						</view>
 					<view class="MsoNormal">
-						<text>(</text>8<text>)未经智能快洗事先书面许可,不应自行或授权、协助任何第三方非法抓取智能快洗所展示的任何内容(“非法抓取”是指采用未经智能快洗认可的程序或者非正常浏览等技术手段获取内容数据的行为)。</text>
+						五、知识产权保护
 					</view>
 					<view class="MsoNormal">
-						【责任承担】如您在使用智能快洗服务过程中涉及违反服务说明或违反用户义务中的一项或多项,则需要对自己的行为承担法律责任。承担法律责任的形式包括但不限于:造成的损失由您自己承担,对受到侵害者(包括智能快洗)进行赔偿。特别的,若您违反用户义务导致智能快洗承担了因您的行为导致的行政处罚或侵权损害赔偿责任等损失(含诉讼费、律师费等相关法律程序费用)后,您还应立即给予智能快洗等额的赔偿。此外,根据具体违法违规情形,智能快洗有权作出独立判断,立即暂停或终止对您提供部分或全部服务,包括锁定、注销、删除帐号等措施。
+						【本用户小程序所载述的域名、商标、商号、信息、文字、图形、图像、声音、链接、软件及所有其它内容或组成部分均由本公司、内容或组成部分提供商或第三方许可人提供。上述内容的知识产权依具体情况分别为本公司、内容或组成部分提供商或第三方许可人所拥有。
 					</view>
 					<view class="MsoNormal">
-						您知悉并理解,如果智能快洗发现您的上述违法违规行为,依据相关法律法规的规定,智能快洗有权或有义务立即停止相关服务,删除或屏蔽相关违规信息、服务评价,并视情况进行调查取证,保存有关记录,或向国家有关机关举报。同时,智能快洗有权自主删除、屏蔽含有该内容的任何数据信息。智能快洗将根据国家相关法律法规要求,对依法删除、屏蔽的数据信息予以记录、保存。
+						未经本公司或商标权人事先书面许可,任何单位或个人不得以任何方式或理由对本用户小程序的商标、商号或标识的任何部分进行使用、复制、修改、传播或与其它产品捆绑使用
 					</view>
 					<view class="MsoNormal">
-						【广告促销】您理解并同意:为向您提供更为细致、贴心的服务,在经过您的事先确认后,智能快洗或智能快洗授权、认可的第三方商家、广告商可能通过您注册时填写的手机号码或者电子邮箱向您发送您可能感兴趣的商品服务的广告宣传信息、促销优惠等商业性信息,其方式和范围可不经向您特别通知而变更;如果您不愿意接收此类信息,则您有权通过智能快洗平台提供的相应的退订方式进行退订。
+						除法律另有规定或双方另有约定外,未经本公司和/或其他权利人事先书面许可,任何人不得以任何形式通过任何方式(包括但不限于电子、机械复印或录制等方式)复制、展示、修改、转让、分发、重新发布、下载、张贴或传输本用户小程序的内容。
 					</view>
 					<view class="MsoNormal">
-						您理解并同意,对上述的相关广告信息,您应审慎判断其真实性和可靠性,除法律法规明确规定外,您应对依该广告信息进行的交易负责。
+						六、免责声明
 					</view>
 					<view class="MsoNormal">
-						【使用目的】除非在特定服务条款或规则中您与智能快洗另有约定或智能快洗另行予以书面同意,您将确保本服务协议下的服务仅为您个人非商业性质的使用。未经智能快洗书面同意,您不得使用未经智能快洗授权的任何插件、外挂或第三方工具对本服务协议下的服务进行干扰、破坏、修改或施加其他影响。
+						本用户小程序所提供的信息,仅供参考之用,不宜用于任何研究或商业用途。本用户小程序并不保证该等信息的准确性、有效性、及时性或完整性。本公司及其员工无需以任何方式就任何信息传递或传送的失误、不准确或错误对用户或任何其他人士负任何直接或间接责任。在法律和本用户小程序允许的范围内,本公司不承担用户或任何第三方就使用或未能使用本用户小程序所提供的信息或任何链接所引致的任何直接、间接的损害赔偿(包括但不限于收益、预期利润的损失或失去的业务、未实现预期的节减)。本公司保留自行决定及修改、更正本用户小程序中任何内容和组成部分的权利(包括任何遗漏或错误的信息和内容)。本公司可以在任何时间对本用户小程序、本用户小程序上所描述的内容、产品、项目、服务或价格作出任何修改,而无需事前通知和事后说明,有需要的情况除外
 					</view>
 					<view class="MsoNormal">
-						五、知识产权
+						本用户小程序、本用户小程序所述的内容、信息和材料以及在本用户小程序上可获得的软件等均“依原样”提供,不包含任何明示或暗示性质的陈述或保证。在法律许可或不禁止范围内,本公司承诺不作出任何明示或暗示性质的陈述和保证,包括但不限于有关安全性、准确性、完整性、适销性、无侵权、适合某项特别目的或没有计算机病毒的保证。您应为使用本用户小程序承担全部责任和风险。
 					</view>
+					<view class="MsoNormal">如发生以下情况,本用户小程序不对用户的直接或间接损失承担法律责任:</view>
 					<view class="MsoNormal">
-						【知识产权】您理解并知悉,除另有书面声明以外,以下信息和内容的知识产权(包括但不限于专利权、著作权、商标权及商业秘密)归智能快洗所有:
+						<text>(</text>1<text>)营业中断</text>
 					</view>
 					<view class="MsoNormal">
-						1. <text>在智能快洗相关服务中所提供的内容和信息(包括但不限于软件、技术、程序、网页、文字、图片、图像、地图、图标、音频、视频、图表、版面设计、电子文档、数据资料等);</text>
+						<text>(</text>2<text>)无法登录本用户小程序,或登录本用户小程序延迟或中断</text>
 					</view>
 					<view class="MsoNormal">
-						2. <text>智能快洗用于提供上述内容和信息的基础设施和平台(包括但不限于软件、网站、应用程序等);</text>
+						<text>(</text>3<text>)数据无法传送、错误传送、毁损、灭失或其他修改</text>
 					</view>
 					<view class="MsoNormal">
-						3. <text>在智能快洗提供相关服务中所使用的各项商标、商业形象、商业标识、技术诀窍、标语、文案等;</text>
+						<text>(</text>4<text>)因处理本用户小程序上对其它用户小程序的链接或本用户小程序上存在对其它用户小程序的链接所遭受的任何种类的损失或损害</text>
 					</view>
 					<view class="MsoNormal">
-						4. <text>智能快洗平台服务的开发、运营、维护等过程中产生的所有数据和信息。</text>
+						<text>(</text>5<text>)就客户使用本用户小程序(包括链接到第三方用户小程序或自第三方用户小程序链接)而可能产生的计算机病毒、系统失灵或功能紊乱</text>
 					</view>
 					<view class="MsoNormal">
-						智能快洗所拥有的上述权利及所提供服务中所包含的任何内容的知识产权均受到法律保护,未经智能快洗事先书面许可,您承诺不应且不应允许或协助任何人以任何形式(包括但不限于通过任何机器人、蜘蛛、截屏等程序或设备)进行使用、出租、出借、分发、展示、复制、修改、链接、转载、汇编、发表、出版、抓取、监视、引用或创造相关衍生作品。
+						<text>(</text>6<text>)本法律声明第四条第三项中规定的六种情形所引起的用户个人资料的披露或泄露</text>
 					</view>
 					<view class="MsoNormal">
-						【用户生成内容】您理解并同意,您在使用智能快洗提供的服务时上传、提交、存储或发布的内容(包括但不限于文字、图片、视频、音频、动画等)均由您原创或已获合法授权。您通过智能快洗上传、提交、存储或发布的任何内容的知识产权归属您或原始著作权人所有,您的上传、提交、存储或发布行为不会侵犯他人的知识产权或其他合法权益。
+						<text>(</text>7<text>)因不可抗力或本公司无法合理控制的其他原因所导致的用户损失</text>
 					</view>
 					<view class="MsoNormal">
-						您知悉、理解并同意,您一旦接受本服务协议,即表明您主动将上述内容的非专属、可转让的财产性权利,如著作权(包括但不限于:复制权、发行权、出租权、展览权、表演权、放映权、广播权、信息网络传播权、摄制权、改编权、翻译权、汇编权以及应当由著作权人享有的其他可转让权利),在全世界范围内永久、免费、独家且不可撤销地授权给智能快洗及其关联公司,智能快洗及其关联公司可基于该等授权使用上述内容(包括但不限于用于商业用途)或向第三方自主进行任何必要的转授权。该等授权、转授权的使用场景包括但不限于当前或其他任何网站、应用程序、产品或移动终端设备等,且智能快洗及其关联公司或智能快洗及其关联公司所授权许可的第三方可通过对上述授权内容进行修改、复制、改编、翻译、汇编或制作,形成衍生产品。在不违反相关法律法规的强制性规定、尊重相关原始授权内容的知识产权的基础上,该等衍生产品的相关知识产权归智能快洗及其关联公司或智能快洗所授权许可的第三方所有。
+						七、服务变更、暂停、中断或终止
 					</view>
 					<view class="MsoNormal">
-						您确认并同意授权智能快洗及其关联公司以自己的名义或委托专业第三方针对有关您上传、提交、存储或发布的内容(含衍生作品)的侵权行为进行独立自主的维权并获得全部赔偿。维权形式包括但不限于:监测侵权行为、发送维权函、提起诉讼或仲裁、调解、和解等。智能快洗及其关联公司有权对维权事宜做出独立决策并予以实施
+						如因系统升级或维护需要而暂停本用户小程序网络服务时,本用户小程序将尽可能事先通告
 					</view>
 					<view class="MsoNormal">
-						您同意,因您通过智能快洗上传、发布的任何内容导致的知识产权侵权问题,您将承担全部责任;如智能快洗及其关联公司,或智能快洗授权的其他服务提供方因第三方知识产权维权而产生损失,您将等额赔偿
+						如发生下列情形之一,本用户小程序有权随时暂停、中断或终止向用户提供本用户小程序用户服务而无需通知,并有权拒绝用户于当前、未来某时段或永久使用本用户小程序所提供服务之全部或任何部分:(1)用户提供任何错误、不实、过时、不完整或具有误导性的信息和资料,或本用户小程序有理由或有依据怀疑前述信息和资料为错误、不实、过时、不完整或具误导性的;(2)用户违反本法律声明或相关使用协议中规定的任何使用规则。
 					</view>
 					<view class="MsoNormal">
-						&nbsp;
+						除上述情形外,本用户小程序同时保留在不事先通知用户的情况下随时暂停、中断或终止部分或全部网络服务的权利,对于所有服务的暂停、中断或终止而造成的任何损失,除法律另有规定或双方另有约定外,本公司不对用户或任何第三方承担任何法律责任。
 					</view>
 					<view class="MsoNormal">
-						本服务协议已经构成《著作权法》第二十五条所规定的书面协议,其效力及于用户在智能快洗平台发布的任何受著作权法保护的作品内容,无论该内容形成于本服务协议签订前还是本服务协议签订后。智能快洗及智能快洗转授权、许可的相关方有权将您在智能快洗平台发表的产品使用体验、产品讨论或图片进行使用或者与其他人合作使用,使用范围包括但不限于网站、电子杂志、杂志、刊物、海报、公众号文章、微信小程序等。
+						八、条款修改
 					</view>
 					<view class="MsoNormal">
-						【软件使用】在使用智能快洗相关客户端的过程中,您可能需要下载特定软件。为了改善用户体验、修复漏洞、保障安全性等考虑,智能快洗有权对软件进行更新,您应该将相关软件更新至最新版本,否则智能快洗将不保证您能正常使用相关软件。
+						本公司保留在任何时间自行修改、增删本法律声明中的任何内容和条款的权利。您每次登录或使用本用户小程序时,均视为同意接受当时已生效的用户声明条款的制约。因此,建议您每次登录或使用本用户小程序时查看本法律声明是否修订或增删及修订或增删的情况
 					</view>
 					<view class="MsoNormal">
-						如果您从未经智能快洗授权的第三方获取软件或与该软件名称相同的安装程序,智能快洗无法保证该软件能够正常使用,由此造成的相关损失,智能快洗不予负责。
+						九、法律适用与司法管辖
 					</view>
 					<view class="MsoNormal">
-						【软件使用禁止性规定】除非智能快洗书面许可,您在使用智能快洗的软件时不得从事下列任一行为:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)删除、编辑或遮挡软件及其副本上关于著作权、商标或其他权利标识或标记的信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)复制、发布、出售或出租软件或其任何部分;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)对软件进行反向工程、反向汇编、反向编译,或者以其他方式尝试挖掘、提取软件的源代码;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>4<text>)其他对软件、软件所产生的数据所进行的任何增加、删减、变动的任何行为,包含制作、利用、授权各种第三方外挂、插件、系统进行上述行为。</text>
-					</view>
-					<view class="MsoNormal">
-						六、协议的终止
-					</view>
-					<view class="MsoNormal">
-						【协议终止情形】本服务协议于以下任一情形下终止:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)智能快洗有权依据本服务协议约定,收回、注销用户账号,此情形下,本服务协议于账号收回、注销之日终止;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)在满足智能快洗平台公示的账号注销条件时,您通过网站自助服务或智能快洗的客服注销智能快洗的用户账号,本服务协议于账号注销之日终止。您理解并同意,您已认真阅读、认可《智能快洗隐私政策》,并已了解、同意相关用户注销流程及注销后的权利义务安排;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)智能快洗有权根据自身商业安排经过合理的提前通知终止全部智能快洗平台服务,本服务协议于智能快洗平台全部服务依法定程序及方式终止之日终止。</text>
-					</view>
-					<view class="MsoNormal">
-						本服务协议终止后,智能快洗将无法继续向您提供任何服务或履行任何其他义务,包括但不限于为您保留或向您披露其原智能快洗账号中的任何信息,向您或第三方转发任何未曾阅读或发送过的信息等。
-					</view>
-					<view class="MsoNormal">
-						<text>本服务协议的终止不影响第五条知识产权条款以及其他根据其内容应继续有效</text> <text>的条款的有效性,也不影响本服务协议终止前各方的相关权利和义务,包括但不</text> <text>限于守约方依据本服务协议向违约方追究相应的违约责任。</text>
-					</view>
-					<view class="MsoNormal">
-						七、通知与送达
-					</view>
-					<view class="MsoNormal">
-						您知悉并认可,智能快洗可视情况通过下列任意一种或几种方式向您通知重要信息:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)向您注册时所提交的电子邮箱地址发送电子信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)向您注册时所提交的手机号码发送电子信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)向您提供的实际地址进行寄送纸质载体信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>4<text>)在网站或客户端显著位置刊登电子信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>5<text>)向智能快洗网站或相应客户端的账户的站内信或其他即时通信客户端发送电子信息。</text>
-					</view>
-					<view class="MsoNormal">
-						上述电子信息在发送成功或刊登完成后即视为送达。相关纸质载体的发送以相关邮寄凭证上的邮寄日期后的第五个自然日视为送达。
-					</view>
-					<view class="MsoNormal">
-						上述送达方式同样可适用于相关仲裁或司法程序(含起诉、审理、执行等各阶段)。
-					</view>
-					<view class="MsoNormal">
-						您应当保证所提供的联系方式是准确、有效的,并进行适时更新,如因提供的联系方式不准确或怠于更新等不可归责于智能快洗的原因,导致相关通知、文件、文书无法送达或及时送达,您将自行承担由此可能产生的法律后果。
-					</view>
-					<view class="MsoNormal">
-						八、不可抗力或其他免责事由
-					</view>
-					<view class="MsoNormal">
-						【不可抗力】您理解并同意,在使用本服务的过程中,可能会遇到不可抗力等风险因素,使本服务协议下的服务发生中断或终止。不可抗力是指不能预见、不能克服并不能避免且对一方或双方造成重大影响的客观事件,包括但不限于信息网络设备维护、信息网络连接故障、电脑、通讯或其他系统的故障、电力故障、罢工、劳动争议、暴乱、起义、骚乱、生产力或生产资料不足、火灾、洪水、风暴、爆炸、战争、政府行为、法律法规变动、司法行政机关的命令、其他不可抗力或第三方的不作为而造成的不能服务或延迟服务等行为。出现上述情况时,智能快洗将努力在第一时间与相关部门配合,及时进行修复,但是由此给您造成的损失,智能快洗在法律允许的范围内免责。
-					</view>
-					<view class="MsoNormal">
-						【其他免责事由】您理解并同意,在法律允许的范围内,智能快洗对以下事由所导致的服务中断或终止不承担责任:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)受到计算机病毒、木马或其他恶意程序、黑客攻击的破坏;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)用户或智能快洗的电脑软件、系统、硬件和通信线路出现故障;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)用户操作不当;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>4<text>)用户通过非智能快洗授权的方式使用本服务;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>5<text>)其他智能快洗无法控制或合理预见的情形。</text>
-					</view>
-					<view class="MsoNormal">
-						【信息真实性】智能快洗提示您,在使用本服务的过程中,您可能会遇到网络信息或其他用户行为带来的风险,该等风险包含他人匿名或冒名的含有威胁、诽谤、令人反感、非法、误导、欺骗等任何信息或行为所造成任何心理、生理上的伤害或经济损失。请您仔细甄别,并在遇到上述相关不法行为时及时向智能快洗或有关机关举报或投诉。智能快洗将对相关内容开展日常检查并在收到举报或投诉时进行相应处理,但请您注意,智能快洗不对非智能快洗所发出或刊登的任何信息的真实性、适用性、合法性承担责任,也不对因第三方侵权行为给您造成的损害负责。
-					</view>
-					<view class="MsoNormal">
-						【责任限制】除非另有明确书面说明,在符合法律法规规定的情况下,智能快洗不对其网站和客户端上的信息、内容、材料、产品或服务做任何形式的明示或默示的声明或担保。
-					</view>
-					<view class="MsoNormal">
-						九、管辖、法律适用与争议解决
-					</view>
-					<view class="MsoNormal">
-						本服务协议的成立、生效、履行、解释与纠纷解决,适用中华人民共和国大陆地区法律法规,并且排除一切冲突法规定的适用。
-					</view>
-					<view class="MsoNormal">
-						如因某项具体服务中的产品或服务问题导致您与智能快洗间出现纠纷,您同意,该等纠纷将由适用于该项具体服务的服务条款或规则中所规定的争议解决地的有管辖权人民法院受理。就本服务协议而言,如您因本服务协议文本与智能快洗产生争议纠纷,您同意交由本服务协议签订地有管辖权人民法院受理。本服务协议签订地为上海市杨浦区。
-					</view>
-					<view class="MsoNormal">
-						十、其他
-					</view>
-					<view class="MsoNormal">
-						【关键词】本服务协议各条款前所列关键词仅供帮助理解条款主旨及快速定位查询条款所用,不能代替条款的任何内容,亦不作为解释条款的依据,智能快洗建议您仔细阅读各条款的具体表述,以维护您的合法权益。
-					</view>
-					<view class="MsoNormal">
-						【可分性】如果本服务协议中任何一条被视为废止、无效或因任何理由不可执行,该条应视为可分的且并不影响任何其余条款的有效性和可执行性。
-					</view>
-					<view class="MsoNormal">
-						再次感谢您的耐心阅读!
-					</view>
-					<view style="text-align: right;">
-						陕西山海高科信息技术有限公司
-					</view>
-					<view style="text-align: right;">
-						2020年8月
+						本法律声明的制定、执行、解释及争议问题的解决和处理均适用中华人民共和国法律、法规。双方因使用本用户小程序所产生的争议,若协商不成,任何一方可向本公司所在地人民法院提起诉讼。
 					</view>
 				</view>
 			</view>
 		</view>
-		<view class="footer" @click="goBack" v-if="!hideZysx">
-			我已阅读并同意无人洗车《注意事项及服务协议》
-		</view>
 	</view>
 </template>
 
@@ -361,26 +161,14 @@
 		},
 		data() {
 			return {
-				hideZysx: false
 			}
 		},
 		onLoad(option) {
-			// 从个人中心打开的
-			if(option.fromPage == 'usercenter'){
-				this.hideZysx = true
-				uni.setNavigationBarTitle({
-					title: "服务协议"
-				})
-			}
+			uni.setNavigationBarTitle({
+				title: "服务协议"
+			})
 		},
 		methods: {
-			// 点击已阅读返回上一页
-			goBack () {
-				// 出发已阅读事件
-				uni.$emit('read',{msg:'read'})
-				uni.navigateBack()
-			}
-			
 		}
 	}
 </script>

+ 623 - 0
pages/cart/cart.vue

@@ -0,0 +1,623 @@
+<template>
+	<view class="cart-pages">
+		<view class="cart-bar" v-if="cartList.length>0">
+			<view>共<text class="special-val">{{count}}</text>件商品</view>
+			<view @click="editCart">
+				<text class="edit" v-if="!isEdit">管理</text>
+				<text class="save" v-else>完成</text>
+			</view>
+		</view>
+		<view class="goods-list">
+			<!-- 按分类显示 -->
+			<view class="goods-class-box" v-for="(item,cindex) in cartList" :key="item.goodsTypeNo">
+				<view class="goods-class-head">
+					<view @click="goodsClasChange(cindex)">
+						<view 
+						class="check-button" 
+						v-if="isSxGoodAll(item).length||isEdit"
+						:class="item.checked?'checked':'uncheck'">
+						</view>
+						<view v-else class="check-button disabled"></view>
+						<view class="goodClsName">
+							{{item.name}}
+						</view>
+					</view>
+					<view class="des" v-if="item.goldLimit>0">
+						<view>商品满<text>{{item.goldLimit}}</text></view>
+						<image mode="scaleToFill" style="width: 26rpx;height: 26rpx;" src="/static/ledou.png"></image>
+						<view>才可购买</view>
+					</view>
+				</view>
+				<view class="goods-class-list">
+					<!-- 商品列表 -->
+					<view class="goods-item" v-for="(good,index) in item.shoppingCartGoodsList" :key="good.id">
+						<view class="checkbox" 
+						   @click="goodsChange(good,index,cindex)">
+							<view
+							class="check-button" 
+							v-if="isSxGood(good)||isEdit"
+							:class="good.checked?'checked':'uncheck'">
+							</view>
+							<view v-else class="check-button disabled"></view>
+						</view>
+						<view class="goods-info">
+							<view class="goods-imgs">
+								<view v-if="good.goods.inventoryQty==0||good.goods.state == 0" class="goods-staus">
+									<text v-if="good.goods.state == 0">已下架</text>
+									<text v-if="good.goods.state == 1&&good.goods.inventoryQty==0">已售罄</text>
+								</view>
+								<u-image border-radius="12" width="158rpx" height="140rpx" :src="good.goods.homeImage+'?x-oss-process=image/resize,m_pad,h_140,w_158,color_ffffff'"></u-image>
+							</view>
+							<view class="goods-text">
+								<view class="good-name">{{good.goods.name}}</view>
+								<view class="goods-price">
+									<view>
+										<text>{{good.goods.sellGold}}</text>
+										<image mode="scaleToFill" style="width: 30rpx;height: 30rpx;"src="/static/ledou.png"></image>
+									</view>
+									<view v-if="good.goods.inventoryQty>0&&good.goods.state==1">
+										<uni-numbers-box @change="goodsNumsChange()" :index="cindex+'-'+index" :value="good.buyQty" :max="good.goods.inventoryQty" :min="1"></uni-numbers-box>
+									</view>
+									<view v-else>
+										<view style="width: 100rpx;text-align: center;">×{{good.buyQty}}</view>
+									</view>
+								</view>
+								<view class="goods-kucun" v-if="good.goods.state == 1&&good.goods.inventoryQty==0">库存不足</view>
+								<view class="goods-kucun" v-else>库存:<text>{{good.goods.inventoryQty}}</text></view>
+							</view>
+						</view>
+					</view>
+					<!-- 小计 -->
+					<view class="goods-class-heji">
+						<view>合计:<text>{{item.total}}</text></view>
+						<image mode="scaleToFill" style="width: 30rpx;height: 30rpx;"src="/static/ledou.png"></image>
+					</view>
+				</view>
+			</view>
+			<view class="noData" v-if="!loading&&cartList.length==0">
+				<u-empty mode="car">
+					<view slot="bottom">
+						<u-button size="mini" @click="toBuy">去选商品</u-button>
+					</view>
+				</u-empty>
+			</view>
+			<view class="loading" v-if="loading">
+				<u-loading :show="loading"></u-loading>
+				<view>正在加载...</view>
+			</view>
+		</view>
+		<view class="cart-submit" v-if="cartList.length>0">
+			<view @click="checkAllChange()">
+				<view 
+				class="check-button" 
+				:class="checkAll?'checked':'uncheck'">
+				</view>
+				<view class="checkAll">
+					{{checkAll?'取消':'全选'}}
+				</view>
+			</view>
+			<view v-if="!isEdit">
+				<view class="heji">
+					<view>总计:</view>
+					<text>{{totalPrice}}</text>
+					<u-image mode="scaleToFill" width="35rpx" height="35rpx" src="/static/ledou.png"></u-image>
+				</view>
+				<u-button size="mini" :custom-style="toOrderButton" type="error" @click="toOrder">立即下单</u-button>
+			</view>
+			<view v-else>
+				<u-button size="mini" :custom-style="toOrderButton" type="error" @click="delGoods">删除</u-button>
+			</view>
+		</view>
+		<!-- 弹框提示 -->
+		<u-popup v-model="showMsg" border-radius="15" closeable mode="center" width="500rpx">
+			<view style="padding: 40rpx;line-height: 40rpx;font-size: 28rpx;">
+				<view style="text-align: center;font-size: 32rpx;margin-bottom: 20rpx;">提示</view>
+				<view v-for="item in msgContent" :key="item.id">{{item.message}}</view>
+			</view>
+		</u-popup>
+	</view>
+</template>
+<script>
+	import {
+		getCartList,
+		deleteGoodsFormCart,
+		updateGoodsBuyQty
+	} from '@/api/shoppingCart.js'
+	export default {
+		data() {
+			return {
+				toOrderButton: {
+					borderRadius:'100rpx',
+					fontSize:'30rpx',
+					width: '200rpx',
+					height: '80rpx'
+				},
+				checkAll: false,// 全选
+				isEdit: false, // 是否编辑模式
+				cartList: [], // 商品列表
+				loading: false,
+				showMsg: false,
+				msgContent: []
+			};
+		},
+		computed: {
+			// 用户信息
+			userData(){
+				return this.$store.state.vuex_userData
+			},
+			// 总数
+			count() {
+				let arr = this.cartList
+				let count = 0
+				arr.map(item=>{
+					count = count + item.shoppingCartGoodsList.length
+					if(!item.hasOwnProperty("checked")){
+						item.checked = false
+					}
+					item.shoppingCartGoodsList.map(goods=>{
+						if(!goods.hasOwnProperty("checked")){
+							goods.checked = false
+						}
+					})
+				})
+				return count
+			},
+			// 总计
+			totalPrice(){
+				let arr = this.cartList
+				let total = 0
+				arr.map(item=>{
+					let xj = 0
+					item.shoppingCartGoodsList.map(a =>{
+						if(a.checked){
+							total = total + a.buyQty * a.goods.sellGold
+							xj = xj + a.buyQty * a.goods.sellGold
+						}
+					})
+					item.total = xj
+				})
+				return total
+			},
+		},
+		onLoad() {
+			// 获取购物车数据
+			this.loading = true
+			this.getCartList()
+		},
+		methods: {
+			// 计算购物车数量
+			getCarCount(){
+				let arr = this.$store.state.vuex_cartList || []
+				let count = 0
+				arr.map(item=>{
+					count = count + item.shoppingCartGoodsList.length
+				})
+				this.$u.vuex('vuex_cartNums', count)
+			},
+			// 查询购物车
+			getCartList(){
+				getCartList({}).then(res => {
+					if(res.status == 200){
+						this.$u.vuex('vuex_cartList', res.data)
+						this.cartList = JSON.parse(JSON.stringify(res.data))
+						this.getCarCount()
+						// 默认全选
+						if(!this.isEdit){
+							this.checkAllChange()
+						}
+					}
+					this.loading = false
+					setTimeout(()=>{
+						uni.hideLoading()
+					},500)
+				})
+			},
+			// 去选商品
+			toBuy(){
+				uni.switchTab({
+					url:"/pages/goods/index"
+				})
+			},
+			// 获取当前选择的商品, type: 0 删除,1 立即下单
+			getCheckGoods(type){
+				let arr = this.cartList
+				let goods = []
+				arr.map(item=>{
+					item.shoppingCartGoodsList.map(a =>{
+						if(a.checked){
+							goods.push(type?a:a.id)
+						}
+					})
+				})
+				return goods
+			},
+			// 设置每个分类下的商品选中状态
+			setClsGoodStatus(item,checked){
+				item.shoppingCartGoodsList.map(good=>{
+					// 已下架,已删除,已销完的不选
+					if((good.goods.inventoryQty==0||good.goods.state == 0) && !this.isEdit){
+						good.checked = false
+					}else{
+						good.checked = checked
+					}
+				})
+			},
+			// 全选 或 取消全选
+			checkAllChange() {
+				let arr = this.cartList
+				arr.map(item=>{
+					item.checked = !this.checkAll
+					this.setClsGoodStatus(item,!this.checkAll)
+				})
+				this.checkAll = !this.checkAll
+				arr.splice()
+			},
+			// 每个分类的全选
+			goodsClasChange(index){
+				let item = this.cartList[index]
+				item.checked = !item.checked
+				this.setClsGoodStatus(item,item.checked)
+				// 判断是否全选
+				this.hasCheckAll()
+			},
+			// 商品选择
+			goodsChange(good,index,cindex){
+				let goods = this.cartList[cindex] // 当前分类
+				good.checked = !good.checked
+				// 判断当前分类是否全选
+				this.clasGoodsHasCheckAll(goods)
+			},
+			// 判断某个商品是否失效
+			isSxGood(item){
+				return !(item.goods.inventoryQty==0||item.goods.state == 0||item.goods.delFlage == 0) || this.isEdit
+			},
+			// 判断分类下商品是否都是已失效
+			isSxGoodAll(row){
+				return row.shoppingCartGoodsList.filter(item => {
+					return this.isSxGood(item)
+				})
+			},
+			// 判断某个分类是否全选
+			clasGoodsHasCheckAll(row){
+				let goods = this.isSxGoodAll(row)
+				let len = goods.length
+				let clen = 0
+				if(len==0){
+					return
+				}
+				goods.map(item=>{
+					if(item.checked){
+						clen = clen + 1
+					}
+				})
+				row.checked = clen == len
+				this.cartList.splice()
+				// 判断是否全选
+				this.hasCheckAll()
+			},
+			// 是否全选
+			hasCheckAll(){
+				let list = this.cartList
+				let len = list.length
+				let clen = 0
+				list.map(item => {
+					if(item.checked){
+						clen = clen + 1
+					}
+				})
+				this.checkAll = clen == len
+				list.splice()
+			},
+			// 编辑购物车
+			editCart(){
+				this.isEdit = !this.isEdit
+				this.checkAll = true
+				this.checkAllChange()
+			},
+			// 判断当前分类下的商品总和是否满足规则
+			hasZgjindu(){
+				let result = []
+				let list = this.cartList.filter(item=>item.total>0)
+				for(let i=0;i<list.length;i++){
+					let item = list[i]
+					let ret = 0
+					item.shoppingCartGoodsList.map(good=>{
+						if(good.checked){
+							ret = ret + good.goods.sellGold * good.buyQty
+						}
+					})
+					result.push({id:item.goodsTypeNo,val:ret >= item.goldLimit,message:`[${item.name}]的商品合计满${item.goldLimit}乐豆才可购买`})
+				}
+				
+				console.log(result)
+				return result.filter(item=>!item.val)
+			},
+			// 立即下单
+			toOrder(){
+				let goods = this.getCheckGoods(1)
+				if(this.userData.currentGold >= this.totalPrice){
+					if(goods.length){
+						// 判断是否满足规则
+						let a = this.hasZgjindu()
+						if(a.length==0){
+							this.$u.vuex("vuex_toOrderList",goods)
+							uni.redirectTo({
+								url:"/pages/toOrder/index?orderForm=SHOPPING_CAR"
+							})
+						}else{
+							this.showMsg = true
+							this.msgContent = a
+						}
+					}else{
+						uni.showToast({
+							title:"请选择商品",
+							icon:"none"
+						})
+					}
+				}else{
+					uni.showToast({
+						title:"你的乐豆余额不足",
+						icon:"none"
+					})
+				}
+			},
+			// 删除购物车商品
+			delGoodFormCart(ids){
+				uni.showLoading({
+					mask: true,
+					title: "正在删除..."
+				})
+				deleteGoodsFormCart({idList:ids}).then(res => {
+					if(res.status == 200){
+						// 刷新购物车
+						this.getCartList()
+					}else{
+						uni.hideLoading()
+					}
+				})
+			},
+			// 删除商品
+			delGoods(){
+				let ids = this.getCheckGoods(0)
+				if(ids.length){
+					this.delGoodFormCart(ids)
+				}else{
+					uni.showToast({
+						title:"请选择要删除的商品",
+						icon:"none"
+					})
+				}
+			},
+			// 更新商品数量
+			updateGoodsBuyQty(item){
+				uni.showLoading({
+					mask: true,
+					title: "更新数量中..."
+				})
+				updateGoodsBuyQty(item).then(res => {
+					uni.hideLoading()
+				})
+			},
+			// 更改商品数量
+			goodsNumsChange(val,id){
+				console.log(val,id)
+				let cindex = id.split('-')[0]
+				let index = id.split('-')[1]
+				let item = this.cartList[cindex]
+				let row = item.shoppingCartGoodsList[index]
+				row.buyQty = val
+				this.updateGoodsBuyQty({id:row.id,buyQty:row.buyQty})
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+page{
+	height: 100%;
+}
+.cart-pages{
+	width: 100%;
+	height: 100%;
+	display: flex;
+	flex-direction: column;
+	.noData{
+		padding-top: 150upx;
+	}
+	.loading{
+		display: flex;
+		justify-content: center;
+		padding: 150rpx 0;
+	}
+	.cart-bar{
+		display: flex;
+		justify-content: space-between;
+		.edit{
+			color: #666;
+		}
+		.save{
+			color: #00aaff;
+		}
+		.special-val{
+			color: #FA3534;
+			font-weight: bold;
+			margin: 0 10rpx;
+		}
+		>view{
+			padding:20upx;
+		}
+	}
+	.check-button{
+		width: 40rpx;
+		height: 40rpx;
+	}
+	.checked{
+		background: url('/static/checked.png') no-repeat center center;
+		background-size: 100% 100%;
+	}
+	.uncheck{
+		background: url('/static/uncheck.png') no-repeat center center;
+		background-size: 100% 100%;
+	}
+	.disabled{
+		border:2rpx solid #EEEEEE;
+		border-radius: 100rpx;
+		background: #F8F8F8;
+	}
+	.goods-list{
+		flex-grow: 1;
+		overflow: auto;
+		.goods-class-box{
+			background: #FFFFFF;
+			box-shadow: 1px 1px 3px #eee;
+			margin-bottom: 20upx;
+			.goods-class-head{
+				display: flex;
+				align-items: center;
+				padding: 20upx;
+				border-bottom: 1px solid #F8F8F8;
+				justify-content: space-between;
+				> view{
+					&:first-child{
+						display: flex;
+						align-items: center;
+					}
+					.goodClsName{
+						font-size: 30rpx;
+						margin-left: 10rpx;
+					}
+				}
+				.des{
+					display: flex;
+					align-items: center;
+					font-size: 26upx;
+					color: #999;
+					text{
+						color: #FA3534;
+					}
+				}
+			}
+		}
+		
+		.goods-item{
+			padding: 20upx;
+			display: flex;
+			align-items: center;
+			border-bottom: 1px solid #F8F8F8;
+			&:last-child{
+				border: 0;
+			}
+			.checkbox{
+				width: 60rpx;
+				overflow: hidden;
+				height: 140rpx;
+				display: flex;
+				align-items: center;
+			}
+			.goods-info{
+				display: flex;
+				align-items: center;
+				flex-grow: 1;
+				.goods-imgs{
+					position: relative;
+					border:1px solid #eee;
+					border-radius: 10rpx;
+					.goods-staus{
+						width: 100%;
+						height: 100%;
+						position: absolute;
+						z-index: 10000;
+						border-radius: 15rpx;
+						background: rgba($color: #000000, $alpha: 0.4);
+						text-align: center;
+						line-height: 140rpx;
+						left: 0;
+						top: 0;
+						color: #eee;
+						font-size: 24upx;
+						font-weight: bold;
+					}
+				}
+				.goods-text{
+					padding-left: 20upx;
+					flex-grow: 1;
+					.good-name{
+						font-weight: bold;
+						word-break: break-all;
+					}
+				}
+			}
+			.goods-kucun{
+				padding-top: 10rpx;
+				font-size: 22rpx;
+				text{
+					color: #999;
+				}
+			}
+			.goods-price{
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				padding-top: 10upx;
+				>view{
+					&:first-child{
+						font-size: 22upx;
+						display: flex;
+						align-items: center;
+						text{
+							color: red;
+							font-size: 32upx;
+							margin-right: 6upx;
+							font-weight: bold;
+						}
+					}
+				}
+			}
+		}
+		.goods-class-heji{
+			padding: 20upx;
+			display: flex;
+			align-items: center;
+			justify-content: flex-end;
+			font-size: 24rpx;
+			text{
+				color: red;
+			}
+		}
+	}
+	.cart-submit{
+		background: #FFFFFF;
+		box-shadow: 1px 1px 3px #eee;
+		border-top: 1px solid #eee;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		>view{
+			display: flex;
+			align-items: center;
+			.checkAll{
+				margin-left: 10rpx;
+			}
+			&:first-child{
+				padding: 10upx 20upx;
+			}
+			&:last-child{
+				padding: 10upx 20upx;
+				font-size: 26upx;
+				> view{
+					padding-right: 30upx;
+				}
+				.heji{
+					display: flex;
+					align-items: center;
+					font-weight: bold;
+					text{
+						color: red;
+						font-size: 40upx;
+					}
+				}
+			}
+		}
+	}
+}
+</style>

+ 84 - 0
pages/checkOut/checkFinish.vue

@@ -0,0 +1,84 @@
+<template>
+	<view class="page-cont">
+		<view class="icon-cont">
+			<u-icon class="icon" name="checkmark" color="#fff" size="80"></u-icon>
+			<view>支付成功</view>
+			<view class="num-cont">
+				<view>
+					{{payNum}}
+				</view>
+				<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+			</view>
+		</view>
+		<view class="back-btn">
+			<u-button :custom-style="btnStyle" @click="toHome">返回首页</u-button>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			btnStyle: {
+				backgroundColor: '#07c160',
+				color:'#fff'
+			},
+			payNum: 0 //支付乐豆数
+		}
+	},
+	onLoad(option) {
+		console.log(option,'option')
+		this.payNum = option.num
+	},
+	methods: {
+		// 返回首页
+		toHome() {
+			uni.reLaunch({
+			    url: '/pages/index/index'
+			})
+		}
+	}
+}
+</script>
+
+<style lang="less">
+	page{
+		height: 100%;
+	}
+	.page-cont{
+		width: 100%;
+		height: 100%;
+		background-color: #fff;
+		padding: 0 40upx;
+		.icon-cont{
+			width: 100%;
+			height: 400upx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			.num-cont{
+				display: flex;
+				color: red;
+				font-size: 36upx;
+				font-weight: 600;
+			}
+			>view{
+				font-size: 30upx;
+				margin-top: 40upx;
+			}
+		}
+		.icon{
+			width: 120upx;
+			height: 120upx;
+			background-color: #07c160;
+			display: flex;
+			justify-content: center;
+			border-radius: 50%;
+		}
+		.back-btn{
+			margin-top: 40upx;
+		}
+	}
+</style>

+ 274 - 0
pages/checkOut/checkOut.vue

@@ -0,0 +1,274 @@
+<template>
+	<view class="page-content">
+		<view class="content">
+			<u-field
+				class="field-item"
+				:value="store.name"
+				disabled
+				input-align="right"
+				label="收取门店"
+			>
+			</u-field>
+			<u-field
+				v-model="remarks"
+				label="备注"
+				input-align="right"
+				auto-height
+				:maxlength="10"
+				placeholder="请填写备注(最多10个字符)"
+			>
+			</u-field>
+			<view class="num-cont">
+				<text class="u-required">支付数量</text>
+				<view class="num-input">
+					<u-input v-model="number" input-align="right" type="number" placeholder="请输入数量" />
+					<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+				</view>
+			</view>
+		</view>
+		<view class="pay-btn">
+			<view class="total">
+				<text>{{number||0}}</text>
+				<view><u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image></view>
+			</view>
+			<view>
+				<u-button @click="handlePay" type="success" >确认支付</u-button>
+			</view>
+		</view>
+		 <!-- 确认支付弹窗 -->
+		 <u-popup mode="center" :mask-close-able="false" closeable @close="closeModal" negative-top="300" v-model="showPayModal" width="600rpx" >
+			<view class="slot-content">
+				<view class="slot-title">请输入支付密码</view>
+				<view class="text-cont">
+					<view>
+						<text>收取门店:</text>
+						<text>{{store.name||'--'}}</text>
+					</view>
+					<view class="num-text">
+						<text>支付数量:</text>
+						<view>
+							<text class="num-big">{{number}}</text>
+							<u-image mode="scaleToFill" width="30rpx" height="30rpx" src="/static/ledou.png"></u-image>
+						</view>
+					</view>
+					<view>
+						<text>备&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注:</text>
+						<text>{{remarks||'无'}}</text>
+					</view>
+				</view>
+				<view class="footer">
+					<input v-model="password" 
+					type="password" 
+					:focus="focus"
+					placeholder="请输入支付密码" 
+					:maxlength="30"
+					@confirm="confirm"
+					/>
+				</view>
+				<view class="fot-btn">
+					<u-button @click="confirm" type="success" >确认支付</u-button>
+				</view>
+			</view>
+		</u-popup>
+		
+		<!-- 提示用户设置支付密码 -->
+		<u-modal v-model="showSetPswModal" 
+		content="请先设置支付密码,才能使用乐豆" 
+		show-cancel-button 
+		confirm-text="去设置" 
+		cancel-text="暂时放弃"
+		@confirm="toSetPwd"
+		@cancel="showSetPswModal=false"
+		></u-modal>
+	</view>
+</template>
+
+<script>
+	import { sellerReceive } from '@/api/user.js'
+	import { existPayPwd } from '@/api/order.js'
+	export default{
+		data() {
+			return {
+				showSetPswModal: false,
+				store: null, // 门店信息
+				remarks: '', // 备注
+				number: '',  // 支付数量
+				showPayModal: false, // 支付弹窗
+				password: '', // 支付密码
+				partnerNo: '', // 销售商编号
+				currentGold: 0, //用户当前拥有乐豆数
+				focus: false
+			}
+		},
+		onLoad(opts) {
+			this.currentGold = this.$store.state.vuex_userData.currentGold
+			console.log(this.currentGold,'currentGold')
+			this.store = JSON.parse(decodeURIComponent(opts.store))
+			this.partnerNo = this.store.officialPartnerNo
+			// console.log(this.store,'22222')
+		},
+		methods: {
+			// 跳转到设置支付密码页
+			toSetPwd () {
+				uni.navigateTo({
+					url:"/pages/userCenter/userInfo/smsVerification"
+				})
+			},
+			// 确认支付
+			handlePay() {
+				if (!this.number) {
+					uni.showToast({
+						title: '请输入支付数量',
+						icon: 'none'
+					})
+				} else {
+					if (this.number>this.currentGold) {
+						uni.showToast({
+							title: '您当前余额不足!',
+							icon: 'none'
+						})
+						return false
+					}
+					existPayPwd().then(res => {
+						console.log(res,'rrrrrr')
+						if(res.status == 200) {
+							// 设置过支付密码,输入密码
+							if(res.data) {
+								this.showPayModal = true
+								setTimeout(()=>{
+									this.focus = true
+								},300)
+							} else {
+								// 没设置过支付密码,提示设置密码
+								 this.showSetPswModal = true
+							}
+						}
+					})
+				}
+			},
+			// 关闭弹窗
+			closeModal() {
+				this.showPayModal = false
+				this.password = ''
+			},
+			// 输入密码完成 支付
+			confirm(e) {
+				if(this.password == ''){
+					uni.showToast({
+						title: '请输入支付密码',
+						icon: 'none'
+					})
+					return
+				}
+				let data = {
+					"payPassword": this.password,
+					"changeNum": this.number,
+					"remarks": this.remarks,
+					"officialPartnerNo": this.partnerNo
+				}
+				sellerReceive(data).then(res => {
+					console.log(res)
+					if(res.status == 200){
+						uni.redirectTo({
+							url: '/pages/checkOut/checkFinish?num='+this.number
+						})
+					} 
+				})
+			}
+		},
+	}
+</script>
+
+<style lang="less">
+	page{
+		height: 100%;
+	}
+	.page-content{
+		width: 100%;
+		height: 100%;
+		padding: 20upx;
+		background-color: #f8f8f8;
+		.content{
+			background-color: #fff;
+		}
+		.num-cont{
+			width: 100%;
+			padding: 16upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.num-input{
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				>u-input {
+					width: 300upx;
+				}
+			}
+		}
+		.pay-btn{
+			padding: 0 30upx;
+			.total {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				padding: 60upx 0;
+				text{
+					font-size: 48upx;
+					font-weight: 600;
+					color: red;
+				}
+			}
+		}
+	}
+	.slot-content{
+		padding: 30upx 0;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-between;
+		.slot-title{
+			font-size: 36rpx;
+		}
+		.text-cont{
+			width: 100%;
+			margin-top: 20upx;
+			// font-size: 20rpx;
+			>view {
+				padding: 15upx 60upx;
+				display: flex;
+				>text{
+					&:last-child {
+						flex: 1;
+						padding-left: 30upx;
+					}
+				}
+				.num-big{
+					font-size: 36upx;
+					color: red;
+					padding-left: 30upx;
+					font-weight: 600;
+				}
+			}
+			.num-text{
+				align-items: center;
+				>view {
+					display: flex;
+					align-items: center;
+				}
+			}
+			
+		}
+		.footer{
+			width: 80%;
+			border-bottom: 1px solid #b1b1b1;
+			>input {
+				text-align: center;
+				padding: 10upx 0;
+			}
+		}
+		.fot-btn{
+			margin-top: 30upx;
+		}
+	}
+</style>

+ 0 - 665
pages/getOrder/getOrder.vue

@@ -1,665 +0,0 @@
-<template>
-	<view class="order-content">
-		<view class="step">
-			<uni-steps :options="[{title: '停车'}, {title: '检查'}, {title: '下单'}]" :active="stepIndex" active-color="rgb(255,0,0)"></uni-steps>
-		</view>
-		<view class="step-content">
-			<!-- 停车 -->
-			<view v-if="stepIndex===0" class="step-item step-one">
-				<text>请确认车辆是否停到指定位置</text>
-				<image src="/static/img/step-one.png" mode="aspectFit"></image>
-			</view>
-			<!-- 检查 -->
-			<view v-if="stepIndex===1" class="step-item step-two">
-				<view class="item top">
-					<text class="item-text">-请完成以下操作-</text>
-					<image src="/static/img/cztis.png" mode="aspectFit"></image>
-					<view class="care">
-						注意:洗车过程中禁止移动车辆和上下车
-					</view>
-				</view>
-				<view class="item bottom" @click="lookMore">
-					<view class="item-text">
-						<text>超高加装件不能清洗</text>
-						<view class="right">
-							<text>查看更多</text>
-							<u-icon name="arrow-right" size="28"></u-icon>
-						</view>
-					</view>
-					<image src="/static/img/zyts.png" ></image>
-				</view>
-			</view>
-			<!-- 下单 -->
-			<view v-if="stepIndex===2" class="step-item step-three">
-				<view class="choose">
-					<view class="title">
-						请选择服务模式
-					</view>
-					<view class="list">
-						<view :class="['item', serverIndex==index ?'avtive':'']" @click="chooseItem(index)" v-for="(item,index) in itemList"
-						 :key="index">
-							<text>{{item.itemName}}</text>
-							<text class="price">¥{{item.currentPrice}}</text>
-						</view>
-						<u-empty text="暂无服务项目" img-width="120" v-if="itemList.length==0 && status!='loading'" mode="list"></u-empty>
-					</view>
-				</view>
-				<view class="choose-content">
-					<view class="choose-item">
-						<view class="item" >
-							<text>优惠卷</text>
-							<view @click="intoChooseCoupon" v-if="couponList.length" class="right">
-								<u-icon name="gift" color="rgb(255,0,0)" size="32"></u-icon>
-								<text class="coopon">{{checkedCoupon?(checkedCoupon.couponTitle+'(¥-'+checkedCoupon.couponAmount+')'):''}}</text>
-								<u-icon name="arrow-right" color="rgb(255,0,0)" size="32"></u-icon>
-							</view>
-							<view v-else class="right">
-								<text>暂无可用优惠券</text>
-							</view>
-						</view>
-						<view class="item phone">
-							<text>手机号码</text>
-							<view class="right">
-								<text>{{userPhone}}</text>
-							</view>
-						</view>
-					</view>
-					<view class="read" @click="intoAgreement">
-						<u-radio-group v-model="isRead">
-							<u-radio shape="square" :disabled="isRead!='read'" name="read" active-color="red" icon-size="28" label-size="28">
-								点击阅读并同意
-								<text>无人洗车</text>
-								<text>《注意事项及服务协议》</text>
-							</u-radio>
-						</u-radio-group>
-					</view>
-				</view>
-			</view>
-		</view>
-		<view class="step-footer">
-			<button class="next-button" @click="nextStep" v-if="stepIndex!=2" type="warn">下一步</button>
-			<view v-else class="pay">
-				<text>合计:</text>
-				<text class="amount">¥{{finalAmount}}</text>
-				<view class="">
-					<button :disabled="disabledPay" @click="handleSubmit" type="warn">去付款</button>
-				</view>
-			</view>
-		</view>
-	</view>
-</template>
-
-<script>
-	import {couponEnable} from '@/api/coupon.js'
-	import uniSteps from '@/components/uni-steps/uni-steps.vue'
-	import {
-		getUserInfo
-	} from '@/api/login.js'
-	import {
-		getStoreItems,
-		saveOrder,
-		signPay
-	} from '@/api/order.js'
-	import {
-		getStoreStatus
-	} from '@/api/store.js'
-	export default {
-		components: {
-			uniSteps
-		},
-		data() {
-			return {
-				status: 'loadmore',
-				disabledPay: false,
-				userPhone: '',
-				stepIndex: 0, // 当前步奏下标
-				serverIndex: 0, // 选择服务下标
-				itemList: [], // 服务类型
-				isRead: '', // 是否同意协议
-				couponList: [], // 用户可用优惠券
-				checkedCoupon: null, // 用户当前所选优惠券
-				amount: 0, // 所选服务项目总金额
-				couponAmount: 0, // 优惠券优惠金额
-				finalAmount: 0, // 用户最终所需支付金额
-			}
-		},
-		onLoad(options) {
-			// 存储当前扫码的设备及网点id
-			if (options.scene) {
-				let scene = decodeURIComponent(options.scene);
-				//&是我们定义的参数链接方式
-				let storeId = scene.split(",")[0];
-				let bizId = scene.split(',')[1];
-				//其他逻辑处理。。。。。
-				this.$u.vuex('vuex_bizId',bizId)
-				this.$u.vuex('vuex_storeId',storeId)
-				// 判断当前门店是否已运营
-				this.getStoreStatus(storeId,bizId)
-			} else {
-				// 判断是否扫码过
-				if (this.$store.state.vuex_bizId != '') {
-					this.dataInit()
-				} else {
-					// 返回首页
-					uni.reLaunch({
-						url: "/pages/index/index"
-					})
-				}
-			}
-		},
-		onUnload() {
-			uni.removeStorageSync('stepIndex')
-			uni.$off('couponChoose', this.couponChoose)
-		},
-		onShow() {
-			const index = uni.getStorageSync('stepIndex')
-			this.stepIndex = index ? index : 0
-			console.log(this.stepIndex)
-		},
-		methods: {
-			// 查询基础数据
-			dataInit(){
-				// 监听点击已阅读事件
-				uni.$once('read', this.read)
-				// 监听用户选择的优惠券
-				uni.$on('couponChoose', this.couponChoose)
-				// 获取用户信息
-				this.getUserPhone()
-				// 获取服务项目
-				this.getServerList()
-			},
-			// 获取网点营业状态
-			getStoreStatus(storeId, bizId) {
-				uni.showLoading({
-					title: '加载中...',
-					mask: true
-				})
-				getStoreStatus({
-					storeId: storeId,
-					deviceNo: bizId
-				}).then(res => {
-					uni.hideLoading()
-					console.log(res,'---------')
-					if(res.status != 200 && res.status != 401) {
-						uni.showModal({
-						    title: '提示',
-						    content: res.message,
-							showCancel: false,
-						    success: function (res) {
-						        if (res.confirm) {
-									uni.reLaunch({
-										url:'/pages/index/index'
-									})
-						        }
-						    }
-						});
-					}else{
-						this.dataInit()
-					}
-				})
-			},
-			// 获取用户信息
-			getUserPhone() {
-				getUserInfo().then(res => {
-					console.log(res, 'rrrrrrr')
-					if (res.status == 200) {
-						this.userPhone = res.data.mobile
-					} else {
-					}
-				})
-			},
-			// 查看更多注意事项
-			lookMore() {
-				uni.navigateTo({
-					url: '/pages/careMore/careMore'
-				})
-			},
-			// 获取服务列表
-			getServerList(flag) {
-				this.status = 'loading'
-				let storeId = this.$store.state.vuex_storeId
-				getStoreItems({
-					storeId: storeId
-				}).then(res => {
-					this.status = 'loadmore'
-					if (res.status == 200) {
-						this.itemList = res.data
-						// 支付失败 重查服务项时不切换服务及重查优惠券
-						if (!flag) {
-							this.serverIndex = 0
-							// 获取用户可用优惠券
-							this.getCouponList()
-						}
-					} else {
-						this.itemList = []
-					}
-				})
-			},
-			// 选择服务项目
-			chooseItem(index) {
-				this.serverIndex = index
-				// 获取用户可用优惠券
-				this.getCouponList()
-			},
-			// 下一步
-			nextStep() {
-				this.stepIndex = this.stepIndex === 0 ? 1 : 2
-				uni.setStorageSync('stepIndex', this.stepIndex)
-			},
-			// 已阅读
-			read(e) {
-				this.isRead = e.msg
-			},
-			// 获取用户选择的优惠券
-			couponChoose (e) {
-				this.checkedCoupon = e.curCoupon
-				// 计算合计
-				this.getFinalAmount()
-			},
-			// 获取用户可用优惠券
-			getCouponList() {
-				let item = this.itemList[this.serverIndex]
-				let params = {
-					consumAmount: item.currentPrice, //服务金额
-					consumStoreId: this.$store.state.vuex_storeId, // 门店id
-					itemId: item.itemId  // 服务id
-				}
-				uni.showLoading({
-					title: '正在查询可用优惠券...',
-					mask: true
-				})
-				couponEnable(params).then(res=> {
-					uni.hideLoading()
-					if (res.status == 200) {
-						this.couponList = res.data
-						this.checkedCoupon = res.data.length ? this.findCouponMax() : null
-					} else {
-						this.couponList = []
-						this.checkedCoupon = null
-					}
-					// 计算合计
-					this.getFinalAmount()
-				})
-			},
-			// 查找优惠卷中优惠金额最大得
-			findCouponMax(){
-				// 比较数据中优惠金额最大的值 并返回该对象
-				let obj = this.couponList.reduce((p, v) => p.couponAmount < v.couponAmount ? v : p)
-				return obj
-			},
-			// 计算合计
-			getFinalAmount() {
-				this.amount = this.itemList[this.serverIndex].currentPrice
-				this.couponAmount = (this.checkedCoupon && this.checkedCoupon.couponAmount > this.amount) ? this.amount : (this.checkedCoupon ?this.checkedCoupon.couponAmount : 0)
-				let ret = this.amount - this.couponAmount
-				this.finalAmount = ret.toFixed(2)
-			},
-			// 选择优惠券
-			intoChooseCoupon() {
-				this.couponList.map((item)=> {
-					item.checked = (this.checkedCoupon && item.id == this.checkedCoupon.id) ? true : false
-				})
-				uni.navigateTo({
-					url: `/pages/coupon/chooseCoupon/chooseCoupon?list=${encodeURIComponent(JSON.stringify(this.couponList))}&curCoupon=${encodeURIComponent(JSON.stringify(this.checkedCoupon))}`
-				})
-			},
-			// 打开服务协议
-			intoAgreement() {
-				uni.navigateTo({
-					url: '/pages/agreement/agreement'
-				})
-			},
-			// 去付款 保存订单
-			handleSubmit() {
-				if (this.itemList.length == 0) {
-					this.toashMsg('请先选择服务')
-					return
-				}
-				if (this.isRead != 'read') {
-					this.toashMsg('请先阅读并同意无人洗车《注意事项及服务协议》!')
-					return
-				} 
-				uni.showLoading({
-					title: '请求中...',
-					mask: true
-				})
-				let item = this.itemList[this.serverIndex]
-				let storeId = this.$store.state.vuex_storeId
-				let deviceNo = this.$store.state.vuex_bizId
-				let params = {
-					"itemId": item.itemId, // 服务id
-					"itemCode": item.itemCode,
-					"storeId": storeId, // 门店id
-					"deviceNo": deviceNo, // 设备编号
-					"orderTime": this.$u.timeFormat(Date.now(), 'yyyy-mm-dd hh:MM:ss'),
-					"payableAmount": this.amount, // 应付金额 即优惠前金额
-					"paymentAmount": this.finalAmount, // 实收金额 即优惠后金额
-					"couponAmount": this.couponAmount, // 优惠金额
-				}
-				console.log(item,'itemitemitem')
-				this.$u.vuex('vuex_itemTime',item.duration)
-				if (this.checkedCoupon) {
-					params.couponReceivesList = [{id:this.checkedCoupon.id}]
-				}
-				this.disabledPay = true
-				saveOrder(params).then(res => {
-					if (res.status == 200) {
-						let data = res.data
-						// 保存成功后 请求预支付返回吊起微信支付所需参数
-						this.getPayData(data)
-						this.$u.vuex('vuex_itemCode',data.itemCode)
-						this.$u.vuex('vuex_orderNo',data.orderNo)
-					} else {
-						uni.hideLoading()
-						this.toashMsg(res.message)
-						this.disabledPay = false
-						setTimeout(()=>{
-							// 刷新服务项
-							this.getServerList(true)
-						},2000)
-					}
-				})
-			},
-			// 预支付 返回微信支付所需参数
-			getPayData(orderData) {
-				let _this = this
-				signPay({
-					orderId: orderData.id
-				}).then(res => {
-					console.log(res, '预支付')
-					uni.hideLoading()
-					if (res.status == 200) {
-						let data = res.data
-						// 0元订单直接支付成功,不用吊微信支付
-						if (data.tradeStatus && data.tradeStatus == "PAID") {
-							this.paySuccess()
-						} else {
-							uni.requestPayment({
-								provider: 'wxpay',
-								timeStamp: data.timeStamp,
-								nonceStr: data.nonceStr,
-								package: data.package,
-								signType: data.signType,
-								paySign: data.paySign,
-								success: function(res) {
-									console.log('success:' + JSON.stringify(res));
-									_this.paySuccess()
-								},
-								fail: function(err) {
-									console.log('fail:' + JSON.stringify(err));
-									_this.payFail(err)
-									_this.disabledPay = false
-								}
-							});
-						}
-					} else {
-						this.toashMsg(res.message)
-						this.disabledPay = false
-					}
-				})
-			},
-			// 付款成功后
-			paySuccess(){
-				this.$u.vuex('vuex_orderStatus','PAID')
-				this.$u.vuex('vuex_orderDjs',0)
-				this.$u.vuex('vuex_workStep',0)
-				this.$u.vuex('vuex_workStatus','linking')
-				 
-				// 付款成功后开始洗车
-				uni.showLoading({
-					title: '支付验证中...',
-					mask: true
-				})
-				setTimeout(()=>{
-					this.disabledPay = false
-					uni.hideLoading()
-					uni.redirectTo({
-						url: `/pages/work/index/index`
-					})
-				},3000)
-			},
-			// 付款失败或取消
-			payFail(err){
-				this.$u.vuex('vuex_orderStatus','FAIL')
-				let content = '支付失败,请重试'
-				if(err.errMsg.indexOf("cancel")>=0){
-					content = '支付取消'
-					this.toashMsg(content)
-					// 取消支付 跳到订单列表
-					setTimeout(()=>{
-						uni.redirectTo({
-							url: `/pages/order/order`
-						})
-					},500)
-				}
-				this.toashMsg(content)
-				
-			}
-		}
-	}
-</script>
-
-<style lang="scss">
-	page {
-		height: 100%;
-	}
-
-	.order-content {
-		width: 100%;
-		height: 100%;
-		display: flex;
-		flex-direction: column;
-
-		.step {
-			padding: 40rpx 0;
-		}
-		.step-content {
-			flex: 1;
-			width: 100%;
-			display: flex;
-			flex-direction: column;
-			overflow-y: scroll;
-			.step-item {
-				width: 100%;
-				display: flex;
-				flex-direction: column;
-				align-items: center;
-				flex: 1;
-			}
-
-			// 第一步
-			.step-one {
-				text {
-					color: #999;
-					margin: 40rpx 0;
-				}
-			}
-
-			// 第二步
-			.step-two {
-				background-color: #F8F8F8;
-				justify-content: space-around;
-
-				.item {
-					background-color: #fff;
-					width: 92%;
-					height: 45%;
-					display: flex;
-					flex-direction: column;
-					align-items: center;
-					image {
-						width: 80%;
-						flex: 1;
-					}
-
-				}
-
-				.top {
-					text {
-						color: #df928e;
-						font-size: 24rpx;
-					}
-
-					.item-text {
-						padding-top: 20rpx;
-					}
-
-					.care {
-						padding: 10rpx 20rpx;
-						background-color: #ff805b;
-						border-radius: 30rpx;
-						color: #fff;
-						font-size: 24rpx;
-						margin-bottom: 20rpx;
-					}
-				}
-
-				.bottom {
-					text {
-						font-size: 24rpx;
-						color: #333;
-					}
-					.item-text {
-						width: 100%;
-						padding: 0 40rpx;
-						display: flex;
-						justify-content: space-between;
-						padding-top: 20rpx;
-					}
-					image {
-						margin-top: 20rpx;
-					}
-				}
-			}
-
-			// 第三步 下单
-			.step-three {
-				.choose {
-					width: 100%;
-					height: auto;
-					padding-bottom: 60rpx;
-					display: flex;
-					flex-direction: column;
-					align-items: center;
-					border-bottom: 1px solid #eee;
-
-					.title {
-						color: #666;
-					}
-
-					.list {
-						width: 100%;
-						display: flex;
-						justify-content: space-around;
-						padding: 0 20rpx;
-
-						.item {
-							width: 30%;
-							height: 140rpx;
-							display: flex;
-							flex-direction: column;
-							align-items: center;
-							justify-content: center;
-							border: 1px solid #eee;
-							border-radius: 15rpx;
-							margin-top: 30rpx;
-							color: #999;
-
-							.price {
-								font-size: 34rpx;
-								margin-top: 10rpx;
-							}
-						}
-
-						.avtive {
-							color: #333;
-							border-color: rgb(255, 0, 0);
-
-							.price {
-								color: rgb(255, 0, 0);
-							}
-						}
-					}
-
-				}
-
-				.choose-content {
-					flex: 1;
-					width: 100%;
-
-					.choose-item {
-						width: 100%;
-
-						.item {
-							padding: 0 30rpx;
-						}
-					}
-
-					.item {
-						width: 100%;
-						height: 100rpx;
-						display: flex;
-						align-items: center;
-						justify-content: space-between;
-						border-bottom: 1px solid #eee;
-
-						.coopon {
-							color: rgb(255, 0, 0);
-						}
-					}
-
-					.phone {
-						border-bottom: none;
-					}
-
-					.read {
-						width: 100%;
-						border-top: 1px solid #eee;
-						padding-top: 40rpx;
-						display: flex;
-						justify-content: center;
-
-						text {
-							color: #999;
-						}
-
-						text:last-child {
-							color: #ff9ba5;
-						}
-					}
-				}
-			}
-		}
-
-		.step-footer {
-			width: 100%;
-			background-color: #fff;
-
-			.next-button {
-				margin: 0;
-				border-radius: 0;
-				padding: 10rpx 0;
-			}
-
-			.pay {
-				width: 100%;
-				height: 100%;
-				padding: 10rpx;
-				border-top: 1px solid #eee;
-				display: flex;
-				align-items: center;
-				justify-content: flex-end;
-
-				.amount {
-					color: rgb(255, 0, 0);
-					font-size: 36rpx;
-					margin-right: 40rpx;
-				}
-
-				button {
-					width: 200rpx;
-				}
-			}
-		}
-	}
-</style>

+ 116 - 0
pages/goods/goods.vue

@@ -0,0 +1,116 @@
+<template>
+	<view class="content">
+		<view v-if="goldLimit>0" class="info">该类商品需购满{{goldLimit}}乐豆才能下单哦!</view>
+		<view v-if="goodsList.length">
+			<uni-coods :list="goodsList"></uni-coods>
+			<view class="loadmore"><u-loadmore @loadmore="loadmore" :status="status" /></view>
+		</view>
+		<!-- 购物车 -->
+		<uni-cart-fix :dragPic="dragPic"></uni-cart-fix>
+	</view>
+</template>
+
+<script>
+	import {
+		getGoodsList
+	} from '@/api/goods.js'
+	export default {
+		data() {
+			return {
+				clsId: '',
+				goldLimit:0,
+				goodsName: '',
+				pageNo: 1,
+				pageSize: 10,
+				goodsList:[],
+				status: 'loadmore',
+				count: 0,
+				dragPic: '/static/cart.png',  //  购物车图标
+			};
+		},
+		onLoad(opts) {
+			this.goodsName = opts.name
+			this.clsId = opts.goodsTypeNo
+			this.goldLimit = opts.goldLimit
+			uni.setNavigationBarTitle({
+				title: this.goodsName
+			})
+			this.getGoods()
+		},
+		// 下拉刷新
+		onPullDownRefresh() {
+			console.log('refresh')
+			this.pageNo = 1
+			this.getGoods()
+			setTimeout(function () {
+				uni.stopPullDownRefresh()
+			}, 200)
+		},
+		methods: {
+			// 查询商品
+			getGoods(item,index){
+				getGoodsList({
+					pageNo: this.pageNo,
+					pageSize: this.pageSize,
+					goodsTypeNo:this.clsId,
+				}).then(res => {
+					console.log(res,'goodsList')
+					if(res.status == 200){
+						this.count = res.data.count
+						if(this.pageNo == 1){
+							this.goodsList = res.data.list
+							if(res.data.list.length == this.count){
+								this.status = 'nomore'
+							}else{
+								this.status = 'loadmore'
+							}
+						}else{
+							this.goodsList = this.goodsList.concat(res.data.list)
+							this.goodsList.splice()
+							this.status = 'loadmore'
+						}
+					}
+				})
+			},
+			loadmore(){
+				if(this.count <= this.goodsList.length) {
+					this.status = 'nomore'
+				}else{
+					this.status = 'loading'
+					this.pageNo = ++ this.pageNo
+					this.getGoods()
+				}
+			}
+		},
+		onReachBottom() {
+			this.loadmore()
+		}
+	}
+</script>
+
+<style lang="scss">
+   .content {
+	   width: 100%;
+		.goods{
+			padding: 20upx 0;
+		}
+		.goods-list{
+			display: flex;
+			flex-wrap: wrap;
+			justify-content: space-between;
+			padding: 20upx 20upx 0;
+			background: #FFFFFF;
+			>view{
+				margin-bottom: 20upx;
+			}
+		}
+		.info{
+			text-align: center;
+			color: #DD524D;
+			margin-bottom: 20upx;
+		}
+		.loadmore{
+			padding: 20upx 0;
+		}
+	}
+</style>

+ 279 - 0
pages/goods/goodsDetail.vue

@@ -0,0 +1,279 @@
+<template>
+	<view class="goods-detail">
+		<view>
+			<!-- 商品信息 -->
+			<view class="goods-head">
+				<view class="goods-imgs">
+					<view class="goods-staus" v-if="goodContent.inventoryQty == 0 || goodContent.delFlage == 0 || goodContent.state == 0"></view>
+					<u-swiper height="325" :border-radius="15" mode="number" indicator-pos="bottomRight" :list="imageList"></u-swiper>
+				</view>
+				<view class="goods-name">
+					<view>
+						{{goodContent.name}}
+					</view>
+					<view>
+						<text>{{goodContent.sellGold}}</text>
+						<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+					</view>
+				</view>
+				<view class="goods-price">
+					<view>兑换数量<text>(库存{{goodContent.inventoryQty}}件)</text></view>
+					<view>
+						<u-number-box :max="goodContent.inventoryQty" v-model="nums"></u-number-box>
+					</view>
+				</view>
+				<view v-if="goldLimit>0" class="goods-goldLimit">
+					此类商品需要满<text>{{goldLimit}}</text>乐豆才可购买
+				</view>
+			</view>
+			<!-- 商品属性 -->
+			<view class="goods-attr">
+				<view>
+					<view>运费</view>
+					<view>免运费</view>
+				</view>
+				<view>
+					<view>限购</view>
+					<view>每人限购1件</view>
+				</view>
+				<view>
+					<view>售后</view>
+					<view>兑换商品,一经售出,不支持退换货</view>
+				</view>
+			</view>
+			<!-- 商品详情 -->
+			<view class="goods-content">
+				<jyf-parser :html="goodContent.desc" ref="article"></jyf-parser>
+			</view>
+		</view>
+		<!-- 底部浮动按钮 -->
+		<view class="bottom-btns" v-if="goodContent&&goodContent.inventoryQty > 0&&goodContent.state==1">
+			<view><u-button :custom-style="addCartButton" type="warning" @click="addCart">加入购物车</u-button></view>
+			<view><u-button :custom-style="toOrderButton" type="error" @click="toOrder()">立即下单</u-button></view>
+		</view>
+		<!-- 购物车 -->
+		<uni-cart-fix :closeCurPage="true" :dragPic="dragPic"></uni-cart-fix>
+	</view>
+</template>
+
+<script>
+	import {
+		getGoodsDetail
+	} from '@/api/goods.js'
+	import {
+		addGoodsToCart
+	} from '@/api/shoppingCart.js'
+	import jyfParser from "@/components/jyf-parser/jyf-parser";
+	export default {
+		components: {
+		    jyfParser
+		  },
+		data() {
+			return {
+				addCartButton: {
+					background: '#ff9000',
+					borderRadius:'100rpx 0 0 100rpx'
+				},
+				toOrderButton: {
+					borderRadius:'0 100rpx 100rpx 0'
+				},
+				imageList:[], // 商品图片
+				nums:1, // 商品数量
+				id: '',
+				goodContent: null,
+				goldLimit: 0,
+				dragPic: '/static/cart.png',  //  购物车图标
+			};
+		},
+		onLoad(opts) {
+			console.log(opts)
+			this.id = opts.id
+			this.getDetail()
+		},
+		methods: {
+			// 查详情
+			getDetail(){
+				getGoodsDetail({id:this.id}).then(res => {
+					console.log(res)
+					if(res.status == 200){
+						this.goodContent = res.data
+						this.goldLimit = res.data.goodsType.goldLimit || 0
+						let arr=res.data.images.split(',')
+						arr.map(item => {
+							this.imageList.push({image:item})
+						})
+					}
+				})
+			},
+			// 添加购物车
+			addGoodToCart(item){
+				uni.showLoading({
+					mask: true,
+					title: "正在加入购物车..."
+				})
+				addGoodsToCart(item).then(res => {
+					if(res.status == 200){
+						// 刷新购物车数量
+						if(!item.hasCunzai){
+							this.$store.state.vuex_cartNums = this.$store.state.vuex_cartNums + 1
+						}
+						setTimeout(()=>{
+							uni.showToast({
+								icon: 'none',
+								title:'添加成功'
+							})
+							// 刷新购物车数据
+							uni.$emit('getCartList')
+						},50)
+					}
+				})
+			},
+			// 判断当前商品是否已存在购物车中
+			hasCunzai(data){
+				let list = this.$store.state.vuex_cartList
+				let row = list.find(item=> item.goodsTypeNo == data.goodsTypeNo)
+				return row
+			},
+			// 加入购物车
+			addCart() {
+				let item = this.goodContent
+				this.addGoodToCart({goodsNo:item.goodsNo,buyQty:this.nums,hasCunzai:this.hasCunzai(item)})
+			},
+			// 立即下单
+			toOrder(){
+				// console.log(this.goodContent,this.id,'pppppppp')
+				if(this.goodContent.sellGold * this.nums >= this.goldLimit){
+					this.$u.vuex("vuex_toOrderList",[{id:this.id,buyQty:this.nums,goodsNo:this.goodContent.goodsNo,goods:this.goodContent}])
+					uni.redirectTo({
+						url:"/pages/toOrder/index?orderForm=ORDER_NOW"
+					})
+				}else{
+					uni.showToast({
+						icon:"none",
+						title:"此商品需要满" +this.goldLimit+ "乐豆才可购买"
+					})
+				}
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+page{
+	height: 100%;
+}
+.goods-detail{
+	width: 100%;
+	height: 100%;
+	display: flex;
+	flex-direction: column;
+	> view{
+		&:first-child{
+			flex-grow: 1;
+			overflow: auto;
+		}
+	}
+	.goods-head{
+		background: #FFFFFF;
+		box-shadow: 1px 1px 3px #eee;
+		padding: 10upx 0;
+		.goods-imgs{
+			position: relative;
+			margin: 20upx 30upx 10upx;
+			.goods-staus{
+				width: 100%;
+				height: 100%;
+				position: absolute;
+				z-index: 10000;
+				background: url(../../static/yxt.png) no-repeat center center;
+				background-size: 100% 100%;
+				left: 0;
+				top: 0;
+			}
+		}
+		.goods-name{
+			padding:0 40upx;
+			margin: 20upx 0;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			>view{
+				&:first-child{
+					width: 60%;
+					font-weight: bold;
+					font-size: 30upx;
+				}
+				&:last-child{
+					display: flex;
+					align-items: center;
+					text{
+						color: #d42a26;
+						font-size: 36upx;
+						margin-right: 6upx;
+						font-weight: bold;
+					}
+				}
+			}
+		}
+		.goods-price{
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding:0 40upx;
+			>view{
+				&:first-child{
+					font-size: 22upx;
+					text{
+						color: #999;
+						font-size: 24upx;
+						margin-right: 6upx;
+					}
+				}
+			}
+		}
+		.goods-goldLimit{
+			padding: 10upx 40upx;
+			color: #F0AD4E;
+			font-size: 24rpx;
+			text-align: right;
+			text{
+				color: red;
+			}
+		}
+	}
+	.goods-attr{
+		margin: 20upx 0;
+		background: #FFFFFF;
+		padding: 20upx 40upx;
+		box-shadow: 1px 1px 3px #eee;
+		> view{
+			display: flex;
+			align-items: center;
+			>view{
+				padding: 10upx 0;
+				&:first-child{
+					padding-right: 15upx;
+					color: #666;
+				}
+			}
+		}
+	}
+	.goods-content{
+		background: #F8F8F8;
+		padding: 20upx;
+		box-shadow: 1px 1px 3px #eee;
+		min-height: 50vh;
+	}
+	
+	.bottom-btns{
+		background: #FFFFFF;
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		padding: 30upx 100upx;
+		>view{
+			width: 50%;
+		}
+	}
+}
+</style>

+ 155 - 0
pages/goods/index.vue

@@ -0,0 +1,155 @@
+<template>
+	<view class="content">
+		<u-swiper height="250" @click="clickBanner" :list="imageTopList"></u-swiper>
+		<view class="t1">
+			<u-image height="40" src="/static/t1.png"></u-image>
+		</view>
+		<!-- 商品 -->
+		<view class="goods">
+			<view v-for="(item,index) in goodsList" :key="index" v-if="item&&item.list.length">
+				<u-section :title="item.type.name" font-size="35" line-color="#01c9b2" sub-title="更多" @click="toGoods(item.type)"></u-section>
+				<view class="goods-list">
+					<uni-coods :goldLimit="item.type.goldLimit" :list="item.list"></uni-coods>
+				</view>
+			</view>
+			<view v-if="goodsListLength==0">
+				<u-empty icon-size="60" :text="noDataText" mode="list"></u-empty>
+			</view>
+		</view>
+		<!-- 购物车 -->
+		<uni-cart-fix :dragPic="dragPic"></uni-cart-fix>
+	</view>
+</template>
+
+<script>
+	import {
+		getGoodsClass,
+		getGoodsList
+	} from '@/api/goods.js'
+	import {bannerList} from '@/api/banner.js'
+	import {checkLogin} from '@/api/login.js'
+	export default {
+		components: {
+		},
+		data() {
+			return {
+				noDataText: '正在加载...',
+				imageTopList:[],
+				goodsList:[], // 商品
+				goodsType:[], // 商品分类
+				dragPic: '/static/cart.png',  //  购物车图标
+			}
+		},
+		onLoad() {
+			this.pageInit()
+		},
+		computed: {
+			goodsListLength() {
+				return this.goodsList.length
+			}
+		},
+		onShow() {
+			// 是否登录
+			checkLogin().then(res => {
+				if(res.status != 200){
+					uni.navigateTo({
+						url:"/pages/login/login"
+					})
+				}
+			})
+		},
+		// 下拉刷新
+		onPullDownRefresh() {
+			console.log('refresh')
+			this.pageInit()
+			setTimeout(function () {
+				uni.stopPullDownRefresh()
+			}, 200)
+		},
+		methods: { 
+			pageInit(){
+				this.getbannerList()
+				this.goodsList = []
+				getGoodsClass({}).then(res => {
+					console.log(res)
+					if(res.status == 200){
+						this.goodsType = res.data
+						this.goodsType.map((item,index) => {
+							this.getGoods(item,index)
+						})
+					}else{
+						this.goodsList = []
+						this.noDataText = '暂无商品'
+					}
+				})
+			},
+			// 点击banner
+			clickBanner(index){
+				let row = this.imageTopList[index]
+				console.log(index,row)
+				if(row.jumpType !== 'NONE'){
+					// 跳外网地址
+					if(row.jumpUrl.indexOf('http') == 0){
+						
+					}
+					// 跳小程序页面
+					if(row.jumpUrl.indexOf('/pages') == 0){
+						uni.navigateTo({
+							url: row.jumpUrl
+						})
+					}
+				}
+			},
+			// 获取banner
+			getbannerList(){
+				bannerList({type:'banner',location:'MALL_TOP'}).then(res=>{
+					if(res.status==200){
+						this.imageTopList=res.data
+					}
+				})
+			},
+			// 更多商品
+			toGoods(item){
+				uni.navigateTo({
+					url:"/pages/goods/goods?goodsTypeNo="+ item.goodsTypeNo + "&goldLimit="+ item.goldLimit + "&name=" + item.name
+				})
+			},
+			// 查询商品
+			getGoods(item,index){
+				getGoodsList({pageNo:1,pageSize:item.popularizeGoodsLimit,goodsTypeNo:item.goodsTypeNo}).then(res => {
+					console.log(res,'goodsList')
+					if(res.status == 200&&res.data.list&&res.data.list.length){
+						this.goodsList[index] = {
+							type: item,
+							list: res.data.list
+						}
+						this.goodsList.splice()
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.content {
+		background: url(../../static/topBg.png) no-repeat top center;
+		background-size: 100%;
+		width: 100%;
+		.goods{
+			>view{
+				padding: 25upx 20upx 10upx;
+				background: #FFFFFF;
+				border-radius: 15upx;
+				box-shadow: 0upx 6upx 10upx #eee;
+				margin-bottom: 20upx;
+				> .goods-list{
+					padding-top: 5upx;
+				}
+			}
+		}
+		.t1{
+			padding: 20upx 0;
+		}
+	}
+</style>

+ 361 - 26
pages/index/index.vue

@@ -1,51 +1,386 @@
 <template>
 	<view class="content">
-		<u-swiper height="200" :list="imageTopList"></u-swiper>
-		<view class="goods">
-			<u-section title="人气零食" :show-line="false" sub-title="更多"></u-section>
+		<u-swiper height="250" @click="clickBanner" :list="imageTopList"></u-swiper>
+		<!-- 导航按钮 -->
+		<view class="nav">
+			<u-grid :col="4" :border="false" @click="toPage">
+				<u-grid-item :index="3">
+					<u-image width="90rpx" height="90rpx" src="/static/hexiao.png"></u-image>
+					<view class="grid-text">投递/兑换</view>
+				</u-grid-item>
+				<u-grid-item :index="0">
+					<u-image width="90rpx" height="90rpx" src="/static/zhinan.png"></u-image>
+					<view class="grid-text">回收分类</view>
+				</u-grid-item>
+				<u-grid-item :index="1">
+					<u-image width="90rpx" height="90rpx" src="/static/liucheng.png"></u-image>
+					<view class="grid-text">使用指南</view>
+				</u-grid-item>
+				<u-grid-item :index="2">
+					<u-image width="90rpx" height="90rpx" src="/static/shouyi.png"></u-image>
+					<view class="grid-text">投递二维码</view>
+				</u-grid-item>
+			</u-grid>
+		</view>
+		<!-- 网点 -->
+		<view class="storeList">
+			 <u-section title="附近的回收机" :right="false" line-color="#01c9b2" class="store-section"></u-section>
+			 <view class="stores-box">
+			 	<view class="stores-item" v-for="item in stationDataList" :key="item.id" @click="viewStore(item)">
+			 		<view class="item-con">
+			 			<image src="/static/md-icon.png" class="item-icon"></image>
+			 			<view class="s-name item-main">{{ item.name }}</view>
+			 		</view>
+			 		<view class="item-con">
+			 			<image src="/static/dz-icon.png" class="item-icon"></image>
+			 			<view class="s-address item-main">
+			 				<view>{{ item.provinceName||'' }}{{ item.cityName||'' }}{{ item.districtName||'' }}{{ item.address||'' }}</view>
+			 				<view>
+			 					<u-icon name="map-fill" color="#01c9b2" size="30"></u-icon>
+			 					{{ item.distanct.distance ? (item.distanct.distance / 1000).toFixed(1) : 0 }}KM
+			 					<u-icon name="arrow-right" color="#999" size="20"></u-icon>
+			 				</view>
+			 			</view>
+			 		</view>
+			 		<view class="item-con">
+			 			<image src="/static/time-icon.png" class="item-icon"></image>
+			 			<view class="s-time item-main">
+			 				<view>
+			 					<text>营业时间:</text>
+			 					<text v-for="(tItem, tInd) in item.deliveryTimeRuleItemList" :key="tInd">
+			 						{{ tItem.openTime }} - {{ tItem.closeTime }}{{ tInd == item.deliveryTimeRuleItemList.length - 1 ? '' : ',' }}
+			 					</text>
+			 				</view>
+			 			</view>
+			 		</view>
+			 	</view>
+				<view v-if="stationDataList.length==0">
+					<u-empty icon-size="60" text="暂无数据" mode="list"></u-empty>
+				</view>
+			 </view>
 		</view>
 	</view>
 </template>
 
 <script>
 	import {
-		checkLogin
-	} from '@/api/login.js'
-	import {
-		getMapStoreList
-	} from '@/api/store.js'
-	import {
-		getLookUpDatas
-	} from '@/api/data.js'
-	import {
-		getUnFinishedOrder
-	} from '@/api/order.js'
+		getCartList,
+		addGoodsToCart,
+		deleteGoodsFormCart,
+		updateGoodsBuyQty
+	} from '@/api/shoppingCart.js'
+	import {bannerList} from '@/api/banner.js'
+	import {getLookUpDatas,openDevice} from '@/api/data.js'
+	import {stationList} from '@/api/station.js'
+	import {checkLogin,getUserInfo} from '@/api/login.js'
+	import {parseQueryString} from '@/libs/tools.js'
+	import { sellerFindByPartnerNo } from '@/api/user.js'
 	export default {
-		components: {
-		},
 		data() {
 			return {
-				imageTopList:[
-					{photo:''},
-					{photo:''}
-				]
+				imageTopList: [],
+				stationDataList: [] ,//  附近网点列表
+				hasLogin: false
 			}
 		},
-		onReady() {
+		onLoad() {
+			// 查询购物车列表
+			this.getCartList()
+			// 刷新购物车列表
+			uni.$on("getCartList",item =>{
+				this.getCartList()
+			})
+			// 更新购物车数量
+			uni.$on('getCarCount',item => {
+				this.getCarCount()
+			})
+			// 查询用户信息
+			uni.$on("getUserInfo",item=>{
+				this.getUserInfo(item)
+			})
 		},
-		onShow() {
+		onUnload() {
+			console.log('onUnload')
+			uni.$off('getCarCount')
+			uni.$off('getCartList')
+			uni.$off('getUserInfo')
 		},
-		onLoad() {
+		onShow() {
+			// 获取订单状态数据字典
+			// this.getCodeList('RUBBISH_TYPE','vuex_rubbishType')
+			// 获取顶部轮播图
+			this.getbannerList()
+			//  获取经纬度
+			this.getLocation()
+			// 是否登录
+			checkLogin().then(res => {
+				console.log(res,'checkLogin')
+				this.hasLogin = res.status == 200
+				if(!this.hasLogin&&!this.$store.state.vuex_noLogin){
+					uni.navigateTo({
+						url:"/pages/login/login"
+					})
+				}
+			})
 		},
-		methods: { 
+		methods: {
+			// 获取用户信息
+			getUserInfo(){
+				getUserInfo().then(res => {
+					if(res.status == 200){
+						this.$u.vuex("vuex_userData",res.data)
+					}
+				})
+			},
+			// 获取数据字典
+			getCodeList(code,key) {
+				getLookUpDatas({
+					type: code
+				}).then(res => {
+					if (res.status == 200) {
+						this.$u.vuex(key, res.data)
+					}
+				})
+			},
+			//  获取经纬度
+			getLocation() {
+				const _this = this;
+				uni.getLocation({
+					type: 'wgs84',
+					success: function(res) {
+						_this.getStationList(res.longitude, res.latitude)
+					},
+					fail: function(error) {
+						console.log(error)
+						uni.showToast({ icon: 'none', title: '定位失败' })
+					}
+				});
+			},
+			//  获取网点列表
+			getStationList(lng, lat) {
+				stationList({ lng: lng, lat: lat }).then(res => {
+					if (res.status == 200) {
+						this.stationDataList = res.data
+					} else {
+						this.stationDataList = []
+					}
+				});
+			},
+			// 获取banner
+			getbannerList(){
+				bannerList({type:'banner',location:'HOME_TOP'}).then(res=>{
+					if(res.status==200){
+						this.imageTopList=res.data
+					}
+				})
+			},
+			// 点击banner
+			clickBanner(index){
+				let row = this.imageTopList[index]
+				console.log(index,row)
+				if(row.jumpType !== 'NONE'){
+					uni.navigateTo({
+						url: row.jumpUrl
+					})
+				}
+			},
+			// 查询购物车
+			getCartList(){
+				getCartList({}).then(res => {
+					if(res.status == 200){
+						this.$u.vuex('vuex_cartList', res.data)
+						this.getCarCount()
+					}
+					uni.hideLoading()
+				})
+			},
+			// 计算购物车数量
+			getCarCount(){
+				let arr = this.$store.state.vuex_cartList || []
+				let count = 0
+				arr.map(item=>{
+					count = count + item.shoppingCartGoodsList.length
+				})
+				this.$u.vuex('vuex_cartNums', count)
+			},
+			// 更多商品
+			toGoods(clsId){
+				uni.navigateTo({
+					url:"/pages/goods/goods?id="+clsId
+				})
+			},
+			// 去登录
+			toLoginPage(){
+				uni.navigateTo({
+					url: '/pages/login/login'
+				})
+			},
+			// 快速导航
+			toPage(e){
+				let path=[
+					'/pages/userCenter/fenlei',
+					'/pages/userCenter/zhinan',
+					'/pages/userCenter/myCode/myCode',
+					''
+				]
+				 
+				if(e>1){
+					//判断是否登录
+					if(this.hasLogin){
+						if(path[e]!=''){
+							uni.navigateTo({
+								url: path[e]
+							})
+						}else{
+							// 核销
+							this.smHx()
+						}
+					}else{
+						this.toLoginPage()
+					}
+				}else{
+					uni.navigateTo({
+						url: path[e]
+					})
+				}
+			},
+			// 扫码核销
+			smHx(){
+				const _this = this
+				uni.scanCode({
+					success(e) {
+						console.log(e)
+						// 普通二维码,用户扫箱体的二维码开箱
+						if(e.scanType == 'QR_CODE'){
+							let params = parseQueryString(e.result)
+							console.log(params)
+							if(params.codeType == 'hexiao'){  //  扫商户码
+								_this.getStoreData(params.officialPartnerNo)
+							}else{  //  扫箱体码
+								_this.openDevice(e.result)
+							}
+						}
+						// 小程序码,用户核销
+						// if(e.scanType == 'WX_CODE'){
+						// 	let scene = e.path.split('?')[1]
+						// 	uni.navigateTo({
+						// 		url: '/pages/checkOut/checkOut?scene='+scene.split("=")[1]
+						// 	})
+						// }
+					},
+					fail(err) {
+						console.log(err)
+					}
+				})
+			},
+			// 扫商户码,获取商户信息
+			getStoreData(params) {
+				sellerFindByPartnerNo({officialPartnerNo: params}).then(res => {
+					if(res.status == 200){
+						let store = res.data
+						uni.navigateTo({
+							url: '/pages/checkOut/checkOut?store='+encodeURIComponent(JSON.stringify(store))
+						})
+					} 
+				})
+			},
+			// 开箱
+			openDevice(data){
+				let params = parseQueryString(data)
+				openDevice(params).then(res => {
+					console.log(res)
+					if(res.status == 200){
+						// uni.showToast({
+						// 	icon:"none",
+						// 	title:"认证成功,请点击设备开启按钮"
+						// })
+					}
+				})
+			},
+			// 查看网点
+			viewStore(item){
+				uni.navigateTo({
+					url: '/pages/store/store?id=' + item.id + '&stationNo=' + item.stationNo
+				})
+			}
 		}
 	}
 </script>
 
 <style lang="scss" scoped>
 	.content {
-		.goods{
-			padding: 30upx 0;
+		// background: url(../../static/topBg.png) no-repeat top center;
+		// background-size: 100%;
+		width: 100%;
+		.nav {
+			margin: 20upx 0;
+			border-radius: 15upx;
+			box-shadow: 0upx 3upx 6upx #eee;
+			overflow: hidden;
+			.grid-text {
+				padding-top: 10upx;
+			}
+		}
+		.storeList {
+			padding: 25upx 0 20upx;
+			.store-section {
+				display: block;
+				margin-bottom: 20rpx;
+			}
+			.stores-box {
+				padding-top: 5upx;
+				.stores-item {
+					background: #ffffff;
+					border-radius: 15upx;
+					box-shadow: 0upx 3upx 6upx #eee;
+					border-bottom: 1px solid #f8f8f8;
+					padding: 10upx 20upx;
+					margin-bottom: 20rpx;
+					&:last-child {
+						border: 0;
+					}
+					.item-con {
+						display: flex;
+						align-items: center;
+						&:last-child {
+							.item-main {
+								border: none;
+							}
+						}
+						.item-icon {
+							width: 30rpx;
+							height: 30rpx;
+							margin-right: 10rpx;
+							flex-shrink: 0;
+							padding: 22rpx 0;
+						}
+						.item-main {
+							font-size: 28rpx;
+							color: #666;
+							padding: 22rpx 0;
+							border-bottom: 1rpx solid #f2f2f2;
+							flex-grow: 1;
+						}
+						.s-name{
+							font-size: 30rpx;
+							color: #333;
+						}
+						.s-address {
+							display: flex;
+							align-items: center;
+							justify-content: space-between;
+							>view{
+								&:last-child{
+									width: 30%;
+									display: flex;
+									align-items: center;
+									justify-content: flex-end;
+								}
+							}
+						}
+					}
+				}
+			}
 		}
 	}
 </style>

+ 85 - 0
pages/login/login.scss

@@ -0,0 +1,85 @@
+.login-wrap, .forget-wrap, .apply-wrap{
+	background-color: #FFFFFF;
+	width: 100%;
+	height: 100vh;
+	box-sizing: border-box;
+	.logo{
+		display: flex;
+		justify-content: center;
+		padding: 100upx 0;
+	}
+	.login-form{
+		display: block;
+		width: 80%;
+		margin: 0 auto;
+		.form-item{
+			margin-bottom: 20upx;
+			position: relative;
+			display: flex;
+			align-items: center;
+			border: 1upx solid #dcdee2;
+			border-radius: 15upx;
+			.require-tip{
+				position: absolute;
+				left: 0;
+				top: 26upx;
+				color: red;
+			}
+			.item-inp{
+				flex-grow: 1;
+			}
+			.item-inp, .item-picker{
+				font-size: 30upx;
+				padding: 14upx 20upx;
+			}
+			.getcode-btn{
+				position: absolute;
+				right: 0upx;
+				top: 0;
+				font-size: 24upx;
+				background: #999;
+				color: #FFFFFF;
+				border: 0;
+				border-top-left-radius: 0;
+				border-bottom-left-radius: 0;
+				line-height: 3;
+				z-index: 10;
+			}
+		}
+		.flex-box{
+			display: flex;
+			justify-content: space-between;
+			font-size: 26upx;
+		}
+		.form-btn-con{
+			margin-top: 60upx;
+			.form-btn{
+				font-size: 32upx;
+				display: block;
+				line-height: 75upx;
+				margin: 0 auto;
+				background-color: #07c160;
+				color: #fff;
+			}
+			uni-button.form-btn:after{
+				border: none;
+			}
+			.apply-btn{
+				display: block;
+				text-align: center;
+				margin-top: 50upx;
+			}
+		}
+	}
+	
+	.authUserYs{
+		text-align: center;
+		position: absolute;
+		bottom: 5%;
+		width: 100%;
+		font-size: 24upx;
+		text{
+			color: #ff0000;
+		}
+	}
+}

+ 75 - 49
pages/login/login.vue

@@ -1,33 +1,48 @@
 <template>
 	<view class="content">
-		<image class="logo-img" mode="aspectFit" src="/static/img/logo.png"></image>
-		<u-button shape="circle" class="login-btn" type="success" plain :hair-line="false" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
-			<view class="login-btn-content">
-			  <view class="wechat-img"></view>
-			  <view>微信登陆</view>
+		<view>
+			<view>
+				<view class="logo">
+					<u-image src="/static/logo.png" width="140" height="140" ></u-image>
+				</view>
+				<view class="login-btns">
+					<u-button shape="circle" :custom-style="wxButton" class="login-btn" type="success" :hair-line="false" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
+						微信登陆
+					</u-button>
+					<u-gap height="30"></u-gap>
+					<u-button shape="circle" :custom-style="phoneButton" class="login-btn" @click="phoneLogin" type="primary">
+						手机号码登录
+					</u-button>
+				</view>
+			</view>
+			<view class="nologin">
+				<u-button shape="circle" size="mini" plain lass="login-btn" @click="cansel" type="info">
+					暂不登录
+				</u-button>
 			</view>
-		</u-button>
-		<view class="canseLogin" @click="gotoHome()">
-		  取消登录
 		</view>
+		<view @click="toYs">登录即代表同意<text>隐私政策</text>和<text>服务条款</text></view>
 	</view>
 </template>
 
 <script>
 	import {
 		login
-	} from "@/api/login.js"
+	} from "@/api/login"
 	export default {
 		components: {},
 		data() {
 			return {
 				path: '/pages/index/index',
 				lanuch: true,
-				code: ''
+				code: '',
+				wxButton: {
+					background: '#07c160'
+				},
+				phoneButton: {
+					background: '#00aaff'
+				}
 			}
-		},
-		onShow() {
-			
 		},
 		mounted() {},
 		onLoad(option) {
@@ -43,6 +58,17 @@
 			}
 		},
 		methods: {
+			cansel(){
+				this.$store.state.vuex_noLogin = true
+				uni.reLaunch({
+					url: '/pages/index/index'
+				})
+			},
+			toYs(){
+				uni.navigateTo({
+					url: '/pages/agreement/agreement'
+				})
+			},
 			getPhoneNumber(e) {
 				let _this = this
 				uni.showLoading({
@@ -52,6 +78,7 @@
 				if (!this.code) {
 					this.wxLogin()
 				} 
+				console.log(this.code, e)
 				if (e.target.errMsg === 'getPhoneNumber:ok') {
 					setTimeout(()=>{
 						login({
@@ -65,6 +92,7 @@
 							if (res.status == '200') {
 								getApp().globalData.token = res.data
 								_this.$u.vuex('vuex_token',res.data)
+								uni.$emit("getUserInfo")
 								if (_this.path === '/pages/index/index' || _this.lanuch) {
 									uni.reLaunch({
 										url: _this.path
@@ -97,14 +125,15 @@
 				uni.login({
 					provider: 'weixin',
 					success(res) {
+						console.log(res.code)
 						_this.code = res.code
 					}
 				})
-				console.log(this.code,'1111111111')
 			},
-			gotoHome () {
-			  wx.reLaunch({
-			    url: '/pages/index/index'
+			// 手机号登录
+			phoneLogin () {
+			  wx.navigateTo({
+			    url: '/pages/login/phoneLogin'
 			  })
 			}
 		}
@@ -115,39 +144,36 @@
 	.content {
 		width: 100%;
 		height: 100%;
-		padding: 0;
+		padding: 40upx;
 		display: flex;
-		align-items: center;
-		padding-top: 35%;
-		.logo-img {
-			width: 400rpx;
-			height: 100rpx;
+		flex-direction: column;
+		> view{
+			text-align: center;
+			&:first-child{
+				flex-grow: 1;
+				height: 80vh;
+				padding: 20% 10%;
+				display: flex;
+				flex-direction: column;
+				justify-content: space-between;
+			}
+			&:last-child{
+				font-size: 24upx;
+				text{
+					color: #07c160;
+				}
+			}
+			.logo{
+				text-align: center;
+				display: flex;
+				justify-content: center;
+			}
+			.login-btns{
+				padding: 60upx 0;
+				.login-btn{
+					margin: 30upx 0;
+				}
+			}
 		}
 	}
-	.wechat-img {
-	  width: 40px;
-	  height: 35px;
-	  margin-right: 10px;
-	  padding-top: 10px;
-	  background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyBjbGFzcz0iaWNvbiIgd2lkdGg9IjMwcHgiIGhlaWdodD0iMzBweCIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiMwOUJCMDciIGQ9Ik0xMDEwLjggNjI4YzAtMTQxLjItMTQxLjMtMjU2LjItMjk5LjktMjU2LjItMTY4IDAtMzAwLjMgMTE1LjEtMzAwLjMgMjU2LjIgMCAxNDEuNCAxMzIuMyAyNTYuMiAzMDAuMyAyNTYuMiAzNS4yIDAgNzAuNy04LjkgMTA2LTE3LjdsOTYuOCA1My0yNi42LTg4LjJjNzAuOS01My4yIDEyMy43LTEyMy43IDEyMy43LTIwMy4zek02MTggNTg4LjhjLTIyLjEgMC00MC0xNy45LTQwLTQwczE3LjktNDAgNDAtNDAgNDAgMTcuOSA0MCA0MGMwIDIyLTE3LjkgNDAtNDAgNDB6IG0xOTQuMy0wLjNjLTIyLjEgMC00MC0xNy45LTQwLTQwczE3LjktNDAgNDAtNDAgNDAgMTcuOSA0MCA0MC0xNy45IDQwLTQwIDQweiIgIC8+PHBhdGggZmlsbD0iIzA5QkIwNyIgZD0iTTM2Ni4zIDEwNi45Yy0xOTQuMSAwLTM1My4xIDEzMi4zLTM1My4xIDMwMC4zIDAgOTcgNTIuOSAxNzYuNiAxNDEuMyAyMzguNGwtMzUuMyAxMDYuMiAxMjMuNC02MS45YzQ0LjIgOC43IDc5LjYgMTcuNyAxMjMuNyAxNy43IDExLjEgMCAyMi4xLTAuNSAzMy0xLjQtNi45LTIzLjYtMTAuOS00OC4zLTEwLjktNzQgMC0xNTQuMyAxMzIuNS0yNzkuNSAzMDAuMi0yNzkuNSAxMS41IDAgMjIuOCAwLjggMzQgMi4xQzY5MiAyMTIuNiA1MzkuOSAxMDYuOSAzNjYuMyAxMDYuOXpNMjQ3LjcgMzQ5LjJjLTI2LjUgMC00OC0yMS41LTQ4LTQ4czIxLjUtNDggNDgtNDggNDggMjEuNSA0OCA0OC0yMS41IDQ4LTQ4IDQ4eiBtMjQ2LjYgMGMtMjYuNSAwLTQ4LTIxLjUtNDgtNDhzMjEuNS00OCA0OC00OCA0OCAyMS41IDQ4IDQ4LTIxLjUgNDgtNDggNDh6IiAgLz48L3N2Zz4K') no-repeat center  center;
-	}
-	
-	.login-btn {
-	  margin-top: 30px;
-	}
-	
-	.login-btn-content {
-	  width: 65vw;
-	  display: flex;
-	  justify-content: center;
-	  align-items: center;
-	}
-	.canseLogin{
-	  width: 65vw;
-	  padding : 20rpx 15rpx;
-	  text-align : center;
-	  font-size: 1em;
-	  margin-top: 1.8em;
-	  color: #666;
-	}
 </style>

+ 186 - 0
pages/login/phoneLogin.vue

@@ -0,0 +1,186 @@
+<template>
+	<view class="forget-wrap">
+		<view class="logo">
+			<u-image src="/static/logo.png" width="140" height="140" ></u-image>
+		</view>
+		<form class="login-form" @submit="formSubmit">
+			<view class="form-item">
+				<input v-model="form.phone" class="item-inp" name="phone" type="number" maxlength="11" placeholder="请输入登录手机号" />
+			</view>
+			<view class="form-item">
+				<input v-model="form.verifyCode" class="item-inp" name="verifyCode" type="number" maxlength="6" placeholder="请输入短信验证码" />
+				<button class="getcode-btn" :disabled="isDisable" @click="getCodeValidate">{{nowVal}}</button>
+			</view>
+			<view class="form-btn-con">
+				<button class="form-btn" @click="submitFn">登录</button>
+			</view>
+		</form>
+		<!-- 图文验证码 -->
+		<uni-popup ref="imageTxtPopup" type="center">
+			<popup-con title="图文验证码" :popBtn="popBtn" :changeImg="changeImg" @captchaImg="captchaVerify"></popup-con>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import { isvalidPhone } from '@/libs/validate.js'
+	import uniPopup from '@/components/uni-popup/uni-popup.vue'
+	import popupCon from '@/components/uni-popup/popup-con.vue'
+	import { loginPhone, sendVerifyCode, checkCustomerState } from '@/api/user.js'
+	export default{
+		components: {
+			uniPopup,
+			popupCon
+		},
+		data(){
+			return{
+				form: {
+					phone: '',
+					verifyCode: '',
+					password: '',
+					passwords: ''
+				},
+				nowVal: '获取验证码',  //  按钮显示内容
+				count: '',  //  当前秒数
+				timer: null,  //  倒计时
+				isDisable: false,  //  是否禁止获取验证码
+				popBtn: [],  //  name为操作按钮名称,color为操作按钮颜色值
+				changeImg: false,  //  是否重新更换图形验证码
+				randomCode: '',  //  图片验证码随机码
+				wxcode: ''
+			}
+		},
+		onLoad(opts) {
+		},
+		onUnload() {
+			uni.$off('getUserInfo')
+		},
+		methods: {
+			//   登录
+			submitFn(){
+				const _this = this
+				//  表单校验
+				if(this.form.phone == ''){
+					uni.showToast({icon: 'none',title: '请输入登录手机号'})
+					return
+				}
+				if(!isvalidPhone(this.form.phone)){
+				  uni.showToast({icon: 'none',title: '请输入正确的手机号码'})
+				  return
+				}
+				if(this.form.verifyCode == ''){
+					uni.showToast({icon: 'none',title: '请输入验证码'})
+					return
+				}
+				// 校验短信验证码是否正确
+				const obj = {}
+				obj.phone = _this.form.phone
+				obj.random = _this.randomCode  // 当前随机码
+				obj.verifiCode = _this.form.verifyCode
+				
+				uni.login({
+					provider: 'weixin',
+					success(res) {
+						console.log(res)
+						_this.wxcode = res.code
+						obj.code = res.code
+						loginPhone(obj).then(res => {
+						  if(res.status == 200){
+							console.log(res,'login success')
+							getApp().globalData.token = res.data
+							_this.$u.vuex('vuex_token',res.data)
+							uni.$emit("getUserInfo")
+						    uni.navigateBack({
+						    	delta: 2
+						    })
+						  }else{
+							  uni.showToast({icon: 'none',title: res.message})
+						  }
+						})
+					}
+				})
+			},
+			//  单击获取验证码
+			getCodeValidate(){
+				if(this.form.phone){
+					if(!isvalidPhone(this.form.phone)){
+						uni.showToast({icon: 'none',title: '请输入正确的手机号码'})
+						return
+					}else{
+						// 先校验手机号用户是否禁用
+						checkCustomerState({phone:this.form.phone}).then(res=>{
+							if(res.status == 200) {
+								this.retsetCode()
+								//  图文验证码
+								this.$refs.imageTxtPopup.open()
+							} else {
+								uni.showToast({
+									title: res.message,
+									icon: 'none'
+								})
+							}
+						})
+					}
+				}else{
+					uni.showToast({icon: 'none',title: '请先输入手机号'})
+				}
+			},
+			//  开始倒计时
+			getCodeFun(){
+				const TIME_COUNT = 60
+				if (!this.timer) {
+				  this.count = TIME_COUNT
+				  this.timer = setInterval(() => {
+				    if (this.count > 0 && this.count <= TIME_COUNT) {
+				      this.count--
+				      this.nowVal = this.count + 's后重发'
+				      this.isDisable = true
+				    } else {
+				      this.nowVal = '重新获取验证码'
+				      clearInterval(this.timer)
+				      this.timer = null
+				      this.isDisable = false
+				    }
+				  }, 1000)
+				}
+			},
+			//  验证图片验证码
+			captchaVerify(code, nowRandomCode){
+				const _this = this
+				let obj = {}
+				obj.phone = this.form.phone
+				obj.random = nowRandomCode
+				obj.code = code
+				//  发送短信验证码
+				sendVerifyCode(obj).then(res => {
+					console.log(JSON.stringify(res))
+					if(res.status == 200){  //  验证码输入正确
+						_this.randomCode = nowRandomCode  //  图片验证码随机码
+						//  关闭   图形验证码 弹框
+						_this.$refs.imageTxtPopup.close()
+						//  开启倒计时
+						_this.getCodeFun()
+						uni.showToast({icon: 'none',title: '验证码发送成功'})
+					}else {  //  验证码输入错误
+						_this.retsetCode()
+						uni.showToast({icon: 'none',title: res.message})
+					}
+				})
+			},
+			// 重新触发获取图片验证码
+			retsetCode(){
+				const _this = this
+				_this.form.verifyCode = ''
+				_this.randomCode = ''
+				//  切换验证码重新校验
+				_this.changeImg = false
+				_this.$nextTick(function(){
+					_this.changeImg = true
+				})
+			}
+		}
+	}
+</script>
+<style scoped lang="scss">
+	@import './login.scss';
+</style>

+ 292 - 0
pages/order/LogList.vue

@@ -0,0 +1,292 @@
+<template>
+	<view class="pagesCons">
+		<view class="tab-body">
+					<scroll-view scroll-y class="scroll-view" @scrolltolower="onreachBottom">
+						<view class="check-order-list" v-for="(item,index) in list" :key="item.id"
+						 >
+							<view class="order-log">
+								<view v-if="!item.expressNum">待发货</view>
+								<view v-else>
+									<view>
+										快递公司:<text class="address-title">{{item.expressName}}</text>
+										<u-button v-if="item.expressState=='WAIT_SIGN'" 
+										:custom-style="btnStyle" 
+										@click="handleGet(index)"
+										 type="primary" shape="circle" size="mini" >确认收货</u-button>
+									</view>
+									<view>
+										<text>运单编号:</text>
+										<text>{{item.expressNum}}</text>
+										<u-button @click="copyLogNum(item.expressNum)" style="margin-left: 20upx;" shape="square" size="mini">复制</u-button>
+									</view>
+								</view>
+							</view>
+							<u-gap height="10" bg-color="#f8f8f8"></u-gap>
+							<view class="bundle-list" v-for="row in item.orderGoodsList" :key="row.id">
+								<view class="img-cont">
+									<image :src="row.goodsImages"></image>
+								</view>
+								<view >
+									<view class="ellipsis-two">{{row.goodsName}}</view>
+									<view class="bundle-num">
+										<view ><text class="price-num">{{row.payGold}}</text> <text class="price-text">乐豆</text></view>
+										<view >X {{row.buyQty}}</view>
+									</view>
+								</view>
+							</view>
+						</view>
+						<u-empty style="padding-top: 10vh;height: auto;" :text="noDataText" img-width="120" v-if="list.length==0 && status!='loading'"
+						 mode="list"></u-empty>
+						<view style="padding: 20upx;">
+							<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
+						</view>
+					</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { queryOrderExpress, finishOrder } from '@/api/order.js'
+	export default {
+		components: {
+		},
+		data() {
+			return {
+				btnStyle:{
+					width: '180rpx',
+					fontSize: '30rpx',
+					float: 'right'
+				},
+				isShow: false, // 是否显示物流弹框
+				status: 'loadmore',
+				noDataText: '暂无数据',
+				list: [],
+				total: 0,
+				orderSn: '' // 订单编号
+			}
+		},
+		onLoad(option) {
+			if(option.orderNo) {
+				this.orderSn = option.orderNo
+				this.getRow()
+			}
+		},
+		methods: {
+			// scroll-view到底部加载更多
+			onreachBottom() {
+				if (this.list.length < this.total) {
+					this.pageNo += 1
+					this.getRow()
+				} else {
+					uni.showToast({
+						title: '已经到底了',
+						icon: 'none'
+					});
+					this.status = "nomore"
+				}
+			},
+			// 查询列表
+			getRow() {
+				this.status = "loading"
+				queryOrderExpress({orderSn:this.orderSn}).then(res => {
+					console.log(res,'rrrrrrrr')
+					if (res.status == 200) {
+						this.list = res.data || []
+					} else {
+						this.list = []
+						this.total = 0
+						this.noDataText = res.message
+					}
+					this.status = "loadmore"
+				})
+			},
+			// 确认收货
+			handleGet(index) {
+				console.log(index,'iiiiiiiiii')
+				let params = {
+					  "expressNo": this.list[index].expressNo,
+						"orderNo": this.list[index].orderNo,
+				}
+				finishOrder(params).then(res=>{
+					if(res.status==200) {
+						uni.$emit('refresh')
+						uni.showToast({
+							title:res.message,
+							icon: 'none'
+						})
+						this.getRow()
+					} 
+				})
+			},
+			
+			// 复制运单编号 
+			copyLogNum (logNum) {
+				// H5 不支持
+				uni.setClipboardData({
+					data: logNum,
+					success: function(res) {
+						uni.getClipboardData({
+							success: function(res) {
+								uni.showToast({
+									title: '已复制到剪贴板',
+									icon: 'none'
+								});
+							}
+						});
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	page {
+		height: 100%;
+		width: 100%;
+		background: #F8F8F8;
+	}
+
+	.pagesCons {
+		height: 100%;
+		width: 100%;
+		background: #F8F8F8;
+		display: flex;
+		flex-direction: column;
+
+		.text-right {
+			text-align: right;
+		}
+
+		.tab-body {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+
+			.uTabs {
+				border-bottom: 1px solid #EEEEEE;
+				box-shadow: 1px 1px 3px #eeeeee;
+			}
+
+			.check-list {
+				flex: 1;
+				overflow-y: scroll;
+
+				.swiper-item {
+					width: 100%;
+					height: 100%;
+					overflow: hidden;
+
+					.scroll-view {
+						width: 100%;
+						height: 100%;
+						overflow: auto;
+					}
+				}
+			}
+			// 列表样式
+			.check-order-list {
+				background: #ffffff;
+				padding: 10upx 20upx;
+				margin: 25upx;
+				border-radius: 6upx;
+				box-shadow: 1px 1px 3px #EEEEEE;
+				font-size: 28upx;
+				.check-row {
+					display: flex;
+					align-items: center;
+					padding: 20upx 10upx;
+
+					.icon-xian {
+						text-align: right;
+						width: 40upx;
+					}
+
+					&:first-child {
+						border-bottom: 1px dashed #F8F8F8;
+
+						.createDate {
+							color: #666;
+							font-size: 26upx;
+							margin-left: 10upx;
+						}
+					}
+
+					&:last-child {
+						border-top: 1px dashed #F8F8F8;
+					}
+
+					>view {
+						&:first-child {
+							flex: 1;
+						}
+					}
+				}
+				// 订单中商品列表
+				.bundle-list {
+					display: flex;
+					padding: 20upx 10upx;
+					font-size: 28upx;
+					border-bottom: 1px solid #F8F8F8;
+					&:last-child {
+						border-bottom: none;
+					}
+					.img-cont {
+						width: 160upx;
+						height: 160upx;
+						>image {
+							width: 100%;
+							height: 100%;
+						}
+					}
+					>view {
+						&:last-child {
+							flex: 1;
+							margin-left: 20upx;
+							padding: 10upx 0upx;
+							display: flex;
+							flex-direction: column;
+							justify-content: space-between;
+						}
+					}
+					.bundle-num {
+						display: flex;
+						justify-content: space-between;
+					}
+				}
+				.btn-cont {
+					width: 180upx;
+					height: 60upx;
+					float: right;
+					// background-color: #2979ff;
+					// color: #fff;
+					// text-align: center;
+					// border-radius: 100upx;
+					font-size: 30upx;
+				}
+				.price-text{
+					font-size: 20upx;
+					margin-left: 10upx;
+				}
+				.price-num{
+					font-size: 32upx;
+					color: red;
+				}
+				.total-text{
+					margin-right: 50upx;
+				}
+				.money-total{
+					margin-right: 10upx;
+				}
+			}
+		}
+		// 物流弹窗
+		.order-log {
+			padding: 20upx ;
+			font-size: 28upx;
+			>view{
+				line-height: 60upx;
+			}
+		}
+	}
+</style>

+ 571 - 129
pages/order/order.vue

@@ -1,178 +1,620 @@
 <template>
-	<view class="order-pages">
-		<scroll-view scroll-y="true" class="scroll-Y" @scrolltolower="reachBottom">
-			<view class="order-list">
-				<view v-for="item in list" :key="item.id" class="order-list-item" @click="goView(item)">
-					<view>
-						<view>{{item.storeName}}</view>
-						<view :class="item.orderStatus">{{getOptionName(orderStatusList,item.orderStatus)}}</view>
-					</view>
-					<view>
-						<view class="order-carNo">{{item.customerMobile}}</view>
-						<u-icon name="arrow-right" color="#666" size="28"></u-icon>
-					</view>
-					<view>
-						<view class="order-price">
-							<!-- 显示用户实付金额,未支付显示0 -->
-							<text>¥{{item.payStatus=='PAID' ?item.paymentAmount:0}}</text>
-							<text>{{item.payType}}</text>
+	<view class="pagesCons">
+		<view class="tab-body">
+			<view class="uTabs">
+				<u-tabs-swiper ref="uTabs" :list="tabList" name="dispName" :current="current" @change="tabsChange" :is-scroll="false"
+				 swiperWidth="750"></u-tabs-swiper>
+			</view>
+			<swiper class="check-list" :current="swiperCurrent" @transition="transition" @change="swiperChange" @animationfinish="animationfinish">
+				<swiper-item class="swiper-item" v-for="(tabs, index) in tabList" :key="index">
+					<scroll-view scroll-y class="scroll-view" @scrolltolower="onreachBottom">
+						<view class="check-order-list" v-if="index==current" v-for="item in list" :key="item.id"
+						 @click="viewRow(item)">
+							<view class="check-row">
+								<view class="createDate">{{item.createDate}}</view>
+								<view>{{item.orderStateDictValue}}</view>
+							</view>
+							<view class="bundle-list" v-for="row in item.orderGoodsList" :key="row.id">
+								<view class="img-cont">
+									<image :src="row.goodsImages"></image>
+								</view>
+								<view>
+									<view class="ellipsis-two">{{row.goodsName}}</view>
+									<view class="bundle-num">
+										<view class="num-cont">
+											<text class="price-num">{{row.payGold}}</text> 
+											<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+										</view>
+										<view>X {{row.buyQty}}</view>
+									</view>
+								</view>
+							</view>
+							<view class="check-row">
+								<view class="text-right">
+									<text class="total-text">
+										共{{item.goodsNum}}件商品
+									</text>
+									<view class="num-cont" v-if="item.orderState=='WAIT_PAY'">
+										<text class="money-total">应付</text>
+										<text class="price-num">{{item.payGold}}</text>
+										<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+									</view>
+									<view class="num-cont" v-else>
+										<text class="money-total">实付</text>
+										<text class="price-num">{{item.payGold}}</text> 
+										<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+									</view>
+								</view>
+							</view>
+							<view class="check-row">
+								<view v-if="item.orderState=='WAIT_PAY'"  class="text-right left-time">
+										<text style="margin-right: 20upx;">
+											支付剩余
+										</text>
+										<u-count-down @end="getRow" 
+										style="margin-right: 20upx;" separator ="zh" 
+										:timestamp="item.leftTimeT" :show-days="false" :show-hours="false"></u-count-down>
+									<u-button :custom-style="btnStyle" @click="toPay(item)"  shape="circle" type="success" size="medium">去支付</u-button>
+								</view>
+								<view v-if="item.orderState=='WAIT_SEND'||item.orderState=='SEND_PART'" class="text-right">
+									<u-button :custom-style="btnStyle" @click="showTip" shape="circle" size="medium">提醒发货</u-button>
+								</view>
+								<view v-if="item.orderState=='SEND_ALL'||item.orderState=='SEND_PART'" class="text-right">
+									<u-button @click="showLog(item)" :custom-style="btnStyle" 
+									style="margin-right: 20upx;margin-left: 20upx;" shape="circle" size="medium">查看物流</u-button>
+									<u-button :custom-style="btnStyle" @click="showLog(item)" shape="circle" type="primary" size="medium">确认收货</u-button>
+								</view>
+								<view v-if="item.orderState=='FINISH'" class="text-right">
+									<u-button @click="showLog(item)" :custom-style="btnStyle" shape="circle" size="medium">查看物流</u-button>
+								</view>
+							</view>
+						</view>
+						<u-empty style="padding-top: 10vh;height: auto;" :text="noDataText" img-width="120" v-if="list.length==0 && status!='loading'"
+						 mode="list"></u-empty>
+						<view v-if="index==current" style="padding: 20upx;">
+							<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
 						</view>
-						<view>{{item.orderTime}}</view>
-					</view>
+					</scroll-view>
+				</swiper-item>
+			</swiper>
+		</view>
+		<!-- 提示用户设置支付密码 -->
+		<u-modal v-model="showSetPswModal" 
+		content="请先设置支付密码,才能使用乐豆" 
+		show-cancel-button 
+		confirm-text="去设置" 
+		cancel-text="暂时放弃"
+		@confirm="toSetPwd"
+		@cancel="showSetPswModal=false"
+		></u-modal>
+		<!-- 确认取消弹窗 -->
+		<u-modal v-model="showLeavePsw" 
+		title="确认放弃支付吗?"
+		content="您的订单在30分钟内未支付将被取消" 
+		show-cancel-button 
+		confirm-text="确认放弃" 
+		cancel-text="继续支付"
+		@confirm="canclePay"
+		@cancel="payAgain"
+		></u-modal>
+		<!-- 确认支付弹窗 -->
+		 <u-popup mode="center" :mask-close-able="false" negative-top="300" closeable @close="closePayModal" v-model="showInputPsw" width="500rpx" >
+			<view class="slot-content">
+				<view>确认支付</view>
+				<view class="text-cont">
+					<text class="num-big">{{totalPrice}}</text>
+					<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+				</view>
+				<view class="footer">
+					<input 
+					v-model="password" 
+					maxlength="30" 
+					:focus="focus"
+					style="text-align: center;"
+				    type="password" 
+					placeholder="请输入支付密码" 
+					@confirm="toPayOrder"/>
+				</view>
+				<view class="fot-btn">
+					<u-button  @click="toPayOrder" type="success" >确认支付</u-button>
 				</view>
 			</view>
-			<u-empty :text="noDataText" img-width="120" v-if="list.length==0 && status!='loading'" mode="list"></u-empty>
-			<view style="padding: 20upx;">
-				<u-loadmore v-if="count>pageSize || status=='loading'" :status="status" />
-			</view>
-		</scroll-view>
+		</u-popup>
 	</view>
 </template>
 
 <script>
-	import {getOrderList, orderDetail} from '@/api/order.js'
+	import {
+		getLookUpDatas,
+		listLookUp
+	} from '@/api/data'
+	import {
+		getOrderList, signPay, existPayPwd
+	} from '@/api/order.js'
+	import moment from 'moment'
 	export default {
+		components: {},
 		data() {
 			return {
+				btnStyle:{
+					width: '180rpx',
+					fontSize: '30rpx',
+				},
+				status: 'loadmore',
 				noDataText: '暂无数据',
-				status: 'loading',
-				list:[],
-				pageNo:1,
-				pageSize:10,
-				count:0,
-				orderStatusList: []
+				tabList: [{
+						dispName: '全部',
+						typeId: 2,
+						queryLabel: [] // tab参数
+					},
+					{
+						dispName: '待支付',
+						typeId: 1,
+						queryLabel: ['WAIT_PAY'] // tab参数
+					},
+					{
+						dispName: '待发货',
+						typeId: 3,
+						queryLabel: ['WAIT_SEND'] // tab参数
+					},
+					{
+						dispName: '待收货',
+						typeId: 3,
+						queryLabel: ['SEND_ALL','SEND_PART'] // tab参数
+					},
+					{
+						dispName: '已完成',
+						typeId: 3,
+						queryLabel: ['FINISH'] // tab参数
+					},
+
+				],
+				current: 0,
+				swiperCurrent: 0,
+				pageNo: 1,
+				pageSize: 10,
+				list: [],
+				logData: { // 物流信息
+					logName: '韵达快递',
+					logNum: 12356544544
+				},
+				total: 0,
+				totalPrice: 0, // 支付合计
+				password: '', // 支付密码
+				focus: false,
+				action: 'swiperChange', // 操作类型,上划分页,或左右滑动
+				showSetPswModal: false,  // 设置支付密码弹窗
+				showInputPsw: false, // 打开输入密码弹窗
+				showLeavePsw: false, // 打开确定放弃弹窗
+				payFinish: false  // 是否支付成功
 			}
 		},
-		onShow() {
+		onLoad() {
+			// 监听设置密码是否成功
+			uni.$once('setPswSuccess', this.setPsw)
+			// 监听页面刷新事件 在详情支付成功后或在物流确认收货后刷新列表
+			uni.$on('refresh', this.handleRefresh)
 			this.pageInit()
 		},
+		onUnload() {
+			uni.$off('refresh', this.handleRefresh)
+		},
+		onShow() {
+			this.getRow(1)  //  解决安卓息屏后倒计时不走问题
+		},
+		// 下拉刷新
+		onPullDownRefresh() {
+			console.log('refresh')
+			this.pageNo = 1
+			this.getRow()
+			setTimeout(function () {
+				uni.stopPullDownRefresh()
+			}, 200)
+		},
 		methods: {
-			pageInit () {
+			pageInit() {
+				this.sortIndex = 1
 				this.pageNo = 1
-				this.count = 0
-				this.list = []
-				this.orderStatusList = this.$store.state.vuex_payStatus
-				this.getList()
-			},
-			getOptionName (list,val) {
-			  let p = list.find((item) => {
-				  return item.code == val
-			  })
-			  return p ? p.dispName : '-'
-			},
-			// 获取订单列表
-			getList() {
-				this.status = "loading"
-				let payTypeList = this.$store.state.vuex_payType
+				this.getRow()
+			},
+			handleRefresh() {
+				this.getRow()
+			},
+			// tabs通知swiper切换
+			tabsChange(index) {
+				this.swiperCurrent = index;
+			},
+			swiperChange(event) {
+				this.action = 'swiperChange'
+				this.status = 'loading'
+			},
+			// swiper-item左右移动,通知tabs的滑块跟随移动
+			transition(e) {
+				let dx = e.detail.dx;
+				this.$refs.uTabs.setDx(dx);
+			},
+			// 由于swiper的内部机制问题,快速切换swiper不会触发dx的连续变化,需要在结束时重置状态
+			// swiper滑动结束,分别设置tabs和swiper的状态
+			animationfinish(e) {
+				let current = e.detail.current;
+				let isCurtab = this.current == current
+				if (this.status != "nomore") {
+					let loadData = this.action == 'swiperChange' ? !isCurtab : isCurtab;
+					if (loadData) {
+						this.$refs.uTabs.setFinishCurrent(current);
+						this.swiperCurrent = current;
+						this.current = current;
+						this.resetPage();
+					}
+				}
+			},
+			// scroll-view到底部加载更多
+			onreachBottom() {
+				this.action = 'onreachBottom'
+				if (this.list.length < this.total) {
+					this.pageNo += 1
+					this.getRow()
+				} else {
+					if(this.list.length) {
+						uni.showToast({
+							title: '已经到底了',
+							icon: 'none'
+						});
+					}
+					this.status = "nomore"
+				}
+			},
+			// 查询列表
+			getRow(pageNo) {
+				this.status = "loadmore"
+				if (pageNo) {
+					this.pageNo = pageNo
+				}
 				let params = {
 					pageNo: this.pageNo,
-					pageSize: this.pageSize
+					pageSize: this.pageSize,
+					orderStateList: this.tabList[this.current].queryLabel, // tab分类
 				}
-				getOrderList(params).then(res=>{
-					this.status = "loadmore"
-					if(res.status == 200) {
-						let list = res.data.list
-						list.map(item => {
-							item.payType = item.payType ? this.getOptionName(payTypeList,item.payType) : ''
+				this.noDataText = '暂无数据'
+				this.status = "loading"
+				getOrderList(params).then(res => {
+					if (res.status == 200) {
+						if (this.pageNo > 1) {
+							this.list = this.list.concat(res.data.list || [])
+						} else {
+							this.list = res.data.list || []
+						}
+						const date1 = moment().toArray()  //  当前时间 数组形式
+						this.list.map(item=>{ 
+							const date2 = moment(item.orderTime).toDate()  //  下单时间  日期格式
+							const date3 = moment(date2).toArray()  //  下单时间  数组形式
+							const tt = 1800 - moment(date1).diff(moment(date3), 'seconds')//   距离30分钟支付   当前剩余秒数 = 1800秒 - 计算相差的秒数(当前时间-支付时间)
+							item.leftTimeT = tt > 0 ? tt : 0
 						})
-						this.list = this.list.concat(list)
-						this.count = res.data.count
+						this.total = res.data.count || 0
 					} else {
 						this.list = []
-						this.count = 0
+						this.total = 0
 						this.noDataText = res.message
 					}
+					this.status = "loadmore"
 				})
 			},
-			// 查看详情
-			goView(item){
+			resetPage() {
+				this.status = 'loading';
+				// 上划分页
+				if (this.action == 'onreachBottom') {
+					this.getRow();
+				}
+				// 左右切换tab
+				if (this.action == 'swiperChange') {
+					this.list = [];
+					this.getRow(1);
+				}
+			},
+			// 获取查询参数 刷新列表
+			refresh(params) {
+				// console.log(params,'1111111111')
+				this.searchParams = params
+				this.getRow(1)
+			},
+			
+			// 跳转到设置支付密码页
+			toSetPwd () {
 				uni.navigateTo({
-					url:"/pages/order/orderDetail?id="+item.id
+					url:"/pages/userCenter/userInfo/smsVerification"
 				})
 			},
-			// 滚动到底部自动加载下页
-			reachBottom() {
-				if(this.list.length < this.count){
-					this.pageNo += 1
-					this.getList()
-				}else{
-					this.status = "nomore"
+			// 设置密码成功, 打开输入密码弹窗
+			setPsw (e) {
+				if (e.success) {
+					this.showInputPsw = true
+					setTimeout(()=>{
+						this.focus = true
+					},300)
 				}
-			}
-		},
-		
+			},
+			// 关闭输入密码弹窗
+			closePayModal(){
+				if(!this.payFinish) {
+					this.showLeavePsw = true
+				} 
+			},
+			//确认放弃
+			canclePay() {
+				this.password = ''
+				this.showLeavePsw = false
+				this.showInputPsw = false
+				this.focus = false
+			},
+			// 继续支付
+			payAgain () {
+				this.focus = false
+				this.showLeavePsw = false
+				this.showInputPsw = true
+				setTimeout(()=>{
+					this.focus = true
+				},300)
+			},
+			// 支付 判断用户是否设置过支付密码
+			toPay(item) {
+				this.orderId = item.id
+				this.totalPrice = item.originalGold
+				this.payFinish = false
+				// 判断用户是否设置过支付密码
+				existPayPwd().then(res=>{
+					console.log(res,'rrrrrr')
+					if(res.status == 200) {
+						// 设置过支付密码,输入密码
+						if(res.data) {
+							this.showInputPsw = true
+							setTimeout(()=>{
+								this.focus = true
+							},300)
+						} else {
+							// 没设置过支付密码,提示设置密码
+							 this.showSetPswModal = true
+						}
+					} 
+				})
+			},
+			// 支付
+			toPayOrder() {
+				if (this.password === '') {
+					uni.showToast({
+						title: '请先输入支付密码',
+						icon: 'none'
+					})
+					return false
+				}
+				let params = {
+					payPwd: this.password,
+					id: this.orderId
+				}
+				signPay(params).then(res=>{
+					this.btnLoading = false
+					if(res.status == 200) {
+						// 关闭弹窗 刷新列表
+						this.payFinish = true
+						this.showInputPsw = false
+						this.getRow()
+						setTimeout(()=>{
+							// 跳转到支付完成界面
+							uni.navigateTo({
+								url:"/pages/toOrder/payFinish?id=" + this.orderId
+							})
+						},500)
+						
+					} else{
+						this.password = ''
+					}
+				})
+			},
+			// 提醒发货
+			showTip() {
+				uni.showToast({
+					title: '已提醒商家发货',
+					icon: 'none'
+				})
+			},
+			// 查看物流
+			showLog(item) {
+				console.log(item, '111111')
+				uni.navigateTo({
+					url: "/pages/order/LogList?orderNo=" + item.orderNo
+				})
+			},
+			// 详细页
+			viewRow(item) {
+				// if (!this.$hasPermissions('M_backlog_detail_mobile')) {
+				// 	return
+				// }
+				console.log(item, '111111')
+				// 已完成的
+				uni.navigateTo({
+					url: "/pages/order/orderDetail?id=" + item.id
+				})
+			},
+		}
 	}
 </script>
 
 <style lang="scss">
-	page{
+	page {
 		height: 100%;
-	}
-	.order-pages{
 		width: 100%;
+		background: #F8F8F8;
+	}
+
+	.pagesCons {
 		height: 100%;
-		.scroll-Y {
-			width: 100%;
-			height: 100%;
-			.order-list{
-				padding: 25rpx;
-				.order-list-item{
-					box-shadow: 1rpx 1rpx 5rpx #eee;
-					border: 1px solid #eee;
-					border-radius: 10rpx;
-					margin: 30rpx 0;
-					> view{
-						padding:20rpx 30rpx;
-						display: flex;
-						align-items: center;
-						border-bottom: 1px dashed #eee;
-						&:last-child{
-							border: 0;
-						}
-						>view{
-							&:first-child{
-								flex-grow: 1;
-							}
-							&:last-child{
-								padding-left: 15rpx;
-							}
-						}
-						.FINISHED{
-							color: #00aa00;
-						}
-						.UN_PAY{
-							color: #ff0000;
-						}
-						.CANCELED{
-							color: #7e7b88;
-						}
-						.PAID{
-							color: #00aaff;
-						}
-						.REFUNDING{
-							color: #00557f;
+		width: 100%;
+		background: #F8F8F8;
+		display: flex;
+		flex-direction: column;
+
+		.text-right {
+			text-align: right;
+		}
+
+		.tab-body {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+
+			.uTabs {
+				border-bottom: 1px solid #EEEEEE;
+				box-shadow: 1px 1px 3px #eeeeee;
+			}
+
+			.check-list {
+				flex: 1;
+				overflow-y: scroll;
+
+				.swiper-item {
+					width: 100%;
+					height: 100%;
+					overflow: hidden;
+
+					.scroll-view {
+						width: 100%;
+						height: 100%;
+						overflow: auto;
+					}
+				}
+			}
+
+			// 列表样式
+			.check-order-list {
+				background: #ffffff;
+				padding: 10upx 20upx;
+				margin: 25upx;
+				border-radius: 6upx;
+				box-shadow: 1px 1px 3px #EEEEEE;
+				font-size: 28upx;
+
+				.check-row {
+					display: flex;
+					align-items: center;
+					padding: 20upx 10upx;
+
+					.icon-xian {
+						text-align: right;
+						width: 40upx;
+					}
+
+					&:first-child {
+						border-bottom: 1px dashed #F8F8F8;
+
+						.createDate {
+							color: #666;
+							font-size: 26upx;
+							margin-left: 10upx;
 						}
-						.REFUNDED{
-							color: #005500;
+					}
+
+					&:last-child {
+						border-top: 1px dashed #F8F8F8;
+					}
+
+					>view {
+						&:first-child {
+							flex: 1;
 						}
-						.order-carNo{
-							font-size: 32rpx;
+					}
+				}
+
+				// 订单中商品列表
+				.bundle-list {
+					display: flex;
+					padding: 20upx 10upx;
+					font-size: 28upx;
+					border-bottom: 1px solid #F8F8F8;
+
+					.img-cont {
+						width: 158rpx;
+						height: 140upx;
+						border-radius: 15upx;
+						overflow: hidden;
+
+						>image {
+							width: 100%;
+							height: 100%;
 						}
-						.order-price{
-							text{
-								margin-right: 20rpx;
-								color: #666;
-								&:first-child{
-									color: red;
-									font-size: 32rpx;
-								}
-							}
+					}
+
+					>view {
+						&:last-child {
+							flex: 1;
+							padding: 10upx 0;
+							margin-left: 20upx;
+							display: flex;
+							flex-direction: column;
+							justify-content: space-between;
 						}
 					}
+
+					.bundle-num {
+						display: flex;
+						justify-content: space-between;
+					}
+				}
+				.btn-cont {
+					width: 180upx;
+					font-size: 30upx;
+				}
+
+				.price-text {
+					font-size: 20upx;
+					margin-left: 10upx;
+				}
+
+				.price-num {
+					font-size: 32upx;
+					font-weight: 600;
+					color: red;
+					margin-right: 6rpx;
+				}
+
+				.total-text {
+					margin-right: 50upx;
+				}
+
+				.money-total {
+					margin-right: 10upx;
+				}
+			}
+		}
+		// 乐豆数量
+		.num-cont{
+			display: flex;
+			align-items: center;
+			float: right;
+		}
+		// 支付密码弹窗
+		.slot-content{
+			padding: 30upx 0;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: space-between;
+			.text-cont{
+				width: 100%;
+				padding: 60upx 0;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				.num-big{
+					font-size: 40upx;
+					color: red;
+					font-weight: 600;
+					margin-right: 6rpx;
 				}
 			}
-			.u-empty.data-v-6938e513{
-				height: 90%;
+			.footer{
+				width: 80%;
+				border-bottom: 1px solid #b1b1b1;
+				margin-bottom: 30upx;
 			}
 		}
 	}

+ 357 - 114
pages/order/orderDetail.vue

@@ -1,126 +1,278 @@
 <template>
 	<view class="order-pages">
 		<view class="order-info">
-			<u-cell-group>
-				<u-cell-item title="订单状态" :arrow="false">
-					<view slot="right-icon">
-						<text :class="orderInfo.orderStatus">{{getOptionName(orderStatusList,orderInfo?orderInfo.orderStatus:'')}}</text>
+			<!-- 订单状态 -->
+			<view class="order-status">
+				<view class="status-title">{{orderInfo.orderStateDictValue}}</view>
+				<view v-if="orderInfo.orderState=='WAIT_PAY'" class="status-care">
+					请在 <text>{{leftTime}}</text>分钟内付款,过期系统将自动取消订单
+				</view>
+				<view v-if="orderInfo.orderState=='CANCEL'" class="status-care">
+					超时未支付,系统已自动取消订单
+				</view>
+			</view>
+			<u-gap height="10" bg-color="#f8f8f8"></u-gap>
+			<!-- 地址 -->
+			<view class="order-address">
+				<view>
+					<text class="address-title">{{orderInfo.receiveAddress}}</text>
+				</view>
+				<view>
+					<text style="margin-right: 30upx;">{{orderInfo.receiverName}}</text>
+					<text>{{orderInfo.receiverPhone}}</text>
+				</view>
+			</view>
+			<u-gap height="10" bg-color="#f8f8f8"></u-gap>
+			<!-- 商品列表 -->
+			<view class="bundle-list" v-for="item in orderInfo.orderGoodsList" :key="item.id">
+				<view class="img-cont">
+					<image :src="item.goodsImages"></image>
+				</view>
+				<view>
+					<view class="ellipsis-two">{{item.goodsName}}</view>
+					<view class="bundle-num">
+						<view class="num-cont">
+							<text class="price-num">{{item.payGold}}</text> 
+							<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+						</view>
+						<view>X {{item.buyQty}}</view>
 					</view>
+				</view>
+			</view>
+			<u-gap height="10" bg-color="#f8f8f8"></u-gap>
+			<!-- 订单信息 -->
+			<u-cell-group>
+				<u-cell-item title="订单编号" :value-style="{color: '#000'}" :arrow="false">
+					{{orderInfo.orderSn}}
 				</u-cell-item>
-				<u-cell-item title="订单编号" :arrow="false" >
-					{{orderInfo.orderNo}}
-				</u-cell-item>
-				<u-cell-item title="创建时间" :arrow="false" >
+				<u-cell-item title="下单时间" :value-style="{color: '#000'}" :arrow="false">
 					{{orderInfo.orderTime}}
 				</u-cell-item>
-				<u-cell-item title="服务网点" :arrow="false">
-					{{orderInfo.storeName}}
-				</u-cell-item>
-				<u-cell-item title="服务项目" :arrow="false">
-					{{orderInfo.itemName}}
-				</u-cell-item>
-				<u-cell-item title="手机号" :arrow="false">
-					{{orderInfo.customerMobile}}
-				</u-cell-item>
-				<u-cell-item v-if="orderInfo.payType" title="支付方式" :arrow="false">
-					{{orderInfo.payType}}
+				<u-cell-item v-if="orderInfo.payTime" title="支付时间" :value-style="{color: '#000'}" :arrow="false">
+					{{orderInfo.payTime}}
 				</u-cell-item>
-				<u-cell-item title="应付金额" :arrow="false">
-					¥{{orderInfo.payableAmount}}
-				</u-cell-item>
-				<!-- 已取消订单优惠金额显示0 -->
-				<u-cell-item title="优惠金额" :arrow="false">
-					{{(orderInfo.couponAmount && orderInfo.orderStatus!='CANCELED')?orderInfo.couponAmount:0}}
+				<u-gap height="10" bg-color="#f8f8f8"></u-gap>
+				<u-cell-item title="商品合计" :value-style="{color: '#000'}" :arrow="false">
+					<view class="num-cont">
+						<text class="price-num">{{orderInfo.payGold}}</text>
+						<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+					</view>
 				</u-cell-item>
-				<u-cell-item v-if="orderInfo.orderCoupons && orderInfo.orderCoupons.length" title="优惠券" :arrow="false">
-					{{orderInfo.orderCoupons[0].couponTitle}}
+				<u-cell-item title="运费" :value-style="{color: '#000'}" :arrow="false">
+					免运费
 				</u-cell-item>
-				<u-cell-item title="实付金额" :arrow="false">
-					<text class="order-price">¥{{orderInfo.payStatus=='PAID' ? orderInfo.paymentAmount : 0}}</text>
+				<u-cell-item :title="(orderInfo.orderState=='WAIT_PAY'||orderInfo.orderState=='CANCEL') ? '待支付':'实际支付'" :value-style="{color: '#000'}"
+				 :arrow="false">
+				 <view class="num-cont">
+					 <text class="price-num">{{orderInfo.payGold}}</text>
+					 <u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+				 </view>
 				</u-cell-item>
 			</u-cell-group>
-			<view class="order-photo">
-				<view v-if="orderInfo.beginImage">
-					<view>洗车前</view>
-					<u-image @click="showImage(orderInfo.beginImage)" width="100%" height="400rpx" mode="aspectFit" :src="orderInfo.beginImage"></u-image>
+		</view>
+		<view v-if="orderInfo.orderState=='WAIT_PAY'" class="footer">
+			<u-button @click="toPay" type="success">去支付</u-button>
+		</view>
+		<!-- 提示用户设置支付密码 -->
+		<u-modal v-model="showSetPswModal" 
+		content="请先设置支付密码,才能使用乐豆" 
+		show-cancel-button 
+		confirm-text="去设置" 
+		cancel-text="暂时放弃"
+		@confirm="toSetPwd"
+		@cancel="showSetPswModal=false"
+		></u-modal>
+		<!-- 确认取消弹窗 -->
+		<u-modal v-model="showLeavePsw" 
+		title="确认放弃支付吗?"
+		content="您的订单在30分钟内未支付将被取消" 
+		show-cancel-button 
+		confirm-text="确认放弃" 
+		cancel-text="继续支付"
+		@confirm="canclePay"
+		@cancel="payAgain"
+		></u-modal>
+		<!-- 确认支付弹窗 -->
+		 <u-popup mode="center" :mask-close-able="false" negative-top="300" closeable @close="closePayModal" v-model="showInputPsw" width="500rpx" >
+			<view class="slot-content">
+				<view>确认支付</view>
+				<view class="text-cont">
+					<text class="num-big">{{totalPrice}}</text>
+					<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
 				</view>
-				<view v-if="orderInfo.endImage">
-					<view>洗车后</view>
-					<u-image @click="showImage(orderInfo.endImage)" width="100%" height="400rpx" mode="aspectFit" :src="orderInfo.endImage"></u-image>
+				<view class="footer">
+					<input 
+					v-model="password" 
+					:focus="focus"
+					@confirm="toPayOrder" 
+					maxlength="30" 
+					style="text-align: center;" type="password" 
+					placeholder="请输入支付密码" />
+				</view>
+				<view class="fot-btn">
+					<u-button  @click="toPayOrder" type="success" >确认支付</u-button>
 				</view>
 			</view>
-		</view>
-		<view v-if="orderInfo.orderStatus=='UN_PAY'" class="footer">
-			<u-button @click="cancleOrder" type="error" plain>取消订单</u-button>
-		</view>
+		</u-popup>
 	</view>
 </template>
 
 <script>
-	import {orderDetail, cancleOrder} from '@/api/order.js'
-	import {getLookUpDatas} from '@/api/data.js'
-	export default{
+	import {
+		orderDetail,
+		signPay,
+		existPayPwd
+	} from '@/api/order.js'
+	import {
+		getLookUpDatas
+	} from '@/api/data.js'
+	import moment from 'moment'
+	export default {
 		data() {
 			return {
-				orderInfo: null,
-				src: '',
-				orderStatusList: []
+				orderInfo: {},
+				totalPrice: 0, // 支付合计
+				password: '', // 支付密码
+				showSetPswModal: false,  // 设置支付密码弹窗
+				showInputPsw: false, // 打开输入密码弹窗
+				showLeavePsw: false, // 打开确定放弃弹窗
+				orderId: '', // 订单id
+				leftTime: null,
+				payFinish: false , // 是否支付成功
+				focus: false
 			}
 		},
 		onLoad(options) {
+			// 监听设置密码是否成功
+			uni.$once('setPswSuccess', this.setPsw)
 			if (options.id) {
 				console.log(options.id)
-				this.getOrderDetail(options.id)
-				this.orderStatusList = this.$store.state.vuex_payStatus
+				this.orderId = options.id
+				this.getOrderDetail()
 			}
 		},
-		methods:{
-			getOptionName (list,val) {
-			  if(val){
-				  let p = list.find((item) => {
-				  				  return item.code == val
-				  })
-				  return p ? p.dispName : '-'
-			  }
-			  return '-'
+		computed: {
+			
+		},
+		methods: {
+			// 支付剩余时间
+			leftTimeFun() {
+				const date1 = moment().toArray()  //  当前时间 数组形式
+				const date2 = moment(this.orderInfo.orderTime).toDate()  //  下单时间  日期格式
+				const date3 = moment(date2).toArray()  //  下单时间  数组形式
+				const date4 = moment(date1).diff(moment(date3), 'seconds')//计算相差的秒数
+				const tt = 30 - Math.ceil(date4/60)  //向上取整
+				if (tt > 0) {
+					this.leftTime = tt
+				} else {
+					// this.getOrderDetail()
+					this.leftTime = '00'
+				}
 			},
 			// 获取订单详情
-			getOrderDetail (id) {
-				let payTypeList = this.$store.state.vuex_payType
-				orderDetail({id:id}).then(res =>{
+			getOrderDetail() {
+				orderDetail({
+					id: this.orderId
+				}).then(res => {
+					console.log(res,'rrrrrrrr')
 					if (res.status == 200) {
 						this.orderInfo = res.data
-						this.orderInfo.payType = this.orderInfo.payType ? this.getOptionName(payTypeList,this.orderInfo.payType) : ''
-					} else {
-					}
+						if(this.orderInfo.orderState=='WAIT_PAY') {
+							this.leftTimeFun()
+						}
+					} 
 				})
 			},
-			// 取消订单
-			cancleOrder (){
-				cancleOrder({id:this.orderInfo.id}).then(res=>{
-					if (res.status==200) {
-						this.toashMsg(res.message)
-						setTimeout(()=>{
-							uni.navigateBack()
-						},500)
-					}
+			// 跳转到设置支付密码页
+			toSetPwd () {
+				uni.navigateTo({
+					url:"/pages/userCenter/userInfo/smsVerification"
 				})
 			},
-			// 图片预览
-			showImage (url) {
-				uni.previewImage({
-					urls: [url],
-					longPressActions: {
-						itemList: ['发送给朋友', '保存图片', '收藏'],
-						success: function(data) {
-							console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
-						},
-						fail: function(err) {
-							console.log(err.errMsg);
+			// 设置密码成功, 打开输入密码弹窗
+			setPsw (e) {
+				if (e.success) {
+					this.showInputPsw = true
+					setTimeout(()=>{
+						this.focus = true
+					},300)
+				}
+			},
+			// 关闭输入密码弹窗
+			closePayModal(){
+				if(!this.payFinish) {
+					this.showLeavePsw = true
+				} 
+			},
+			//确认放弃
+			canclePay() {
+				this.password = ''
+				this.showLeavePsw = false
+				this.showInputPsw = false
+				this.focus = false
+			},
+			// 继续支付
+			payAgain () {
+				this.focus = false
+				this.showLeavePsw = false
+				this.showInputPsw = true
+				setTimeout(()=>{
+					this.focus = true
+				},300)
+			},
+			// 支付 判断用户是否设置过支付密码
+			toPay() {
+				this.totalPrice = this.orderInfo.originalGold
+				this.payFinish = false
+				// 判断用户是否设置过支付密码
+				existPayPwd().then(res=>{
+					console.log(res,'rrrrrr')
+					if(res.status == 200) {
+						// 设置过支付密码,输入密码
+						if(res.data) {
+							this.showInputPsw = true
+							setTimeout(()=>{
+								this.focus = true
+							},300)
+						} else {
+							// 没设置过支付密码,提示设置密码
+							 this.showSetPswModal = true
 						}
+					} 
+				})
+			},
+			// 支付
+			toPayOrder() {
+				if (this.password === '') {
+					uni.showToast({
+						title: '请先输入支付密码',
+						icon: 'none'
+					})
+					return false
+				}
+				let id = this.orderInfo.id
+				let params = {
+					payPwd: this.password,
+					id: id
+				}
+				signPay(params).then(res=>{
+					this.btnLoading = false
+					if(res.status == 200) {
+						// 关闭弹窗 刷新页面
+						this.payFinish = true
+						this.showInputPsw = false
+						this.getOrderDetail()
+						// 刷新订单列表
+						uni.$emit('refresh')
+						// 跳转到支付完成界面
+						uni.navigateTo({
+							url:"/pages/toOrder/payFinish?id=" + id
+						})
+					} else{
+						this.password = ''
 					}
-				});
-			}
+				})
+			},
 		},
 	}
 </script>
@@ -128,52 +280,143 @@
 <style lang="scss">
 	page {
 		height: 100%;
+		background-color: #fff;
 	}
-	.order-pages{
+
+	.order-pages {
 		width: 100%;
 		height: 100%;
+		padding: 0 24upx;
 		display: flex;
 		flex-direction: column;
-		.order-info{
+
+		.order-info {
 			width: 100%;
 			flex: 1;
 			overflow-y: scroll;
-			.u-cell{
-				padding:10rpx 32rpx;
-			}
-			.order-photo{
-				padding:0 30rpx;
-				>view{
-					text-align: center;
-					padding: 20rpx;
+
+			// 状态
+			.order-status {
+				padding: 30upx 0;
+				text-align: center;
+
+				.status-title {
+					font-size: 36upx;
+					color: #000;
+				}
+
+				.status-care {
+					font-size: 24upx;
+					margin-top: 10upx;
+					color: #a9aaac;
+
+					>text {
+						color: red;
+					}
 				}
 			}
-			.FINISHED{
-				color: #00aa00;
-			}
-			.UN_PAY{
-				color: #ff0000;
-			}
-			.CANCELED{
-				color: #7e7b88;
-			}
-			.PAID{
-				color: #00aaff;
+
+			// 地址
+			.order-address {
+				font-size: 32upx;
+				padding: 20upx 0;
+
+				>view {
+					line-height: 60upx;
+				}
+
+				.address-title {
+					color: #000;
+				}
 			}
-			.REFUNDING{
-				color: #00557f;
+
+			// 订单中商品列表
+			.bundle-list {
+				display: flex;
+				padding: 20upx 10upx;
+				font-size: 28upx;
+				border-bottom: 1px solid #F8F8F8;
+
+				.img-cont {
+					width: 158rpx;
+					height: 140upx;
+					border-radius: 15upx;
+					overflow: hidden;
+
+					>image {
+						width: 100%;
+						height: 100%;
+					}
+				}
+
+				>view {
+					&:last-child {
+						flex: 1;
+						margin-left: 20upx;
+						padding: 10upx 0;
+						display: flex;
+						flex-direction: column;
+						justify-content: space-between;
+					}
+				}
+
+				.bundle-num {
+					display: flex;
+					justify-content: space-between;
+				}
 			}
-			.REFUNDED{
-				color: #005500;
+
+			.price-text {
+				font-size: 20upx;
+				margin-left: 10upx;
 			}
-			.order-price{
-				font-size: 36rpx;
+
+			.price-num {
+				font-size: 32upx;
 				color: red;
+				font-weight: 600;
+				margin-right: 6rpx;
+			}
+
+			.u-cell {
+				padding: 10rpx 32rpx;
 			}
 		}
-		.footer{
+		// 乐豆数量
+		.num-cont{
+			display: flex;
+			align-items: center;
+			float: right;
+		}
+		.footer {
 			padding: 20rpx;
 		}
-		
+		// 支付密码弹窗
+		.slot-content{
+			padding: 30upx 0;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: space-between;
+			.text-cont{
+				width: 100%;
+				padding: 60upx 0;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				.num-big{
+					font-size: 40upx;
+					color: red;
+					font-weight: 600;
+					margin-right: 6rpx;
+				}
+			}
+			.footer{
+				width: 80%;
+				border-bottom: 1px solid #b1b1b1;
+				margin-bottom: 30upx;
+			}
+		}
+
 	}
 </style>

+ 231 - 0
pages/store/store.vue

@@ -0,0 +1,231 @@
+<template>
+	<view class="content">
+		<map 
+		id="map" 
+		:latitude="lat" 
+		:longitude="lng" 
+		scale="18" 
+		show-compass 
+		show-location 
+		:markers="markers"
+		style="width: 100%; height:500rpx;">
+		</map>
+		<!-- 网点信息及设备 -->
+		<view class="details" v-if="stationData">
+			<view class="details-address">
+				<image src="/static/md-big-pic.png" class="store-pic"></image>
+				<view class="store-info">
+					<view>{{ stationData.name }}</view>
+					<view>{{ stationData.provinceName||'' }}{{ stationData.cityName||'' }}{{ stationData.districtName||'' }}{{ stationData.address||'' }}</view>
+					<view>
+						营业时间:
+						<text v-for="(tItem, tInd) in stationData.deliveryTimeRuleItemList" :key="tInd">
+							{{ tItem.openTime }} - {{ tItem.closeTime }}{{ tInd == stationData.deliveryTimeRuleItemList.length - 1 ? '' : ',' }}
+						</text>
+					</view>
+				</view>
+			</view>
+			<!-- 设备列表 -->
+			<view class="details-dev">
+				<view class="details-dev-box" v-for="item in deviceData">
+					<view class="details-dev-title">设备编号:<text>{{ item.srcDeviceCode }}</text></view>
+					<view class="details-dev-cons">
+						<view class="dev-item" v-for="boxItem in item.deviceTypeBoxList">
+							<view class="item-pic-con">
+								<text v-if="boxItem.flag==1" class="full-sign">已满</text>
+								<u-image mode="aspectFit" height="80" width="80" :src="`/static/${boxItem.rubbishType}.png`" class="type-sign"></u-image>
+							</view>
+							<view class="dev-main">
+								<view>
+									{{ boxItem.rubbishTypeDictValue }}
+								</view>
+								<view class="rule-con">
+									{{ getRule(boxItem.rubbishType).rubbishWeight }}g/
+									<text class="goleNum">{{ getRule(boxItem.rubbishType).goleNum }}</text>
+									<image src="/static/ledou.png" class="ld-pic"></image>
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+				<u-empty v-if="deviceData.length==0" icon-size="60" text="暂无设备" mode="list" margin-top="120"></u-empty>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { stationDetail, stationDevice } from '@/api/station.js'
+	export default {
+		data() {
+			return {
+				stationId: '',  //  网点id
+				stationNo: '',  //  网点编号
+				lat: '',
+				lng: '',
+				mapCtx: null, // 地图对象
+				markers: [], // 标注点
+				stationData: null,  //  网点信息
+				deviceData: [],  //  设备信息
+			};
+		},
+		onLoad(options) {
+			this.stationId = options.id
+			this.stationNo = options.stationNo
+			this.getStation()  //  网点信息
+			this.getDevice()  //  设备信息
+		},
+		methods: {
+			//  网点信息
+			getStation(){
+				stationDetail({ id: this.stationId }).then(res => {
+					if(res.status == 200){
+						this.stationData = res.data
+						this.markers = []
+						this.markers.push({
+							latitude: res.data.lat,
+							longitude: res.data.lng,
+							width: 30,
+							height: 30,
+							iconPath: "/static/store.png"
+						})
+						this.lng = res.data.lng
+						this.lat = res.data.lat
+					}else{
+						this.stationData = null
+						this.markers = []
+						this.lng = ''
+						this.lat = ''
+					}
+				})
+			},
+			//  设备信息
+			getDevice(){
+				stationDevice({ stationNo: this.stationNo }).then(res => {
+					if(res.status == 200){
+						this.deviceData = res.data
+					}else{
+						this.deviceData = []
+					}
+				})
+			},
+			//  根据垃圾类型获取兑换规则
+			getRule(type){
+				let row = null
+				if(this.stationData.goldExRuleItemList){
+					row = this.stationData.goldExRuleItemList.find(item => item.rubbishType == type)
+				}
+				return { rubbishWeight: row.rubbishWeight || 0, goleNum: row.goleNum || 0 }
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+.content{
+	width: 100%;
+	padding: 0;
+	.details{
+		margin: 20upx;
+		.details-address{
+			display: flex;
+			align-items: center;
+			padding: 20upx;
+			background: #FFFFFF;
+			border-radius: 15upx;
+			box-shadow: 0upx 3upx 6upx #eee;
+			margin-bottom: 20upx;
+			.store-pic{
+				width: 120rpx;
+				height:120rpx;
+				margin-right: 20rpx;
+			}
+			.store-info{
+				>view{
+					font-size: 24upx;
+					padding: 5upx 0;
+					color: #666;
+					&:first-child{
+						font-weight: bold;
+						font-size: 30upx;
+						color: #333;
+					}
+				}
+			}
+		}
+		.details-dev{
+			.details-dev-box{
+				padding: 20upx 20upx 5upx;
+				background: #FFFFFF;
+				border-radius: 15upx;
+				box-shadow: 0upx 3upx 6upx #eee;
+				margin-bottom: 20upx;
+				.details-dev-title{
+					border-bottom: 1px solid #F8F8F8;
+					padding: 10upx 0 20upx;
+					text{
+						color: #666;
+					}
+				}
+				.details-dev-cons{
+					padding: 10upx 0;
+					display: flex;
+					flex-wrap: wrap;
+					.dev-item{
+						width: 50%;
+						display: flex;
+						align-items: center;
+						> view{
+							padding: 25upx 10upx 15upx 0;
+							&:last-child{
+								view{
+									display: flex;
+									align-items: center;
+									.u-tag{
+										margin-left: 10upx;
+									}
+								}
+							}
+						}
+						.item-pic-con{
+							position: relative;
+							padding-left: 30rpx;
+							.full-sign{
+								font-size: 24rpx;
+								padding: 4rpx 10rpx 14rpx;
+								color: #fff;
+								background: url('/static/full-bg.png') no-repeat;
+								background-size: 100% 100%;
+								transform: scale(0.8);
+								position: absolute;
+								left: 0;
+								top: 0;
+								width: 68rpx;
+								height: 55rpx;
+								z-index: 9;
+							}
+						}
+						.dev-main{
+							.rule-con{
+								color: #666;
+								font-size: 24upx;
+								.goleNum{
+									color: #eb0000;
+									font-size: 26rpx;
+									font-weight: bold;
+									margin-left: 4rpx;
+								}
+								.ld-pic{
+									width: 30rpx;
+									height: 30rpx;
+									margin-left: 6rpx;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+</style>

+ 157 - 0
pages/toOrder/editAddress.vue

@@ -0,0 +1,157 @@
+<template>
+	<view class="content">
+		<u-form :model="form" ref="uForm" :label-width="140" :error-type="['toast']">
+			<u-form-item label="姓名" required prop="receiverName">
+				<u-input placeholder="请输入姓名" :maxlength="30" v-model="form.receiverName" />
+			</u-form-item>
+			<u-form-item label="电话" required prop="receiverPhone">
+				<u-input placeholder="请输入电话" :maxlength="11" type="number" v-model="form.receiverPhone" />
+			</u-form-item>
+			<u-form-item label="省市区" required prop="receiveAreasName">
+				<u-input v-model="areaInfo.label" placeholder="请选择省市区" @click="openAddress" type="select" />
+				<Address ref="applyAddress" @onConfirm="areaConfirm"></Address>
+			</u-form-item>
+			<u-form-item label="详细地址" required prop="receiveAddress">
+				<textarea :auto-height="true" placeholder="请输入收货详细地址(最多100个字符)" :maxlength="100" v-model="form.receiveAddress" class="receiveAddress"/>
+			</u-form-item>
+		</u-form>
+		<view class="buttons">
+			<u-button type="primary" @click="submit">提交</u-button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		saveAddress
+	} from '@/api/receiveAddress.js'
+	import Address from '@/components/address.vue'
+	export default {
+		components: {
+			Address
+		},
+		data() {
+			return {
+				show: false,
+				form: {
+					receiverName: '',
+					receiverPhone: '',
+					receiveAddress: '' // 详细地址
+				},
+				receiveAreas: '', //地址编码
+				areaName: '', //地址
+				areaInfo: {},  //  省市区
+				areaIdArr: [],  //  省市区id数组
+				rules: {
+				}
+			};
+		},
+		onLoad(option) {
+			this.form = this.$store.state.vuex_OrderAddress
+			if (this.form.receiveAreasName) {
+				this.areaIdArr = this.form.receiveAreas.split(',')
+				this.areaInfo.label = this.form.receiveAreasName.replace(/\,/g,'-')
+				uni.setNavigationBarTitle({
+					title: '修改地址'
+				})
+			} else {
+				uni.setNavigationBarTitle({
+					title: '新增地址'
+				})
+			}
+		},
+		onUnload() {
+			this.$u.vuex("vuex_OrderAddress",{})
+		},
+		methods: {
+			submit() {
+				this.$refs.uForm.validate(valid => {
+					if (valid) {
+						console.log('验证通过');
+						if (this.form.receiverName ==='') {
+							uni.showToast({
+								title: '请输入姓名',
+								icon: 'none'
+							})
+							return false
+						}
+						if (this.form.receiverPhone ==='') {
+							uni.showToast({
+								title: '请输入电话',
+								icon: 'none'
+							})
+							return false
+						}
+						//  省市区
+						if(this.areaIdArr.length == 0){
+							uni.showToast({icon: 'none',title: '请选择省市区'})
+							return
+						}
+						if (this.form.receiveAddress ==='') {
+							uni.showToast({
+								title: '请输入详细地址',
+								icon: 'none'
+							})
+							return false
+						}
+						let params = {
+							receiverName: this.form.receiverName,
+							receiverPhone: this.form.receiverPhone,
+							receiveAreasName: this.areaInfo.label.replace(/\-/g,','), // 地址名称
+							receiveAreas: this.areaIdArr.join(','), 
+							receiveAddress: this.form.receiveAddress // 详细地址
+						}
+						if(this.form.id) {
+							params.id = this.form.id
+						}
+						saveAddress(params).then(res=>{
+							if(res.status == 200) {
+								uni.showToast({
+									title: res.message,
+									icon: 'none'
+								})
+								setTimeout(()=>{
+									uni.navigateBack()
+								},300)
+							} 
+						})
+					} else {
+						console.log('验证失败');
+					}
+				});
+			},
+			//  选择省区市
+			areaConfirm(e) {
+				console.log('已选择的省市区', e)
+				this.areaInfo = e
+				this.areaIdArr = [ e.provinceCode, e.cityCode, e.areaCode ]
+			},
+			openAddress(){
+				//  省市区  回显     参数为省市区id数组
+				// console.log(this.areaIdArr,'this.areaIdArr')
+				this.$refs.applyAddress.open(this.areaIdArr)
+			},
+		},
+		// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
+		onReady() {
+			this.$refs.uForm.setRules(this.rules);
+		}
+	};
+</script>
+
+<style lang="scss">
+	.content{
+		padding: 0 50upx;
+		background: #FFFFFF;
+		width: 100%;
+		.buttons{
+			padding: 80upx 100upx;
+		}
+		.receiveAddress{
+			width: 100%;
+			line-height: 1.5em;
+			box-sizing: border-box;
+			font-style: normal;
+		}
+	}
+</style>

+ 465 - 0
pages/toOrder/index.vue

@@ -0,0 +1,465 @@
+<template>
+	<view class="cart-pages">
+		<view v-if="!userInfo.receiveAddress" @click="editAddress" class="noAddress">
+			<view>请输入收货地址</view>
+			<u-icon name="arrow-right" size="36"></u-icon>
+		</view>
+		<view v-else class="cart-bar">
+			<view>
+				<u-image height="40rpx" width="40rpx" src="/static/position.png"></u-image>
+			</view>
+			<view class="position">
+				 <view class="address">{{receiveAddress}}</view>
+				 <view>{{userInfo.receiverName +'&nbsp;&nbsp;&nbsp;' + userInfo.receiverPhone}}</view>
+			</view>
+			<view @click="editAddress">
+				<u-image height="50rpx" width="50rpx" src="/static/edit.png"></u-image>
+			</view>
+		</view>
+		<view class="goods-list">
+			<!-- 商品列表 -->
+			<view class="goods-item" v-for="(item,index) in goodsList" :key="item.id">
+				<view class="goods-imgs">
+					<u-image border-radius="12" width="158rpx" height="140rpx" :src="item.goods.homeImage"></u-image>
+				</view>
+				<view class="goods-info">
+					<view class="good-name">{{item.goods.name}}</view>
+					<view class="goods-price">
+						<view>
+							<text>{{item.goods.sellGold}}</text>
+							<u-image mode="scaleToFill" width="30rpx" height="30rpx" src="/static/ledou.png"></u-image>
+						</view>
+						<view>×{{item.buyQty}}</view>
+					</view>
+				</view>
+			</view>
+			<!-- 总计 -->
+			<view class="goods-heji">
+				<view>
+					<view>商品合计:</view>
+					<view class="heji">
+						<text>{{totalPrice}}</text>
+						<u-image mode="scaleToFill" width="35rpx" height="35rpx" src="/static/ledou.png"></u-image>
+					</view>
+				</view>
+				<view>
+					<view>运费:</view>
+					<view>免运费</view>
+				</view>
+			</view>
+		</view>
+		<view class="cart-submit">
+			<view>
+			  <view>总计:<text>{{totalPrice}}</text></view>
+			  <u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+			</view>
+			<view>
+				<u-button size="mini" :loading="btnLoading" :custom-style="toOrderButton" type="success" @click="toSaveOrder">确认支付</u-button>
+			</view>
+		</view>
+		<!-- 提示用户设置支付密码 -->
+		<u-modal v-model="showSetPswModal" 
+		content="请先设置支付密码,才能使用乐豆" 
+		show-cancel-button 
+		confirm-text="去设置" 
+		cancel-text="暂时放弃"
+		@confirm="toSetPwd"
+		@cancel="showSetPswModal=false"
+		></u-modal>
+		<!-- 确认取消弹窗 -->
+		<u-modal v-model="showLeavePsw" 
+		title="确认放弃支付吗?"
+		content="您的订单在30分钟内未支付将被取消" 
+		show-cancel-button 
+		confirm-text="确认放弃" 
+		cancel-text="继续支付"
+		@confirm="canclePay"
+		@cancel="payAgain"
+		></u-modal>
+		<!-- 确认支付弹窗 -->
+		 <u-popup mode="center" :mask-close-able="false" negative-top="300" closeable @close="showLeavePsw=true" v-model="showInputPsw" width="500rpx" >
+			<view class="slot-content">
+				<view>确认支付</view>
+				<view class="text-cont">
+					<text class="num-big">{{totalPrice}}</text>
+					<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+				</view>
+				<view class="footer">
+					<input 
+					v-model="password" 
+					maxlength="30" 
+					:focus="focus"
+					style="text-align: center;"
+					type="password" 
+					@confirm="toPay"
+					placeholder="请输入支付密码" />
+				</view>
+				<view class="fot-btn">
+					<u-button :loading="payBtn" @click="toPay" type="success" >确认支付</u-button>
+				</view>
+			</view>
+		</u-popup>
+	</view>
+</template>
+
+<script>
+	import { saveOrder, signPay, existPayPwd} from '@/api/order.js'
+	import {
+		findAddressBycustomerNo
+	} from '@/api/receiveAddress.js'
+	export default {
+		data() {
+			return {
+				toOrderButton: {
+					borderRadius:'100rpx',
+					fontSize:'30rpx',
+					width: '200rpx',
+					height: '80rpx'
+				},
+				goodsList: [], // 商品列表
+				// 用户信息
+				userInfo: {},
+				btnLoading: false,  // 提交按钮加载圈
+				orderId: '', // 订单id
+				password: '', // 支付密码
+				showSetPswModal: false,  // 设置支付密码弹窗
+				showInputPsw: false, // 打开输入密码弹窗
+				showLeavePsw: false, // 打开确定放弃弹窗
+				payBtn: false,
+				orderForm: '', // 商品下单来源,商品详情或购物车
+				focus: false
+			};
+		},
+		onShow() {
+			this.getLocation()
+		},
+		onLoad(opts) {
+			this.orderForm = opts.orderForm
+			this.goodsList = this.$store.state.vuex_toOrderList
+			// 监听设置密码是否成功
+			uni.$once('setPswSuccess', this.setPsw)
+		},
+		computed: {
+			// 总计
+			totalPrice() {
+				let total = 0
+				this.goodsList.map(item => {
+					total = total + item.buyQty * item.goods.sellGold
+				})
+				return total 
+			},
+			// 收货地址
+			receiveAddress() { 
+				if (this.userInfo.receiveAreasName) {
+					let area = this.userInfo.receiveAreasName.split(',')
+					return area[0]+area[1]+area[2]+this.userInfo.receiveAddress
+				}
+			}
+		},
+		methods: {
+			// 获取用户位置
+			getLocation() {
+				 findAddressBycustomerNo({}).then(res => {
+					 console.log(res)
+					 if (res.status == 200) {
+						 this.userInfo = res.data[0] || {}
+					 } else {
+						 this.userInfo = {}
+					 }
+				 })
+			},
+			//新增/修改收货地址信息
+			editAddress(){
+				this.$u.vuex("vuex_OrderAddress",this.userInfo)
+				uni.navigateTo({
+					url:"/pages/toOrder/editAddress"
+				})
+			},
+			// 跳转到设置支付密码页
+			toSetPwd () {
+				uni.navigateTo({
+					url:"/pages/userCenter/userInfo/smsVerification"
+				})
+			},
+			// 设置密码成功, 打开输入密码弹窗
+			setPsw (e) {
+				if (e.success) {
+					this.showInputPsw = true
+					setTimeout(()=>{
+						this.focus = true
+					},300)
+				}
+			},
+			//确认放弃
+			canclePay() {
+				this.showLeavePsw = false
+				this.showInputPsw = false
+				this.focus = false
+				this.password = ''
+				// 跳转到订单列表
+				uni.redirectTo({
+					url:"/pages/order/order"
+				})
+			},
+			// 继续支付
+			payAgain () {
+				this.focus = false
+				this.showLeavePsw = false
+				this.showInputPsw = true
+				setTimeout(()=>{
+					this.focus = true
+				},300)
+			},
+			// 支付  校验用户是否设置过支付密码
+			toCheckPwd(){
+				// 判断用户是否设置过支付密码
+				existPayPwd().then(res=>{
+					console.log(res,'rrrrrr')
+					if(res.status == 200) {
+						// 设置过支付密码,输入密码
+						if(res.data) {
+							this.showInputPsw = true
+							setTimeout(()=>{
+								this.focus = true
+							},300)
+						} else {
+							// 没设置过支付密码,提示设置密码
+							 this.showSetPswModal = true
+						}
+					} 
+				})
+			},
+			// 支付  保存订单
+			toSaveOrder () {
+				if (!this.userInfo.receiveAddress) {
+					uni.showToast({
+						title: '请先输入收货地址',
+						icon: 'none'
+					})
+					return false
+				}
+				// 已生成订单
+				if(this.orderId) {
+					// 校验用户是否设置过支付密码
+					this.toCheckPwd()
+				} else {
+					this.btnLoading = true
+					let orderGoodsList = []
+					this.goodsList.map((item,index)=>{
+						orderGoodsList[index] = {
+							goodsNo: item.goodsNo,
+							buyQty: item.buyQty
+						}
+					})
+					
+					let params = {
+						receiveAddress: this.receiveAddress,
+						receiverName: this.userInfo.receiverName,
+						receiverPhone: this.userInfo.receiverPhone,
+						orderGoodsList: orderGoodsList,
+						orderForm: this.orderForm,
+						payGold: this.totalPrice
+					}
+					saveOrder(params).then(res=>{
+						console.log(res,'rrrrrrr')
+						this.btnLoading = false
+						if(res.status==200) {
+							this.orderId = res.data.id
+							// 校验用户是否设置过支付密码
+							this.toCheckPwd()
+							// 刷新购物车
+							uni.$emit('getCartList')
+						} 
+					})
+				}
+			},
+			// 支付
+			toPay() {
+				if (this.password === '') {
+					uni.showToast({
+						title: '请先输入支付密码',
+						icon: 'none'
+					})
+					return false
+				}
+				let params = {
+					payPwd: this.password,
+					id: this.orderId
+				}
+				this.payBtn = true
+				signPay(params).then(res=>{
+					this.payBtn = false
+					if(res.status == 200) {
+						// 跳转到支付完成界面
+						uni.redirectTo({
+							url:"/pages/toOrder/payFinish?id=" + this.orderId
+						})
+					} else{
+						this.password = ''
+					}
+				})
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+page{
+	height: 100%;
+}
+.cart-pages{
+	width: 100%;
+	height: 100%;
+	display: flex;
+	flex-direction: column;
+	.cart-bar{
+		background: #FFFFFF;
+		border-bottom: 1px solid #F8F8F8;
+		border-top: 10upx solid #F8F8F8;
+		display: flex;
+		align-items: center;
+		padding:15upx 20upx;
+		.position{
+			flex-grow: 1;
+		}
+		> view{
+			padding: 10upx;
+			.address{
+				padding: 5upx 0;
+			}
+			&:last-child{
+				padding: 0 20upx;
+			}
+		}
+	}
+	.noAddress{
+		background: #FFFFFF;
+		border-bottom: 1px solid #F8F8F8;
+		border-top: 10upx solid #F8F8F8;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		padding:30upx 20upx;
+		font-size: 30upx;
+	}
+	.goods-list{
+		padding: 20upx 0;
+		flex-grow: 1;
+		overflow: auto;
+		.goods-class-box{
+			background: #FFFFFF;
+			box-shadow: 1px 1px 3px #eee;
+			margin-bottom: 20upx;
+		}
+		
+		.goods-item{
+			padding: 20upx 40upx;
+			display: flex;
+			align-items: center;
+			border-bottom: 1px solid #F8F8F8;
+			background: #fff;
+			&:last-child{
+				border: 0;
+			}
+			.goods-imgs{
+				position: relative;
+			}
+			.goods-info{
+				flex-grow: 1;
+				padding-left: 20upx;
+				.good-name{
+					font-weight: bold;
+					word-break: break-all;
+				}
+			}
+			.goods-price{
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				padding-top: 20upx;
+				>view{
+					&:first-child{
+						display: flex;
+						align-items: center;
+						text{
+							color: red;
+							font-size: 35upx;
+							margin-right: 6upx;
+							font-weight: bold;
+						}
+					}
+				}
+			}
+		}
+	}
+	.goods-heji{
+		padding: 20upx 40upx;
+		background: #FFFFFF;
+		box-shadow: 1px 1px 3px #eee;
+		margin-top: 20upx;
+		>view{
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 10upx 0;
+			.heji{
+				display: flex;
+				align-items: center;
+				text{
+					color: red;
+					margin-right: 6upx;
+					font-size: 35upx;
+					font-weight: bold;
+				}
+			}
+		}
+	}
+	.cart-submit{
+		padding: 20upx 30upx;
+		background: #FFFFFF;
+		box-shadow: 1px 1px 3px #eee;
+		border-top: 1px solid #eee;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		> view{
+			&:first-child{
+				display: flex;
+				align-items: center;
+				text{
+					color: red;
+					font-size: 40upx;
+					margin-right: 6upx;
+					font-weight: bold;
+				}
+			}
+		}
+	}
+	// 支付密码弹窗
+	.slot-content{
+		padding: 30upx 0;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-between;
+		.text-cont{
+			width: 100%;
+			padding: 60upx 0;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			.num-big{
+				font-size: 40upx;
+				color: red;
+				font-weight: 600;
+				margin-right: 6rpx;
+			}
+		}
+		.footer{
+			width: 80%;
+			border-bottom: 1px solid #b1b1b1;
+			margin-bottom: 30upx;
+		}
+	}
+}
+</style>

+ 75 - 0
pages/toOrder/payFinish.vue

@@ -0,0 +1,75 @@
+<template>
+	<view class="page-cont">
+		<view class="icon-cont">
+			<u-icon class="icon" name="checkmark" color="#fff" size="80"></u-icon>
+			<view>支付成功</view>
+		</view>
+		<u-button @click="toOrderDetail" type="success">查看订单详情</u-button>
+		<view class="back-btn">
+			<u-button @click="toHome">返回首页</u-button>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			orderId: '' //订单id
+		}
+	},
+	onLoad(option) {
+		console.log(option,'option')
+		this.orderId = option.id
+	},
+	methods: {
+		// 查看订单详情
+		toOrderDetail() {
+			uni.redirectTo({
+			    url: '/pages/order/orderDetail?id=' + this.orderId
+			})
+		},
+		// 返回首页
+		toHome() {
+			uni.reLaunch({
+			    url: '/pages/index/index'
+			})
+		}
+	}
+}
+</script>
+
+<style lang="less">
+	page{
+		height: 100%;
+	}
+	.page-cont{
+		width: 100%;
+		height: 100%;
+		background-color: #fff;
+		padding: 0 40upx;
+		.icon-cont{
+			width: 100%;
+			height: 400upx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			>view{
+				font-size: 30upx;
+				margin-top: 40upx;
+			}
+		}
+		.icon{
+			width: 120upx;
+			height: 120upx;
+			background-color: #07c160;
+			display: flex;
+			justify-content: center;
+			border-radius: 50%;
+		}
+		.back-btn{
+			margin-top: 40upx;
+		}
+	}
+</style>

+ 62 - 0
pages/userCenter/aboutUs.vue

@@ -0,0 +1,62 @@
+<template>
+	<view class="container">
+		<view class="logoContent">
+			<view class="logoBorder">
+				<image class="logoImg" src="/static/logo.png"></image>
+			</view>
+		</view>
+		<view class="textContent">
+			<view>智享亿家作为中国出色的垃圾分类专家和平台,致力于改变中国社区环保现状,通过多年的耕耘和积累,打造的城市垃圾分类一体化智能解决方案已获得咸阳、西安航天等多地市的环保垃圾处理资格,并成为全国住建部在咸阳市的环保模范单位。</view>
+		</view>
+	</view>
+</template>
+
+<script>
+</script>
+
+<style lang="less">
+	page{
+		background: #FFFFFF;
+	}
+	.container{
+		font-size: 32rpx;
+		padding:0 50rpx;
+		text-align: center;
+		color:#666;
+		.logoContent{
+			.logoBorder{
+				width:200rpx;
+				height:200rpx;
+				border:2px solid #eee;
+				border-radius: 20rpx;
+				margin:50rpx 0 15rpx 0;
+				display: inline-block;
+				position: relative;
+				.logoImg{
+					width:180rpx;
+					height:180rpx;
+					position: absolute;
+					top:0;
+					left:0;
+					right:0;
+					bottom:0;
+					margin:auto;
+				}
+			}
+		}
+		.textContent{
+			text-align: left;
+			margin-top: 30rpx;
+			font-size: 32rpx;
+			.tetxTitle{
+				margin-bottom: 10rpx;
+				font-size: 32rpx;
+			}
+			> view{
+				padding: 16upx 0;
+				line-height: 50upx;
+				text-indent: 60rpx;
+			}
+		}
+	}
+</style>

+ 155 - 0
pages/userCenter/deliveryRecord.vue

@@ -0,0 +1,155 @@
+<template>
+	<view class="deliveryRecord-container">
+		<scroll-view class="scroll-con" scroll-y @scrolltolower="onreachBottom">
+			<!-- 列表数据 -->
+			<view class="cell-item-con">
+				<u-gap height="15"></u-gap>
+				<view class="cell-item" v-for="(item, index) in listdata" :key="index">
+					<text class="cell-item-date">{{item.deliveryTime}}</text>
+					<view class="cell-item-main">
+						<u-image mode="scaleToFill" shape="circle" width="80rpx" height="80rpx" :src="`/static/${item.rubbishType}.png`" class="cell-item-pic"></u-image>
+						<view class="cell-item-r">
+							<view class="cell-item-head">
+								<view class="cell-item-val">
+									<text class="cell-item-num">{{item.rubbishWeight}}</text>克
+							    </view>
+								<view class="cell-item-ledu">
+									<text>+{{item.goldNum}}</text>
+								    <u-image mode="scaleToFill" width="34rpx" height="34rpx" src="/static/ledou.png"></u-image>
+								</view>
+							</view>
+							<text class="cell-item-des">{{item.stationName}}</text>
+						</view>
+					</view>
+				</view>
+			</view>
+			<u-empty class="nodata" :text="noDataText" v-if="listdata.length==0 && status!='loading'" mode="list"></u-empty>
+			<view class="loadmore">
+				<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import {
+		getDeliveryLogList
+	} from '@/api/deliveryRecord.js'
+	export default {
+		data() {
+			return {
+				listdata: [],
+				pageNo: 1,  //  当前页码
+				pageSize: 10,  //  每页条数
+				total: 0,  //  数据总条数
+				noDataText: '暂无数据',  //  列表请求状态提示语
+				status: 'loadmore',  //  加载中状态
+			}
+		},
+		onShow() {
+			this.searchHandle(1)
+		},
+		methods:{
+			// 搜索查询
+			searchHandle (pageNo,suppName) {
+				this.status = "loading"
+				pageNo ? this.pageNo = pageNo : null
+				getDeliveryLogList({
+					pageNo: this.pageNo,
+					pageSize: this.pageSize,
+				}).then(res => {
+					if (res.status == 200) {
+						if(this.pageNo>1){
+							this.listdata = this.listdata.concat(res.data.list || [])
+						}else{
+							this.listdata = res.data.list || []
+						}
+						this.total = res.data.count || 0
+					} else {
+						this.noDataText = res.message
+						this.listdata = []
+						this.total = 0
+					}
+					this.status = "loadmore"
+				})
+			},
+			// scroll-view到底部加载更多
+			onreachBottom() {
+				if(this.listdata.length < this.total){
+					this.pageNo += 1
+					this.searchHandle()
+				}else{
+					uni.showToast({ title: '已经到底了', icon: 'none' })
+					this.status = "nomore"
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.deliveryRecord-container{
+		width: 100%;
+		//  列表
+		.scroll-con{
+			height: 100%;
+			overflow: auto;
+		}
+		//  列表样式
+		.cell-item-con{
+			.cell-item{
+				background-color: #fff;
+				color: #606266;
+				padding: 20rpx 32rpx 22rpx;
+				border-bottom: 1rpx solid #EEEEEE;
+				&:last-child{
+					border:0;
+				}
+				.cell-item-date{
+					display: block;
+					color: #909399;
+					font-size: 24rpx;
+				}
+				.cell-item-main{
+					display: flex;
+					justify-content: space-around;
+					align-items: center;
+					padding-top: 14rpx;
+					.cell-item-pic{
+						flex-shrink: 0;
+						margin-right: 20rpx;
+					}
+					.cell-item-r{
+						flex-grow: 1;
+						.cell-item-head{
+							display: flex;
+							justify-content: space-between;
+							align-items: center;
+							.cell-item-val{
+								font-size: 30rpx;
+								font-weight: bold;
+								.cell-item-num{
+									display: inline-block;
+									margin-right: 6rpx;
+								}
+							}
+							.cell-item-ledu{
+								display: flex;
+								justify-content: space-between;
+								align-items: center;
+								text{
+									font-size: 40rpx;
+									color: #01c9b2;
+								}
+							}
+						}
+						.cell-item-des{
+							color: #909399;
+							font-size: 26rpx;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 35 - 0
pages/userCenter/fenlei.vue

@@ -0,0 +1,35 @@
+<template>
+	<view class="zn-container">
+		<u-image width="750rpx" height="2722rpx" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/9a11b2813f3548a19b77d97c1cb0ae8c.jpg"></u-image>
+		<u-image width="750rpx" height="1117rpx" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/8c40db43da34483ba1493daa584e2ff3.jpg"></u-image>
+		<u-image width="750rpx" height="2423" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/da88fdfe54384906a4ba0491dcbfb376.jpg"></u-image>
+		<u-image width="750rpx" height="4259" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/77e0d574d1ef496ba1e5cc72acf927f7.jpg"></u-image>
+		<u-image width="750rpx" height="2824" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/8964ef3f71534ef0b8f9568dedd5ce14.jpg"></u-image>
+		<u-image width="750rpx" height="2526" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/1be83306886a47ebaf2d1bd2ac23ea59.jpg"></u-image>
+		<u-image width="750rpx" height="4336" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/dc07c79759374f45a2b7e180ea837d20.jpg"></u-image>
+		<u-image width="750rpx" height="3591" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/bdd2c38634ad434c8e776870328fe1e1.jpg"></u-image>
+		<u-image width="750rpx" height="4698" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/099d4966e7d8437b84f464e60bc2f375.jpg"></u-image>
+		<u-image width="750rpx" height="2211" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/6327e833ff514966b4a365b9fb40ffb5.jpg"></u-image>
+		<u-image width="750rpx" height="1116" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/1cc4cc47dfdb4d40ac78b997c49f8912.jpg"></u-image>
+		<u-image width="750rpx" height="2841" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/4f896f1078af4f998679bf08a06e5df3.jpg"></u-image>
+		<u-image width="750rpx" height="1884" src="https://chelingzhu.oss-cn-beijing.aliyuncs.com/dev/2020/11/10/58c40a9d9101419fafc4d6a347622ea7.jpg"></u-image>
+	</view>
+</template>
+
+<script>
+	export default{
+		data() {
+			return {
+				baseUrl: ''
+			}
+		},
+		onLoad() {
+		}
+	}
+</script>
+
+<style lang="less">
+	.zn-container{
+		width: 100%;
+	}
+</style>

+ 119 - 38
pages/userCenter/index.vue

@@ -1,74 +1,126 @@
 <template>
 	<view class="user-content">
 		<!-- 头部 -->
-		<view class="user-head">
+		<view class="user-head" @click="toUserPage">
 			<view class="user-photo">
 				<open-data type="userAvatarUrl"></open-data>
+				<u-image v-show="!hasLogin" src="/static/logo.png" width="100" height="100"></u-image>
 			</view>
 			<view class="user-info">
-				<open-data type="userNickName"></open-data>
+				<text v-if="hasLogin">{{user.mobile||'--'}}</text>
+				<u-button v-else="!hasLogin" plain size="mini" shape="circle" @click="toLoginPage">立即登录</u-button>
+			</view>
+			<view v-if="hasLogin">
+				<u-icon name="arrow-right" color="#fff"></u-icon>
+			</view>
+		</view>
+		<view class="my-ledou" v-if="hasLogin">
+			<view class="user-jifen">
+				<view>我的乐豆:<text>{{user.currentGold||0}}</text></view>
+				<u-image mode="scaleToFill" width="35rpx" height="35rpx" src="/static/ledou.png"></u-image>
+			</view>
+			<view>
+				<u-button size="mini" type="warning" shape="circle" @click="toLdPage">查看明细</u-button>
 			</view>
 		</view>
 		<!-- 列表 -->
 		<view class="user-list">
 			<u-cell-group>
-				<u-cell-item icon="gift" index="0" @click="toPage" title="我的优惠卷"></u-cell-item>
-				<u-cell-item icon="order" index="1" @click="toPage" title="我的订单"></u-cell-item>
-				<u-cell-item icon="file-text" index="2" @click="toPage" title="服务协议"></u-cell-item>
-				<!-- <u-cell-item icon="info-circle" index="3" @click="toPage" title="关于我们"></u-cell-item> -->
+				<u-cell-item v-if="hasLogin" icon="order" icon-size="38" :icon-style="{color:'#ff5500'}" index="0" @click="toPage" title="我的订单"></u-cell-item>
+				<u-cell-item v-if="hasLogin" icon="gift" icon-size="40" :icon-style="{color:'#00aaff'}" index="1" @click="toPage" title="投递记录"></u-cell-item>
+				<u-cell-item icon="question-circle" icon-size="40" :icon-style="{color:'#19be6b'}" index="2" @click="toPage" title="常见问题"></u-cell-item>
+				<u-cell-item icon="phone" icon-size="40" :icon-style="{color:'#f00'}" @click="callPhone" title="联系客服"></u-cell-item>
+				<u-cell-item icon="file-text" icon-size="40" :icon-style="{color:'#ffaa00'}" index="3" @click="toPage" title="服务协议"></u-cell-item>
+				<u-cell-item icon="info-circle" icon-size="38" :icon-style="{color:'#55aa00'}" index="4" @click="toPage" title="关于我们"></u-cell-item>
 			</u-cell-group>
 		</view>
-		<!-- 退出 -->
-		<view class="user-btn">
-			<u-button type="error" @click="quitSys" shape="circle">退出登录</u-button>
-		</view>
 	</view>
 </template>
 
 <script>
-	import {logout} from '@/api/login.js'
+	import { checkLogin, getUserInfo } from '@/api/login.js'
 	export default {
 		data() {
 			return {
-				
+				hasLogin: false,
+				userData: {}
 			};
 		},
 		onShow() {
+			checkLogin().then(res => {
+				this.hasLogin = res.status == 200
+				if(this.hasLogin){
+					this.getUserInfo()
+				}else{
+					uni.navigateTo({
+						url:"/pages/login/login"
+					})
+				}
+			})
+		},
+		computed: {
+			user() {
+				return this.userData 
+			}
 		},
 		onLoad() {
 		},
 		methods:{
+			// 获取用户信息
+			getUserInfo(){
+				getUserInfo().then(res => {
+					console.log(res,'getUserInfo')
+					if(res.status == 200){
+						this.$u.vuex("vuex_userData",res.data)
+						this.userData = res.data
+					}
+				})
+			},
 			// 打开对应的页面
 			toPage(index){
-				let pageUrl=['/pages/coupon/index/index','/pages/order/order','/pages/agreement/agreement?fromPage=usercenter']
+				console.log(index)
+				let pageUrl=[
+					'/pages/order/order',
+					'/pages/userCenter/deliveryRecord',
+					'/pages/userCenter/question',
+					'/pages/agreement/agreement?fromPage=usercenter',
+					'/pages/userCenter/aboutUs'
+					]
 				uni.navigateTo({
 					url: pageUrl[index]
 				})
 			},
-			// 退出登录
-			quitSys(){
-				let _this = this
-				uni.showModal({
-				  title: '提示',
-				  content: '您确定要退出登录吗?',
-				  success(res) {
-				    if (res.confirm) {
-				      logout({}).then(res => {
-				       getApp().globalData.token = ''
-				       _this.$u.vuex('vuex_token','')
-					   // 关闭socket
-					   _this.$store.commit("$closeWebsocket")
-				        uni.reLaunch({
-				        	url: '/pages/index/index'
-				        });
-				      });
-				    }
-				  }
-				});
+			// 电话客服
+			callPhone () {
+				uni.makePhoneCall({
+				    phoneNumber: this.$store.state.vuex_kfMobile
+				})
+			},
+			//  跳转
+			toUserPage(){
+				//  未登录跳转登录,已登录跳转用户信息页
+				if(this.hasLogin){
+					uni.navigateTo({
+						url: '/pages/userCenter/userInfo/userInfo'
+					})
+				}else{
+					this.toLoginPage()
+				}
+			},
+			//  乐豆明细
+			toLdPage(){
+				uni.navigateTo({
+					url: '/pages/userCenter/ldDetailed'
+				})
 			},
 			bindGetUserInfo(res){
 				console.log(res)
 			},
+			toLoginPage(){
+				uni.navigateTo({
+					url: '/pages/login/login'
+				})
+			}
 		}
 	}
 </script>
@@ -77,27 +129,56 @@
 	.user-content{
 		width: 100%;
 		.user-head{
+			background: #01c9b2;
 			display: flex;
 			align-items: center;
-			padding: 35rpx;
+			padding: 35rpx 55rpx;
 			.user-info{
 				flex-grow: 1;
 				padding: 0 20rpx;
+				color: #FFFFFF;
 			}
 			.user-photo{
 				width: 100rpx;
 				height: 100rpx;
 				border-radius: 50%;
 				overflow: hidden;
-				margin-right: 30rpx;
+				margin-right: 5rpx;
+			}
+		}
+		.my-ledou{
+			background: #FFFFFF;
+			border-radius: 15upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 20upx;
+			margin: 20upx;
+			box-shadow: 0upx 3upx 6upx #eee;
+			.user-jifen{
+				display: flex;
+				align-items: center;
+				text{
+					font-size: 40upx;
+					font-weight: bold;
+					color: red;
+				}
+				>view{
+					&:first-child{
+						display: flex;
+						align-items: center;
+					}
+				}
 			}
 		}
-		
 		.user-list{
-			padding:0 20rpx;
+			border-radius: 15upx;
+			margin: 20upx;
+			overflow: hidden;
+			box-shadow: 0upx 3upx 6upx #eee;
 		}
 		.user-btn{
-			padding: 85rpx 100rpx;
+			padding: 85rpx 200rpx;
 		}
 	}
 </style>

+ 229 - 0
pages/userCenter/ldDetailed.vue

@@ -0,0 +1,229 @@
+<template>
+	<view class="ldDetailed-container">
+		<!-- 筛选菜单 -->
+		<u-dropdown ref="uDropdown" class="filter-dropdown">
+			<u-dropdown-item v-model="queryParam.changeType" :title="titType" :options="optionsType" @change="searchHandle()"></u-dropdown-item>
+			<u-dropdown-item v-model="timeScope" :title="titScope" :options="optionsScope" @change="searchHandle()"></u-dropdown-item>
+		</u-dropdown>
+		<scroll-view class="scroll-con" scroll-y @scrolltolower="onreachBottom">
+			<!-- 列表数据 -->
+			<view class="cell-item-con">
+				<view class="cell-item" v-for="(item, index) in listdata" :key="index">
+					<text class="cell-item-month" v-if="timeScope == 'threeMonth'">{{item.month}}</text>
+					<view class="cell-item-main" v-for="(subItem, ind) in item.monthDataList" :key="ind">
+						<view :class="['cell-item-pic']">
+							<u-image mode="scaleToFill" v-if="subItem.changeType == 'ADD'" shape="circle" width="70rpx" height="70rpx" src="/static/tudi.png"></u-image>
+							<u-image mode="scaleToFill" v-else shape="circle" width="70rpx" height="70rpx" src="/static/bued.png"></u-image>
+						</view>
+						<view class="cell-item-c">
+							<text class="cell-item-des">{{subItem.operateTypeDictValue||'--'}}</text>
+							<text class="cell-item-date">{{subItem.createDate}}</text>
+						</view>
+						<view :class="['cell-item-score', subItem.changeType == 'ADD' ? 'black' : 'red']">
+							<text>{{subItem.changeType == 'ADD' ? '+'+subItem.changeNum : '-'+subItem.changeNum}}</text>
+							<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
+						</view>
+					</view>
+					<view class="nodata" v-if="item.monthDataList.length==0 && status!='loading'">
+						<u-empty :text="noDataText" mode="list"></u-empty>
+					</view>
+				</view>
+			</view>
+			<view class="nodata" v-if="listdata.length==0 && status!='loading'">
+				<u-empty :text="noDataText" mode="list"></u-empty>
+			</view>
+			<view class="loadmore">
+				<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import {ldUsedQuery} from '@/api/user.js'
+	import getDate from '@/libs/getDate'
+	import moment from 'moment'
+	export default {
+		data() {
+			return {
+				listdata: [],
+				pageNo: 1,  //  当前页码
+				pageSize: 10,  //  每页条数
+				total: 0,  //  数据总条数
+				noDataText: '暂无数据',  //  列表请求状态提示语
+				status: 'loadmore',  //  加载中状态
+				timeScope: 'threeMonth', // 时间类别 1:近三个月 2:本月 3:本月前一月 4:本月前2月
+				queryParam: {  //  过滤条件
+					changeType: '', // 金币变更类型
+				},
+				optionsType: [
+					{ label: '所有记录', value: '', },
+					{ label: '获取记录', value: 'ADD', },
+					{ label: '使用记录', value: 'SUB', }
+				]
+			}
+		},
+		onShow() {
+			this.searchHandle()
+		},
+		onLoad() {
+			this.timeScope = 'threeMonth'
+			this.queryParam.changeType = ''
+		},
+		computed: {
+			// 时间过滤条件
+			optionsScope(){  //  过滤条件  近3个月
+				let arr = [
+					{ label: '近3个月', value: 'threeMonth' },
+					{ label: '本月', value: 'thisMonth' }
+				]
+				arr[2] = { label: new Date().getMonth() + '月', value: 'lastMonth' }
+				arr[3] = { label: new Date().getMonth()-1 + '月', value: 'lastTwoMonth' }
+				return arr
+			},
+			titType(){  //  过滤条件 所有记录 title
+				const row = this.optionsType.find(item => item.value == this.queryParam.changeType)
+				return row ? row.label : this.optionsType[0].label
+			},
+			titScope(){  //  过滤条件 近3个月 title
+				const row = this.optionsScope.find(item => item.value == this.timeScope)
+				return row ? row.label : this.optionsScope[0].label
+			},
+			// 查询时间段
+			queryDate() {
+				var dt = new Date();
+				const threeTime = dt.setMonth( dt.getMonth()-2 )
+				const quickType = {
+				  threeMonth: [moment(getDate.getThreeMonthDays().starttime), moment(getDate.getThreeMonthDays().endtime)],
+				  lastMonth: [moment(getDate.getLastMonthDays().starttime), moment(getDate.getLastMonthDays().endtime)],
+				  thisMonth: [moment(getDate.getCurrMonthDays().starttime), moment(getDate.getCurrMonthDays().endtime)],
+				  lastTwoMonth: [moment(getDate.getLastTwoMonthDays().starttime), moment(getDate.getLastTwoMonthDays().endtime)],
+				}
+				let queryTime = {
+					beginDate: quickType[this.timeScope][0].format('YYYY-MM-DD'),
+					endDate: quickType[this.timeScope][1].format('YYYY-MM-DD')
+				}
+				return queryTime
+			},
+			
+		},
+		methods:{
+			// 搜索查询
+			searchHandle () {
+				this.listdata = []
+				this.status = "loading"
+				let params = Object.assign(this.queryParam,this.queryDate)
+				console.log(params,'pppppppp')
+				ldUsedQuery(params).then(res => {
+					console.log(res,'pppppppp')
+					if (res.status == 200) {
+						let list = res.data
+						// 查询3个月时 数据处理
+						if (this.timeScope == 'threeMonth') {
+							list.map(item=>{
+								let m = moment(item.month).month()+1
+								item.month = (m == moment().month()+1) ? '本月' : m+'月'
+							})
+						}
+						this.listdata = list
+					} else {
+						this.noDataText = res.message
+						this.listdata = []
+						this.total = 0
+					}
+					this.status = "nomore"
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="less">
+	page{
+		height: 100%;
+		background-color: #fff;
+	}
+	.ldDetailed-container{
+		width: 100%;
+		height: 100%;
+		.nodata{
+			margin: 50upx 0;
+		}
+		// 筛选菜单
+		.filter-dropdown{
+			background-color: #fff!important;
+			.u-dropdown__menu__item{
+				background-color: #fff!important;
+			}
+		}
+		//  列表
+		.scroll-con{
+			height: calc(100% - 40);
+			overflow: auto;
+		}
+		//  列表样式
+		.cell-item-con{
+			.cell-item{
+				background-color: #fff;
+				color: #606266;
+				.cell-item-month{
+					display: block;
+					color: #909399;
+					font-size: 26rpx;
+					padding: 16rpx 30rpx;
+					background-color: #f8f8f8;
+				}
+				.cell-item-main{
+					display: flex;
+					align-items: center;
+					padding: 20rpx 30rpx;
+					border-bottom: 1rpx solid #e9e9e9;
+					.cell-item-pic{
+						flex-shrink: 0;
+						width: 90rpx;
+						height: 90rpx;
+						line-height: 90rpx;
+						background-color: #FFFFFF;
+						border-radius: 50%;
+						text-align: center;
+						display: flex;
+						align-items: center;
+					}
+					.cell-item-c{
+						flex-grow: 1;
+						.cell-item-des{
+							display: block;
+							color: #606266;
+							font-size: 30rpx;
+							margin-bottom: 10rpx;
+						}
+						.cell-item-date{
+							display: block;
+							color: #909399;
+							font-size: 24rpx;
+						}
+					}
+					.cell-item-score{
+						flex-shrink: 0;
+						font-size: 40rpx;
+						display: flex;
+						align-items: center;
+					}
+					.black{
+						color: #01c9b2;
+					}
+					.red{
+						color: red;
+					}
+					.orange{
+						background-color: #fcbd71;
+						color: #fff;
+					}
+				}
+				.cell-item-main:last-child{
+					border: none;
+				}
+			}
+		}
+	}
+</style>

+ 58 - 0
pages/userCenter/myCode/myCode.vue

@@ -0,0 +1,58 @@
+<template>
+	<view class="codes">
+		<view class="canvasbox">
+			<canvas style="width: 200px;height: 200px;" canvas-id="myQrcode"></canvas>
+		</view>
+		<view class="text">
+			请将二维码对准设备摄像头
+		</view>
+	</view>
+</template>
+
+<script>
+	import drawQrcode from 'weapp-qrcode'
+	export default {
+		data() {
+			return {
+				qrcode: null
+			}
+		},
+		onLoad() {
+			this.creatQrCode()
+		},
+		methods: {
+			creatQrCode() {
+			  let userData = this.$store.state.vuex_userData
+			  console.log(userData)
+			  drawQrcode({
+			    width: 200,
+			    height: 200,
+			    canvasId: 'myQrcode',
+			    text: `userId=${userData.customNo}&type=user`
+			  })
+			}
+		}
+	}
+</script>
+
+<style>
+.codes{
+	width: 100%;
+	padding: 50rpx;
+}
+.canvasbox{
+	box-shadow: 3upx 3upx 6upx #eee;
+	background: #FFFFFF;
+	height: 230px;
+	width: 230px;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	margin: 50rpx auto;
+}
+.text{
+	text-align: center;
+	padding: 20rpx;
+	color: #999999;
+}
+</style>

+ 61 - 0
pages/userCenter/question.vue

@@ -0,0 +1,61 @@
+<template>
+	<view class="lc" >
+		<view class="lc-container">
+			<!-- 常见问题 -->
+			<view class="lc-container-xs"  style="font-size: 32rpx;">
+				<view class="lc-container-title" >Q&A常见问题</view>
+				<view class="lc-container-step" >Q: 为什么投放垃圾后乐豆没有到账 ?</view>
+				<view class="lc-container-step-item">A: 每次需要投放最小计算单位以上的重量才会有乐豆奖励。</view>
+				<view class="lc-container-step" >Q: 如何修改支付密码 ?</view>
+				<view class="lc-container-step-item">A: 点击“我的”,前往[个人中心],进入“支付密码”页面可修改支付密码。</view>
+				<view class="lc-container-step" >Q: 乐豆余额不足时该如何兑换商品 ?</view>
+				<view class="lc-container-step-item">A: 余额不足时不可兑换商品,需要通过各种方式增加乐豆积累后可照常兑换商品</view>
+				<view class="lc-container-step" >Q: 乐豆余额可以提现吗 ?</view>
+				<view class="lc-container-step-item">A: 当前版本暂不支持乐豆余额提现,乐豆仅供线上商城、乐享便利兑换使用。</view>
+				<view class="lc-container-step" >Q: 如何完成垃圾投放 ?</view>
+				<view class="lc-container-step-item">A: 通过首页地图找到附近的乐色箱,通过手机号认证身份后,按下开箱按钮,将分类好的垃圾投放进箱內。</view>
+				<view class="lc-container-step" >Q: 如何查看已兑换商品订单的物流状态 ?</view>
+				<view class="lc-container-step-item">A: 点击“我的”,前往[我的订单],通过订单显示的快递公司和快递单号,可自行查询物流信息。</view>
+				<view class="lc-container-step" >Q: 如何进行线下兑换 ?</view>
+				<view class="lc-container-step-item">A: 可根据首页地图找到附近的乐享便利店,选择好所需商品后,向店员支付对应数量的乐豆,完成乐豆抵扣兑换商品。</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+</script>
+
+<style lang="scss">
+	.lc{
+		padding: 15px;
+		line-height: 170%;
+		.lc-container{
+			font-size: 32rpx;
+			.lc-container-xs{
+				margin-bottom: 50rpx;
+				.lc-container-title{
+					text-align: center;
+					font-weight: bold;
+					font-size: 45rpx;
+					margin-bottom:40rpx ;
+				}
+				.lc-container-step{
+					color:#217330;
+					font-size: 38rpx;
+					margin: 10rpx 0;
+				.lc-container-step-name{
+					font-weight: bold;
+				}
+				.lc-container-step-item{
+					text{
+						margin-right: 5rpx;
+						font-size: 35rpx;
+						color: #DD524D;
+					}
+				}
+			}
+		}
+		}
+	}
+</style>

+ 101 - 0
pages/userCenter/userInfo/changePayPwd.vue

@@ -0,0 +1,101 @@
+<template>
+	<view class="changePayPwd-container">
+		<text class="pwd-describe">请输入当前支付密码</text>
+		<view class="pwd-item">
+			<input v-model="oldPwd" border type="password" placeholder="请输入支付密码" :maxlength="30" class="inp-pwd" />
+		</view>
+		<view class="btn-con">
+			<u-button class="handle-btn" type="info" size="medium" @click="cancel">取消</u-button>
+			<u-button class="handle-btn" type="primary" size="medium" @click="submit">确定</u-button>
+		</view>
+		<view class="linkbtn-con">
+			<text class="link-btn" @click="goPage">忘记支付密码</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { checkPayPwd } from '@/api/order.js'
+	export default {
+		data() {
+			return {
+				oldPwd: ''  //  旧密码
+			}
+		},
+		onShow() {
+		},
+		onLoad() {
+		},
+		methods:{
+			//  确定
+			submit(){
+				if(this.oldPwd){
+					checkPayPwd({oldPayPassword:this.oldPwd}).then(res=>{
+						if(res.status == 200) {
+							//  跳转到设置密码
+							uni.redirectTo({
+								url: `/pages/userCenter/userInfo/paymentPwd?oldPwd=${this.oldPwd}`
+							})
+						} 
+					})
+					
+				}else{
+					uni.showToast({ title: '请输入支付密码', icon: 'none' })
+				}
+			},
+			//  取消
+			cancel(){
+				uni.navigateBack({ delta: 1 })
+			},
+			//  忘记支付密码
+			goPage(){
+				uni.redirectTo({
+					url: '/pages/userCenter/userInfo/smsVerification'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.changePayPwd-container{
+		width: 100%;
+		padding: 0 30rpx;
+		box-sizing: border-box;
+		background-color: #fff;
+		.pwd-describe{
+			display: block;
+			color: #606266;
+			padding: 80rpx 0 70rpx;
+			text-align: center;
+		}
+		.pwd-item{
+			.inp-pwd{
+				padding: 10upx 0;
+				border: 1px solid #cacaca;
+				text-align: center;
+			}
+		}
+		.btn-con{
+			display: flex;
+			justify-content: space-between;
+			padding-top: 130rpx;
+			.handle-btn{
+				display: inline-block;
+				width: 45%;
+				margin: 0 auto;
+				text-align: center;
+			}
+		}
+		.linkbtn-con{
+			text-align: center;
+			.link-btn{
+				display: inline-block;
+				font-size: 28rpx;
+				color: #298bf2;
+				margin-top: 200rpx;
+			}
+		}
+	}
+</style>
+

+ 173 - 0
pages/userCenter/userInfo/paymentPwd.vue

@@ -0,0 +1,173 @@
+<template>
+	<view class="paymentPwd-container">
+		<text class="pwd-describe">{{nowSetp == 1 ? '请设置6位数字支付密码' : nowSetp == 2 ? '请再次输入密码' : ''}}</text>
+		<view class="sms-item" @click="showKeyboard=!showKeyboard">
+			<u-message-input mode="bottomLine" :maxlength="6" v-model="value" :dot-fill="true" :disabled-keyboard="true"></u-message-input>
+		</view>
+		<!-- 数字键盘 -->
+		<u-keyboard ref="uKeyboard" :dot-enabled="false" :mask="false" :tooltip="false" v-model="showKeyboard" @change="valChange" @backspace="backspace"></u-keyboard>
+	</view>
+</template>
+
+<script>
+	import {setPayPwd, changePayPwd} from '@/api/order.js'
+	export default {
+		data() {
+			return {
+				nowSetp: 1,  //  当前第几次设置密码
+				value: '', //输入的内容
+				showKeyboard: false,  //  是否打开键盘
+				oPwd: '',  //  第一次密码
+				tPwd: '',  //  第二次密码
+				oldPwd: '', // 原密码
+				mobile: '', // 用户手机号
+				verifiCode: '', // 短信验证码
+			}
+		},
+		onShow() {
+		},
+		onLoad(option) {
+			if (option.code){
+				this.mobile = option.mobile
+				this.verifiCode = option.code
+				this.oldPwd = ''
+			}
+			if (option.oldPwd){
+				this.oldPwd = option.oldPwd
+			}
+			//因为此时实例没有挂载完成,需要延迟操作
+			setTimeout(() => {
+			  this.showKeyboard = true
+			}, 50)
+		},
+		watch: {
+			// 监听输入框输入长度
+			 value: {
+				handler(newVal) {
+					if(newVal.length==6) {
+						if(this.nowSetp == 1){
+							this.oPwd = this.value
+							if(this.oldPwd && this.oPwd === this.oldPwd) {
+								uni.showToast({
+									title: '新密码与原密码相同,请重新输入!',
+									icon: 'none'
+								})
+								this.value = ''
+								return false
+							} else {
+								this.value = ''
+								this.nowSetp++
+								this.showKeyboard = true
+							}
+						}else if(this.nowSetp == 2){
+							this.tPwd = this.value
+							this.showKeyboard = false
+							this.checkPwd()
+						}
+					}
+				},
+				deep: true
+			}
+		},
+		methods:{
+			// 按键被点击(点击退格键不会触发此事件)
+			valChange(val) {
+				// 将每次按键的值拼接到value变量中,注意+=写法
+				if(this.value.length < 6){
+					this.value += val
+				}
+			},
+			// 退格键被点击
+			backspace() {
+				// 删除value的最后一个字符
+				if(this.value.length) this.value = this.value.substr(0, this.value.length - 1)
+			},
+			//  密码校验
+			checkPwd(){
+				if(this.oPwd == this.tPwd){
+					if(this.oldPwd) {
+						this.changePsw()
+					} else{
+						//  设置密码 请求接口
+						this.setPsw()
+					}
+					
+				}else{
+					uni.showToast({ title: '两次密码不一致请重新输入', icon: 'none' })
+					this.value = ''
+					this.showKeyboard = true
+				}
+			},
+			// 首次设置密码
+			setPsw () {
+				let params = {
+					mobile: this.mobile,
+					verifiCode: this.verifiCode,
+					payPassword: this.value
+				}
+				setPayPwd(params).then(res=>{
+					if(res.status==200) {
+						uni.showToast({ title: res.message, icon: 'none' })
+						 uni.$emit('setPswSuccess', {success: true})
+						setTimeout(()=>{
+							uni.navigateBack({
+							    delta: 1
+							})
+						}, 2000)
+					} 
+				})
+			},
+			// 修改密码
+			changePsw () {
+				let params = {
+					oldPayPassword: this.oldPwd,
+					payPassword: this.value
+				}
+				changePayPwd(params).then(res=>{
+					if(res.status==200) {
+						uni.showToast({ title: res.message, icon: 'none' })
+						setTimeout(()=>{
+							uni.navigateBack({
+							    delta: 1
+							})
+						}, 2000)
+					} 
+				})
+			},
+			//  取消
+			cancel(){
+				this.oPwd = ''
+				this.tPwd = ''
+				this.value = ''
+				this.nowSetp = 1
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.paymentPwd-container{
+		width: 100%;
+		padding: 0 30rpx;
+		box-sizing: border-box;
+		background-color: #fff;
+		.pwd-describe{
+			display: block;
+			color: #606266;
+			padding: 80rpx 0 70rpx;
+			text-align: center;
+		}
+		.btn-con{
+			display: flex;
+			justify-content: space-between;
+			padding-top: 130rpx;
+			.handle-btn{
+				display: inline-block;
+				width: 45%;
+				margin: 0 auto;
+				text-align: center;
+			}
+		}
+	}
+</style>
+

+ 210 - 0
pages/userCenter/userInfo/smsVerification.vue

@@ -0,0 +1,210 @@
+<template>
+	<view class="smsVerification-container">
+		<view v-if="sendCode" class="">
+			<view class="sms-title">输入短信验证码</view>
+			<text class="sms-describe">验证码已发送至{{userPhone}},请在下方输入框内输入6位数字验证码</text>
+			<view class="sms-item" @click="showKeyboard=!showKeyboard">
+				<u-message-input mode="bottomLine" :maxlength="6" v-model="value" :disabled-keyboard="true"></u-message-input>
+			</view>
+			<view class="sendcode-con">
+				<text :class="['getcode-btn', isDisable ? 'grey-btn' : '']" @click="isDisable ? null : pageInit()">{{nowVal}}</text>
+			</view>
+		</view>
+		<!-- 数字键盘 -->
+		<u-keyboard ref="uKeyboard" :dot-enabled="false" :mask="false" :tooltip="false" v-model="showKeyboard" @change="valChange" @backspace="backspace"></u-keyboard>
+		<!-- 图文验证码 -->
+		<uni-popup :maskClick="false" ref="imageTxtPopup" type="center">
+			<popup-con title="图文验证码" :popBtn="popBtn" :changeImg="changeImg" @captchaImg="captchaVerify"></popup-con>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import uniPopup from '@/components/uni-popup/uni-popup.vue'
+	import popupCon from '@/components/uni-popup/popup-con.vue'
+	import { sendVerifyCode } from '@/api/user.js'
+	import { checkCode } from '@/api/order.js'
+	export default {
+		components: {
+			uniPopup,
+			popupCon
+		},
+		data() {
+			return {
+				nowVal: '获取验证码',  //  按钮显示内容
+				count: '',  //  当前秒数
+				timer: null,  //  倒计时
+				isDisable: false,  //  是否禁止获取验证码
+				value: '', //输入的内容
+				phone: '', // 用户手机号
+				showKeyboard: false,  //  是否打开键盘
+				popBtn: [],  //  name为操作按钮名称,color为操作按钮颜色值
+				changeImg: false,  //  是否重新更换图形验证码
+				verifyCode: '',
+				randomCode: '',  //  图片验证码随机码
+				sendCode: false  // 短信是否发送成功
+			}
+		},
+		onLoad() {
+			this.phone = this.$store.state.vuex_userData.mobile
+			console.log(this.$store.state.vuex_userData,'his.$store.state.vuex_OrderAddress')
+			//因为此时实例没有挂载完成,需要延迟操作
+			setTimeout(() => {
+			  this.pageInit()
+			}, 50)
+		},
+		computed: {
+			userPhone () {
+				return this.phone.substr(0,3) + "****" + this.phone.substr(7)
+			}
+		},
+		watch: {
+			// 监听输入框输入长度
+			 value: {
+				handler(newVal) {
+					// console.log(newVal.length,'NNNNNNNNNNNN')
+					if(newVal.length==6) {
+						let params = {
+							mobile: this.phone,
+							verifiCode: newVal
+						}
+						checkCode(params).then(res=>{
+							if(res.status==200) {
+								//  跳转到设置密码
+								uni.redirectTo({
+									url: `/pages/userCenter/userInfo/paymentPwd?code=${this.value}&mobile=${this.phone}`
+								})
+							} 
+						})
+						
+					}
+				},
+				deep: true
+			}
+		},
+		methods:{
+			pageInit () {
+				this.value = ''
+				this.sendCode = false
+				this.showKeyboard = false
+				this.retsetCode()
+				//  图文验证码
+				this.$refs.imageTxtPopup.open()
+			},
+			//  验证图片验证码
+			captchaVerify(code, nowRandomCode){
+				let obj = {}
+				obj.phone = this.phone
+				obj.random = nowRandomCode
+				obj.code = code
+				//  短信验证码
+				sendVerifyCode(obj).then(res => {
+					console.log(JSON.stringify(res))
+					if(res.status == 200){  //  验证码输入正确
+						this.randomCode = nowRandomCode  //  图片验证码随机码
+						//  关闭   图形验证码 弹框
+						this.$refs.imageTxtPopup.close()
+						//  开启倒计时
+						this.getCodeFun()
+						this.sendCode = true
+						this.showKeyboard = true
+						uni.showToast({icon: 'none',title: '验证码发送成功'})
+					}else {  //  验证码输入错误
+						this.retsetCode()
+						uni.showToast({icon: 'none',title: res.message})
+					}
+				})
+			},
+			// 重新触发获取图片验证码
+			retsetCode(){
+				const _this = this
+				_this.verifyCode = ''
+				_this.randomCode = ''
+				//  切换验证码重新校验
+				_this.changeImg = false
+				_this.$nextTick(function(){
+					_this.changeImg = true
+				})
+			},
+			// 按键被点击(点击退格键不会触发此事件)
+			valChange(val) {
+				// 将每次按键的值拼接到value变量中,注意+=写法
+				if(this.value.length < 6){
+					this.value += val
+				}
+			},
+			// 退格键被点击
+			backspace() {
+				// 删除value的最后一个字符
+				if(this.value.length) this.value = this.value.substr(0, this.value.length - 1)
+			},
+			//  开始倒计时
+			getCodeFun(){
+				const TIME_COUNT = 60
+				if (!this.timer) {
+				  this.count = TIME_COUNT
+				  this.timer = setInterval(() => {
+				    if (this.count > 0 && this.count <= TIME_COUNT) {
+				      this.count--
+				      this.nowVal = this.count + '秒后重新发送'
+				      this.isDisable = true
+				    } else {
+				      this.nowVal = '重新获取验证码'
+				      clearInterval(this.timer)
+				      this.timer = null
+				      this.isDisable = false
+				    }
+				  }, 1000)
+				}
+			},
+			//  取消
+			cancel(){
+				uni.navigateBack({
+				    delta: 1
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.smsVerification-container{
+		width: 100%;
+		padding: 0 30rpx;
+		box-sizing: border-box;
+		background-color: #fff;
+		.sms-title {
+		  margin: 50rpx 0 30rpx;
+		  font-size: 36rpx;
+		  font-weight: bold;
+		}
+		.sms-describe{
+			display: block;
+			color: #606266;
+			margin: 20rpx 0 50rpx;
+		}
+		.sendcode-con{
+			text-align: center;
+			padding-top: 70rpx;
+			.getcode-btn {
+				display: block;
+				font-size: 28rpx;
+				color: #298bf2;
+			}
+			.grey-btn{
+				color: #999;
+			}
+		}
+		.btn-con{
+			display: flex;
+			justify-content: space-between;
+			padding-top: 130rpx;
+			.handle-btn{
+				display: inline-block;
+				width: 45%;
+				margin: 0 auto;
+				text-align: center;
+			}
+		}
+	}
+</style>

+ 132 - 0
pages/userCenter/userInfo/userInfo.vue

@@ -0,0 +1,132 @@
+<template>
+	<view class="userInfo-container">
+		<u-cell-group>
+			<u-cell-item title="头像" :arrow="false" center>
+				<view class="user-photo"><open-data type="userAvatarUrl"></open-data></view>
+			</u-cell-item>
+			<u-cell-item title="手机号码" :value="userDate.mobile" :arrow="false"></u-cell-item>
+			<u-cell-item title="收货地址" :value="address?'修改收货地址':'设置收货地址'" index="0" @click="editAddress"></u-cell-item>
+			<u-cell-item title="支付密码" :value="existPayPwd?'修改密码':'设置密码'" @click="setPayPwd"></u-cell-item>
+		</u-cell-group>
+		<!-- 退出 -->
+		<view class="user-btn">
+			<u-button type="success" :custom-style="quitButton" @click="quitSys" shape="circle">退出登录</u-button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {existPayPwd} from '@/api/order.js'
+	import {findAddressBycustomerNo} from '@/api/receiveAddress.js'
+	import {logout} from '@/api/login.js'
+	export default {
+		data() {
+			return {
+				quitButton: {
+					borderRadius:'100rpx',
+					fontSize:'30rpx',
+					background: '#01c9b2'
+				},
+				userDate: {},
+				existPayPwd: null,
+				address: null,
+				userInfo: {}
+			}
+		},
+		onShow() {
+			this.userDate = this.$store.state.vuex_userData
+			this.getPayPwd()
+			this.getAddress()
+		},
+		methods:{
+			// 获取用户位置
+			getAddress() {
+				 findAddressBycustomerNo({}).then(res => {
+					 console.log(res)
+					 if (res.status == 200&&res.data.length) {
+						 this.address = res.data[0].receiveAreasName
+						 this.userInfo = res.data[0]
+					 } else {
+						 this.address = ''
+						 this.userInfo = {}
+					 }
+				 })
+			},
+			// 判断是否设置过支付密码
+			getPayPwd(){
+				existPayPwd().then(res=>{
+					if(res.status == 200) {
+						if(res.data) {
+							this.existPayPwd = true
+						} else {
+							this.existPayPwd = false
+						}
+					}
+				})
+			},
+			// 修改收货地址
+			editAddress(index){
+				this.$u.vuex("vuex_OrderAddress",this.userInfo)
+				uni.navigateTo({
+					url:"/pages/toOrder/editAddress"
+				})
+			},
+			// 设置密码
+			setPayPwd(){
+				// 设置过支付密码,则修改密码
+				if(this.existPayPwd){
+					uni.navigateTo({ url: '/pages/userCenter/userInfo/changePayPwd' })
+				}else{
+					// 没设置过支付密码,提示设置密码
+					uni.navigateTo({ url: '/pages/userCenter/userInfo/smsVerification' })
+				}
+			},
+			// 退出登录
+			quitSys(){
+				let _this = this
+				uni.showModal({
+				  title: '提示',
+				  content: '您确定要退出登录吗?',
+				  success(res) {
+				    if (res.confirm) {
+				      logout({}).then(res => {
+				       getApp().globalData.token = ''
+				       _this.$u.vuex('vuex_token','')
+					   _this.$u.vuex('vuex_userData','')
+					   _this.$u.vuex('vuex_cartList','')
+					   _this.$u.vuex('vuex_OrderAddress','')
+					   _this.$u.vuex('vuex_toOrderList','')
+					   // 关闭socket
+					   _this.$store.commit("$closeWebsocket")
+				        uni.reLaunch({
+				        	url: '/pages/index/index'
+				        })
+				      })
+				    }
+				  }
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.userInfo-container{
+		width: 100%;
+		.logout-btn{
+			width: 60%;
+			margin-top: 200rpx;
+		}
+		.user-btn{
+			padding: 85rpx 200rpx;
+		}
+		.user-photo{
+			width: 100rpx;
+			height: 100rpx;
+			border-radius: 50%;
+			overflow: hidden;
+			margin-right: 5rpx;
+			float: right;
+		}
+	}
+</style>

+ 160 - 0
pages/userCenter/zhinan.vue

@@ -0,0 +1,160 @@
+<template>
+	<view class="lc" >
+		<view class="lc-container">
+			<!-- 新手引导 -->
+			<view class="lc-container-xs">
+				<view class="lc-container-title" style="margin-top: 0;">新手引导</view>
+				<view class="lc-container-step" style="margin-top: 0;">(<text>一</text>)、新手入驻</view>
+				<view class="lc-container-step-name" style="font-weight: bold; font-size: 32rpx;margin: 20rpx 0;">用户登录</view>
+				<view class="lc-container-step-item">
+					(<text>1</text>)
+					<text style="margin-left:10rpx ;">用户进入小程序,点击微信登录,授权手机号后将自动登录。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>2</text>)
+					<text style="margin-left:10rpx ;">用户进入小程序,点击手机号验证登录,可通过手机验证码登录小程序。</text>
+				</view>
+				<view class="lc-container-step-name" style="font-weight: bold;font-size: 32rpx;margin: 20rpx 0;">我的</view>
+				<view class="lc-container-step-item">
+					(<text>1</text>)
+					<text style="margin-left:10rpx ;">点击右下角「我的」,点击头像进入「个人中心」。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>2</text>)
+					<text style="margin-left:10rpx ;"> 进入“支付密码”页面,可设置/修改支付密码。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>3</text>)
+					<text style="margin-left:10rpx ;"> 进入“收货地址”页面,进行收货地址管理。</text>
+				</view>
+				<view class="lc-container-step">(<text>二</text>)、使用手册</view>
+				<view class="lc-container-step-name" style="font-weight: bold;font-size: 32rpx;margin: 20rpx 0;">垃圾投放</view>
+				<view class="lc-container-step-item">
+					(<text>1</text>)
+					<text style="margin-left:10rpx ;">进入首页,可查看距离自己当前位置最近的3个回收网点。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>2</text>)
+					<text style="margin-left:10rpx ;">在自动回收机上输入手机号进行身份验证后,选择对应的投递类型。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>3</text>)
+					<text style="margin-left:10rpx ;">按下设备的开箱按钮,将分类装好的垃圾投放进相应的回收箱内。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>4</text>)
+					<text style="margin-left:10rpx ;">系统自动称重,获得相应的乐豆积分。</text>
+				</view>
+				<view class="lc-container-step-name" style="font-weight: bold;font-size: 32rpx;margin: 20rpx 0;">兑换</view>
+				<view class="lc-container-step-name" style="font-weight: bold;font-size: 32rpx;margin: 20rpx 0;">乐豆商城</view>
+				<view class="lc-container-step-item">
+					(<text>1</text>)
+					<text style="margin-left:10rpx ;">进入小程序,点击「商城」,可查看商城商品。</text>
+					</view>
+				<view class="lc-container-step-item">
+					(<text>2</text>)
+					<text style="margin-left:10rpx ;">点击商品右侧的“购物车”添加商品,点击“去兑换”进入订单页面。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>3</text>)
+					<text style="margin-left:10rpx ;">确认订单无误后,点击“支付"跳转至支付页面,输入支付密码,完成兑换。</text>
+					</view>
+				<view class="lc-container-step-item">
+					(<text>4</text>)
+					<text style="margin-left:10rpx ;">收到货后要进行确认收货。</text>
+				</view>
+				<view class="lc-container-step-name" style="font-weight: bold;font-size: 32rpx;margin: 20rpx 0;">乐享亭</view>
+				<view class="lc-container-step-item">
+					(<text>1</text>)
+					<text style="margin-left:10rpx ;">找到附近的乐享亭,选择自己需要兑换的商品。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>2</text>)
+					<text style="margin-left:10rpx ;">同乐享亭店员沟通确认兑换该商品需要支付的乐豆。</text>
+				</view>
+				<view class="lc-container-step-item">
+					(<text>3</text>)
+					<text style="margin-left:10rpx ;">点击首页中间的“扫一扫”图标,输入需要支付的乐豆数字,点击“支付”输入支付密码后完成兑换。</text>
+				</view>
+			</view>
+			
+			<!-- 乐豆使用说明 -->
+			<view class="lc-container-xs" style="font-size: 32rpx;">
+				<view class="lc-container-title" >Q&A乐豆使用说明</view>
+				<view class="lc-container-step" >Q: 什么是乐豆 ?</view>
+				<view class="lc-container-step-item">A: 乐豆是用于乐色管家用户使用乐色管家各种服务及增值服务的种类、数量或时间等的一种统计代码,并非任何代币票券,不能用于乐色管家服务及增值服务以外的任何商品或服务。</view>
+				<view class="lc-container-step" >Q: 如何使用乐豆 ?</view>
+				<view class="lc-container-step-item">A: 乐豆可以用于兑换积分商城丰富的商品、服务,以及参与线上线下活动等。</view>
+				<view class="lc-container-step" >Q: 如何获得乐豆 ?</view>
+				<view class="lc-container-step-item">A: 用户可通过完成「垃圾投放」「系统任务」等方式来获取乐豆。</view>
+				<view class="lc-container-step" >Q: 乐豆的有效期限是多长 ?</view>
+				<view class="lc-container-step-item">A: 用户获得但未使用的乐豆长期有效。</view>
+				<view class="lc-container-step" >Q: 如何查看我的乐豆数量 ?</view>
+				<view class="lc-container-step-item">A: 点击“我的”,可查看乐豆余额;点击“乐豆明细”小图标可查看乐豆明细。</view>
+				<view class="lc-container-step" >Q: 乐豆的使用范围 ?</view>
+				<view class="lc-container-step-item">A: 乐色管家小程序+乐享亭。</view>
+			</view>
+			
+			<!-- 常见问题 -->
+			<view class="lc-container-xs"  style="font-size: 32rpx;">
+				<view class="lc-container-title" >Q&A常见问题</view>
+				<view class="lc-container-step" >Q: 为什么投放垃圾后乐豆没有到账 ?</view>
+				<view class="lc-container-step-item">A: 每次需要投放最小计算单位以上的重量才会有乐豆奖励。</view>
+				<view class="lc-container-step" >Q: 如何修改支付密码 ?</view>
+				<view class="lc-container-step-item">A: 点击“我的”,前往[个人中心],进入“支付密码”页面可修改支付密码。</view>
+				<view class="lc-container-step" >Q: 乐豆余额不足时该如何兑换商品 ?</view>
+				<view class="lc-container-step-item">A: 余额不足时不可兑换商品,需要通过各种方式增加乐豆积累后可照常兑换商品</view>
+				<view class="lc-container-step" >Q: 乐豆余额可以提现吗 ?</view>
+				<view class="lc-container-step-item">A: 当前版本暂不支持乐豆余额提现,乐豆仅供线上商城、乐享便利兑换使用。</view>
+				<view class="lc-container-step" >Q: 如何完成垃圾投放 ?</view>
+				<view class="lc-container-step-item">A: 通过首页地图找到附近的乐色箱,通过手机号认证身份后,按下开箱按钮,将分类好的垃圾投放进箱內。</view>
+				<view class="lc-container-step" >Q: 如何查看已兑换商品订单的物流状态 ?</view>
+				<view class="lc-container-step-item">A: 点击“我的”,前往[我的订单],通过订单显示的快递公司和快递单号,可自行查询物流信息。</view>
+				<view class="lc-container-step" >Q: 如何进行线下兑换 ?</view>
+				<view class="lc-container-step-item">A: 可根据首页地图找到附近的乐享便利店,选择好所需商品后,向店员支付对应数量的乐豆,完成乐豆抵扣兑换商品。</view>
+			</view>
+			<view style="font-size: 32rpx;">
+				温馨提示:使用过程中,如有其他问题,可前往[我的],点击“联系客服”图标,拨打客服电话进行沟通。
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+</script>
+
+<style lang="scss">
+	.lc{
+		padding: 15px;
+		line-height: 170%;
+		.lc-container{
+			font-size: 32rpx;
+			.lc-container-xs{
+				margin-bottom: 50rpx;
+				.lc-container-title{
+					text-align: center;
+					font-weight: bold;
+					font-size: 45rpx;
+					margin:40rpx ;
+				}
+				.lc-container-step{
+					color:#217330;
+					font-size: 38rpx;
+					margin: 30rpx 0;
+				.lc-container-step-name{
+					font-weight: bold;
+					margin: 20rpx 0;
+				}
+				.lc-container-step-item{
+					margin: 20rpx 0;
+					text{
+						margin-right: 5rpx;
+						font-size: 35rpx;
+						color: #DD524D;
+					}
+				}
+			}
+		}
+		}
+	}
+</style>

BIN
static/CLOTHES.png


BIN
static/GLASS.png


BIN
static/HARM.png


BIN
static/METAL.png


BIN
static/MET_PLA.png


BIN
static/PAPER.png


BIN
static/PLASTIC.png


BIN
static/RECYCLING.png


BIN
static/add-cart.png


BIN
static/addCart.png


BIN
static/bued.png


BIN
static/cart.png


BIN
static/checked.png


BIN
static/dz-icon.png


BIN
static/edit.png


BIN
static/full-bg.png


BIN
static/hexiao.png


BIN
static/imgError.png


BIN
static/ledou.png


BIN
static/liucheng.png


BIN
static/loading.gif


BIN
static/logo.png


BIN
static/md-big-pic.png


BIN
static/md-icon.png


BIN
static/position.png


BIN
static/shouyi.png


BIN
static/store.png


BIN
static/t1.png


BIN
static/tabbar/home-active.png


BIN
static/tabbar/home.png


BIN
static/tabbar/shop-active.png


BIN
static/tabbar/shop.png


Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov