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.

1459 lines
47 KiB

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