Files
2025-12-22 17:13:05 +08:00

504 lines
13 KiB
Vue

<template>
<view class="shop-choose-store" v-if="isLoad">
<fixed>
<view class="rel search-info">
<view class="user-store-info abs">
<image mode="aspectFill" lazy-load class="store-bg abs" src="https://lbqny.migugu.com/admin/farm/bg-store.png">
</image>
</view>
<uni-nav-bar :fixed="false" :shadow="false" :statusBar="true" :onlyLeft="true" color="#fff"
:backgroundColor="`none`">
<view @tap.stop="toChooseLocation" class="flex-y-center" slot="left">
<i class="iconfont icon-dingwei mr-sm"></i>
<view class="text-bold max-400 ellipsis">
{{location.address ?location.address : isLoad ? '定位失败' : '定位中...'}}
</view>
<i class="iconfont icon-down-bold ml-sm"></i>
</view>
</uni-nav-bar>
<view class="flex-between fill-base">
<view style="width: 550rpx;">
<search @input="toSearch" @confirm="toSearch" type="input" :radius="30"
:disabled="location.address ? false : true" :placeholder="`搜索${rankList[rankInd].title}名称`">
</search>
</view>
<view @tap.stop="toShowRank" class="flex-center c-caption b-1px-l" style="width: 200rpx;">
{{rankList[rankInd].title}}
<i class="iconfont icon-down-bold ml-md" :class="[{'rotate-180':show_rank_item}]"></i>
</view>
</view>
</view>
</fixed>
<uni-popup @change="popupChange" ref="rank_item" type="top" :custom="true">
<view :style="{height: searchHeight + 'px' }"></view>
<view class="pd-lg fill-base">
<view @tap.stop="handerTabChange(index)" class="f-paragraph c-title" :class="[{'mt-md':index!=0}]"
:style="{color:index==rankInd?primaryColor:''}" v-for="(item,index) in rankList" :key="index">
{{item.title}}
</view>
</view>
</uni-popup>
<block v-for="(item,index) in list.data" :key="index">
<block v-if="rankList[rankInd].id === 1">
<view @tap.stop="goDetail(index)"
class="farm-item fill-base flex-center mt-md ml-md mr-md pd-lg box-shadow radius-24">
<image mode="aspectFill" lazy-load class="cover radius-24" :src="item.cover"></image>
<view class="flex-1 ml-lg">
<view class="flex-y-center f-title c-title mt-sm mb-sm">
<view class="max-title ellipsis">{{item.title}}</view>
<!-- <view class="status-btn flex-center c-caption ml-sm radius-10"
:class="[{'fill-space':item.is_open==0},{'fill-body':item.is_open==1}]"
:style="{color:item.is_open==1?primaryColor:''}">
{{item.is_open==1?'营业中':'闭店中'}}
</view> -->
</view>
<view class="star-fill-info rel">
<view class="flex-warp star rel">
<view class="item-star flex-center" v-for="(aitem,aindex) in 5" :key="aindex">
<i class="iconfont icon-star-bold-fill"></i>
</view>
</view>
<view class="star-fill abs" :style="{width: item.star_percent}">
<view class="flex-warp">
<view class="item-star flex-center" v-for="(aitem,aindex) in 5" :key="aindex">
<i class="iconfont icon-star-bold-fill icon-font-color"
:style="{backgroundImage: '-webkit-linear-gradient(90deg, #FDCD47, #FFC000)'}"></i>
</view>
</view>
</view>
</view>
<view class="flex-y-center f-caption c-caption mt-sm"><i
class="iconfont icon-dingwei mr-sm"></i>
<view class="addr-text ellipsis">{{item.address}}</view>
</view>
</view>
</view>
</block>
<block v-if="rankList[rankInd].id === 2">
<view @tap.stop="goDetail(index)"
class="farm-item rel fill-base mt-md ml-md mr-md pd-lg box-shadow radius-24">
<view class="more-btn abs flex-center">
<view class="flex-y-baseline" :style="{color:primaryColor}">
<view>进店选购</view>
<i class="iconfont icon-right"></i>
</view>
</view>
<view class="flex-center">
<image mode="aspectFill" lazy-load class="cover box-shadow-mini radius-24" :src="item.cover">
</image>
<view class="flex-1 ml-lg">
<view class="flex-between f-title c-title mt-sm mb-sm">
<view class="max-300 ellipsis">{{item.title}}</view>
<view class="f-caption c-caption">
{{item.distance}}
</view>
</view>
<view class="star-fill-info rel">
<view class="flex-warp star rel">
<view class="item-star flex-center" v-for="(aitem,aindex) in 5" :key="aindex">
<i class="iconfont icon-star-bold-fill"></i>
</view>
</view>
<view class="star-fill abs" :style="{width: item.star_percent}">
<view class="flex-warp">
<view class="item-star flex-center" v-for="(aitem,aindex) in 5" :key="aindex">
<i class="iconfont icon-star-bold-fill icon-font-color"
:style="{backgroundImage: '-webkit-linear-gradient(90deg, #FDCD47, #FFC000)'}"></i>
</view>
</view>
</view>
</view>
<view class="flex-y-center f-caption c-caption mt-sm"><i
class="iconfont icon-dingwei mr-sm"></i>
<view class="addr-text ellipsis">{{item.address}}</view>
</view>
</view>
</view>
</view>
</block>
<block v-if="rankList[rankInd].id === 3">
<view @tap.stop="goDetail(index)"
class="goods-item flex-center mt-md ml-md mr-md pd-lg fill-base radius-24">
<image mode="aspectFill" lazy-load class="cover radius-16" :src="item.cover"></image>
<view class="flex-1 ml-lg">
<view class="flex-center">
<view class="flex-1">
<view class="f-title c-title text-bold mt-sm mb-sm ellipsis">{{item.goods_name}}
</view>
<view class="flex-y-baseline f-caption c-warning">¥<view class="f-lg-title">
{{item.show_price}}
</view>
</view>
<view class="f-caption c-caption text-delete">¥{{item.show_init_price}}</view>
</view>
<image lazy-load class="add-car-img" src="/static/image/shop/add-car.png">
</image>
</view>
</view>
</view>
</block>
</block>
<load-more :noMore="list.current_page>=list.last_page&&list.data.length>0" :loading="loading" v-if="loading">
</load-more>
<abnor v-if="!loading&&list.data.length<=0&&list.current_page==1"></abnor>
<abnor @confirm="$util.checkAuth({ type: 'userLocation' })" :tip="[{ text: '定位失败,请开启地理位置授权后重试~', color: 0 }]"
:button="[{ text: '开启定位' , type: 'confirm' }]" btnSize="" v-if="!loading && !location.lng"> </abnor>
<view class="space-max-footer"></view>
<fix-bottom-button @confirm="$util.goUrl({ url: 1, openType: `navigateBack` })"
:text="[{ text: '返回首页', type: 'confirm' }]" bgColor="#fff" v-if="isLoad"> </fix-bottom-button>
</view>
</template>
<script>
import {
mapState,
mapActions,
mapMutations
} from "vuex"
import uniSegmentedControl from "@/components/uni-segmented-control.vue"
export default {
components: {
uniSegmentedControl
},
data() {
return {
isLoad: false,
searchHeight: 0,
rankInd: 0,
rankList: [{
id: 1,
title: '搜农场',
methodKey: 'home',
method: 'farmerList'
}, {
id: 2,
title: '搜店铺',
methodKey: 'shop',
method: 'indexStoreList'
}, {
id: 3,
title: '搜商品',
methodKey: 'shop',
method: 'goodsList'
}],
param: {
page: 1,
long: '',
lat: '',
store_name: ''
},
list: {
data: []
},
loading: true,
lockTap: false,
show_rank_item: false,
goodsInd: 0,
goodsInfo: {},
subIndex: 0,
currentSpecs: {}, //存放最后选中的商品
currentNum: 1, //选中数量
carIsHave: {
id: 0,
isHave: false,
},
}
},
computed: mapState({
primaryColor: state => state.config.configInfo.primaryColor,
subColor: state => state.config.configInfo.subColor,
configInfo: state => state.config.configInfo,
userInfo: state => state.user.userInfo,
location: state => state.user.location,
}),
async onLoad() {
this.$util.setNavigationBarColor({
color: '#ffffff',
bg: ''
})
if (this.isLoad) return
this.$util.showLoading()
this.initIndex()
},
async onShow() {
if (!this.isLoad || (this.location.lat && this.rankInd != 2)) return
let [err, result] = await uni.getSetting()
if (err || !result.authSetting[`scope.userLocation`]) return
this.initIndex()
},
onPullDownRefresh() {
// #ifndef APP-PLUS
uni.showNavigationBarLoading()
// #endif
this.initRefresh()
uni.stopPullDownRefresh()
},
onReachBottom() {
if (this.list.current_page >= this.list.last_page || this.loading) return
this.param.page = this.param.page + 1
this.loading = true
this.getList()
},
onShareAppMessage(e) {
let path = `/user/pages/store-list`
this.$util.log(path);
return {
title: '',
imageUrl: '',
path,
}
},
methods: {
...mapActions(['getUserInfo']),
...mapMutations(['updateUserItem']),
async initIndex() {
let {
location
} = this
if (!location.lat) {
location = await this.$util.getBmapLocation()
this.updateUserItem({
key: 'location',
val: location
})
}
if (!location.lng) {
this.loading = false
this.isLoad = true
return
}
await this.getList()
setTimeout(() => {
this.toSetResHeight()
}, 200)
},
async initRefresh() {
this.param.page = 1
this.initIndex()
},
async toSetResHeight() {
const query = uni.createSelectorQuery();
query.select('.search-info').boundingClientRect(data => {
this.searchHeight = data.height
}).exec();
},
handerTabChange(index) {
this.rankInd = index
this.$refs.rank_item.close()
this.$util.showLoading()
this.param.page = 1
this.list.data = []
this.getList()
},
toShowRank() {
let {
show_rank_item,
} = this
if (this.lockTap) return
this.lockTap = true
setTimeout(() => {
let methodModel = show_rank_item ? 'close' : 'open'
this.$refs.rank_item[methodModel]()
}, 500)
},
popupChange(e) {
let {
show
} = e
this.show_rank_item = show
setTimeout(() => {
this.lockTap = false
}, 200)
},
toSearch(val) {
this.param.page = 1
this.param.store_name = val
this.getList()
},
async getList() {
let {
list: oldList,
param,
location,
rankList,
rankInd
} = this
let {
lat = 0,
lng = 0
} = location
param = Object.assign({}, param, {
lat,
lng,
})
let {
id: rankType,
methodKey,
method
} = rankList[rankInd]
if (rankType == 3) {
param.type = 1
}
if (rankType != 2) {
if (rankType == 1) {
param.title = param.store_name
} else {
param.goods_name = param.store_name
}
delete param.store_name
}
let newList = await this.$api[methodKey][method](param);
if (rankType != 3) {
newList.data.map(item => {
item.is_open = 1
item.star_percent = (item.star * 1 / 5 * 100).toFixed(2) + '%'
})
}
if (this.param.page == 1) {
this.list = newList
} else {
newList.data = oldList.data.concat(newList.data)
this.list = newList
}
this.loading = false
this.isLoad = true
this.$util.hideAll()
},
// 选择地区
async toChooseLocation(e) {
await this.$util.checkAuth({
type: 'userLocation'
})
let [, {
address = '',
longitude: lng,
latitude: lat
} = {}] = await uni.chooseLocation();
if (!lng) return
let location = {
lng,
lat,
address
}
this.updateUserItem({
key: 'location',
val: location
})
this.location = location
this.param.page = 1
this.getList()
},
async goDetail(index) {
let {
id,
store_id = 0
} = this.list.data[index]
let {
id: rankType
} = this.rankList[this.rankInd]
if (rankType === 2) {
store_id = id
}
let url = {
1: `/home/pages/farm/detail?id=${id}`,
2: `/shop/pages/store?id=${store_id}`,
3: `/shop/pages/detail?id=${id}`
}
this.$util.goUrl({
url: url[rankType]
})
}
}
}
</script>
<style lang="scss">
.shop-choose-store {
.user-store-info {
width: 100%;
z-index: -1;
.store-bg {
width: 100%;
height: 168rpx;
height: calc(168rpx + env(safe-area-inset-bottom) / 2);
padding-bottom: calc(5px + env(safe-area-inset-bottom) / 2);
z-index: -1;
}
}
.search-box-radius {
border-radius: 30rpx 30rpx 0 0;
}
.farm-item {
.cover {
width: 160rpx;
height: 160rpx;
}
.icon-dingwei {
font-size: 24rpx;
}
.status-btn {
width: 80rpx;
height: 36rpx;
font-size: 20rpx;
}
.max-title {
max-width: 450rpx;
// max-width: 370rpx;
}
.addr-text {
max-width: 420rpx;
}
.more-btn {
top: 0;
right: 0;
width: 122rpx;
height: 46rpx;
font-size: 20rpx;
background: rgba(112, 152, 64, 0.1);
border-radius: 0 25rpx 0 15rpx;
.iconfont {
font-size: 20rpx;
}
}
}
.goods-item {
.cover {
width: 180rpx;
height: 170rpx;
}
.add-car-img {
width: 70rpx;
height: 70rpx;
}
.ellipsis {
max-width: 370rpx;
}
}
}
</style>