修改效果
This commit is contained in:
+8
-1
@@ -241,7 +241,8 @@
|
||||
"mustEatList": "CHEFLINK Must-Eat",
|
||||
"newCalendar": "New Arrival Calendar",
|
||||
"newCalendarNav": "Today's New",
|
||||
"freshSeafoodToday": "Fresh Seafood Today"
|
||||
"freshSeafoodToday": "Fresh Seafood Today",
|
||||
"energyMeal": "Energy Meals"
|
||||
},
|
||||
"mustEatListTabs": {
|
||||
"merchant": "Merchant Rank",
|
||||
@@ -589,6 +590,12 @@
|
||||
"voucherUploadFailed": "Upload failed, please try again",
|
||||
"pleaseBindCreditCard": "No bank card linked. Please add a card before paying."
|
||||
},
|
||||
"energyMeal": {
|
||||
"title": "Energy Meals",
|
||||
"addAllToCart": "Add all to cart",
|
||||
"empty": "No energy meals yet",
|
||||
"unavailable": "This bundle is unavailable"
|
||||
},
|
||||
"store": {
|
||||
"addToCart": "Add to cart",
|
||||
"appetizers": "Appetizers",
|
||||
|
||||
@@ -241,7 +241,8 @@
|
||||
"mustEatList": "CHEFLINK必吃榜",
|
||||
"newCalendar": "上新日历",
|
||||
"newCalendarNav": "今日上新",
|
||||
"freshSeafoodToday": "今日现打海鲜"
|
||||
"freshSeafoodToday": "今日现打海鲜",
|
||||
"energyMeal": "能量餐"
|
||||
},
|
||||
"mustEatListTabs": {
|
||||
"merchant": "商家榜单",
|
||||
@@ -589,6 +590,12 @@
|
||||
"voucherUploadFailed": "上传失败,请重试",
|
||||
"pleaseBindCreditCard": "未绑定银行卡,请先绑定后再支付"
|
||||
},
|
||||
"energyMeal": {
|
||||
"title": "能量餐",
|
||||
"addAllToCart": "一键加入购物车",
|
||||
"empty": "暂无能量餐",
|
||||
"unavailable": "套餐暂不可购买"
|
||||
},
|
||||
"store": {
|
||||
"addToCart": "加入购物车",
|
||||
"appetizers": "开胃菜",
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
"name" : "CHEFLINK delivery",
|
||||
"appid" : "__UNI__06509BE",
|
||||
"description" : "",
|
||||
"versionName" : "3.2.4",
|
||||
"versionCode" : 324,
|
||||
"versionName" : "3.2.5",
|
||||
"versionCode" : 325,
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
|
||||
@@ -13,8 +13,10 @@ export type FeaturedDishQueryBody = {
|
||||
|
||||
/** 运营入口固定参数(精选菜品列表 operationalEntry) */
|
||||
export const OPERATIONAL_ENTRY = {
|
||||
FEATURED: 'featured',
|
||||
FRESH_SEAFOOD_TODAY: 'fresh-seafood-today',
|
||||
LIMITED_AIR_SEAFOOD: 'limited-air-seafood',
|
||||
NEW_DISH_CALENDAR: 'new-dish-calendar',
|
||||
} as const
|
||||
|
||||
export type RouteQueryMap = Record<string, string | undefined>
|
||||
@@ -63,41 +65,10 @@ export function buildMustEatListQuery(routeQuery?: RouteQueryMap): FeaturedDishQ
|
||||
return mergeRouteQueryIntoBody({ salesSort: 'desc' }, routeQuery)
|
||||
}
|
||||
|
||||
/** 当天 00:00:00 ~ 23:59:59(本地时区,10 位秒级时间戳) */
|
||||
export function getTodayCreateTimeRange(): { createBeginTime: number; createEndTime: number } {
|
||||
const now = new Date()
|
||||
const createBeginTime = Math.floor(
|
||||
new Date(
|
||||
now.getFullYear(),
|
||||
now.getMonth(),
|
||||
now.getDate(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
).getTime() / 1000,
|
||||
)
|
||||
const createEndTime = Math.floor(
|
||||
new Date(
|
||||
now.getFullYear(),
|
||||
now.getMonth(),
|
||||
now.getDate(),
|
||||
23,
|
||||
59,
|
||||
59,
|
||||
0,
|
||||
).getTime() / 1000,
|
||||
)
|
||||
return { createBeginTime, createEndTime }
|
||||
}
|
||||
|
||||
/** 上新日历:当天创建 + 新品(isNew = 1) */
|
||||
/** 今日上新/上新日历:运营入口 new-dish-calendar(全量新品,按上架时间倒序) */
|
||||
export function buildNewCalendarQuery(routeQuery?: RouteQueryMap): FeaturedDishQueryBody {
|
||||
return mergeRouteQueryIntoBody(
|
||||
{
|
||||
...getTodayCreateTimeRange(),
|
||||
isNew: 1,
|
||||
},
|
||||
{ operationalEntry: OPERATIONAL_ENTRY.NEW_DISH_CALENDAR },
|
||||
routeQuery,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ export function resolveQuickTopicFromMerchantCategory(
|
||||
/** 快捷入口 topic 与 operationalEntry 固定映射 */
|
||||
export const TOPIC_OPERATIONAL_ENTRY: Partial<Record<QuickTopicSlug, string>> = {
|
||||
'live-seafood-air': 'limited-air-seafood',
|
||||
'new-calendar': 'new-dish-calendar',
|
||||
'fresh-seafood-today': 'fresh-seafood-today',
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<view class="energy-meal-skeleton">
|
||||
<view v-for="i in 2" :key="i" class="energy-meal-skeleton__card">
|
||||
<view class="energy-meal-skeleton__head">
|
||||
<view class="energy-meal-skeleton__title skeleton-item"></view>
|
||||
<view class="energy-meal-skeleton__merchant skeleton-item"></view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="j in 2"
|
||||
:key="j"
|
||||
class="energy-meal-skeleton__row"
|
||||
:class="{ 'energy-meal-skeleton__row--last': j === 2 }"
|
||||
>
|
||||
<view class="energy-meal-skeleton__img skeleton-item"></view>
|
||||
<view class="energy-meal-skeleton__main">
|
||||
<view class="energy-meal-skeleton__name skeleton-item"></view>
|
||||
<view class="energy-meal-skeleton__price skeleton-item"></view>
|
||||
<view class="energy-meal-skeleton__member skeleton-item"></view>
|
||||
<view class="energy-meal-skeleton__sales skeleton-item"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="energy-meal-skeleton__action">
|
||||
<view class="energy-meal-skeleton__btn skeleton-item"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.skeleton-item {
|
||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
.energy-meal-skeleton {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__card {
|
||||
margin-bottom: 24rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__head {
|
||||
padding: 24rpx 24rpx 8rpx;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__title {
|
||||
width: 280rpx;
|
||||
height: 36rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__merchant {
|
||||
width: 180rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__row {
|
||||
display: flex;
|
||||
padding: 28rpx 24rpx;
|
||||
border-bottom: 1rpx solid #ebebeb;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__row--last {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__img {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__name {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__price {
|
||||
width: 160rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__member {
|
||||
width: 320rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__sales {
|
||||
width: 180rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 999rpx;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__action {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 8rpx 24rpx 24rpx;
|
||||
}
|
||||
|
||||
.energy-meal-skeleton__btn {
|
||||
width: 280rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,436 @@
|
||||
<script setup lang="ts">
|
||||
import Config from '@/config/index'
|
||||
import { useUserStore } from '@/store'
|
||||
import EnergyMealSkeleton from './components/energy-meal-skeleton.vue'
|
||||
import {
|
||||
appEnergyMealAddCartPost,
|
||||
appEnergyMealListPost,
|
||||
type EnergyMealItemVo,
|
||||
type EnergyMealVo,
|
||||
} from '@/service'
|
||||
import { formatSalesCount, thumbnailImg } from '@/utils/utils'
|
||||
|
||||
const { t } = useI18n()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const filterMerchantId = ref<string>('')
|
||||
const mealList = ref<EnergyMealVo[]>([])
|
||||
const paging = ref<ZPagingInstance | null>(null)
|
||||
const addingMealId = ref<string | number | null>(null)
|
||||
const loading = ref(true)
|
||||
|
||||
onLoad((options: Record<string, string | undefined>) => {
|
||||
if (options?.merchantId) {
|
||||
filterMerchantId.value = String(options.merchantId)
|
||||
}
|
||||
})
|
||||
|
||||
function firstImage(raw?: string) {
|
||||
if (typeof raw !== 'string' || !raw.trim()) return ''
|
||||
return raw.split(',')[0].trim()
|
||||
}
|
||||
|
||||
function sortedItems(meal: EnergyMealVo): EnergyMealItemVo[] {
|
||||
const list = Array.isArray(meal.itemList) ? [...meal.itemList] : []
|
||||
return list.sort((a, b) => Number(a.sort ?? 0) - Number(b.sort ?? 0))
|
||||
}
|
||||
|
||||
function canAddMeal(meal: EnergyMealVo) {
|
||||
return sortedItems(meal).some((item) => item.merchantDishVo?.id)
|
||||
}
|
||||
|
||||
function dishCover(item: EnergyMealItemVo) {
|
||||
return firstImage(item.merchantDishVo?.dishImage)
|
||||
}
|
||||
|
||||
function dishName(item: EnergyMealItemVo) {
|
||||
const name = String(item.merchantDishVo?.dishName ?? '').trim()
|
||||
const qty = Number(item.quantity) || 1
|
||||
if (!name) return '--'
|
||||
if (qty > 1) {
|
||||
return `${name} × ${qty}`
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
function dishPrice(item: EnergyMealItemVo) {
|
||||
const dish = item.merchantDishVo ?? {}
|
||||
const discount = Number(dish.discountPrice)
|
||||
const original = Number(dish.originalPrice)
|
||||
if (Number.isFinite(discount) && discount > 0) return discount.toFixed(2)
|
||||
if (Number.isFinite(original) && original > 0) return original.toFixed(2)
|
||||
return '0.00'
|
||||
}
|
||||
|
||||
function dishOriginalPrice(item: EnergyMealItemVo) {
|
||||
const dish = item.merchantDishVo ?? {}
|
||||
const discount = Number(dish.discountPrice)
|
||||
const original = Number(dish.originalPrice)
|
||||
if (
|
||||
Number.isFinite(original) &&
|
||||
original > 0 &&
|
||||
Number.isFinite(discount) &&
|
||||
original > discount
|
||||
) {
|
||||
return original.toFixed(2)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function dishMemberPrice(item: EnergyMealItemVo) {
|
||||
const member = Number(item.merchantDishVo?.memberPrice)
|
||||
return Number.isFinite(member) && member > 0 ? member.toFixed(2) : ''
|
||||
}
|
||||
|
||||
function openDishDetail(item: EnergyMealItemVo, meal: EnergyMealVo) {
|
||||
const dishId = item.merchantDishVo?.id ?? item.dishId
|
||||
const merchantId = meal.merchantId ?? item.merchantDishVo?.merchantId
|
||||
if (!dishId || !merchantId) return
|
||||
uni.navigateTo({
|
||||
url: `/pages-store/pages/store/dishes?id=${dishId}&storeId=${merchantId}`,
|
||||
})
|
||||
}
|
||||
|
||||
async function onQuery(pageNum: number, pageSize: number) {
|
||||
if (pageNum === 1) {
|
||||
loading.value = true
|
||||
}
|
||||
try {
|
||||
const body: Record<string, string> = {}
|
||||
if (filterMerchantId.value) {
|
||||
body.merchantId = filterMerchantId.value
|
||||
}
|
||||
const res = await appEnergyMealListPost({
|
||||
params: { pageNum, pageSize },
|
||||
body,
|
||||
})
|
||||
const rows = Array.isArray(res.rows) ? res.rows : []
|
||||
const total = Number(res.total ?? rows.length)
|
||||
await paging.value?.completeByTotal(rows, total)
|
||||
} catch {
|
||||
await paging.value?.complete(false)
|
||||
} finally {
|
||||
if (pageNum === 1) {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleAddAllToCart(meal: EnergyMealVo) {
|
||||
if (!userStore.checkLogin()) return
|
||||
if (!meal.id) return
|
||||
if (!canAddMeal(meal)) {
|
||||
uni.showToast({
|
||||
title: t('pages-store.energyMeal.unavailable'),
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (addingMealId.value != null) return
|
||||
|
||||
addingMealId.value = meal.id
|
||||
try {
|
||||
await appEnergyMealAddCartPost({
|
||||
body: {
|
||||
energyMealId: meal.id,
|
||||
count: 1,
|
||||
},
|
||||
options: { hideErrorToast: true },
|
||||
})
|
||||
uni.showToast({
|
||||
title: t('toast.addCartSuccess'),
|
||||
icon: 'none',
|
||||
})
|
||||
userStore.getUserCartAllData()
|
||||
} catch (err: any) {
|
||||
uni.showToast({
|
||||
title: err?.msg || err?.message || t('common.prompt.request-failed-please-try-again-later'),
|
||||
icon: 'none',
|
||||
})
|
||||
} finally {
|
||||
if (addingMealId.value === meal.id) {
|
||||
addingMealId.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<z-paging
|
||||
ref="paging"
|
||||
v-model="mealList"
|
||||
bg-color="#f2f2f2"
|
||||
:auto="true"
|
||||
:hide-empty-view="loading"
|
||||
@query="onQuery"
|
||||
>
|
||||
<template #top>
|
||||
<navbar :title="t('pages-store.energyMeal.title')" circle-back />
|
||||
</template>
|
||||
|
||||
<view
|
||||
v-show="loading"
|
||||
class="animate-in fade-in animate-ease-out animate-duration-300"
|
||||
>
|
||||
<energy-meal-skeleton />
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-show="!loading"
|
||||
class="animate-in fade-in animate-ease-in animate-duration-300 energy-meal-page"
|
||||
>
|
||||
<view
|
||||
v-for="meal in mealList"
|
||||
:key="meal.id"
|
||||
class="energy-meal-card"
|
||||
>
|
||||
<view v-if="meal.mealName" class="energy-meal-card__head">
|
||||
<text class="energy-meal-card__title line-clamp-1">{{ meal.mealName }}</text>
|
||||
<text
|
||||
v-if="meal.merchant?.merchantName"
|
||||
class="energy-meal-card__merchant line-clamp-1"
|
||||
>
|
||||
{{ meal.merchant.merchantName }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="(item, index) in sortedItems(meal)"
|
||||
:key="item.id || `${meal.id}-${index}`"
|
||||
class="energy-dish-row"
|
||||
:class="{ 'energy-dish-row--last': index === sortedItems(meal).length - 1 }"
|
||||
@click="openDishDetail(item, meal)"
|
||||
>
|
||||
<view class="energy-dish-row__img-wrap">
|
||||
<image
|
||||
:src="thumbnailImg(dishCover(item))"
|
||||
mode="aspectFill"
|
||||
class="energy-dish-row__img"
|
||||
/>
|
||||
</view>
|
||||
<view class="energy-dish-row__main">
|
||||
<text class="energy-dish-row__name line-clamp-2">{{ dishName(item) }}</text>
|
||||
<view class="energy-dish-row__price-row">
|
||||
<text class="energy-dish-row__price-current">${{ dishPrice(item) }}</text>
|
||||
<text
|
||||
v-if="dishOriginalPrice(item)"
|
||||
class="energy-dish-row__price-old"
|
||||
>
|
||||
${{ dishOriginalPrice(item) }}
|
||||
</text>
|
||||
</view>
|
||||
<view
|
||||
v-if="dishMemberPrice(item)"
|
||||
class="energy-dish-row__member"
|
||||
>
|
||||
<text class="energy-dish-row__member-diamond">◆</text>
|
||||
<text class="energy-dish-row__member-text">
|
||||
{{ Config.appName }} {{ t('pages.search.member-price-line') }}: ${{ dishMemberPrice(item) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="energy-dish-row__sales-wrap">
|
||||
<text class="energy-dish-row__sales-tag">
|
||||
{{ t('pages.search.weekly-sales') }}:{{ formatSalesCount(item.merchantDishVo?.salesCount) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="canAddMeal(meal)"
|
||||
class="energy-meal-card__action"
|
||||
>
|
||||
<view
|
||||
class="energy-meal-card__btn"
|
||||
:class="{ 'energy-meal-card__btn--loading': addingMealId === meal.id }"
|
||||
@click.stop="handleAddAllToCart(meal)"
|
||||
>
|
||||
{{ t('pages-store.energyMeal.addAllToCart') }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<template #empty>
|
||||
<view v-if="!loading" class="energy-meal-empty">
|
||||
<image class="energy-meal-empty__img" src="@img/chef/100.png" mode="aspectFit" />
|
||||
<text class="energy-meal-empty__text">{{ t('pages-store.energyMeal.empty') }}</text>
|
||||
</view>
|
||||
</template>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.energy-meal-page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.energy-meal-card {
|
||||
margin-bottom: 24rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.energy-meal-card__head {
|
||||
padding: 24rpx 24rpx 8rpx;
|
||||
}
|
||||
|
||||
.energy-meal-card__title {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
line-height: 42rpx;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.energy-meal-card__merchant {
|
||||
display: block;
|
||||
margin-top: 6rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 34rpx;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.energy-dish-row {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding: 28rpx 24rpx;
|
||||
border-bottom: 1rpx solid #ebebeb;
|
||||
}
|
||||
|
||||
.energy-dish-row--last {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.energy-dish-row__img-wrap {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.energy-dish-row__img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.energy-dish-row__main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.energy-dish-row__name {
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
font-weight: 500;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.energy-dish-row__price-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.energy-dish-row__price-current {
|
||||
font-size: 32rpx;
|
||||
line-height: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #e02e24;
|
||||
}
|
||||
|
||||
.energy-dish-row__price-old {
|
||||
font-size: 24rpx;
|
||||
line-height: 28rpx;
|
||||
color: #999;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.energy-dish-row__member {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.energy-dish-row__member-diamond {
|
||||
font-size: 20rpx;
|
||||
line-height: 1;
|
||||
color: #b8860b;
|
||||
}
|
||||
|
||||
.energy-dish-row__member-text {
|
||||
font-size: 24rpx;
|
||||
line-height: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #8b6914;
|
||||
}
|
||||
|
||||
.energy-dish-row__sales-wrap {
|
||||
margin-top: auto;
|
||||
padding-top: 12rpx;
|
||||
}
|
||||
|
||||
.energy-dish-row__sales-tag {
|
||||
display: inline-block;
|
||||
padding: 8rpx 18rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f5f5f5;
|
||||
font-size: 22rpx;
|
||||
line-height: 28rpx;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.energy-meal-card__action {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 8rpx 24rpx 24rpx;
|
||||
}
|
||||
|
||||
.energy-meal-card__btn {
|
||||
min-width: 280rpx;
|
||||
height: 72rpx;
|
||||
padding: 0 32rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #111;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
line-height: 72rpx;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.energy-meal-card__btn--loading {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.energy-meal-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 48rpx;
|
||||
}
|
||||
|
||||
.energy-meal-empty__img {
|
||||
width: 250rpx;
|
||||
height: 250rpx;
|
||||
}
|
||||
|
||||
.energy-meal-empty__text {
|
||||
margin-top: 24rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #8a8a8a;
|
||||
}
|
||||
</style>
|
||||
@@ -284,6 +284,12 @@
|
||||
},
|
||||
{
|
||||
"path": "pages/home-store/index"
|
||||
},
|
||||
{
|
||||
"path": "pages/energy-meal/index",
|
||||
"style": {
|
||||
"onReachBottomDistance": 80
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = defineProps({
|
||||
/** 外部列表(菜谱页等);首页不传则使用固定五项 */
|
||||
/** 外部列表(菜谱页等);首页不传则使用固定六项 */
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
@@ -55,6 +55,11 @@ const fixedTabs = [
|
||||
nameKey: 'pages.home.quickTabs.freshSeafoodToday',
|
||||
logoUrl: '/static/app/images/home/xiandahaixian.png',
|
||||
},
|
||||
{
|
||||
id: 'energy-meal',
|
||||
nameKey: 'pages.home.quickTabs.energyMeal',
|
||||
logoUrl: '/static/app/images/home/nengliangcan.png',
|
||||
},
|
||||
]
|
||||
|
||||
const useFixedTabs = computed(() => !props.list || props.list.length === 0)
|
||||
@@ -63,10 +68,6 @@ function selectTab(item: Record<string, unknown>) {
|
||||
emit('changeType', item[props.valueKey])
|
||||
}
|
||||
|
||||
function imageWidthByIndex(index: number) {
|
||||
return (index + 1) % 2 === 1 ? '104rpx' : '210rpx'
|
||||
}
|
||||
|
||||
function getTabName(item: Record<string, unknown>) {
|
||||
if (useFixedTabs.value && item.nameKey) {
|
||||
return t(String(item.nameKey))
|
||||
@@ -97,8 +98,7 @@ const displayList = computed(() =>
|
||||
<image
|
||||
class="tab-img"
|
||||
:src="getImage(item as Record<string, unknown>)"
|
||||
mode="scaleToFill"
|
||||
:style="{ width: imageWidthByIndex(index) }"
|
||||
mode="heightFix"
|
||||
/>
|
||||
<text class="tab-label line-clamp-1">{{ getTabName(item as Record<string, unknown>) }}</text>
|
||||
</view>
|
||||
@@ -122,7 +122,6 @@ const displayList = computed(() =>
|
||||
|
||||
.tab-img {
|
||||
height: 144rpx;
|
||||
width: auto;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
@@ -236,6 +236,10 @@ function handleItemClick(e) {
|
||||
}
|
||||
function tabsTypeChange(id: string | number) {
|
||||
const topic = String(id)
|
||||
if (topic === 'energy-meal') {
|
||||
navigateTo('/pages-store/pages/energy-meal/index')
|
||||
return
|
||||
}
|
||||
if (!isQuickTopicSlug(topic)) {
|
||||
return
|
||||
}
|
||||
@@ -310,6 +314,9 @@ function handleClickSwiper(item: any) {
|
||||
case 3: // 会员
|
||||
navigateTo('/pages-user/pages/member/index')
|
||||
break
|
||||
case 5: // 钱包
|
||||
navigateTo('/pages-user/pages/balance/index')
|
||||
break
|
||||
// case 4:
|
||||
// navigateTo('/pages/ai/chat/index')
|
||||
// break
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import request from '@/http/vue-query';
|
||||
import type { CustomRequestOptions } from '@/http/types';
|
||||
|
||||
export interface EnergyMealListQueryBo {
|
||||
merchantId?: number | string;
|
||||
mealName?: string;
|
||||
merchantName?: string;
|
||||
}
|
||||
|
||||
export interface EnergyMealItemVo {
|
||||
id?: number | string;
|
||||
energyMealId?: number | string;
|
||||
dishId?: number | string;
|
||||
quantity?: number;
|
||||
sort?: number;
|
||||
delFlag?: number;
|
||||
merchantDishVo?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface EnergyMealVo {
|
||||
id?: number | string;
|
||||
merchantId?: number | string;
|
||||
mealName?: string;
|
||||
coverImage?: string;
|
||||
sort?: number;
|
||||
delFlag?: number;
|
||||
remark?: string;
|
||||
merchant?: {
|
||||
id?: number | string;
|
||||
merchantName?: string;
|
||||
logo?: string;
|
||||
merchantAddress?: string;
|
||||
};
|
||||
itemList?: EnergyMealItemVo[];
|
||||
}
|
||||
|
||||
export interface EnergyMealAddCartBo {
|
||||
energyMealId: number | string;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
/** 能量餐分页列表 POST /app/energyMeal/list */
|
||||
export async function appEnergyMealListPost({
|
||||
params,
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
params: { pageNum: number; pageSize: number };
|
||||
body?: EnergyMealListQueryBo;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<{ rows?: EnergyMealVo[]; total?: number }>(
|
||||
'/app/energyMeal/list',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
data: body ?? {},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** 能量餐一键加入购物车 POST /app/energyMeal/addCart */
|
||||
export async function appEnergyMealAddCartPost({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: EnergyMealAddCartBo;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<{ data?: number[] }>('/app/energyMeal/addCart', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
@@ -44,3 +44,4 @@ export * from './automaticCookingMachine';
|
||||
export * from './userCoupon';
|
||||
export * from './marketingActivity';
|
||||
export * from './marketActivity';
|
||||
export * from './energyMeal';
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
Reference in New Issue
Block a user