mrr.sj.front/pages/user/store-syr-list.vue

590 lines
18 KiB
Vue
Raw Permalink Normal View History

2026-03-24 11:45:13 +08:00
<template>
<view class="syr-list-page">
<!-- 自定义导航栏 -->
<custom-navbar
title="门店手艺人列表"
:show-back="true"
backgroundColor="#fff"
></custom-navbar>
<!-- 手艺人列表 -->
<scroll-view
class="syr-list-scroll"
scroll-y="true"
:style="{height: scrollViewHeight + 'px'}"
@scrolltolower="loadMore"
>
<view class="syr-list-container">
<!-- 手艺人网格列表 -->
<view class="syr-grid">
<view
v-for="(artisan, index) in artisanList"
:key="artisan.id"
class="syr-card"
@click="goArtisanDetail(artisan)"
>
<!-- 头像部分 -->
<view class="syr-avatar-container">
<image
:src="artisan.avatar || defaultAvatar"
class="syr-avatar"
mode="aspectFill"
></image>
</view>
<!-- 信息部分 -->
<view class="syr-info">
<!-- 第一行名字和距离 -->
<view class="syr-name-row">
<text class="syr-name">{{ artisan.name }}</text>
<view class="syr-distance">
<image
src="/static/images/icons/address_icon.png"
class="distance-icon"
></image>
<text class="distance-text">{{ formatDistance(artisan.distance) }}</text>
</view>
</view>
<!-- 第二行从业经历 -->
<view class="syr-experience-row">
<text class="syr-experience">从业经历</text>
<image
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/0a9bcad4-a3b2-457f-bdfd-d659d6b1b084.png"
class="experience-icon"
@click.stop="goQualification(artisan)"
></image>
</view>
<!-- 第三行入驻时间 -->
<view class="syr-join-row">
<text class="syr-join">入驻{{ formatWorkingYears(artisan.working_years) }}</text>
</view>
</view>
</view>
</view>
<!-- 加载状态 -->
<view class="loading-status">
<text v-if="loading" class="loading-text">加载中...</text>
<text v-if="finished && artisanList.length > 0" class="no-more-text">~ 暂时只有这些了 ~</text>
</view>
<!-- 空状态 -->
<!-- <view v-if="!loading && artisanList.length === 0" class="empty-state">
<image
src="/static/images/common/empty.png"
class="empty-image"
></image>
<text class="empty-text">暂无手艺人</text>
</view> -->
</view>
</scroll-view>
</view>
</template>
<script>
import request from "@/utils/request";
export default {
data() {
return {
artisanList: [], // 手艺人列表
loading: false, // 加载状态
finished: false, // 是否已加载完毕
page: 1, // 当前页码
limit: 10, // 每页数量
total: 0, // 总数量
shopId: null, // 店铺ID
scrollViewHeight: 0, // 滚动区域高度
// 默认头像
defaultAvatar: "https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/yh/1756713709528-717.png?x-oss-process=image/resize,p_40"
};
},
onLoad(options) {
// 从路由参数获取店铺ID
if (options.shopId) {
this.shopId = options.shopId;
} else if (options.id) {
// 也可能是从店铺详情页面传过来的id
this.shopId = options.id;
}
console.log("接收到的店铺ID:", this.shopId);
// 计算滚动区域高度
this.calculateScrollHeight();
// 获取手艺人列表
this.getArtisanList();
},
onReady() {
// 页面加载完成后再计算一次高度,确保准确
setTimeout(() => {
this.calculateScrollHeight();
}, 100);
},
methods: {
// 计算滚动区域高度
calculateScrollHeight() {
const systemInfo = uni.getSystemInfoSync();
// 获取导航栏高度假设为44px可以根据实际情况调整
const navBarHeight = 44;
// 状态栏高度
const statusBarHeight = systemInfo.statusBarHeight || 0;
// 计算可用高度
this.scrollViewHeight = systemInfo.windowHeight - (navBarHeight + statusBarHeight);
},
// 获取手艺人列表
getArtisanList() {
if (this.loading || this.finished) {
return;
}
this.loading = true;
// 获取用户位置
const userLocation = this.getUserLocation();
console.log("获取到的用户位置:", userLocation);
const params = {
page: this.page,
limit: this.limit
};
if (this.shopId) {
params.sjid = this.shopId;
}
// 传递位置参数给后端
if (userLocation) {
params.userLat = userLocation.latitude;
params.userLngz = userLocation.longitude;
}
request
.post("/user/sjSyrBind/syrList", params)
.then((res) => {
console.log("手艺人列表接口返回:", res);
if (res.code === 200) {
const resultData = res.data || {};
const list = resultData.list || [];
const total = resultData.count || list.length || 0;
// 格式化数据时传入用户位置用于距离计算
const formattedList = this.formatArtisanList(list, userLocation);
console.log("格式化后的列表(包含距离):", formattedList);
if (this.page === 1) {
this.artisanList = formattedList;
} else {
this.artisanList = [...this.artisanList, ...formattedList];
}
this.total = total;
if (list.length < this.limit) {
this.finished = true;
} else {
this.page += 1;
}
} else {
console.error("接口返回错误:", res);
uni.showToast({
title: res.msg || '获取手艺人列表失败',
icon: 'none'
});
}
})
.catch((err) => {
console.error("获取手艺人列表失败:", err);
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
});
})
.finally(() => {
this.loading = false;
});
},
// 格式化手艺人列表数据
formatArtisanList(list, userLocation = null) {
if (!list || list.length === 0) {
return [];
}
// 如果没有传入用户位置,尝试获取
if (!userLocation) {
userLocation = this.getUserLocation();
}
// 模拟数据,用于调试布局
const mockData = [
{ id: 1, name: "梅子", working_years: "1年6个月", distance: 32.29 },
{ id: 2, name: "王安宇", working_years: "10年10个月", distance: 2.29 },
{ id: 3, name: "王安宇...", working_years: "10年10个月", distance: 2.29 },
{ id: 4, name: "梅子", working_years: "1年6个月", distance: 2.29 }
];
// 正式环境使用接口数据
const dataToUse = list.length > 0 ? list : mockData;
return list.map((item) => {
// 计算从业年限
let workingYears = "0年0个月";
if (item.working_years) {
workingYears = item.working_years;
} else if (item.add_time) {
// 从 add_time 计算
const createdDate = new Date(item.add_time);
const now = new Date();
const years = now.getFullYear() - createdDate.getFullYear();
const months = now.getMonth() - createdDate.getMonth();
let totalMonths = years * 12 + months;
if (totalMonths < 0) totalMonths = 0;
const formattedYears = Math.floor(totalMonths / 12);
const formattedMonths = totalMonths % 12;
workingYears = `${formattedYears}${formattedMonths}个月`;
}
// 计算距离
let distance = null;
if (userLocation && userLocation.latitude && userLocation.longitude &&
item.latitude && item.longitude) {
try {
const lat1 = parseFloat(userLocation.latitude);
const lng1 = parseFloat(userLocation.longitude);
const lat2 = parseFloat(item.latitude);
const lng2 = parseFloat(item.longitude);
// 调用距离计算函数
distance = this.calculateDistance(lat1, lng1, lat2, lng2);
console.log(`计算距离: 用户(${lat1},${lng1}) -> 手艺人(${lat2},${lng2}) = ${distance}km`);
} catch (e) {
console.error("计算距离失败:", e);
}
}
return {
id: item.id || item.user_id || '',
name: item.name || item.nick_name || '手艺人',
avatar: item.head_photo,
working_years: workingYears,
distance: distance, // 距离字段
latitude: item.latitude, // 保留经纬度供后续使用
longitude: item.longitude,
service_count: item.service_count || 0,
good_rating: item.good_rating || '100%',
default_times: item.default_times,
work_state: item.work_state,
is_ok: item.is_ok,
is_del: item.is_del
};
});
},
// 格式化从业年限显示
formatWorkingYears(yearsStr) {
// 如果已经是格式化好的字符串,直接返回
if (typeof yearsStr === 'string') {
return yearsStr;
}
// 否则尝试转换
try {
// 假设是月份数
const months = parseInt(yearsStr);
if (!isNaN(months)) {
const y = Math.floor(months / 12);
const m = months % 12;
return `${y}${m}个月`;
}
} catch (e) {
console.error("格式化从业年限失败:", e);
}
return "0年0个月";
},
// 添加距离计算函数Haversine公式
calculateDistance(lat1, lng1, lat2, lng2) {
// 将度转换为弧度
const toRad = (angle) => (angle * Math.PI) / 180;
const R = 6371; // 地球半径(公里)
const dLat = toRad(lat2 - lat1);
const dLng = toRad(lng2 - lng1);
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
Math.sin(dLng / 2) * Math.sin(dLng / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c;
return parseFloat(distance.toFixed(2)); // 保留2位小数
},
// 获取用户位置(修改为返回完整对象)
getUserLocation() {
let addressRes = {};
let userAdrees = uni.getStorageSync("userAdrees");
if (userAdrees) {
addressRes = userAdrees.addressRes;
} else {
addressRes = getApp().globalData.addressRes;
}
// 确保返回包含经纬度的对象
if (addressRes && addressRes.latitude && addressRes.longitude) {
return {
latitude: parseFloat(addressRes.latitude),
longitude: parseFloat(addressRes.longitude),
address: addressRes.address
};
}
return null;
},
// 格式化距离显示
formatDistance(distance) {
if (!distance && distance !== 0) {
return "距离未知";
}
// 如果是字符串,尝试转换为数字
const numDistance = typeof distance === 'string' ? parseFloat(distance) : distance;
if (isNaN(numDistance)) {
return distance;
}
// 保留两位小数
return `${numDistance.toFixed(2)}Km`;
},
// 加载更多
loadMore() {
if (!this.finished) {
this.getArtisanList();
}
},
// 跳转到手艺人(员工)详情页
goArtisanDetail(artisan) {
uni.navigateTo({
url: `/pages/user/employee-detail?id=${artisan.id}`
});
},
// 跳转到资质页面
goQualification(artisan) {
// 跳转到资质页面传递手艺人ID
uni.navigateTo({
url: `/pages/user/qualifications?id=${artisan.id}`
});
},
// 下拉刷新
onPullDownRefresh() {
// 重置页码和状态
this.page = 1;
this.finished = false;
this.artisanList = [];
// 重新加载数据
this.getArtisanList();
// 停止下拉刷新
uni.stopPullDownRefresh();
}
}
};
</script>
<style lang="less">
.syr-list-page {
background-color: #f5f5f5;
min-height: 100vh;
.syr-list-scroll {
width: 100%;
.syr-list-container {
margin: 20rpx 0;
padding: 0 35rpx;
.syr-header {
padding: 30rpx 0 20rpx;
.syr-count {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
}
.syr-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.syr-card {
width: 331rpx;
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.syr-avatar-container {
width: 100%;
height: 327rpx;
.syr-avatar {
width: 100%;
height: 100%;
background-color: #f0f0f0;
}
}
.syr-info {
padding: 20rpx;
.syr-name-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
.syr-name {
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 34rpx;
color: #000000;
line-height: 48rpx;
text-align: left;
font-style: normal;
}
.syr-distance {
display: flex;
align-items: center;
.distance-icon {
transform: translateY(-1rpx);
width: 18rpx;
height: 21rpx;
margin-right: 6rpx;
}
.distance-text {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 33rpx;
text-align: left;
font-style: normal;
}
}
}
.syr-experience-row {
display: flex;
align-items: center;
margin-bottom: 8rpx;
.experience-icon {
width: 68rpx;
height: 24rpx;
}
.syr-experience {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 26rpx;
color: #000000;
line-height: 37rpx;
text-align: left;
font-style: normal;
margin-right: 14rpx;
}
}
.syr-join-row {
display: flex;
align-items: center;
.join-icon {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
.syr-join {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 33rpx;
text-align: left;
font-style: normal;
}
}
}
}
}
.loading-status {
padding: 40rpx 0;
text-align: center;
.loading-text {
font-size: 26rpx;
color: #999;
}
.no-more-text {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 24rpx;
color: #CECECE;
line-height: 33rpx;
text-align: left;
font-style: normal;
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
.empty-image {
width: 200rpx;
height: 200rpx;
margin-bottom: 30rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
}
}
}
}
</style>