湘妃到家前端代码仓库
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.
 
 
 
 
 

765 lines
17 KiB

<template>
<view class="technician-Detail">
<van-nav-bar class="technician-Detail-Top" title="技师详情" left-arrow @click-left="back" safe-area-inset-top />
<view class="technician-Detail-img">
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
<van-swipe-item v-for="(item,index) in technicianImages" :key="index">
<image :src="item" style="width: 100%;" mode="widthFix"></image>
</van-swipe-item>
<template #indicator="{ active, total }">
<!-- <div class="custom-indicator">{{ active + 1 }}/{{ total }}</div> -->
</template>
</van-swipe>
<view class="technician-Detail-img-text">下单付款后商家会在10分钟内联系你哦~</view>
</view>
<view class="techni-content">
<view class="userInfo">
<view class="img-box">
<image @click="showImage(technicianDetail.image)" :src="technicianDetail.image" mode="aspectFill">
</image>
</view>
<view class="base-info">
<view class="username-tag">
<view class="username">{{ technicianDetail.title }}</view>
<view v-if="technicianDetail.isVip" class="tag">
<image src="@/static/order/s.png" mode="aspectFit"></image>
<view class="auth">官方认证</view>
</view>
</view>
<view class="build">
<view class="sex">
<image src="../../static/technician/sex.png" mode="aspectFit"></image>
</view>
<view class="address">
{{ technicianDetail.area }}
</view>
<view class="cm">
{{ technicianDetail.cm }}
</view>
<view class="weight">
{{ technicianDetail.kg /2 }}kg
</view>
<view class="real-name">
<image src="../../static/technician/real-name.png" mode="aspectFit"></image>
<view class="desc">实名</view>
</view>
</view>
<view class="service-experience">
<view class="experience">
{{ technicianDetail.experience }}年经验
</view>
<view class="service-num">
近期服务过{{ technicianDetail.isFw }}次
</view>
</view>
</view>
</view>
<view class="view">
<view class="service-description">
<div v-for="item in serviceDescList" class="sesc-item">
<image src="../../static/technician/desc.png" mode="aspectFit"></image>
<view>{{ item }}</view>
</div>
</view>
</view>
<view class="line">
<view></view>
</view>
<view class="text">
<div class="colleact-info">
<view style="color: #454545;">个人介绍</view>
<view v-if="collect == 0" class="selective-technician">
<view @click.stop="addCollect(technicianDetail.id)" class="btn">
立即收藏
</view>
</view>
</div>
<view style="color: #A1A1A1; margin-top: 5px;">
{{ technicianDetail.notes }}
</view>
</view>
<!-- <view class="ServicesAvailable">
<view>服务项目</view>
</view> -->
<van-tabs class="tabs" v-model:active="activeTag">
<van-tab title="服务项目">
<van-empty v-if="projectList.length <= 0" image="/static/empty/message-list.png" image-size="400rpx"
description="暂无服务" />
<view v-else class="server-list">
<view v-for="item in projectList" class="server-item" @click="toPayOrder(item)">
<view class="img-box">
<image :src="item.image" mode="aspectFill"></image>
</view>
<view class="server-info">
<view class="server-title">{{ item.title }}</view>
<view class="time-coupon">
<image src="@/static/home/time-icon.png"></image>
<view class="time">{{ item.times }}分钟</view>
<!-- <view class="coupon">{{ item.subTitle }}</view> -->
</view>
<view class="price">
<view class="current-price">
<text class="unit">¥</text>{{ item.price }}
</view>
<view class="original-price">
<text class="unit">¥</text>{{ item.oldPrice }}
</view>
</view>
<view class="sales-volume">
<image src="@/static/icons/icon1.png"></image>
<view class="desc">已售出{{ item.payNum }}+单</view>
</view>
</view>
<view class="selective-technician">
<view @click.stop="toPayOrder(item)"
:class="{ notAvailable : technicianDetail.bookable != 'Y' }" class="btn">
{{ technicianDetail.bookable == 'Y' ? '立即预约' : '不可预约' }}
</view>
</view>
</view>
</view>
</van-tab>
<van-tab title="健康证">
<view class="health-certificate">
<van-empty v-if="!technicianDetail.healthCertificate" image="/static/empty/order.png" image-size="400rpx"
description="技师暂未上传健康证" />
<view v-else class="health-certificate-main">
<image @click="showImage(technicianDetail.healthCertificate)"
:src="technicianDetail.healthCertificate" mode="widthFix" style="width: 100%;"></image>
</view>
</view>
</van-tab>
<van-tab title="营业证">
<view class="health-certificate">
<van-empty v-if="!technicianDetail.businessLicense" image="/static/empty/order.png" image-size="400rpx"
description="技师暂未上传健康证" />
<view v-else class="health-certificate-main">
<image @click="showImage(technicianDetail.businessLicense)"
:src="technicianDetail.businessLicense" mode="widthFix" style="width: 100%;"></image>
</view>
</view>
</van-tab>
<van-tab title="用户评论">
<view class="review bg-white mar-10 box-s">
<!-- <view class="review-title">用户评论({{ countReviewNum }}+条)</view> -->
<view class="review-classify">
<view @click="selectReview(0)" class="review-classify-item"
:class="{'select-classify' : reviewQueryParams.fraction == 0}">
好评
<text class="num">{{ goodReputationNum }}</text>
</view>
<view @click="selectReview(1)" class="review-classify-item"
:class="{'select-classify' : reviewQueryParams.fraction == 1}">
中评
<text class="num">{{ mediumReviewNum }}</text>
</view>
<view @click="selectReview(2)" class="review-classify-item"
:class="{'select-classify' : reviewQueryParams.fraction == 2}">
差评
<text class="num">{{ negativeComment }}</text>
</view>
</view>
<van-list v-if="reviewList.length > 0" v-model:loading="loading" :finished="finished"
finished-text="没有更多了" @load="onLoad">
<reviewListVue :list="reviewList"></reviewListVue>
</van-list>
<van-empty v-else image="/static/empty/record.png" image-size="400rpx" description="暂无评论" />
</view>
</van-tab>
</van-tabs>
</view>
</view>
</template>
<script>
import {
showImagePreview
} from 'vant';
import reviewListVue from '@/components/review/reviewList/reviewList.vue'
export default {
components : { reviewListVue },
data() {
return {
searchKeyword: '',
technicianDetail: {},
projectList: [],
queryParams: {
pageNo: 1,
pageSize: 100,
fraction: 0
},
loading: false,
finished: false,
serviceDescList: ['实名认证', '头像认证', '健康证', '按摩师证'],
collect: 0,
technicianImages: [],
activeTag: 0,
goodReputationNum: 0, //好评数量
mediumReviewNum: 0, //中评数量
negativeComment: 0, //差评数量
countReviewNum: 0, //总评论条数
reviewList: [],
reviewQueryParams: {
pageNo: 1,
pageSize: 10,
fraction: 0,
tenantId : '',
// projectId : '1797549059400646658',
type : 0
},
}
},
onShow() {
this.getTechnicianDetail()
},
methods: {
//获取技师详情
getTechnicianDetail() {
this.$api('getTechnicianDetail', {
id: this.$route.query.id
}, res => {
if (res.code == 200) {
this.collect = res.result.collect
this.technicianDetail = res.result.msgTechnician
this.reviewQueryParams.tenantId = this.technicianDetail.id
this.getReview(this.reviewQueryParams.fraction)
if (!res.result.msgTechnician.images) { //如果用户没有上传个人相册,那么这里给个默认值
this.technicianImages = this.technicianDetail.image ? this.technicianDetail.image.split(',') : []
} else {
this.technicianImages = res.result.msgTechnician.images.split(',')
}
this.projectList = res.result.list
}
})
},
back() {
uni.switchTab({
url: '/pages/index/technician'
})
},
toPayOrder(item) {
if (this.technicianDetail.bookable != 'Y') {
return uni.showToast({
title: '技师未开启接单',
icon: 'none'
})
}
this.$api('createVipOrder', {
projectId: item.id,
technicianId: this.$route.query.id
}, res => {
if (res.code == 200) {
if (res.code == 200) {
let {
distance,
id,
setKmOpen
} = this.$route.query
uni.navigateTo({ //setKmOpen 是否开启假距离 distance 距离信息
url: `/pages/order/payOrder?orderId=${res.result.id}&distance=${distance}&id=${id}&current=technicianDetail&setKmOpen=${setKmOpen}`
})
}
}
})
},
addCollect(tenId) { //新增收藏
this.$api('addCollect', {
tenId
}, res => {
if (res.code == 200) {
uni.showToast({
title: '收藏成功',
icon: 'none'
})
this.getTechnicianDetail()
}
})
},
//放大显示图片
showImage(imgUrl) {
if(imgUrl){
showImagePreview({
images: [imgUrl],
closeable: true,
});
}
},
//选择了评论
selectReview(index) {
this.reviewQueryParams.fraction = index;
this.reviewQueryParams.pageSize + 10;
this.getReview(index)
},
//获取评论
getReview(index) {
this.loading = true
this.$api('getCommentList', this.reviewQueryParams, res => {
if (res.code == 200) {
this.reviewList = res.result;
// if(res.result.total > this.queryParams.pageSize){
// this.finished = true;
// }
this.finished = true;
this.loading = false;
if (index > -1) {
let list = ['goodReputationNum', 'mediumReviewNum', 'negativeComment']
let a = list[index];
this[a] = res.result.length
}
}
})
},
//滑动到屏幕底部
onLoad(){
console.log('触发');
this.queryParams.pageSize += 10;
this.getReview()
}
}
}
</script>
<style scoped lang="scss">
.technician-Detail {
width: 750rpx;
background: #F5F5F5;
margin: 0 auto;
.technician-Detail-Top {
background-color: var(--van-primary-color);
::v-deep .van-nav-bar__title {
color: #fff;
}
::v-deep i {
color: #fff;
}
}
.technician-Detail-img {
position: relative;
max-height: 900rpx;
overflow: hidden;
.my-swipe .van-swipe-item {
color: #fff;
font-size: 20px;
line-height: 150px;
text-align: center;
}
.custom-indicator {
position: absolute;
right: 15rpx;
bottom: 80rpx;
padding: 5rpx 10rpx;
font-size: 20rpx;
background: rgba(0, 0, 0, 0.1);
}
.technician-Detail-img-text {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 80rpx;
background: rgba(255, 255, 255, .6);
color: #4E4E50;
}
}
.techni-content {
width: calc(100% - 40rpx);
margin: 10rpx 20rpx 0rpx 20rpx;
.userInfo {
display: flex;
background: white;
border-radius: 10rpx;
box-sizing: border-box;
padding: 20rpx 10rpx 0rpx 10rpx;
color: #666666;
.img-box {
width: 120rpx;
height: 120rpx;
overflow: hidden;
border-radius: 50%;
&::v-deep div {
background-position: center top !important;
background-size: 100% !important;
}
image {
width: 120rpx;
height: 120rpx;
}
}
.base-info {
display: flex;
flex-direction: column;
justify-content: space-between;
box-sizing: border-box;
padding-left: 15rpx;
width: calc(100% - 120rpx);
.username-tag {
display: flex;
align-items: center;
.username {
margin-right: 5rpx;
color: #333333;
font-size: 26rpx;
}
.tag {
position: relative;
display: flex;
align-items: center;
image {
height: 45rpx;
width: 90rpx;
vertical-align: middle;
}
.auth {
position: absolute;
white-space: nowrap;
color: #FF6200;
left: 23rpx;
font-size: 17rpx;
}
}
}
.build {
display: flex;
align-items: center;
.sex {
width: 25rpx;
height: 25rpx;
image {
width: 100%;
height: 100%;
}
}
.real-name {
display: flex;
align-items: center;
padding: 0rpx 3rpx;
border: 1px solid #3484E8;
color: #3484E8;
font-size: 22rpx;
image {
width: 18rpx;
height: 18rpx;
}
}
>view {
border-right: 1px solid #ccc;
padding: 0rpx 8rpx;
&:nth-child(1) {
padding-left: 0;
}
&:nth-last-child(2) {
border-right: none;
}
}
}
.service-experience {
display: flex;
.experience {
color: #ED9044;
margin-right: 20rpx;
}
.service-num {}
}
}
}
.service-description {
display: flex;
background: white;
justify-content: space-between;
padding: 30rpx 10rpx;
.sesc-item {
display: flex;
color: #FFD777;
image {
width: 30rpx;
height: 30rpx;
}
}
}
.line {
padding: 0rpx 10rpx;
background: white;
view {
border-bottom: 2px dashed #EBE7E7;
}
}
.text {
background: white;
box-sizing: border-box;
padding: 10rpx 10rpx 30rpx 10rpx;
border-bottom-left-radius: 10rpx;
border-bottom-right-radius: 10rpx;
}
.review {
padding: 0rpx 20rpx 40rpx 20rpx;
.review-title {
padding: 25rpx 20rpx;
font-size: 32rpx;
font-weight: 500;
}
.review-classify {
display: flex;
padding: 30rpx 0rpx 30rpx 0rpx;
.review-classify-item {
background: #EEEDED;
padding: 5rpx 15rpx;
border-radius: 5rpx;
margin-right: 15rpx;
color: #666;
}
.select-classify {
background: #ECFCF1;
color: #55B16E;
}
}
}
}
.ServicesAvailable {
margin-top: 10px;
border-radius: 5px;
background-color: #fff;
padding: 10px 0px;
font-size: 16px;
view {
border-left: 4px outset #55B16E;
margin-left: 10px;
padding-left: 10px;
}
}
.tabs {
margin-top: 20rpx;
&::v-deep .van-tabs__wrap {
border-radius: 10rpx;
}
}
.server-list {
padding-bottom: 80rpx;
.server-item {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
background: white;
border-radius: 15rpx;
box-sizing: border-box;
padding: 15rpx;
margin: 20rpx 0rpx;
.img-box {
width: 150rpx;
height: 150rpx;
border-radius: 10rpx;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.server-info {
display: flex;
flex-direction: column;
justify-content: space-around;
width: calc(100% - 330rpx);
box-sizing: border-box;
padding: 0 10rpx;
.server-title {}
.time-coupon,
.price {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.time-coupon {
font-size: 26rpx;
image {
width: 22rpx;
height: 22rpx;
}
.time {
color: #B8B8B8;
margin-left: 6rpx;
}
.coupon {
display: flex;
justify-content: center;
align-items: center;
background: #F29E45;
color: white;
width: 140rpx;
height: 45rpx;
border-radius: 10rpx;
margin-left: 10rpx;
}
}
.price {
display: flex;
align-items: center;
color: #B8B8B8;
.current-price {
font-size: 30rpx;
font-weight: 600;
color: #D34430;
margin-right: 5rpx;
}
.unit {
font-size: 20rpx;
}
}
.sales-volume {
display: flex;
align-items: center;
color: #B8B8B8;
font-size: 26rpx;
image {
width: 23rpx;
height: 23rpx;
}
}
}
.selective-technician {
display: flex;
flex-wrap: wrap;
align-items: center;
width: 170rpx;
.btn {
display: flex;
align-items: center;
justify-content: center;
height: 60rpx;
width: 170rpx;
border-radius: 40rpx;
color: white;
background: linear-gradient(170deg, #53CEAC, #5AC796);
}
.notAvailable {
background: #ccc;
}
}
}
}
.health-certificate {
padding-bottom: 80rpx;
.health-certificate-main {
margin: 15rpx 0rpx 30rpx 0rpx;
background: white;
min-height: 30vh;
border-radius: 10rpx;
box-sizing: border-box;
padding: 15rpx;
}
}
.colleact-info {
display: flex;
justify-content: space-between;
font-size: 28rpx;
align-items: center;
height: 60rpx;
.selective-technician {
display: flex;
flex-wrap: wrap;
align-items: center;
.btn {
display: flex;
align-items: center;
justify-content: center;
height: 50rpx;
width: 170rpx;
border-radius: 40rpx;
color: white;
background: linear-gradient(170deg, #53CEAC, #5AC796);
}
}
}
}
</style>