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.

1412 lines
48 KiB

7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
2 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
2 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
2 months ago
2 months ago
2 months ago
7 months ago
7 months ago
7 months ago
2 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
2 months ago
7 months ago
7 months ago
7 months ago
2 months ago
2 months ago
2 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
  1. <template>
  2. <view class="service-new container">
  3. <view class="service-new-address">
  4. <uni-card padding=0 :is-shadow="false">
  5. <view class="service-new-title" slot="title">
  6. <view class="service-new-title-left">
  7. <view class="service-new-flag"></view>
  8. <view>服务地址</view>
  9. </view>
  10. </view>
  11. <view class="split-line"></view>
  12. <view class="service-new-address-content">
  13. <view class="service-new-address-selected">
  14. <view class="personal-address-info">
  15. <view class="personal-address-text">
  16. {{currentAddress.province}} {{currentAddress.city}} {{currentAddress.detailAddress}}
  17. </view>
  18. <view class="personal-address-people">
  19. <view>
  20. {{currentAddress.name}}
  21. </view>
  22. <view style="border: solid #7D8196 1px; margin: 0 10px; height: 12px;"> </view>
  23. <view>
  24. {{currentAddress.phone}}
  25. </view>
  26. </view>
  27. </view>
  28. </view>
  29. </view>
  30. </uni-card>
  31. </view>
  32. <view class="service-new-pet">
  33. <uni-card padding=0 :is-shadow="false">
  34. <view class="service-new-title" slot="title">
  35. <view class="service-new-title-left">
  36. <view class="service-new-flag">
  37. </view>
  38. <view class="service-new-title-text">
  39. 服务宠物
  40. </view>
  41. </view>
  42. </view>
  43. <view class="split-line"></view>
  44. <view class="service-new-pet-content">
  45. <view class="personal-pet-list">
  46. <view v-for="(item,index) in showPets" :key="index">
  47. <view class="personal-pet-list-item">
  48. <view class="personal-pet-info">
  49. <!-- 左侧头像 -->
  50. <view class="pet-avatar">
  51. <u-avatar :src="item.photo?item.photo:defaultPhoto" size="60"
  52. shape="circle"></u-avatar>
  53. </view>
  54. <!-- 中间内容 -->
  55. <view class="pet-info" style="flex: 1; margin: 0 20rpx; max-width: 50%;">
  56. <view class="pet-name-gender" style="display: flex; align-items: center;">
  57. <view>{{item.name}}</view>
  58. <view class="pet-gender"
  59. style="margin-left: 10rpx; display: flex;align-items: center;">
  60. <img :src="item.gender=='男生'?'../../static/images/details/boy.svg':'../../static/images/details/girl.svg'"
  61. alt="sex" style="width: 16px;height: 16px;" />
  62. </view>
  63. </view>
  64. <view class="pet-dates ellipsis">
  65. {{ item.pets.map(e=>e.serviceDate).join(';') }}
  66. </view>
  67. </view>
  68. <!-- 右侧天数统计 -->
  69. <view class="date-total" style="margin-left: auto;width: 140rpx;text-align: end;">
  70. {{item.pets.length}}
  71. </view>
  72. </view>
  73. </view>
  74. </view>
  75. </view>
  76. </view>
  77. </uni-card>
  78. </view>
  79. <view class="service-new-pet">
  80. <uni-card padding=0 :is-shadow="false">
  81. <view class="service-new-title" slot="title">
  82. <view class="service-new-title-left">
  83. <view class="service-new-flag">
  84. </view>
  85. <view class="service-new-title-text">
  86. 服务信息及费用
  87. </view>
  88. </view>
  89. </view>
  90. <view class="split-line"></view>
  91. <view class="service-new-pet-content">
  92. <view class="personal-pet-list">
  93. <view v-for="item in dailyShowData" :key="item.date" class="service-new-address">
  94. <view class="service-summary">
  95. <view style="display: flex; align-items: center;">
  96. <view style="padding-right: 10rpx;color: #7D8196;">{{ getDateText(item.date) }}</view>
  97. <!-- <view style="padding-right: 10rpx;color: #7D8196;">{{ item.date }}</view> -->
  98. <view
  99. style="margin: 0 10rpx; width: 2px; height: 20rpx; background-color: #7D8196;">
  100. </view>
  101. <view style="color: #333333; margin-left: 10rpx;">{{baseProduct}}
  102. {{item.customServicesTotalCnt? ' + 定制服务' + item.customServicesTotalCnt + '项' : '' }}
  103. </view>
  104. </view>
  105. <view style="display: flex; align-items: center;">
  106. <view style="color: #333333;margin-right: 10rpx;">¥{{ item.totalCost }}</view>
  107. <view>
  108. <u-icon @click="toggleExpand( item.date )"
  109. :name="expandedIndexs.includes( item.date ) ? 'arrow-up' : 'arrow-down'"
  110. color="#FFBF60" size="14"></u-icon>
  111. </view>
  112. </view>
  113. </view>
  114. <view v-if="!expandedIndexs.includes(item.date)" class="split-line"></view>
  115. <view v-show="expandedIndexs.includes(item.date)" class="service-details">
  116. <!-- 基础服务 上门次数 额外费用 -->
  117. <view>基础服务</view>
  118. <view v-for="(priceItem, priceIndex) in item.priceDetails" :key="priceIndex"
  119. class="price-details-item">
  120. <view style="display: flex;" v-for="(item2, index) in priceItem.item" :key="index">
  121. <view v-if="item2.quantity" class="service-item">
  122. <view v-if="item2.itemName != item.name"
  123. class="price-details-item-price-total-item">- {{ item2.itemName }}
  124. </view>
  125. <view class="price-details-item-price-total-item">¥{{ parseFloat(item2.price) }} ×
  126. {{ item2.quantity }} {{ item2.unit }}</view>
  127. </view>
  128. </view>
  129. </view>
  130. <view v-if="item.customServicesTotalCnt>0" style="margin-top: 20rpx;">定制服务</view>
  131. <view v-for="(pet, petIndex) in item.pets" :key="petIndex">
  132. <view
  133. v-if="pet.customServices &&pet.customServices.filter(e=>e.quantity>0).length>0"
  134. style="display: flex; align-items: center; justify-content: flex-start; margin-top: 20rpx;">
  135. <view class="pet-avatar">
  136. <u-avatar :src="pet.photo?pet.photo:defaultPhoto" size="34"
  137. shape="circle"></u-avatar>
  138. </view>
  139. <view style="margin-left: 20rpx;">{{ pet.name}}</view>
  140. </view>
  141. <!-- 定制服务 -->
  142. <view v-for="(customItem, customIndex) in pet.customServices" :key="customIndex">
  143. <view v-if="customItem.quantity" class="service-item">
  144. <view>- {{ customItem.name }}</view>
  145. <view>¥{{ parseFloat(customItem.price).toFixed(2) }} × {{ customItem.quantity }} </view>
  146. </view>
  147. </view>
  148. </view>
  149. </view>
  150. </view>
  151. <view class="service-new-address">
  152. <view v-if="needPreFamiliarize.length>0" class="total-cost">
  153. <view>提前熟悉 </view>
  154. <view>¥{{ (price_config && price_config.preFamiliarize && price_config.preFamiliarize.price) || 40 }}</view>
  155. </view>
  156. <!-- 伴宠师价格已合并到基础服务价格中不再单独显示 -->
  157. <view class="total-cost">
  158. <view>费用总计 </view>
  159. <view>¥{{ parseFloat(originalTotalPrice).toFixed(2) }}</view>
  160. </view>
  161. <view class="total-cost" @click="selectCoupon">
  162. <view>平台优惠</view>
  163. <view style="color: #FF530A;">
  164. {{ selectedCoupon ? selectedCoupon.stockName : '未使用优惠券' }}
  165. <uni-icons type="right" size="28rpx" color="#AAA"></uni-icons>
  166. </view>
  167. </view>
  168. <view class="total-cost" v-if="discountMemberText">
  169. <view>会员折扣</view>
  170. <view style="display: flex; align-items: center;">
  171. <view style="color: #999999;">{{ currentMember.itemType }}{{ discountMemberText }}折优惠</view>
  172. <view style="border: solid #7D8196 1px; margin: 0 10rpx; height: 12px;"> </view>
  173. <view style="color: #FF530A;">-¥{{ parseFloat(memberDiscount).toFixed(2) }}</view>
  174. </view>
  175. </view>
  176. <view class="total-cost" v-if="$globalData.newOrderData.moreOrderPrice && $globalData.newOrderData.moreOrderPrice > 0">
  177. <view>再来一单费用</view>
  178. <view style="color: #FF530A;">+¥{{ parseFloat($globalData.newOrderData.moreOrderPrice).toFixed(2) }}</view>
  179. </view>
  180. <view class="total-cost">
  181. <view>应付费用</view>
  182. <view style="font-weight: 500;font-size: 32rpx;">¥{{ parseFloat(finalPrice).toFixed(2) }}</view>
  183. </view>
  184. </view>
  185. </view>
  186. </view>
  187. </uni-card>
  188. </view>
  189. <view class="service-new-pet">
  190. <uni-card padding=0 :is-shadow="false">
  191. <view class="service-new-title" slot="title">
  192. <view class="service-new-title-left">
  193. <view class="service-new-flag">
  194. </view>
  195. <view class="service-new-title-text">
  196. 服务细则
  197. </view>
  198. </view>
  199. </view>
  200. <view class="split-line"></view>
  201. <view class="service-new-details-content">
  202. <view style="margin: 30rpx 0;">
  203. <u-checkbox-group @change="changePreFamiliarize" :value="needPreFamiliarize"
  204. iconPlacement="right" placement="column">
  205. <u-checkbox activeColor="#FFBF60" label="是否提前熟悉" name="是否提前熟悉" shape="circle"></u-checkbox>
  206. </u-checkbox-group>
  207. </view>
  208. <view class="split-line"></view>
  209. <view class="service-new-details-desc">
  210. <view style="display: flex;">
  211. <text style="width: 20rpx;">*</text>
  212. <text style="flex: 1;">价格{{ (price_config && price_config.preFamiliarize && price_config.preFamiliarize.price) || 40 }}/</text>
  213. </view>
  214. <view style="display: flex; margin: 20rpx 0;">
  215. <text style="width: 20rpx;">*</text>
  216. <text style="flex: 1;">服务内容: 购买此服务后伴宠师将在您离家前按照约定日期提前上门沟通熟悉喂养要求及宠物</text>
  217. </view>
  218. <view style="display: flex;">
  219. <text style="width: 20rpx;">*</text>
  220. <text style="flex: 1;">服务保障: 购买此服务后平台支持在提前熟悉后上门服务第一天前无理由免费更换伴宠师1次</text>
  221. </view>
  222. </view>
  223. </view>
  224. </uni-card>
  225. </view>
  226. <view class="details-subscribe">
  227. <view class="details-radio" style="width: 100%;padding-bottom: 20rpx;">
  228. <view>
  229. <u-checkbox-group v-model="isAgree" size="16" labelSize="14" labelColor="#999999">
  230. <u-checkbox activeColor="#FFBF60" label="我同意" name="我同意" labelSize="14" size="14"
  231. shape="circle"></u-checkbox>
  232. </u-checkbox-group>
  233. </view>
  234. <text style="color: #FFBF60;font-size: 28rpx;" @click="checkAgreement">猫妈狗爸用户服务协议和隐私协议</text>
  235. </view>
  236. <view style="display: flex;justify-content: space-between; align-items: center;">
  237. <view style="height: 80rpx; display: flex; align-items: center;">
  238. <text style="color: #333333;">订单总价: </text>
  239. <text style="color: #FF530A; font-size: 40rpx;">¥{{ parseFloat(finalPrice).toFixed(2) }} <text
  240. style="font-size: 32rpx;"></text></text>
  241. </view>
  242. <view style="display: flex;">
  243. <u-button color="#FFF4E4" customStyle="width: 200rpx; color: #FFAA48; margin-right: 20rpx;"
  244. text="上一步" @click="goBack"></u-button>
  245. <u-button color="#FFBF60" customStyle="width: 200rpx; color: #FFF;" text="支付"
  246. @click="goNext"></u-button>
  247. </view>
  248. </view>
  249. </view>
  250. <view v-if="showCoupon" class="calendar-popup">
  251. <view class="calendar-mask"></view>
  252. <view class="calendar-content">
  253. <view class="price-details">
  254. <view class="price-details-header">
  255. <text
  256. style="text-align: center; width: 100%; font-size: 32rpx; font-weight: 500; color: #333333;">优惠券</text>
  257. <u-icon name="close" @click="togglePriceDetails"></u-icon>
  258. </view>
  259. <view class="split-line"></view>
  260. <scroll-view class="price-details-body" scroll-y v-if="showCouponList">
  261. <view v-for="(item,index) in couponList" style="padding-bottom:14px;" :key="index">
  262. <view class="coupon-card" :class="{
  263. 'auto-selected': item.checked && item.checked.length > 0 && item.isAutoSelected,
  264. 'manual-selected': item.checked && item.checked.length > 0 && !item.isAutoSelected
  265. }">
  266. <view class="card-left"><text
  267. style="font-size: 40rpx; margin-left: 5rpx;">{{ getCouponAmountOrDiscount(item) }}</text>
  268. </view>
  269. <view class="card-right">
  270. <view class="card-content">
  271. <view class="card-info">
  272. {{item.stockName}}
  273. <text v-if="item.checked && item.checked.length > 0 && item.isAutoSelected" style="color: #FF530A; font-size: 24rpx; margin-left: 10rpx;">(自动选择)</text>
  274. <text v-if="item.checked && item.checked.length > 0 && !item.isAutoSelected" style="color: #FF530A; font-size: 24rpx; margin-left: 10rpx;">(手动选择)</text>
  275. </view>
  276. <view class="card-time">有效期限: {{item.expireTime.slice(0, 10)}}截止</view>
  277. </view>
  278. <view style="width: 20%;">
  279. <u-checkbox-group :value="item.checked" @change="changeCoupon">
  280. <u-checkbox :disabled="item.transactionMinimum > originalTotalPrice"
  281. shape="circle" :name="item.id" activeColor="#ffbf60"></u-checkbox>
  282. </u-checkbox-group>
  283. </view>
  284. </view>
  285. </view>
  286. </view>
  287. </scroll-view>
  288. </view>
  289. <u-button color="#FFBF60" type="primary" @click="confirmCoupon">确定</u-button>
  290. </view>
  291. </view>
  292. </view>
  293. </template>
  294. <script>
  295. import {
  296. getPersonalInfo,
  297. getCouponList,
  298. getCouponListForOrder
  299. } from "@/api/system/personal.js"
  300. import {
  301. getToken,
  302. getOpenIdKey
  303. } from '@/utils/auth'
  304. import {
  305. createOrderNew
  306. } from '@/api/system/user.js'
  307. import dayjs from '@/utils/lib/dayjs.min.js'
  308. export default {
  309. data() {
  310. return {
  311. isPaying: false,
  312. currentAddress: {},
  313. currentPetsByDay: [],
  314. showPets: [],
  315. expandedIndexs: [],
  316. isAgree: false,
  317. needPreFamiliarize: [],
  318. dailyShowData: [],
  319. originalTotalPrice: 0,
  320. totalPrice: 0, // 总费用
  321. discount: 0, // 平台优惠
  322. memberDiscount: 0, // 会员折扣
  323. finalPrice: 0, // 应付费用
  324. defaultPhoto: 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/pet/catdog.png',
  325. currentMember: {},
  326. memberDiscountList: [{
  327. itemType: "新晋家长",
  328. },
  329. {
  330. itemType: "普卡会员",
  331. },
  332. {
  333. itemType: "银卡会员",
  334. },
  335. {
  336. itemType: "金卡会员",
  337. }
  338. ],
  339. couponList: [],
  340. showCoupon: false,
  341. selectedCoupon: null,
  342. showCouponList: true,
  343. couponId: null,
  344. basePrice: 0,
  345. baseProduct: '',
  346. // 节假日价格配置
  347. holidayPrice: 75,
  348. normalPrice: 75,
  349. holidayDate: [],
  350. //折扣
  351. discountMemberText : '',
  352. companionLevelTitle : '',
  353. freePetConfig : {
  354. cat: { freeCount: 1 },
  355. smallDog: { freeCount: 0 },
  356. mediumDog: { freeCount: 0 },
  357. largeDog: { freeCount: 0 }
  358. },
  359. }
  360. },
  361. onLoad() {
  362. if (getToken() && getOpenIdKey()) {
  363. this.getPersonalInfo()
  364. }
  365. this.originalTotalPrice = this.$globalData.newOrderData.totalPrice
  366. if (this.originalTotalPrice) {
  367. this.basePrice = this.$globalData.mainSku[0].price
  368. this.baseProduct = this.$globalData.mainSku[0].name
  369. this.currentAddress = this.$globalData.newOrderData.currentAddress
  370. this.currentPetsByDay = this.$globalData.newOrderData.currentPetsByDay
  371. this.needPreFamiliarize = this.$globalData.newOrderData.needPreFamiliarize
  372. } else {
  373. // 返回首页
  374. uni.reLaunch({
  375. url: '/pages/index'
  376. });
  377. }
  378. this.initPriceConfig()
  379. this.getShowPets()
  380. this.groupPetsByDate()
  381. this.getCouponList()
  382. // this.totalPrice = this.$globalData.newOrderData.totalPrice
  383. this.companionLevelTitle = (this.$globalData.newOrderData.companionLevel && this.$globalData.newOrderData.companionLevel.paramValue) || ''
  384. },
  385. methods: {
  386. companionLevelPrice(){
  387. let companionLevel = this.$globalData.newOrderData.companionLevel
  388. if (!companionLevel || !companionLevel.paramValueText) {
  389. return 0
  390. }
  391. let paramValueText = isNaN(companionLevel.paramValueText) ? 0 : Number(companionLevel.paramValueText)
  392. let addPrice = this.isAddPrice()
  393. let memberRate = isNaN(this.$store.state.memberRate) ? 1 : Number(this.$store.state.memberRate)
  394. let price = paramValueText * addPrice
  395. return price * memberRate
  396. },
  397. //判断当前选中的地址是否加价
  398. isAddPrice(){
  399. let currentAddress = this.$globalData.newOrderData.currentAddress || {}
  400. let defaultPrice = 1
  401. try{
  402. defaultPrice = this.price_config.cityConfig.priceRates.default
  403. }catch(e){
  404. defaultPrice = 1
  405. }
  406. if(!this.price_config.cityConfig || !currentAddress.province || !currentAddress.city){
  407. return defaultPrice
  408. }
  409. let addressList = this.price_config.cityConfig.priceRates || []
  410. for(let key in addressList){
  411. if((currentAddress.province + currentAddress.city).includes(key)){
  412. return addressList[key]
  413. }
  414. }
  415. return defaultPrice
  416. },
  417. getDateText(date){
  418. return dayjs(date).format('MM-DD')
  419. },
  420. // 将currentPets转换为showPets
  421. getShowPets() {
  422. const showPets = []
  423. // 将 currentPetsByDay 通过petId分组
  424. const groupedPets = this.currentPetsByDay.reduce((acc, pet) => {
  425. pet.index = pet.petId + '-' + pet.serviceDate
  426. if (!acc[pet.petId]) {
  427. acc[pet.petId] = []; // 如果不存在,则初始化一个空数组
  428. }
  429. acc[pet.petId].push(pet); // 将当前宠物添加到对应的 petId 数组中
  430. return acc;
  431. }, {});
  432. console.log(groupedPets)
  433. // 循环将pets转换为showPets
  434. for (let petId in groupedPets) {
  435. const showPet = {
  436. petId: petId,
  437. name: groupedPets[petId][0].name,
  438. gender: groupedPets[petId][0].gender,
  439. petType: groupedPets[petId][0].petType,
  440. bodyType: groupedPets[petId][0].bodyType,
  441. photo: groupedPets[petId][0].photo,
  442. pets: groupedPets[petId]
  443. }
  444. showPets.push(showPet)
  445. }
  446. this.showPets = showPets
  447. console.log(this.showPets)
  448. },
  449. // 将宠物按天分组
  450. groupPetsByDate() {
  451. const dailyShowData = []
  452. const dailyPets = [];
  453. // 按日期分组宠物
  454. this.currentPetsByDay.forEach(pet => {
  455. const serviceDate = pet.serviceDate;
  456. if (!dailyPets[serviceDate]) {
  457. dailyPets[serviceDate] = [];
  458. }
  459. dailyPets[serviceDate].push(pet);
  460. });
  461. // 计算每日费用
  462. for (const date in dailyPets) {
  463. const pets = dailyPets[date];
  464. const priceDetails = []
  465. // 基础服务 - 根据是否为节假日设置价格
  466. const holidayPrice = isNaN(this.holidayPrice) ? 75 : Number(this.holidayPrice)
  467. const normalPrice = isNaN(this.normalPrice) ? 75 : Number(this.normalPrice)
  468. const baseServiceCost = Number(this.isHoliday(date) ? holidayPrice : normalPrice)
  469. const largeDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('大型')).length;
  470. let mediumDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('中型')).length;
  471. let smallDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('小型')).length;
  472. let catCount = pets.filter(pet => pet.petType === 'cat').length;
  473. const additionalCostItem = []
  474. let additionalCost = 0
  475. // 单天总宠物费用
  476. let totalPetCost = pets.reduce((acc, pet) => {
  477. return acc + this.calculatePetCost(pet);
  478. }, 0);
  479. // 根据 freePetConfig 配置计算免费宠物数量
  480. const freePetConfig = this.price_config.freePetConfig || this.freePetConfig
  481. // 计算收费的宠物数量(扣除免费数量)
  482. const chargeableMediumDogCount = Math.max(0, mediumDogCount - freePetConfig.mediumDog.freeCount)
  483. const chargeableSmallDogCount = Math.max(0, smallDogCount - freePetConfig.smallDog.freeCount)
  484. const chargeableCatCount = Math.max(0, catCount - freePetConfig.cat.freeCount)
  485. // 计算额外宠物费用
  486. if (chargeableMediumDogCount > 0) {
  487. additionalCost += (this.calculatePetCost({
  488. petType: 'dog',
  489. bodyType: '中型',
  490. }) * chargeableMediumDogCount)
  491. additionalCostItem.push({
  492. itemName: '中型犬',
  493. price: this.calculatePetCost({
  494. petType: 'dog',
  495. bodyType: '中型',
  496. }),
  497. quantity: chargeableMediumDogCount,
  498. unit: '只'
  499. })
  500. }
  501. if (chargeableSmallDogCount > 0) {
  502. additionalCost += (this.calculatePetCost({
  503. petType: 'dog',
  504. bodyType: '小型',
  505. }) * chargeableSmallDogCount)
  506. additionalCostItem.push({
  507. itemName: '小型犬',
  508. price: this.calculatePetCost({
  509. petType: 'dog',
  510. bodyType: '小型',
  511. }),
  512. quantity: chargeableSmallDogCount,
  513. unit: '只'
  514. })
  515. }
  516. if (chargeableCatCount > 0) {
  517. additionalCost += (this.calculatePetCost({
  518. petType: 'cat',
  519. }) * chargeableCatCount)
  520. additionalCostItem.push({
  521. itemName: '猫猫',
  522. price: this.calculatePetCost({
  523. petType: 'cat',
  524. }),
  525. quantity: chargeableCatCount,
  526. unit: '只'
  527. })
  528. }
  529. // 计算收费的大型犬数量(扣除免费数量)
  530. const chargeableLargeDogCount = Math.max(0, largeDogCount - freePetConfig.largeDog.freeCount)
  531. if (chargeableLargeDogCount > 0) {
  532. additionalCost += (this.calculatePetCost({
  533. petType: 'dog',
  534. bodyType: '大型',
  535. }) * chargeableLargeDogCount)
  536. additionalCostItem.push({
  537. itemName: '大型犬',
  538. price: this.calculatePetCost({
  539. petType: 'dog',
  540. bodyType: '大型',
  541. }),
  542. quantity: chargeableLargeDogCount,
  543. unit: '只'
  544. })
  545. }
  546. // 当日多次服务次数 - 基础价格乘以倍数
  547. let multServicesTotalCost = 0
  548. const maxFeedCount = Math.max(...pets.map(pet => pet.feedCount));
  549. const multiService = this.price_config.multiService || { two: { price: 1 }, three: { price: 1 } }
  550. if (maxFeedCount === 2) {
  551. multServicesTotalCost += baseServiceCost * (multiService.two.price || 1); // 基础价格 × 2次倍数
  552. } else if (maxFeedCount === 3) {
  553. multServicesTotalCost += baseServiceCost * (multiService.three.price || 1); // 基础价格 × 3次倍数
  554. }
  555. priceDetails.push({
  556. name: '专业喂养',
  557. item: [{
  558. itemName: this.isHoliday(date) ? '节假日' : '非节假日',
  559. price: baseServiceCost,
  560. quantity: 1,
  561. unit: '天'
  562. }, ]
  563. })
  564. priceDetails.push({
  565. name: '上门次数',
  566. item: [{
  567. itemName: `1天2次 (${this.isHoliday(date) ? '节假日' : '非节假日'})`,
  568. price: baseServiceCost * (multiService.two.price || 1),
  569. quantity: maxFeedCount === 2 ? 1 : 0,
  570. unit: '天'
  571. },
  572. {
  573. itemName: `1天3次 (${this.isHoliday(date) ? '节假日' : '非节假日'})`,
  574. price: baseServiceCost * (multiService.three.price || 1),
  575. quantity: maxFeedCount === 3 ? 1 : 0,
  576. unit: '天'
  577. },
  578. ]
  579. })
  580. if (additionalCostItem.length > 0) {
  581. priceDetails.push({
  582. name: '额外宠物费用',
  583. item: additionalCostItem
  584. })
  585. }
  586. // 所有宠物定制服务费用
  587. const customServiceCost = pets.reduce((acc, pet) => Number(acc) + Number(this.calculatePetCustomServiceCost(pet)), 0)
  588. // console.log(baseServiceCost + additionalCost + multServicesTotalCost + customServiceCost);
  589. console.log(baseServiceCost , additionalCost , multServicesTotalCost , customServiceCost);
  590. if (isNaN(baseServiceCost)) {
  591. console.log('baseServiceCost is not a number', baseServiceCost);
  592. }
  593. if (isNaN(additionalCost)) {
  594. console.log('additionalCost is not a number', additionalCost);
  595. }
  596. if (isNaN(multServicesTotalCost)) {
  597. console.log('multServicesTotalCost is not a number', multServicesTotalCost);
  598. }
  599. if (isNaN(customServiceCost)) {
  600. console.log('customServiceCost is not a number', customServiceCost, pets);
  601. uni.showToast({
  602. title: '定制服务费用计算错误',
  603. icon: 'none'
  604. })
  605. }
  606. // 确保所有数值都是有效的数字,避免NaN
  607. const safeBaseServiceCost = isNaN(baseServiceCost) ? 0 : Number(baseServiceCost)
  608. const safeAdditionalCost = isNaN(additionalCost) ? 0 : Number(additionalCost)
  609. const safeMultServicesTotalCost = isNaN(multServicesTotalCost) ? 0 : Number(multServicesTotalCost)
  610. const safeCustomServiceCost = isNaN(customServiceCost) ? 0 : Number(customServiceCost)
  611. const totalCost = parseFloat(safeBaseServiceCost + safeAdditionalCost + safeMultServicesTotalCost + safeCustomServiceCost).toFixed(2)
  612. // 所有宠物定制服务总项数,每个类型的服务只算一次
  613. const acc = []
  614. pets.map(pet => {
  615. pet.customServices.forEach(service => {
  616. if (!acc.includes(service.skuId) && service.quantity > 0) {
  617. acc.push(service.skuId)
  618. }
  619. })
  620. })
  621. const customServicesTotalCnt = acc.length
  622. dailyShowData.push({
  623. date,
  624. pets,
  625. priceDetails,
  626. totalCost,
  627. customServicesTotalCnt
  628. })
  629. }
  630. // 将dailyShowData按日期排序
  631. this.dailyShowData = dailyShowData.sort((a, b) => new Date(a.date) - new Date(b.date))
  632. this.getShowTotalPrice()
  633. },
  634. calculatePetCost(pet) {
  635. let petExtra = this.price_config.petExtra || {}
  636. let petCost = 0;
  637. if (pet.petType === 'cat' && petExtra.cat) {
  638. petCost += Number(petExtra.cat.price || 0); // 猫额外费用
  639. } else if (pet.petType === 'dog' && pet.bodyType.includes('小型') && petExtra.smallDog) {
  640. petCost += Number(petExtra.smallDog.price || 0); // 小型犬额外费用
  641. } else if (pet.petType === 'dog' && pet.bodyType.includes('中型') && petExtra.mediumDog) {
  642. petCost += Number(petExtra.mediumDog.price || 0); // 中型犬额外费用
  643. } else if (pet.petType === 'dog' && pet.bodyType.includes('大型') && petExtra.largeDog) {
  644. petCost += Number(petExtra.largeDog.price || 0); // 大型犬额外费用
  645. }
  646. return petCost;
  647. },
  648. // 计算宠物定制服务费用
  649. calculatePetCustomServiceCost(pet) {
  650. console.log('pet.customServices',pet.customServices)
  651. // 确保customServices存在且为数组
  652. if (!pet.customServices || !Array.isArray(pet.customServices)) {
  653. return 0
  654. }
  655. const customServiceCost = pet.customServices.reduce((acc, item) => {
  656. if (isNaN(item.price) || isNaN(item.quantity)) {
  657. console.log('customServiceCost item price or quantity is not a number', item);
  658. throw new Error('customServiceCost item price or quantity is not a number')
  659. }
  660. const price = Number(item.price)
  661. const quantity = Number(item.quantity)
  662. return Number(acc) + price * quantity
  663. }, 0)
  664. console.log('customServiceCost',customServiceCost)
  665. return parseFloat(customServiceCost).toFixed(2)
  666. },
  667. // 展开或收起服务详情
  668. toggleExpand(index) {
  669. console.log(index)
  670. this.expandedIndexs = this.expandedIndexs.includes(index) ? this.expandedIndexs.filter(i => i !== index) :
  671. [...this.expandedIndexs, index];
  672. // this.expandedIndexs.push(index)
  673. console.log(this.expandedIndexs)
  674. },
  675. goBack() {
  676. let len = getCurrentPages().length;
  677. if (len >= 2) {
  678. uni.navigateBack();
  679. } else {
  680. uni.redirectTo({
  681. url: '/pages/newOrder/serviceNew2'
  682. });
  683. }
  684. },
  685. changeAgree() {
  686. this.isAgree = !this.isAgree
  687. },
  688. checkAgreement() {
  689. uni.navigateTo({
  690. url: '/pages/details/agreement'
  691. });
  692. },
  693. // 初始化价格配置
  694. initPriceConfig() {
  695. let priceConfig = this.$store.state.price_config
  696. console.log('价格配置:', priceConfig)
  697. // 将价格配置赋值给组件
  698. this.price_config = priceConfig || {}
  699. // 获取伴宠师等级价格和城市倍率,确保都是有效数字
  700. let companionPrice = isNaN(this.$globalData.newOrderData.companionLevelPrice) ? 0 : Number(this.$globalData.newOrderData.companionLevelPrice)
  701. let cityPriceRate = isNaN(this.$globalData.newOrderData.cityPriceRate) ? 1 : Number(this.$globalData.newOrderData.cityPriceRate)
  702. let memberRate = isNaN(this.$store.state.memberRate) ? 1 : Number(this.$store.state.memberRate)
  703. if(priceConfig.basePrice && priceConfig.basePrice.holiday){
  704. const holidayBasePrice = isNaN(priceConfig.basePrice.holiday) ? 75 : Number(priceConfig.basePrice.holiday)
  705. this.holidayPrice = Number((holidayBasePrice * memberRate * cityPriceRate) + companionPrice).toFixed(2)
  706. } else {
  707. this.holidayPrice = 75
  708. }
  709. if(priceConfig.basePrice && priceConfig.basePrice.normal){
  710. const normalBasePrice = isNaN(priceConfig.basePrice.normal) ? 75 : Number(priceConfig.basePrice.normal)
  711. this.normalPrice = Number((normalBasePrice * memberRate * cityPriceRate) + companionPrice).toFixed(2)
  712. } else {
  713. this.normalPrice = 75
  714. }
  715. if(priceConfig.holidays && Array.isArray(priceConfig.holidays) && priceConfig.holidays.length > 0){
  716. this.holidayDate = priceConfig.holidays
  717. }else{
  718. this.holidayDate = []
  719. }
  720. this.discountMemberText = (memberRate * 10)
  721. },
  722. // 判断是否为节假日
  723. isHoliday(date) {
  724. return this.holidayDate.includes(date)
  725. },
  726. // 节流
  727. throttle(func, delay) {
  728. let lastCall = 0;
  729. return function(...args) {
  730. const now = new Date().getTime();
  731. if (now - lastCall < delay) {
  732. return;
  733. }
  734. lastCall = now;
  735. func(...args);
  736. }
  737. },
  738. getPersonalInfo() {
  739. getPersonalInfo().then(res => {
  740. if (res && (res.id || res.id === 0)) {
  741. let userLevel = res.level
  742. this.currentMember = this.memberDiscountList.find(item => {
  743. if (item.itemType.includes(userLevel)) {
  744. return item
  745. }
  746. })
  747. this.getShowTotalPrice()
  748. // 重新计算最优惠的优惠券
  749. if (this.couponList.length > 0) {
  750. this.autoSelectBestCoupon()
  751. }
  752. }
  753. })
  754. },
  755. // 获取优惠券列表
  756. getCouponList() {
  757. getCouponListForOrder().then(res => {
  758. let rows = res.rows
  759. console.log(rows)
  760. this.couponList = rows.filter(item => item.couponState == "SENDED")
  761. this.couponList.forEach(item => {
  762. item.checked = []
  763. item.couponAmount = 20
  764. item.isAutoSelected = false
  765. })
  766. // 自动选择最优惠的优惠券
  767. this.autoSelectBestCoupon()
  768. })
  769. },
  770. selectCoupon() {
  771. this.showCoupon = true
  772. },
  773. changeCoupon(item) {
  774. this.showCouponList = false
  775. const selectedCouponId = item[0]
  776. const selectedCoupon = this.couponList.find(coupon => coupon.id === selectedCouponId)
  777. // 清空所有优惠券的选中状态和自动选择标记
  778. this.couponList.forEach(coupon => {
  779. coupon.checked = null
  780. coupon.isAutoSelected = false
  781. })
  782. // 如果选择了优惠券,检查是否有相同 couponState 的优惠券已被使用
  783. if (selectedCoupon) {
  784. // 检查是否有相同 couponState 的优惠券已被使用
  785. const hasSameStateUsed = this.couponList.some(coupon =>
  786. coupon.id !== selectedCouponId &&
  787. coupon.couponState === selectedCoupon.couponState &&
  788. coupon.checked &&
  789. coupon.checked.length > 0
  790. )
  791. if (hasSameStateUsed) {
  792. uni.showToast({
  793. title: '相同类型的优惠券不可重复使用',
  794. icon: 'none'
  795. })
  796. this.showCouponList = true
  797. return
  798. }
  799. // 设置选中状态,标记为用户手动选择
  800. selectedCoupon.checked = item
  801. selectedCoupon.isAutoSelected = false
  802. }
  803. this.showCouponList = true
  804. },
  805. confirmCoupon() {
  806. this.selectedCoupon = this.couponList.find(coupon => coupon.checked && coupon.checked.length > 0)
  807. if (!this.selectedCoupon) {
  808. this.couponId = null
  809. this.discount = 0
  810. } else {
  811. this.couponId = this.selectedCoupon?.id
  812. // 如果优惠券是折扣
  813. if (this.selectedCoupon?.stockType == "PDISCOUNT" && this.selectedCoupon?.discountPercent > 0) {
  814. //保留两位小数
  815. this.discount = (this.originalTotalPrice * (1 - this.selectedCoupon.discountPercent / 100))
  816. .toFixed(2)
  817. } else {
  818. this.discount = this.selectedCoupon?.discountAmount
  819. }
  820. }
  821. this.getShowTotalPrice()
  822. this.showCoupon = false
  823. },
  824. togglePriceDetails() {
  825. this.showCoupon = !this.showCoupon
  826. },
  827. // 构造订单
  828. constructOrder() {
  829. const order = {
  830. openId: getOpenIdKey(),
  831. addressId: this.currentAddress.id,
  832. totalPrice: this.finalPrice,//应付费用
  833. needPreFamiliarize: this.needPreFamiliarize.length > 0,
  834. couponId: this.couponId,
  835. petOrderServices: this.getPetOrderServices(this.currentPetsByDay),
  836. //费用明细
  837. //dailyShowData : JSON.stringify(this.dailyShowData),
  838. //优惠券优惠
  839. couponDiscount: this.discount,
  840. //会员折扣
  841. memberDiscount: this.memberDiscount,
  842. //费用总计
  843. oldPrice : this.originalTotalPrice,
  844. //提前熟悉的费用
  845. preFamiliarizePrice: (this.price_config.preFamiliarize && this.price_config.preFamiliarize.price) || 40,
  846. //伴宠师等级名称
  847. companionLevelTitle : this.companionLevelTitle,
  848. //伴宠师等级加价(已合并到基础价格中)
  849. companionLevelPrice: 0,
  850. }
  851. if(this.buyInfo.teacher){
  852. order.teacherId = this.buyInfo.teacher.userId
  853. }
  854. if(this.$globalData.newOrderData.companionLevel){
  855. //打印
  856. console.log(this.$globalData.newOrderData.companionLevel);
  857. order.companionLevel = this.$globalData.newOrderData.companionLevel.paramValueNum
  858. // order.companionLevel = ['', 'junior', 'senior'].indexOf(this.$globalData.newOrderData.companionLevel)
  859. }
  860. if(this.$globalData.newOrderData.orderId){
  861. order.orderId = this.$globalData.newOrderData.orderId
  862. }
  863. // 再来一单费用
  864. if(this.$globalData.newOrderData.moreOrderPrice){
  865. order.moreOrderPrice = this.$globalData.newOrderData.moreOrderPrice
  866. }
  867. console.log(order)
  868. return order
  869. },
  870. getSkuList(customServices, feedCount, price) {
  871. console.log('customServices', JSON.parse(JSON.stringify(customServices)));
  872. const skuList = customServices.filter(service => service.quantity > 0).map(service2 => {
  873. return {
  874. skuId: service2.skuId,
  875. quantity: service2.quantity,
  876. isMainProduct: service2.isMainProduct,
  877. price: service2.price
  878. }
  879. })
  880. skuList.push({
  881. skuId: this.$globalData.mainSku[0].skuId,
  882. quantity: feedCount,
  883. isMainProduct: true,
  884. price
  885. })
  886. return skuList
  887. },
  888. getPetOrderServices(currentPetsByDay) {
  889. console.log('currentPetsByDay', JSON.parse(JSON.stringify(currentPetsByDay)));
  890. const petOrderServices = currentPetsByDay.map(pet => {
  891. let price = this.isHoliday(pet.serviceDate) ? this.holidayPrice : this.normalPrice
  892. // 当日多次服务次数 - 基础价格乘以倍数
  893. let feedCountPrice = 0;
  894. const multiService = this.price_config.multiService || { two: { price: 1 }, three: { price: 1 } }
  895. if (pet.feedCount == 2) {
  896. feedCountPrice += price * (multiService.two.price || 1); // 基础价格 × 2次倍数
  897. } else if (pet.feedCount == 3) {
  898. feedCountPrice += price * (multiService.three.price || 1); // 基础价格 × 3次倍数
  899. }
  900. return {
  901. petId: pet.petId,
  902. serviceDate: pet.serviceDate,
  903. feedCount: pet.feedCount,
  904. selectedTimeSlots: pet.selectedTimeSlots.join(','),
  905. skuList: this.getSkuList(pet.customServices, pet.feedCount, price),
  906. feedCountPrice,//当日多次服务加价
  907. }
  908. })
  909. return petOrderServices
  910. },
  911. pay(params) {
  912. if (this.isPaying) {
  913. return;
  914. }
  915. this.isPaying = true
  916. uni.requestPayment({
  917. provider: 'wxpay',
  918. timeStamp: params.timeStamp,
  919. nonceStr: params.nonceStr,
  920. package: params.package_ || params.packageValue,
  921. signType: params.signType,
  922. paySign: params.paySign,
  923. success: (res) => {
  924. this.$modal.showToast('支付成功')
  925. this.$globalData.newOrderData = {
  926. currentAddress: {},
  927. currentPets: [],
  928. totalPrice: 0,
  929. needPreFamiliarize: []
  930. }
  931. uni.reLaunch({
  932. // url: '/pages_order/order/orderList'
  933. url: '/pages_order/order/payOrderSuccessful'
  934. });
  935. },
  936. fail: (err) => {
  937. this.loading = false
  938. console.log('支付失败', err)
  939. this.$modal.showToast('支付失败')
  940. uni.reLaunch({
  941. url: '/pages_order/order/orderList'
  942. });
  943. },
  944. complete: () => {
  945. this.loading = false
  946. this.isPaying = false
  947. }
  948. })
  949. },
  950. changePreFamiliarize(name) {
  951. const preFamiliarizePrice = (this.price_config.preFamiliarize && this.price_config.preFamiliarize.price) || 40
  952. if (name && name.length > 0) {
  953. this.needPreFamiliarize = name
  954. this.originalTotalPrice = this.originalTotalPrice + preFamiliarizePrice
  955. } else {
  956. this.needPreFamiliarize = []
  957. this.originalTotalPrice = this.originalTotalPrice - preFamiliarizePrice
  958. }
  959. // 重新计算最优惠的优惠券
  960. this.autoSelectBestCoupon()
  961. this.getShowTotalPrice()
  962. },
  963. getShowTotalPrice() {
  964. // 会员折扣已经在上一个页面减去了,这里需要根据originalTotalPrice反推会员减去了多少
  965. // originalTotalPrice: 已经应用会员折扣后的价格
  966. // memberRate: 会员折扣率(如0.9表示9折)
  967. // 反推原价:originalTotalPrice / memberRate
  968. // 会员折扣金额:原价 - originalTotalPrice
  969. const originalPriceBeforeMemberDiscount = this.originalTotalPrice / this.$store.state.memberRate
  970. this.memberDiscount = (originalPriceBeforeMemberDiscount - this.originalTotalPrice).toFixed(2)
  971. // 获取再来一单费用
  972. const moreOrderPrice = this.$globalData.newOrderData.moreOrderPrice || 0
  973. // 计算最终支付价格
  974. // finalPrice: 最终支付价格 = 已应用会员折扣的价格 + 再来一单费用 - 优惠券优惠
  975. this.finalPrice = (this.originalTotalPrice + moreOrderPrice - this.discount).toFixed(2)
  976. },
  977. getCouponAmountOrDiscount(item) {
  978. if (item.stockType == "PDISCOUNT") {
  979. return item.discountPercent / 10 + '折'
  980. } else {
  981. return '¥' + item.discountAmount
  982. }
  983. },
  984. // 自动选择最优惠的优惠券
  985. autoSelectBestCoupon() {
  986. // 清空所有优惠券的选中状态和自动选择标记
  987. this.couponList.forEach(coupon => {
  988. coupon.checked = null
  989. coupon.isAutoSelected = false
  990. })
  991. // 过滤出可用的优惠券(满足最低消费要求)
  992. const availableCoupons = this.couponList.filter(coupon =>
  993. this.originalTotalPrice >= coupon.transactionMinimum
  994. )
  995. if (availableCoupons.length === 0) {
  996. this.selectedCoupon = null
  997. this.couponId = null
  998. this.discount = 0
  999. return
  1000. }
  1001. // 计算每个优惠券的实际优惠金额
  1002. const couponsWithDiscount = availableCoupons.map(coupon => {
  1003. let discountAmount = 0
  1004. if (coupon.stockType === "PDISCOUNT" && coupon.discountPercent > 0) {
  1005. // 折扣券:计算折扣后的优惠金额
  1006. discountAmount = this.originalTotalPrice * (coupon.discountPercent / 100)
  1007. } else {
  1008. // 满减券:直接使用优惠金额
  1009. discountAmount = coupon.discountAmount
  1010. }
  1011. return {
  1012. ...coupon,
  1013. calculatedDiscount: discountAmount
  1014. }
  1015. })
  1016. // 按优惠金额从高到低排序,选择最优惠的
  1017. couponsWithDiscount.sort((a, b) => b.calculatedDiscount - a.calculatedDiscount)
  1018. // 选择最优惠的优惠券
  1019. const bestCoupon = couponsWithDiscount[0]
  1020. // 在原始的 couponList 中找到对应的优惠券并设置选中状态
  1021. const originalCoupon = this.couponList.find(coupon => coupon.id === bestCoupon.id)
  1022. if (originalCoupon) {
  1023. originalCoupon.checked = [originalCoupon.id]
  1024. originalCoupon.isAutoSelected = true // 标记为自动选择
  1025. this.selectedCoupon = originalCoupon
  1026. this.couponId = originalCoupon.id
  1027. // 计算优惠金额
  1028. if (originalCoupon.stockType === "PDISCOUNT" && originalCoupon.discountPercent > 0) {
  1029. this.discount = (this.originalTotalPrice * (1 - originalCoupon.discountPercent / 100)).toFixed(2)
  1030. } else {
  1031. this.discount = originalCoupon.discountAmount
  1032. }
  1033. console.log('自动选择最优惠优惠券:', originalCoupon.stockName, '优惠金额:', this.discount)
  1034. }
  1035. // 重新计算总价
  1036. this.getShowTotalPrice()
  1037. },
  1038. goNext() {
  1039. if (!this.isAgree) {
  1040. uni.showToast({
  1041. title: '请先同意用户协议',
  1042. icon: 'none'
  1043. })
  1044. return
  1045. }
  1046. const order = this.constructOrder()
  1047. createOrderNew(order).then(res => {
  1048. if (res.code == 200) {
  1049. this.pay(res.data)
  1050. } else {
  1051. this.$modal.showToast('创建订单失败,请重试');
  1052. this.loading = false
  1053. }
  1054. })
  1055. }
  1056. }
  1057. }
  1058. </script>
  1059. <style scoped lang="scss">
  1060. .container {
  1061. position: relative;
  1062. height: 100%;
  1063. padding-bottom: 200rpx;
  1064. .details-subscribe {
  1065. background-color: #FFFFFF;
  1066. padding: 10px;
  1067. width: 100%;
  1068. height: 200rpx;
  1069. position: fixed;
  1070. bottom: 0;
  1071. z-index: 100;
  1072. .details-btn {
  1073. width: 100%;
  1074. border-radius: 6px;
  1075. background: #FFB13F;
  1076. font-size: 16px;
  1077. color: #FFFFFF;
  1078. }
  1079. .details-radio {
  1080. display: flex;
  1081. align-items: center;
  1082. justify-content: center;
  1083. }
  1084. }
  1085. }
  1086. .service-new {
  1087. .service-new-flag {
  1088. width: 8rpx;
  1089. height: 32rpx;
  1090. background: #FFBF60;
  1091. border-radius: 30rpx 30rpx 30rpx 30rpx;
  1092. margin-right: 10rpx;
  1093. }
  1094. .split-line {
  1095. width: 100%;
  1096. height: 1rpx;
  1097. background: #EFEFEF;
  1098. }
  1099. .service-new-title {
  1100. display: flex;
  1101. font-weight: 500;
  1102. font-size: 28rpx;
  1103. color: #333333;
  1104. line-height: 33rpx;
  1105. margin: 42rpx 0 30rpx;
  1106. justify-content: space-between;
  1107. .service-new-title-left {
  1108. display: flex;
  1109. align-items: center;
  1110. }
  1111. }
  1112. .service-new-details-desc {
  1113. font-weight: 400;
  1114. font-size: 24rpx;
  1115. color: #A94F20;
  1116. line-height: 28rpx;
  1117. text-align: left;
  1118. padding: 26rpx 0;
  1119. }
  1120. .personal-address-info {
  1121. display: flex;
  1122. align-items: center;
  1123. justify-content: flex-start;
  1124. flex-wrap: wrap;
  1125. margin: 32rpx 0;
  1126. width: 80%;
  1127. .personal-address-text {
  1128. color: #333;
  1129. font-size: 28rpx;
  1130. font-weight: bold;
  1131. width: 100%;
  1132. }
  1133. .personal-address-people {
  1134. color: #7D8196;
  1135. font-size: 28rpx;
  1136. font-weight: 400;
  1137. display: flex;
  1138. justify-content: flex-start;
  1139. align-items: center;
  1140. }
  1141. }
  1142. .service-new-address-selected {
  1143. display: flex;
  1144. justify-content: space-between;
  1145. align-items: center;
  1146. }
  1147. }
  1148. .personal-pet-list {
  1149. margin-top: 20rpx;
  1150. .personal-pet-list-item {
  1151. margin-bottom: 20rpx;
  1152. background-color: #F9F9F9;
  1153. height: 172rpx;
  1154. border-radius: 8rpx;
  1155. .personal-pet-info {
  1156. height: 100%;
  1157. display: flex;
  1158. align-items: center;
  1159. padding: 0 20rpx;
  1160. }
  1161. }
  1162. }
  1163. .service-new-address {
  1164. .service-summary {
  1165. height: 90rpx;
  1166. display: flex;
  1167. justify-content: space-between;
  1168. align-items: center;
  1169. padding: 15rpx;
  1170. cursor: pointer;
  1171. transition: background-color 0.3s;
  1172. }
  1173. .service-details {
  1174. padding: 10rpx 15rpx;
  1175. background-color: #F9F9F9;
  1176. margin-bottom: 10rpx;
  1177. .pet-info {
  1178. display: flex;
  1179. justify-content: space-between;
  1180. margin: 5rpx 0;
  1181. font-size: 24rpx;
  1182. color: #333;
  1183. }
  1184. .service-item {
  1185. display: flex;
  1186. justify-content: space-between;
  1187. width: 100%;
  1188. color: #999999;
  1189. font-size: 28rpx;
  1190. }
  1191. }
  1192. .total-cost {
  1193. padding: 10rpx 15rpx;
  1194. font-size: 28rpx;
  1195. color: #333;
  1196. display: flex;
  1197. justify-content: space-between;
  1198. }
  1199. }
  1200. .calendar-popup {
  1201. position: fixed;
  1202. bottom: 0;
  1203. left: 0;
  1204. right: 0;
  1205. z-index: 999;
  1206. .calendar-content {
  1207. background: #F5F5F7;
  1208. border-radius: 16rpx 16rpx 0 0;
  1209. padding: 0 20rpx 40rpx;
  1210. }
  1211. }
  1212. .calendar-mask {
  1213. position: fixed;
  1214. top: 0;
  1215. left: 0;
  1216. right: 0;
  1217. bottom: 0;
  1218. background: rgba(0, 0, 0, 0.5);
  1219. /* 半透明黑色 */
  1220. z-index: 998;
  1221. /* 确保在内容下方 */
  1222. pointer-events: none;
  1223. /* 使遮罩层不阻止点击事件 */
  1224. }
  1225. .calendar-content {
  1226. position: relative;
  1227. /* 确保内容在遮罩层之上 */
  1228. z-index: 999;
  1229. /* 确保内容在遮罩层之上 */
  1230. }
  1231. .price-details {
  1232. background: #F5F5F7;
  1233. /* 背景颜色 */
  1234. padding: 10px 10px 0 10px;
  1235. /* 内边距 */
  1236. z-index: 1000;
  1237. /* 确保在其他元素之上 */
  1238. min-height: 600rpx;
  1239. /* 固定高度 */
  1240. overflow: hidden;
  1241. /* 隐藏超出部分 */
  1242. }
  1243. .price-details-header {
  1244. display: flex;
  1245. justify-content: space-between;
  1246. align-items: center;
  1247. padding-bottom: 20rpx;
  1248. }
  1249. .price-details-body {
  1250. margin-top: 20rpx;
  1251. max-height: 450rpx;
  1252. /* 留出头部空间 */
  1253. overflow-y: auto;
  1254. /* 允许上下滚动 */
  1255. }
  1256. .coupon-card {
  1257. display: flex;
  1258. align-items: center;
  1259. width: 100%;
  1260. padding: 10px 0;
  1261. background: #fff;
  1262. border-radius: 8px;
  1263. -webkit-mask-image: radial-gradient(circle at 88px 4px, transparent 4px, #d8d8d8 4.5px), radial-gradient(closest-side circle at 50%, #d8d8d8 99%, transparent 100%);
  1264. -webkit-mask-size: 100%, 2px 4px;
  1265. -webkit-mask-repeat: repeat, repeat-y;
  1266. -webkit-mask-position: 0 -4px, 87px;
  1267. -webkit-mask-composite: source-out;
  1268. mask-composite: subtract;
  1269. // background: linear-gradient(45deg, orange, red);
  1270. // &.auto-selected {
  1271. // border: 2px solid #FF530A;
  1272. // background: linear-gradient(135deg, #fff 0%, #FFF4E4 100%);
  1273. // }
  1274. // &.manual-selected {
  1275. // border: 2px solid #4CAF50;
  1276. // background: linear-gradient(135deg, #fff 0%, #E8F5E8 100%);
  1277. // }
  1278. }
  1279. .card-left {
  1280. width: 88px;
  1281. text-align: center;
  1282. font-size: 28rpx;
  1283. color: #FF530A;
  1284. }
  1285. .card-right {
  1286. padding: 0px 12px;
  1287. display: flex;
  1288. flex: 1;
  1289. /* flex-direction: column; */
  1290. justify-content: space-between;
  1291. align-items: center;
  1292. height: 60px;
  1293. s .card-content {
  1294. width: 80%;
  1295. }
  1296. .card-icon {
  1297. position: relative;
  1298. right: -10px;
  1299. top: -10px;
  1300. }
  1301. }
  1302. .card-info {
  1303. margin: 0;
  1304. font-size: 14px;
  1305. line-height: 20px;
  1306. color: #333333;
  1307. }
  1308. .card-time {
  1309. font-size: 12px;
  1310. line-height: 16px;
  1311. font-weight: normal;
  1312. color: #aaaaaa;
  1313. margin-top: 4px;
  1314. }
  1315. </style>