fix:修复bug
This commit is contained in:
+18
-51
@@ -14,60 +14,27 @@ const message = useMessage();
|
||||
function handleClickSearch() {
|
||||
uni.navigateTo({
|
||||
url: '/pages-user/pages/search-address/index',
|
||||
events: {
|
||||
chooseAddress: (data: any) => {
|
||||
console.log('搜索的地址信息', data)
|
||||
if (data) {
|
||||
addressStore.setAddressLocation({
|
||||
displayName: data.displayName,
|
||||
formattedAddress: data.formattedAddress,
|
||||
longitude: data.location.lng,
|
||||
latitude: data.location.lat
|
||||
})
|
||||
setTimeout(()=> {
|
||||
uni.navigateTo({
|
||||
url: '/pages/address/choose-type'
|
||||
})
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
useEventEmit(EventEnum.CHOOSE_ADDRESS, (data) => {
|
||||
console.log('搜索的地址信息', data)
|
||||
if(data) {
|
||||
// 从addressComponents中提取州名/省名
|
||||
// let stateName = '';
|
||||
// if (data.addressComponents && Array.isArray(data.addressComponents)) {
|
||||
// // 先判断是否为中国地址
|
||||
// const countryComponent = data.addressComponents.find(component =>
|
||||
// component.types && component.types.includes('country')
|
||||
// );
|
||||
// const isChina = countryComponent && (countryComponent.shortText === 'CN' || countryComponent.longText === '中国');
|
||||
//
|
||||
// if (isChina) {
|
||||
// // 中国地址:优先取市级(locality),如果没有则取省级(administrative_area_level_1)
|
||||
// const cityComponent = data.addressComponents.find(component =>
|
||||
// component.types && component.types.includes('locality')
|
||||
// );
|
||||
// const provinceComponent = data.addressComponents.find(component =>
|
||||
// component.types && component.types.includes('administrative_area_level_1')
|
||||
// );
|
||||
//
|
||||
// if (cityComponent) {
|
||||
// stateName = cityComponent.longText || cityComponent.shortText || '';
|
||||
// } else if (provinceComponent) {
|
||||
// stateName = provinceComponent.longText || provinceComponent.shortText || '';
|
||||
// }
|
||||
// } else {
|
||||
// // 美国等其他国家:取州级(administrative_area_level_1)
|
||||
// const stateComponent = data.addressComponents.find(component =>
|
||||
// component.types && component.types.includes('administrative_area_level_1')
|
||||
// );
|
||||
// if (stateComponent) {
|
||||
// stateName = stateComponent.longText || stateComponent.shortText || '';
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
addressStore.setAddressLocation({
|
||||
displayName: data.displayName,
|
||||
formattedAddress: data.formattedAddress,
|
||||
longitude: data.location.lng,
|
||||
latitude: data.location.lat
|
||||
})
|
||||
setTimeout(()=> {
|
||||
uni.navigateTo({
|
||||
url: '/pages/address/choose-type'
|
||||
})
|
||||
}, 300)
|
||||
}
|
||||
})
|
||||
|
||||
function reservationTime() {
|
||||
uni.navigateTo({ url: '/pages/address/reservation-time' })
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import dayjs from "dayjs";
|
||||
// MONDAY/TUESDAY/WEDNESDAY 09:00-16:00
|
||||
// MONDAY 09:00-18:00;TUESDAY 09:00-10:00;WEDNESDAY 09:00-18:00;THURSDAY 09:00-18:00;FRIDAY 08:00-09:00
|
||||
const storeBusinessHours = ref('');
|
||||
// 是否仅选择日期(当进入页面传递了 storeBusinessHours 时开启)
|
||||
const onlySelectDay = ref(false);
|
||||
// 是否仅选择日期(当前需求:只选哪一天配送,不选具体时间段)
|
||||
const onlySelectDay = ref(true);
|
||||
|
||||
// 业务规则:只能预约周一 / 周四 / 周五
|
||||
// JS 中:0-周日 1-周一 ... 4-周四 5-周五
|
||||
|
||||
@@ -15,10 +15,11 @@ const addressStore = useAddressStore()
|
||||
const visitMethodRef = ref<InstanceType<typeof VisitMethod>>()
|
||||
const buildingTypeRef = ref<InstanceType<typeof BuildingType>>()
|
||||
function openVisitMethod() {
|
||||
visitMethodRef.value?.onOpen()
|
||||
// deliveryType: 1-亲自送达(0) 2-放门口(1),打开时回显当前选中
|
||||
visitMethodRef.value?.onOpen(+addressStore.addressInfo.deliveryType === 2 ? 1 : 0)
|
||||
}
|
||||
|
||||
const visitMethod = ref(t('components.visit.leaveItToMePersonally')) // 默认选择亲自送达
|
||||
const visitMethod = ref(t('components.visit.putItAtTheDoor')) // 默认选择放在门口
|
||||
function visitMethodConfirm(data: any) {
|
||||
console.log('visitMethodConfirm', data)
|
||||
visitMethod.value = data.label;
|
||||
|
||||
@@ -14,10 +14,11 @@ const addressStore = useAddressStore()
|
||||
const visitMethodRef = ref<InstanceType<typeof VisitMethod>>()
|
||||
const buildingTypeRef = ref<InstanceType<typeof BuildingType>>()
|
||||
function openVisitMethod() {
|
||||
visitMethodRef.value?.onOpen()
|
||||
// deliveryType: 1-亲自送达(0) 2-放门口(1),打开时回显当前选中
|
||||
visitMethodRef.value?.onOpen(+addressStore.addressInfo.deliveryType === 2 ? 1 : 0)
|
||||
}
|
||||
|
||||
const visitMethod = ref(t('components.visit.leaveItToMePersonally')) // 默认选择亲自送达
|
||||
const visitMethod = ref(t('components.visit.putItAtTheDoor')) // 默认选择放在门口
|
||||
function visitMethodConfirm(data: any) {
|
||||
console.log('visitMethodConfirm', data)
|
||||
visitMethod.value = data.label;
|
||||
|
||||
@@ -14,10 +14,11 @@ const addressStore = useAddressStore()
|
||||
const visitMethodRef = ref<InstanceType<typeof VisitMethod>>()
|
||||
const buildingTypeRef = ref<InstanceType<typeof BuildingType>>()
|
||||
function openVisitMethod() {
|
||||
visitMethodRef.value?.onOpen()
|
||||
// deliveryType: 1-亲自送达(0) 2-放门口(1),打开时回显当前选中
|
||||
visitMethodRef.value?.onOpen(+addressStore.addressInfo.deliveryType === 2 ? 1 : 0)
|
||||
}
|
||||
|
||||
const visitMethod = ref(t('components.visit.leaveItToMePersonally')) // 默认选择亲自送达
|
||||
const visitMethod = ref(t('components.visit.putItAtTheDoor')) // 默认选择放在门口
|
||||
function visitMethodConfirm(data: any) {
|
||||
console.log('visitMethodConfirm', data)
|
||||
visitMethod.value = data.label;
|
||||
|
||||
@@ -14,10 +14,11 @@ const addressStore = useAddressStore()
|
||||
const visitMethodRef = ref<InstanceType<typeof VisitMethod>>()
|
||||
const buildingTypeRef = ref<InstanceType<typeof BuildingType>>()
|
||||
function openVisitMethod() {
|
||||
visitMethodRef.value?.onOpen()
|
||||
// deliveryType: 1-亲自送达(0) 2-放门口(1),打开时回显当前选中
|
||||
visitMethodRef.value?.onOpen(+addressStore.addressInfo.deliveryType === 2 ? 1 : 0)
|
||||
}
|
||||
|
||||
const visitMethod = ref(t('components.visit.leaveItToMePersonally')) // 默认选择亲自送达
|
||||
const visitMethod = ref(t('components.visit.putItAtTheDoor')) // 默认选择放在门口
|
||||
function visitMethodConfirm(data: any) {
|
||||
console.log('visitMethodConfirm', data)
|
||||
visitMethod.value = data.label;
|
||||
|
||||
@@ -14,10 +14,11 @@ const addressStore = useAddressStore()
|
||||
const visitMethodRef = ref<InstanceType<typeof VisitMethod>>()
|
||||
const buildingTypeRef = ref<InstanceType<typeof BuildingType>>()
|
||||
function openVisitMethod() {
|
||||
visitMethodRef.value?.onOpen()
|
||||
// deliveryType: 1-亲自送达(0) 2-放门口(1),打开时回显当前选中
|
||||
visitMethodRef.value?.onOpen(+addressStore.addressInfo.deliveryType === 2 ? 1 : 0)
|
||||
}
|
||||
|
||||
const visitMethod = ref(t('components.visit.leaveItToMePersonally')) // 默认选择亲自送达
|
||||
const visitMethod = ref(t('components.visit.putItAtTheDoor')) // 默认选择放在门口
|
||||
function visitMethodConfirm(data: any) {
|
||||
console.log('visitMethodConfirm', data)
|
||||
visitMethod.value = data.label;
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { UserAddressBo } from '@/service/types';
|
||||
export const useAddressStore = defineStore('store-address', () => {
|
||||
const addressInfo = ref<UserAddressBo>({
|
||||
type: '',
|
||||
/** 配送类型 1 2 */
|
||||
deliveryType: '1',
|
||||
/** 配送类型 1-亲自送达 2-放门口,默认放门口 */
|
||||
deliveryType: '2',
|
||||
/** 配送说明 */
|
||||
deliveryRemark: '',
|
||||
/** 配送图片 */
|
||||
@@ -60,8 +60,8 @@ export const useAddressStore = defineStore('store-address', () => {
|
||||
addressInfo.value = {
|
||||
id: '',
|
||||
type: '',
|
||||
/** 配送类型 1 2 */
|
||||
deliveryType: '1',
|
||||
/** 配送类型 1-亲自送达 2-放门口,默认放门口 */
|
||||
deliveryType: '2',
|
||||
/** 配送说明 */
|
||||
deliveryRemark: '',
|
||||
/** 配送图片 */
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
<template>
|
||||
<view class="class-bullet-container">
|
||||
<!-- 第一行(可拖动 + 自动滚动) -->
|
||||
<!-- 第一行:自动缓慢滚动 + 可手动滑动 -->
|
||||
<view class="scroll-row first-row">
|
||||
<scroll-view
|
||||
class="ab-scroll mb-22rpx"
|
||||
scroll-x
|
||||
show-scrollbar="false"
|
||||
id="sv-1"
|
||||
style="--ab-scroll-timeout: 50s"
|
||||
:scroll-left="scrollLeft1"
|
||||
@touchstart="onTouchStart1"
|
||||
@touchend="onTouchEnd1"
|
||||
@touchcancel="onTouchEnd1"
|
||||
@scroll="onScroll1"
|
||||
>
|
||||
<view id="sv-inner-1" :class="['sv-inner', { 'paused': isDragging1 }]">
|
||||
<view class="sv-inner" id="sv1-inner">
|
||||
<!-- 一份内容 -->
|
||||
<view
|
||||
v-for="(item, idx) in categories"
|
||||
:key="item.id + '-a-' + idx"
|
||||
:key="item.id + '-row1-a-' + idx"
|
||||
class="category-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<image v-if="item.categoryImage || item.logoUrl" :src="item.categoryImage || item.logoUrl" class="category-icon" mode="aspectFit" />
|
||||
<text class="category-text">{{ item.categoryName || item.name }}</text>
|
||||
</view>
|
||||
<!-- 第二份重复内容(用于无缝循环) -->
|
||||
<!-- 第二份重复内容,用于无缝滚动 -->
|
||||
<view
|
||||
v-for="(item, idx) in categories"
|
||||
:key="item.id + '-b-' + idx"
|
||||
:key="item.id + '-row1-b-' + idx"
|
||||
class="category-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
@@ -39,24 +37,22 @@
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 第二行(可拖动 + 自动滚动,速度不同) -->
|
||||
<!-- 第二行:反向数据,自动滚动速度略不同 -->
|
||||
<view class="scroll-row">
|
||||
<scroll-view
|
||||
class="ab-scroll"
|
||||
scroll-x
|
||||
show-scrollbar="false"
|
||||
id="sv-2"
|
||||
style="--ab-scroll-timeout: 70s"
|
||||
:scroll-left="scrollLeft2"
|
||||
@touchstart="onTouchStart2"
|
||||
@touchend="onTouchEnd2"
|
||||
@touchcancel="onTouchEnd2"
|
||||
@scroll="onScroll2"
|
||||
>
|
||||
<view id="sv-inner-2" :class="['sv-inner', { 'paused': isDragging2 }]">
|
||||
<view class="sv-inner" id="sv2-inner">
|
||||
<view
|
||||
v-for="(item, idx) in categoriesReversed"
|
||||
:key="item.id + '-c-' + idx"
|
||||
:key="item.id + '-row2-a-' + idx"
|
||||
class="category-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
@@ -65,7 +61,7 @@
|
||||
</view>
|
||||
<view
|
||||
v-for="(item, idx) in categoriesReversed"
|
||||
:key="item.id + '-d-' + idx"
|
||||
:key="item.id + '-row2-b-' + idx"
|
||||
class="category-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
@@ -80,7 +76,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onMounted, nextTick, getCurrentInstance } from 'vue'
|
||||
import { computed, ref, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
|
||||
// 定义分类项接口(与模板字段一致)
|
||||
interface CategoryItem {
|
||||
@@ -88,7 +84,7 @@ interface CategoryItem {
|
||||
categoryImage?: string
|
||||
logoUrl?: string
|
||||
name?: string
|
||||
categoryName: string
|
||||
categoryName?: string
|
||||
}
|
||||
|
||||
// 定义组件属性
|
||||
@@ -128,116 +124,121 @@ const categoriesReversed = computed(() => {
|
||||
return list.slice().reverse()
|
||||
})
|
||||
|
||||
// 自动滚动(CSS 动画)+ 手动拖动时暂停
|
||||
const isDragging1 = ref(false)
|
||||
const isDragging2 = ref(false)
|
||||
const RESUME_DELAY_MS = 1200
|
||||
let resumeTimer1: any
|
||||
let resumeTimer2: any
|
||||
// ===== 自动滚动相关(电商标签推荐风格) =====
|
||||
// 视口宽度,用于计算最大可滚动距离(scrollWidth - viewportWidth)
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
const viewportWidth = systemInfo.windowWidth || 0
|
||||
|
||||
// 中心定位与边界重置,避免滚动到底卡住
|
||||
const scrollLeft1 = ref(0)
|
||||
const scrollLeft2 = ref(0)
|
||||
const copyWidth1Px = ref(0)
|
||||
const copyWidth2Px = ref(0)
|
||||
const viewportWidth1Px = ref(0)
|
||||
const viewportWidth2Px = ref(0)
|
||||
|
||||
function measureAndInit() {
|
||||
const ins = getCurrentInstance()
|
||||
const q = uni.createSelectorQuery().in(ins?.proxy as any)
|
||||
q.select('#sv-1').boundingClientRect()
|
||||
.select('#sv-inner-1').boundingClientRect()
|
||||
.select('#sv-2').boundingClientRect()
|
||||
.select('#sv-inner-2').boundingClientRect()
|
||||
.exec((res) => {
|
||||
const sv1 = res?.[0]
|
||||
const inner1 = res?.[1]
|
||||
const sv2 = res?.[2]
|
||||
const inner2 = res?.[3]
|
||||
if (sv1?.width) viewportWidth1Px.value = sv1.width
|
||||
if (inner1?.width) copyWidth1Px.value = inner1.width / 2
|
||||
if (sv2?.width) viewportWidth2Px.value = sv2.width
|
||||
if (inner2?.width) copyWidth2Px.value = inner2.width / 2
|
||||
// 初始化到中间位置
|
||||
if (copyWidth1Px.value) scrollLeft1.value = copyWidth1Px.value
|
||||
if (copyWidth2Px.value) scrollLeft2.value = copyWidth2Px.value
|
||||
})
|
||||
// 最大可滚动距离(由 scroll 事件提供,避免自己算)
|
||||
const maxScroll1 = ref(0)
|
||||
const maxScroll2 = ref(0)
|
||||
|
||||
const isTouching1 = ref(false)
|
||||
const isTouching2 = ref(false)
|
||||
|
||||
let autoTimer1: any = null
|
||||
let autoTimer2: any = null
|
||||
let resumeTimer1: any = null
|
||||
let resumeTimer2: any = null
|
||||
|
||||
// 速度和间隔可以根据效果微调
|
||||
const AUTO_INTERVAL = 30
|
||||
const AUTO_STEP_1 = 0.6
|
||||
const AUTO_STEP_2 = 0.4
|
||||
const RESUME_DELAY = 800
|
||||
const RESET_THRESHOLD = 2 // 在距离末尾一定范围内就重置
|
||||
|
||||
function startAuto1() {
|
||||
if (autoTimer1) return
|
||||
autoTimer1 = setInterval(() => {
|
||||
if (isTouching1.value) return
|
||||
let next = scrollLeft1.value + AUTO_STEP_1
|
||||
const max = maxScroll1.value
|
||||
if (max > 0 && next >= max - RESET_THRESHOLD) {
|
||||
// 距离最右侧很近时,从头开始,实现循环
|
||||
next = 0
|
||||
}
|
||||
scrollLeft1.value = next
|
||||
}, AUTO_INTERVAL)
|
||||
}
|
||||
|
||||
function recenter1(currentLeft?: number) {
|
||||
const cw = copyWidth1Px.value
|
||||
const vw = viewportWidth1Px.value
|
||||
if (!cw || !vw) return
|
||||
const left = currentLeft ?? scrollLeft1.value
|
||||
const mod = left % cw
|
||||
scrollLeft1.value = cw + mod
|
||||
function startAuto2() {
|
||||
if (autoTimer2) return
|
||||
autoTimer2 = setInterval(() => {
|
||||
if (isTouching2.value) return
|
||||
let next = scrollLeft2.value + AUTO_STEP_2
|
||||
const max = maxScroll2.value
|
||||
if (max > 0 && next >= max - RESET_THRESHOLD) {
|
||||
next = 0
|
||||
}
|
||||
scrollLeft2.value = next
|
||||
}, AUTO_INTERVAL)
|
||||
}
|
||||
|
||||
function recenter2(currentLeft?: number) {
|
||||
const cw = copyWidth2Px.value
|
||||
const vw = viewportWidth2Px.value
|
||||
if (!cw || !vw) return
|
||||
const left = currentLeft ?? scrollLeft2.value
|
||||
const mod = left % cw
|
||||
scrollLeft2.value = cw + mod
|
||||
function stopAuto1() {
|
||||
if (autoTimer1) {
|
||||
clearInterval(autoTimer1)
|
||||
autoTimer1 = null
|
||||
}
|
||||
}
|
||||
|
||||
function stopAuto2() {
|
||||
if (autoTimer2) {
|
||||
clearInterval(autoTimer2)
|
||||
autoTimer2 = null
|
||||
}
|
||||
}
|
||||
|
||||
function onTouchStart1() {
|
||||
isDragging1.value = true
|
||||
isTouching1.value = true
|
||||
if (resumeTimer1) clearTimeout(resumeTimer1)
|
||||
stopAuto1()
|
||||
}
|
||||
|
||||
function onTouchEnd1() {
|
||||
// 手指松开后,若在边界附近,立即重置到中间位置,保持无缝
|
||||
recenter1(scrollLeft1.value)
|
||||
resumeTimer1 = setTimeout(() => {
|
||||
isDragging1.value = false
|
||||
}, RESUME_DELAY_MS)
|
||||
isTouching1.value = false
|
||||
startAuto1()
|
||||
}, RESUME_DELAY)
|
||||
}
|
||||
|
||||
function onScroll1(e: any) {
|
||||
isDragging1.value = true
|
||||
if (resumeTimer1) clearTimeout(resumeTimer1)
|
||||
const left = e?.detail?.scrollLeft ?? 0
|
||||
const cw = copyWidth1Px.value
|
||||
const vw = viewportWidth1Px.value
|
||||
if (cw && vw) {
|
||||
const total = cw * 2
|
||||
// 临界阈值,靠近起点或终点时重置
|
||||
const threshold = 10
|
||||
if (left <= threshold || left >= total - vw - threshold) {
|
||||
recenter1(left)
|
||||
const detail = e?.detail
|
||||
if (detail && typeof detail.scrollLeft === 'number') {
|
||||
scrollLeft1.value = detail.scrollLeft
|
||||
// scrollWidth - viewportWidth 为最大可滚动距离
|
||||
if (typeof detail.scrollWidth === 'number' && viewportWidth > 0) {
|
||||
const max = detail.scrollWidth - viewportWidth
|
||||
maxScroll1.value = max > 0 ? max : 0
|
||||
}
|
||||
}
|
||||
resumeTimer1 = setTimeout(() => {
|
||||
isDragging1.value = false
|
||||
}, RESUME_DELAY_MS)
|
||||
}
|
||||
|
||||
function onTouchStart2() {
|
||||
isDragging2.value = true
|
||||
isTouching2.value = true
|
||||
if (resumeTimer2) clearTimeout(resumeTimer2)
|
||||
stopAuto2()
|
||||
}
|
||||
|
||||
function onTouchEnd2() {
|
||||
recenter2(scrollLeft2.value)
|
||||
resumeTimer2 = setTimeout(() => {
|
||||
isDragging2.value = false
|
||||
}, RESUME_DELAY_MS)
|
||||
isTouching2.value = false
|
||||
startAuto2()
|
||||
}, RESUME_DELAY)
|
||||
}
|
||||
|
||||
function onScroll2(e: any) {
|
||||
isDragging2.value = true
|
||||
if (resumeTimer2) clearTimeout(resumeTimer2)
|
||||
const left = e?.detail?.scrollLeft ?? 0
|
||||
const cw = copyWidth2Px.value
|
||||
const vw = viewportWidth2Px.value
|
||||
if (cw && vw) {
|
||||
const total = cw * 2
|
||||
const threshold = 10
|
||||
if (left <= threshold || left >= total - vw - threshold) {
|
||||
recenter2(left)
|
||||
const detail = e?.detail
|
||||
if (detail && typeof detail.scrollLeft === 'number') {
|
||||
scrollLeft2.value = detail.scrollLeft
|
||||
if (typeof detail.scrollWidth === 'number' && viewportWidth > 0) {
|
||||
const max = detail.scrollWidth - viewportWidth
|
||||
maxScroll2.value = max > 0 ? max : 0
|
||||
}
|
||||
}
|
||||
resumeTimer2 = setTimeout(() => {
|
||||
isDragging2.value = false
|
||||
}, RESUME_DELAY_MS)
|
||||
}
|
||||
|
||||
// 点击处理
|
||||
@@ -252,9 +253,20 @@ function navigateTo(url: string) {
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
measureAndInit()
|
||||
// 启动自动滚动,maxScroll 值会在第一次 scroll 事件时更新
|
||||
setTimeout(() => {
|
||||
startAuto1()
|
||||
startAuto2()
|
||||
}, 300)
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
stopAuto1()
|
||||
stopAuto2()
|
||||
if (resumeTimer1) clearTimeout(resumeTimer1)
|
||||
if (resumeTimer2) clearTimeout(resumeTimer2)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -280,8 +292,6 @@ onMounted(() => {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20rpx;
|
||||
animation: ab-move-marquee var(--ab-scroll-timeout) linear infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
@@ -316,17 +326,5 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
// GPU 动画,无缝循环(两份内容)
|
||||
@keyframes ab-move-marquee {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
.paused {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
// 取消 CSS 动画,由 JS 控制的 scroll-left 实现无缝滚动,避免与手势滚动冲突导致的抖动
|
||||
</style>
|
||||
|
||||
@@ -24,7 +24,7 @@ function handleClickFood(item: any) {
|
||||
<view class="text-24rpx lh-24rpx flex items-center mt-12rpx">
|
||||
<text class="text-#333 font-500">{{ item.rating }}</text>
|
||||
<image src="@img/chef/124.png" class="w-24rpx h-24rpx mx-4rpx mt-2rpx"></image>
|
||||
<text class="text-#7D7D7D">({{ item.commentCount }}) • {{ item.deliveryTime }} {{ t('common.minutes') }}</text>
|
||||
<text class="text-#7D7D7D">({{ item.commentCount }}) • {{ item.deliveryTime }} {{ Number(item.deliveryTime) === 1 ? t('common.day') : t('common.days') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -7,12 +7,24 @@
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
-->
|
||||
<script setup lang="ts">
|
||||
// @ts-ignore - Vue SFC default export is provided by tooling
|
||||
import Collection from "@/components/collection/index.vue";
|
||||
import {appCollectCollectPost} from "@/service";
|
||||
import {CollectionType} from "@/constant/enums";
|
||||
const { t } = useI18n();
|
||||
type FoodBoxItem = {
|
||||
id: number | string;
|
||||
merchantId?: string;
|
||||
isCollect?: boolean;
|
||||
dishImage?: string;
|
||||
logo?: string;
|
||||
dishName?: string;
|
||||
merchantName?: string;
|
||||
originalPrice?: string | number;
|
||||
[key: string]: any;
|
||||
};
|
||||
const props = defineProps<{
|
||||
item: object;
|
||||
item: FoodBoxItem;
|
||||
}>();
|
||||
|
||||
function handleClickFood() {
|
||||
@@ -34,10 +46,11 @@ if(props.item.merchantId){
|
||||
}
|
||||
|
||||
function handleCollectionChange(value: boolean) {
|
||||
const isDish = !!props.item?.merchantId;
|
||||
appCollectCollectPost({
|
||||
body: {
|
||||
targetId: props.item.id,
|
||||
targetType: CollectionType.STORE
|
||||
targetId: String(props.item.id),
|
||||
targetType: isDish ? CollectionType.DISH : CollectionType.STORE
|
||||
}
|
||||
}).then(res=> {
|
||||
props.item.isCollect = value;
|
||||
@@ -69,7 +82,7 @@ function handleCollectionChange(value: boolean) {
|
||||
<!-- <text class="text-#7D7D7D">({{ item.commentCount }}) • {{ item.deliveryTime }}{{ t('common.minutes') }}</text> -->
|
||||
</view>
|
||||
</view>
|
||||
<collection :is-collected="item.isCollect" @collectionChange="handleCollectionChange" />
|
||||
<collection :is-collected="item.isCollect" @collection-change="handleCollectionChange" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -25,7 +25,7 @@ function handleClickFood(item: any) {
|
||||
<view class="w-156rpx text-center line-clamp-1 text-#333 text-28rpx lh-28rpx mt-12rpx font-500">
|
||||
{{ item.merchantName }}
|
||||
</view>
|
||||
<view v-if="+item.deliveryService === 1" class="mt-12rpx text-center text-24rpx lh-24rpx text-#7D7D7D">{{ item.deliveryTime }}{{ t('common.minutes') }}</view>
|
||||
<view v-if="+item.deliveryService === 1" class="mt-12rpx text-center text-24rpx lh-24rpx text-#7D7D7D">{{ item.deliveryTime }}{{ Number(item.deliveryTime) === 1 ? t('common.day') : t('common.days') }}</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="shrink-0 w-30rpx op-0">1</view>
|
||||
|
||||
@@ -392,7 +392,7 @@ const debouncedEmit = debounce(1300, (isCollected: boolean, id: string, type: Co
|
||||
<view class="flex-center-sb mt-12rpx">
|
||||
<view class="text-28rpx text-#999">
|
||||
<view class="line-through">US${{ item?.originalPrice }}</view>
|
||||
<!-- <view>{{ t('pages-store.store.sales') }}:{{ item?.salesCount }}</view> -->
|
||||
<view>{{ t('pages-store.store.sales') }}:{{ item?.salesCount }}</view>
|
||||
</view>
|
||||
|
||||
<view class="center w-64rpx h-64rpx rounded-50% bg-white shadow-lg">
|
||||
|
||||
@@ -36,7 +36,16 @@ import {getCouponReceiveListApi, receiveAllCouponApi} from "@/pages-user/service
|
||||
const userStore = useUserStore();
|
||||
const configStore = useConfigStore();
|
||||
const message = useMessage();
|
||||
const { t } = useI18n();
|
||||
const { t, locale } = useI18n();
|
||||
|
||||
function daySuffix(value: unknown) {
|
||||
const n = Number(value)
|
||||
const isEn = String(locale.value || '').toLowerCase().startsWith('en')
|
||||
if (isEn) {
|
||||
return n === 1 ? ` ${t('pages-store.store.day')}` : ` ${t('pages-store.store.days')}`
|
||||
}
|
||||
return t('pages-store.store.days')
|
||||
}
|
||||
const tabbarHomeRef = ref<InstanceType<typeof TabbarHome>>();
|
||||
const tabbarShopRef = ref<InstanceType<typeof TabbarShop>>();
|
||||
const tabbarOrderRef = ref<InstanceType<typeof TabbarOrder>>();
|
||||
@@ -614,7 +623,7 @@ function getInviteInfo() {
|
||||
</text>
|
||||
</view>
|
||||
<view class="mt-4rpx text-24rpx text-#a0611d">
|
||||
{{ t('pages-store.store.validDays') }}: {{ item.validDays }} {{ t('pages-store.store.days') }}</view>
|
||||
{{ t('pages-store.store.validDays') }}: {{ item.validDays }}{{ daySuffix(item.validDays) }}</view>
|
||||
<view class="mt-8rpx text-24rpx text-#a0611d">
|
||||
{{ item?.merchantVo?.merchantName }}
|
||||
</view>
|
||||
|
||||
@@ -152,7 +152,7 @@ function handleSubmitCollectRecipe(item: any) {
|
||||
const collectRecipe = debounce(1000, (item: any) => {
|
||||
appCollectCollectPost({
|
||||
body: {
|
||||
targetId: item.id,
|
||||
targetId: String(item.id),
|
||||
targetType: CollectionType.RECIPE
|
||||
}
|
||||
}).then(res=> {
|
||||
|
||||
Reference in New Issue
Block a user