339 lines
7.9 KiB
Vue
339 lines
7.9 KiB
Vue
<script setup lang="ts">
|
|
import Search from "../tabbar-home/components/search.vue";
|
|
import { useConfigStore, useUserStore } from "@/store";
|
|
import BrowseSkeleton from "./components/browse-skeleton.vue";
|
|
import {
|
|
appMerchantDishNearbyListPost,
|
|
appSearchSearchRecipePost,
|
|
} from "@/service";
|
|
import {thumbnailImg} from "@/utils/utils";
|
|
const configStore = useConfigStore();
|
|
const userStore = useUserStore();
|
|
|
|
const loading = ref(false);
|
|
const recipePreviewLimit = 4;
|
|
|
|
const { t } = useI18n();
|
|
|
|
function navigateTo(url: string) {
|
|
if(userStore.checkLogin()) {
|
|
uni.navigateTo({
|
|
url,
|
|
});
|
|
}
|
|
}
|
|
|
|
async function initData() {
|
|
if(!recipeData.value) {
|
|
loading.value = true;
|
|
}
|
|
getRecipeData()
|
|
// 获取菜品数据
|
|
appMerchantDishNearbyList()
|
|
}
|
|
|
|
// 获取菜谱数据
|
|
const recipeData = ref<any[]>([]);
|
|
function getRecipeData() {
|
|
appSearchSearchRecipePost({
|
|
params: {
|
|
pageNum: 1,
|
|
pageSize: 10,
|
|
},
|
|
body: {}
|
|
}).then(res=> {
|
|
console.log('菜谱数据', res)
|
|
recipeData.value = res.rows;
|
|
}).finally(()=> {
|
|
loading.value = false;
|
|
})
|
|
}
|
|
function navigateToRecipeDetail(id: string | number) {
|
|
navigateTo(`/pages-user/pages/recipe/index?id=${id}`)
|
|
}
|
|
|
|
function navigateToRecipeList() {
|
|
navigateTo('/pages-user/pages/recipe/list')
|
|
}
|
|
|
|
// 获取附近的菜品
|
|
const dishData = ref<any[]>([]);
|
|
function appMerchantDishNearbyList() {
|
|
appMerchantDishNearbyListPost({
|
|
params: {
|
|
pageNum: 1,
|
|
pageSize: 10,
|
|
},
|
|
body: {
|
|
lat: String(userStore.userLocation.latitude ?? ''),
|
|
lng: String(userStore.userLocation.longitude ?? ''),
|
|
}
|
|
}).then(res=> {
|
|
console.log('菜品数据', res)
|
|
dishData.value = res.rows;
|
|
})
|
|
}
|
|
function handleClickDish(item: any) {
|
|
navigateTo(`/pages-store/pages/store/index?id=${item.merchantId}`)
|
|
}
|
|
|
|
function getMerchantName(item: any) {
|
|
return item?.merchantVo?.merchantName || item?.merchantName||item?.dishName || '--'
|
|
}
|
|
|
|
function getMerchantLogo(item: any) {
|
|
return item?.merchantVo?.logo || item?.logo || item?.dishImage?.split?.(',')?.[0] || item?.dishImage || ''
|
|
}
|
|
|
|
function getMerchantRate(item: any) {
|
|
const rating = Number(item?.merchantVo?.rating ?? item?.rating ?? 0)
|
|
return Number.isFinite(rating) && rating > 0 ? rating.toFixed(1) : '5.0'
|
|
}
|
|
|
|
function getPreviewRecipeList() {
|
|
return recipeData.value.slice(0, recipePreviewLimit)
|
|
}
|
|
|
|
function showRecipeMore() {
|
|
return recipeData.value.length > recipePreviewLimit
|
|
}
|
|
|
|
async function getPlatformDefaultStoreInfo() {}
|
|
|
|
defineExpose({
|
|
initData,
|
|
init: getPlatformDefaultStoreInfo,
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<view
|
|
class="bg-#fff"
|
|
:style="[
|
|
{
|
|
height: configStore.windowHeight + 'px',
|
|
},
|
|
]"
|
|
>
|
|
<z-paging ref="paging">
|
|
<template #top>
|
|
<status-bar />
|
|
</template>
|
|
<view
|
|
v-show="loading"
|
|
class="animate-in fade-in animate-ease-out animate-duration-300"
|
|
>
|
|
<browse-skeleton />
|
|
</view>
|
|
<view
|
|
v-show="!loading"
|
|
class="animate-in fade-in animate-ease-in animate-duration-300"
|
|
>
|
|
<view class="px-24rpx pt-16rpx">
|
|
<search />
|
|
</view>
|
|
<view class="browse-wrap px-24rpx">
|
|
<view class="section-title mt-36rpx">{{ t("pages.browse.titleRecipes") }}</view>
|
|
<view class="mt-28rpx">
|
|
<scroll-view scroll-x class="recipe-scroll" :show-scrollbar="false" :enable-flex="true">
|
|
<view class="recipe-track">
|
|
<view
|
|
v-for="item in getPreviewRecipeList()"
|
|
:key="item.id"
|
|
class="recipe-item"
|
|
@click="navigateToRecipeDetail(item.id)"
|
|
>
|
|
<image
|
|
:src="thumbnailImg(item?.recipeImage?.split(',')[0])"
|
|
class="recipe-avatar"
|
|
mode="aspectFill"
|
|
/>
|
|
<text class="recipe-name line-clamp-1">{{ item.recipeName }}</text>
|
|
</view>
|
|
<view v-if="showRecipeMore()" class="recipe-more" @click="navigateToRecipeList">
|
|
<view class="recipe-more__text-wrap">
|
|
<text class="recipe-more__text">{{ t("pages.browse.moreRecipes") }}</text>
|
|
</view>
|
|
<i class="i-carbon:chevron-right recipe-more__icon"></i>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<view class="section-title mt-54rpx">{{ t("pages.browse.titleCuisine") }}</view>
|
|
<scroll-view scroll-x class="store-scroll mt-28rpx pb-40rpx" :show-scrollbar="false" :enable-flex="true">
|
|
<view class="store-track">
|
|
<view v-for="item in dishData" :key="item.id" @click="handleClickDish(item)" class="store-card">
|
|
<image
|
|
:src="thumbnailImg(getMerchantLogo(item))"
|
|
class="store-card__cover"
|
|
mode="aspectFill"
|
|
/>
|
|
<view class="store-card__right">
|
|
<view class="store-card__name line-clamp-2">{{ getMerchantName(item) }}</view>
|
|
<view class="store-card__rating">★★★★★ {{ getMerchantRate(item) }}</view>
|
|
<view class="store-card__brand">{{ t("pages.browse.brandTag") }}</view>
|
|
<view class="store-card__arrow center">
|
|
<i class="i-carbon:chevron-right text-30rpx text-white"></i>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
|
|
<template #bottom>
|
|
<view class="h-50px"></view>
|
|
<view :style="[configStore.iosSafeBottomPlaceholder]"></view>
|
|
</template>
|
|
</z-paging>
|
|
</view>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.browse-wrap {
|
|
background: #fff;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 32rpx;
|
|
line-height: 48rpx;
|
|
// font-weight: 700;
|
|
color: #1c1c1c;
|
|
}
|
|
|
|
.recipe-scroll,
|
|
.store-scroll {
|
|
width: 100%;
|
|
}
|
|
|
|
.recipe-track {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 22rpx;
|
|
padding-right: 24rpx;
|
|
}
|
|
|
|
.recipe-item {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.recipe-avatar {
|
|
width: 112rpx;
|
|
height: 112rpx;
|
|
border-radius: 56rpx;
|
|
background: #f1f1f1;
|
|
}
|
|
|
|
.recipe-name {
|
|
max-width: 140rpx;
|
|
margin-top: 14rpx;
|
|
text-align: center;
|
|
font-size: 26rpx;
|
|
line-height: 32rpx;
|
|
color: #222;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.recipe-more {
|
|
flex-shrink: 0;
|
|
height: 112rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 4rpx;
|
|
padding: 4rpx 8rpx;
|
|
}
|
|
|
|
.recipe-more__text-wrap {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
gap: 6rpx;
|
|
}
|
|
|
|
.recipe-more__text {
|
|
font-size: 24rpx;
|
|
line-height: 28rpx;
|
|
color: #8a8a8a;
|
|
font-weight: 500;
|
|
writing-mode: vertical-rl;
|
|
text-orientation: upright;
|
|
letter-spacing: 2rpx;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.recipe-more__icon {
|
|
font-size: 20rpx;
|
|
color: #8a8a8a;
|
|
}
|
|
|
|
.store-track {
|
|
display: flex;
|
|
align-items: stretch;
|
|
gap: 22rpx;
|
|
padding-right: 24rpx;
|
|
}
|
|
|
|
.store-card {
|
|
width: 404rpx;
|
|
height: 220rpx;
|
|
border-radius: 20rpx;
|
|
overflow: hidden;
|
|
background: #fff;
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
|
}
|
|
|
|
.store-card__cover {
|
|
width: 184rpx;
|
|
height: 220rpx;
|
|
background: #f2f2f2;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.store-card__right {
|
|
flex: 1;
|
|
padding: 16rpx 14rpx 14rpx 16rpx;
|
|
position: relative;
|
|
}
|
|
|
|
.store-card__name {
|
|
font-size: 28rpx;
|
|
line-height: 34rpx;
|
|
color: #191919;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.store-card__rating {
|
|
margin-top: 8rpx;
|
|
color: #111;
|
|
font-size: 26rpx;
|
|
line-height: 30rpx;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.store-card__brand {
|
|
margin-top: 12rpx;
|
|
color: #d39a48;
|
|
font-size: 24rpx;
|
|
line-height: 28rpx;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.store-card__arrow {
|
|
position: absolute;
|
|
right: 10rpx;
|
|
bottom: 12rpx;
|
|
width: 52rpx;
|
|
height: 52rpx;
|
|
border-radius: 50%;
|
|
background: #111;
|
|
}
|
|
</style>
|