You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

730 lines
18 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. <template>
  2. <view class="payOrder">
  3. <mNavbar title="确认订单" :leftClick="leftClick" />
  4. <view class="bac"></view>
  5. <view class="box">
  6. <view class="server-item">
  7. <view class="img-box">
  8. <image :src="projectDetail.image" mode="aspectFill"></image>
  9. </view>
  10. <view class="server-info">
  11. <view class="server-title">{{ projectDetail.title }}</view>
  12. <view class="time-coupon">
  13. <image src="@/static/home/time-icon.png"></image>
  14. <view class="time">{{ projectDetail.times }}分钟</view>
  15. </view>
  16. <!-- <view class="price">
  17. <view class="current-price">
  18. <text class="unit"></text>299
  19. </view>
  20. <view class="original-price">
  21. <text class="unit"></text>399
  22. </view>
  23. </view> -->
  24. <!-- <view class="coupon">{{ projectDetail.subTitle }}</view> -->
  25. <view class="sales-volume">
  26. <image src="@/static/icons/icon1.png"></image>
  27. <view class="desc">已售出 {{ projectDetail.payNum }}+ </view>
  28. </view>
  29. </view>
  30. </view>
  31. <van-cell-group>
  32. <van-cell title="请选择地址" is-Link @click="selectAddressPopupShow = true"
  33. :value="(address.name + address.phone + address.addressDetail) || ''">
  34. <template #icon>
  35. <image class="icon" src="../../static/payOrder/1.png" mode="aspectFill"></image>
  36. </template>
  37. </van-cell>
  38. <van-cell title="服务技师">
  39. <text style="color: #EF8C94;">{{ technicianDetail.title }}</text>
  40. <template #icon>
  41. <image class="icon" src="../../static/payOrder/2.png" mode="aspectFill"></image>
  42. </template>
  43. </van-cell>
  44. <van-cell title="服务时间" is-Link @click="onServiceTime">
  45. <text style="color: #EF8C94;">
  46. {{ time.timeName ? (dateObj.format('MM-DD') + ' ' + time.timeName) : '' }}
  47. </text>
  48. <template #icon>
  49. <image class="icon" src="../../static/payOrder/3.png" mode="aspectFill"></image>
  50. </template>
  51. </van-cell>
  52. <van-cell title="精油选择" is-Link @click="showEssentialOil">
  53. <text style="color: #EF8C94;">
  54. {{ essentialOil.name }}
  55. </text>
  56. <template #icon>
  57. <image class="icon" src="../../static/payOrder/9.png" mode="aspectFill"></image>
  58. </template>
  59. </van-cell>
  60. <van-cell title="出行方式">
  61. <text style="color: #fff;
  62. background-color: #EF8C94;
  63. padding: 5px 10px;
  64. border-radius: 5px;
  65. font-size: 12px;">出租车</text>
  66. <template #icon>
  67. <image class="icon" src="../../static/payOrder/4.png" mode=""></image>
  68. </template>
  69. </van-cell>
  70. <!-- <van-cell title="出行费用">
  71. <text>{{ temp }}</text>
  72. <template #icon>
  73. <image class="icon" src="../../static/payOrder/2.png" mode="aspectFill"></image>
  74. </template>
  75. </van-cell> -->
  76. <view class="mileage">
  77. <view class="top">
  78. 全程共
  79. <text style="color: #EF8C94;
  80. font-size: 16px;">{{ distance || 0}}</text>
  81. 公里
  82. </view>
  83. <view class="info">
  84. 2公里内免费 超过2公里每公里{{ travelMoney }}
  85. </view>
  86. </view>
  87. <van-cell title="订单备注" is-Link @click="remarkShow = true">
  88. <text>{{ remark || '选填' }}</text>
  89. <template #icon>
  90. <image class="icon" src="../../static/payOrder/5.png" mode=""></image>
  91. </template>
  92. </van-cell>
  93. </van-cell-group>
  94. <van-cell-group style="margin-top: 10px;">
  95. <van-radio-group v-model="payMethod">
  96. <van-cell>
  97. <template #title>
  98. <text>账户余额</text>
  99. <text style="color: #888;">余额{{ userInfo.price }}</text>
  100. </template>
  101. <template #icon>
  102. <image class="icon" src="../../static/payOrder/6.png" mode=""></image>
  103. </template>
  104. <template #right-icon>
  105. <van-radio :name="1" checked-color="#EF8C94"></van-radio>
  106. </template>
  107. </van-cell>
  108. <van-cell title="微信支付">
  109. <template #icon>
  110. <image class="icon" src="../../static/payOrder/7.png" mode=""></image>
  111. </template>
  112. <template #right-icon>
  113. <van-radio :name="0" checked-color="#EF8C94"></van-radio>
  114. </template>
  115. </van-cell>
  116. </van-radio-group>
  117. </van-cell-group>
  118. <van-cell-group style="margin-top: 10px;">
  119. <van-cell title="优惠劵" is-Link @click="selectCouponPopupShow = true">
  120. <text v-if="coupon.money" style="color: #4899a6;">优惠 {{ coupon.money }}</text>
  121. <text v-else style="color:#EF8C94">{{ couponNum == 0 ? '无' : `${couponNum}` }}</text>
  122. <template #icon>
  123. <image class="icon" src="../../static/payOrder/6.png" mode=""></image>
  124. </template>
  125. </van-cell>
  126. </van-cell-group>
  127. <view style="color: #888;font-size: 12px;padding: 10px 0;;">
  128. 温馨提示下单前请仔细查看下单须知
  129. </view>
  130. <view class="agreement">
  131. <van-checkbox v-model="agreement" checked-color="#15BA11"></van-checkbox>
  132. 本人已同意<text @click="configPopupShow = true" style="color: #15BA11;">用户使用协议</text>
  133. </view>
  134. </view>
  135. <view class="submit">
  136. <view class="price">
  137. <view>
  138. <text style="color: #000;">合计</text>
  139. <text style="font-size: 18px;
  140. font-weight: 600;">{{ count }}</text>
  141. </view>
  142. <view style="font-size: 10px;margin-top: 5px;">
  143. 已优惠{{ coupon.money || 0 }}
  144. </view>
  145. </view>
  146. <view class="btn" @click="submit">
  147. 立即支付
  148. </view>
  149. </view>
  150. <selectTime :show="selectTimeShow" @select="selectTime" :dateList="dateList" :timeList="timeList"
  151. :loading="timeLoading" @selectDate="getVipTenOrderList" @close="selectTimeShow = false"
  152. :title="selectTimeTitle" />
  153. <selectTechnician :serviceId="projectDetail.id" @select="selectTechnician" :show="selectTechnicianShow"
  154. @close="selectTechnicianShow = false" />
  155. <selectCouponPopup :show="selectCouponPopupShow" @selectCoupon="selectCoupon" @countCouponNum="countCouponNum"
  156. @close="selectCouponPopupShow = false" />
  157. <selectAddressPopup :show="selectAddressPopupShow" @select="selectAddress"
  158. @close="selectAddressPopupShow = false" />
  159. <selectEssentialOil :show="essentialOilShow" @select="selectEssentialOil"
  160. @close="essentialOilShow = false" />
  161. <van-popup v-model:show="remarkShow" round position="bottom" @close="remarkShow = false"
  162. :style="{ height: '160px' }">
  163. <van-field v-model="remark" rows="4" autosize type="textarea" maxlength="50" placeholder="请输入留言"
  164. show-word-limit />
  165. </van-popup>
  166. <configPopup :keyValue="keyValue" :show="configPopupShow" :list="config" @close="configPopupShow = false" />
  167. </view>
  168. </template>
  169. <script>
  170. import mNavbar from '@/components/base/m-navbar.vue'
  171. import selectTime from '@/components/payOrder/selectTime.vue'
  172. import selectTechnician from '@/components/payOrder/selectTechnicianPopup.vue'
  173. import selectAddressPopup from '@/components/payOrder/selectAddressPopup.vue'
  174. import selectCouponPopup from '@/components/payOrder/selectCouponPopup.vue'
  175. import selectEssentialOil from '../../components/payOrder/selectEssentialOilPopup.vue'
  176. import configPopup from '@/components/configPopup'
  177. import Position from '@/utils/position.js'
  178. import { showDialog } from 'vant';
  179. import { showNotify } from 'vant'
  180. export default {
  181. components: {
  182. mNavbar,
  183. selectTime,
  184. selectTechnician,
  185. selectAddressPopup,
  186. selectCouponPopup,
  187. configPopup,
  188. selectEssentialOil
  189. },
  190. data() {
  191. return {
  192. payMethod: 1,
  193. remark: '',
  194. agreement: false,
  195. selectTimeShow: false,
  196. selectTechnicianShow: false,
  197. selectCouponPopupShow: false,
  198. selectAddressPopupShow: false,
  199. remarkShow: false,
  200. selectTimeTitle: '',
  201. technicianDetail: {},
  202. projectDetail: {},
  203. time: {},
  204. address: {},
  205. coupon: {},
  206. userInfo: {},
  207. order: [],
  208. dateList: [],
  209. timeList: [],
  210. timeLoading: false,
  211. dateObj: '',
  212. price: 0, //用于保存商品原价
  213. temp: 0,//路费
  214. count: 0, //计算出的价格
  215. configPopupShow: false,
  216. config: [],
  217. keyValue: 'protocol',
  218. distance : 0,
  219. travelMoney : 0,
  220. selectDay : '', //用户选择的日期
  221. couponNum : 0,
  222. essentialOilShow : false,
  223. essentialOil : '', //用户选中的精油
  224. }
  225. },
  226. onShow() {
  227. this.getOrderDetail()
  228. this.getUserInfo()
  229. this.getConfig()
  230. let today = this.dayjs()
  231. this.dateList.push(today)
  232. for (let i = 1; i < 7; i++) {
  233. this.dateList.push(today.add(i, 'day'))
  234. }
  235. },
  236. methods: {
  237. //获取订单详情
  238. getOrderDetail() {
  239. this.$api('getOrderVipDetail', {
  240. id: this.$route.query.orderId
  241. }, res => {
  242. if (res.code == 200) {
  243. this.projectDetail = res.result.shop
  244. this.technicianDetail = res.result.technician
  245. this.order = res.result.order
  246. this.getVipTenOrderList(this.dayjs())
  247. this.initPrice()
  248. }
  249. })
  250. },
  251. //获取技师上钟时间
  252. getVipTenOrderList(item) {
  253. this.selectDay = item
  254. this.timeLoading = true
  255. this.$api('getVipTenOrderList', {
  256. tenId: this.technicianDetail.id,
  257. name: item.format('dddd')
  258. }, res => {
  259. if (res.code == 200) {
  260. this.timeList = res.result
  261. }
  262. this.timeLoading = false
  263. })
  264. },
  265. //获取用户信息
  266. getUserInfo() {
  267. this.$api('getUserInfo', {}, res => {
  268. if (res.code == 200) {
  269. this.userInfo = res.result;
  270. }
  271. })
  272. },
  273. //点击返回箭
  274. leftClick() {
  275. let {current,id,distance,orderId} = this.$route.query
  276. if (current == 'technicianDetail') { //返回技师详情
  277. return uni.navigateTo({
  278. url: `/pages/technician/technicianDetail?id=${id}&distance=${distance}`
  279. })
  280. }
  281. if (current == 'orderDetail') { //返回订单详情
  282. return uni.navigateTo({
  283. url: `/pages/order/orderDetail?id=${orderId}`
  284. })
  285. }
  286. uni.navigateTo({ //返回技师选择列表
  287. url: `/pages/technician/selectTechnician?serviceId=${this.projectDetail.id}`
  288. })
  289. },
  290. //支付
  291. submit() {
  292. if (!this.address.id) {
  293. return this.selectAddressPopupShow = true
  294. }
  295. if (!this.time.id) {
  296. return this.selectTimeShow = true
  297. }
  298. if(!this.essentialOil.id){
  299. return this.essentialOilShow = true
  300. }
  301. if (!this.agreement) {
  302. return uni.showToast({
  303. title: '请勾选用户使用协议协议',
  304. icon: 'none'
  305. })
  306. }
  307. let data = {
  308. addressId: this.address.id, //地址id
  309. orderId: this.order.id, //订单id
  310. payType: this.payMethod, // 支付类型
  311. remark: this.remark, //备注
  312. serviceTime: this.time.id, //服务时间
  313. travelType: 1, //出行方式
  314. travelDistance: this.distance, //技师距离
  315. serviceDate : this.selectDay.format('YYYY-MM-DD')//服务时间
  316. }
  317. if (this.coupon.id) {
  318. data.couponId = this.coupon.id //优惠劵id
  319. }
  320. this.$api('payVipOrder', data, res => {
  321. if (res.code == 200) {
  322. if (this.payMethod == 1) { //余额支付
  323. showDialog({
  324. title: '支付成功',
  325. message: '订单支付成功!请前往订单查看',
  326. }).then(() => {
  327. this.paySusscess()
  328. });
  329. } else if (this.payMethod == 0) { //微信支付
  330. this.$wxPay(res,this.paySusscess,this.paySusscess)
  331. }
  332. }else{ //不管成功失败都跳往订单页面
  333. this.paySusscess()
  334. }
  335. })
  336. },
  337. //显示选择技师上钟时间弹框
  338. onServiceTime() {
  339. this.selectTimeShow = true
  340. this.selectTimeTitle = '请选择服务时间'
  341. },
  342. //选择技师上钟时间
  343. selectTime(obj) {
  344. this.selectTimeShow = false
  345. this.time = obj.time
  346. this.dateObj = obj.date
  347. },
  348. //选择技师
  349. selectTechnician(item) {
  350. this.selectTechnicianShow = false
  351. this.technicianDetail = item
  352. },
  353. //选择优惠券
  354. selectCoupon(item) {
  355. if (item.useMoney > this.price) { //判断优惠券使用条件(满多少可用)
  356. this.selectCouponPopupShow = false
  357. return uni.showToast({icon: 'none',title: `此券需满${item.useMoney}可用`});
  358. }
  359. this.count = this.price //先恢复商品价格,防止多次选择优惠券前端多次减金额
  360. this.selectCouponPopupShow = false
  361. this.coupon = item
  362. this.count = this.price - item.money
  363. },
  364. //显示选择地址弹框
  365. selectAddress(item) {
  366. if(!item.latitude && !item.longitude){ //判断地址信息有没有经纬度信息,避免出现距离计算出现问题
  367. this.selectAddressPopupShow = false
  368. return uni.showToast({icon: 'none',title: '选择的地址异常,请选择其他地址或重新添加'});
  369. }
  370. this.selectAddressPopupShow = false
  371. this.address = item
  372. this.calculatedDistance(); //计算两地距离
  373. },
  374. wxPay() {
  375. this.$api('createOrderWXPay', {}, res => {
  376. if (res.code == 200) {
  377. this.$wxPay(res,this.paySusscess,this.paySusscess)
  378. }
  379. })
  380. },
  381. //获取配置信息
  382. getConfig() {
  383. this.$api('getConfig', {}, res => {
  384. if (res.code == 200) {
  385. this.config = res.result
  386. res.result.forEach(item => {
  387. if(item.keyValue == 'travel_money'){
  388. this.travelMoney = item.content
  389. }
  390. })
  391. }
  392. })
  393. },
  394. //计算距离
  395. calculatedDistance(){ //计算距离
  396. // Position.getLocation(result => {
  397. // this.distance = Position.calculateDistance(result.latitude, result.longitude, this.technicianDetail.latitude, this.technicianDetail.longitude)
  398. // //计算路费
  399. // if (this.distance < 2) {
  400. // this.temp = 0
  401. // }else{
  402. // this.temp = Number((this.distance * this.travelMoney).toFixed(2));
  403. // this.initPrice()
  404. // }
  405. // })
  406. if(this.$route.query.setKmOpen=='Y'){ //是否打开了假距离
  407. this.distance = this.$route.query.distance
  408. }else{
  409. this.distance = Position.calculateDistance(this.address.latitude, this.address.longitude, this.technicianDetail.latitude, this.technicianDetail.longitude)
  410. }
  411. //计算路费
  412. if (this.distance < 2) {
  413. this.temp = 0
  414. }else{
  415. this.temp = Number((this.distance * this.travelMoney).toFixed(2));
  416. this.initPrice()
  417. }
  418. },
  419. //初始化金额数据(用于前端计算)
  420. initPrice(){
  421. this.price = Number(this.order.money + this.temp).toFixed(2)
  422. this.count = Number(this.order.money + this.temp).toFixed(2)
  423. },
  424. //支付成功(跳转订单)
  425. paySusscess(){
  426. uni.switchTab({
  427. url: '/pages/index/order?active=1'
  428. })
  429. },
  430. //获取优惠券数量
  431. countCouponNum(num){
  432. this.couponNum = num
  433. },
  434. //显示选择精油弹框
  435. showEssentialOil(){
  436. this.essentialOilShow = true
  437. },
  438. //用户选择精油
  439. selectEssentialOil(essentialoil){
  440. this.essentialOil = essentialoil
  441. this.essentialOilShow = false
  442. }
  443. }
  444. }
  445. </script>
  446. <style scoped lang="scss">
  447. body {
  448. background-color: #f3f3f3;
  449. }
  450. .payOrder {
  451. .bac {
  452. position: absolute;
  453. width: 100%;
  454. height: 100px;
  455. background: #F6BEC3;
  456. }
  457. .box {
  458. position: relative;
  459. width: calc(100% - 30px);
  460. margin: 15px;
  461. margin-top: 30rpx;
  462. min-height: 500px;
  463. border-radius: 10px;
  464. padding-bottom: 80px;
  465. .server-item {
  466. display: flex;
  467. flex-wrap: wrap;
  468. justify-content: space-between;
  469. background: white;
  470. border-radius: 15rpx;
  471. box-sizing: border-box;
  472. padding: 25rpx;
  473. margin: 20rpx 0rpx;
  474. .img-box {
  475. width: 150rpx;
  476. height: 150rpx;
  477. background: #ccc;
  478. border-radius: 10rpx;
  479. overflow: hidden;
  480. image {
  481. width: 100%;
  482. height: 100%;
  483. }
  484. }
  485. .server-info {
  486. width: calc(100% - 150rpx);
  487. box-sizing: border-box;
  488. padding: 10rpx 15rpx;
  489. display: flex;
  490. flex-direction: column;
  491. justify-content: space-around;
  492. .server-title {
  493. font-size: 15px;
  494. }
  495. .time-coupon,
  496. .price {
  497. display: flex;
  498. flex-wrap: wrap;
  499. align-items: center;
  500. }
  501. .time-coupon {
  502. margin: 10rpx 0rpx;
  503. font-size: 26rpx;
  504. image {
  505. width: 25rpx;
  506. height: 25rpx;
  507. }
  508. .time {
  509. color: #B8B8B8;
  510. margin-left: 6rpx;
  511. }
  512. }
  513. .coupon {
  514. display: flex;
  515. justify-content: center;
  516. align-items: center;
  517. background: #F29E45;
  518. color: white;
  519. width: 140rpx;
  520. height: 45rpx;
  521. border-radius: 10rpx;
  522. margin-left: 10rpx;
  523. }
  524. // .price {
  525. // font-size: 26rpx;
  526. // color: #B8B8B8;
  527. // .current-price {
  528. // font-size: 30rpx;
  529. // font-weight: 600;
  530. // color: #D34430;
  531. // }
  532. // .unit{
  533. // font-size: 20rpx;
  534. // }
  535. // }
  536. .sales-volume {
  537. display: flex;
  538. align-items: center;
  539. color: #B8B8B8;
  540. font-size: 26rpx;
  541. image {
  542. width: 25rpx;
  543. height: 25rpx;
  544. }
  545. }
  546. }
  547. }
  548. .icon {
  549. width: 14px;
  550. height: 14px;
  551. vertical-align: middle;
  552. padding: 6rpx;
  553. }
  554. .mileage {
  555. display: flex;
  556. flex-direction: column;
  557. padding: 10px;
  558. .top {
  559. padding: 5px 10px;
  560. padding-left: 25px;
  561. background-color: #F7C8CC;
  562. font-size: 12px;
  563. position: relative;
  564. }
  565. .top::after {
  566. content: '';
  567. position: absolute;
  568. display: block;
  569. width: 8px;
  570. height: 8px;
  571. background-color: #6fc6ad;
  572. top: 50%;
  573. left: 10px;
  574. transform: translate(0, -40%);
  575. border-radius: 4px;
  576. }
  577. .info {
  578. padding: 10px;
  579. background-color: #FEF4F5;
  580. color: #888;
  581. font-size: 11px;
  582. line-height: 20px;
  583. }
  584. }
  585. .agreement {
  586. display: flex;
  587. justify-content: center;
  588. align-items: center;
  589. padding: 10px 0;
  590. .van-checkbox{
  591. margin-right: 5rpx;
  592. }
  593. }
  594. }
  595. .submit {
  596. position: fixed;
  597. bottom: 0;
  598. left: 0;
  599. width: 100%;
  600. height: 60px;
  601. background-color: #fff;
  602. display: flex;
  603. justify-content: space-between;
  604. align-items: center;
  605. .price {
  606. color: #F39637;
  607. padding: 0 20px;
  608. }
  609. .btn {
  610. background: #EF8C94;
  611. color: white;
  612. width: 120px;
  613. height: 45px;
  614. border-radius: 23px;
  615. font-size: 16px;
  616. display: flex;
  617. justify-content: center;
  618. align-items: center;
  619. }
  620. }
  621. }
  622. </style>