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.

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