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

10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
9 months ago
10 months ago
3 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 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 = this.technicianDetail.image ? this.technicianDetail.image.split(',') : []
  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>