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.
 
 
 
 
 

500 lines
11 KiB

<template>
<view class="home">
<view class="home-top">
<view class="search">
<view @click="showSelectArea" class="left-area">
<image src="@/static/home/address-icon.png"></image>
<view class="area">{{ area }}</view>
<image src="../../static/home/arrow-icon.png" mode="aspectFit"></image>
<view class="parting-line">|</view>
</view>
<view class="center-area">
<image src="@/static/home/search-icon.png"></image>
<van-field @click="searchAddress" v-model="queryParams.title" center placeholder="请选择地区" />
</view>
<view class="right-area">
<view @click="searchAddress" class="search-button">
搜索
</view>
</view>
</view>
</view>
<view class="home-content">
<view class="banner b-relative">
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
<van-swipe-item v-for="item in bannerList" :key="item.id">
<image class="banner-image" :src="item.image" mode="widthFix"></image>
</van-swipe-item>
</van-swipe>
</view>
<view v-if="projectList.length > 0" class="server-list">
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" ref="list"
@load="onLoad">
<view v-for="item in projectList" class="server-item" @click="toServiceDetail(item.id)">
<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="selectTechnician(item.id)" class="btn">
选择技师
</view>
</view>
</view>
</van-list>
</view>
<van-empty v-else image="/static/empty/data.png" image-size="400rpx" description="暂无项目" />
</view>
<selectArea :show="showAeraPro" @close="closeAreaPro" @select="selectArea"></selectArea>
</view>
</template>
<script>
import selectArea from '../../components/selectArea.vue';
import Position from '@/utils/position.js'
export default {
components: {
selectArea
},
data() {
return {
bannerList: [],
projectList: [],
queryParams: {
pageNo: 1,
pageSize: 10,
title: ''
},
loading: false,
finished: false,
technicianList: [],
showAeraPro: false,
area: ''
}
},
onShow() {
this.getBanner()
this.getProject()
this.getLocation()
},
methods: {
//list列表滑动到底部自动新增数据列表
onLoad() {
this.queryParams.pageSize += 10;
this.getProject()
},
//获取banner
getBanner() {
this.$api('getBanner', {}, res => {
this.bannerList = res.result;
})
},
//获取项目列表
getProject() {
this.$api('getProjectList', this.queryParams, res => {
if (res.code == 200) {
this.projectList = res.result.records;
} else {
this.finished = true
}
if (this.queryParams.pageSize > res.result.total) {
this.finished = true
}
this.loading = false
})
},
//获取技师详情
selectTechnician(id) {
this.$api('getProjectDetail', {
id
}, res => {
if (res.code == 200) {
uni.navigateTo({
url: `/pages/technician/selectTechnician?serviceId=${id}`
})
sessionStorage.setItem('technicianList', JSON.stringify(res.result.tenPageList))
}
})
},
//跳转技师详情
toServiceDetail(id) {
uni.navigateTo({
url: '/pages/technician/subscribeService?id=' + id
})
},
//显示选择地区
showSelectArea() {
this.showAeraPro = true;
},
//关闭选择地区
closeAreaPro() {
this.showAeraPro = false;
},
//选择了地区信息
selectArea(area) {
this.area = area;
this.showAeraPro = false;
//后端逻辑
this.updateSessionPositon(area)
},
//搜索地址
searchAddress() {
Position.getLocation(res => {
Position.selectAddress(res.longitude, res.latitude, success => {
let address = this.extractProvinceAndCity(success)
this.queryParams.title = address.city
})
})
},
//提取用户选择的地址信息(省市县信息)
extractProvinceAndCity(res) { //提取用户选择的地址信息(省市)
if (!res.address && res.name) { //用户直接选择城市的逻辑
return {
province: '',
city: res.name
};
}
if (res.address) { //用户选择了详细地址,要从详细地址中提取出省市县信息
// 使用正则表达式匹配省市县
const regex = /(?<province>[\u4e00-\u9fa5]+?省)(?<city>[\u4e00-\u9fa5]+?(?:市|自治州|盟|地区))/;
const match = res.address.match(regex);
if (match) { // 如果匹配成功,则返回省和市的信息
return {
province: match.groups.province,
city: match.groups.city
};
}
}
return { //用户没选择地址就点了确定按钮
province: '',
city: ''
}
},
//获取用户详细地址(省市县)
getLocation() {
Position.getLocationDetail().then(res => {
sessionStorage.setItem("position", JSON.stringify(res))
this.area = res.addressDetail.district
})
},
//初始化用户所在地区
initUserArea() {
if (!sessionStorage.getItem('position')) return this.getLocation()
let positionInfo = JSON.parse(sessionStorage.getItem('position'))
this.area = positionInfo.addressDetail.district
},
//更新用户所在区域(更新区县信息)
updateSessionPositon(area) {
if (sessionStorage.getItem('position')) {
let position = JSON.parse(sessionStorage.getItem('position'))
position.addressDetail.district = area
sessionStorage.setItem('position', JSON.stringify(position))
}
}
}
}
</script>
<style lang="scss" scoped>
.home {
width: 750rpx;
background: #F5F5F5;
margin: 0 auto;
.home-top {
height: 350rpx;
background: linear-gradient(38deg, #4899A6, #60BDA2);
padding-top: 60rpx;
.search {
height: 82rpx;
width: 710rpx;
background: #FFFFFF;
margin: 0px auto;
border-radius: 41rpx;
box-sizing: border-box;
padding: 0 15rpx;
display: flex;
align-items: center;
justify-content: space-between;
.left-area,
.center-area {
display: flex;
align-items: center;
}
.left-area {
max-width: 160rpx;
image {
flex-shrink: 0;
width: 26rpx;
height: 26rpx;
}
.area {
font-size: 24rpx;
display: -webkit-box;
-webkit-line-clamp: 2;
/* 限制显示两行 */
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
color: #292929;
}
.parting-line {
flex-shrink: 0;
font-size: 26rpx;
color: #ccc;
margin: 0rpx 5rpx;
}
}
.center-area {
display: flex;
flex-wrap: nowrap;
align-items: center;
width: calc(100% - 290rpx);
image {
width: 26rpx;
height: 26rpx;
}
.van-field {
background-color: transparent;
box-sizing: border-box;
height: 82rpx;
line-height: 82rpx;
width: calc(100% - 30rpx);
padding: 0rpx 10rpx 0rpx 0rpx;
input {
height: 82rpx;
font-size: 60rpx;
}
}
}
.right-area {
.search-button {
background: #60BDA2;
height: 60rpx;
width: 130rpx;
font-size: 26rpx;
border-radius: 35rpx;
color: white;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
.home-content {
width: calc(100% - 40rpx);
margin: -240rpx 20rpx 0rpx 20rpx;
.banner {
box-sizing: border-box;
.my-swipe {
width: 100%;
margin: 0px auto;
border-radius: 20rpx;
height: 334rpx;
overflow: hidden;
.van-swipe-item {
width: 100%;
.banner-image {
width: 100%;
image {
width: 100%;
}
}
}
}
}
.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);
}
}
}
}
}
}
</style>