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.

1092 lines
31 KiB

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