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.

393 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 == '3'" @click="goToReview">
  29. <text>去评价</text>
  30. </view>
  31. <view class="footer-btn pay-btn" v-if="orderDetail.status == '3'" @click="handleReorder">
  32. <text>再来一单</text>
  33. </view>
  34. <view class="footer-btn pay-btn" v-if="orderDetail.status == '2'" @click="handleReorder">
  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.forEach(p => {
  132. price += p.salePrice * p.quantity
  133. itemsText = [...new Set([...itemsText, p.productName])]
  134. })
  135. pet.itemList = itemList
  136. })
  137. //6、将每个宠物添加进items
  138. items.push({
  139. price,
  140. pets,
  141. day,
  142. itemsText,
  143. })
  144. })
  145. //根据日期排序
  146. items = items.sort((a, b) => dayjs(a.day).valueOf() - dayjs(b.day).valueOf())
  147. items.forEach(n => {
  148. n.day = dayjs(n.day).format('MM-DD')
  149. })
  150. console.log(items);
  151. //=====================服务项目以及费用的计算结束=====================
  152. // 构建符合组件渲染需要的数据结构
  153. this.orderDetail = {
  154. // 地址信息
  155. address: {
  156. address: data.receiverProvince + data.receiverCity + data.receiverDistrict + data.receiverDetailAddress,
  157. contact: data.receiverName + ' ' + data.receiverPhone
  158. },
  159. // 宠物信息
  160. pets: data.petVOList ? data.petVOList.map(pet => {
  161. return {
  162. id: pet.id,
  163. name: pet.name,
  164. avatar: pet.photo,
  165. gender: pet.gender,
  166. serviceDays: pet.orderServiceText ? pet.orderServiceText.length : 0,
  167. serviceDates: pet.orderServiceText || [],
  168. services: pet.productNameText || []
  169. };
  170. }) : [],
  171. // 服务项目列表
  172. items,
  173. // 费用信息
  174. totalAmount: data.totalAmount,
  175. discount: data.totalAmount - data.payAmount,
  176. finalAmount: data.payAmount,
  177. // 订单状态
  178. status: data.status.toString(),
  179. // 备注信息
  180. remarks: {
  181. keyHandoverMethod: '存于快递柜',
  182. isAdvanceFamiliar: true,
  183. priceInfo: `价格${data.payAmount}`,
  184. serviceContent: '服务内容: 伴宠师将按照约定时间上门照顾宠物',
  185. serviceCondition: '服务保障: 购买此服务后,平台将安排伴宠师与您确认服务细节',
  186. notes: data.note || ''
  187. },
  188. // 其他信息
  189. orderInfo: {
  190. orderNumber: data.orderSn,
  191. orderTime: data.createTime,
  192. paymentTime: data.paymentTime
  193. }
  194. };
  195. // 如果有服务信息,处理服务日期和时间段
  196. if (data.orderServiceList && data.orderServiceList.length > 0) {
  197. // 处理服务日期和时间段
  198. const serviceDate = data.orderServiceList[0].serviceDate;
  199. const serviceTime = data.orderServiceList[0].expectServiceTime;
  200. // 更新服务项目描述
  201. if (this.orderDetail.items.length > 0) {
  202. this.orderDetail.items[0].serviceDate = serviceDate;
  203. this.orderDetail.items[0].serviceTime = timeSlotMap[serviceTime] || serviceTime;
  204. }
  205. }
  206. }
  207. }).catch(err => {
  208. console.error('获取订单详情失败', err);
  209. });
  210. },
  211. // 去付款
  212. goToPay() {
  213. const { orderPay } = require('@/api/order/order.js');
  214. orderPay({
  215. orderId: this.orderId
  216. }).then(res => {
  217. this.pay(res.data)
  218. }).catch(err => {
  219. console.log(err);
  220. });
  221. },
  222. pay(params) {
  223. if (this.isPaying) {
  224. return;
  225. }
  226. this.isPaying = true
  227. uni.requestPayment({
  228. provider: 'wxpay',
  229. timeStamp: params.timeStamp,
  230. nonceStr: params.nonceStr,
  231. package: params.package_,
  232. signType: params.signType,
  233. paySign: params.paySign,
  234. success: (res) => {
  235. this.$modal.showToast('支付成功')
  236. this.getOrderDetail()
  237. },
  238. fail: (err) => {
  239. this.loading = false
  240. console.log('支付失败', err)
  241. this.$modal.showToast('支付失败')
  242. },
  243. complete: () => {
  244. this.loading = false
  245. this.isPaying = false
  246. }
  247. })
  248. },
  249. // 去评价
  250. goToReview() {
  251. const order = this.detail;
  252. uni.navigateTo({
  253. url: `/pages_order/order/orderReview?id=${order.teacherId}&orderId=${order.orderId}`
  254. });
  255. },
  256. // 处理取消订单
  257. handleCancelOrder() {
  258. this.getOrderDetail();
  259. },
  260. // 处理再来一单/查看服务记录
  261. handleReorder() {
  262. if (this.orderDetail.status == '3') {
  263. // 再来一单 - 可以添加伴宠师选择弹窗
  264. uni.showToast({
  265. title: '再来一单功能开发中',
  266. icon: 'none'
  267. });
  268. } else if (this.orderDetail.status == '2') {
  269. // 查看服务记录
  270. uni.navigateTo({
  271. url: `/pages_order/order/serviceRecord?orderId=${this.orderId}`
  272. });
  273. }
  274. },
  275. // 修改订单
  276. modifyOrder() {
  277. // 跳转到服务选择页面,并传递订单ID参数
  278. uni.navigateTo({
  279. url: `/pages_order/order/orderModify?orderId=${this.orderId}`
  280. });
  281. }
  282. }
  283. }
  284. </script>
  285. <style lang="scss" scoped>
  286. .order-detail-page {
  287. background-color: #f5f5f5;
  288. min-height: 100vh;
  289. display: flex;
  290. flex-direction: column;
  291. }
  292. .order-detail-content {
  293. flex: 1;
  294. padding: 20rpx;
  295. }
  296. .order-detail-footer {
  297. display: flex;
  298. justify-content: flex-end;
  299. align-items: center;
  300. padding: 20rpx 30rpx;
  301. background-color: #FFFFFF;
  302. border-top: 1px solid #EEEEEE;
  303. .footer-btn {
  304. padding: 16rpx 30rpx;
  305. border-radius: 30rpx;
  306. font-size: 26rpx;
  307. margin-left: 20rpx;
  308. }
  309. .cancel-btn {
  310. background-color: #FFFFFF;
  311. color: #666;
  312. border: 1px solid #DDDDDD;
  313. }
  314. .pay-btn {
  315. background-color: #FFAA48;
  316. color: #FFFFFF;
  317. }
  318. .modify-btn {
  319. background-color: #FFAA48;
  320. color: #FFFFFF;
  321. }
  322. .review-btn {
  323. background-color: #FFAA48;
  324. color: #FFFFFF;
  325. }
  326. .contact-btn {
  327. background-color: #FFFFFF;
  328. color: #666;
  329. border: 1px solid #DDDDDD;
  330. }
  331. }
  332. </style>