mrr.sj.front/pages/user/syr-detail.vue

780 lines
21 KiB
Vue
Raw Normal View History

2026-03-24 11:45:13 +08:00
<template>
<view class="detail-page">
<custom-navbar title="手艺人主页" :show-back="true" backgroundColor="#fff" :show-headle="true"
headleSrc="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/3b04f0c1-a55e-4658-9de5-22175cce9bbc.png"
@onHeadleClick="goInvite"></custom-navbar>
<!-- 手艺人顶部首图 -->
<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 @click="previewImage()">
<video :src="syrdetail.video" v-if="syrdetail.video" id="myVideo" class="banner-image"
:autoplay="true" :controls="false" :muted="true" :loop="true" enable-play-gesture="true"
object-fit="cover">
</video>
<image v-else :src="headPhoto" mode="aspectFill" class="banner-image" referrer="no-referrer">
</image>
</swiper-item>
</swiper> -->
<view class="banner-swiper">
<video :src="imgVideoList.main_video.url" v-if="imgVideoList.main_video" id="myVideo"
class="banner-image" :autoplay="true" :controls="false" :muted="true" :loop="true"
enable-play-gesture="true" object-fit="cover">
</video>
<image v-else-if="!imgVideoList.main_video && imgVideoList.main_img" :src="imgVideoList.main_img.url"
mode="aspectFill" class="banner-image" referrer="no-referrer">
</image>
<image v-else src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/9682f8ef-cb0c-47df-a42e-1795bd1f625b.png" mode="aspectFill" class="banner-image" referrer="no-referrer">
</image>
<cover-view class="album flex-row-center" v-if="imgVideoList.main_video || imgVideoList.main_img" @click="goAlbum">
<cover-view class="album-left flex-row-center-center">
{{ imgVideoList.main_video?"视频":"图片" }}
</cover-view>
<cover-view class="album-line">
</cover-view>
<cover-view class="album-right flex-row-center-center" >
<cover-view class="album-right-text">
<cover-view>相册</cover-view>
</cover-view>
<cover-image src="/static/images/icons/right7_13.png" class="album-right-img"></cover-image>
</cover-view>
</cover-view>
</view>
</view>
<!-- 手艺人信息卡片 -->
<view class="detail-info">
<view class="detail-info-user">
<view class="detail-info-user__heard">
<image :src="headPhoto" mode="aspectFill" class="detail-info-user__heard__photo"
referrer="no-referrer"></image>
<view class="detail-info-user__heard__name">
<view class="detail-info-user__heard__name__text">
{{ syrdetail.name }}
</view>
<view class="detail-info-user__heard__name__time">
<view class="detail-info-user__heard__name__time__text1">
营业时间
</view>
<view class="detail-info-user__heard__name__time__text2">
{{ syrdetail.default_times }}
</view>
</view>
</view>
</view>
<view class="detail-info-user__company">
<view class="detail-info-user__company__name" @click="goQualifications">
<view class="detail-info-user__company__name__card">
<image src="/static/images/syr/company.png" mode="aspectFill"
class="detail-info-user__company__name__card__img" referrer="no-referrer"></image>
</view>
<view class="detail-info-user__company__name__text">
{{ syrdetail.for_shop }}
</view>
</view>
<view class="detail-info-user__company__reserve">
<view class="detail-info-user__company__reserve__card">
最近可约
</view>
<view class="detail-info-user__company__reserve__text">
{{ formatRelativeTime(syrdetail.earliest_reserve_time) }}
</view>
</view>
</view>
<view class="detail-info-user__adress">
<view class="detail-info-user__adress__left">
<text class="detail-info-user__adress__left__text1">店铺所在地</text>
<text class="detail-info-user__adress__left__text2">{{
syrdetail.dependency
}}</text>
</view>
<view class="detail-info-user__adress__right">
<image src="/static/images/syr/distance.png" mode="widthFix"
class="detail-info-user__adress__right__img" referrer="no-referrer"></image>
{{ syrdetail.distance }}Km
</view>
</view>
<view class="detail-info-user__introduction">
{{ syrdetail.detail }}
</view>
<image src="/static/images/syr/banner.png" mode="widthFix" class="detail-info-user__banner"
referrer="no-referrer"></image>
</view>
<view class="detail-info-shop">
<view class="detail-info-shop-title">全部项目</view>
<projectTabs :tabsPopList="tabsPopList" @clickTap="clickTap" @clickPopTap="clickPopTap"></projectTabs>
<CommonList background="transparent" ref="groupRef" :apiUrl="'/user/getserverlist'"
:listScrollHeight="`${count * 200 + 80}rpx`" @load-success-all="listSuccess">
<template #listData="{ list }">
<serviceCardList :list="list"></serviceCardList>
</template>
<!-- 空数据状态 -->
<template #empty>
<noData></noData>
</template>
</CommonList>
</view>
<evaluationList :evaluated_id="syrdetail.id" :evaluated_type="1" v-if="syrdetail.id" @goList="goList">
</evaluationList>
</view>
</view>
</template>
<script>
import {
handleImgSizeUni
} from '@/utils/service.js'
import CommonList from "@/components/common/CommonList.vue";
import request from "../../utils/request";
import projectTabs from "./components/project-tabs.vue";
import serviceCardList from "./components/serviceCardList.vue";
import evaluationList from '@/pages/evaluate/components/evaluationList';
export default {
components: {
projectTabs,
CommonList,
serviceCardList,
evaluationList
},
data() {
return {
imgVideoList: {},
videoContext: null,
count: 1,
syrdetail: {
qualifications: [],
},
distance: 12.31, //距离
queryData: {
publish_user_id: null,
server_kind: 1,
page: 1,
limit: 10,
order_type: 1,
},
tabsPopList: [],
showPopup: false,
autoShare: false,
autoShareExecuted: false
};
},
onLoad(options) {
console.log(options);
this.queryData.publish_user_id = options.id;
// 检查是否需要自动分享
if (options.autoShare === '1') {
this.autoShare = true;
}
this.getShopDetail(options.id);
this.$nextTick(() => {
this.search();
});
this.getImgVideoList();
},
computed: {
headPhoto() {
if (this.syrdetail.head_photo == "-" || !this.syrdetail.head_photo) {
return `https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/yh/1756713709528-717.png?x-oss-process=image/resize,p_40`
} else {
return this.syrdetail.head_photo
}
}
},
methods: {
goAlbum() {
uni.navigateTo({
url: `/pages/album/index?id=${this.queryData.publish_user_id}&user_type=1`
});
},
getImgVideoList() {
request.post("/user/imgVideo/main", {
user_id: this.queryData.publish_user_id,
user_type: 1
}).then(res => {
if (res.code == 200) {
this.imgVideoList = res.data
}
})
},
goList() {
uni.navigateTo({
url: `/pages/evaluate/evaluationList?evaluated_id=${this.syrdetail.id}&evaluated_type=1`
})
},
listSuccess(e) {
if (e.count) {
this.count = e.count <= 4 ? e.count : 4
}
},
formatRelativeTime(datetime) {
// 将传入值转换为Date对象兼容字符串和Date实例
const targetDate = new Date(datetime);
// 处理无效日期:直接返回原始输入
if (isNaN(targetDate.getTime())) {
return typeof datetime === "string" ? datetime : "";
}
// 获取当前时间(本地时区)的年、月、日
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth(); // 月份从0开始0=1月
const currentDate = now.getDate();
// 计算明天的年、月、日(当前时间+24小时
const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000);
const tomorrowYear = tomorrow.getFullYear();
const tomorrowMonth = tomorrow.getMonth();
const tomorrowDate = tomorrow.getDate();
// 提取目标日期的年、月、日
const targetYear = targetDate.getFullYear();
const targetMonth = targetDate.getMonth();
const targetDay = targetDate.getDate();
// 格式化小时和分钟(确保两位数,如 9:5 → 09:05
const hours = String(targetDate.getHours()).padStart(2, "0");
const minutes = String(targetDate.getMinutes()).padStart(2, "0");
// 判断日期属于今天、明天还是其他
if (
targetYear === currentYear &&
targetMonth === currentMonth &&
targetDay === currentDate
) {
return `今天${hours}:${minutes}`;
} else if (
targetYear === tomorrowYear &&
targetMonth === tomorrowMonth &&
targetDay === tomorrowDate
) {
return `明天${hours}:${minutes}`;
} else {
// 非今天/明天返回原始输入若为Date对象则转为字符串保留原始格式
return typeof datetime === "string" ? datetime : targetDate.toString();
}
},
setShare(imageUrl) {
// 备用图片地址(常量提取,方便统一维护)
const backupImageUrl =
"https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/yh/1756713709528-717.png?x-oss-process=image/resize,p_40";
// 获取页面栈,用于返回
const pages = getCurrentPages();
// 生成分享配置的公共函数(接收图片地址,返回完整配置)
const getShareConfig = (imgUrl) => ({
provider: "weixin",
scene: "WXSceneSession",
type: 5,
title: "好友刚推了个超赞手艺人点开认识TA ~",
miniProgram: {
id: "gh_89c92e18b70b", // 小程序原始ID
path: `/subPackages/user/syr-detail?id=${this.syrdetail.id}`, // 动态路径
type: this.$store.state.wxShareType, // 版本类型
webUrl: "https://www.baidu.com/", // 降级网页地址
},
imageUrl: imgUrl, // 动态传入图片地址
success: (res) => {
console.log("分享成功:", JSON.stringify(res));
// 延迟返回并显示成功提示
setTimeout(() => {
// 返回上一页即profile页面
uni.navigateBack({
delta: 1,
success: () => {
// 在profile页面显示分享成功提示
// 使用事件总线或全局状态传递消息
uni.showToast({
title: '分享成功',
icon: 'success',
duration: 1000
});
}
});
}, 500); // 延迟0.5秒,让用户看到分享界面
},
fail: (err) => {
console.log("分享失败:", JSON.stringify(err));
uni.showToast({
title: '分享失败',
icon: 'none',
duration: 1000
});
// 分享失败也返回,但提示失败
setTimeout(() => {
uni.navigateBack({
delta: 1,
success: () => {
uni.showToast({
title: '分享失败',
icon: 'none',
duration: 2000
});
}
});
}, 1500);
},
});
// 首次分享使用传入的imageUrl
uni.share(getShareConfig(imageUrl))
.catch(() => {
// 首次失败时,自动使用备用图重试
console.log("首次分享图片无效,尝试备用图片分享...");
uni.share(getShareConfig(backupImageUrl));
});
},
async goInvite() {
let _that = this;
let imageUrl =
"https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/yh/1756713709528-717.png?x-oss-process=image/resize,p_40";
var pages = getCurrentPages();
var page = pages[pages.length - 1];
var bitmap = null;
// 获取当前页面 webview 的对象实例
var currentWebview = await page.$getAppWebview();
bitmap = await new plus.nativeObj.Bitmap("store-detail");
// 将webview内容绘制到Bitmap对象中
currentWebview.draw(
bitmap,
function() {
console.log("截屏绘制图片成功", bitmap);
bitmap.save(
"_doc/a.jpg", {},
async function(i) {
imageUrl = i.target;
try {
// 直接调用导入的函数,不要加 this
const processedUrl = await handleImgSizeUni(i.target);
console.log("处理后的图片地址:", processedUrl);
// 赋值给组件数据
imageUrl = processedUrl;
} catch (err) {
console.error("处理失败:", err);
}
_that.setShare(imageUrl);
bitmap.clear();
},
function(e) {
_that.setShare(imageUrl);
console.log("保存图片失败:" + JSON.stringify(e));
}
);
},
function(e) {
_that.setShare(imageUrl);
console.log("截屏绘制图片失败:" + JSON.stringify(e));
}
);
},
previewImage(index) {
// uni.previewImage({
// urls: this.photoList,
// current: index
// })
},
clickTap(e) {
if (e.order_type) {
this.queryData.order_type = e.order_type;
this.search();
}
},
clickPopTap(e) {
this.queryData.first_class = e;
this.search();
},
// 去资质页
goQualifications() {
uni.navigateTo({
url: `/pages/user/qualifications?id=${this.queryData.publish_user_id}`,
});
},
// 获取手艺人详情
getShopDetail(id) {
let addressRes = {};
let userAdrees = uni.getStorageSync("userAdrees");
if (userAdrees) {
addressRes = userAdrees.addressRes;
} else {
addressRes = getApp().globalData.addressRes;
}
let userLat = addressRes.latitude;
let userLngz = addressRes.longitude;
request
.post("/user/syrdetail", {
id,
userLat,
userLngz
})
.then((res) => {
this.syrdetail = res.data;
this.syrdetail.distance = this.syrdetail.distance.toFixed(2)
this.tabsPopList = [];
this.syrdetail.servers_kill.forEach((element, index) => {
let obj = {
id: element,
name: this.syrdetail.servers_kill_arr[index],
active: false,
};
this.tabsPopList.push(obj);
});
// 如果需要自动分享且未执行过
if (this.autoShare && !this.autoShareExecuted) {
this.autoShareExecuted = true;
// 等待页面渲染
setTimeout(() => {
this.autoTriggerShare();
}, 1000);
}
})
.catch((err) => {
console.log(err);
});
},
// 自动触发分享
autoTriggerShare() {
// #ifdef APP-PLUS
console.log('开始自动分享');
this.goInvite();
// #endif
// #ifdef MP-WEIXIN
uni.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
});
uni.showToast({
title: '请点击右上角分享',
icon: 'none',
duration: 2000
});
// #endif
},
search() {
// 触发列表刷新
this.$refs.groupRef.manualRefresh(this.queryData);
},
},
};
</script>
<style lang="less">
.detail-page {
/* 主图区域 */
.main-image-section {
position: relative;
width: 750rpx;
height: 602rpx;
background-color: #999;
.banner-swiper {
width: 750rpx;
height: 602rpx;
position: relative;
.banner-image {
width: 750rpx;
height: 602rpx;
}
.album {
position: absolute;
bottom: 25rpx;
left: 20rpx;
height: 44rpx;
width: 184rpx;
background: rgba(0, 0, 0, 0.4);
border-radius: 23rpx;
.album-left {
width: 73rpx;
height: 44rpx;
background: #FFFFFF;
border-radius: 23rpx;
display: flex;
align-items: center;
justify-content: center;
line-height: 40rpx;
font-weight: 400;
font-size: 22rpx;
text-align: center;
color: #333333;
}
.album-line {
width: 2rpx;
height: 20rpx;
background: #A09C9E;
border-radius: 1rpx;
margin: 0 18rpx;
}
.album-right {
height: 44rpx;
.album-right-text {
// width: 44rpx;
// height: 44rpx;
// border-radius: 23rpx;
// min-width: 50rpx;
//line-height: 44rpx;
transform: translateY(-4rpx);
font-weight: 400;
font-size: 22rpx;
text-align: center;
color: #FFFFFF;
}
.album-right-img {
width: 8rpx;
height: 16rpx;
padding-left: 8rpx;
}
}
}
}
}
.detail-info {
transform: translateY(20rpx);
padding: 0 20rpx;
position: relative;
.detail-info-user {
padding: 20rpx 26rpx 20rpx 30rpx;
background: #ffffff;
border-radius: 20rpx;
.detail-info-user__heard {
display: flex;
flex-wrap: nowrap;
align-items: center;
&__photo {
width: 122rpx;
height: 122rpx;
border-radius: 50%;
margin-right: 17rpx;
}
&__name {
&__text {
font-weight: 500;
font-size: 42rpx;
color: #333333;
line-height: 59rpx;
text-align: left;
font-style: normal;
}
&__time {
display: flex;
align-items: center;
flex-wrap: nowrap;
&__text1 {
font-weight: 400;
font-size: 22rpx;
color: #5b5b5b;
}
&__text2 {
margin-left: 6rpx;
font-family: DINPro, DINPro;
font-weight: 500;
font-size: 24rpx;
color: #5b5b5b;
transform: translateY(-2rpx);
}
}
}
}
.detail-info-user__company {
display: flex;
margin-top: 37rpx;
&__name {
background: #ffffff;
border-radius: 8rpx;
border: 2rpx solid #cccfd1;
padding-right: 8rpx;
display: flex;
align-items: center;
margin-right: 21rpx;
&__text {
font-weight: 400;
font-size: 20rpx;
color: #a7abae;
text-align: left;
font-style: normal;
}
&__card {
margin-right: 8rpx;
width: 39rpx;
height: 34rpx;
background: rgba(212, 215, 223, 0.2);
border-radius: 6rpx;
border: 1rpx solid rgba(169, 172, 179, 0.2);
display: flex;
align-items: center;
justify-content: center;
&__img {
width: 22rpx;
height: 21rpx;
}
}
}
&__reserve {
display: flex;
align-items: center;
background: #ffffff;
border-radius: 8rpx;
border: 2rpx solid #e8101e;
padding-right: 10rpx;
&__text {
font-family: DINPro, DINPro;
font-weight: bold;
font-size: 20rpx;
color: #e8101e;
line-height: 24rpx;
text-align: left;
font-style: normal;
}
&__card {
margin-right: 8rpx;
height: 100%;
padding: 0rpx 10rpx;
background: #ffecf0;
border-radius: 6rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: 500;
font-size: 20rpx;
color: #e8101e;
text-align: left;
font-style: normal;
}
}
}
.detail-info-user__adress {
margin-top: 20rpx;
display: flex;
justify-content: space-between;
&__left {
&__text1 {
font-weight: 400;
font-size: 24rpx;
color: #a7abae;
line-height: 33rpx;
text-align: left;
font-style: normal;
margin-right: 10rpx;
}
&__text2 {
font-weight: 400;
font-size: 24rpx;
color: #333333;
line-height: 33rpx;
text-align: left;
font-style: normal;
}
}
&__right {
font-weight: bold;
font-size: 24rpx;
color: #666666;
text-align: left;
font-style: normal;
display: flex;
flex-direction: row;
align-items: center;
&__img {
width: 17.5rpx;
margin-right: 9rpx;
}
}
}
.detail-info-user__introduction {
margin-top: 33rpx;
padding-top: 25rpx;
font-weight: 400;
font-size: 24rpx;
color: #666666;
line-height: 33rpx;
text-align: left;
font-style: normal;
position: relative;
background-image: url("/static/images/syr/introduction.png");
/* 背景图片不重复显示 */
background-repeat: no-repeat;
/* 背景图片位置:左上角(默认值,可省略) */
background-position: left top;
/* 背景图片宽度为72rpx高度自适应保持比例 */
background-size: 72rpx auto;
/* 建议设置元素尺寸以确保图片可见 */
}
.detail-info-user__banner {
width: 100%;
margin-top: 30rpx;
}
}
.detail-info-shop {
padding: 20rpx;
background: #ffffff;
border-radius: 20rpx;
margin-top: 20rpx;
.detail-info-shop-title {
width: 136rpx;
height: 48rpx;
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 34rpx;
color: #333333;
line-height: 48rpx;
text-align: left;
font-style: normal;
}
}
}
}
::v-deep .list-container {
padding: 0 !important;
}
.evaluationList {
margin: 20rpx 0rpx 0rpx 0rpx !important;
}
</style>