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.

403 lines
12 KiB

  1. <template>
  2. <view class="order-detail-page">
  3. <!-- 订单内容区域 -->
  4. <view class="order-detail-content">
  5. <!-- 服务地址组件 -->
  6. <service-address :address="orderDetail.address"></service-address>
  7. <!-- 服务宠物组件 -->
  8. <service-pets :pets="orderDetail.pets"></service-pets>
  9. <!-- 服务项目及费用组件 -->
  10. <service-items :items="orderDetail.items" :totalAmount="orderDetail.totalAmount"
  11. :discount="orderDetail.discount" :finalAmount="orderDetail.finalAmount"
  12. :memberDiscount="orderDetail.memberDiscount"
  13. :orderDetail="orderDetail"
  14. ></service-items>
  15. <!-- 服务备注组件 -->
  16. <service-remarks :remarks="orderDetail.remarks"></service-remarks>
  17. <!-- 其他信息组件 -->
  18. <order-info :orderInfo="orderDetail.orderInfo"></order-info>
  19. </view>
  20. <!-- 底部按钮区域 -->
  21. <view class="order-detail-footer">
  22. <view class="footer-btn cancel-btn" v-if="[0, 1].includes(orderDetail.status)" @click="$refs.cancelOrderPopup.open()">
  23. <text>取消订单</text>
  24. </view>
  25. <view class="footer-btn pay-btn" v-if="orderDetail.status == '0'" @click="goToPay">
  26. <text>去付款</text>
  27. </view>
  28. <view class="footer-btn modify-btn" v-if="[0, 1].includes(orderDetail.status)" @click="modifyOrder">
  29. <text>修改订单</text>
  30. </view>
  31. <view class="footer-btn pay-btn" v-if="[3].includes(orderDetail.status) && !order.evaluation" @click="goToReview">
  32. <text>去评价</text>
  33. </view>
  34. <view class="footer-btn pay-btn" v-if="orderDetail.status == '3'" @click="handleReorder">
  35. <text>再来一单</text>
  36. </view>
  37. <view class="footer-btn pay-btn" v-if="[2,3,11].includes(orderDetail.status)" @click="viewServiceRecord">
  38. <text>查看服务记录</text>
  39. </view>
  40. <view class="footer-btn contact-btn">
  41. <text>联系客服</text>
  42. </view>
  43. </view>
  44. <!-- 取消订单弹窗 -->
  45. <cancel-order-popup
  46. ref="cancelOrderPopup"
  47. @cancel="handleCancelOrder"
  48. ></cancel-order-popup>
  49. <!-- 客服组件 -->
  50. <Kefu></Kefu>
  51. </view>
  52. </template>
  53. <script>
  54. import Kefu from '@/pages/common/kefu.vue'
  55. import ServiceAddress from '@/pages_order/components/order/ServiceAddress.vue'
  56. import ServicePets from '@/pages_order/components/order/ServicePets.vue'
  57. import ServiceItems from '@/pages_order/components/order/ServiceItems.vue'
  58. import ServiceRemarks from '@/pages_order/components/order/ServiceRemarks.vue'
  59. import OrderInfo from '@/pages_order/components/order/OrderInfo.vue'
  60. import CancelOrderPopup from '@/pages_order/components/order/CancelOrderPopup.vue'
  61. import { getOrderList } from "@/api/system/user.js"
  62. import { getOpenIdKey } from '@/utils/auth'
  63. import { getOrderDetail } from '@/api/order/order.js'
  64. import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js'
  65. import dayjs from '@/utils/lib/dayjs.min.js'
  66. // 服务时间段映射
  67. const timeSlotMap = {
  68. 'MORNING': '上午',
  69. 'AFTERNOON': '下午',
  70. 'EVENING': '晚上'
  71. }
  72. export default {
  73. components: {
  74. Kefu,
  75. ServiceAddress,
  76. ServicePets,
  77. ServiceItems,
  78. ServiceRemarks,
  79. OrderInfo,
  80. CancelOrderPopup
  81. },
  82. data() {
  83. return {
  84. orderId: null,
  85. orderDetail: {},//格式化后的数据
  86. detail : {},//未格式化的数据
  87. isPaying: false,
  88. loading: false
  89. };
  90. },
  91. onLoad(options) {
  92. if (options.id) {
  93. this.orderId = options.id;
  94. this.getOrderDetail();
  95. }
  96. },
  97. methods: {
  98. // 获取订单详情
  99. getOrderDetail() {
  100. const params = {
  101. openId: getOpenIdKey(),
  102. orderId: this.orderId
  103. };
  104. getOrderDetail(params).then(res => {
  105. if (res) {
  106. // 处理接口返回的数据
  107. const data = res;
  108. this.detail = data; // 保存原始数据
  109. data.petVOList.forEach(pet => {
  110. pet.orderServiceText = getOrderServiceText(pet.id, data.orderServiceList) // 日期
  111. pet.productNameText = getProductNameText(pet.id, data.orderItemList, data.orderServiceList) // 服务
  112. })
  113. //=====================服务项目以及费用的计算开始=====================
  114. let items = []
  115. //1、找出有哪些日期
  116. let days = [...new Set(data.orderServiceList.map(item => item.serviceDate))]
  117. days.forEach(day => {
  118. let price = 0;
  119. let itemsText = []
  120. //2、找出每个日期对应的服务对象
  121. let dayItems = data.orderServiceList.filter(item => item.serviceDate === day)
  122. //3、找出每个服务对象对应的宠物
  123. let pets = data.petVOList.filter(item => dayItems.some(dayItem => dayItem.petId === item.id))
  124. //深度拷贝pets
  125. pets = JSON.parse(JSON.stringify(pets))
  126. //4、将每个服务对象添加进对应的宠物
  127. pets.forEach(pet => {
  128. pet.serviceList = dayItems.filter(item => item.petId === pet.id)
  129. let itemList = []
  130. //5、将每个服务对象中添加对应的项目
  131. pet.serviceList.forEach(item => {
  132. itemList.push(...(data.orderItemList.filter(n => n.orderServiceId == item.id)))
  133. })
  134. itemList = itemList.reverse();
  135. itemList.forEach(p => {
  136. price += p.salePrice * p.quantity
  137. itemsText = [...new Set([...itemsText, p.productName])]
  138. })
  139. pet.itemList = itemList
  140. })
  141. //6、将每个宠物添加进items
  142. items.push({
  143. price,
  144. pets,
  145. day,
  146. itemsText,
  147. })
  148. })
  149. //根据日期排序
  150. items = items.sort((a, b) => dayjs(a.day).valueOf() - dayjs(b.day).valueOf())
  151. items.forEach(n => {
  152. n.day = dayjs(n.day).format('MM-DD')
  153. })
  154. console.log(items);
  155. //=====================服务项目以及费用的计算结束=====================
  156. // 构建符合组件渲染需要的数据结构
  157. this.orderDetail = {
  158. // 地址信息
  159. address: {
  160. address: data.receiverProvince + data.receiverCity + data.receiverDistrict + data.receiverDetailAddress,
  161. contact: data.receiverName + ' ' + data.receiverPhone
  162. },
  163. // 宠物信息
  164. pets: data.petVOList ? data.petVOList.map(pet => {
  165. return {
  166. id: pet.id,
  167. name: pet.name,
  168. avatar: pet.photo,
  169. gender: pet.gender,
  170. serviceDays: pet.orderServiceText ? pet.orderServiceText.length : 0,
  171. serviceDates: pet.orderServiceText || [],
  172. services: pet.productNameText || []
  173. };
  174. }) : [],
  175. // 服务项目列表
  176. items,
  177. // 费用信息
  178. totalAmount: data.totalAmount,
  179. discount: data.couponDiscount,
  180. memberDiscount: data.memberDiscount,
  181. finalAmount: data.payAmount,
  182. needPreFamiliarize : data.needPreFamiliarize,
  183. companionLevelPrice : data.companionLevelPrice,
  184. // 订单状态
  185. status: data.status.toString(),
  186. // 备注信息
  187. remarks: {
  188. keyHandoverMethod: '存于快递柜',
  189. isAdvanceFamiliar: data.needPreFamiliarize,
  190. priceInfo: `价格${data.preFamiliarizePrice}`,
  191. serviceContent: '服务内容: 伴宠师将按照约定时间上门照顾宠物',
  192. serviceCondition: '服务保障: 购买此服务后,平台将安排伴宠师与您确认服务细节',
  193. notes: data.note || ''
  194. },
  195. // 其他信息
  196. orderInfo: {
  197. orderNumber: data.orderSn,
  198. orderTime: data.createTime,
  199. paymentTime: data.paymentTime
  200. }
  201. };
  202. // 如果有服务信息,处理服务日期和时间段
  203. if (data.orderServiceList && data.orderServiceList.length > 0) {
  204. // 处理服务日期和时间段
  205. const serviceDate = data.orderServiceList[0].serviceDate;
  206. const serviceTime = data.orderServiceList[0].expectServiceTime;
  207. // 更新服务项目描述
  208. if (this.orderDetail.items.length > 0) {
  209. this.orderDetail.items[0].serviceDate = serviceDate;
  210. this.orderDetail.items[0].serviceTime = timeSlotMap[serviceTime] || serviceTime;
  211. }
  212. }
  213. }
  214. }).catch(err => {
  215. console.error('获取订单详情失败', err);
  216. });
  217. },
  218. // 去付款
  219. goToPay() {
  220. const { orderPay } = require('@/api/order/order.js');
  221. orderPay({
  222. orderId: this.orderId
  223. }).then(res => {
  224. this.pay(res.data)
  225. }).catch(err => {
  226. console.log(err);
  227. });
  228. },
  229. pay(params) {
  230. if (this.isPaying) {
  231. return;
  232. }
  233. this.isPaying = true
  234. uni.requestPayment({
  235. provider: 'wxpay',
  236. timeStamp: params.timeStamp,
  237. nonceStr: params.nonceStr,
  238. package: params.package_,
  239. signType: params.signType,
  240. paySign: params.paySign,
  241. success: (res) => {
  242. this.$modal.showToast('支付成功')
  243. this.getOrderDetail()
  244. },
  245. fail: (err) => {
  246. this.loading = false
  247. console.log('支付失败', err)
  248. this.$modal.showToast('支付失败')
  249. },
  250. complete: () => {
  251. this.loading = false
  252. this.isPaying = false
  253. }
  254. })
  255. },
  256. // 去评价
  257. goToReview() {
  258. const order = this.detail;
  259. uni.navigateTo({
  260. url: `/pages_order/order/orderReview?id=${order.teacherId}&orderId=${order.orderId}`
  261. });
  262. },
  263. // 处理取消订单
  264. handleCancelOrder() {
  265. this.getOrderDetail();
  266. },
  267. // 处理再来一单
  268. handleReorder() {
  269. if (this.orderDetail.status == '4') {
  270. // 再来一单 - 可以添加伴宠师选择弹窗
  271. uni.showToast({
  272. title: '再来一单功能开发中',
  273. icon: 'none'
  274. });
  275. }
  276. },
  277. // 查看服务记录
  278. viewServiceRecord() {
  279. uni.navigateTo({
  280. url: `/pages_order/order/serviceRecord?orderId=${this.orderId}`
  281. });
  282. },
  283. // 修改订单
  284. modifyOrder() {
  285. // 跳转到服务选择页面,并传递订单ID参数
  286. uni.navigateTo({
  287. url: `/pages_order/order/orderModify?orderId=${this.orderId}`
  288. });
  289. }
  290. }
  291. }
  292. </script>
  293. <style lang="scss" scoped>
  294. .order-detail-page {
  295. background-color: #f5f5f5;
  296. min-height: 100vh;
  297. display: flex;
  298. flex-direction: column;
  299. }
  300. .order-detail-content {
  301. flex: 1;
  302. padding: 20rpx;
  303. }
  304. .order-detail-footer {
  305. display: flex;
  306. justify-content: flex-end;
  307. align-items: center;
  308. padding: 20rpx 30rpx;
  309. background-color: #FFFFFF;
  310. border-top: 1px solid #EEEEEE;
  311. .footer-btn {
  312. padding: 16rpx 30rpx;
  313. border-radius: 30rpx;
  314. font-size: 26rpx;
  315. margin-left: 20rpx;
  316. }
  317. .cancel-btn {
  318. background-color: #FFFFFF;
  319. color: #666;
  320. border: 1px solid #DDDDDD;
  321. }
  322. .pay-btn {
  323. background-color: #FFAA48;
  324. color: #FFFFFF;
  325. }
  326. .modify-btn {
  327. background-color: #FFAA48;
  328. color: #FFFFFF;
  329. }
  330. .review-btn {
  331. background-color: #FFAA48;
  332. color: #FFFFFF;
  333. }
  334. .contact-btn {
  335. background-color: #FFFFFF;
  336. color: #666;
  337. border: 1px solid #DDDDDD;
  338. }
  339. }
  340. </style>