mrr.sj.front/pages/shop/service-detail.nvue

1015 lines
22 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="detail-page">
<!-- 使用自定义导航栏 -->
<custom-navbar title="服务详情" :show-back="true" :showUser="false" titleColor="#000"></custom-navbar>
<!-- 主图区域 banner -->
<view class="main-image-section">
<swiper class="banner-swiper" circular :indicator-dots="false" :autoplay="false" :interval="3000"
:duration="500" indicator-active-color="#fff" indicator-color="rgba(255, 255, 255, 0.6)">
<swiper-item v-if="serviceInfo.video">
<video :src="serviceInfo.video" v-if="serviceInfo.video && showVideo" id="myVideo"
class="banner-image" :autoplay="true" :controls="false" :muted="isMuted"
:enable-progress-gesture="false" :loop="true" object-fit="cover">
</video>
<view class="video-controls">
<!-- <view class="control-btn" @click="togglePlay">
<image :src="isPlaying ? '/static/images/pause.png' : '/static/images/play.png'" class="control-icon"></image>
</view> -->
<view class="control-btn" @click="toggleMute">
<image :src="isMuted ? '/static/images/mute.png' : '/static/images/unmute.png'"
class="control-icon"></image>
</view>
</view>
<text class="banner-tag">{{1}}/{{serviceInfo.photo.length + 1}}</text>
</swiper-item>
<swiper-item v-for="(item, index) in serviceInfo.photo" :key="index"
@click="previewImage(serviceInfo.photo, index)">
<image :src="item" mode="aspectFill" class="banner-image" referrer="no-referrer"></image>
<text class="banner-tag"
v-if="serviceInfo.video">{{index+2}}/{{serviceInfo.photo.length + 1}}</text>
<text class="banner-tag" v-else>{{index+1}}/{{serviceInfo.photo.length}}</text>
</swiper-item>
</swiper>
</view>
<!-- 服务信息 -->
<view class="service-info">
<view class="service-price">
<text class="price-symbol">¥</text>
<text class="price-value">{{serviceInfo.server_price}}</text>
</view>
<view class="service-title">
<text
class="service-type">{{serviceInfo.server_kind == 1 ? '到家' : serviceInfo.server_kind == 2 ? '到店' : ''}}</text>
<text class="title-text">{{serviceInfo.title}}</text>
</view>
<!-- <view class="service-tabs">
<text class="tab-item">简约</text>
<text class="tab-item">百搭</text>
<text class="tab-item">显白</text>
<text class="tab-item">春夏流行色</text>
</view> -->
<view class="service-shop" v-if="serviceInfo.server_kind == 2">
<view class="shop-info">
<image class="shop-logo" :src="serviceInfo.shop_head_photo" mode="aspectFill"
@click="goShopHome(serviceInfo.publish_user_id)"></image>
<view class="shop-info-you">
<text class="shop-name">{{serviceInfo.shop_name}}</text>
<view class="stars"></view>
<view class="shop-class-w">
<text class="shop-class">主营:{{serviceInfo.shop_class.substr(1)}}</text>
</view>
<text class="shop-time">营业时间:{{serviceInfo.shop_business_time}}</text>
</view>
</view>
<view class="shop-cont">
<view class="shop-cont-left">
<view>
<text
class="shop-address">{{serviceInfo.shop_dependency}}{{serviceInfo.shop_address}}</text>
</view>
<view>
<text class="shop-tell">电话:{{serviceInfo.phone}}</text>
</view>
<!-- <text class="shop-distance">距您4.2km</text> -->
</view>
<view class="shop-cont-right">
<image src="/static/images/go_map.png" class="shop-headle" mode="aspectFit" @click="openMap">
</image>
<image src="/static/images/go_phone.png" class="shop-headle" mode="aspectFit"
@click="goContact(serviceInfo.phone)"></image>
</view>
</view>
</view>
</view>
<!-- 到家地址以及服务时间 -->
<!-- <view class="user-choice" v-if="serviceInfo.server_kind == 1">
<view class="choice-item" @click="goAddressList">
<text class="choice-tit">到家地址</text>
<view class="choice-cont">
<view class="address-left">
<image src="/static/images/position_icon.png" class="address-icon" mode=""></image>
<text class="choice-text">玉琢礼小区</text>
</view>
<image src="/static/images/arrow_right.png" class="enter-icon" mode="aspectFit"></image>
</view>
</view>
<view class="choice-item">
<text class="choice-tit">服务时间</text>
<view class="choice-cont">
<text class="choice-text">三天内可预约</text>
<image src="/static/images/arrow_right.png" class="enter-icon" mode="aspectFit"></image>
</view>
</view>
</view> -->
<!-- 评论区域 -->
<!-- <view class="comments-section">
<view class="section-title">
<text class="section-num">评价({{comments.length}})</text>
<view class="look-all">
<text class="look">查看全部</text>
<image src="/static/images/arrow_right.png" class="enter-icon" mode="aspectFit"></image>
</view>
</view>
<view class="comment-list">
<view class="comment-item" v-for="(item, index) in comments" :key="index">
<view class="comment-left">
<view class="comment-header">
<image :src="item.avatar" class="user-avatar"></image>
<view class="comment-user-info">
<text class="user-name">{{item.userName}}</text>
<view class="user-two">
<text class="comment-tab">{{item.tab}}</text>
<text class="comment-type">{{item.type}}</text>
</view>
</view>
</view>
<text class="comment-content text-overflow">{{item.content}}</text>
</view>
<view class="comment-images" v-if="item.images && item.images.length">
<image
:src="item.images[0]"
mode="aspectFill"
class="comment-image"
></image>
</view>
</view>
</view>
</view> -->
<!-- 手艺人区域 -->
<view class="service-syr" v-if="serviceInfo.server_kind == 1">
<image class="syr-head" v-if="syrInfo.head_photo" :src="syrInfo.head_photo" mode="aspectFill"></image>
<view class="syr-info">
<text class="syr-name">{{syrInfo.name}}</text>
</view>
<view class="look-btn" @click="goSyrHome(serviceInfo.publish_user_id)">
<text class="look-text">进入逛逛</text>
</view>
</view>
<!-- 项目说明 -->
<view class="notice-section">
<view class="section-title">
<text class="section-tit">项目说明</text>
</view>
<view class="notice-content">
<view class="notice-cont">
<text class="notice-title">
服务时长:
</text>
<text class="notice-text">
{{serviceInfo.server_time}}分钟
</text>
</view>
<view class="notice-cont" v-for="(item,i) in serviceInfo.detail">
<text class="notice-title">
{{item.title}}
</text>
<text class="notice-text">
{{item.text}}
</text>
</view>
</view>
</view>
<!-- 步骤 -->
<view class="notice-section">
<view class="section-title">
<text class="section-tit">项目步骤</text>
</view>
<view class="notice-content">
<view class="notice-cont" v-for="(item,i) in serviceInfo.process">
<text class="notice-title">
{{item.title}}
</text>
<text class="notice-text">
{{item.text}}
</text>
</view>
</view>
</view>
<!-- 订购须知 -->
<view class="notice-section">
<view class="section-title">
<text class="section-tit">订购须知</text>
<!-- <view class="section-tit-right">
<text class="rule-text">取消、退款、赔付规则</text>
<image src="/static/images/arrow_right.png" class="enter-icon" mode="aspectFit"></image>
</view> -->
</view>
<view class="notice-content">
<text class="notice-text">
{{serviceInfo.purchasenotes}}
</text>
</view>
</view>
<!-- 底部按钮 -->
<view class="bottom-bar">
<!-- <view class="lianxi" @click="goContact(serviceInfo.phone)">
<image src="/static/images/tell_icon.png" class="lianxi-icon" mode=""></image>
<text class="lianxi-text">联系TA</text>
</view> -->
<view class="submit-btn" @click="submitOrder"
:class="syrInfo.order_taking == 2 || sjInfo.order_taking == 2 ? 'cannot-submit' : ''">
<text class="btn-text">立即预约</text>
</view>
</view>
<!-- 获取权限提示匡内容 -->
<view class="permission" :class="{ transform: isShowPer }">
<text class="per-tit">美融融plus 对拨打电话权限申请说明</text>
<text class="per-cont">当您需要联系商家或平台客服的时候,需要获取拨打电话权限。</text>
</view>
</view>
</template>
<script>
import request from '../../utils/request'
import CustomNavbar from '@/components/custom-navbar/custom-navbar.vue'
import _public from '../../utils/public'
import locationService from '../../utils/locationService';
import permissionUtils from '../../utils/per'
export default {
components: {
CustomNavbar
},
data() {
return {
isShowPer: false,
showVideo: false,
time: '12:30',
date: '今天',
isMuted: true,
serviceInfo: {
"id": null,
"title": null,
"server_price": null,
"server_time": null,
"line_price": null,
"sales_num": 0,
"photo": [],
"video": null,
"first_class_id": null,
"second_class_id": null,
"detail": [],
"process": [],
"purchase_notes": null,
"publish_user_id": null,
"server_kind": null,
"state": null,
"add_time": null,
"approve_user_id": null,
"approve_time": null,
"is_hot": null,
"is_delete": null,
"doorto_price": null
},
syrInfo: {},
sjInfo: {},
videoContext: null,
// 评价
comments: [{
userName: '山河*明月',
avatar: '/static/images/avatar1.jpg',
time: '2024-01-20',
content: '工作非常专业,态度很好,第一次来,非常满意,下次还会来',
images: ['/static/images/comment1.jpg', '/static/images/comment2.jpg'],
tab: '超出期待',
type: '双色法式美甲'
}]
}
},
onLoad(option) {
// Android可能需要延迟加载
request.post('/sj/serverdetail', {
id: option.id
}).then(async (res) => {
const sjdiscount = await request.post('/sj/getsjdiscount', {
id: res.data.first_class_id
});
res.data.server_price = _public.roundUpToTwoDecimals(Number(res.data.server_price), sjdiscount
.data.ratio)
this.getSyrDetail(res.data.publish_user_id)
if (uni.getSystemInfoSync().platform === 'android') {
this.$nextTick(() => {
this.serviceInfo = res.data;
});
} else {
this.serviceInfo = res.data;
}
})
},
mounted() {
this.videoContext = uni.createVideoContext('myVideo', this); // 绑定 video 实例
},
onShow() {
this.showVideo = true;
},
onHide() {
this.showVideo = false;
},
methods: {
// 获取手艺人详情
getSyrDetail(id) {
request.post('/sj/syrdetail', {
id
}).then(res => {
this.syrInfo = res.data;
}).catch(err => {
console.log(err)
})
},
// 跳转手艺人详情
goSyrHome(id) {
uni.navigateTo({
url: '/pages/shop/servicesyr-home?id=' + id
})
},
// 开启或关闭声音
toggleMute() {
this.isMuted = !this.isMuted;
},
previewImage(urls, current) {
uni.previewImage({
urls: urls,
current: current
})
},
submitOrder() {
console.log('点击了', this.syrInfo, this.sjInfo)
this.isLogin = uni.getStorageSync('accessToken') ? true : false;
if (!this.isLogin) {
uni.showModal({
title: '登录提醒',
content: '您暂未登录,无法预约服务,是否前去登录?',
confirmColor: '#F1AC66',
success(e) {
if (e.confirm) {
// uni.oprPresentLogin()
uni.navigateTo({
url: '/pages/blogPopup/blogPopup'
});
}
}
})
return;
};
if (this.syrInfo.order_taking == 2 || this.sjInfo.order_taking == 2) return;
uni.navigateTo({
url: '/pages/shop/create-order?id=' + this.serviceInfo.id
})
},
// 显示权限说明弹窗
showPermissionDialog(title, content) {
return new Promise((resolve) => {
uni.showModal({
title,
content,
confirmText: '去开启',
success(res) {
resolve(res.confirm);
}
});
});
},
async goContact(phone) {
// uni.navigateTo({
// url: '/pages/contact/contact?phone='+this.serviceInfo.phone
// })
const systemInfo = uni.getSystemInfoSync()
if (systemInfo.platform === 'ios') {
uni.makePhoneCall({
phoneNumber: phone //仅为示例
})
} else {
let permission = '';
if (systemInfo.platform === 'ios') {
permission = 'phone'
} else {
permission = 'android.permission.CALL_PHONE'
}
this.isShowPer = true;
const firstRequest = !plus.storage.getItem(`perm_${permission}`)
if (firstRequest) {
this.isShowPer = true;
}
// 1. 检查权限
const {
granted
} = await permissionUtils.checkPermission('phone', '需要拨打电话权限,方便您联系商家或平台');
if (granted) {
this.isShowPer = false;
uni.makePhoneCall({
phoneNumber: phone //仅为示例
})
return;
}
this.isShowPer = false;
// 2. 显示权限说明弹窗
const confirm = await this.showPermissionDialog(
'拨打电话权限申请',
'我们需要拨打电话权限,方便您联系商家或平台'
);
if (!confirm) return;
// 3. 请求权限
const result = await permissionUtils.requestPermission('phone', '需要拨打电话权限,方便您联系商家或平台');
console.log('result', result)
if (result) {
uni.makePhoneCall({
phoneNumber: phone //仅为示例
})
return;
} else {
locationService.openAppSettings();
return;
// uni.showToast({ title: '相机权限被拒绝', icon: 'none' });
}
}
},
// 打开手机已有地图
openMap() {
let that = this;
// #ifdef MP-WEIXIN
uni.openLocation({
success: function(res) {
console.log('打开系统位置地图成功');
},
fail: function(error) {
console.log(error);
}
});
// #endif
// #ifdef APP-PLUS
_public.goMap({
latitude: parseFloat(that.serviceInfo.latitude),
longitude: parseFloat(that.serviceInfo.longitude),
name: that.serviceInfo.shop_name,
address: that.serviceInfo.shop_address
})
// #endif
},
}
}
</script>
<style>
.detail-page {
padding-bottom: 120rpx;
}
/* 主图区域 */
.main-image-section {
position: relative;
width: 750rpx;
height: 750rpx;
background-color: #999;
}
.banner-swiper {
width: 750rpx;
height: 750rpx;
}
.banner-image {
width: 750rpx;
height: 750rpx;
}
.banner-tag {
font-size: 20rpx;
font-weight: 500;
color: #FFFFFF;
padding: 6rpx 12rpx;
background-color: rgba(0, 0, 0, 0.40);
position: absolute;
border-radius: 20rpx;
right: 26rpx;
bottom: 28rpx;
}
/* 服务信息 */
.user-choice,
.comments-section,
.notice-section {
background-color: #fff;
padding: 24rpx;
box-shadow: 0 0 12rpx 0 rgba(0, 0, 0, 0.05);
margin: 0 24rpx 24rpx;
border-radius: 16rpx;
}
.service-info {
margin: 20rpx 24rpx;
background-color: #fff;
box-shadow: 0 0 12rpx 0 rgba(0, 0, 0, 0.05);
padding-top: 24rpx;
border-radius: 16rpx;
}
.service-price {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
margin-bottom: 18rpx;
padding: 0 24rpx;
}
.price-symbol {
font-size: 24rpx;
color: #FF4767;
font-weight: 500;
margin-right: 2rpx;
}
.price-value {
font-size: 32rpx;
color: #FF4767;
font-weight: 500;
}
.service-title {
margin-bottom: 16rpx;
padding: 0 24rpx;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: flex-start;
}
.service-type {
font-size: 24rpx;
color: #FFFFFF;
background-color: #FF94B4;
padding: 2rpx 10rpx;
border-radius: 14rpx;
margin-right: 12rpx;
}
.title-text {
flex: 1;
font-size: 26rpx;
color: #333333;
font-weight: 500;
}
.service-tabs {
display: flex;
}
.tab-item {
height: 24rpx;
line-height: 24rpx;
font-size: 16rpx;
color: #999999;
background-color: #FFF2F2;
padding: 0 8rpx;
border-radius: 8rpx;
}
/* 到家地址以及可预约时间 */
.choice-item {
height: 90rpx;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.choice-tit {
font-size: 24rpx;
color: #999999;
margin-right: 16rpx;
}
.choice-cont {
flex: 1;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
}
.address-left {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.choice-text {
font-size: 24rpx;
color: #666666;
}
.address-icon {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
.enter-icon {
width: 24rpx;
height: 24rpx;
margin-left: 8rpx;
}
/* 手艺人区域 */
.service-syr {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
margin: 0 24rpx 24rpx;
background-color: #fff;
box-shadow: rgba(0, 0, 0, 0.05);
padding: 24rpx;
}
.syr-head {
width: 104rpx;
height: 104rpx;
border-radius: 54rpx;
margin-right: 10rpx;
}
.syr-info {
flex: 1;
}
.syr-name {
font-size: 28rpx;
color: #3D3D3D;
}
.look-btn {
width: 130rpx;
height: 56rpx;
border: 1rpx solid #FF4767;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
border-radius: 28rpx;
}
.look-text {
font-size: 28rpx;
color: #FF4767;
}
/* 评论区域 */
.section-title {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
}
.section-num {
font-size: 28rpx;
font-weight: 500;
color: #3D3D3D;
}
.look-all {
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
align-items: center;
}
.look {
font-size: 24rpx;
color: #666666;
}
.comment-item {
padding: 24rpx 0;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
}
.comment-item:last-child {
padding-bottom: 0rpx;
}
.comment-header {
display: flex;
align-items: center;
margin-bottom: 14rpx;
}
.user-avatar {
width: 64rpx;
height: 64rpx;
border-radius: 32rpx;
margin-right: 14rpx;
background-color: #000;
}
.comment-user-info {
flex: 1;
}
.user-name {
font-size: 28rpx;
color: #3D3D3D;
margin-bottom: 10rpx;
}
.comment-tab {
font-size: 16rpx;
padding: 0 8rpx;
border-radius: 12rpx;
color: #FF4767;
background-color: rgba(255, 148, 180, 0.50);
margin-right: 8rpx;
}
.comment-type {
font-size: 20rpx;
color: #999999;
}
.comment-content {
font-size: 22rpx;
color: #333333;
line-height: 1.5;
}
.comment-images {
width: 154rpx;
height: 154rpx;
background-color: #000;
margin-left: 56rpx;
}
.comment-image {
width: 160rpx;
height: 160rpx;
border-radius: 8rpx;
}
/* 购买须知 */
.section-tit {
font-size: 28rpx;
font-weight: 500;
color: #3D3D3D;
}
.section-tit-right {
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
align-items: center;
}
.rule-text {
font-size: 28rpx;
color: #D10F13;
}
.notice-item {
margin-bottom: 24rpx;
}
.notice-title {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.notice-content {
margin-top: 32rpx;
}
.notice-cont {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: flex-start;
margin-bottom: 16rpx;
}
.notice-cont:last-child {
margin-bottom: 0;
}
.notice-text {
flex: 1;
font-size: 26rpx;
color: #666;
}
/* 底部按钮 */
.bottom-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 104rpx;
background-color: #FFFFFF;
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: flex-end;
/* padding-bottom: env(safe-area-inset-bottom); */
border-top: 1rpx solid rgba(0, 0, 0, 0.10);
padding: 0 38rpx;
}
.lianxi {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
}
.lianxi-text {
font-size: 16rpx;
color: #666666;
}
.lianxi-icon {
width: 34rpx;
height: 34rpx;
margin-bottom: 10rpx;
}
.submit-btn {
width: 410rpx;
height: 64rpx;
background: #FF4767;
border-radius: 32rpx;
color: #FFFFFF;
font-size: 28rpx;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
margin-left: 146rpx;
}
.cannot-submit {
background-color: #999999;
}
.service-shop {}
.shop-info {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
padding: 0 24rpx 16rpx;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
}
.shop-logo {
width: 112rpx;
height: 136rpx;
background-color: #000;
margin-right: 20rpx;
}
.shop-info-you {
flex: 1;
display: flex;
flex-flow: column wrap;
justify-content: space-between;
align-items: flex-start;
}
.shop-name {
font-size: 28rpx;
color: #3D3D3D;
margin-bottom: 10rpx;
}
.shop-class-w {
width: 480rpx;
}
.shop-class {
margin-bottom: 8rpx;
}
.shop-class,
.shop-time {
font-size: 24rpx;
color: #666666;
}
.shop-cont {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
padding: 16rpx 24rpx;
}
.shop-cont-left {
display: flex;
flex-flow: column wrap;
justify-content: space-between;
align-items: flex-start;
}
.shop-cont-right {
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
align-items: center;
}
.shop-address,
.shop-tell {
width: 450rpx;
font-size: 24rpx;
color: #333333;
}
.shop-distance {
font-size: 24rpx;
color: #666666;
}
.shop-headle {
width: 40rpx;
height: 40rpx;
margin-left: 60rpx;
}
.video-controls {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 100rpx;
display: flex;
align-items: flex-start;
justify-content: center;
z-index: 3;
}
.control-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 30rpx;
margin: 0 20rpx;
}
.control-icon {
width: 40rpx;
height: 40rpx;
}
/* H5适配 */
/* #ifdef H5 */
.bottom-bar {
padding-bottom: 0;
}
/* #endif */
/* APP适配 */
/* #ifdef APP-PLUS */
.detail-page {
padding-bottom: 188rpx;
}
.permission.transform {
top: 180rpx;
opacity: 1;
visibility: visible;
}
/* #endif */
/* 小程序适配 */
/* #ifdef MP-WEIXIN */
.custom-navbar {
background: linear-gradient(180deg, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 100%);
}
/* #endif */
</style>