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.

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