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.

683 lines
20 KiB

5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
  1. <template>
  2. <view class="service-new container">
  3. <view class="order-type-select" v-if="!buyInfo.teacher">
  4. <view class="order-type-title">
  5. <image style="width: 40rpx; height: 40rpx;margin-right: 10rpx;" slot='cover'
  6. src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/petServiceOrder/OrderIcon.png">
  7. </image>
  8. <!-- <image style="width: 32rpx; height: 32rpx; margin-right: 10rpx;" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/petServiceOrder/SystemOrderCircle.png"></image> -->
  9. 下单方式系统派单 <text style="color: #999;font-size: 26rpx;">(需先选择伴宠师等级)</text>
  10. </view>
  11. <view class="order-type-options">
  12. <view class="order-type-option"
  13. v-for="item in teacherLevelList"
  14. :key="item.id"
  15. :class="{active: item.id == companionLevel.id}"
  16. @click="selectCompanionLevel(item)">
  17. <image style="width: 40rpx; height: 40rpx; margin-right: 10rpx;"
  18. :src="item.paramValueImage || 'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/pet/catdog.png'"></image>
  19. {{ item.paramValue }}
  20. <view class="info-icon" @click.stop="showCompanionInfo(item)">
  21. <uni-icons type="info" size="20" color="#FFB13F"></uni-icons>
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. <view class="order-type-select"
  27. style="padding-bottom: 0rpx;"
  28. v-if="buyInfo.teacher">
  29. <view class="order-type-title order-type-title-custom"
  30. style="border-radius: 10rpx;">
  31. <view class="order-type-title-main"
  32. style="padding-left: 10rpx;">
  33. <image style="width: 40rpx; height: 40rpx; margin-right: 10rpx;" src="https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/petServiceOrder/OrderIcon.png"></image>
  34. <view class="main-title">
  35. 下单方式指定喂养员 - {{buyInfo.teacher.userName}}
  36. </view>
  37. </view>
  38. <view class="sub-title">
  39. 若伴宠师1小时内无响应或拒绝单则系统派单
  40. </view>
  41. </view>
  42. </view>
  43. <uni-popup ref="companionInfoPopup" type="center">
  44. <view class="companion-info-popup">
  45. <view class="companion-info-title">
  46. <text>{{ showLevelInfo.paramValue }}</text>
  47. </view>
  48. <view class="companion-info-content">
  49. <view class="companion-info-item">
  50. <text class="companion-info-label">等级:</text>
  51. <text class="companion-info-value">{{ showLevelInfo.paramValue }}</text>
  52. </view>
  53. <view class="companion-info-item">
  54. <text class="companion-info-label">价格:</text>
  55. <text class="companion-info-value">{{ companionLevelPrice() }}</text>
  56. </view>
  57. <view class="companion-info-item">
  58. <text class="companion-info-label">分类标准:</text>
  59. <text class="companion-info-value"
  60. v-html="showLevelInfo.paramValueArea"
  61. >
  62. </text>
  63. </view>
  64. </view>
  65. <view class="companion-info-close" @click="closeCompanionInfo">
  66. <uni-icons type="close" size="24" color="#fff"></uni-icons>
  67. </view>
  68. </view>
  69. </uni-popup>
  70. <view class="service-new-address">
  71. <uni-card padding=0 :is-shadow="false">
  72. <view class="service-new-title" slot="title">
  73. <view class="service-new-title-left">
  74. <view class="service-new-flag"></view>
  75. <view>服务地址</view>
  76. </view>
  77. </view>
  78. <view class="split-line"></view>
  79. <view class="service-new-address-content">
  80. <view v-if="isAddressSelected" class="service-new-address-selected" >
  81. <view class="personal-address-info">
  82. <view class="personal-address-text">
  83. {{currentAddress.province}} {{currentAddress.city}} {{currentAddress.detailAddress}}
  84. </view>
  85. <view class="personal-address-people">
  86. <view>
  87. {{currentAddress.name}}
  88. </view>
  89. <view style="border: solid #7D8196 1px; margin: 0 10px; height: 12px;"> </view>
  90. <view>
  91. {{currentAddress.phone}}
  92. </view>
  93. </view>
  94. </view>
  95. <view>
  96. <uni-icons type="right" size="28rpx" color="#AAA" @click="selectAddress"></uni-icons>
  97. </view>
  98. </view>
  99. <view v-else class="service-new-unselect">
  100. <view style="width: 50%;">
  101. <u-button color="#FFBF60" icon="plus-circle-fill" text="添加地址" shape="circle" plain @click="selectAddress">
  102. </u-button>
  103. </view>
  104. </view>
  105. </view>
  106. </uni-card>
  107. </view>
  108. <view class="service-new-pet">
  109. <uni-card padding=0 :is-shadow="false">
  110. <view class="service-new-title" slot="title">
  111. <view class="service-new-title-left">
  112. <view class="service-new-flag">
  113. </view>
  114. <view class="service-new-title-text">
  115. 服务宠物
  116. </view>
  117. </view>
  118. <view v-if="isPetSelected" class="add-pet" @click="selectPet">
  119. <u-icon name="plus-circle-fill" color="#FFBF60" size="28rpx" style="margin-right: 10rpx;"></u-icon>
  120. 添加宠物
  121. </view>
  122. </view>
  123. <view class="split-line"></view>
  124. <view class="service-new-pet-content">
  125. <view v-if="isPetSelected" class="personal-pet-list">
  126. <view v-for="(item,index) in currentPets" :key="index">
  127. <view class="personal-pet-list-item">
  128. <view class="personal-pet-info">
  129. <!-- 左侧头像 -->
  130. <view class="pet-avatar">
  131. <u-avatar :src="item.photo?item.photo:defaultPhoto" size="60" shape="circle"></u-avatar>
  132. </view>
  133. <!-- 中间内容 -->
  134. <view class="pet-info" style="flex: 1; margin: 0 20rpx; max-width: 50%;">
  135. <view class="pet-name-gender" style="display: flex; align-items: center;">
  136. <view>{{item.name}}</view>
  137. <view class="pet-gender" style="margin-left: 10rpx; display: flex;align-items: center;">
  138. <img :src="item.gender=='男生'?'../../static/images/details/boy.svg':'../../static/images/details/girl.svg'" alt="sex"
  139. style="width: 16px;height: 16px;"/>
  140. </view>
  141. </view>
  142. <view class="pet-dates ellipsis" >
  143. {{ getSelectedDateString(item.selectedDate) }}
  144. </view>
  145. </view>
  146. <!-- 右侧天数统计 -->
  147. <view class="date-total" style="margin-left: auto;width: 140rpx;text-align: end;">
  148. {{item.selectedDate.length}}
  149. <uni-icons type="right" size="28rpx" color="#AAA" @click="selectPet"></uni-icons>
  150. </view>
  151. </view>
  152. </view>
  153. </view>
  154. </view>
  155. <view v-else class="service-new-unselect">
  156. <view style="width: 50%;">
  157. <u-button color="#FFBF60" icon="plus-circle-fill" text="添加宠物" shape="circle" plain @click="selectPet">
  158. </u-button>
  159. </view>
  160. </view>
  161. </view>
  162. </uni-card>
  163. </view>
  164. <view class="service-new-pet">
  165. <uni-card padding=0 :is-shadow="false">
  166. <view class="service-new-title" slot="title">
  167. <view class="service-new-title-left">
  168. <view class="service-new-flag">
  169. </view>
  170. <view class="service-new-title-text">
  171. 服务细则
  172. </view>
  173. </view>
  174. </view>
  175. <view class="split-line"></view>
  176. <view class="service-new-details-content">
  177. <view style="margin: 30rpx 0;">
  178. <u-checkbox-group
  179. v-model="needPreFamiliarize"
  180. iconPlacement="right"
  181. placement="column">
  182. <u-checkbox activeColor="#FFBF60" label="是否提前熟悉" name="是否提前熟悉" shape="circle"></u-checkbox>
  183. </u-checkbox-group>
  184. </view>
  185. <view class="split-line"></view>
  186. <view class="service-new-details-desc">
  187. <view style="display: flex;">
  188. <text style="width: 20rpx;">*</text>
  189. <text style="flex: 1;">价格{{ price_config.preFamiliarize.price }}/</text>
  190. </view>
  191. <view style="display: flex; margin: 20rpx 0;">
  192. <text style="width: 20rpx;">*</text>
  193. <text style="flex: 1;">服务内容: 购买此服务后伴宠师将在您离家前按照约定日期提前上门沟通熟悉喂养要求及宠物</text>
  194. </view>
  195. <view style="display: flex;">
  196. <text style="width: 20rpx;">*</text>
  197. <text style="flex: 1;">服务保障: 购买此服务后平台支持在提前熟悉后上门服务第一天前无理由免费更换伴宠师1次</text>
  198. </view>
  199. </view>
  200. </view>
  201. </uni-card>
  202. </view>
  203. <view class="details-subscribe">
  204. <button class="details-btn" @click="goNext">下一步</button>
  205. </view>
  206. </view>
  207. </template>
  208. <script>
  209. import {
  210. getProductList,
  211. getOpenId
  212. } from "@/api/system/user"
  213. import { setToken,getToken,getOpenIdKey,setOpenIdKey } from '@/utils/auth'
  214. import { mapState } from 'vuex'
  215. export default {
  216. data()
  217. {
  218. return {
  219. isAddressSelected:false,
  220. currentAddress:{},
  221. isPetSelected:false,
  222. currentPets:[],
  223. needPreFamiliarize:[],
  224. defaultPhoto:'https://catmdogf.oss-cn-shanghai.aliyuncs.com/CMDF/front/personal/pet/catdog.png',
  225. companionLevel: {}, // 默认选择初级伴宠师
  226. showLevelInfo : {},
  227. }
  228. },
  229. computed: {
  230. ...mapState(['teacherLevelList', 'buyInfo', 'price_config'])
  231. },
  232. onLoad: function(option) {
  233. },
  234. onShow() {
  235. if (!getToken() || !getOpenIdKey()) {
  236. this.login()
  237. }
  238. if(this.$globalData.mainSku.length < 1 || !this.$globalData.mainSku[0].price){
  239. // 获取主产品
  240. this.getProductList()
  241. }
  242. this.currentAddress = this.$globalData.newOrderData.currentAddress
  243. if(this.currentAddress&&this.currentAddress.name){
  244. this.isAddressSelected=true
  245. }
  246. this.currentPets = this.$globalData.newOrderData.currentPets
  247. if(this.currentPets&&this.currentPets.length>0){
  248. this.isPetSelected=true
  249. }
  250. this.needPreFamiliarize = this.$globalData.newOrderData.needPreFamiliarize
  251. // 初始化伴宠师等级
  252. if(this.$globalData.newOrderData.companionLevel) {
  253. this.companionLevel = this.$globalData.newOrderData.companionLevel
  254. }else{
  255. this.companionLevel = this.teacherLevelList[0]
  256. this.$globalData.newOrderData.companionLevel = this.companionLevel
  257. }
  258. // 计算并保存伴宠师等级价格
  259. this.$globalData.newOrderData.companionLevelPrice = this.calculateCompanionLevelPrice(this.companionLevel)
  260. // 保存城市倍率
  261. this.$globalData.newOrderData.cityPriceRate = this.isAddPrice()
  262. this.$store.commit('getUserInfo')
  263. },
  264. methods:{
  265. companionLevelPrice(){
  266. let price = Number(this.showLevelInfo.paramValueText) * this.isAddPrice()
  267. return price * this.$store.state.memberRate
  268. },
  269. // 计算伴宠师等级价格(用于保存到全局数据)
  270. calculateCompanionLevelPrice(level) {
  271. if (!level || !level.paramValueText) {
  272. return 0
  273. }
  274. let price = Number(level.paramValueText) * this.isAddPrice()
  275. return price * this.$store.state.memberRate
  276. },
  277. //判断当前选中的地址是否加价
  278. isAddPrice(){
  279. let currentAddress = this.$globalData.newOrderData.currentAddress || {}
  280. let defaultPrice = 1
  281. try{
  282. defaultPrice = this.price_config.cityConfig.priceRates.default
  283. }catch(e){
  284. defaultPrice = 1
  285. }
  286. if(!this.price_config.cityConfig || !currentAddress.province || !currentAddress.city){
  287. return defaultPrice
  288. }
  289. let addressList = this.price_config.cityConfig.priceRates || []
  290. for(let key in addressList){
  291. if((currentAddress.province + currentAddress.city).includes(key)){
  292. return addressList[key]
  293. }
  294. }
  295. return defaultPrice
  296. },
  297. selectAddress(){
  298. uni.navigateTo({
  299. url: "/pages/newOrder/addressList"
  300. });
  301. },
  302. selectPet(){
  303. uni.navigateTo({
  304. url: "/pages/newOrder/petList"
  305. });
  306. },
  307. selectCompanionLevel(level) {
  308. this.companionLevel = level;
  309. // 将选择的伴宠师等级保存到全局数据
  310. this.$globalData.newOrderData.companionLevel = level;
  311. // 计算并保存伴宠师等级价格
  312. this.$globalData.newOrderData.companionLevelPrice = this.calculateCompanionLevelPrice(level);
  313. },
  314. showCompanionInfo(level) {
  315. this.showLevelInfo = level
  316. this.$refs.companionInfoPopup.open();
  317. },
  318. closeCompanionInfo() {
  319. this.$refs.companionInfoPopup.close();
  320. },
  321. getProductList() {
  322. getProductList({
  323. "publishStatus": 1,
  324. "categoryId": 76,
  325. "needSku": true
  326. }).then(response => {
  327. if (response && response.content && response.content.length > 0) {
  328. const skus = response && response.content[0].skus
  329. if(skus && skus.length>0){
  330. let price = this.price_config.basePrice.normal || skus[0].price
  331. let productSku = {
  332. "skuId": skus[0].id,
  333. // "price":(price * this.$store.state.memberRate).toFixed(2),
  334. "price":(skus[0].price).toFixed(2),
  335. "name":response.content[0].name,
  336. "quantity": 1,
  337. "isMainProduct":true
  338. }
  339. this.$globalData.mainSku = [productSku]
  340. }
  341. }else {
  342. uni.showToast('获取主产品失败,请联系管理员')
  343. }
  344. console.log(response);
  345. })
  346. },
  347. login() {
  348. uni.login({
  349. provider: 'weixin',
  350. success: (loginRes) => {
  351. this.getOpenId(loginRes.code)
  352. },
  353. fail: function(error) {
  354. // 授权失败处理
  355. uni.showToast('授权失败,请授权后再试')
  356. }
  357. });
  358. },
  359. getOpenId(code) {
  360. getOpenId(code).then(res => {
  361. if (res.code == 200 && res.data) {
  362. let resData = JSON.parse(res.data)
  363. let token = resData.token;
  364. let openId = resData.openId;
  365. setOpenIdKey(openId)
  366. if(token){
  367. setToken(token)
  368. }
  369. }
  370. })
  371. },
  372. goNext(){
  373. console.log('this.$globalData', this.$globalData)
  374. if(!this.isAddressSelected) {
  375. this.$modal.showToast('请选择服务地址');
  376. return;
  377. }
  378. if(!this.isPetSelected) {
  379. this.$modal.showToast('请选择宠物');
  380. return;
  381. }
  382. this.$globalData.newOrderData.needPreFamiliarize = this.needPreFamiliarize
  383. // 保存城市倍率
  384. this.$globalData.newOrderData.cityPriceRate = this.isAddPrice()
  385. uni.navigateTo({
  386. url: "/pages/newOrder/serviceNew2"
  387. });
  388. console.log(this.$globalData.newOrderData)
  389. },
  390. getSelectedDateString(selectDate){
  391. //显示日期为01/01;01/02;
  392. if(!selectDate || selectDate.length === 0) return '';
  393. return selectDate.map(date => {
  394. // 从日期字符串中提取月和日
  395. const [,month, day] = date.date.split('-');
  396. return `${month}/${day}`;
  397. }).join(';');
  398. }
  399. }
  400. }
  401. </script>
  402. <style scoped lang="less">
  403. .container {
  404. position: relative;
  405. height: 100%;
  406. padding-bottom: 78px;
  407. .order-type-select {
  408. padding: 20rpx 30rpx;
  409. margin-bottom: 20rpx;
  410. .order-type-title {
  411. background-color: #FFF9F0;
  412. display: flex;
  413. align-items: center;
  414. font-size: 28rpx;
  415. color: #333;
  416. margin-bottom: 20rpx;
  417. padding: 20rpx;
  418. border-radius: 40rpx;
  419. }
  420. .order-type-options {
  421. display: flex;
  422. justify-content: space-between;
  423. margin-top: 20rpx;
  424. flex-wrap: wrap;
  425. gap: 20rpx;
  426. .order-type-option {
  427. display: flex;
  428. align-items: center;
  429. width: 48%;
  430. height: 80rpx;
  431. background-color: #FFFFFF;
  432. border-radius: 40rpx;
  433. padding: 0 20rpx;
  434. font-size: 28rpx;
  435. color: #666;
  436. position: relative;
  437. border: 2rpx solid transparent;
  438. &.active {
  439. border: 2rpx solid #FFB13F;
  440. background-color: #FFF5E5;
  441. }
  442. .info-icon {
  443. position: absolute;
  444. right: 20rpx;
  445. }
  446. }
  447. }
  448. }
  449. .companion-info-popup {
  450. width: 600rpx;
  451. background-color: #FFFFFF;
  452. border-radius: 20rpx;
  453. padding: 40rpx;
  454. position: relative;
  455. &::after {
  456. content: '';
  457. display: flex;
  458. position: absolute;
  459. top: 0rpx;
  460. left: 0;
  461. width: 100%;
  462. height: 100rpx;
  463. background-color: #FFB13F;
  464. }
  465. .companion-info-title {
  466. font-size: 32rpx;
  467. font-weight: bold;
  468. color: #fff;
  469. text-align: center;
  470. border-bottom: 1rpx solid #EFEFEF;
  471. position: relative;
  472. z-index: 2;
  473. height: 100rpx;
  474. }
  475. .companion-info-content {
  476. .companion-info-item {
  477. margin-bottom: 40rpx;
  478. .companion-info-label {
  479. font-size: 28rpx;
  480. color: #666;
  481. margin-right: 10rpx;
  482. }
  483. .companion-info-value {
  484. font-size: 28rpx;
  485. color: #333;
  486. }
  487. }
  488. }
  489. .companion-info-close {
  490. position: absolute;
  491. bottom: -80rpx;
  492. left: 50%;
  493. transform: translateX(-50%);
  494. width: 80rpx;
  495. height: 80rpx;
  496. border-radius: 50%;
  497. display: flex;
  498. align-items: center;
  499. justify-content: center;
  500. }
  501. }
  502. .details-subscribe {
  503. background-color: #FFFFFF;
  504. padding: 10px;
  505. width: 100%;
  506. height: 78px;
  507. position: fixed;
  508. bottom: 0;
  509. z-index: 100;
  510. .details-btn {
  511. width: 100%;
  512. border-radius: 6px;
  513. background: #FFB13F;
  514. font-size: 16px;
  515. color: #FFFFFF;
  516. }
  517. }
  518. }
  519. .service-new{
  520. .service-new-flag {
  521. width: 8rpx;
  522. height: 32rpx;
  523. background: #FFBF60;
  524. border-radius: 30rpx 30rpx 30rpx 30rpx;
  525. margin-right: 10rpx;
  526. }
  527. .split-line{
  528. width: 100%;
  529. height: 1rpx;
  530. background: #EFEFEF;
  531. }
  532. .service-new-title{
  533. display: flex;
  534. font-weight: 500;
  535. font-size: 28rpx;
  536. color: #333333;
  537. line-height: 33rpx;
  538. margin: 42rpx 0 30rpx;
  539. justify-content: space-between;
  540. .service-new-title-left{
  541. display: flex;
  542. align-items: center;
  543. }
  544. }
  545. .service-new-unselect{
  546. height: 156rpx;
  547. display: flex;
  548. justify-content: center;
  549. align-items: center;
  550. }
  551. .add-pet{
  552. font-weight: 400;
  553. font-size: 28rpx;
  554. color: #FFAA48;
  555. line-height: 40rpx;
  556. display: flex;
  557. align-items: center;
  558. }
  559. .service-new-details-desc{
  560. font-weight: 400;
  561. font-size: 24rpx;
  562. color: #A94F20;
  563. line-height: 28rpx;
  564. text-align: left;
  565. padding: 26rpx 0;
  566. }
  567. .personal-address-info{
  568. display: flex;
  569. align-items: center;
  570. justify-content: flex-start;
  571. flex-wrap: wrap;
  572. margin: 32rpx 0;
  573. width: 80%;
  574. .personal-address-text{
  575. color: #333;
  576. font-size: 28rpx;
  577. font-weight: bold;
  578. width: 100%;
  579. }
  580. .personal-address-people{
  581. color: #7D8196;
  582. font-size: 28rpx;
  583. font-weight: 400;
  584. display: flex;
  585. justify-content: flex-start;
  586. align-items: center;
  587. }
  588. }
  589. .service-new-address-selected{
  590. display: flex;
  591. justify-content: space-between;
  592. align-items: center;
  593. }
  594. }
  595. .personal-pet-list {
  596. margin-top: 20rpx;
  597. .personal-pet-list-item {
  598. margin-bottom: 20rpx;
  599. background-color: #F9F9F9;
  600. height: 172rpx;
  601. border-radius: 8rpx;
  602. .personal-pet-info {
  603. height: 100%;
  604. display: flex;
  605. align-items: center;
  606. padding: 0 20rpx;
  607. }
  608. }
  609. }
  610. .order-type-title-custom {
  611. background-color: #FFF9F0;
  612. font-size: 28rpx;
  613. color: #333;
  614. margin-bottom: 20rpx;
  615. padding: 20rpx;
  616. border-radius: 20rpx;
  617. display: flex;
  618. flex-direction: column;
  619. align-items: flex-start !important;
  620. }
  621. .order-type-title-main {
  622. display: flex;
  623. align-items: flex-start;
  624. }
  625. .main-title {
  626. font-size: 28rpx;
  627. font-weight: bold;
  628. line-height: 1.2;
  629. color: #D97B2B;
  630. }
  631. .sub-title {
  632. font-size: 24rpx;
  633. color: #D97B2B;
  634. margin-top: 6rpx;
  635. line-height: 1.2;
  636. }
  637. </style>