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.

1418 lines
56 KiB

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
  1. <template>
  2. <view class="service-new container">
  3. <view style="background-color: #FFF4E5; margin: 10px; padding: 10px; border-radius: 8rpx;">
  4. <view style="display: flex;">
  5. <image style="width: 40rpx; height: 40rpx;" slot='cover'
  6. src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/petServiceOrder/OrderIcon.png">
  7. </image>
  8. <text style="color: #A94F20; font-size: 28rpx; font-weight: 500;">
  9. 下单方式
  10. <text v-if="buyInfo.teacher">指定喂养员 - {{ buyInfo.teacher.userName }}</text>
  11. <text v-else>系统派单</text>
  12. </text>
  13. </view>
  14. <view style="margin-top: 10rpx;">
  15. <text v-if="buyInfo.teacher" style="color: #A94F20; font-size: 24rpx; font-weight: 400;">
  16. (若伴宠师1小时内无响应或拒绝接单则系统派单)
  17. </text>
  18. </view>
  19. </view>
  20. <view>
  21. <uni-card padding=0 :is-shadow="false">
  22. <view class="service-new-title" slot="title">
  23. <view class="service-new-title-left">
  24. <view class="service-new-flag"></view>
  25. <view>爱宠选择</view>
  26. </view>
  27. </view>
  28. <view class="split-line"></view>
  29. <view class="service-new-pet-content">
  30. <scroll-view scroll-x class="scroll-view">
  31. <view class="scroll-content">
  32. <view v-for="item in currentPets" :key="item.id" class="service-new-pet-item ellipsis"
  33. :class="{ 'pet-selected': item.id === currentPetId, 'pet-unselect': item.id !== currentPetId }"
  34. @click="selectPet(item)">
  35. {{ item.name }}
  36. </view>
  37. </view>
  38. </scroll-view>
  39. </view>
  40. </uni-card>
  41. </view>
  42. <view>
  43. <uni-card padding=0 :is-shadow="false">
  44. <view class="service-new-title" slot="title">
  45. <view class="service-new-title-left">
  46. <view class="service-new-flag"></view>
  47. <view>服务日期</view>
  48. </view>
  49. </view>
  50. <view class="split-line"></view>
  51. <view class="service-new-pet-content">
  52. <scroll-view scroll-y class="scroll-view-vertical">
  53. <view v-for="(month, monthIndex) in sortedGroupedDates" :key="monthIndex" class="month-group">
  54. <view class="month-title">{{ month.monthLabel }}</view>
  55. <scroll-view scroll-x class="scroll-view-horizontal">
  56. <view class="dates-wrapper">
  57. <view v-for="(day, dayIndex) in month.dates" :key="dayIndex" class="calendar-day"
  58. :class="{ 'day-selected': isDateSelected(day) }" @click="selectDate(day)">
  59. <image :src="isDateSelected(day) ?
  60. 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/updated.png' :
  61. 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/update_un.png'" class="calendar-bg" />
  62. <text class="day-text"
  63. :class="{ 'day-highlighted': isCurrentSelected(day), 'day-normal': !isCurrentSelected(day) }">
  64. {{ day.date < 10 ? '0' + day.date : day.date }}</text>
  65. </view>
  66. </view>
  67. </scroll-view>
  68. </view>
  69. </scroll-view>
  70. </view>
  71. </uni-card>
  72. </view>
  73. <view>
  74. <uni-card padding=0 :is-shadow="false">
  75. <view class="service-new-title" slot="title">
  76. <view class="service-new-title-left">
  77. <view class="service-new-flag"></view>
  78. <view>期望时间 <span class="time-slot-time-tip">*请勾选您可以接受的上门时间段</span></view>
  79. </view>
  80. </view>
  81. <view class="split-line"></view>
  82. <view class="service-new-pet-content">
  83. <view class="time-slots">
  84. <view v-for="slot in timeSlots" :key="slot.id" class="time-slot-item"
  85. @click="selectTimeSlot(slot.id)">
  86. <image :src="slot.selected ? slot.activeIcon : slot.inactiveIcon" class="time-slot-icon" />
  87. <view class="time-slot-info">
  88. <text class="time-slot-time">{{ slot.time }}</text>
  89. </view>
  90. </view>
  91. </view>
  92. </view>
  93. </uni-card>
  94. </view>
  95. <view>
  96. <uni-card padding=0 :is-shadow="false">
  97. <view class="service-new-title" slot="title">
  98. <view class="service-new-title-left">
  99. <view class="service-new-flag"></view>
  100. <view>服务选择</view>
  101. </view>
  102. <view style="display: flex; justify-content: flex-end; align-items: center; ">
  103. <view style="margin-right: 10rpx;color: #AAAAAA;">爱宠{{ currentPetId && getCurrentPetName() }}
  104. 全日期保持一致</view>
  105. <u-switch space="2" :value="isAllSame" activeColor="#f9ae3d" size="18" @change="isAllSameChange"
  106. inactiveColor="rgb(230, 230, 230)">
  107. </u-switch>
  108. </view>
  109. </view>
  110. <view class="split-line"></view>
  111. <view class="service-new-pet-content">
  112. <view class="service-item">
  113. <view class="service-item-header">
  114. <image src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/service.png"
  115. class="service-icon"></image>
  116. <text class="service-title">基础服务</text>
  117. </view>
  118. <view class="service-list">
  119. <!-- <view style="border-radius: 8rpx" :style="{'background-color': needFeed.length > 0 ? '#FFFCF2' : '#F9F9F9', 'border': needFeed.length > 0 ? '1px solid #FFBF60' : 'none'}" >
  120. <view style="padding: 30rpx 0; margin: 0 20rpx; ">
  121. <u-checkbox-group
  122. v-model="needFeed"
  123. iconPlacement="right"
  124. placement="column">
  125. <u-checkbox activeColor="#FFBF60" label="专业喂养" shape="circle"></u-checkbox>
  126. </u-checkbox-group>
  127. </view>
  128. </view> -->
  129. <view class="service-list" style="border-radius: 8rpx;margin-top: 28rpx;">
  130. <view class="service-row" style="background-color: #FFECCD">
  131. <view class="service-row-content"
  132. :style="{ 'border-bottom': feedCount > 1 ? '1rpx solid #ECBFA8' : 'none' }">
  133. <text class="service-name" style="color: #A94F20;">一天多次</text>
  134. <view class="service-price">
  135. <u-number-box slot="right-icon" :value="feedCount" @change="feedCountChange"
  136. step="1" :min="1" :max="3">
  137. <view slot="minus" class="minus">
  138. <u-icon name="minus-circle-fill" size="20" color="#FFBF60"></u-icon>
  139. </view>
  140. <text slot="input" style="width: 40rpx;text-align: center;"
  141. class="input">{{ feedCount }}</text>
  142. <view slot="plus" class="plus">
  143. <u-icon name="plus-circle-fill" color="#FFBF60" size="20"></u-icon>
  144. </view>
  145. </u-number-box>
  146. </view>
  147. </view>
  148. </view>
  149. <view v-if="feedCount > 1" class="service-row" style="background-color: #FFECCD">
  150. <view class="service-row-content">
  151. <text class="service-name" style="color: #A94F20;">额外服务费</text>
  152. <view class="service-price" style="color:#A94F20">
  153. ¥{{ feedCount > 2 ? 130 : 45 }}
  154. </view>
  155. </view>
  156. </view>
  157. </view>
  158. </view>
  159. </view>
  160. <view class="service-item">
  161. <view class="service-item-header">
  162. <image src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/love.png"
  163. class="service-icon"></image>
  164. <text class="service-title">定制服务</text>
  165. </view>
  166. <view class="service-list" style="border-radius: 8rpx;">
  167. <view class="service-row" v-for="(item, index) in customServices" :key="item.skuId">
  168. <view class="service-row-content"
  169. :style="{ 'border-bottom': index !== customServices.length - 1 ? '1rpx solid #EFEFEF' : 'none' }">
  170. <text class="service-name" style="">{{ item.name }}</text>
  171. <view class="service-price">
  172. <text
  173. style="font-size: 32rpx; color: #FFBF60; margin-right: 20rpx;">¥{{ item.price }}/</text>
  174. <u-number-box slot="right-icon" :value="item.quantity" :name="item.name"
  175. @change="customServiceCountChange" step="1" :min="0" :max="10">
  176. <view slot="minus" class="minus">
  177. <u-icon name="minus-circle-fill" size="20" color="#FFBF60"></u-icon>
  178. </view>
  179. <text slot="input" style="width: 40rpx;text-align: center;"
  180. class="input">{{ item.quantity }}</text>
  181. <view slot="plus" class="plus">
  182. <u-icon name="plus-circle-fill" color="#FFBF60" size="20"></u-icon>
  183. </view>
  184. </u-number-box>
  185. </view>
  186. </view>
  187. </view>
  188. </view>
  189. </view>
  190. </view>
  191. </uni-card>
  192. </view>
  193. <view v-if="!showPriceDetails" class="details-subscribe">
  194. <view style="display: flex;justify-content: space-between;">
  195. <view style="height: 80rpx;">
  196. <view>
  197. <text style="color: #333333;">订单总价 </text>
  198. <text style="color: #FF530A; font-size: 40rpx;">¥{{ totalPrice }} <text
  199. style="font-size: 32rpx;">.00</text></text>
  200. </view>
  201. <view style="display: flex; justify-content: flex-end;" @click="togglePriceDetails">
  202. <text v-if="currentDayPrice" style="color:#FF530A; font-size: 22rpx;"> 当日价格¥{{ currentDayPrice
  203. }}.00 |</text>
  204. <text style="color:#FF530A; font-size: 22rpx;margin-left: 10rpx;">明细</text>
  205. <u-icon name="arrow-up" color="#FF530A" size="10"></u-icon>
  206. </view>
  207. </view>
  208. <view style="display: flex;">
  209. <u-button color="#FFF4E4" customStyle="width: 200rpx; color: #FFAA48; margin-right: 20rpx;"
  210. text="上一步" @click="goBack"></u-button>
  211. <u-button color="#FFBF60" customStyle="width: 200rpx; color: #FFF;" text="确认下单"
  212. @click="goNext"></u-button>
  213. </view>
  214. </view>
  215. </view>
  216. <!-- 遮罩层 -->
  217. <view v-if="showPriceDetails" class="price-details-overlay">
  218. <view class="price-details">
  219. <view class="price-details-header">
  220. <text
  221. style="text-align: center; width: 100%; font-size: 32rpx; font-weight: 500; color: #333333;">价格明细</text>
  222. <u-icon name="close" @click="togglePriceDetails"></u-icon>
  223. </view>
  224. <view style="text-align: center; width: 100%; font-size: 28rpx; color: #AAAAAA; margin: 20rpx 0;">
  225. 实际支付金额以确认下单页为准</view>
  226. <view class="split-line"></view>
  227. <scroll-view class="price-details-body" scroll-y>
  228. <view v-for="(item, index) in priceDetails" :key="index">
  229. <view class="price-details-item">
  230. <view v-if="showName(item)" style="font-size: 28rpx; color: #333333;">{{ item.name }}</view>
  231. <view class="price-details-item-price-total">
  232. <view style="display: flex;" v-for="(item2, index) in item.item" :key="index">
  233. <view style="display: flex; align-items: center;">
  234. <view v-if="item2.date && item2.quantity"
  235. class="price-details-item-price-total-item">{{ item2.date }}</view>
  236. <view v-if="item2.itemName != item.name && item2.quantity"
  237. class="price-details-item-price-total-item">{{ item2.itemName }}</view>
  238. <view v-if="item2.quantity" class="price-details-item-price-total-item">
  239. ¥{{ item2.price }} × {{ item2.quantity }} {{ item2.unit }}</view>
  240. </view>
  241. <view v-if="item2.quantity"
  242. style="color: #333333; margin-left: 20rpx; margin: auto 0; width: 100rpx; text-align: right; font-size: 28rpx;">
  243. ¥{{ item2.price * item2.quantity }}</view>
  244. </view>
  245. </view>
  246. </view>
  247. </view>
  248. </scroll-view>
  249. <view style="position: absolute; bottom: 0; left: 0; right: 0; padding: 20rpx;">
  250. <view class="split-line"></view>
  251. <view class="price-details-item" style="margin: 20rpx 0;">
  252. <view style="font-size: 32rpx; color: #333333; font-weight: 500;">合计</view>
  253. <view style="font-size: 32rpx; color: #333333; font-weight: 500;">¥{{ totalPrice }}</view>
  254. </view>
  255. <view class="split-line"></view>
  256. </view>
  257. </view>
  258. <view class="details-subscribe">
  259. <view style="display: flex;justify-content: space-between;">
  260. <view style="height: 80rpx;">
  261. <view>
  262. <text style="color: #333333;">订单总价 </text>
  263. <text style="color: #FF530A; font-size: 40rpx;">¥{{ totalPrice }} <text
  264. style="font-size: 32rpx;">.00</text></text>
  265. </view>
  266. <view style="display: flex; justify-content: flex-end;" @click="togglePriceDetails">
  267. <text v-if="currentDayPrice" style="color:#FF530A; font-size: 22rpx;"> 当日价格¥{{
  268. currentDayPrice }}.00 |</text>
  269. <text style="color:#FF530A; font-size: 22rpx;margin-left: 10rpx;">明细</text>
  270. <u-icon name="arrow-up" color="#FF530A" size="10"></u-icon>
  271. </view>
  272. </view>
  273. <view style="display: flex;">
  274. <u-button color="#FFF4E4" customStyle="width: 200rpx; color: #FFAA48; margin-right: 20rpx;"
  275. text="上一步" @click="goBack"></u-button>
  276. <u-button color="#FFBF60" customStyle="width: 200rpx; color: #FFF;" text="确认下单"
  277. @click="goNext"></u-button>
  278. </view>
  279. </view>
  280. </view>
  281. </view>
  282. </view>
  283. </template>
  284. <script>
  285. import {
  286. getProductList,
  287. getOpenId
  288. } from "@/api/system/user"
  289. import { setToken, setOpenIdKey } from '@/utils/auth'
  290. export default {
  291. data() {
  292. return {
  293. basePrice: 75,
  294. baseProduct: '专业喂养',
  295. currentPets: [],
  296. currentPetId: '',
  297. currentMonthDay: {},
  298. selectedDates: [],
  299. groupedDates: [],
  300. timeSlots: [
  301. {
  302. id: 'MORNING',
  303. name: '早上',
  304. time: '08:00-12:00',
  305. selected: false,
  306. activeIcon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/morning.png',
  307. inactiveIcon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/morning_un.png'
  308. },
  309. {
  310. id: 'AFTERNOON',
  311. name: '午后',
  312. time: '12:00-18:00',
  313. selected: false,
  314. activeIcon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/noon.png',
  315. inactiveIcon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/noon_un.png'
  316. },
  317. {
  318. id: 'EVENING',
  319. name: '晚间',
  320. time: '18:00-22:00',
  321. selected: false,
  322. activeIcon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/night.png',
  323. inactiveIcon: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/newOrder/night_un.png'
  324. }
  325. ],
  326. feedCount: 1,
  327. // customServices原始值
  328. customServicesStr: '',
  329. customServices: [
  330. { name: '陪玩(20分钟)', price: 20, quantity: 0 },
  331. { name: '活动区吸毛', price: 20, quantity: 0 },
  332. { name: '毛发梳理', price: 15, quantity: 0 },
  333. { name: '身体清洁(如眼、耳、鼻等)', price: 5, quantity: 0 },
  334. { name: '指甲修剪', price: 10, quantity: 0 },
  335. { name: '会员深度清洁', price: 20, quantity: 0 },
  336. { name: '喂药', price: 15, quantity: 0 },
  337. { name: '上药', price: 25, quantity: 0 }
  338. ],
  339. showPriceDetails: false, // 控制价格明细的显示
  340. priceDetails: [],
  341. totalPrice: 0,
  342. isAllSame: false,
  343. newOrderData: [],
  344. // 提前熟悉费用
  345. needPreFamiliarizeCost: 0,
  346. // 基础服务总费用
  347. baseServiceTotalCost: 0,
  348. // 额外宠物总费用
  349. additionalTotalCost: 0,
  350. // 多次服务总费用
  351. multServicesTotalCost: 0,
  352. // 定制服务总费用
  353. customServicesTotalCost: 0,
  354. // 一天两次日期
  355. oneDayTwoTimesDates: [],
  356. // 一天三次日期
  357. oneDayThreeTimesDates: [],
  358. // 宠物类型次数统计
  359. petTypeCounts: [],
  360. // 定制服务单项总次数统计
  361. customServiceItemCount: [],
  362. // 当日价格
  363. currentDayPrice: 0,
  364. }
  365. },
  366. onLoad: function (option) {
  367. },
  368. mounted() {
  369. this.currentPets = this.$globalData.newOrderData.currentPets;
  370. if (this.currentPets.length < 1) {
  371. uni.reLaunch({
  372. url: '/pages/index'
  373. });
  374. return
  375. }
  376. if (this.$globalData.mainSku && this.$globalData.mainSku[0]) {
  377. this.basePrice = this.$globalData.mainSku[0].price
  378. this.baseProduct = this.$globalData.mainSku[0].name
  379. }
  380. this.getProductList()
  381. },
  382. watch: {
  383. currentPetId: {
  384. immediate: true,
  385. handler(newId) {
  386. if (newId) {
  387. this.updateGroupedDates()
  388. }
  389. }
  390. }
  391. },
  392. methods: {
  393. initNewOrderData() {
  394. const needPreFamiliarize = this.$globalData.newOrderData.needPreFamiliarize.length > 0
  395. const pets = []
  396. // 初始化当前宠物全日期保持一致
  397. this.currentPets = this.currentPets.map(pet => {
  398. pet.isAllSame = false
  399. return pet
  400. })
  401. this.currentPets.map(pet => {
  402. // 单个宠物服务日期列表
  403. const serviceDateList = pet.selectedDate.map(item => item.date)
  404. serviceDateList.forEach(date => {
  405. pets.push({
  406. petId: pet.id,
  407. serviceDate: date,
  408. name: pet.name,
  409. gender: pet.gender,
  410. petType: pet.petType,
  411. bodyType: pet.bodyType,
  412. photo: pet.photo,
  413. feedCount: 1,
  414. selectedTimeSlots: [],
  415. customServices: [],
  416. //额外费用
  417. additionalCost: 0
  418. })
  419. })
  420. })
  421. this.newOrderData = {
  422. needPreFamiliarize: needPreFamiliarize, // 是否需要提前熟悉 40元/次 参与计算
  423. pets: pets
  424. }
  425. // 默认选择第一个宠物
  426. this.selectPet(this.currentPets[0] || {})
  427. this.calculateTotalPrice()
  428. },
  429. // 选择宠物
  430. selectPet(pet) {
  431. this.currentPetId = pet.id
  432. // 默认选择当前宠物的最小日期
  433. if (pet.selectedDate?.length > 1) {
  434. const minDate = pet.selectedDate.reduce((min, date) => {
  435. const currentDate = new Date(date.date);
  436. const minDate = new Date(min.date);
  437. return currentDate < minDate ? date : min;
  438. }, pet.selectedDate[0]);
  439. // 当前选择日期
  440. this.currentMonthDay = {
  441. petId: this.currentPetId,
  442. date: new Date(minDate.date).getDate(),
  443. fullDate: minDate.date
  444. }
  445. } else {
  446. this.currentMonthDay = {
  447. petId: this.currentPetId,
  448. date: new Date(pet.selectedDate[0].date).getDate(),
  449. fullDate: pet.selectedDate[0].date
  450. }
  451. }
  452. this.getCurrentPetIsAllSame()
  453. this.selectDate(this.currentMonthDay)
  454. },
  455. selectDate(day) {
  456. // 当前选择日期
  457. this.currentMonthDay = day
  458. const selectedDay = this.selectedDates?.find(item => item.fullDate === day.fullDate && item
  459. .currentPetId === day.petId)
  460. if (!selectedDay) {
  461. this.selectedDates.push(day)
  462. }
  463. // 还原当前选择日期是否已选择期望时间
  464. const pets = this.newOrderData?.pets
  465. const selectedPet = pets.find(pet => pet.petId === this.currentPetId && pet.serviceDate === this
  466. .currentMonthDay.fullDate);
  467. const selectedTimeSlots = selectedPet ? selectedPet.selectedTimeSlots : [];
  468. if (selectedTimeSlots.length > 0) {
  469. this.timeSlots.forEach(slot => {
  470. if (selectedTimeSlots.includes(slot.id)) {
  471. slot.selected = true
  472. } else {
  473. slot.selected = false
  474. }
  475. })
  476. } else {
  477. this.timeSlots.forEach(slot => {
  478. slot.selected = false
  479. })
  480. }
  481. // 还原当前选择日期喂食次数
  482. this.feedCount = selectedPet ? selectedPet.feedCount : 1
  483. // 还原当前选择日期是否已选择定制服务
  484. this.customServices = selectedPet.customServices.length > 0 ? selectedPet.customServices : JSON.parse(this.customServicesStr)
  485. this.getCurrentDayPrice(this.currentMonthDay.fullDate)
  486. },
  487. isDateSelected(day) {
  488. const selectedDay = this.selectedDates.find(item => item.fullDate === day.fullDate && this.currentPetId ===
  489. item.petId)
  490. if (selectedDay) {
  491. return true
  492. }
  493. return false
  494. },
  495. isCurrentSelected(day) {
  496. return this.currentMonthDay.fullDate === day.fullDate && this.currentPetId === day.petId
  497. },
  498. updateGroupedDates() {
  499. const currentPet = this.currentPets.find(pet => pet.id === this.currentPetId)
  500. if (!currentPet) return
  501. // 按月份分组日期
  502. const grouped = currentPet.selectedDate.reduce((acc, dateObj) => {
  503. const date = new Date(dateObj.date)
  504. const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`
  505. const monthLabel = `${date.getFullYear()}${date.getMonth() + 1}`
  506. if (!acc[monthKey]) {
  507. acc[monthKey] = {
  508. monthLabel,
  509. dates: []
  510. }
  511. }
  512. acc[monthKey].dates.push({
  513. petId: currentPet.id,
  514. date: date.getDate(),
  515. fullDate: dateObj.date
  516. })
  517. return acc
  518. }, {})
  519. // 转换为数组并排序
  520. this.groupedDates = Object.values(grouped).sort((a, b) => {
  521. return a.monthLabel.localeCompare(b.monthLabel)
  522. })
  523. },
  524. selectTimeSlot(slotId) {
  525. const slot = this.timeSlots.find(slot => slot.id === slotId)
  526. if (slot) {
  527. slot.selected = !slot.selected
  528. }
  529. // 将期望时间添加到当前宠物
  530. const selectedTimeSlots = this.timeSlots.filter(slot => slot.selected)
  531. if (this.isAllSame) {
  532. // 如果保持一致,则更新该宠物所有期望时间
  533. this.newOrderData.pets.forEach(pet => {
  534. pet.selectedTimeSlots = selectedTimeSlots.map(item => item.id)
  535. })
  536. } else {
  537. const currentPetIndex = this.newOrderData.pets.findIndex(pet => pet.petId === this.currentPetId
  538. && pet.serviceDate === this.currentMonthDay.fullDate)
  539. if (currentPetIndex !== -1) {
  540. this.newOrderData.pets[currentPetIndex].selectedTimeSlots = selectedTimeSlots.map(item => item.id)
  541. }
  542. }
  543. },
  544. feedCountChange(e) {
  545. this.feedCount = e.value
  546. if (this.isAllSame) {
  547. // 如果保持一致,则更新该宠物的喂食次数
  548. this.newOrderData.pets.forEach(pet => {
  549. if (pet.petId === this.currentPetId) {
  550. pet.feedCount = this.feedCount
  551. }
  552. })
  553. } else {
  554. const pets = this.newOrderData.pets
  555. const currentPetIndex = pets.findIndex(pet => pet.petId === this.currentPetId && pet.serviceDate ===
  556. this.currentMonthDay.fullDate)
  557. if (currentPetIndex !== -1) {
  558. this.newOrderData.pets[currentPetIndex].feedCount = this.feedCount
  559. }
  560. }
  561. this.calculateTotalPrice()
  562. },
  563. customServiceCountChange(val) {
  564. console.log(val)
  565. this.customServices.forEach(item => {
  566. if (item.name === val.name) {
  567. item.quantity = val.value
  568. }
  569. })
  570. if (this.isAllSame) {
  571. // 如果保持一致,则更新当前宠物的定制服务次数
  572. this.newOrderData.pets.forEach(pet => {
  573. if (pet.petId === this.currentPetId) {
  574. pet.customServices = JSON.parse(JSON.stringify(this.customServices))
  575. }
  576. })
  577. } else {
  578. const pets = this.newOrderData.pets
  579. const currentPetIndex = pets.findIndex(pet => pet.petId === this.currentPetId && pet.serviceDate ===
  580. this.currentMonthDay.fullDate)
  581. if (currentPetIndex !== -1) {
  582. this.newOrderData.pets[currentPetIndex].customServices = JSON.parse(JSON.stringify(this
  583. .customServices))
  584. }
  585. }
  586. this.calculateTotalPrice()
  587. },
  588. togglePriceDetails() {
  589. this.showPriceDetails = !this.showPriceDetails; // 切换价格明细的显示状态
  590. if (this.showPriceDetails) {
  591. this.priceDetailDate()
  592. }
  593. },
  594. calculateTotalPrice() {
  595. // 1. 订单维度:是否需要提前熟悉
  596. if (this.$globalData.newOrderData.needPreFamiliarize && this.$globalData.newOrderData.needPreFamiliarize.length > 0) {
  597. this.needPreFamiliarizeCost = 40
  598. } else {
  599. this.needPreFamiliarizeCost = 0
  600. }
  601. // 2. 日期维度
  602. // 2.1 基础服务费用
  603. const uniqueDates = new Set(this.newOrderData.pets.map(item => item.serviceDate)); // 去重日期
  604. this.baseServiceTotalCost = uniqueDates.size * this.basePrice; // 每个唯一日期75元
  605. // 2.2 额外宠物费用
  606. // petType为dog 且bodyType包含 '大型' 则为大型犬,40元/次
  607. // petType为dog 且bodyType包含 '中型' 则为中型犬,30元/次
  608. // petType为dog 且bodyType包含 '小型' 则为小型犬,15元/次
  609. // petType为cat 则为猫,10元/次
  610. this.newOrderData.pets.forEach(pet => {
  611. if (pet.petType === 'dog' && pet.bodyType.includes('大型')) {
  612. pet.additionalCost = 40
  613. } else if (pet.petType === 'dog' && pet.bodyType.includes('中型')) {
  614. pet.additionalCost = 30
  615. } else if (pet.petType === 'dog' && pet.bodyType.includes('小型')) {
  616. pet.additionalCost = 15
  617. } else if (pet.petType === 'cat') {
  618. pet.additionalCost = 10
  619. }
  620. })
  621. // const largeDogArray = this.newOrderData.pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('大型'));
  622. // this.additionalTotalCost = this.additionalTotalCost + (largeDogArray.length * 40)
  623. // // 非大型犬
  624. // const otherPets = this.newOrderData.pets.filter(pet => pet.petType !== 'dog' && !pet.bodyType.includes('大型'));
  625. // 宠物日期分组
  626. const dailyPets = [];
  627. // 按日期分组宠物
  628. this.newOrderData.pets.forEach(pet => {
  629. const serviceDate = pet.serviceDate;
  630. if (!dailyPets[serviceDate]) {
  631. dailyPets[serviceDate] = [];
  632. }
  633. dailyPets[serviceDate].push(pet);
  634. });
  635. const petTypeCounts = []
  636. let additionalTotalCost = 0
  637. // 计算每日额外宠物费用
  638. for (const date in dailyPets) {
  639. const pets = dailyPets[date];
  640. const largeDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('大型')).length;
  641. let mediumDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('中型')).length;
  642. let smallDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('小型')).length;
  643. let catCount = pets.filter(pet => pet.petType === 'cat').length;
  644. let additionalCost = 0
  645. // 总宠物费用
  646. let totalPetCost = pets.reduce((acc, pet) => {
  647. return acc + this.calculatePetCost(pet);
  648. }, 0);
  649. // 如果总宠物费用>30
  650. if (totalPetCost > 30) {
  651. // 如果猫数量>=3
  652. if (catCount >= 3) {
  653. additionalCost = totalPetCost - 30
  654. catCount = catCount - 3
  655. } else if (smallDogCount >= 2) {
  656. additionalCost = totalPetCost - 30
  657. smallDogCount = smallDogCount - 2
  658. } else if (mediumDogCount >= 1) {
  659. additionalCost = totalPetCost - 30
  660. mediumDogCount = mediumDogCount - 1
  661. } else {
  662. additionalCost = totalPetCost - 25
  663. catCount = catCount - 1
  664. smallDogCount = smallDogCount - 1
  665. }
  666. petTypeCounts.push({
  667. date,
  668. largeDogCount,
  669. mediumDogCount,
  670. smallDogCount,
  671. catCount
  672. })
  673. }
  674. // 如果有大型犬,额外费用为40元/只
  675. if (largeDogCount > 0) {
  676. additionalCost += (40 * largeDogCount)
  677. }
  678. // 如果有额外费用,添加到总额外费用
  679. if (additionalCost > 0) {
  680. additionalTotalCost += additionalCost;
  681. }
  682. }
  683. this.additionalTotalCost = additionalTotalCost
  684. this.petTypeCounts = petTypeCounts
  685. // 2.3 当日多次服务总价
  686. // 计算每日多次服务次数费用
  687. let multServicesTotalCost = 0
  688. let oneDayTwoTimesDates = []
  689. let oneDayThreeTimesDates = []
  690. for (const date in dailyPets) {
  691. const maxFeedCount = Math.max(...dailyPets[date].map(pet => pet.feedCount));
  692. if (maxFeedCount === 2) {
  693. multServicesTotalCost += 45; // 1天2次
  694. oneDayTwoTimesDates.push(date)
  695. } else if (maxFeedCount === 3) {
  696. multServicesTotalCost += 130; // 1天3次
  697. oneDayThreeTimesDates.push(date)
  698. }
  699. }
  700. this.oneDayTwoTimesDates = oneDayTwoTimesDates
  701. this.oneDayThreeTimesDates = oneDayThreeTimesDates
  702. this.multServicesTotalCost = multServicesTotalCost
  703. // 3. 定制服务
  704. //定制服务单项总次数统计
  705. const customServiceItemCount = JSON.parse(this.customServicesStr)
  706. let customServicesTotalCost = 0
  707. this.newOrderData.pets.forEach(pet => {
  708. const customServices = pet.customServices
  709. // 定制服务费用
  710. customServices.forEach(service => {
  711. const itemIndex = customServiceItemCount.findIndex(item => item.name === service.name)
  712. if (itemIndex !== -1) {
  713. customServiceItemCount[itemIndex].quantity += service.quantity
  714. }
  715. customServicesTotalCost += service.price * service.quantity;
  716. })
  717. });
  718. this.customServiceItemCount = customServiceItemCount
  719. this.customServicesTotalCost = customServicesTotalCost
  720. this.totalPrice = this.needPreFamiliarizeCost
  721. + this.baseServiceTotalCost
  722. + this.additionalTotalCost
  723. + this.multServicesTotalCost
  724. + this.customServicesTotalCost; // 更新总价
  725. this.getCurrentDayPrice(this.currentMonthDay.fullDate)
  726. },
  727. calculatePetCost(pet) {
  728. // 宠物额外费用 不计算大型犬
  729. let petCost = 0;
  730. if (pet.petType === 'cat') {
  731. petCost += 10; // 猫额外费用
  732. } else if (pet.petType === 'dog' && pet.bodyType.includes('小型')) {
  733. petCost += 15; // 小型犬额外费用
  734. } else if (pet.petType === 'dog' && pet.bodyType.includes('中型')) {
  735. petCost += 30; // 中型犬额外费用
  736. }
  737. return petCost;
  738. },
  739. goNext() {
  740. this.calculateTotalPrice(); // 计算总价
  741. this.showPriceDetails = false;
  742. this.$globalData.newOrderData.currentPetsByDay = this.newOrderData.pets
  743. this.$globalData.newOrderData.totalPrice = this.totalPrice
  744. uni.navigateTo({
  745. url: '/pages/newOrder/confirmOrder'
  746. });
  747. },
  748. goBack() {
  749. this.showPriceDetails = false
  750. let len = getCurrentPages().length;
  751. this.loading = false
  752. if (len >= 2) {
  753. uni.navigateBack();
  754. } else {
  755. uni.redirectTo({
  756. url: '/pages/newOrder/serviceNew'
  757. });
  758. }
  759. },
  760. // 价格明细数据
  761. priceDetailDate() {
  762. const priceDetails = []
  763. if (this.newOrderData.needPreFamiliarize) {
  764. priceDetails.push({
  765. name: '提前熟悉',
  766. item: [{
  767. itemName: '提前熟悉',
  768. price: 40,
  769. quantity: this.newOrderData.needPreFamiliarize ? 1 : 0,
  770. unit: '次'
  771. },]
  772. })
  773. }
  774. const uniqueDateCount = new Set(this.newOrderData.pets.map(item => item.serviceDate)).size; // 去重日期
  775. if (uniqueDateCount > 1) {
  776. priceDetails.push({
  777. name: this.baseProduct, item: [
  778. { itemName: this.baseProduct, price: this.basePrice, quantity: uniqueDateCount, unit: '天' },
  779. ]
  780. })
  781. }
  782. if (this.oneDayTwoTimesDates.length > 0 || this.oneDayThreeTimesDates.length > 0) {
  783. priceDetails.push({
  784. name: '上门次数',
  785. item: [{
  786. itemName: '1天2次',
  787. price: 45,
  788. quantity: this.oneDayTwoTimesDates.length,
  789. unit: '天'
  790. },
  791. {
  792. itemName: '1天3次',
  793. price: 130,
  794. quantity: this.oneDayThreeTimesDates.length,
  795. unit: '天'
  796. },
  797. ]
  798. })
  799. }
  800. // 过滤宠物类型数量>0的数组
  801. const additionalCostItem = []
  802. const petTypeArr = this.petTypeCounts.filter(item => item.largeDogCount > 0 || item.mediumDogCount > 0 ||
  803. item.smallDogCount > 0 || item.catCount > 0)
  804. // 假设largeDogCount=1 mediumDogCount=2 smallDogCount=3 catCount=4 则生成4条数据
  805. petTypeArr.forEach(item => {
  806. if (item.largeDogCount > 0) {
  807. additionalCostItem.push({
  808. itemName: '大型犬',
  809. price: 40,
  810. quantity: item.largeDogCount,
  811. unit: '只',
  812. date: item.date
  813. })
  814. }
  815. if (item.mediumDogCount > 0) {
  816. additionalCostItem.push({
  817. itemName: '中型犬',
  818. price: 30,
  819. quantity: item.mediumDogCount,
  820. unit: '只',
  821. date: item.date
  822. })
  823. }
  824. if (item.smallDogCount > 0) {
  825. additionalCostItem.push({
  826. itemName: '小型犬',
  827. price: 15,
  828. quantity: item.smallDogCount,
  829. unit: '只',
  830. date: item.date
  831. })
  832. }
  833. if (item.catCount > 0) {
  834. additionalCostItem.push({
  835. itemName: '猫猫',
  836. price: 10,
  837. quantity: item.catCount,
  838. unit: '只',
  839. date: item.date
  840. })
  841. }
  842. })
  843. // 按日期先后顺序排序
  844. additionalCostItem.sort((a, b) => new Date(a.date) - new Date(b.date))
  845. if (additionalCostItem.length > 0) {
  846. priceDetails.push({
  847. name: '额外宠物费用',
  848. item: additionalCostItem
  849. })
  850. }
  851. const customServiceItem = this.customServiceItemCount.filter(item => item.quantity > 0).map(service => {
  852. return { itemName: service.name, price: service.price, quantity: service.quantity, unit: '次' }
  853. })
  854. if (customServiceItem.length > 0) {
  855. priceDetails.push({
  856. name: '定制服务',
  857. item: customServiceItem
  858. })
  859. }
  860. this.priceDetails = priceDetails
  861. this.calculateTotalPrice()
  862. },
  863. showName(item) {
  864. return item.item.some(item2 => item2.quantity > 0)
  865. },
  866. isAllSameChange(e) {
  867. if (e) {
  868. this.isAllSame = true
  869. this.setCurrentPetIsAllSame()
  870. // 当前宠物全日期保持一致
  871. this.newOrderData.pets.forEach(pet => {
  872. if (pet.petId === this.currentPetId) {
  873. pet.selectedTimeSlots = this.timeSlots.filter(slot => slot.selected).map(item => item.id)
  874. pet.feedCount = this.feedCount
  875. pet.customServices = this.customServices
  876. }
  877. })
  878. this.calculateTotalPrice()
  879. } else {
  880. this.isAllSame = false
  881. this.setCurrentPetIsAllSame()
  882. }
  883. },
  884. getProductList() {
  885. getProductList({
  886. "publishStatus": 1,
  887. "categoryId": 78,
  888. "needSku": true
  889. }).then(response => {
  890. if (response && response.content && response.content.length > 0) {
  891. this.customServices = response.content.map(item => {
  892. const skus = item.skus
  893. if (skus && skus.length > 0) {
  894. let productSku = {
  895. "skuId": skus[0].id,
  896. "price": skus[0].price,
  897. "name": item.name,
  898. "quantity": 0,
  899. "isMainProduct": false
  900. }
  901. return productSku
  902. }
  903. })
  904. this.customServicesStr = JSON.stringify(this.customServices)
  905. // 初始化新订单数据
  906. this.initNewOrderData()
  907. } else {
  908. uni.showToast('获取主产品失败,请联系管理员')
  909. }
  910. console.log(response);
  911. })
  912. },
  913. login() {
  914. uni.login({
  915. provider: 'weixin',
  916. success: (loginRes) => {
  917. this.getOpenId(loginRes.code)
  918. },
  919. fail: function (error) {
  920. // 授权失败处理
  921. uni.showToast('授权失败,请授权后再试')
  922. }
  923. });
  924. },
  925. getOpenId(code) {
  926. getOpenId(code).then(res => {
  927. if (res.code == 200 && res.data) {
  928. let resData = JSON.parse(res.data)
  929. let token = resData.token;
  930. let openId = resData.openId;
  931. setOpenIdKey(openId)
  932. if (token) {
  933. setToken(token)
  934. }
  935. }
  936. })
  937. },
  938. getCurrentDayPrice(currentDay) {
  939. const currentDayPets = this.newOrderData.pets.filter(pet => pet.serviceDate === currentDay)
  940. // 基础服务
  941. const baseServiceCost = this.basePrice
  942. const largeDogCount = currentDayPets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('大型')).length;
  943. let mediumDogCount = currentDayPets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('中型')).length;
  944. let smallDogCount = currentDayPets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('小型')).length;
  945. let catCount = currentDayPets.filter(pet => pet.petType === 'cat').length;
  946. const additionalCostItem = []
  947. let additionalCost = 0
  948. // 单天总宠物费用
  949. let totalPetCost = currentDayPets.reduce((acc, pet) => {
  950. return acc + this.calculatePetCost(pet);
  951. }, 0);
  952. // 如果总宠物费用>30
  953. if (totalPetCost > 30) {
  954. // 如果猫数量>=3,则免3只猫
  955. if (catCount >= 3) {
  956. additionalCost = totalPetCost - 30
  957. catCount = catCount - 3
  958. } else if (smallDogCount >= 2) { // 如果小型犬数量>=2,则免2只小型犬
  959. additionalCost = totalPetCost - 30
  960. smallDogCount = smallDogCount - 2
  961. } else if (mediumDogCount >= 1) { // 如果中型犬数量>=1,则免1只中型犬
  962. additionalCost = totalPetCost - 30
  963. mediumDogCount = mediumDogCount - 1
  964. } else {
  965. additionalCost = totalPetCost - 25
  966. catCount = catCount - 1
  967. smallDogCount = smallDogCount - 1
  968. }
  969. if (largeDogCount > 0) {
  970. additionalCostItem.push({ itemName: '大型犬', price: 40, quantity: largeDogCount, unit: '只' })
  971. }
  972. if (mediumDogCount > 0) {
  973. additionalCostItem.push({ itemName: '中型犬', price: 30, quantity: mediumDogCount, unit: '只' })
  974. }
  975. if (smallDogCount > 0) {
  976. additionalCostItem.push({ itemName: '小型犬', price: 15, quantity: smallDogCount, unit: '只' })
  977. }
  978. if (catCount > 0) {
  979. additionalCostItem.push({ itemName: '猫猫', price: 10, quantity: catCount, unit: '只' })
  980. }
  981. }
  982. // 如果有大型犬,额外费用为40元/只
  983. if (largeDogCount > 0) {
  984. additionalCost += (40 * largeDogCount)
  985. }
  986. // 当日多次服务次数
  987. let multServicesTotalCost = 0
  988. const maxFeedCount = Math.max(...currentDayPets.map(pet => pet.feedCount));
  989. if (maxFeedCount === 2) {
  990. multServicesTotalCost += 45; // 1天2次
  991. } else if (maxFeedCount === 3) {
  992. multServicesTotalCost += 130; // 1天3次
  993. }
  994. // 所有宠物定制服务费用
  995. const customServiceCost = currentDayPets.reduce((acc, pet) => acc + this.calculatePetCustomServiceCost(pet), 0)
  996. const totalCost = baseServiceCost + additionalCost + multServicesTotalCost + customServiceCost
  997. this.currentDayPrice = totalCost
  998. },
  999. calculatePetCustomServiceCost(pet) {
  1000. const customServiceCost = pet.customServices.reduce((acc, item) => acc + item.price * item.quantity, 0)
  1001. return customServiceCost
  1002. },
  1003. getCurrentPetName() {
  1004. const currentPet = this.currentPets.find(pet => pet.id === this.currentPetId)
  1005. return currentPet.name
  1006. },
  1007. setCurrentPetIsAllSame() {
  1008. const currentPet = this.currentPets.find(pet => pet.id === this.currentPetId)
  1009. currentPet.isAllSame = this.isAllSame
  1010. },
  1011. getCurrentPetIsAllSame() {
  1012. const currentPet = this.currentPets.find(pet => pet.id === this.currentPetId)
  1013. this.isAllSame = currentPet.isAllSame
  1014. },
  1015. },
  1016. computed: {
  1017. sortedGroupedDates() {
  1018. return this.groupedDates.sort((a, b) => {
  1019. const dateA = new Date(a.monthLabel.replace('年', '-').replace('月', '-01'))
  1020. const dateB = new Date(b.monthLabel.replace('年', '-').replace('月', '-01'))
  1021. return dateA - dateB
  1022. })
  1023. }
  1024. }
  1025. }
  1026. </script>
  1027. <style scoped lang="less">
  1028. .container {
  1029. position: relative;
  1030. height: 100%;
  1031. padding-bottom: 160rpx;
  1032. .details-subscribe {
  1033. background-color: #FFFFFF;
  1034. padding: 10px;
  1035. width: 100%;
  1036. height: 160rpx;
  1037. position: fixed;
  1038. bottom: 0;
  1039. z-index: 100;
  1040. .details-btn {
  1041. width: 100%;
  1042. border-radius: 6px;
  1043. background: #FFB13F;
  1044. font-size: 16px;
  1045. color: #FFFFFF;
  1046. }
  1047. }
  1048. }
  1049. .service-new {
  1050. .service-new-flag {
  1051. width: 8rpx;
  1052. height: 32rpx;
  1053. background: #FFBF60;
  1054. border-radius: 30rpx 30rpx 30rpx 30rpx;
  1055. margin-right: 10rpx;
  1056. }
  1057. .split-line {
  1058. width: 100%;
  1059. height: 1rpx;
  1060. background: #EFEFEF;
  1061. }
  1062. .service-new-title {
  1063. display: flex;
  1064. font-weight: 500;
  1065. font-size: 28rpx;
  1066. color: #333333;
  1067. line-height: 33rpx;
  1068. margin: 42rpx 0 30rpx;
  1069. justify-content: space-between;
  1070. .service-new-title-left {
  1071. display: flex;
  1072. align-items: center;
  1073. }
  1074. }
  1075. .service-new-pet-content {
  1076. padding: 20rpx 0;
  1077. }
  1078. .service-new-pet-item {
  1079. height: 96rpx;
  1080. width: 184rpx;
  1081. border-radius: 8rpx;
  1082. padding: 0 20rpx;
  1083. margin-right: 40rpx;
  1084. display: flex;
  1085. align-items: center;
  1086. justify-content: center;
  1087. font-size: 28rpx;
  1088. flex-shrink: 0;
  1089. }
  1090. .scroll-content {
  1091. display: inline-flex;
  1092. }
  1093. .scroll-view {
  1094. width: 100%;
  1095. white-space: nowrap;
  1096. }
  1097. .pet-selected {
  1098. background: #FFBF60;
  1099. color: #FFFFFF;
  1100. }
  1101. .pet-unselect {
  1102. background: #F5F5F7;
  1103. color: #7D8196;
  1104. }
  1105. }
  1106. .calendar-wrapper {
  1107. display: flex;
  1108. gap: 20rpx;
  1109. padding: 20rpx;
  1110. }
  1111. .scroll-view {
  1112. width: 100%;
  1113. white-space: nowrap;
  1114. }
  1115. .calendar-day {
  1116. position: relative;
  1117. width: 80rpx;
  1118. height: 80rpx;
  1119. display: flex;
  1120. align-items: center;
  1121. justify-content: center;
  1122. cursor: pointer;
  1123. margin-right: 20rpx;
  1124. flex-shrink: 0;
  1125. }
  1126. .calendar-bg {
  1127. position: absolute;
  1128. width: 88rpx;
  1129. height: 78rpx;
  1130. z-index: 1;
  1131. }
  1132. .day-text {
  1133. position: relative;
  1134. z-index: 2;
  1135. top: 5rpx;
  1136. }
  1137. .day-highlighted {
  1138. font-size: 38rpx;
  1139. font-weight: bold;
  1140. color: #FFBF60;
  1141. }
  1142. .day-normal {
  1143. color: #3E3A39;
  1144. font-size: 32rpx;
  1145. }
  1146. .month-group {
  1147. margin-bottom: 30rpx;
  1148. .month-title {
  1149. font-size: 32rpx;
  1150. color: #666;
  1151. margin-bottom: 20rpx;
  1152. }
  1153. .dates-wrapper {
  1154. display: inline-flex;
  1155. }
  1156. }
  1157. .scroll-view-vertical {
  1158. height: 100%;
  1159. }
  1160. .scroll-view-horizontal {
  1161. width: 100%;
  1162. white-space: nowrap;
  1163. }
  1164. .time-slots {
  1165. display: flex;
  1166. justify-content: space-around;
  1167. }
  1168. .time-slot-item {
  1169. display: flex;
  1170. flex-direction: column;
  1171. align-items: center;
  1172. width: 200rpx;
  1173. cursor: pointer;
  1174. }
  1175. .time-slot-icon {
  1176. width: 160rpx;
  1177. height: 160rpx;
  1178. margin-bottom: 10rpx;
  1179. }
  1180. .time-slot-info {
  1181. display: flex;
  1182. flex-direction: column;
  1183. align-items: center;
  1184. }
  1185. .time-slot-name {
  1186. font-size: 28rpx;
  1187. color: #333;
  1188. margin-bottom: 8rpx;
  1189. }
  1190. .time-slot-time {
  1191. font-size: 24rpx;
  1192. color: #666;
  1193. }
  1194. .time-slot-time-tip {
  1195. background-color: #FFECCD;
  1196. color: #A94F20;
  1197. margin-left: 10rpx;
  1198. padding: 5rpx 10rpx;
  1199. font-size: 20rpx;
  1200. }
  1201. .service-item {
  1202. margin-bottom: 20rpx;
  1203. /* 每个服务项之间的间距 */
  1204. }
  1205. .service-item-header {
  1206. display: flex;
  1207. align-items: center;
  1208. margin-bottom: 10rpx;
  1209. /* 标题与服务列表之间的间距 */
  1210. }
  1211. .service-icon {
  1212. width: 40rpx;
  1213. /* 图标大小 */
  1214. height: 40rpx;
  1215. /* 图标大小 */
  1216. margin-right: 10rpx;
  1217. /* 图标与标题之间的间距 */
  1218. }
  1219. .service-title {
  1220. font-size: 28rpx;
  1221. /* 服务标题字体大小 */
  1222. font-weight: bold;
  1223. /* 服务标题加粗 */
  1224. }
  1225. .service-row {
  1226. display: flex;
  1227. align-items: center;
  1228. /* 垂直居中对齐 */
  1229. flex-wrap: wrap;
  1230. background-color: #F9F9F9;
  1231. }
  1232. .service-row-content {
  1233. display: flex;
  1234. justify-content: space-between;
  1235. /* 每行的上下内边距 */
  1236. width: 100%;
  1237. padding: 32rpx 0rpx;
  1238. margin: 0 20rpx;
  1239. }
  1240. .service-name {
  1241. width: 50%;
  1242. white-space: nowrap;
  1243. overflow: hidden;
  1244. text-overflow: ellipsis;
  1245. font-size: 28rpx;
  1246. color: #333;
  1247. /* 服务名称颜色 */
  1248. }
  1249. .service-price {
  1250. display: flex;
  1251. align-items: center;
  1252. /* 垂直居中对齐 */
  1253. }
  1254. .service-count {
  1255. display: flex;
  1256. align-items: center;
  1257. /* 垂直居中对齐 */
  1258. margin-left: 10rpx;
  1259. /* 价格数量之间的间距 */
  1260. }
  1261. .price-details {
  1262. position: fixed;
  1263. /* 固定位置 */
  1264. bottom: 160rpx;
  1265. /* 根据需要调整位置 */
  1266. left: 0;
  1267. right: 0;
  1268. background: #FFF;
  1269. /* 背景颜色 */
  1270. padding: 10px 10px 0 10px;
  1271. /* 内边距 */
  1272. border-radius: 8rpx 8rpx 0 0;
  1273. /* 圆角 */
  1274. z-index: 1000;
  1275. /* 确保在其他元素之上 */
  1276. min-height: 600rpx;
  1277. /* 固定高度 */
  1278. overflow: hidden;
  1279. /* 隐藏超出部分 */
  1280. }
  1281. .price-details-header {
  1282. display: flex;
  1283. justify-content: space-between;
  1284. align-items: center;
  1285. }
  1286. .price-details-body {
  1287. margin-top: 10px;
  1288. max-height: 300rpx;
  1289. /* 留出头部空间 */
  1290. overflow-y: auto;
  1291. /* 允许上下滚动 */
  1292. }
  1293. .price-details-overlay {
  1294. position: fixed;
  1295. /* 固定位置 */
  1296. top: 0;
  1297. left: 0;
  1298. right: 0;
  1299. bottom: 0;
  1300. background: rgba(0, 0, 0, 0.5);
  1301. /* 半透明背景 */
  1302. z-index: 999;
  1303. /* 确保在其他元素之上 */
  1304. display: flex;
  1305. justify-content: center;
  1306. align-items: center;
  1307. }
  1308. .price-details-item {
  1309. display: flex;
  1310. justify-content: space-between;
  1311. margin-bottom: 20rpx;
  1312. .price-details-item-price-total {
  1313. display: flex;
  1314. width: 70%;
  1315. justify-content: flex-end;
  1316. flex-wrap: wrap;
  1317. }
  1318. .price-details-item-price-total-item {
  1319. color: #999999;
  1320. text-align: right;
  1321. font-size: 28rpx;
  1322. margin-right: 20rpx;
  1323. }
  1324. }
  1325. </style>