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.

731 lines
18 KiB

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