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.

764 lines
17 KiB

8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
  1. <template>
  2. <view class="technician-Detail">
  3. <van-nav-bar class="technician-Detail-Top" title="技师详情" left-arrow @click-left="back" safe-area-inset-top />
  4. <view class="technician-Detail-img">
  5. <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
  6. <van-swipe-item v-for="(item,index) in technicianImages" :key="index">
  7. <image :src="item" style="width: 100%;" mode="widthFix"></image>
  8. </van-swipe-item>
  9. <template #indicator="{ active, total }">
  10. <!-- <div class="custom-indicator">{{ active + 1 }}/{{ total }}</div> -->
  11. </template>
  12. </van-swipe>
  13. <view class="technician-Detail-img-text">下单付款后商家会在10分钟内联系你哦~</view>
  14. </view>
  15. <view class="techni-content">
  16. <view class="userInfo">
  17. <view class="img-box">
  18. <image @click="showImage(technicianDetail.image)" :src="technicianDetail.image" mode="aspectFill">
  19. </image>
  20. </view>
  21. <view class="base-info">
  22. <view class="username-tag">
  23. <view class="username">{{ technicianDetail.title }}</view>
  24. <view v-if="technicianDetail.isVip" class="tag">
  25. <image src="@/static/order/s.png" mode="aspectFit"></image>
  26. <view class="auth">官方认证</view>
  27. </view>
  28. </view>
  29. <view class="build">
  30. <view class="sex">
  31. <image src="../../static/technician/sex.png" mode="aspectFit"></image>
  32. </view>
  33. <view class="address">
  34. {{ technicianDetail.area }}
  35. </view>
  36. <view class="cm">
  37. {{ technicianDetail.cm }}
  38. </view>
  39. <view class="weight">
  40. {{ technicianDetail.kg /2 }}kg
  41. </view>
  42. <view class="real-name">
  43. <image src="../../static/technician/real-name.png" mode="aspectFit"></image>
  44. <view class="desc">实名</view>
  45. </view>
  46. </view>
  47. <view class="service-experience">
  48. <view class="experience">
  49. {{ technicianDetail.experience }}年经验
  50. </view>
  51. <view class="service-num">
  52. 近期服务过{{ technicianDetail.isFw }}
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. <view class="view">
  58. <view class="service-description">
  59. <div v-for="item in serviceDescList" class="sesc-item">
  60. <image src="../../static/technician/desc.png" mode="aspectFit"></image>
  61. <view>{{ item }}</view>
  62. </div>
  63. </view>
  64. </view>
  65. <view class="line">
  66. <view></view>
  67. </view>
  68. <view class="text">
  69. <div class="colleact-info">
  70. <view style="color: #454545;">个人介绍</view>
  71. <view v-if="collect == 0" class="selective-technician">
  72. <view @click.stop="addCollect(technicianDetail.id)" class="btn">
  73. 立即收藏
  74. </view>
  75. </view>
  76. </div>
  77. <view style="color: #A1A1A1; margin-top: 5px;">
  78. {{ technicianDetail.notes }}
  79. </view>
  80. </view>
  81. <!-- <view class="ServicesAvailable">
  82. <view>服务项目</view>
  83. </view> -->
  84. <van-tabs class="tabs" v-model:active="activeTag">
  85. <van-tab title="服务项目">
  86. <van-empty v-if="projectList.length <= 0" image="/static/empty/message-list.png" image-size="400rpx"
  87. description="暂无服务" />
  88. <view v-else class="server-list">
  89. <view v-for="item in projectList" class="server-item" @click="toPayOrder(item)">
  90. <view class="img-box">
  91. <image :src="item.image" mode="aspectFill"></image>
  92. </view>
  93. <view class="server-info">
  94. <view class="server-title">{{ item.title }}</view>
  95. <view class="time-coupon">
  96. <image src="@/static/home/time-icon.png"></image>
  97. <view class="time">{{ item.times }}分钟</view>
  98. <!-- <view class="coupon">{{ item.subTitle }}</view> -->
  99. </view>
  100. <view class="price">
  101. <view class="current-price">
  102. <text class="unit"></text>{{ item.price }}
  103. </view>
  104. <view class="original-price">
  105. <text class="unit"></text>{{ item.oldPrice }}
  106. </view>
  107. </view>
  108. <view class="sales-volume">
  109. <image src="@/static/icons/icon1.png"></image>
  110. <view class="desc">已售出{{ item.payNum }}+</view>
  111. </view>
  112. </view>
  113. <view class="selective-technician">
  114. <view @click.stop="toPayOrder(item)"
  115. :class="{ notAvailable : technicianDetail.bookable != 'Y' }" class="btn">
  116. {{ technicianDetail.bookable == 'Y' ? '立即预约' : '不可预约' }}
  117. </view>
  118. </view>
  119. </view>
  120. </view>
  121. </van-tab>
  122. <van-tab title="健康证">
  123. <view class="health-certificate">
  124. <van-empty v-if="!technicianDetail.healthCertificate" image="/static/empty/order.png" image-size="400rpx"
  125. description="技师暂未上传健康证" />
  126. <view v-else class="health-certificate-main">
  127. <image @click="showImage(technicianDetail.healthCertificate)"
  128. :src="technicianDetail.healthCertificate" mode="widthFix" style="width: 100%;"></image>
  129. </view>
  130. </view>
  131. </van-tab>
  132. <van-tab title="营业证">
  133. <view class="health-certificate">
  134. <van-empty v-if="!technicianDetail.businessLicense" image="/static/empty/order.png" image-size="400rpx"
  135. description="技师暂未上传健康证" />
  136. <view v-else class="health-certificate-main">
  137. <image @click="showImage(technicianDetail.businessLicense)"
  138. :src="technicianDetail.businessLicense" mode="widthFix" style="width: 100%;"></image>
  139. </view>
  140. </view>
  141. </van-tab>
  142. <van-tab title="用户评论">
  143. <view class="review bg-white mar-10 box-s">
  144. <!-- <view class="review-title">用户评论({{ countReviewNum }}+)</view> -->
  145. <view class="review-classify">
  146. <view @click="selectReview(0)" class="review-classify-item"
  147. :class="{'select-classify' : reviewQueryParams.fraction == 0}">
  148. 好评
  149. <text class="num">{{ goodReputationNum }}</text>
  150. </view>
  151. <view @click="selectReview(1)" class="review-classify-item"
  152. :class="{'select-classify' : reviewQueryParams.fraction == 1}">
  153. 中评
  154. <text class="num">{{ mediumReviewNum }}</text>
  155. </view>
  156. <view @click="selectReview(2)" class="review-classify-item"
  157. :class="{'select-classify' : reviewQueryParams.fraction == 2}">
  158. 差评
  159. <text class="num">{{ negativeComment }}</text>
  160. </view>
  161. </view>
  162. <van-list v-if="reviewList.length > 0" v-model:loading="loading" :finished="finished"
  163. finished-text="没有更多了" @load="onLoad">
  164. <reviewListVue :list="reviewList"></reviewListVue>
  165. </van-list>
  166. <van-empty v-else image="/static/empty/record.png" image-size="400rpx" description="暂无评论" />
  167. </view>
  168. </van-tab>
  169. </van-tabs>
  170. </view>
  171. </view>
  172. </template>
  173. <script>
  174. import {
  175. showImagePreview
  176. } from 'vant';
  177. import reviewListVue from '@/components/review/reviewList/reviewList.vue'
  178. export default {
  179. components : { reviewListVue },
  180. data() {
  181. return {
  182. searchKeyword: '',
  183. technicianDetail: {},
  184. projectList: [],
  185. queryParams: {
  186. pageNo: 1,
  187. pageSize: 100,
  188. fraction: 0
  189. },
  190. loading: false,
  191. finished: false,
  192. serviceDescList: ['实名认证', '头像认证', '健康证', '按摩师证'],
  193. collect: 0,
  194. technicianImages: [],
  195. activeTag: 0,
  196. goodReputationNum: 0, //好评数量
  197. mediumReviewNum: 0, //中评数量
  198. negativeComment: 0, //差评数量
  199. countReviewNum: 0, //总评论条数
  200. reviewList: [],
  201. reviewQueryParams: {
  202. pageNo: 1,
  203. pageSize: 10,
  204. fraction: 0,
  205. tenantId : '',
  206. projectId : '1797549059400646658',
  207. type : 0
  208. },
  209. }
  210. },
  211. onShow() {
  212. this.getTechnicianDetail()
  213. },
  214. methods: {
  215. //获取技师详情
  216. getTechnicianDetail() {
  217. this.$api('getTechnicianDetail', {
  218. id: this.$route.query.id
  219. }, res => {
  220. if (res.code == 200) {
  221. this.collect = res.result.collect
  222. this.technicianDetail = res.result.msgTechnician
  223. this.reviewQueryParams.tenantId = this.technicianDetail.id
  224. this.getReview(this.reviewQueryParams.fraction)
  225. if (res.result.msgTechnician.images == '') { //如果用户没有上传个人相册,那么这里给个默认值
  226. this.technicianImages = ['/static/technician/album.png']
  227. } else {
  228. this.technicianImages = res.result.msgTechnician.images.split(',')
  229. }
  230. this.projectList = res.result.list
  231. }
  232. })
  233. },
  234. back() {
  235. uni.switchTab({
  236. url: '/pages/index/technician'
  237. })
  238. },
  239. toPayOrder(item) {
  240. if (this.technicianDetail.bookable != 'Y') {
  241. return uni.showToast({
  242. title: '技师未开启接单',
  243. icon: 'none'
  244. })
  245. }
  246. this.$api('createVipOrder', {
  247. projectId: item.id,
  248. technicianId: this.$route.query.id
  249. }, res => {
  250. if (res.code == 200) {
  251. if (res.code == 200) {
  252. let {
  253. distance,
  254. id,
  255. setKmOpen
  256. } = this.$route.query
  257. uni.navigateTo({ //setKmOpen 是否开启假距离 distance 距离信息
  258. url: `/pages/order/payOrder?orderId=${res.result.id}&distance=${distance}&id=${id}&current=technicianDetail&setKmOpen=${setKmOpen}`
  259. })
  260. }
  261. }
  262. })
  263. },
  264. addCollect(tenId) { //新增收藏
  265. this.$api('addCollect', {
  266. tenId
  267. }, res => {
  268. if (res.code == 200) {
  269. uni.showToast({
  270. title: '收藏成功',
  271. icon: 'none'
  272. })
  273. this.getTechnicianDetail()
  274. }
  275. })
  276. },
  277. //放大显示图片
  278. showImage(imgUrl) {
  279. if(imgUrl){
  280. showImagePreview({
  281. images: [imgUrl],
  282. closeable: true,
  283. });
  284. }
  285. },
  286. //选择了评论
  287. selectReview(index) {
  288. this.reviewQueryParams.fraction = index;
  289. this.reviewQueryParams.pageSize + 10;
  290. this.getReview(index)
  291. },
  292. //获取评论
  293. getReview(index) {
  294. this.loading = true
  295. this.$api('getCommentList', this.reviewQueryParams, res => {
  296. if (res.code == 200) {
  297. this.reviewList = res.result;
  298. // if(res.result.total > this.queryParams.pageSize){
  299. // this.finished = true;
  300. // }
  301. this.finished = true;
  302. this.loading = false;
  303. if (index > -1) {
  304. let list = ['goodReputationNum', 'mediumReviewNum', 'negativeComment']
  305. let a = list[index];
  306. this[a] = res.result.length
  307. }
  308. }
  309. })
  310. },
  311. //滑动到屏幕底部
  312. onLoad(){
  313. console.log('触发');
  314. this.queryParams.pageSize += 10;
  315. this.getReview()
  316. }
  317. }
  318. }
  319. </script>
  320. <style scoped lang="scss">
  321. .technician-Detail {
  322. width: 750rpx;
  323. background: #F5F5F5;
  324. margin: 0 auto;
  325. .technician-Detail-Top {
  326. background-color: var(--van-primary-color);
  327. ::v-deep .van-nav-bar__title {
  328. color: #fff;
  329. }
  330. ::v-deep i {
  331. color: #fff;
  332. }
  333. }
  334. .technician-Detail-img {
  335. position: relative;
  336. max-height: 900rpx;
  337. overflow: hidden;
  338. .my-swipe .van-swipe-item {
  339. color: #fff;
  340. font-size: 20px;
  341. line-height: 150px;
  342. text-align: center;
  343. }
  344. .custom-indicator {
  345. position: absolute;
  346. right: 15rpx;
  347. bottom: 80rpx;
  348. padding: 5rpx 10rpx;
  349. font-size: 20rpx;
  350. background: rgba(0, 0, 0, 0.1);
  351. }
  352. .technician-Detail-img-text {
  353. display: flex;
  354. align-items: center;
  355. justify-content: center;
  356. position: absolute;
  357. left: 0;
  358. bottom: 0;
  359. width: 100%;
  360. height: 80rpx;
  361. background: rgba(255, 255, 255, .6);
  362. color: #4E4E50;
  363. }
  364. }
  365. .techni-content {
  366. width: calc(100% - 40rpx);
  367. margin: 10rpx 20rpx 0rpx 20rpx;
  368. .userInfo {
  369. display: flex;
  370. background: white;
  371. border-radius: 10rpx;
  372. box-sizing: border-box;
  373. padding: 20rpx 10rpx 0rpx 10rpx;
  374. color: #666666;
  375. .img-box {
  376. width: 120rpx;
  377. height: 120rpx;
  378. overflow: hidden;
  379. border-radius: 50%;
  380. &::v-deep div {
  381. background-position: center top !important;
  382. background-size: 100% !important;
  383. }
  384. image {
  385. width: 120rpx;
  386. height: 120rpx;
  387. }
  388. }
  389. .base-info {
  390. display: flex;
  391. flex-direction: column;
  392. justify-content: space-between;
  393. box-sizing: border-box;
  394. padding-left: 15rpx;
  395. width: calc(100% - 120rpx);
  396. .username-tag {
  397. display: flex;
  398. align-items: center;
  399. .username {
  400. margin-right: 5rpx;
  401. color: #333333;
  402. font-size: 26rpx;
  403. }
  404. .tag {
  405. position: relative;
  406. display: flex;
  407. align-items: center;
  408. image {
  409. height: 45rpx;
  410. width: 90rpx;
  411. vertical-align: middle;
  412. }
  413. .auth {
  414. position: absolute;
  415. white-space: nowrap;
  416. color: #FF6200;
  417. left: 23rpx;
  418. font-size: 17rpx;
  419. }
  420. }
  421. }
  422. .build {
  423. display: flex;
  424. align-items: center;
  425. .sex {
  426. width: 25rpx;
  427. height: 25rpx;
  428. image {
  429. width: 100%;
  430. height: 100%;
  431. }
  432. }
  433. .real-name {
  434. display: flex;
  435. align-items: center;
  436. padding: 0rpx 3rpx;
  437. border: 1px solid #3484E8;
  438. color: #3484E8;
  439. font-size: 22rpx;
  440. image {
  441. width: 18rpx;
  442. height: 18rpx;
  443. }
  444. }
  445. >view {
  446. border-right: 1px solid #ccc;
  447. padding: 0rpx 8rpx;
  448. &:nth-child(1) {
  449. padding-left: 0;
  450. }
  451. &:nth-last-child(2) {
  452. border-right: none;
  453. }
  454. }
  455. }
  456. .service-experience {
  457. display: flex;
  458. .experience {
  459. color: #ED9044;
  460. margin-right: 20rpx;
  461. }
  462. .service-num {}
  463. }
  464. }
  465. }
  466. .service-description {
  467. display: flex;
  468. background: white;
  469. justify-content: space-between;
  470. padding: 30rpx 10rpx;
  471. .sesc-item {
  472. display: flex;
  473. color: #FFD777;
  474. image {
  475. width: 30rpx;
  476. height: 30rpx;
  477. }
  478. }
  479. }
  480. .line {
  481. padding: 0rpx 10rpx;
  482. background: white;
  483. view {
  484. border-bottom: 2px dashed #EBE7E7;
  485. }
  486. }
  487. .text {
  488. background: white;
  489. box-sizing: border-box;
  490. padding: 10rpx 10rpx 30rpx 10rpx;
  491. border-bottom-left-radius: 10rpx;
  492. border-bottom-right-radius: 10rpx;
  493. }
  494. .review {
  495. padding: 0rpx 20rpx 40rpx 20rpx;
  496. .review-title {
  497. padding: 25rpx 20rpx;
  498. font-size: 32rpx;
  499. font-weight: 500;
  500. }
  501. .review-classify {
  502. display: flex;
  503. padding: 30rpx 0rpx 30rpx 0rpx;
  504. .review-classify-item {
  505. background: #EEEDED;
  506. padding: 5rpx 15rpx;
  507. border-radius: 5rpx;
  508. margin-right: 15rpx;
  509. color: #666;
  510. }
  511. .select-classify {
  512. background: #ECFCF1;
  513. color: #55B16E;
  514. }
  515. }
  516. }
  517. }
  518. .ServicesAvailable {
  519. margin-top: 10px;
  520. border-radius: 5px;
  521. background-color: #fff;
  522. padding: 10px 0px;
  523. font-size: 16px;
  524. view {
  525. border-left: 4px outset #55B16E;
  526. margin-left: 10px;
  527. padding-left: 10px;
  528. }
  529. }
  530. .tabs {
  531. margin-top: 20rpx;
  532. &::v-deep .van-tabs__wrap {
  533. border-radius: 10rpx;
  534. }
  535. }
  536. .server-list {
  537. padding-bottom: 80rpx;
  538. .server-item {
  539. display: flex;
  540. flex-wrap: wrap;
  541. justify-content: space-between;
  542. background: white;
  543. border-radius: 15rpx;
  544. box-sizing: border-box;
  545. padding: 15rpx;
  546. margin: 20rpx 0rpx;
  547. .img-box {
  548. width: 150rpx;
  549. height: 150rpx;
  550. border-radius: 10rpx;
  551. overflow: hidden;
  552. image {
  553. width: 100%;
  554. height: 100%;
  555. }
  556. }
  557. .server-info {
  558. display: flex;
  559. flex-direction: column;
  560. justify-content: space-around;
  561. width: calc(100% - 330rpx);
  562. box-sizing: border-box;
  563. padding: 0 10rpx;
  564. .server-title {}
  565. .time-coupon,
  566. .price {
  567. display: flex;
  568. flex-wrap: wrap;
  569. align-items: center;
  570. }
  571. .time-coupon {
  572. font-size: 26rpx;
  573. image {
  574. width: 22rpx;
  575. height: 22rpx;
  576. }
  577. .time {
  578. color: #B8B8B8;
  579. margin-left: 6rpx;
  580. }
  581. .coupon {
  582. display: flex;
  583. justify-content: center;
  584. align-items: center;
  585. background: #F29E45;
  586. color: white;
  587. width: 140rpx;
  588. height: 45rpx;
  589. border-radius: 10rpx;
  590. margin-left: 10rpx;
  591. }
  592. }
  593. .price {
  594. display: flex;
  595. align-items: center;
  596. color: #B8B8B8;
  597. .current-price {
  598. font-size: 30rpx;
  599. font-weight: 600;
  600. color: #D34430;
  601. margin-right: 5rpx;
  602. }
  603. .unit {
  604. font-size: 20rpx;
  605. }
  606. }
  607. .sales-volume {
  608. display: flex;
  609. align-items: center;
  610. color: #B8B8B8;
  611. font-size: 26rpx;
  612. image {
  613. width: 23rpx;
  614. height: 23rpx;
  615. }
  616. }
  617. }
  618. .selective-technician {
  619. display: flex;
  620. flex-wrap: wrap;
  621. align-items: center;
  622. width: 170rpx;
  623. .btn {
  624. display: flex;
  625. align-items: center;
  626. justify-content: center;
  627. height: 60rpx;
  628. width: 170rpx;
  629. border-radius: 40rpx;
  630. color: white;
  631. background: linear-gradient(170deg, #53CEAC, #5AC796);
  632. }
  633. .notAvailable {
  634. background: #ccc;
  635. }
  636. }
  637. }
  638. }
  639. .health-certificate {
  640. padding-bottom: 80rpx;
  641. .health-certificate-main {
  642. margin: 15rpx 0rpx 30rpx 0rpx;
  643. background: white;
  644. min-height: 30vh;
  645. border-radius: 10rpx;
  646. box-sizing: border-box;
  647. padding: 15rpx;
  648. }
  649. }
  650. .colleact-info {
  651. display: flex;
  652. justify-content: space-between;
  653. font-size: 28rpx;
  654. align-items: center;
  655. height: 60rpx;
  656. .selective-technician {
  657. display: flex;
  658. flex-wrap: wrap;
  659. align-items: center;
  660. .btn {
  661. display: flex;
  662. align-items: center;
  663. justify-content: center;
  664. height: 50rpx;
  665. width: 170rpx;
  666. border-radius: 40rpx;
  667. color: white;
  668. background: linear-gradient(170deg, #53CEAC, #5AC796);
  669. }
  670. }
  671. }
  672. }
  673. </style>