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.

971 lines
30 KiB

2 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" shape="circle"></u-avatar>
  52. </view>
  53. <!-- 中间内容 -->
  54. <view class="pet-info" style="flex: 1; margin: 0 20rpx; max-width: 50%;">
  55. <view class="pet-name-gender" style="display: flex; align-items: center;">
  56. <view>{{item.name}}</view>
  57. <view class="pet-gender" style="margin-left: 10rpx; display: flex;align-items: center;">
  58. <img :src="item.gender=='男生'?'../../static/images/details/boy.svg':'../../static/images/details/girl.svg'" alt="sex"
  59. style="width: 16px;height: 16px;"/>
  60. </view>
  61. </view>
  62. <view class="pet-dates ellipsis" >
  63. {{ item.pets.map(e=>e.serviceDate).join(';') }}
  64. </view>
  65. </view>
  66. <!-- 右侧天数统计 -->
  67. <view class="date-total" style="margin-left: auto;width: 140rpx;text-align: end;">
  68. {{item.pets.length}}
  69. </view>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </view>
  75. </uni-card>
  76. </view>
  77. <view class="service-new-pet">
  78. <uni-card padding=0 :is-shadow="false">
  79. <view class="service-new-title" slot="title">
  80. <view class="service-new-title-left">
  81. <view class="service-new-flag">
  82. </view>
  83. <view class="service-new-title-text">
  84. 服务信息及费用
  85. </view>
  86. </view>
  87. </view>
  88. <view class="split-line"></view>
  89. <view class="service-new-pet-content">
  90. <view class="personal-pet-list">
  91. <view v-for="item in dailyShowData" :key="item.date" class="service-new-address">
  92. <view class="service-summary">
  93. <view style="display: flex; align-items: center;">
  94. <view style="padding-right: 10rpx;color: #7D8196;">{{ item.date }}</view>
  95. <view style="margin: 0 10rpx; width: 2px; height: 20rpx; background-color: #7D8196;"></view>
  96. <view style="color: #333333; margin-left: 10rpx;">{{baseProduct}}
  97. {{item.customServicesTotalCnt? ' + 定制服务' + item.customServicesTotalCnt + '项' : '' }} </view>
  98. </view>
  99. <view style="display: flex; align-items: center;">
  100. <view style="color: #333333;margin-right: 10rpx;">¥{{ item.totalCost }}.00</view>
  101. <view>
  102. <u-icon @click="toggleExpand( item.date )" :name="expandedIndexs.includes( item.date ) ? 'arrow-up' : 'arrow-down'" color="#FFBF60" size="14"></u-icon>
  103. </view>
  104. </view>
  105. </view>
  106. <view v-if="!expandedIndexs.includes(item.date)" class="split-line"></view>
  107. <view v-show="expandedIndexs.includes(item.date)" class="service-details">
  108. <!-- 基础服务 上门次数 额外费用 -->
  109. <view>基础服务</view>
  110. <view v-for="(priceItem, priceIndex) in item.priceDetails" :key="priceIndex" class="price-details-item" >
  111. <view style="display: flex;" v-for="(item2, index) in priceItem.item" :key="index">
  112. <view v-if="item2.quantity" class="service-item">
  113. <view v-if="item2.itemName != item.name" class="price-details-item-price-total-item">- {{ item2.itemName }}</view>
  114. <view class="price-details-item-price-total-item">¥{{ item2.price }} × {{ item2.quantity }} {{ item2.unit }}</view>
  115. </view>
  116. </view>
  117. </view>
  118. <view v-if="item.customServicesTotalCnt>0" style="margin-top: 20rpx;">定制服务</view>
  119. <view v-for="(pet, petIndex) in item.pets" :key="petIndex">
  120. <view v-if="pet.customServices &&pet.customServices.filter(e=>e.quantity>0).length>0" style="display: flex; align-items: center; justify-content: flex-start; margin-top: 20rpx;">
  121. <view class="pet-avatar">
  122. <u-avatar :src="pet.photo?pet.photo:defaultPhoto" size="34" shape="circle"></u-avatar>
  123. </view>
  124. <view style="margin-left: 20rpx;">{{ pet.name}}</view>
  125. </view>
  126. <!-- 定制服务 -->
  127. <view v-for="(customItem, customIndex) in pet.customServices" :key="customIndex">
  128. <view v-if="customItem.quantity" class="service-item">
  129. <view>- {{ customItem.name }}</view>
  130. <view>¥{{ customItem.price }} × {{ customItem.quantity }} </view>
  131. </view>
  132. </view>
  133. </view>
  134. </view>
  135. </view>
  136. <view class="service-new-address">
  137. <view v-if="needPreFamiliarize.length>0" class="total-cost">
  138. <view>提前熟悉 </view>
  139. <view>¥40</view>
  140. </view>
  141. <view class="total-cost">
  142. <view>费用总计 </view>
  143. <view>¥{{ originalTotalPrice }}</view>
  144. </view>
  145. <view class="total-cost">
  146. <view>平台优惠</view>
  147. <view style="color: #FF530A;">-¥{{ discount }}
  148. <uni-icons type="right" size="28rpx" color="#AAA" @click="selectCoupon"></uni-icons>
  149. </view>
  150. </view>
  151. <view class="total-cost">
  152. <view>会员折扣</view>
  153. <view style="display: flex; align-items: center;">
  154. <view style="color: #999999;">{{ currentMember.itemType }}</view>
  155. <view style="border: solid #7D8196 1px; margin: 0 10rpx; height: 12px;"> </view>
  156. <view style="color: #FF530A;">-¥{{ memberDiscount }}</view>
  157. </view>
  158. </view>
  159. <view class="total-cost">
  160. <view>应付费用</view>
  161. <view style="font-weight: 500;font-size: 32rpx;">¥{{ finalPrice }}</view>
  162. </view>
  163. </view>
  164. </view>
  165. </view>
  166. </uni-card>
  167. </view>
  168. <view class="service-new-pet">
  169. <uni-card padding=0 :is-shadow="false">
  170. <view class="service-new-title" slot="title">
  171. <view class="service-new-title-left">
  172. <view class="service-new-flag">
  173. </view>
  174. <view class="service-new-title-text">
  175. 服务细则
  176. </view>
  177. </view>
  178. </view>
  179. <view class="split-line"></view>
  180. <view class="service-new-details-content">
  181. <view style="margin: 30rpx 0;">
  182. <u-checkbox-group
  183. @change="changePreFamiliarize"
  184. :value="needPreFamiliarize"
  185. iconPlacement="right"
  186. placement="column">
  187. <u-checkbox activeColor="#FFBF60" label="是否提前熟悉" name="是否提前熟悉" shape="circle"></u-checkbox>
  188. </u-checkbox-group>
  189. </view>
  190. <view class="split-line"></view>
  191. <view class="service-new-details-desc">
  192. <view style="display: flex;">
  193. <text style="width: 20rpx;">*</text>
  194. <text style="flex: 1;">价格40元/</text>
  195. </view>
  196. <view style="display: flex; margin: 20rpx 0;">
  197. <text style="width: 20rpx;">*</text>
  198. <text style="flex: 1;">服务内容: 购买此服务后伴宠师将在您离家前按照约定日期提前上门沟通熟悉喂养要求及宠物</text>
  199. </view>
  200. <view style="display: flex;">
  201. <text style="width: 20rpx;">*</text>
  202. <text style="flex: 1;">服务保障: 购买此服务后平台支持在提前熟悉后上门服务第一天前无理由免费更换伴宠师1次</text>
  203. </view>
  204. </view>
  205. </view>
  206. </uni-card>
  207. </view>
  208. <view class="details-subscribe">
  209. <view class="details-radio" style="width: 100%;padding-bottom: 20rpx;">
  210. <view>
  211. <u-checkbox-group v-model="isAgree" size="16" labelSize="14" labelColor="#999999">
  212. <u-checkbox activeColor="#FFBF60" label="我同意" name="我同意" labelSize="14" size="14" shape="circle"></u-checkbox>
  213. </u-checkbox-group>
  214. </view>
  215. <text style="color: #FFBF60;font-size: 28rpx;" @click="checkAgreement">猫妈狗爸用户服务协议和隐私协议</text>
  216. </view>
  217. <view style="display: flex;justify-content: space-between; align-items: center;">
  218. <view style="height: 80rpx; display: flex; align-items: center;">
  219. <text style="color: #333333;">订单总价: </text>
  220. <text style="color: #FF530A; font-size: 40rpx;">¥{{ finalPrice }} <text style="font-size: 32rpx;"></text></text>
  221. </view>
  222. <view style="display: flex;">
  223. <u-button color="#FFF4E4" customStyle="width: 200rpx; color: #FFAA48; margin-right: 20rpx;" text="上一步" @click="goBack"></u-button>
  224. <u-button color="#FFBF60" customStyle="width: 200rpx; color: #FFF;" text="支付" @click="goNext"></u-button>
  225. </view>
  226. </view>
  227. </view>
  228. <view v-if="showCoupon" class="calendar-popup">
  229. <view class="calendar-mask" ></view>
  230. <view class="calendar-content">
  231. <view class="price-details">
  232. <view class="price-details-header">
  233. <text style="text-align: center; width: 100%; font-size: 32rpx; font-weight: 500; color: #333333;">优惠券</text>
  234. <u-icon name="close" @click="togglePriceDetails"></u-icon>
  235. </view>
  236. <view class="split-line"></view>
  237. <scroll-view class="price-details-body" scroll-y v-if="showCouponList">
  238. <view v-for="(item,index) in couponList" style="padding-bottom:14px;" :key="index">
  239. <view class="coupon-card">
  240. <view class="card-left"><text style="font-size: 40rpx; margin-left: 5rpx;">{{ getCouponAmountOrDiscount(item) }}</text></view>
  241. <view class="card-right">
  242. <view class="card-content">
  243. <view class="card-info">{{item.stockName}}</view>
  244. <view class="card-time">有效期限: {{item.expireTime.slice(0, 10)}}截止</view>
  245. </view>
  246. <view style="width: 20%;">
  247. <u-checkbox-group :value="item.checked" @change="changeCoupon">
  248. <u-checkbox :disabled="item.transactionMinimum > originalTotalPrice" shape="circle" :name="item.id" activeColor="#ffbf60"></u-checkbox>
  249. </u-checkbox-group>
  250. </view>
  251. </view>
  252. </view>
  253. </view>
  254. </scroll-view>
  255. </view>
  256. <u-button color="#FFBF60" type="primary" @click="confirmCoupon">确定</u-button>
  257. </view>
  258. </view>
  259. </view>
  260. </template>
  261. <script>
  262. import {getPersonalInfo,getCouponList,getCouponListForOrder} from "@/api/system/personal.js"
  263. import {getToken,getOpenIdKey} from '@/utils/auth'
  264. import { createOrderNew } from '@/api/system/user.js'
  265. export default {
  266. data() {
  267. return {
  268. isPaying:false,
  269. currentAddress: {},
  270. currentPetsByDay: [],
  271. showPets: [],
  272. expandedIndexs: [],
  273. isAgree: false,
  274. needPreFamiliarize: [],
  275. dailyShowData: [],
  276. originalTotalPrice:0,
  277. totalPrice: 0, // 总费用
  278. discount: 0, // 平台优惠
  279. memberDiscount:0, // 会员折扣
  280. finalPrice: 0, // 应付费用
  281. defaultPhoto:'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/pet/catdog.png',
  282. currentMember:{},
  283. memberDiscountList:[
  284. {
  285. itemType:"新晋家长9.5折优惠",
  286. discount:0.05
  287. },
  288. {
  289. itemType:"普卡会员9折优惠",
  290. discount:0.1
  291. },
  292. {
  293. itemType:"银卡会员8.8折优惠",
  294. discount:0.12
  295. },
  296. {
  297. itemType:"金卡会员8.5折优惠",
  298. discount:0.15
  299. }
  300. ],
  301. couponList:[],
  302. showCoupon:false ,
  303. selectedCoupon:null,
  304. showCouponList:true,
  305. couponId:null,
  306. basePrice:0,
  307. baseProduct:'',
  308. }
  309. },
  310. onLoad() {
  311. if (getToken() && getOpenIdKey()) {
  312. this.getPersonalInfo()
  313. }
  314. this.originalTotalPrice = this.$globalData.newOrderData.totalPrice
  315. if(this.originalTotalPrice){
  316. this.basePrice = this.$globalData.mainSku[0].price
  317. this.baseProduct = this.$globalData.mainSku[0].name
  318. this.currentAddress = this.$globalData.newOrderData.currentAddress
  319. this.currentPetsByDay = this.$globalData.newOrderData.currentPetsByDay
  320. this.needPreFamiliarize = this.$globalData.newOrderData.needPreFamiliarize
  321. }else{
  322. // 返回首页
  323. uni.reLaunch({
  324. url: '/pages/index'
  325. });
  326. }
  327. this.getCouponList()
  328. this.getShowPets()
  329. this.groupPetsByDate()
  330. // this.totalPrice = this.$globalData.newOrderData.totalPrice
  331. },
  332. methods: {
  333. // 将currentPets转换为showPets
  334. getShowPets() {
  335. const showPets = []
  336. // 将 currentPetsByDay 通过petId分组
  337. const groupedPets = this.currentPetsByDay.reduce((acc, pet) => {
  338. pet.index = pet.petId + '-' + pet.serviceDate
  339. if (!acc[pet.petId]) {
  340. acc[pet.petId] = []; // 如果不存在,则初始化一个空数组
  341. }
  342. acc[pet.petId].push(pet); // 将当前宠物添加到对应的 petId 数组中
  343. return acc;
  344. }, {});
  345. console.log(groupedPets)
  346. // 循环将pets转换为showPets
  347. for(let petId in groupedPets) {
  348. const showPet = {
  349. petId: petId,
  350. name: groupedPets[petId][0].name,
  351. gender: groupedPets[petId][0].gender,
  352. petType: groupedPets[petId][0].petType,
  353. bodyType: groupedPets[petId][0].bodyType,
  354. photo: groupedPets[petId][0].photo,
  355. pets: groupedPets[petId]
  356. }
  357. showPets.push(showPet)
  358. }
  359. this.showPets = showPets
  360. console.log(this.showPets)
  361. },
  362. // 将宠物按天分组
  363. groupPetsByDate() {
  364. const dailyShowData = []
  365. const dailyPets = [];
  366. // 按日期分组宠物
  367. this.currentPetsByDay.forEach(pet => {
  368. const serviceDate = pet.serviceDate;
  369. if (!dailyPets[serviceDate]) {
  370. dailyPets[serviceDate] = [];
  371. }
  372. dailyPets[serviceDate].push(pet);
  373. });
  374. // 计算每日费用
  375. for (const date in dailyPets) {
  376. const pets = dailyPets[date];
  377. const priceDetails = []
  378. // 基础服务
  379. const baseServiceCost = this.basePrice
  380. const largeDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('大型')).length;
  381. let mediumDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('中型')).length;
  382. let smallDogCount = pets.filter(pet => pet.petType === 'dog' && pet.bodyType.includes('小型')).length;
  383. let catCount = pets.filter(pet => pet.petType === 'cat').length;
  384. const additionalCostItem = []
  385. let additionalCost = 0
  386. // 单天总宠物费用
  387. let totalPetCost = pets.reduce((acc, pet) => {
  388. return acc + this.calculatePetCost(pet);
  389. }, 0);
  390. // 如果总宠物费用>30
  391. if(totalPetCost>30){
  392. // 如果猫数量>=3,则免3只猫
  393. if (catCount >= 3) {
  394. additionalCost = totalPetCost - 30
  395. catCount = catCount-3
  396. }else if (smallDogCount >= 2) { // 如果小型犬数量>=2,则免2只小型犬
  397. additionalCost = totalPetCost - 30
  398. smallDogCount = smallDogCount-2
  399. }else if(mediumDogCount >= 1) { // 如果中型犬数量>=1,则免1只中型犬
  400. additionalCost = totalPetCost - 30
  401. mediumDogCount = mediumDogCount-1
  402. }else{
  403. additionalCost = totalPetCost - 25
  404. catCount = catCount - 1
  405. smallDogCount = smallDogCount - 1
  406. }
  407. if(mediumDogCount>0){
  408. additionalCostItem.push({ itemName: '中型犬', price: 30, quantity: mediumDogCount, unit: '只'})
  409. }
  410. if(smallDogCount>0){
  411. additionalCostItem.push({ itemName: '小型犬', price: 15, quantity: smallDogCount, unit: '只'})
  412. }
  413. if(catCount>0){
  414. additionalCostItem.push({ itemName: '猫猫', price: 10, quantity: catCount, unit: '只'})
  415. }
  416. }
  417. // 如果有大型犬,额外费用为40元/只
  418. if (largeDogCount > 0) {
  419. additionalCost +=(40 * largeDogCount)
  420. additionalCostItem.push({ itemName: '大型犬', price: 40, quantity: largeDogCount, unit: '只'})
  421. }
  422. // 当日多次服务次数
  423. let multServicesTotalCost = 0
  424. const maxFeedCount = Math.max(...pets.map(pet => pet.feedCount));
  425. if (maxFeedCount === 2) {
  426. multServicesTotalCost += 45; // 1天2次
  427. } else if (maxFeedCount === 3) {
  428. multServicesTotalCost += 130; // 1天3次
  429. }
  430. priceDetails.push({ name: '专业喂养', item: [
  431. { itemName: '专业喂养', price: baseServiceCost, quantity: 1, unit: '天' },
  432. ]})
  433. priceDetails.push({ name: '上门次数', item: [
  434. { itemName: '1天2次', price: 45, quantity: maxFeedCount === 2 ? 1 : 0, unit: '天'},
  435. { itemName: '1天3次', price: 130, quantity: maxFeedCount === 3 ? 1 : 0, unit: '天'},
  436. ]})
  437. if(additionalCostItem.length>0){
  438. priceDetails.push({ name: '额外宠物费用', item: additionalCostItem})
  439. }
  440. // 所有宠物定制服务费用
  441. const customServiceCost = pets.reduce((acc, pet) => acc + this.calculatePetCustomServiceCost(pet), 0)
  442. const totalCost = baseServiceCost + additionalCost + multServicesTotalCost + customServiceCost
  443. // 所有宠物定制服务总项数,每个类型的服务只算一次
  444. const acc = []
  445. pets.map(pet=>{
  446. pet.customServices.forEach(service=>{
  447. if(!acc.includes(service.skuId) && service.quantity>0){
  448. acc.push(service.skuId)
  449. }
  450. })
  451. })
  452. const customServicesTotalCnt = acc.length
  453. dailyShowData.push({
  454. date,
  455. pets,
  456. priceDetails,
  457. totalCost,
  458. customServicesTotalCnt
  459. })
  460. }
  461. // 将dailyShowData按日期排序
  462. this.dailyShowData = dailyShowData.sort((a, b) => new Date(a.date) - new Date(b.date))
  463. this.getShowTotalPrice()
  464. },
  465. calculatePetCost(pet) {
  466. // 宠物额外费用 不计算大型犬
  467. let petCost = 0;
  468. if (pet.petType === 'cat') {
  469. petCost += 10; // 猫额外费用
  470. } else if (pet.petType === 'dog' && pet.bodyType.includes('小型')) {
  471. petCost += 15; // 小型犬额外费用
  472. } else if (pet.petType === 'dog' && pet.bodyType.includes('中型')) {
  473. petCost += 30; // 中型犬额外费用
  474. }
  475. return petCost;
  476. },
  477. // 计算宠物定制服务费用
  478. calculatePetCustomServiceCost(pet) {
  479. const customServiceCost = pet.customServices.reduce((acc, item) => acc + item.price * item.quantity, 0)
  480. return customServiceCost
  481. },
  482. // 展开或收起服务详情
  483. toggleExpand(index) {
  484. console.log(index)
  485. this.expandedIndexs = this.expandedIndexs.includes(index) ? this.expandedIndexs.filter(i => i !== index) : [...this.expandedIndexs, index];
  486. // this.expandedIndexs.push(index)
  487. console.log(this.expandedIndexs)
  488. },
  489. goBack() {
  490. let len = getCurrentPages().length;
  491. if(len >= 2) {
  492. uni.navigateBack();
  493. }else {
  494. uni.redirectTo({url:'/pages/newOrder/serviceNew2'});
  495. }
  496. },
  497. changeAgree() {
  498. this.isAgree = !this.isAgree
  499. },
  500. checkAgreement() {
  501. uni.navigateTo({
  502. url: '/pages/details/agreement'
  503. });
  504. },
  505. // 节流
  506. throttle(func, delay) {
  507. let lastCall = 0;
  508. return function(...args) {
  509. const now = new Date().getTime();
  510. if (now - lastCall < delay) {
  511. return;
  512. }
  513. lastCall = now;
  514. func(...args);
  515. }
  516. },
  517. getPersonalInfo(){
  518. getPersonalInfo().then(res=>{
  519. if(res&&(res.id || res.id === 0)){
  520. let userLevel=res.level
  521. this.currentMember = this.memberDiscountList.find(item=>{
  522. if(item.itemType.includes(userLevel)){
  523. return item
  524. }
  525. })
  526. this.getShowTotalPrice()
  527. }
  528. })
  529. },
  530. // 获取优惠券列表
  531. getCouponList() {
  532. getCouponListForOrder().then(res=>{
  533. let rows = res.rows
  534. console.log(rows)
  535. this.couponList=rows.filter(item=>item.couponState=="SENDED")
  536. this.couponList.forEach(item=>{
  537. item.checked = []
  538. item.couponAmount = 20
  539. })
  540. })
  541. },
  542. selectCoupon(){
  543. this.showCoupon = true
  544. },
  545. changeCoupon(item){
  546. this.showCouponList = false
  547. this.couponList.forEach(coupon=>{
  548. if(coupon.id!=item[0]){
  549. coupon.checked = null
  550. }else{
  551. coupon.checked = item
  552. }
  553. })
  554. this.showCouponList = true
  555. },
  556. confirmCoupon(){
  557. this.selectedCoupon = this.couponList.find(coupon=>coupon.checked && coupon.checked.length>0)
  558. if(!this.selectedCoupon){
  559. this.couponId = null
  560. this.discount = 0
  561. }else{
  562. this.couponId = this.selectedCoupon?.id
  563. // 如果优惠券是折扣
  564. if(this.selectedCoupon?.stockType=="PDISCOUNT" && this.selectedCoupon?.discountPercent>0){
  565. //保留两位小数
  566. this.discount = (this.originalTotalPrice * (1-this.selectedCoupon.discountPercent/100)).toFixed(2)
  567. }else{
  568. this.discount = this.selectedCoupon?.discountAmount
  569. }
  570. }
  571. this.getShowTotalPrice()
  572. this.showCoupon = false
  573. },
  574. togglePriceDetails(){
  575. this.showCoupon = !this.showCoupon
  576. },
  577. // 构造订单
  578. constructOrder(){
  579. const order = {
  580. openId:getOpenIdKey(),
  581. addressId:this.currentAddress.id,
  582. totalPrice:this.finalPrice,
  583. needPreFamiliarize:this.needPreFamiliarize.length>0,
  584. couponId:this.couponId,
  585. petOrderServices:this.getPetOrderServices(this.currentPetsByDay),
  586. }
  587. console.log(order)
  588. return order
  589. },
  590. getSkuList(customServices,feedCount){
  591. const skuList = customServices.filter(service=>service.quantity>0).map(service2=>{
  592. return {
  593. skuId:service2.skuId,
  594. quantity:service2.quantity,
  595. isMainProduct:service2.isMainProduct
  596. }
  597. })
  598. skuList.push({
  599. skuId:this.$globalData.mainSku[0].skuId,
  600. quantity:feedCount,
  601. isMainProduct:true
  602. })
  603. return skuList
  604. },
  605. getPetOrderServices(currentPetsByDay){
  606. const petOrderServices = currentPetsByDay.map(pet=>{
  607. return {
  608. petId:pet.petId,
  609. serviceDate:pet.serviceDate,
  610. feedCount:pet.feedCount,
  611. selectedTimeSlots:pet.selectedTimeSlots.join(','),
  612. skuList:this.getSkuList(pet.customServices,pet.feedCount)
  613. }
  614. })
  615. return petOrderServices
  616. },
  617. pay(params) {
  618. if (this.isPaying) {
  619. return;
  620. }
  621. this.isPaying = true
  622. uni.requestPayment({
  623. provider: 'wxpay',
  624. timeStamp: params.timeStamp,
  625. nonceStr: params.nonceStr,
  626. package: params.package_,
  627. signType: params.signType,
  628. paySign: params.paySign,
  629. success: (res) => {
  630. this.$modal.showToast('支付成功')
  631. this.$globalData.newOrderData={
  632. currentAddress:{},
  633. currentPets:[],
  634. totalPrice:0,
  635. needPreFamiliarize:[]
  636. }
  637. uni.navigateTo({
  638. url: '/pages/details/successful'
  639. });
  640. },
  641. fail: (err) => {
  642. this.loading=false
  643. console.log('支付失败', err)
  644. this.$modal.showToast('支付失败')
  645. },
  646. complete: () => {
  647. this.loading=false
  648. this.isPaying = false
  649. }
  650. })
  651. },
  652. changePreFamiliarize(name){
  653. if(name&&name.length>0){
  654. this.needPreFamiliarize=name
  655. this.originalTotalPrice = this.originalTotalPrice + 40
  656. }else{
  657. this.needPreFamiliarize=[]
  658. this.originalTotalPrice = this.originalTotalPrice - 40
  659. }
  660. // 如果总价小于优惠券的最低消费,则不使用优惠券
  661. if(this.selectedCoupon && this.originalTotalPrice<this.selectedCoupon.transactionMinimum){
  662. this.discount = 0
  663. this.couponId = null
  664. this.couponList.forEach(coupon=>{
  665. coupon.checked = null
  666. })
  667. }
  668. this.getShowTotalPrice()
  669. },
  670. getShowTotalPrice(){
  671. //保留两位小数
  672. this.memberDiscount = ((this.originalTotalPrice - this.discount) * this.currentMember.discount).toFixed(2)
  673. this.finalPrice = (this.originalTotalPrice - this.memberDiscount - this.discount).toFixed(2)
  674. },
  675. getCouponAmountOrDiscount(item){
  676. if(item.stockType=="PDISCOUNT"){
  677. return item.discountPercent/10 + '折'
  678. }else{
  679. return '¥' + item.discountAmount
  680. }
  681. },
  682. goNext() {
  683. if(!this.isAgree) {
  684. uni.showToast({
  685. title: '请先同意用户协议',
  686. icon: 'none'
  687. })
  688. return
  689. }
  690. const order = this.constructOrder()
  691. createOrderNew(order).then(res => {
  692. if (res.code == 200) {
  693. this.pay(res.data)
  694. } else {
  695. this.$modal.showToast('创建订单失败,请重试');
  696. this.loading=false
  697. }
  698. })
  699. }
  700. }
  701. }
  702. </script>
  703. <style scoped lang="scss">
  704. .container {
  705. position: relative;
  706. height: 100%;
  707. padding-bottom: 200rpx;
  708. .details-subscribe {
  709. background-color: #FFFFFF;
  710. padding: 10px;
  711. width: 100%;
  712. height: 200rpx;
  713. position: fixed;
  714. bottom: 0;
  715. z-index: 100;
  716. .details-btn {
  717. width: 100%;
  718. border-radius: 6px;
  719. background: #FFB13F;
  720. font-size: 16px;
  721. color: #FFFFFF;
  722. }
  723. .details-radio{
  724. display: flex;
  725. align-items: center;
  726. justify-content: center;
  727. }
  728. }
  729. }
  730. .service-new{
  731. .service-new-flag {
  732. width: 8rpx;
  733. height: 32rpx;
  734. background: #FFBF60;
  735. border-radius: 30rpx 30rpx 30rpx 30rpx;
  736. margin-right: 10rpx;
  737. }
  738. .split-line{
  739. width: 100%;
  740. height: 1rpx;
  741. background: #EFEFEF;
  742. }
  743. .service-new-title{
  744. display: flex;
  745. font-weight: 500;
  746. font-size: 28rpx;
  747. color: #333333;
  748. line-height: 33rpx;
  749. margin: 42rpx 0 30rpx;
  750. justify-content: space-between;
  751. .service-new-title-left{
  752. display: flex;
  753. align-items: center;
  754. }
  755. }
  756. .service-new-details-desc{
  757. font-weight: 400;
  758. font-size: 24rpx;
  759. color: #A94F20;
  760. line-height: 28rpx;
  761. text-align: left;
  762. padding: 26rpx 0;
  763. }
  764. .personal-address-info{
  765. display: flex;
  766. align-items: center;
  767. justify-content: flex-start;
  768. flex-wrap: wrap;
  769. margin: 32rpx 0;
  770. width: 80%;
  771. .personal-address-text{
  772. color: #333;
  773. font-size: 28rpx;
  774. font-weight: bold;
  775. width: 100%;
  776. }
  777. .personal-address-people{
  778. color: #7D8196;
  779. font-size: 28rpx;
  780. font-weight: 400;
  781. display: flex;
  782. justify-content: flex-start;
  783. align-items: center;
  784. }
  785. }
  786. .service-new-address-selected{
  787. display: flex;
  788. justify-content: space-between;
  789. align-items: center;
  790. }
  791. }
  792. .personal-pet-list {
  793. margin-top: 20rpx;
  794. .personal-pet-list-item {
  795. margin-bottom: 20rpx;
  796. background-color: #F9F9F9;
  797. height: 172rpx;
  798. border-radius: 8rpx;
  799. .personal-pet-info {
  800. height: 100%;
  801. display: flex;
  802. align-items: center;
  803. padding: 0 20rpx;
  804. }
  805. }
  806. }
  807. .service-new-address {
  808. .service-summary {
  809. height: 90rpx;
  810. display: flex;
  811. justify-content: space-between;
  812. align-items: center;
  813. padding: 15rpx;
  814. cursor: pointer;
  815. transition: background-color 0.3s;
  816. }
  817. .service-details {
  818. padding: 10rpx 15rpx;
  819. background-color: #F9F9F9;
  820. margin-bottom: 10rpx;
  821. .pet-info {
  822. display: flex;
  823. justify-content: space-between;
  824. margin: 5rpx 0;
  825. font-size: 24rpx;
  826. color: #333;
  827. }
  828. .service-item {
  829. display: flex;
  830. justify-content: space-between;
  831. width: 100%;
  832. color: #999999;
  833. font-size: 28rpx;
  834. }
  835. }
  836. .total-cost {
  837. padding: 10rpx 15rpx;
  838. font-size: 28rpx;
  839. color: #333;
  840. display: flex;
  841. justify-content: space-between;
  842. }
  843. }
  844. .calendar-popup{
  845. position: fixed;
  846. bottom: 0;
  847. left: 0;
  848. right: 0;
  849. z-index: 999;
  850. .calendar-content{
  851. background: #F5F5F7;
  852. border-radius: 16rpx 16rpx 0 0;
  853. padding: 0 20rpx 40rpx;
  854. }
  855. }
  856. .calendar-mask {
  857. position: fixed;
  858. top: 0;
  859. left: 0;
  860. right: 0;
  861. bottom: 0;
  862. background: rgba(0, 0, 0, 0.5); /* 半透明黑色 */
  863. z-index: 998; /* 确保在内容下方 */
  864. pointer-events: none; /* 使遮罩层不阻止点击事件 */
  865. }
  866. .calendar-content {
  867. position: relative; /* 确保内容在遮罩层之上 */
  868. z-index: 999; /* 确保内容在遮罩层之上 */
  869. }
  870. .price-details {
  871. background: #F5F5F7; /* 背景颜色 */
  872. padding: 10px 10px 0 10px; /* 内边距 */
  873. z-index: 1000; /* 确保在其他元素之上 */
  874. min-height: 600rpx; /* 固定高度 */
  875. overflow: hidden; /* 隐藏超出部分 */
  876. }
  877. .price-details-header {
  878. display: flex;
  879. justify-content: space-between;
  880. align-items: center;
  881. padding-bottom: 20rpx;
  882. }
  883. .price-details-body {
  884. margin-top: 20rpx;
  885. max-height: 450rpx; /* 留出头部空间 */
  886. overflow-y: auto; /* 允许上下滚动 */
  887. }
  888. .coupon-card{
  889. display: flex;
  890. align-items: center;
  891. width: 100%;
  892. padding: 10px 0;
  893. background: #fff;
  894. border-radius: 8px;
  895. -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%);
  896. -webkit-mask-size: 100%, 2px 4px;
  897. -webkit-mask-repeat: repeat, repeat-y;
  898. -webkit-mask-position: 0 -4px, 87px;
  899. -webkit-mask-composite: source-out;
  900. mask-composite: subtract;
  901. // background: linear-gradient(45deg, orange, red);
  902. }
  903. .card-left{
  904. width: 88px;
  905. text-align: center;
  906. font-size: 28rpx;
  907. color: #FF530A;
  908. }
  909. .card-right{
  910. padding: 0px 12px;
  911. display: flex;
  912. flex: 1;
  913. /* flex-direction: column; */
  914. justify-content: space-between;
  915. align-items: center;
  916. height: 60px;s
  917. .card-content {
  918. width: 80%;
  919. }
  920. .card-icon{
  921. position: relative;
  922. right: -10px;
  923. top: -10px;
  924. }
  925. }
  926. .card-info{
  927. margin: 0;
  928. font-size: 14px;
  929. line-height: 20px;
  930. color:#333333;
  931. }
  932. .card-time{
  933. font-size: 12px;
  934. line-height: 16px;
  935. font-weight: normal;
  936. color: #aaaaaa;
  937. margin-top: 4px;
  938. }
  939. </style>