@ -1 +1,21 @@ |
|||
{"code":200,"msg":"操作成功","data":{"hotSearch":[{"shopId":271,"shopName":"十日后"},{"shopId":506,"shopName":"弥小爷虾滑"},{"shopId":273,"shopName":"谭木匠"},{"shopId":425,"shopName":"星巴克"},{"shopId":485,"shopName":"荔滋烫捞"}],"temperature":25,"columnList":[{"moduleType":1,"name":"好吃的","nameEn":"DELICIOUS","introduce":"好吃的","introduceEn":"大吉大利今晚吃鸡","crossFileUrl":"/iotFile/2022/06/30/48001398f98b43ea9ba4b4a27e1bbe16.png","verticalFileUrl":"/iotFile/2022/06/21/ea1dfb78855e4ce9b9d0ab1b6e3a307d.png"},{"moduleType":2,"name":"好玩的","nameEn":"FUN","introduce":"好玩的","crossFileUrl":"/iotFile/2022/06/30/f94b26b8157f410b93f8346568a1766d.png","verticalFileUrl":"/iotFile/2022/06/21/50ac7a32182c469aa684dc34cfb11f21.png"},{"moduleType":3,"name":"值得买","nameEn":"WORTH TO BUY","introduce":"值得买","crossFileUrl":"/iotFile/2022/06/30/b85955b2f68a42938c886fac16278aa9.png","verticalFileUrl":"/iotFile/2022/06/20/f7515243eb234e00ae40fe662f79d484.png"}],"status":"多云转晴"}} |
|||
{ |
|||
"code": 200, |
|||
"msg": "操作成功", |
|||
"data": { |
|||
"temperature": "11", |
|||
"columnList": [], |
|||
"hotSearch": [ |
|||
{ "shopId": 43, "shopName": "心血管超声(心超)诊室2" }, |
|||
{ "shopId": 63, "shopName": "临床心里科会议室" }, |
|||
{ "shopId": 66, "shopName": "临床心里科诊室2" }, |
|||
{ "shopId": 96, "shopName": "内镜手术室1" }, |
|||
{ "shopId": 102, "shopName": "消化内镜中心VIP诊室2" }, |
|||
{ "shopId": 155, "shopName": "妇科门诊护士台" }, |
|||
{ "shopId": 286, "shopName": "呼吸内科/胸外科诊室1" }, |
|||
{ "shopId": 342, "shopName": "儿科检验" }, |
|||
{ "shopId": 358, "shopName": "特需门诊3" }, |
|||
{ "shopId": 367, "shopName": "特需门诊19" } |
|||
], |
|||
"status": "晴" |
|||
} |
|||
} |
|||
|
|||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 302 KiB |
|
Before Width: | Height: | Size: 404 KiB |
|
Before Width: | Height: | Size: 888 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 911 B After Width: | Height: | Size: 911 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 668 B After Width: | Height: | Size: 668 B |
|
Before Width: | Height: | Size: 795 B After Width: | Height: | Size: 795 B |
|
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
@ -0,0 +1,10 @@ |
|||
import style from './style.json' |
|||
function importAll(r) { |
|||
const obj = {} |
|||
r.keys().forEach(key => { |
|||
obj[key.replace('./', '').replace('.png', '')] = r(key) |
|||
}) |
|||
return obj |
|||
} |
|||
const images = importAll(require.context('./', false, /\.(png|jpe?g|svg)$/)) |
|||
export default { ...style, images } |
|||
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 301 B |
|
Before Width: | Height: | Size: 304 B After Width: | Height: | Size: 304 B |
|
After Width: | Height: | Size: 911 B |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 303 KiB After Width: | Height: | Size: 303 KiB |
|
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 768 B |
|
Before Width: | Height: | Size: 738 B After Width: | Height: | Size: 738 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
@ -0,0 +1,128 @@ |
|||
{ |
|||
"global": { |
|||
"background": "#dee6f6", |
|||
"appBackground": "#dee6f6", |
|||
"radius": "" |
|||
}, |
|||
"weather": { |
|||
"iconColor": "#000", |
|||
"textColor": "#000" |
|||
}, |
|||
"time": { |
|||
"timeColor": "#000", |
|||
"monthColor": "#000", |
|||
"weekColor": "#516dd8" |
|||
}, |
|||
"searchBar": { |
|||
"backBorderRadius": "24px", |
|||
"background": "#fff", |
|||
"border": "none", |
|||
"borderRadius": "24px", |
|||
"placeholderColor": "rgba(0, 0, 0, 0.2)", |
|||
"stickBg": "linear-gradient(180deg, #6C7CA6 0%, #879ACA 100%)", |
|||
"color": "rgba(0, 0, 0, 0.8)" |
|||
}, |
|||
"menu": { |
|||
"bg1": "rgba(255, 255, 255, 0.4)", |
|||
"bg2": "rgba(255, 255, 255, 0.4)", |
|||
"bg3": "rgba(255, 255, 255, 0.4)", |
|||
"bg4": "rgba(255, 255, 255, 0.4)", |
|||
"bg5": "rgba(255, 255, 255, 0.4)", |
|||
"activeBg1": "#ffffff", |
|||
"activeBg2": "#ffffff", |
|||
"activeBg3": "#ffffff", |
|||
"activeBg4": "#ffffff", |
|||
"activeBg5": "#ffffff", |
|||
"indexBg1": "#ffffff", |
|||
"indexBg2": "#ffffff", |
|||
"indexBg3": "#ffffff", |
|||
"indexBg4": "#ffffff", |
|||
"indexBg5": "#ffffff", |
|||
"color": "rgba(0, 0, 0, 0.4)", |
|||
"activeColor": "rgba(0, 0, 0, 0.8)", |
|||
"indexColor": "rgba(0, 0, 0, 0.8)", |
|||
"barBg": "linear-gradient(113.71deg, #435ACD 0%, #749CF3 100%)" |
|||
}, |
|||
"index": { |
|||
"hotSearchTitleColor": "rgba(0, 0, 0, 0.8)", |
|||
"hotSearchBg": "rgba(255, 255, 255, 0.8)", |
|||
"hotSearchColor": "rgba(0, 0, 0, 0.6)", |
|||
"guideBackground": "linear-gradient(99.5deg, #f0b92b 0%, #f9d556 100%)", |
|||
"guideBorder": "none", |
|||
"guideTopBg": "linear-gradient(180deg, #435acd 0%, #749cf3 100%)", |
|||
"guideQrcodeBg": "rgba(255, 255, 255, 0.2)", |
|||
"guideColor": "#000000", |
|||
"guideMetaColor": "rgba(0, 0, 0, 0.6)", |
|||
"foodBg": "linear-gradient(180deg, #ffffff 0%, #f2f4f8 100%)", |
|||
"foodBorder": "4px solid #F68B51", |
|||
"recBg": "linear-gradient(180deg, #ffffff 0%, #f2f4f8 100%)", |
|||
"recBorder": "none" |
|||
}, |
|||
"brand": { |
|||
"background": "rgba(255, 255, 255, 0.6)", |
|||
"color": "rgba(0, 0, 0, 0.8)", |
|||
"metaColor": "rgba(0, 0, 0, 0.6)", |
|||
"floorNameColor": "rgba(0, 0, 0, 0.8)", |
|||
"floorMetaColor": "rgba(0, 0, 0, 0.6)", |
|||
"qrcodeBg": "rgba(255, 255, 255, 0.8)", |
|||
"qrcodeTextColor": "rgba(0, 0, 0, 0.8)" |
|||
}, |
|||
"food": { |
|||
"background": "linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.5) 100%)", |
|||
"metaColor": "rgba(0, 0, 0, 0.6)" |
|||
}, |
|||
"carousel": { |
|||
"titleColor": "rgba(0, 0, 0, 0.8)", |
|||
"introColor": "rgba(0, 0, 0, 0.6)" |
|||
}, |
|||
"map": { |
|||
"background": "none" |
|||
}, |
|||
"billboard": { |
|||
"background": "#dee6f6", |
|||
"arrowRadius": "100px", |
|||
"legendColor": "rgba(0, 0, 0, 0.6)", |
|||
"titleColor": "#000000", |
|||
"metaColor": "rgba(0, 0, 0, 0.6)" |
|||
}, |
|||
"guide": { |
|||
"floorBg": "linear-gradient(113.71deg, #435acd 0%, #749cf3 100%)", |
|||
"allFloorBg": "left / 150px 100% no-repeat linear-gradient(180deg, #6c7ca6 0%, #879aca 100%), #dee6f6", |
|||
"allFloorBgH": "right / 100px 100vh no-repeat var(--guide-floorBg), left / calc(100vw - 510px - 100px) 100vh no-repeat #dee6f6", |
|||
"arrowRadius": "100px", |
|||
"floorColor": "#FFFFFF", |
|||
"floorActiveColor": "rgba(0, 0, 0, 0.8)", |
|||
"floorActiveBg": "linear-gradient(180deg, rgba(255, 255, 255, 0.8) 0%, #FFFFFF 100%)", |
|||
"currentBg": "linear-gradient(99.5deg, #F0B92B 0%, #F9D556 100%)", |
|||
"currentColor": "rgba(0, 0, 0, 0.8)" |
|||
}, |
|||
"search": { |
|||
"background": "linear-gradient(180deg, #E0E3EE 0%, #D4D9E7 100%)", |
|||
"barBackground": "#fff", |
|||
"placeholderMetaColor": "rgba(81, 109, 216, 1)", |
|||
"keyboardActiveBg": "linear-gradient(180deg, #435ACD 0%, #749CF3 100%)", |
|||
"writeColor": "#516DD8", |
|||
"topBg": "rgba(255, 255, 255, 0.6)", |
|||
"facTitleColor": "rgba(0, 0, 0, 0.8)", |
|||
"facNameColor": "rgba(0, 0, 0, 0.6)", |
|||
"tabsBg": "rgba(0, 0, 0, 0.05)", |
|||
"tabActiveBg": "#FFFFFF", |
|||
"tabColor": "rgba(0, 0, 0, 0.6)", |
|||
"tabActiveColor": "rgba(0, 0, 0, 0.8)", |
|||
"resultTitleColor": "rgba(0, 0, 0, 0.8)", |
|||
"resultMetaColor": "rgba(0, 0, 0, 0.6)", |
|||
"keyBg": "#FFFFFF", |
|||
"keyColor": "rgba(0, 0, 0, 0.8)", |
|||
"hotSearchTitleColor": "rgba(0, 0, 0, 0.8)", |
|||
"hotSearchBg": "rgba(255, 255, 255, 0.8)", |
|||
"hotSearchColor": "rgba(0, 0, 0, 0.6)" |
|||
}, |
|||
"activities": { |
|||
"btnBg": "linear-gradient(113.71deg, #435ACD 0%, #749CF3 100%)", |
|||
"btnColor": "#FFFFFF", |
|||
"detailBg": "#FFFFFF", |
|||
"radius": "16px", |
|||
"titleColor": "rgba(0, 0, 0, 0.8)", |
|||
"introColor": "rgba(0, 0, 0, 0.6)" |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 597 B After Width: | Height: | Size: 597 B |
|
Before Width: | Height: | Size: 593 B After Width: | Height: | Size: 593 B |
@ -1,239 +0,0 @@ |
|||
<template> |
|||
<ScrollView class="scroll" :list="list" :scrollX="isH" :scrollbar="!isH"> |
|||
<TransitionGroup name="zoom" tag="div" class="scroll-content"> |
|||
<div :class="['content-item', item === activity ? 'd' : '']" v-for="item of list" :key="item.activityId"> |
|||
<div class="front"> |
|||
<img :src="config.sourceUrl + item.fileUrl" alt="" /> |
|||
<div class="tr">{{ item.startDate }} - {{ item.endDate }}</div> |
|||
<div class="bottom"> |
|||
<div class="left">{{ switchLanguage(item, 'activityName') }}</div> |
|||
<div class="right" @click="handleActivity(item)">查看详情</div> |
|||
</div> |
|||
</div> |
|||
<div class="back"> |
|||
<ScrollView class="backscroll" scrollbar stopPropagation> |
|||
<div> |
|||
<div class="title">{{ switchLanguage(item, 'activityName') }}</div> |
|||
<div class="desc"> |
|||
{{ switchLanguage(item, 'activityContent') }} |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
</div> |
|||
</div> |
|||
</TransitionGroup> |
|||
</ScrollView> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import 'swiper/css' |
|||
import 'swiper/css/pagination' |
|||
import 'swiper/css/effect-coverflow' |
|||
import { useMediaQuery } from '@vueuse/core' |
|||
|
|||
const isH = useMediaQuery('(min-aspect-ratio: 1/1)') |
|||
defineProps({ |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}) |
|||
const showDetail = ref(false) |
|||
const activity = ref(null) |
|||
function handleActivity(item) { |
|||
activity.value = item |
|||
showDetail.value = true |
|||
} |
|||
const store = useStore() |
|||
const { config } = storeToRefs(store) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.scroll { |
|||
position: relative; |
|||
flex: 1; |
|||
overflow: hidden; |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 48px !important; |
|||
top: 48px !important; |
|||
right: 7px !important; |
|||
background: center / 6px 250px no-repeat url(@/assets/images/scrollBar.png); |
|||
border-radius: 6px; |
|||
opacity: 1 !important; |
|||
height: 250px !important; |
|||
&::after { |
|||
position: absolute; |
|||
content: ''; |
|||
left: 0; |
|||
top: 120px; |
|||
margin: auto; |
|||
width: 48px; |
|||
height: 61px; |
|||
background: center / cover no-repeat url(@/assets/images/scrollHand.png); |
|||
} |
|||
.bscroll-indicator { |
|||
height: 95px !important; |
|||
width: 6px !important; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
background: #ffffff !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
.scroll-content { |
|||
width: 100%; |
|||
display: inline-flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
padding: 48px 0; |
|||
} |
|||
.content-item { |
|||
position: relative; |
|||
width: 944px; |
|||
height: 532px; |
|||
background: var(--activities-detailBg); |
|||
border-radius: var(--activities-radius); |
|||
overflow: hidden; |
|||
margin-bottom: 24px; |
|||
&.d { |
|||
.front { |
|||
z-index: 0; |
|||
} |
|||
.back { |
|||
z-index: 1; |
|||
} |
|||
} |
|||
.front { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
z-index: 1; |
|||
img { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
.tr { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
font-family: 'Montserrat'; |
|||
background: rgba(0, 0, 0, 0.4); |
|||
box-shadow: 0px 15px 24px rgba(173, 196, 236, 0.25); |
|||
font-weight: 700; |
|||
font-size: 16px; |
|||
line-height: 40px; |
|||
color: #ffffff; |
|||
padding: 0 27px; |
|||
height: 40px; |
|||
border-radius: 0px 0px 0px 12px; |
|||
} |
|||
.bottom { |
|||
position: absolute; |
|||
display: flex; |
|||
bottom: 0; |
|||
width: 100%; |
|||
height: 64px; |
|||
.left { |
|||
flex: 1; |
|||
height: 100%; |
|||
padding: 0 40px; |
|||
background: rgba(0, 0, 0, 0.4); |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
line-height: 64px; |
|||
color: #ffffff; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
.right { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 234px; |
|||
height: 100%; |
|||
background: var(--activities-btnBg); |
|||
box-shadow: 0px 15px 24px rgba(173, 196, 236, 0.25); |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
line-height: 21px; |
|||
text-align: center; |
|||
color: var(--activities-btnColor); |
|||
} |
|||
} |
|||
} |
|||
.back { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
display: flex; |
|||
z-index: 0; |
|||
background: var(--activities-detailBg); |
|||
.backscroll { |
|||
position: relative; |
|||
flex: 1; |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 6px !important; |
|||
top: 137px !important; |
|||
right: 31px !important; |
|||
background: rgba(0, 0, 0, 0.05) !important; |
|||
border-radius: 6px; |
|||
opacity: 1 !important; |
|||
height: 174px !important; |
|||
&::after { |
|||
display: none; |
|||
} |
|||
.bscroll-indicator { |
|||
height: 95px !important; |
|||
width: 6px !important; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
background: rgba(0, 0, 0, 0.1) !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
.title { |
|||
font-weight: 700; |
|||
font-size: 28px; |
|||
line-height: 150%; |
|||
padding: 48px 68px 40px 68px; |
|||
color: var(--activities-titleColor); |
|||
} |
|||
.desc { |
|||
padding: 0 68px; |
|||
padding-bottom: 23px; |
|||
font-weight: 400; |
|||
font-size: 16px; |
|||
line-height: 200%; |
|||
color: var(--activities-introColor); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@media (min-aspect-ratio: 1/1) { |
|||
.scroll { |
|||
.scroll-content { |
|||
width: auto; |
|||
flex-direction: row; |
|||
padding: 100px 68px; |
|||
} |
|||
.content-item + .content-item { |
|||
margin-left: 32px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,200 +0,0 @@ |
|||
<template> |
|||
<Dialog @close="back"> |
|||
<div class="content"> |
|||
<div class="carousel"> |
|||
<EffectFade :list="[activity.fileUrl, activity.fileUrl]"> |
|||
<template v-slot="{ item }"> |
|||
<div class="banner-wrapper"> |
|||
<img :src="config.sourceUrl + item" alt="" class="banner" /> |
|||
</div> |
|||
</template> |
|||
</EffectFade> |
|||
</div> |
|||
<div class="intro-content"> |
|||
<h1 class="name pos">{{ switchLanguage(activity, 'activityName') }}</h1> |
|||
<ScrollView class="content-scroll" scrollbar> |
|||
<p class="intro pos">{{ switchLanguage(activity, 'activityContent') }}</p> |
|||
</ScrollView> |
|||
<div class="time-wrapper pos"> |
|||
<p class="common first">{{ $t('ActivityTime') }}:{{ activity.startDate }} {{ $t('zhi') + activity.endDate }}</p> |
|||
<p class="common">{{ $t('activityAddress') }}:{{ switchLanguage(activity, 'activityAddress') }}</p> |
|||
</div> |
|||
<Go class="detail-go" v-if="activity.shopId || activity.point" @click="handleActivity" /> |
|||
</div> |
|||
<Button class="btn" @click="back" /> |
|||
<ThumbQRCode class="thumbs" :title="$t('yuyue')" /> |
|||
</div> |
|||
</Dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { useRouter } from 'vue-router' |
|||
import { useStore } from '@/store/root' |
|||
import Dialog from '@/layouts/Dialog.vue' |
|||
import Button from '@/base/Button/Button.vue' |
|||
import EffectFade from '@/components/EffectFade/EffectFade.vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import Go from '@/base/Go/Go.vue' |
|||
import ThumbQRCode from '@/base/ThumbQRCode/ThumbQRCode.vue' |
|||
import Shop from '@/utils/Class/Shop' |
|||
|
|||
const MALL_TYPE = 1 //商场活动 |
|||
const BRAND_TYPE = 2 //品牌活动 |
|||
const MEMBER_TYPE = 3 //会员活动 |
|||
|
|||
const props = defineProps({ |
|||
activity: Object, |
|||
config: Object |
|||
}) |
|||
|
|||
const router = useRouter() |
|||
const store = useStore() |
|||
|
|||
function handleActivity() { |
|||
let shop |
|||
if (props.activity.activityType === BRAND_TYPE) { |
|||
shop = store.shopList.find(item => item.shopId === props.activity.shopId) |
|||
} |
|||
if (props.activity.activityType === MALL_TYPE || props.activity.activityType === MEMBER_TYPE) { |
|||
const { floorOrder, floor, activityName, fileUrl, point } = props.activity |
|||
shop = new Shop(activityName, floorOrder, floor, fileUrl, point) |
|||
} |
|||
|
|||
if (!shop) { |
|||
return |
|||
} |
|||
store.SET_SHOP(shop) |
|||
router.push('/nav') |
|||
} |
|||
|
|||
const emits = defineEmits(['close']) |
|||
function back() { |
|||
emits('close') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.pos { |
|||
position: relative; |
|||
z-index: 5; |
|||
} |
|||
.content { |
|||
position: relative; |
|||
width: 700px; |
|||
margin: 0 auto; |
|||
margin-top: 350px; |
|||
z-index: 2; |
|||
.thumbs { |
|||
position: absolute; |
|||
top: 120px; |
|||
right: -156px; |
|||
} |
|||
&::before { |
|||
content: ''; |
|||
position: absolute; |
|||
top: 373px; |
|||
left: 0; |
|||
z-index: 2; |
|||
width: 700px; |
|||
height: 420px; |
|||
background: #ffffff; |
|||
border-radius: 12px; |
|||
} |
|||
.intro-content { |
|||
position: relative; |
|||
height: 420px; |
|||
.name { |
|||
padding: 28px 56px 32px 56px; |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
} |
|||
.common { |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
margin-left: 56px; |
|||
&.first { |
|||
padding-bottom: 8px; |
|||
} |
|||
} |
|||
.content-scroll { |
|||
position: relative; |
|||
height: 140px; |
|||
overflow: hidden; |
|||
margin: 0 34px 64px 56px; |
|||
padding-right: 16px; |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.02) !important; |
|||
border-radius: 6px !important; |
|||
opacity: 1 !important; |
|||
.bscroll-indicator { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.1) !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
.intro { |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
line-height: 200%; |
|||
text-align: justify; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
margin-bottom: 64px; |
|||
} |
|||
} |
|||
|
|||
.detail-go { |
|||
bottom: -70px; |
|||
} |
|||
|
|||
.carousel { |
|||
width: 700px; |
|||
height: 393px; |
|||
|
|||
:deep(.swiper) { |
|||
overflow: visible !important; |
|||
z-index: auto; |
|||
} |
|||
:deep(.swiper-pagination) { |
|||
right: 32px; |
|||
left: auto; |
|||
bottom: 5px; |
|||
width: auto; |
|||
} |
|||
:deep(.swiper-pagination-bullet) { |
|||
width: 16px !important; |
|||
height: 3px !important; |
|||
background: rgba(0, 0, 0, 0.1); |
|||
border-radius: 3px !important; |
|||
opacity: inherit !important; |
|||
&.swiper-pagination-bullet-active { |
|||
background: #f1b33e; |
|||
border-radius: 3px !important; |
|||
} |
|||
} |
|||
} |
|||
.banner-wrapper { |
|||
width: 700px; |
|||
height: 393px; |
|||
border-radius: 12px; |
|||
.banner { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
border-radius: 12px; |
|||
} |
|||
} |
|||
|
|||
.btn { |
|||
position: absolute; |
|||
top: 0; |
|||
right: -120px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,455 +0,0 @@ |
|||
<template> |
|||
<Dialog @close="back"> |
|||
<div class="content" :class="{ active: shop.activityList.length || shop.thirdKouCode }"> |
|||
<div class="left"> |
|||
<div class="carousel"> |
|||
<EffectFade :list="shop.doorMaterialList"> |
|||
<template v-slot="{ item }"> |
|||
<div class="banner-wrapper"> |
|||
<img :src="config.sourceUrl + item" alt="" class="banner" /> |
|||
</div> |
|||
</template> |
|||
</EffectFade> |
|||
<div class="like-wrapper" @click="setLike"> |
|||
<img :src="showLikeHeart ? require('@/assets/images/detail/like_active.svg') : require('@/assets/images/detail/like.svg')" class="like-icon" alt="" /> |
|||
<span class="like-num">{{ likeNumber }}</span> |
|||
</div> |
|||
</div> |
|||
<div class="info-content"> |
|||
<div class="shop-info"> |
|||
<div class="logo-wrapper"> |
|||
<img :src="config.sourceUrl + shop.logoUrl" alt="" class="logo" /> |
|||
</div> |
|||
<div class="group" v-if="shop.industryUrl?.length"> |
|||
<div class="icon-box"> |
|||
<img :src="config.sourceUrl + shop.industryUrl" alt="" /> |
|||
</div> |
|||
<div class="group-right"> |
|||
<span class="tip-name">业态</span> |
|||
<span class="name">{{ switchLanguage(shop, 'industryFatherName') }}</span> |
|||
</div> |
|||
</div> |
|||
<div class="group" v-if="shop.houseNumber?.length"> |
|||
<div class="icon-box"> |
|||
<img src="../../assets/images/nav/detail-add.svg" alt="" /> |
|||
</div> |
|||
<div class="group-right"> |
|||
<span class="tip-name">地址</span> |
|||
<span class="name">{{ shop.houseNumber }}</span> |
|||
</div> |
|||
</div> |
|||
<div class="group" v-if="shop.contact?.length"> |
|||
<div class="icon-box"> |
|||
<img src="../../assets/images/nav/phone.svg" alt="" /> |
|||
</div> |
|||
<div class="group-right"> |
|||
<span class="tip-name">电话</span> |
|||
<span class="name">{{ shop.contact }}</span> |
|||
</div> |
|||
</div> |
|||
<div class="group" v-if="shop.businessHours?.length"> |
|||
<div class="icon-box"> |
|||
<img src="../../assets/images/nav/time.svg" alt="" /> |
|||
</div> |
|||
<div class="group-right"> |
|||
<span class="tip-name">营业时间</span> |
|||
<span class="name">{{ shop.businessHours }}</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="shop-intro"> |
|||
<p class="shop-name">{{ switchLanguage(shop, 'shopName') }}</p> |
|||
<ScrollView class="intro-scroll" scrollbar> |
|||
<p class="intro">{{ switchLanguage(shop, 'intro') }}</p> |
|||
</ScrollView> |
|||
</div> |
|||
<Go class="detail-go" @click="go" /> |
|||
</div> |
|||
<div class="lineup-wrapper"> |
|||
<div class="lineup-left"> |
|||
<h1 class="title-tip">{{ $t('qiandengdai') }}</h1> |
|||
<div class="flex align-center"> |
|||
<ScrollView class="lineup-scroll" scroll-x> |
|||
<div class="lineup-content"> |
|||
<div class="flex"> |
|||
<div class="lineup-item" v-for="item of 10" :key="item"> |
|||
<span class="number">12</span> |
|||
<span class="line-up-text">小桌</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
<div class="line"></div> |
|||
<p class="abs-money">147<i>¥/人</i></p> |
|||
</div> |
|||
</div> |
|||
<div class="lineup-btn" @click="handleLineupBtn">{{ $t('join') }}</div> |
|||
</div> |
|||
</div> |
|||
<div class="right" v-if="shop.activityList.length || shop.thirdKouCode"> |
|||
<Tabs /> |
|||
</div> |
|||
<Button class="btn" @click="back" /> |
|||
<ThumbQRCode class="thumbs" :title="$t('yuyue')" /> |
|||
<Transition enter-active-class="animate__animated animate__zoomIn" leave-active-class="animate__animated animate__zoomOut"> |
|||
<QRCode v-if="showLineupQr" @close="showLineupQr = false" /> |
|||
</Transition> |
|||
</div> |
|||
</Dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, defineAsyncComponent } from 'vue' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useRouter } from 'vue-router' |
|||
import { useStore } from '@/store/root' |
|||
import { getBrandLikesNumber, setBrandLikesNumber } from '@/http/api' |
|||
import Dialog from '@/layouts/Dialog.vue' |
|||
import Button from '@/base/Button/Button.vue' |
|||
import EffectFade from '@/components/EffectFade/EffectFade.vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import Go from '@/base/Go/Go.vue' |
|||
import ThumbQRCode from '@/base/ThumbQRCode/ThumbQRCode.vue' |
|||
import Tabs from './children/tabs.vue' |
|||
import { useStatistics } from '@/composables/useStatistics' |
|||
const QRCode = defineAsyncComponent(() => import('@/components/QRCode/QRCode.vue')) |
|||
|
|||
const router = useRouter() |
|||
const store = useStore() |
|||
const { shop, config, showDetail, showSearch, showVoice } = storeToRefs(store) |
|||
|
|||
useStatistics('shop') |
|||
|
|||
const showLikeHeart = ref(false) |
|||
const likeNumber = ref(0) |
|||
getBrandLikesNumber(shop.value.shopId).then(({ data }) => { |
|||
likeNumber.value = data ?? 0 |
|||
}) |
|||
|
|||
function setLike() { |
|||
setBrandLikesNumber(shop.value.shopId).then(() => { |
|||
showLikeHeart.value = true |
|||
likeNumber.value++ |
|||
}) |
|||
} |
|||
|
|||
const showLineupQr = ref(false) |
|||
function handleLineupBtn() { |
|||
showLineupQr.value = true |
|||
} |
|||
|
|||
async function go() { |
|||
await router.push('/nav') |
|||
showDetail.value && store.SET_SHOW_DETAIL(false) |
|||
showSearch.value && store.SET_SHOW_SEARCH(false) |
|||
showVoice.value && store.SET_SHOW_VOICE(false) |
|||
} |
|||
|
|||
function back() { |
|||
store.SET_SHOW_DETAIL(false) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
position: absolute; |
|||
top: 350px; |
|||
left: 50%; |
|||
transform: translate3d(-50%, 0, 0); |
|||
z-index: 2; |
|||
&.active { |
|||
top: 100px; |
|||
} |
|||
&::before { |
|||
content: ''; |
|||
position: absolute; |
|||
top: 373px; |
|||
left: 0; |
|||
z-index: 2; |
|||
width: 700px; |
|||
height: 420px; |
|||
background: linear-gradient(180deg, #ffbd35 0%, #ffd260 100%); |
|||
border-radius: 12px; |
|||
} |
|||
.thumbs { |
|||
position: absolute; |
|||
top: 120px; |
|||
right: -156px; |
|||
} |
|||
|
|||
.detail-go { |
|||
bottom: -90px; |
|||
} |
|||
.left { |
|||
width: 700px; |
|||
.carousel { |
|||
position: relative; |
|||
width: 700px; |
|||
height: 393px; |
|||
background-color: #fff; |
|||
border-radius: 12px; |
|||
overflow: hidden; |
|||
.like-wrapper { |
|||
position: absolute; |
|||
left: 571px; |
|||
top: 32px; |
|||
height: 52px; |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 0 14px; |
|||
background: rgba(0, 0, 0, 0.2); |
|||
border-radius: 54px; |
|||
|
|||
z-index: 1; |
|||
.like-num { |
|||
padding-left: 8px; |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
font-family: 'font_bold'; |
|||
color: #ffffff; |
|||
} |
|||
} |
|||
:deep(.swiper) { |
|||
overflow: visible !important; |
|||
z-index: auto; |
|||
} |
|||
:deep(.swiper-pagination) { |
|||
right: 32px; |
|||
left: auto; |
|||
bottom: 5px; |
|||
width: auto; |
|||
} |
|||
:deep(.swiper-pagination-bullet) { |
|||
width: 16px !important; |
|||
height: 3px !important; |
|||
background: rgba(0, 0, 0, 0.1); |
|||
border-radius: 3px !important; |
|||
opacity: inherit !important; |
|||
&.swiper-pagination-bullet-active { |
|||
background: rgba(255, 255, 255, 1); |
|||
border-radius: 3px !important; |
|||
} |
|||
} |
|||
} |
|||
.banner-wrapper { |
|||
width: 700px; |
|||
height: 393px; |
|||
border-radius: 12px; |
|||
.banner { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
border-radius: 12px; |
|||
} |
|||
} |
|||
.info-content { |
|||
position: relative; |
|||
display: flex; |
|||
align-items: stretch; |
|||
width: 700px; |
|||
height: 420px; |
|||
margin-top: -20px; |
|||
} |
|||
.shop-info { |
|||
position: relative; |
|||
z-index: 3; |
|||
width: 225px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 0px 0px 0px 12px; |
|||
padding-left: 32px; |
|||
.logo-wrapper { |
|||
width: 160px; |
|||
height: 160px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 20px 30px rgba(221, 152, 55, 0.5); |
|||
border-radius: 16px; |
|||
padding: 20px; |
|||
margin-bottom: 32px; |
|||
margin-top: -51px; |
|||
.logo { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: contain; |
|||
} |
|||
} |
|||
.group { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 18px; |
|||
.icon-box { |
|||
width: 36px; |
|||
height: 36px; |
|||
background: rgba(0, 0, 0, 0.05); |
|||
border-radius: 6px; |
|||
margin-right: 12px; |
|||
padding: 9px; |
|||
img { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: contain; |
|||
} |
|||
} |
|||
.group-right { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
.tip-name { |
|||
font-size: 12px; |
|||
transform: scale(0.83); |
|||
color: rgba(0, 0, 0, 0.4); |
|||
padding-bottom: 6px; |
|||
} |
|||
.name { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 12px; |
|||
line-height: 14px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.shop-intro { |
|||
position: relative; |
|||
z-index: 3; |
|||
flex: 1; |
|||
padding-top: 58px; |
|||
padding-left: 40px; |
|||
.shop-name { |
|||
font-weight: 700; |
|||
font-size: 32px; |
|||
line-height: 38px; |
|||
text-align: justify; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
font-family: 'font_bold'; |
|||
padding-bottom: 40px; |
|||
} |
|||
.intro-scroll { |
|||
position: relative; |
|||
overflow: hidden; |
|||
height: 207px; |
|||
margin-right: 16px; |
|||
padding-right: 18px; |
|||
.intro { |
|||
font-size: 14px; |
|||
line-height: 200%; |
|||
text-align: justify; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
flex: 1; |
|||
overflow: hidden; |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.02) !important; |
|||
border-radius: 6px !important; |
|||
opacity: 1 !important; |
|||
height: 200px !important; |
|||
.bscroll-indicator { |
|||
height: 95px !important; |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.1) !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.flex { |
|||
display: flex; |
|||
} |
|||
.align-center { |
|||
align-items: flex-end; |
|||
} |
|||
.lineup-wrapper { |
|||
display: flex; |
|||
align-items: flex-end; |
|||
margin-top: -20px; |
|||
padding: 79px 16px 16px 32px; |
|||
background: #ffffff; |
|||
border-radius: 12px; |
|||
.lineup-left { |
|||
flex: 1; |
|||
.title-tip { |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
font-family: 'font_bold'; |
|||
text-align: justify; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
padding-bottom: 15px; |
|||
} |
|||
} |
|||
.lineup-scroll { |
|||
display: flex; |
|||
width: 310px; |
|||
overflow: hidden; |
|||
margin-right: 40px; |
|||
.lineup-content { |
|||
display: inline-block; |
|||
white-space: nowrap; |
|||
|
|||
.lineup-item { |
|||
display: flex; |
|||
align-items: flex-end; |
|||
margin-right: 24px; |
|||
} |
|||
.number { |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
line-height: 22px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
font-family: 'font_bold'; |
|||
padding-right: 4px; |
|||
} |
|||
.line-up-text { |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
line-height: 16px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.2); |
|||
} |
|||
} |
|||
} |
|||
.line { |
|||
width: 1px; |
|||
height: 20px; |
|||
background: rgba(0, 0, 0, 0.1); |
|||
margin-right: 40px; |
|||
} |
|||
.abs-money { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 24px; |
|||
text-align: right; |
|||
color: #f1b33e; |
|||
i { |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.2); |
|||
} |
|||
} |
|||
.lineup-btn { |
|||
background: linear-gradient(90deg, #f6a62c 0%, #ffbc3f 100%); |
|||
box-shadow: 0px 8px 20px rgba(221, 152, 55, 0.2); |
|||
border-radius: 24px; |
|||
width: 128px; |
|||
height: 37px; |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 14px; |
|||
line-height: 37px; |
|||
text-align: center; |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
.right { |
|||
width: 700px; |
|||
flex: 1; |
|||
margin-top: 40px; |
|||
} |
|||
.btn { |
|||
position: absolute; |
|||
top: 0; |
|||
right: -120px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,266 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<ScrollView class="activity-scroll" :class="{ active: tab.length === 1 }" scrollbar> |
|||
<div class="scroll-content"> |
|||
<h1 class="title">{{ $t('brandActivity') }}</h1> |
|||
<div class="activity-item" v-for="item of list" :key="item.activityId"> |
|||
<div class="img-wrapper"> |
|||
<img :src="config.sourceUrl + item.fileUrl" alt="" class="img" /> |
|||
</div> |
|||
<div class="flex-right"> |
|||
<div class="activity-title"> |
|||
<p class="name">{{ switchLanguage(item, 'activityName') }}</p> |
|||
<p class="look" @click="handleActivity(item)">{{ $t('lookActivity') }}</p> |
|||
</div> |
|||
<p class="activity-intro">{{ switchLanguage(item, 'activityContent') }}</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<h1 class="title">{{ $t('coupon') }}</h1> |
|||
<div class="coupon-item"> |
|||
<div class="coupon-left"> |
|||
<p class="money">¥<i>30</i></p> |
|||
<div class="coupon-info"> |
|||
<p class="coupon-name">30元代金券,满129可用</p> |
|||
<p class="coupon-time">使用时间:2021-01-01至2021-12-30</p> |
|||
</div> |
|||
</div> |
|||
<div class="coupon-btn">{{ $t('get') }}</div> |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
<div class="activity-detail" v-if="showActivityDetail"> |
|||
<h1 class="activity-title">{{ switchLanguage(activity, 'activityName') }}</h1> |
|||
<ScrollView class="scroll" scrollbar> |
|||
<p class="scroll-content">{{ switchLanguage(activity, 'activityContent') }}</p> |
|||
</ScrollView> |
|||
<div class="common first">{{ $t('ActivityTime') }}:{{ activity.startDate }} {{ $t('zhi') + activity.endDate }}</div> |
|||
<div class="common">{{ $t('activityAddress') }}:{{ switchLanguage(activity, 'activityAddress') }}</div> |
|||
<div class="close-activity" @click="showActivityDetail = false"> |
|||
<img src="../../../assets/images/detail/yellow_close.png" alt="" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed, ref } from 'vue' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
|
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
|
|||
defineProps({ |
|||
tab: Array |
|||
}) |
|||
|
|||
const store = useStore() |
|||
const { shop, config } = storeToRefs(store) |
|||
const list = computed(() => shop.value.activityList) |
|||
|
|||
const showActivityDetail = ref(false) |
|||
const activity = ref({}) |
|||
function handleActivity(item) { |
|||
activity.value = item |
|||
showActivityDetail.value = true |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.activity-scroll { |
|||
position: relative; |
|||
overflow: hidden; |
|||
height: 690px; |
|||
&.active { |
|||
height: 860px; |
|||
} |
|||
.title { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 24px; |
|||
margin-bottom: 24px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
.activity-item { |
|||
display: flex; |
|||
align-items: center; |
|||
width: 700px; |
|||
height: 106px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 12px; |
|||
margin-bottom: 16px; |
|||
padding-right: 16px; |
|||
padding-left: 6px; |
|||
&:last-of-type { |
|||
margin-bottom: 40px; |
|||
} |
|||
.img-wrapper { |
|||
width: 160px; |
|||
height: 90px; |
|||
border-radius: 8px; |
|||
overflow: hidden; |
|||
margin-right: 32px; |
|||
.img { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
.flex-right { |
|||
flex: 1; |
|||
.activity-title { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding-bottom: 8px; |
|||
.name { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
.look { |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
background: url('../../../assets/images/detail/arrow.svg') no-repeat right center; |
|||
background-size: 18px 18px; |
|||
padding-right: 26px; |
|||
} |
|||
} |
|||
.activity-intro { |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
line-height: 150%; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
@include more-wrap; |
|||
} |
|||
} |
|||
} |
|||
.coupon-item { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding: 0 24px 0 32px; |
|||
width: 700px; |
|||
height: 106px; |
|||
margin-bottom: 16px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 12px; |
|||
.coupon-left { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
.coupon-name { |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
line-height: 21px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-bottom: 6px; |
|||
} |
|||
.coupon-time { |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
.money { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 24px; |
|||
color: #f1b33e; |
|||
margin-right: 27px; |
|||
i { |
|||
font-size: 48px; |
|||
padding-left: 4px; |
|||
} |
|||
} |
|||
.coupon-btn { |
|||
width: 140px; |
|||
height: 48px; |
|||
text-align: center; |
|||
line-height: 48px; |
|||
background: linear-gradient(90deg, #f6a62c 0%, #ffbc3f 100%); |
|||
box-shadow: 0px 20px 30px rgba(221, 152, 55, 0.2); |
|||
border-radius: 160px; |
|||
color: #fff; |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
} |
|||
} |
|||
} |
|||
.activity-detail { |
|||
position: absolute; |
|||
width: 832px; |
|||
min-height: 396px; |
|||
top: 50%; |
|||
left: 50%; |
|||
transform: translate3d(-50%, -50%, 0); |
|||
background: #ffffff; |
|||
box-shadow: 0px 40px 60px rgba(0, 0, 0, 0.08); |
|||
border-radius: 12px; |
|||
z-index: 10; |
|||
padding-top: 48px; |
|||
padding-left: 56px; |
|||
.activity-title { |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
line-height: 28px; |
|||
text-align: justify; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
margin-bottom: 32px; |
|||
} |
|||
.scroll { |
|||
position: relative; |
|||
height: 155px; |
|||
overflow: hidden; |
|||
margin-right: 34px; |
|||
padding-right: 16px; |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.02) !important; |
|||
border-radius: 6px !important; |
|||
opacity: 1 !important; |
|||
.bscroll-indicator { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.1) !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
.scroll-content { |
|||
font-size: 14px; |
|||
line-height: 200%; |
|||
text-align: justify; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
} |
|||
.common { |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
line-height: 16px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
&.first { |
|||
margin-bottom: 12px; |
|||
padding-top: 49px; |
|||
} |
|||
} |
|||
.close-activity { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 12px; |
|||
right: 12px; |
|||
width: 56px; |
|||
height: 56px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
img { |
|||
width: 56px; |
|||
height: 56px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,123 +0,0 @@ |
|||
<template> |
|||
<div class="wrapper"> |
|||
<h1 class="title">{{ $t('comment') }}</h1> |
|||
<div class="score-wrapper"> |
|||
<div class="score-num">{{ score }}</div> |
|||
<div class="star"> |
|||
<div class="star-num"> |
|||
<img |
|||
:src="item === 0 ? require('@/assets/images/detail/star_active.svg') : require('@/assets/images/detail/star.svg')" |
|||
v-for="item of starList()" |
|||
:key="item" |
|||
alt="" |
|||
class="star-icon" |
|||
/> |
|||
</div> |
|||
<div class="total-comment">{{ totalComment }} {{ $t('totalComment') }}</div> |
|||
</div> |
|||
</div> |
|||
<ScrollView class="scroll" :list="commentList" scrollbar> |
|||
<ul class="comments"> |
|||
<li class="comments-item" v-for="item of commentList" :key="item.tag_count"> |
|||
<span class="txt"> |
|||
{{ item.tag_content }} |
|||
<span>{{ item.tag_count }}</span> |
|||
</span> |
|||
</li> |
|||
</ul> |
|||
</ScrollView> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed } from 'vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
|
|||
const comment = ref({ |
|||
comment_info: { |
|||
avg_score: '2.912871287128713', |
|||
comment_tag_list: { |
|||
comment_tag: [ |
|||
{ |
|||
emotion: 1, |
|||
tag_content: '服务周到', |
|||
tag_count: 6 |
|||
} |
|||
] |
|||
}, |
|||
image_count: 34, |
|||
total_comments: 505 |
|||
}, |
|||
has_more: false, |
|||
page_size: 20 |
|||
}) |
|||
|
|||
const commentList = computed(() => comment.value?.comment_info?.comment_tag_list?.comment_tag ?? []) |
|||
const score = computed(() => Math.floor(comment.value?.comment_info?.avg_score) ?? 0) |
|||
const totalComment = computed(() => comment.value?.comment_info?.total_comments ?? 0) |
|||
|
|||
function starList() { |
|||
return new Array(5).fill(0, 0, score.value).fill(1, score.value) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.title { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
margin-bottom: 24px; |
|||
} |
|||
.scroll { |
|||
position: relative; |
|||
height: 618px; |
|||
overflow: hidden; |
|||
.comments { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
.comments-item { |
|||
height: 43px; |
|||
background: #ffffff; |
|||
border-radius: 8px; |
|||
flex-shrink: 0; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 40px; |
|||
padding: 0 24px; |
|||
margin: 0 16px 16px 0; |
|||
span { |
|||
font-size: 16px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
font-weight: 700; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.star-num { |
|||
margin-bottom: 4px; |
|||
} |
|||
.star-icon { |
|||
width: 20px; |
|||
height: 20px; |
|||
margin-right: 8px; |
|||
} |
|||
.score-wrapper { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 25px; |
|||
.score-num { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 48px; |
|||
color: #f1b33e; |
|||
margin-right: 19px; |
|||
} |
|||
.total-comment { |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,155 +0,0 @@ |
|||
<template> |
|||
<div class="wrapper"> |
|||
<h1 class="title">{{ $t('goods') }}</h1> |
|||
<ScrollView class="scroll" :list="goodsList"> |
|||
<ul class="goods"> |
|||
<li class="goods-item" v-for="item of goodsList" :key="item.item_name"> |
|||
<div class="cover"> |
|||
<img :src="item.item_cover" alt="" class="goods-img" /> |
|||
</div> |
|||
<div class="goods-right"> |
|||
<h1 class="goods-title">{{ item.item_name }}</h1> |
|||
<h1 class="goods-sub">{{ item.sub_title }}</h1> |
|||
<h1 class="price"> |
|||
<span class="sell"> |
|||
¥<i>{{ item.sell_price }}</i> |
|||
</span> |
|||
<span class="original"> |
|||
¥<i>{{ item.original_price }}</i> |
|||
</span> |
|||
</h1> |
|||
</div> |
|||
<div class="button" @click="handleGoods(item)">{{ $t('buy') }}</div> |
|||
</li> |
|||
</ul> |
|||
</ScrollView> |
|||
<QRCode v-if="showCodeRef" :url="goodsRef.item_detail_url" :title="$t('scanBuy')" @click="show(false)" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, defineAsyncComponent } from 'vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
|
|||
const QRCode = defineAsyncComponent(() => import('@/base/QRCode/QRCode.vue')) |
|||
|
|||
const goodsList = ref([ |
|||
{ |
|||
item_store: { store_name: '大紧特紧测试门店' }, |
|||
item_detail_url: |
|||
'alipays://platformapi/startapp?appId=77700272&startMultApp=YES&query=itemId%3D613552052869%26channel%3DALL%26cityId%3D330100%26storeId%3D230021002%26sourceFrom%3DITEM_DETAIL_BASE_INFO&url=%2Findex.html%23pages%2Findex%2Findex&chInfo=ch_tribeopen__chsub_yinli', |
|||
item_cover: 'https://wx1.sinaimg.cn/orj360/004j2Ftyly1gt4lt4kltaj60u01c6n8r02.jpg', |
|||
item_name: '这是商品的名称', |
|||
sub_title: '正文介绍正文介绍正文介绍正文介绍正文介绍正文介绍正文介绍正文介绍正文介绍正文介绍正文介绍正文介绍', |
|||
sell_price: '333', |
|||
original_price: '11111' |
|||
} |
|||
]) |
|||
|
|||
const showCodeRef = ref(false) |
|||
const goodsRef = ref({}) |
|||
function handleGoods(item) { |
|||
goodsRef.value = item |
|||
showCodeRef.value = true |
|||
} |
|||
function show(flag) { |
|||
showCodeRef.value = flag |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.title { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
margin-bottom: 24px; |
|||
} |
|||
.scroll { |
|||
position: relative; |
|||
overflow: hidden; |
|||
height: 690px; |
|||
} |
|||
.goods { |
|||
padding-bottom: 8px; |
|||
} |
|||
.goods-item { |
|||
width: 700px; |
|||
height: 156px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 12px; |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 16px; |
|||
padding: 0 24px 0 8px; |
|||
.cover { |
|||
flex-shrink: 0; |
|||
width: 136px; |
|||
height: 136px; |
|||
margin-right: 24px; |
|||
margin-right: 32px; |
|||
border-radius: 8px; |
|||
overflow: hidden; |
|||
|
|||
.goods-img { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
|
|||
.goods-title { |
|||
font-family: 'font_bold'; |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-bottom: 8px; |
|||
} |
|||
.goods-sub { |
|||
font-size: 14px; |
|||
line-height: 150%; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
margin-bottom: 10px; |
|||
@include more-wrap; |
|||
} |
|||
.price { |
|||
display: flex; |
|||
align-items: baseline; |
|||
.sell { |
|||
display: flex; |
|||
align-items: baseline; |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 16px; |
|||
color: #f1b33e; |
|||
padding-right: 10px; |
|||
i { |
|||
font-size: 32px; |
|||
} |
|||
} |
|||
.original { |
|||
font-weight: 400; |
|||
font-size: 18px; |
|||
text-decoration: line-through; |
|||
color: rgba(0, 0, 0, 0.2); |
|||
} |
|||
} |
|||
.button { |
|||
position: absolute; |
|||
bottom: 16px; |
|||
right: 24px; |
|||
width: 140px; |
|||
height: 48px; |
|||
text-align: center; |
|||
line-height: 48px; |
|||
background: linear-gradient(90deg, #f6a62c 0%, #ffbc3f 100%); |
|||
box-shadow: 0px 20px 30px rgba(221, 152, 55, 0.2); |
|||
border-radius: 150px; |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
font-family: 'font_bold'; |
|||
color: #ffffff; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,119 +0,0 @@ |
|||
<template> |
|||
<div class="wrapper"> |
|||
<h1 class="title">{{ $t('serviceInfo') }}</h1> |
|||
<h2 class="time">{{ businessTime }}</h2> |
|||
|
|||
<h1 class="title">营业信息</h1> |
|||
|
|||
<div class="info-group"> |
|||
<div class="info-list" v-for="(item, index) of serviceList" :key="index"> |
|||
<p class="info">{{ item }}</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed } from 'vue' |
|||
|
|||
const info = ref({ |
|||
service_info: { |
|||
service_desc: '有停车位 有WIFI 有包厢 无烟区', |
|||
service_tag_list: ['有停车位', 'sadf', '有停车位', 'sadf', '有停车位', 'sadf', 'sadf', 'sadddddf', 'sadf阿斯蒂芬', 'sa顶顶顶df', 'sadf'] |
|||
}, |
|||
store_album: { |
|||
picture_list: { |
|||
picture: [ |
|||
{ |
|||
picture_name: '门店内景', |
|||
picture_url: 'https://img.alicdn.com/i4/2200788639881/O1CN01T3Urj72MrYBKTXquz_!!2200788639881-0-koubei.jpg', |
|||
sequence: -1 |
|||
}, |
|||
{ |
|||
picture_name: '门店内景', |
|||
picture_url: 'https://img.alicdn.com/i1/2200788639881/O1CN01xyp6q72MrYBGxRpS6_!!2200788639881-0-koubei.jpg', |
|||
sequence: -1 |
|||
}, |
|||
{ |
|||
picture_name: '门店内景', |
|||
picture_url: 'https://img.alicdn.com/i4/2200788639881/O1CN01T3Urj72MrYBKTXquz_!!2200788639881-0-koubei.jpg', |
|||
sequence: -1 |
|||
}, |
|||
{ |
|||
picture_name: '门店内景', |
|||
picture_url: 'https://img.alicdn.com/i2/2200788639881/O1CN01WKCpfo2MrYBLru6At_!!2200788639881-0-koubei.jpg', |
|||
sequence: -1 |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
store_dto: { |
|||
billboard: '江宁区米粉米线热销榜第2名', |
|||
brand_name: '阿香米线', |
|||
business_time: '周一-周日 10:00-21:30', |
|||
category_name: '美食,快餐小吃,米粉/米线', |
|||
comment_score: '3.4444444444444446', |
|||
comment_total_count: '9', |
|||
contact_info: '18117095769', |
|||
district_info: { |
|||
address: '浦珠北路1号万象汇商业广场B1层Y103号商铺', |
|||
city_code: '320100', |
|||
city_name: '南京市', |
|||
district_code: '320111', |
|||
district_name: '浦口区', |
|||
latitude: '32.125232', |
|||
longitude: '118.730226', |
|||
province_code: '320000', |
|||
province_name: '江苏省' |
|||
}, |
|||
mall_id: '20210207880000000000000009900410', |
|||
score: '2.9', |
|||
store_detail_url: |
|||
'alipays://platformapi/startapp?appId=2021002144672445&supportTourist=true&startMultApp=YES&query=chInfo%3Dch_tribeopen__chsub_1000mu%26sourceFrom%3DTRIBE_OPEN_SHOP', |
|||
store_id: '573127418', |
|||
store_logo: 'https://img.alicdn.com/i4/2200788639881/O1CN01T3Urj72MrYBKTXquz_!!2200788639881-0-koubei.jpg', |
|||
store_name: '阿香米线(南京桥北万象汇餐厅)' |
|||
} |
|||
}) |
|||
|
|||
const businessTime = computed(() => info.value?.store_dto?.business_time ?? '') |
|||
const serviceList = computed(() => info.value?.service_info?.service_tag_list ?? []) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.title { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
margin-bottom: 24px; |
|||
} |
|||
.time { |
|||
font-size: 14px; |
|||
line-height: 150%; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
margin-bottom: 26px; |
|||
} |
|||
|
|||
.info-group { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
.info-list { |
|||
padding: 0 24px; |
|||
text-align: center; |
|||
line-height: 43px; |
|||
height: 43px; |
|||
background: #ffffff; |
|||
border-radius: 8px; |
|||
margin-right: 16px; |
|||
margin-bottom: 16px; |
|||
|
|||
.info { |
|||
font-weight: 700; |
|||
font-size: 16px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,75 +0,0 @@ |
|||
<template> |
|||
<div class="wrapper"> |
|||
<h1 class="title">{{ $t('recommend') }}</h1> |
|||
<ScrollView class="scroll" :list="recommendList"> |
|||
<ul class="recommends"> |
|||
<li class="recommend-item" v-for="item of recommendList" :key="item.good_detail_name"> |
|||
<div class="pic-wrapper"> |
|||
<img class="pic" :src="item?.picture?.picture_url" alt="" /> |
|||
</div> |
|||
<span class="txt">{{ item.good_detail_name }}</span> |
|||
</li> |
|||
</ul> |
|||
</ScrollView> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import { ref } from 'vue' |
|||
|
|||
const recommendList = ref([ |
|||
{ |
|||
good_detail_name: '测试推荐菜', |
|||
picture: { |
|||
picture_url: 'https://img0.baidu.com/it/u=2284782435,2170248613&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1657299600&t=624c0227aa15519b1309ace7f41184ec' |
|||
} |
|||
} |
|||
]) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.title { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
margin-bottom: 24px; |
|||
} |
|||
.scroll { |
|||
position: relative; |
|||
overflow: hidden; |
|||
height: 690px; |
|||
.recommends { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 220px); |
|||
flex-wrap: wrap; |
|||
gap: 24px 19px; |
|||
padding-bottom: 24px; |
|||
.recommend-item { |
|||
height: 162px; |
|||
background: rgba(255, 255, 255, 0.4); |
|||
border-radius: 8px; |
|||
overflow: hidden; |
|||
} |
|||
.pic-wrapper { |
|||
width: 220px; |
|||
height: 124px; |
|||
margin-bottom: 12px; |
|||
.pic { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
|
|||
.txt { |
|||
font-weight: 700; |
|||
font-size: 12px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-left: 12px; |
|||
font-family: 'font_bold'; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,132 +0,0 @@ |
|||
<template> |
|||
<div class="tabs-wrapper" v-if="menuList.tabList.length > 1"> |
|||
<div |
|||
class="tab" |
|||
:ref="el => tabsEl.push(el)" |
|||
:class="{ active: index === tabIdx }" |
|||
@click="handleTab(index)" |
|||
v-for="(item, index) of menuList.tabList" |
|||
:key="item.name" |
|||
> |
|||
{{ switchLanguage(item, 'name') }} |
|||
</div> |
|||
</div> |
|||
<component :tab="menuList.tabList" :is="currentComp"></component> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
import { ref, defineAsyncComponent, computed } from 'vue' |
|||
|
|||
const Activity = defineAsyncComponent(() => import('./Activity.vue')) |
|||
const Goods = defineAsyncComponent(() => import('./Goods.vue')) |
|||
const Comment = defineAsyncComponent(() => import('./Comment.vue')) |
|||
const Info = defineAsyncComponent(() => import('./Info.vue')) |
|||
const Recommend = defineAsyncComponent(() => import('./Recommend.vue')) |
|||
|
|||
const tabList = [ |
|||
{ |
|||
name: '品牌活动', |
|||
nameEn: 'Activity' |
|||
}, |
|||
{ |
|||
name: '商品', |
|||
nameEn: 'goods' |
|||
}, |
|||
{ |
|||
name: '评价', |
|||
nameEn: 'comments' |
|||
}, |
|||
{ |
|||
name: '信息', |
|||
nameEn: 'infomation' |
|||
}, |
|||
{ |
|||
name: '推荐菜', |
|||
nameEn: 'recommend' |
|||
} |
|||
] |
|||
const tabIdx = ref(0) |
|||
function handleTab(index) { |
|||
tabIdx.value = index |
|||
moveTo(index) |
|||
} |
|||
|
|||
const PADDING_LEFT = 6 |
|||
const tabsEl = ref([]) |
|||
const distance = ref(0) |
|||
|
|||
function moveTo(index) { |
|||
distance.value = tabsEl.value[index].offsetLeft - PADDING_LEFT + 'px' |
|||
} |
|||
|
|||
const store = useStore() |
|||
const { shop } = storeToRefs(store) |
|||
|
|||
const _dynamicCompList = [Activity, Goods, Comment, Info, Recommend] |
|||
const menuList = computed(() => { |
|||
if (shop.value.activityList.length && shop.value.thirdKouCode) { |
|||
return { tabList, dynamicCompList: _dynamicCompList } |
|||
} |
|||
|
|||
if (shop.value.activityList.length && !shop.value.thirdKouCode) { |
|||
return { tabList: tabList.slice(0, 1), dynamicCompList: _dynamicCompList.slice(0, 1) } |
|||
} |
|||
|
|||
if (!shop.value.activityList.length && shop.value.thirdKouCode) { |
|||
return { tabList: tabList.slice(1), dynamicCompList: _dynamicCompList.slice(1) } |
|||
} |
|||
|
|||
//无活动和无thirdKouCode |
|||
return { tabList: [], dynamicCompList: [] } |
|||
}) |
|||
const currentComp = computed(() => menuList.value.dynamicCompList[tabIdx.value]) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.tabs-wrapper { |
|||
position: relative; |
|||
display: flex; |
|||
height: 80px; |
|||
padding: 6px; |
|||
background: rgba(0, 0, 0, 0.05); |
|||
border-radius: 12px; |
|||
margin-bottom: 40px; |
|||
&::before { |
|||
position: absolute; |
|||
content: ''; |
|||
top: 6px; |
|||
left: 6px; |
|||
background: #ffffff; |
|||
box-shadow: inset 0px -4px 0px rgba(177, 189, 220, 0.1); |
|||
border-radius: 8px; |
|||
width: 128px; |
|||
height: 68px; |
|||
z-index: 0; |
|||
transition: all 0.5s; |
|||
transform: translate3d(v-bind(distance), 0, 0); |
|||
} |
|||
.tab { |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 128px; |
|||
height: 68px; |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 18px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
margin-right: 12px; |
|||
z-index: 1; |
|||
transition: color 0.5s; |
|||
&:last-child { |
|||
margin-right: 0; |
|||
} |
|||
&.active { |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,104 +0,0 @@ |
|||
<template> |
|||
<div class="brand-recommend"> |
|||
<p class="title">热门推荐</p> |
|||
<ScrollView :list="list" scroll-x class="content"> |
|||
<div class="recommend-content"> |
|||
<div class="group-item" @click="handleShop(item)" v-for="item of list" :key="item.shopId"> |
|||
<div class="logo-wrapper"> |
|||
<img loading="lazy" :src="config.sourceUrl + item.materialList?.[0]" alt="" class="shop-logo" /> |
|||
</div> |
|||
<p class="name"> |
|||
<span class="shop-name">{{ switchLanguage(item, 'shopName') }}</span> |
|||
<span class="name-right"><img :src="config.sourceUrl + item.industryUrl" class="format-icon" alt="" />{{ item.floor }}</span> |
|||
</p> |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
|
|||
defineProps({ |
|||
list: Array, |
|||
config: Object |
|||
}) |
|||
const emits = defineEmits(['click']) |
|||
|
|||
function handleShop(item) { |
|||
emits('click', item) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.brand-recommend { |
|||
margin-left: 170px; |
|||
|
|||
.title { |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
padding-bottom: 12px; |
|||
} |
|||
.content { |
|||
width: 910px; |
|||
overflow: hidden; |
|||
margin-bottom: 40px; |
|||
} |
|||
.recommend-content { |
|||
display: inline-block; |
|||
white-space: nowrap; |
|||
padding-top: 32px; |
|||
height: 255px; |
|||
} |
|||
.group-item { |
|||
display: inline-block; |
|||
width: 320px; |
|||
height: 220px; |
|||
background: rgba(255, 255, 255, 0.4); |
|||
border-radius: 8px; |
|||
overflow: hidden; |
|||
margin-right: 16px; |
|||
} |
|||
.logo-wrapper { |
|||
width: 320px; |
|||
height: 180px; |
|||
background-color: #fff; |
|||
} |
|||
.shop-logo { |
|||
width: 100%; |
|||
height: 100%; |
|||
border-radius: 8px; |
|||
object-fit: cover; |
|||
} |
|||
.name { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding: 13px 12px; |
|||
} |
|||
.shop-name { |
|||
font-weight: 700; |
|||
font-size: 12px; |
|||
line-height: 14px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
.name-right { |
|||
font-weight: 700; |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 12px; |
|||
line-height: 14px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
.format-icon { |
|||
width: 14px; |
|||
height: 14px; |
|||
margin-right: 8px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,204 +0,0 @@ |
|||
<template> |
|||
<ScrollView class="business-scroll"> |
|||
<div class="business-content"> |
|||
<div class="three-wrapper" :class="{ active: cardIdx === index }" v-for="(item, index) of 10" :key="item"> |
|||
<div class="front"> |
|||
<div class="title"> |
|||
<p class="title-left">巴黎贝甜</p> |
|||
<p class="title-right">¥<i>30</i></p> |
|||
</div> |
|||
<p class="sub-title">30元代金券,满129可用</p> |
|||
<ScrollView class="intro-scroll" scrollbar> |
|||
<p class="intro"> |
|||
欧时力(香港)集团全权代理意大利品牌欧时力(OCHIRLY),并组建欧时力(中国)有限公司,全权负责OCHIRLY在大中华区的品牌经营。欧时力自1999年进入中国市场以来,欧时力以前所未有的速度在中国市场发展壮大。在短短的两、三年间,迅速于中国60多个一、二类主要消费城市的160余家加盟店以及专柜年销售额达到2.5亿。销售业绩评效均名列前茅,整体业绩不断上扬!在女装市场享有一定的知名度和美誉度。欧时力(香港)集团全权代理意大利品牌欧时力(OCHIRLY),并组建欧时力(中国)有限公司,全权负责OCHIRLY在大中华区的品牌经营。欧时力自1999年进入中国市场以来,欧时力以前所未有的速度在中国市场发展壮大。在短短的两、三年间,迅速于中国60多个一、二类主要消费城市的160余家加盟店以及专柜年销售额达到2.5亿在短短的两、三年间,迅速于中国60多个一、二类主要消费城市的160余家加盟店以及专柜年销售额达到2.5亿在短短的两、三年间,迅速于中 |
|||
</p> |
|||
</ScrollView> |
|||
<p class="time first">领取时间:2021-01-01</p> |
|||
<p class="time">使用时间:2021-01-01至2021-12-30</p> |
|||
<div class="btn" @click="handleCard(item, index)">立即领取</div> |
|||
</div> |
|||
<div class="back"> |
|||
<div class="code"> |
|||
<img src="" alt="" class="code-img" /> |
|||
<div class="text">微信扫一扫</div> |
|||
</div> |
|||
<div class="btn" @click="cardIdx = -1">返回</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
|
|||
const cardIdx = ref(-1) |
|||
function handleCard(item, index) { |
|||
cardIdx.value = index |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.business-scroll { |
|||
position: relative; |
|||
margin-left: 170px; |
|||
overflow: hidden; |
|||
margin-top: 58px; |
|||
height: 1560px; |
|||
.business-content { |
|||
display: grid; |
|||
grid-template-columns: repeat(2, 420px); |
|||
gap: 56px 30px; |
|||
} |
|||
|
|||
.three-wrapper { |
|||
display: inline-block; |
|||
width: 420px; |
|||
height: 528px; |
|||
position: relative; |
|||
transform-style: preserve-3d; |
|||
transform: perspective(800px); |
|||
transition: all 0.5s; |
|||
transform-origin: center; |
|||
margin-right: 25px; |
|||
|
|||
&.active { |
|||
transform: rotateY(-180deg); |
|||
} |
|||
} |
|||
.front, |
|||
.back { |
|||
width: 420px; |
|||
height: 528px; |
|||
backface-visibility: hidden; |
|||
background: url('../../assets/images/member/line.png') no-repeat center 445px rgba(255, 255, 255, 0.8); |
|||
background-size: 497px 1px; |
|||
overflow: hidden; |
|||
border-radius: 12px; |
|||
.btn { |
|||
height: 83px; |
|||
line-height: 83px; |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
font-family: 'font_bold'; |
|||
text-align: center; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
&::before, |
|||
&::after { |
|||
content: ''; |
|||
position: absolute; |
|||
width: 18px; |
|||
height: 18px; |
|||
background: #f7f7f9; |
|||
bottom: 75px; |
|||
border-radius: 50%; |
|||
} |
|||
&::before { |
|||
left: -9px; |
|||
} |
|||
&::after { |
|||
right: -9px; |
|||
} |
|||
} |
|||
.front { |
|||
position: relative; |
|||
.title { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
color: #f1b33e; |
|||
align-items: baseline; |
|||
padding: 32px 56px 25px 56px; |
|||
|
|||
.title-left { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
font-family: 'font_bold'; |
|||
} |
|||
.title-right { |
|||
font-size: 24px; |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
i { |
|||
font-size: 48px; |
|||
font-weight: 700; |
|||
padding-left: 6px; |
|||
} |
|||
} |
|||
} |
|||
.sub-title { |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
margin-bottom: 40px; |
|||
font-family: 'font_bold'; |
|||
margin-left: 56px; |
|||
} |
|||
.intro-scroll { |
|||
height: 152px; |
|||
overflow: hidden; |
|||
position: relative; |
|||
margin-bottom: 45px; |
|||
margin-right: 34px; |
|||
padding-right: 16px; |
|||
margin-left: 56px; |
|||
|
|||
.intro { |
|||
font-size: 14px; |
|||
line-height: 200%; |
|||
text-align: justify; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
white-space: normal; |
|||
} |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.02) !important; |
|||
border-radius: 6px !important; |
|||
opacity: 1 !important; |
|||
.bscroll-indicator { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.1) !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
} |
|||
.time { |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
margin-left: 56px; |
|||
margin-bottom: 41px; |
|||
|
|||
&.first { |
|||
margin-bottom: 9px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.back { |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
transform: rotateY(-180deg); |
|||
.code { |
|||
height: 445px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
.code-img { |
|||
width: 150px; |
|||
height: 150px; |
|||
} |
|||
.text { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
padding-top: 47px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,154 +0,0 @@ |
|||
<template> |
|||
<Dialog @close="close"> |
|||
<div class="content"> |
|||
<div class="info"> |
|||
<div class="group"> |
|||
<p class="text">车牌号</p> |
|||
<p class="text-bold">沪AB66688</p> |
|||
</div> |
|||
<div class="group"> |
|||
<p class="text">车位号</p> |
|||
<p class="text-bold">E-123</p> |
|||
</div> |
|||
<div class="group"> |
|||
<p class="text">停车时长</p> |
|||
<p class="text-bold">2<i>小时</i>30<i>分钟</i></p> |
|||
</div> |
|||
<div class="last"> |
|||
<p class="text">费用</p> |
|||
<p class="text-bold">¥<i>2</i></p> |
|||
</div> |
|||
</div> |
|||
<div class="right"> |
|||
<div class="car-wrapper"> |
|||
<img src="" alt="" class="car-img" /> |
|||
</div> |
|||
<div class="codes-wrapper"> |
|||
<img src="" alt="" class="code" /> |
|||
<p class="tip">扫码缴费</p> |
|||
</div> |
|||
</div> |
|||
<Button class="car-btn" @click="close" /> |
|||
<Go class="go" /> |
|||
</div> |
|||
</Dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import Button from '@/base/Button/Button.vue' |
|||
import Go from '@/base/Go/Go.vue' |
|||
import Dialog from '@/layouts/Dialog.vue' |
|||
|
|||
const emits = defineEmits(['close']) |
|||
function close() { |
|||
emits('close') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
position: relative; |
|||
display: flex; |
|||
margin: 0 auto; |
|||
margin-top: 160px; |
|||
width: max-content; |
|||
animation-duration: 0.2s; |
|||
} |
|||
.info { |
|||
width: 480px; |
|||
height: 668px; |
|||
background: #ffffff; |
|||
border-radius: 12px; |
|||
padding: 64px 0 0 0; |
|||
} |
|||
.group { |
|||
margin-bottom: 64px; |
|||
padding-left: 64px; |
|||
|
|||
.text-bold { |
|||
font-weight: 700; |
|||
font-size: 32px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
i { |
|||
font-size: 20px; |
|||
padding: 0 5px; |
|||
} |
|||
} |
|||
} |
|||
.text { |
|||
font-weight: 400; |
|||
font-size: 20px; |
|||
line-height: 23px; |
|||
margin-bottom: 18px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
|
|||
.last { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
padding-left: 64px; |
|||
padding-top: 38px; |
|||
border-top: 1px solid rgba(0, 0, 0, 0.1); |
|||
.text-bold { |
|||
font-size: 24px; |
|||
i { |
|||
font-size: 48px; |
|||
padding-left: 5px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
margin-left: 32px; |
|||
.car-wrapper { |
|||
width: 480px; |
|||
height: 270px; |
|||
margin-bottom: 32px; |
|||
background: #ffffff; |
|||
border-radius: 12px; |
|||
overflow: hidden; |
|||
.car-img { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
|
|||
.codes-wrapper { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
width: 480px; |
|||
height: 366px; |
|||
background: #ffffff; |
|||
border-radius: 12px; |
|||
.code { |
|||
width: 150px; |
|||
height: 150px; |
|||
} |
|||
.tip { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
padding-top: 41px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.car-btn { |
|||
position: absolute; |
|||
top: 0; |
|||
right: -112px; |
|||
} |
|||
|
|||
.go { |
|||
position: absolute; |
|||
bottom: -160px; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
} |
|||
</style> |
|||
@ -1,131 +0,0 @@ |
|||
<template> |
|||
<div class="benefits-wrapper"> |
|||
<div class="carousel"> |
|||
<EffectFade :list="data?.fileList ?? []"> |
|||
<template v-slot="{ item }"> |
|||
<div class="banner-wrapper"> |
|||
<img class="banner" :src="config.sourceUrl + item" alt="" /> |
|||
</div> |
|||
</template> |
|||
</EffectFade> |
|||
</div> |
|||
<div class="right"> |
|||
<h1 class="title">{{ switchLanguage(data, 'title') }}</h1> |
|||
<ScrollView class="intro-scroll" scrollbar> |
|||
<p class="intro"> |
|||
{{ switchLanguage(data, 'content') }} |
|||
</p> |
|||
</ScrollView> |
|||
<div class="qrcodeWrapper"> |
|||
<ThumbQRCode class="item" v-for="item of qr" :url="config.sourceUrl + item.fileUrl" :title="switchLanguage(item, 'name')" :key="item.name" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed } from 'vue' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
import EffectFade from '@/components/EffectFade/EffectFade.vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import ThumbQRCode from '@/base/ThumbQRCode/ThumbQRCode.vue' |
|||
|
|||
const props = defineProps({ |
|||
data: Object |
|||
}) |
|||
|
|||
const store = useStore() |
|||
const { config } = storeToRefs(store) |
|||
const qr = computed(() => props.data.qrFileList ?? []) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.benefits-wrapper { |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 100%; |
|||
flex: 1; |
|||
align-items: center; |
|||
padding-top: 48px; |
|||
|
|||
.carousel { |
|||
flex-shrink: 0; |
|||
width: 944px; |
|||
height: 548px; |
|||
|
|||
overflow: hidden; |
|||
:deep(.swiper) { |
|||
overflow: visible; |
|||
.swiper-pagination { |
|||
bottom: -16px; |
|||
.swiper-pagination-bullet { |
|||
width: 34px !important; |
|||
height: 4px !important; |
|||
background: rgba(0, 0, 0, 0.6); |
|||
border-radius: 6px !important; |
|||
opacity: inherit !important; |
|||
margin: 0; |
|||
&.swiper-pagination-bullet-active { |
|||
background: #ffffff; |
|||
border-radius: 6px !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.banner { |
|||
width: 944px; |
|||
height: 532px; |
|||
border-radius: var(--global-radius, 8px); |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
} |
|||
.qrcodeWrapper { |
|||
display: flex; |
|||
margin-left: 68px; |
|||
.item { |
|||
margin-right: 10px; |
|||
} |
|||
} |
|||
.title { |
|||
padding-top: 32px; |
|||
padding-left: 68px; |
|||
font-weight: 700; |
|||
font-size: 28px; |
|||
line-height: 150%; |
|||
color: var(--carousel-titleColor); |
|||
} |
|||
|
|||
.intro-scroll { |
|||
position: relative; |
|||
height: 250px; |
|||
overflow: hidden; |
|||
margin-left: 68px; |
|||
margin-right: 31px; |
|||
padding-right: 31px; |
|||
margin-bottom: 33px; |
|||
margin-top: 32px; |
|||
.intro { |
|||
font-weight: 400; |
|||
font-size: 16px; |
|||
line-height: 200%; |
|||
text-align: justify; |
|||
color: var(--carousel-introColor); |
|||
} |
|||
} |
|||
@media (min-aspect-ratio: 1/1) { |
|||
.benefits-wrapper { |
|||
flex-direction: row; |
|||
align-items: flex-start; |
|||
padding-top: 100px; |
|||
padding-left: 63px; |
|||
.carousel { |
|||
position: relative; |
|||
} |
|||
} |
|||
.title { |
|||
padding-top: 0; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,118 +0,0 @@ |
|||
<template> |
|||
<div class="customer-wrapper"> |
|||
<div class="masker" @click="close"></div> |
|||
<div class="customer-content"> |
|||
<div class="customer-avatar"> |
|||
<div class="avatar-wrapper"> |
|||
<img src="../../assets/images/search/customer.png" class="avatar" alt="" /> |
|||
</div> |
|||
<p class="customer-name">客服001</p> |
|||
</div> |
|||
<div class="time">00:34</div> |
|||
<div class="status">{{ $t('waiting') }}...</div> |
|||
<img src="../../assets/images/search/out.svg" class="off" @click="close" alt="" /> |
|||
<div class="close" @click="close"> |
|||
<img src="../../assets/images/detail/yellow_close.png" alt="" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
const emits = defineEmits(['close']) |
|||
function close() { |
|||
emits('close') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.customer-wrapper { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 1000; |
|||
animation-duration: 0.2s; |
|||
.masker { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
} |
|||
.customer-content { |
|||
position: relative; |
|||
width: 600px; |
|||
height: 400px; |
|||
margin: 0 auto; |
|||
margin-top: 760px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 40px 60px rgba(0, 0, 0, 0.08); |
|||
border-radius: 12px; |
|||
.customer-avatar { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 24px 0 0 32px; |
|||
margin-bottom: 50px; |
|||
|
|||
.avatar-wrapper { |
|||
width: 56px; |
|||
height: 56px; |
|||
box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.04); |
|||
border-radius: 50%; |
|||
padding: 14px; |
|||
background-color: var(--color-fff); |
|||
.avatar { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: contain; |
|||
} |
|||
} |
|||
.customer-name { |
|||
font-weight: 700; |
|||
font-size: 16px; |
|||
padding-left: 16px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
} |
|||
.time { |
|||
font-weight: 700; |
|||
font-size: 48px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
font-family: 'font_bold'; |
|||
padding-bottom: 8px; |
|||
text-align: center; |
|||
} |
|||
.status { |
|||
color: rgba(0, 0, 0, 0.4); |
|||
text-align: center; |
|||
font-size: 18px; |
|||
margin-bottom: 49px; |
|||
} |
|||
.off { |
|||
display: block; |
|||
width: 80px; |
|||
height: 80px; |
|||
margin: 0 auto; |
|||
} |
|||
} |
|||
.close { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 12px; |
|||
right: 12px; |
|||
width: 56px; |
|||
height: 56px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
img { |
|||
width: 56px; |
|||
height: 56px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,36 +0,0 @@ |
|||
<template> |
|||
<swiper v-if="list.length" :watchOverflow="true" :modules="[Autoplay, EffectFade, Pagination]" :pagination="true" effect="fade" :autoplay="true"> |
|||
<swiper-slide v-for="item of list" :key="item"> |
|||
<slot :item="item"></slot> |
|||
</swiper-slide> |
|||
</swiper> |
|||
<img v-else src="../../assets/images/nodata.svg" class="stay-tuned" alt="" /> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import SwiperCore, { Autoplay, EffectFade, Pagination } from 'swiper' |
|||
import { Swiper, SwiperSlide } from 'swiper/vue' |
|||
|
|||
import 'swiper/css' |
|||
import 'swiper/css/effect-fade' |
|||
import 'swiper/css/pagination' |
|||
|
|||
SwiperCore.use([Autoplay, EffectFade, Pagination]) |
|||
|
|||
defineProps({ |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.stay-tuned { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 50%; |
|||
transform: translate3d(-50%, -50%, 0); |
|||
object-fit: contain; |
|||
} |
|||
</style> |
|||
@ -1,194 +0,0 @@ |
|||
<template> |
|||
<ScrollView class="format-wrapper" ref="scroll" :refresh-delay="800" :list="list"> |
|||
<div class="format-scroll"> |
|||
<div class="format-item" @click="handleFormat({ industryName: '全部品牌', industryNameEn: 'all' }, -1)"> |
|||
<div class="parent flex" :class="{ active: parentIdxRef === -1 }"> |
|||
<div class="format-left flex"> |
|||
<img src="../../assets/images/detail/all.svg" class="icon" alt="" /> |
|||
<span class="text">{{ $t('all') }}</span> |
|||
</div> |
|||
<div class="format-right flex"> |
|||
<span class="total">{{ total }}</span> |
|||
<img src="../../assets/images/detail/all_dot.svg" class="right-icon" alt="" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="format-item" v-for="(item, index) of list" :key="item.industryId"> |
|||
<div |
|||
class="parent flex" |
|||
@click="handleFormat(item, index)" |
|||
:class="[index === parentIdxRef ? 'active' : '', index === parentIdxRef && childIdxRef !== -1 ? 'child-active' : '']" |
|||
> |
|||
<div class="format-left flex"> |
|||
<img :src="config.sourceUrl + item.fileUrl" class="icon" alt="" /> |
|||
<span class="text">{{ switchLanguage(item, 'industryName') }}</span> |
|||
</div> |
|||
<div class="format-right flex"> |
|||
<span class="total">{{ item.shopNum }}</span> |
|||
<Arrow :size="18" fill="rgba(0, 0, 0, 0.2)" v-if="item.industryList?.length" class="right-icon svg-icon" /> |
|||
<img src="../../assets/images/detail/all_dot.svg" class="icon" v-else alt="" /> |
|||
</div> |
|||
</div> |
|||
<template v-if="item.industryList?.length"> |
|||
<div class="format-child-wrapper" v-if="index === parentIdxRef"> |
|||
<div class="format-item" v-for="(child, index) of item.industryList" :key="child.industryId"> |
|||
<div class="parent flex" :class="{ active: childIdxRef === index }" @click="handleChildFormat(child, index)"> |
|||
<div class="format-left flex"> |
|||
<span class="text">{{ switchLanguage(child, 'industryName') }}</span> |
|||
</div> |
|||
<div class="format-right flex"> |
|||
<span class="total">{{ child.shopNum ?? 0 }}</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed, nextTick, ref } from 'vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import { Arrow } from '@/base/Svg' |
|||
|
|||
const props = defineProps({ |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
config: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
} |
|||
}) |
|||
const total = computed(() => props.list.reduce((_total, item) => _total + item.shopNum, 0)) |
|||
|
|||
const emits = defineEmits(['click']) |
|||
emits('click', { industryName: '全部品牌', industryNameEn: 'all' }, -1) |
|||
|
|||
const scroll = ref(null) |
|||
const parentIdxRef = ref(-1) |
|||
const childIdxRef = ref(-1) |
|||
function handleFormat(item, index) { |
|||
emits('click', item, index) |
|||
childIdxRef.value = -1 |
|||
parentIdxRef.value = index |
|||
nextTick(() => { |
|||
scroll.value.refresh() |
|||
}) |
|||
} |
|||
function handleChildFormat(child, childIdx) { |
|||
childIdxRef.value = childIdx |
|||
emits('click', child, childIdx) |
|||
nextTick(() => { |
|||
scroll.value.refresh() |
|||
}) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.format-wrapper { |
|||
overflow: hidden; |
|||
height: 810px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
margin-top: 18px; |
|||
.format-scroll { |
|||
overflow: hidden; |
|||
border-radius: 8px; |
|||
} |
|||
.format-item { |
|||
width: 200px; |
|||
background-color: #fff; |
|||
.parent { |
|||
height: 56px; |
|||
padding: 0 12px 0 24px; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
&.active { |
|||
background: linear-gradient(90deg, #ffbd35 0%, #ffd260 100%); |
|||
.icon, |
|||
.right-icon { |
|||
filter: brightness(50) invert(70%); |
|||
&.svg-icon { |
|||
filter: none; |
|||
} |
|||
} |
|||
|
|||
:deep(path) { |
|||
fill: rgba(0, 0, 0, 0.6); |
|||
} |
|||
|
|||
.svg-icon { |
|||
transform: rotate(-180deg); |
|||
} |
|||
.text, |
|||
.total { |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
} |
|||
&.child-active { |
|||
background: transparent; |
|||
.icon, |
|||
.right-icon { |
|||
filter: none; |
|||
} |
|||
:deep(path) { |
|||
fill: rgba(0, 0, 0, 0.6); |
|||
} |
|||
.right-icon { |
|||
transform: rotate(-180deg); |
|||
} |
|||
.text, |
|||
.total { |
|||
color: var(--color-9b0); |
|||
} |
|||
} |
|||
} |
|||
.format-right { |
|||
.icon { |
|||
margin-left: 8px; |
|||
margin-right: 0; |
|||
} |
|||
} |
|||
.icon { |
|||
width: 16px; |
|||
height: 16px; |
|||
margin-right: 8px; |
|||
} |
|||
.text, |
|||
.total { |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
.total { |
|||
font-weight: 400; |
|||
font-family: 'font_regular'; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
.right-icon { |
|||
margin-left: 8px; |
|||
transition: transform 0.3s; |
|||
} |
|||
} |
|||
.format-child-wrapper { |
|||
.parent { |
|||
padding: 0 48px; |
|||
} |
|||
.text { |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
.total { |
|||
color: rgba(0, 0, 0, 0.2); |
|||
} |
|||
} |
|||
} |
|||
.flex { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
</style> |
|||
@ -1,86 +0,0 @@ |
|||
<template> |
|||
<div class="keyboard"> |
|||
<div |
|||
class="letter-item" |
|||
@click="handleLetter(item, index)" |
|||
:class="[item === '空格' ? 'space' : '', item === 'del' ? 'del' : '', letterIdx === index ? 'active' : '']" |
|||
v-for="(item, index) of letter" |
|||
:key="item" |
|||
v-html="generateInnerHTML(item)" |
|||
></div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
import { letter } from '../Search/tabs' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
const store = useStore() |
|||
const { theme } = storeToRefs(store) |
|||
function generateInnerHTML(item) { |
|||
return item === 'del' ? `<img style="width:24px;height:24px" src="${theme.value.images.delete}" alt="">` : item |
|||
} |
|||
|
|||
const emits = defineEmits(['del', 'handle-letter']) |
|||
const timer = ref(null) |
|||
const letterIdx = ref(-1) |
|||
function handleLetter(item, index) { |
|||
letterIdx.value = index |
|||
clearTimeout(timer.value) |
|||
timer.value = setTimeout(() => { |
|||
letterIdx.value = -1 |
|||
clearTimeout(timer.value) |
|||
}, 300) |
|||
|
|||
if (item !== '空格' && item !== 'del') { |
|||
emits('handle-letter', item) |
|||
return |
|||
} |
|||
|
|||
item === 'del' && emits('del') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.keyboard { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
padding-top: 40px; |
|||
.letter-item { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
width: 48px; |
|||
height: 48px; |
|||
text-align: center; |
|||
line-height: 48px; |
|||
background: var(--search-keyBg, #ffffff); |
|||
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.03), inset 0px -1px 0px rgba(177, 189, 220, 0.1); |
|||
border-radius: var(--global-radius, 8px); |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
font-family: 'font_bold'; |
|||
color: var(--search-keyColor, rgba(0, 0, 0, 0.6)); |
|||
margin-right: 8px; |
|||
margin-bottom: 8px; |
|||
&:nth-child(21) { |
|||
margin-left: 28px; |
|||
} |
|||
&.space { |
|||
font-size: 14px; |
|||
} |
|||
&.del { |
|||
width: 104px; |
|||
img { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
} |
|||
&.active { |
|||
background: var(--search-keyboardActiveBg); |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,107 +0,0 @@ |
|||
<template> |
|||
<div class="written-wrapper"> |
|||
<ScrollView class="word-scroll" scroll-x :list="wordsList"> |
|||
<div class="word-content"> |
|||
<div class="word" @click="handleWord(item, index)" :class="{ active: wordIdx === index }" v-for="(item, index) of wordsList" :key="item">{{ item }}</div> |
|||
</div> |
|||
</ScrollView> |
|||
<Written |
|||
@result="getWordList" |
|||
:width="552" |
|||
:height="196" |
|||
background-color="transparent" |
|||
fill-font-size="48px" |
|||
fill-style="rgba(0, 0, 0, 0.02)" |
|||
:stroke-style="theme.search.writeColor" |
|||
/> |
|||
<div class="del" @click="del"> |
|||
<img :src="theme.images.delete" class="del-icon" alt="" /> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
import Written from '../Written/Written.vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
const wordsList = ref([]) |
|||
const store = useStore() |
|||
const { theme } = storeToRefs(store) |
|||
|
|||
function getWordList(list) { |
|||
wordsList.value = list |
|||
} |
|||
|
|||
const emits = defineEmits(['handle-word', 'del']) |
|||
const wordIdx = ref(-1) |
|||
const timer = ref(null) |
|||
function handleWord(item, index) { |
|||
clearTimeout(timer.value) |
|||
wordIdx.value = index |
|||
emits('handle-word', item) |
|||
timer.value = setTimeout(() => { |
|||
wordIdx.value = -1 |
|||
clearTimeout(timer.value) |
|||
}, 300) |
|||
} |
|||
|
|||
function del() { |
|||
emits('del') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.written-wrapper { |
|||
position: relative; |
|||
width: 552px; |
|||
height: 252px; |
|||
background: var(--search-keyBg, #ffffff); |
|||
border-radius: var(--global-radius, 12px); |
|||
margin-top: 16px; |
|||
overflow: hidden; |
|||
.word-scroll { |
|||
position: relative; |
|||
height: 56px; |
|||
background: var(--search-keyBg, #ffffff); |
|||
box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.04); |
|||
.word-content { |
|||
display: inline-block; |
|||
white-space: nowrap; |
|||
} |
|||
.word { |
|||
display: inline-block; |
|||
width: 66px; |
|||
height: 56px; |
|||
text-align: center; |
|||
line-height: 56px; |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
font-family: 'font_bold'; |
|||
color: var(--search-keyColor, rgba(0, 0, 0, 0.6)); |
|||
&.active { |
|||
color: #fff; |
|||
background: var(--search-keyboardActiveBg); |
|||
} |
|||
} |
|||
} |
|||
.del { |
|||
position: absolute; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 104px; |
|||
height: 48px; |
|||
right: 8px; |
|||
bottom: 8px; |
|||
background: rgba(0, 0, 0, 0.05); |
|||
box-shadow: inset 0px -1px 0px rgba(177, 189, 220, 0.1); |
|||
border-radius: var(--global-radius, 8px); |
|||
img { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,49 +0,0 @@ |
|||
<template> |
|||
<div class="language"> |
|||
<div class="language-item" @click="setLanguage('zh')" :class="{ active: language === 'zh' }">中</div> |
|||
<div class="language-item" @click="setLanguage('en')" :class="{ active: language === 'en' }">EN</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { useStore } from '@/store/root' |
|||
import { storeToRefs } from 'pinia' |
|||
|
|||
const store = useStore() |
|||
const { language } = storeToRefs(store) |
|||
|
|||
function setLanguage(lang) { |
|||
store.language !== lang && store.SET_LANGUAGE(lang) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.language { |
|||
position: absolute; |
|||
left: 24px; |
|||
bottom: 56px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 93px; |
|||
height: 32px; |
|||
border-radius: 12px; |
|||
background-color: var(--color-black-opacity-02); |
|||
padding: 0 3px; |
|||
} |
|||
.language-item { |
|||
width: 43px; |
|||
height: 26px; |
|||
border-radius: 10px; |
|||
text-align: center; |
|||
line-height: 26px; |
|||
font-size: 14px; |
|||
color: var(--color-black-opacity-4); |
|||
font-family: 'font_bold'; |
|||
font-weight: bolder; |
|||
&.active { |
|||
background: var(--color-linear-lightgoldenyellow); |
|||
color: var(--color-black-opacity-6); |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,314 +0,0 @@ |
|||
<template> |
|||
<div class="login-by-phone"> |
|||
<div class="masker" @click="handleClose"></div> |
|||
<div class="detail-content"> |
|||
<h4 class="login-text">{{ $t('login') }}</h4> |
|||
<div class="phone-group" @click="changeInputFocus('phone')"> |
|||
<img src="../../assets/images/member/hpone_tip.png" alt="" class="group-icon" /> |
|||
<div class="line"></div> |
|||
<input v-model="phoneRef" readonly type="text" :placeholder="$t('phoneNum')" class="input" /> |
|||
</div> |
|||
<div class="pwd-box"> |
|||
<div class="phone-group pwd"> |
|||
<img src="../../assets/images/member/pwd.png" alt="" class="group-icon" /> |
|||
<div class="line"></div> |
|||
<input v-model="msgRef" @click="changeInputFocus('msg')" readonly type="text" :placeholder="$t('enterCode')" class="input" /> |
|||
</div> |
|||
<div class="button" @click="sendMsg" :class="{ active: isSended }">{{ isSended ? countDownRef + ' ' + $t('again') : $t('sendCode') }}</div> |
|||
</div> |
|||
<div class="comfirm" @click="comfirm" :class="{ active: phoneRef.length && msgRef.length }">{{ $t('denglu') }}</div> |
|||
<div class="phone-keyboard"> |
|||
<div |
|||
class="num" |
|||
@click="handleNum(item === 10 ? '' : item === 11 ? 0 : item, index)" |
|||
:class="{ active: numIdx === index }" |
|||
v-for="(item, index) of 12" |
|||
:key="item" |
|||
v-html="generate(item)" |
|||
></div> |
|||
</div> |
|||
<div class="close" @click="handleClose"> |
|||
<img src="../../assets/images/detail/yellow_close.png" alt="" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, onBeforeUnmount } from 'vue' |
|||
import { checkPhoneNumber } from '@/utils/utils' |
|||
import Message from '@/base/Message/Message' |
|||
|
|||
const emits = defineEmits(['success', 'error', 'close']) |
|||
|
|||
function generate(item) { |
|||
return item === 10 ? '' : item === 11 ? 0 : item === 12 ? `<img src=${require('../../assets/images/member/del.svg')} class="del-icon" alt="" />` : item |
|||
} |
|||
|
|||
const phoneRef = ref('') |
|||
const msgRef = ref('') |
|||
const inputFocusRef = ref('phone') |
|||
const numIdx = ref(-1) |
|||
const numTimer = ref(null) |
|||
|
|||
function handleNum(item, index) { |
|||
clearTimeout(numTimer.value) |
|||
numIdx.value = index |
|||
numTimer.value = setTimeout(() => { |
|||
numIdx.value = -1 |
|||
clearTimeout(numTimer.value) |
|||
}, 300) |
|||
|
|||
if (item === 12) { |
|||
del() |
|||
return |
|||
} |
|||
|
|||
if (inputFocusRef.value === 'phone') { |
|||
if (phoneRef.value.length < 11) { |
|||
phoneRef.value += item |
|||
} |
|||
} |
|||
if (inputFocusRef.value === 'msg') { |
|||
msgRef.value += item |
|||
} |
|||
} |
|||
|
|||
function changeInputFocus(name) { |
|||
inputFocusRef.value = name |
|||
} |
|||
function del() { |
|||
if (inputFocusRef.value === 'phone') { |
|||
phoneRef.value = phoneRef.value.substring(0, phoneRef.value.length - 1) |
|||
} |
|||
if (inputFocusRef.value === 'msg') { |
|||
msgRef.value = msgRef.value.substring(0, msgRef.value.length - 1) |
|||
} |
|||
} |
|||
|
|||
const countDownRef = ref(60) |
|||
const countDownTimer = ref(null) |
|||
const isSended = ref(false) |
|||
//发送验证码 |
|||
function sendMsg() { |
|||
if (isSended.value) return |
|||
if (!checkPhoneNumber(phoneRef.value)) { |
|||
Message({ type: 'error', text: '请输入正确的手机号' }) |
|||
return |
|||
} |
|||
if (!phoneRef.value.length) { |
|||
Message({ type: 'error', text: '手机号不能为空' }) |
|||
return |
|||
} |
|||
isSended.value = true |
|||
inputFocusRef.value = 'msg' |
|||
countDownTimer.value = setInterval(countDown, 1000) |
|||
} |
|||
//一分钟倒计时 |
|||
function countDown() { |
|||
countDownRef.value-- |
|||
if (countDownRef.value <= 0) { |
|||
isSended.value = false |
|||
countDownRef.value = 60 |
|||
clearInterval(countDownTimer.value) |
|||
} |
|||
} |
|||
|
|||
//登录 |
|||
function comfirm() { |
|||
if (!checkPhoneNumber(phoneRef.value)) { |
|||
Message({ type: 'error', text: '请输入正确的手机号' }) |
|||
return |
|||
} |
|||
emits('success') |
|||
} |
|||
|
|||
onBeforeUnmount(() => { |
|||
clearInterval(countDownTimer.value) |
|||
}) |
|||
|
|||
function handleClose() { |
|||
emits('close') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.login-by-phone { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 51; |
|||
animation-duration: 0.3s; |
|||
} |
|||
.masker { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 20; |
|||
} |
|||
.detail-content { |
|||
position: relative; |
|||
width: 484px; |
|||
height: 732px; |
|||
margin: 0 auto; |
|||
margin-top: 594px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 40px 60px rgba(0, 0, 0, 0.08); |
|||
border-radius: 12px; |
|||
z-index: 21; |
|||
|
|||
.close { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 12px; |
|||
right: 12px; |
|||
width: 56px; |
|||
height: 56px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
img { |
|||
width: 56px; |
|||
height: 56px; |
|||
} |
|||
} |
|||
|
|||
.login-text { |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
line-height: 28px; |
|||
margin-bottom: 40px; |
|||
padding-top: 48px; |
|||
padding-left: 72px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
::-webkit-input-placeholder { |
|||
font-size: 12px; |
|||
color: var(--color-0cb); |
|||
} |
|||
.pwd-box { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
width: 340px; |
|||
margin-top: 12px; |
|||
margin-left: 72px; |
|||
margin-bottom: 24px; |
|||
|
|||
.phone-group { |
|||
margin-left: 0; |
|||
} |
|||
|
|||
.button { |
|||
width: 116px; |
|||
height: 64px; |
|||
left: 296px; |
|||
top: 192px; |
|||
text-align: center; |
|||
line-height: 64px; |
|||
background: linear-gradient(90deg, #ffbd35 0%, #ffd260 100%); |
|||
border-radius: 12px; |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
font-family: 'font_bold'; |
|||
} |
|||
} |
|||
.phone-group { |
|||
display: flex; |
|||
align-items: center; |
|||
width: 340px; |
|||
height: 64px; |
|||
margin-left: 72px; |
|||
background: rgba(0, 0, 0, 0.05); |
|||
border-radius: 12px; |
|||
padding-left: 20px; |
|||
&.pwd { |
|||
width: 212px; |
|||
} |
|||
.group-icon { |
|||
width: 20px; |
|||
} |
|||
.line { |
|||
width: 1px; |
|||
height: 14px; |
|||
background: rgba(0, 0, 0, 0.05); |
|||
border-radius: 1px; |
|||
margin: 0 14px; |
|||
} |
|||
} |
|||
.input { |
|||
width: 100%; |
|||
display: block; |
|||
border: none; |
|||
outline: none; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
font-size: 16px; |
|||
background-color: transparent; |
|||
} |
|||
|
|||
.comfirm { |
|||
width: 340px; |
|||
height: 64px; |
|||
line-height: 64px; |
|||
left: 72px; |
|||
top: 280px; |
|||
background: linear-gradient(90deg, #ffbd35 0%, #ffd260 100%); |
|||
border-radius: 12px; |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
text-align: center; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
font-family: 'font_bold'; |
|||
margin: 0 auto; |
|||
margin-bottom: 40px; |
|||
} |
|||
.phone-keyboard { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 108px); |
|||
grid-template-rows: repeat(4, 56px); |
|||
gap: 12px 8px; |
|||
background: linear-gradient(180deg, rgba(0, 0, 0, 0.05) 0%, rgba(0, 0, 0, 0.025) 100%); |
|||
padding: 40px 70px 48px 70px; |
|||
.num { |
|||
background: #ffffff; |
|||
box-shadow: inset 0px -4px 0px rgba(177, 189, 220, 0.1); |
|||
border-radius: 8px; |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
font-family: 'font_bold'; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
&.active { |
|||
background: linear-gradient(90deg, #ffbd35 0%, #ffd260 100%); |
|||
box-shadow: inset 0px -4px 0px rgba(177, 189, 220, 0.1); |
|||
} |
|||
} |
|||
.del { |
|||
height: 56px; |
|||
width: 112px; |
|||
display: inline-flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
.del-icon { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.close { |
|||
position: absolute; |
|||
top: 24px; |
|||
width: 56px; |
|||
height: 56px; |
|||
right: 24px; |
|||
} |
|||
</style> |
|||
@ -1,83 +0,0 @@ |
|||
<template> |
|||
<div class="full-code"> |
|||
<div class="code-wrapper"> |
|||
<img :src="icon" class="img" alt="" /> |
|||
<p class="youhui">{{ title }}</p> |
|||
<slot /> |
|||
<div class="close" @click="handleClose"> |
|||
<img src="../../assets/images/detail/yellow_close.png" alt="" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
defineProps({ |
|||
title: { |
|||
type: String, |
|||
default: '注册成功' |
|||
}, |
|||
icon: { |
|||
type: String, |
|||
default: require('@/assets/images/member/login_success.png') |
|||
} |
|||
}) |
|||
const emits = defineEmits(['close']) |
|||
|
|||
function handleClose() { |
|||
emits('close') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.full-code { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
} |
|||
.code-wrapper { |
|||
position: absolute; |
|||
top: 50%; |
|||
left: 50%; |
|||
width: 592px; |
|||
min-height: 512px; |
|||
transform: translate3d(-50%, -50%, 0); |
|||
background: #ffffff; |
|||
box-shadow: 0px 0px 80px rgba(0, 0, 0, 0.163735); |
|||
padding-top: 96px; |
|||
z-index: 10; |
|||
.img { |
|||
display: block; |
|||
margin: 0 auto; |
|||
margin-bottom: 96px; |
|||
width: 200px; |
|||
height: 200px; |
|||
} |
|||
.youhui { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
line-height: 23px; |
|||
text-align: center; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
|
|||
.close { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 12px; |
|||
right: 12px; |
|||
width: 56px; |
|||
height: 56px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
img { |
|||
width: 56px; |
|||
height: 56px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,104 +0,0 @@ |
|||
<template> |
|||
<div class="mall-wrapper"> |
|||
<div class="carousel"> |
|||
<EffectFade :list="banner"> |
|||
<template v-slot="{ item }"> |
|||
<div class="banner-wrapper"> |
|||
<img :src="config.sourceUrl + item" alt="" class="banner" /> |
|||
</div> |
|||
</template> |
|||
</EffectFade> |
|||
</div> |
|||
<h1 class="title">{{ $t('mallIntroduce') }}</h1> |
|||
<ScrollView :list="introduce.content" scrollbar class="mall-intro-scroll"> |
|||
<p class="mall-intro"> |
|||
{{ switchLanguage(introduce, 'content') }} |
|||
</p> |
|||
</ScrollView> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed } from 'vue' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
import { getMallInfoList } from '@/http/api' |
|||
import EffectFade from '@/components/EffectFade/EffectFade.vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
|
|||
const store = useStore() |
|||
const { config } = storeToRefs(store) |
|||
|
|||
const introduce = ref({}) |
|||
const banner = computed(() => introduce.value?.fileList ?? []) |
|||
getMallInfoList().then(({ data }) => { |
|||
introduce.value = data ?? {} |
|||
}) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.mall-wrapper { |
|||
width: 870px; |
|||
margin-left: 170px; |
|||
margin-right: 40px; |
|||
margin-top: 58px; |
|||
background: rgba(255, 255, 255, 0.4); |
|||
box-shadow: inset 1px 0px 0px #ffffff; |
|||
border-radius: 12px; |
|||
padding-bottom: 52px; |
|||
.carousel { |
|||
width: 870px; |
|||
height: 490px; |
|||
background: #ffffff; |
|||
margin-right: 56px; |
|||
border-radius: 8px; |
|||
overflow: hidden; |
|||
.banner-wrapper { |
|||
width: 870px; |
|||
height: 490px; |
|||
} |
|||
.banner { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
|
|||
.title { |
|||
padding-top: 48px; |
|||
padding-bottom: 32px; |
|||
margin-left: 56px; |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
font-family: 'font_bold'; |
|||
} |
|||
.mall-intro-scroll { |
|||
position: relative; |
|||
overflow: hidden; |
|||
height: 758px; |
|||
margin-left: 56px; |
|||
margin-right: 34px; |
|||
padding-right: 16px; |
|||
.mall-intro { |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
line-height: 200%; |
|||
text-align: justify; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.02) !important; |
|||
border-radius: 6px !important; |
|||
opacity: 1 !important; |
|||
.bscroll-indicator { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.1) !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,105 +0,0 @@ |
|||
<template> |
|||
<div class="big-input"> |
|||
<div class="input-left" @click="handleSearch"> |
|||
<div class="search-content"> |
|||
<img src="../../assets/images/index/index_search.png" class="index-search-icon" alt="" /> |
|||
<div class="mock-input"> |
|||
<p class="search">搜索</p> |
|||
<p class="search-en">search</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="input-right" @click="handleVoice"> |
|||
<img src="../../assets/images/index/index_voice.png" class="index-voice-icon" alt="" /> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { useStore } from '@/store/root' |
|||
|
|||
const store = useStore() |
|||
function handleSearch() { |
|||
store.SET_SHOW_SEARCH(true) |
|||
} |
|||
|
|||
function handleVoice() { |
|||
store.SET_SHOW_SEARCH(true) |
|||
store.SET_SHOW_VOICE(true) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.big-input { |
|||
display: flex; |
|||
height: 108px; |
|||
margin-right: 40px; |
|||
margin-bottom: 46px; |
|||
z-index: 55; |
|||
.input-left { |
|||
position: relative; |
|||
flex: 1; |
|||
background: linear-gradient(90deg, #f6a62c 0%, #ffbc3f 100%); |
|||
box-shadow: 0px 12px 20px rgba(253, 177, 48, 0.1); |
|||
border-radius: 12px; |
|||
margin-right: 20px; |
|||
&::after { |
|||
position: absolute; |
|||
border-radius: 12px; |
|||
content: ''; |
|||
left: 0; |
|||
right: 0; |
|||
top: 0; |
|||
bottom: 4px; |
|||
background: #fff; |
|||
} |
|||
.search-content { |
|||
position: relative; |
|||
z-index: 2; |
|||
} |
|||
.search-content { |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
width: 629px; |
|||
height: 104px; |
|||
background-color: var(--color-white-opacity); |
|||
box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.3), inset 0px 4px 30px rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
&::before { |
|||
position: absolute; |
|||
content: ''; |
|||
width: 2px; |
|||
height: 30px; |
|||
left: 112px; |
|||
top: 37px; |
|||
background: var(--color-black-opacity-2); |
|||
} |
|||
.index-search-icon { |
|||
width: 48px; |
|||
height: 48px; |
|||
margin-right: 54px; |
|||
margin-left: 44px; |
|||
} |
|||
.search { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
line-height: 28px; |
|||
font-family: 'font_bold'; |
|||
color: var(--color-black-opacity-6); |
|||
} |
|||
.search-en { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 14px; |
|||
text-transform: uppercase; |
|||
color: var(--color-black-opacity-4); |
|||
} |
|||
} |
|||
} |
|||
.index-voice-icon { |
|||
margin-top: -9px; |
|||
width: 246px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,388 +0,0 @@ |
|||
<template> |
|||
<Dialog @close="close"> |
|||
<div class="content"> |
|||
<div class="content-left"> |
|||
<div class="poster-wrapper"> |
|||
<img class="poster" :src="movie.posterPath" alt="" /> |
|||
</div> |
|||
<p class="name">{{ movie.showName }}</p> |
|||
<div class="group"> |
|||
<div class="text">导演:</div> |
|||
<div class="info">{{ movie.director }}</div> |
|||
</div> |
|||
<div class="group"> |
|||
<div class="text">类型:</div> |
|||
<div class="info">{{ movie.type }}</div> |
|||
</div> |
|||
<div class="group"> |
|||
<div class="text">语言:</div> |
|||
<div class="info">{{ movie.language }}</div> |
|||
</div> |
|||
<div class="group"> |
|||
<div class="text">片长:</div> |
|||
<div class="info">{{ movie.duration }} 分钟</div> |
|||
</div> |
|||
<div class="group last"> |
|||
<div class="text">主演:</div> |
|||
<div class="info">{{ movie.leadingRole }}</div> |
|||
</div> |
|||
|
|||
<div class="remark"> |
|||
<span>{{ $t('rate') }}</span> |
|||
{{ movie.remark }} |
|||
</div> |
|||
|
|||
<div class="price"> |
|||
<div class="price-num"> |
|||
¥ |
|||
<i>{{ movie.price / 100 }}</i> |
|||
起 |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="content-right"> |
|||
<ScrollView class="date-scroll" scroll-x :list="dateList"> |
|||
<div class="date-content"> |
|||
<div |
|||
class="date-item" |
|||
:ref="el => tabsEl.push(el)" |
|||
:class="{ active: index === tabIdx }" |
|||
@click="handleTab(index)" |
|||
v-for="(item, index) of dateList" |
|||
:key="item.week" |
|||
> |
|||
<span class="date">{{ item.customDate }}</span> |
|||
<span class="week">{{ item.week }}</span> |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
<ScrollView class="list-scroll"> |
|||
<div class="list-content"> |
|||
<table> |
|||
<tr v-for="item of 2" :key="item"> |
|||
<td class="w-190"> |
|||
<div class="start">12:00</div> |
|||
<div class="end">12:00</div> |
|||
</td> |
|||
<td class="w-190"> |
|||
<div class="type">IMAX</div> |
|||
<div class="ting">激光 3 厅</div> |
|||
</td> |
|||
<td class="w-190 line"> |
|||
<div class="ticket">06<i>张</i></div> |
|||
<div class="rest">余票</div> |
|||
</td> |
|||
<td class="w-222 center"> |
|||
<div class="price-num">¥<i>36</i>起</div> |
|||
</td> |
|||
<td> |
|||
<div class="button" @click="showQRCodeDialog">{{ $t('ticket') }}</div> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</ScrollView> |
|||
</div> |
|||
<Button @click="close" class="btn" /> |
|||
</div> |
|||
<QRCode v-if="showCode" @close="showCode = false" title="微信扫码购买" /> |
|||
</Dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed, ref, defineAsyncComponent } from 'vue' |
|||
import { futureDate } from '@/utils/utils' |
|||
import Dialog from '@/layouts/Dialog.vue' |
|||
import Button from '@/base/Button/Button.vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
const QRCode = defineAsyncComponent(() => import('@/base/QRCode/QRCode.vue')) |
|||
|
|||
defineProps({ |
|||
movie: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
} |
|||
}) |
|||
|
|||
const dateList = computed(() => futureDate()) |
|||
|
|||
const tabIdx = ref(0) |
|||
function handleTab(index) { |
|||
tabIdx.value = index |
|||
moveTo(index) |
|||
} |
|||
|
|||
const PADDING_LEFT = 6 |
|||
const tabsEl = ref([]) |
|||
const distance = ref(0) |
|||
|
|||
function moveTo(index) { |
|||
distance.value = tabsEl.value[index].offsetLeft - PADDING_LEFT + 'px' |
|||
} |
|||
|
|||
const showCode = ref(false) |
|||
function showQRCodeDialog() { |
|||
showCode.value = true |
|||
} |
|||
|
|||
const emits = defineEmits(['close']) |
|||
function close() { |
|||
emits('close') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
position: relative; |
|||
display: flex; |
|||
margin: 0 auto; |
|||
margin-top: 360px; |
|||
width: max-content; |
|||
z-index: 10; |
|||
|
|||
.price-num { |
|||
padding-left: 24px; |
|||
padding-right: 24px; |
|||
color: #f1b33e; |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 16px; |
|||
i { |
|||
font-size: 32px; |
|||
padding: 0 4px; |
|||
} |
|||
} |
|||
.content-left { |
|||
width: 260px; |
|||
height: 727px; |
|||
background: #ffffff; |
|||
border-radius: 12px; |
|||
padding: 4px; |
|||
margin-right: 24px; |
|||
.poster-wrapper { |
|||
width: 252px; |
|||
height: 380px; |
|||
border-radius: 8px; |
|||
overflow: hidden; |
|||
margin-bottom: 24px; |
|||
.poster { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
.name { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
font-family: 'font_bold'; |
|||
margin-bottom: 20px; |
|||
@include no-wrap; |
|||
padding-left: 24px; |
|||
} |
|||
.group { |
|||
display: flex; |
|||
padding: 0 24px; |
|||
margin-bottom: 8px; |
|||
&.last { |
|||
margin-bottom: 14px; |
|||
.info { |
|||
height: 28px; |
|||
@include more-wrap; |
|||
} |
|||
} |
|||
.text { |
|||
font-weight: 700; |
|||
font-size: 12px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
padding-right: 8px; |
|||
flex-shrink: 0; |
|||
} |
|||
.info { |
|||
font-weight: 400; |
|||
font-size: 12px; |
|||
line-height: 14px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
} |
|||
|
|||
.remark { |
|||
font-weight: 700; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
margin-left: 24px; |
|||
font-family: 'font_bold'; |
|||
font-size: 14px; |
|||
margin-right: 24px; |
|||
padding-bottom: 47px; |
|||
margin-bottom: 16px; |
|||
border-bottom: 1px solid rgba(0, 0, 0, 0.02); |
|||
|
|||
span { |
|||
font-size: 16px; |
|||
} |
|||
} |
|||
} |
|||
.content-right { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
.date-scroll { |
|||
position: relative; |
|||
overflow: hidden; |
|||
width: 680px; |
|||
height: 128px; |
|||
background: rgba(0, 0, 0, 0.2); |
|||
border-radius: 12px; |
|||
padding: 6px 0; |
|||
margin-bottom: 24px; |
|||
|
|||
.date-content { |
|||
display: inline-block; |
|||
white-space: nowrap; |
|||
padding: 0 6px; |
|||
|
|||
&::before { |
|||
position: absolute; |
|||
content: ''; |
|||
left: 6px; |
|||
background: linear-gradient(90deg, #f6a62c 0%, #ffbc3f 100%); |
|||
box-shadow: 0 20px 30px rgba(221, 152, 55, 0.2); |
|||
border-radius: 8px; |
|||
border: 1px solid rgba(255, 189, 53, 1); |
|||
width: 134px; |
|||
height: 116px; |
|||
z-index: 0; |
|||
transition: all 0.5s; |
|||
transform: translate3d(v-bind(distance), 0, 0); |
|||
} |
|||
|
|||
.date-item { |
|||
display: inline-flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-right: 12px; |
|||
width: 134px; |
|||
height: 116px; |
|||
} |
|||
.date { |
|||
position: relative; |
|||
z-index: 5; |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 20px; |
|||
color: #ffffff; |
|||
padding-bottom: 5px; |
|||
} |
|||
.week { |
|||
font-weight: 400; |
|||
position: relative; |
|||
z-index: 5; |
|||
font-size: 14px; |
|||
text-align: center; |
|||
color: #ffffff; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.list-scroll { |
|||
flex: 1; |
|||
overflow: hidden; |
|||
border-radius: 8px; |
|||
table { |
|||
width: 680px; |
|||
tr { |
|||
display: block; |
|||
background-color: #fff; |
|||
border-radius: 8px; |
|||
margin-bottom: 8px; |
|||
padding: 26px 48px; |
|||
} |
|||
td { |
|||
position: relative; |
|||
vertical-align: middle; |
|||
text-align: left; |
|||
&.center { |
|||
text-align: center; |
|||
} |
|||
.start { |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-bottom: 4px; |
|||
} |
|||
.end { |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
.type { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-bottom: 4px; |
|||
} |
|||
.ting { |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
.ticket { |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
font-family: 'font_bold'; |
|||
padding-bottom: 4px; |
|||
} |
|||
.rest { |
|||
font-weight: 400; |
|||
font-size: 14px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
.button { |
|||
width: 136px; |
|||
height: 56px; |
|||
line-height: 56px; |
|||
text-align: center; |
|||
background: linear-gradient(90deg, #f6a62c 0%, #ffbc3f 100%); |
|||
box-shadow: 0px 20px 30px rgba(221, 152, 55, 0.2); |
|||
border-radius: 53px; |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
font-family: 'font_bold'; |
|||
color: #ffffff; |
|||
} |
|||
} |
|||
.w-190 { |
|||
width: 190px; |
|||
} |
|||
.w-150 { |
|||
width: 150px; |
|||
} |
|||
.w-222 { |
|||
width: 222px; |
|||
} |
|||
} |
|||
.line { |
|||
&:after { |
|||
content: ''; |
|||
position: absolute; |
|||
right: 0; |
|||
height: 32px; |
|||
width: 1px; |
|||
border-right: 1px solid rgba(38, 36, 36, 0.1); |
|||
top: 50%; |
|||
transform: translateY(-50%); |
|||
} |
|||
} |
|||
} |
|||
.btn { |
|||
position: absolute; |
|||
right: 0; |
|||
top: -104px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,231 +0,0 @@ |
|||
<template> |
|||
<TransitionGroup name="width" mode="out-in" tag="div" class="plateinput-wrapper" :class="[searchMethods === '车位' ? 'active' : '']"> |
|||
<div |
|||
class="input" |
|||
v-for="(item, index) of renderInputLength" |
|||
:key="item" |
|||
:class="[index === license.length - 1 ? 'active' : '', searchMethods === '车位' ? 'space' : '']" |
|||
> |
|||
<span class="text">{{ license[index] }}</span> |
|||
</div> |
|||
<div |
|||
key="energy" |
|||
v-if="needsEnergy" |
|||
class="last input" |
|||
@click="handleEnergy" |
|||
:class="[_isEnergy ? 'enrgy' : '', _isEnergy && license.length === ENERGY_PLATE ? 'active' : '']" |
|||
> |
|||
<span class="text" v-if="!_isEnergy">新能源</span> |
|||
<span class="text" v-else>{{ _isEnergy ? (license.length === ENERGY_PLATE && license[license.length - 1]) || '' : '' }}</span> |
|||
</div> |
|||
<div key="btn" class="btn" @click="confirm"> |
|||
<img src="../../assets/images/parking/search-parking.png" class="icon" alt="" /> |
|||
</div> |
|||
</TransitionGroup> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed } from 'vue' |
|||
|
|||
const NOT_ENERGY_PLATE = 7 |
|||
const ENERGY_PLATE = 8 |
|||
|
|||
const props = defineProps({ |
|||
spaceMaxLength: { |
|||
type: Number, |
|||
default: 5 |
|||
}, |
|||
license: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
needsEnergy: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
searchMethods: { |
|||
type: String, |
|||
validator: status => ['车牌', '车位'].includes(status) |
|||
} |
|||
}) |
|||
|
|||
const renderInputLength = computed(() => (props.searchMethods === '车牌' ? NOT_ENERGY_PLATE : props.spaceMaxLength)) |
|||
|
|||
const emits = defineEmits(['handle-energy', 'confirm']) |
|||
const _isEnergy = ref(false) |
|||
emits('handle-energy', _isEnergy.value) |
|||
|
|||
function handleEnergy() { |
|||
_isEnergy.value = !_isEnergy.value |
|||
emits('handle-energy', _isEnergy.value) |
|||
} |
|||
|
|||
function confirm() { |
|||
emits('confirm') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.plateinput-wrapper { |
|||
display: flex; |
|||
position: relative; |
|||
margin-bottom: 32px; |
|||
margin-left: 170px; |
|||
&.active { |
|||
&::before { |
|||
left: 141px; |
|||
} |
|||
} |
|||
&::before { |
|||
content: ''; |
|||
position: absolute; |
|||
width: 2px; |
|||
height: 63px; |
|||
background: rgba(0, 0, 0, 0.1); |
|||
border-radius: 2px; |
|||
left: 176px; |
|||
top: 50%; |
|||
transform: translateY(-50%); |
|||
transition: left 0.5s; |
|||
} |
|||
} |
|||
.input { |
|||
position: relative; |
|||
border-radius: 8px; |
|||
width: 80px; |
|||
height: 100px; |
|||
margin-right: 8px; |
|||
font-weight: 700; |
|||
font-size: 32px; |
|||
line-height: 100px; |
|||
text-align: center; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
font-family: 'font_bold'; |
|||
background: #ffffff; |
|||
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.03); |
|||
border-radius: 8px; |
|||
&.space { |
|||
margin-right: 8px !important; |
|||
width: 132px; |
|||
&:first-child { |
|||
margin-right: 22px !important; |
|||
} |
|||
} |
|||
.text { |
|||
position: relative; |
|||
z-index: 3; |
|||
} |
|||
|
|||
&::after { |
|||
width: 80px; |
|||
height: 100px; |
|||
left: 0; |
|||
top: 0; |
|||
content: ''; |
|||
position: absolute; |
|||
background: #ffffff; |
|||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.03); |
|||
border-radius: 8px; |
|||
z-index: 2; |
|||
} |
|||
&.space { |
|||
&:nth-child(2) { |
|||
margin-right: 12px; |
|||
} |
|||
&::after { |
|||
width: 132px; |
|||
} |
|||
} |
|||
&.active { |
|||
&::before { |
|||
position: absolute; |
|||
content: ''; |
|||
top: -2px; |
|||
right: -2px; |
|||
bottom: -2px; |
|||
left: -2px; |
|||
background: var(--color-linear-lightgoldenyellow); |
|||
border-radius: 8px; |
|||
z-index: 1; |
|||
} |
|||
} |
|||
&:nth-child(2) { |
|||
margin-right: 18px; |
|||
} |
|||
} |
|||
|
|||
.last { |
|||
line-height: initial; |
|||
&.enrgy { |
|||
.text { |
|||
padding-top: 0; |
|||
font-weight: 700; |
|||
font-size: 32px; |
|||
line-height: 90px; |
|||
text-align: center; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
&::after { |
|||
background: #ffffff; |
|||
content: ''; |
|||
} |
|||
} |
|||
&::after { |
|||
content: '+'; |
|||
font-weight: 700; |
|||
font-size: 32px; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
line-height: 60px; |
|||
background: transparent; |
|||
} |
|||
.text { |
|||
width: 80px; |
|||
height: 100px; |
|||
display: inline-block; |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.4); |
|||
border: 2px solid #fff; |
|||
text-align: center; |
|||
border-radius: 8px; |
|||
padding-top: 51px; |
|||
} |
|||
} |
|||
|
|||
.btn { |
|||
position: absolute; |
|||
right: 40px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-left: 12px; |
|||
width: 156px; |
|||
height: 100px; |
|||
background: linear-gradient(90deg, #ffbd35 0%, #ffd260 100%); |
|||
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.03), inset 0px -4px 0px rgba(243, 176, 36, 0.5); |
|||
border-radius: 8px; |
|||
transition: all 0.5s; |
|||
|
|||
.icon { |
|||
width: 32px; |
|||
} |
|||
} |
|||
|
|||
.width-enter-active, |
|||
.width-leave-active { |
|||
width: 80px; |
|||
transition: all 0.5s; |
|||
transition-timing-function: cubic-bezier(0.75, 0, 0.24, 1); |
|||
} |
|||
|
|||
.width-enter-from, |
|||
.width-leave-to { |
|||
width: 0; |
|||
opacity: 0; |
|||
} |
|||
.width-move { |
|||
transition: transform 0.5s !important; |
|||
transition-timing-function: cubic-bezier(0.75, 0, 0.24, 1); |
|||
} |
|||
</style> |
|||
@ -1,91 +0,0 @@ |
|||
<template> |
|||
<div class="keyboard-wrapper"> |
|||
<div |
|||
class="keyboard-item" |
|||
@click="handleKeyboard(item, index)" |
|||
:class="[isUppercaseWord(item) ? 'uppercase' : '', item === 'del' ? 'del' : '', keyboardIdx === index ? 'active' : '', searchMethods === '车位' ? 'space' : '']" |
|||
v-for="(item, index) of list" |
|||
:key="item" |
|||
v-html="generateInnerHTML(item)" |
|||
></div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed } from 'vue' |
|||
import { keyboard } from './keyboard' |
|||
import { isUppercaseWord, isZhWord } from '@/utils/utils' |
|||
|
|||
const props = defineProps({ |
|||
searchMethods: { |
|||
type: String, |
|||
validator: status => ['车牌', '车位'].includes(status) |
|||
} |
|||
}) |
|||
|
|||
const list = computed(() => (props.searchMethods === '车位' ? keyboard.filter(item => !isZhWord(item)) : keyboard)) |
|||
|
|||
function generateInnerHTML(item) { |
|||
return item === 'del' ? `<img src="${require('@/assets/images/parking/del.svg')}" alt="">` : item |
|||
} |
|||
|
|||
const emits = defineEmits(['handle-keyboard', 'del']) |
|||
const keyboardIdx = ref(-1) |
|||
const keyboardTimer = ref(null) |
|||
function handleKeyboard(item, index) { |
|||
item === 'del' ? emits('del') : emits('handle-keyboard', item) |
|||
clearTimeout(keyboardTimer.value) |
|||
keyboardIdx.value = index |
|||
keyboardTimer.value = setTimeout(() => { |
|||
keyboardIdx.value = -1 |
|||
clearTimeout(keyboardTimer.value) |
|||
}, 300) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.keyboard-wrapper { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
margin-left: 170px; |
|||
margin-right: 32px; |
|||
margin-bottom: 56px; |
|||
.keyboard-item { |
|||
width: 41.76px; |
|||
height: 48px; |
|||
background: rgba(255, 255, 255, 0.6); |
|||
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.03), inset 0px -1px 0px rgba(177, 189, 220, 0.1); |
|||
border-radius: 6px; |
|||
text-align: center; |
|||
margin-right: 7px; |
|||
margin-bottom: 8px; |
|||
font-size: 18px; |
|||
font-family: 'font_medium'; |
|||
line-height: 48px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
&.space { |
|||
width: 90.48px; |
|||
&.del { |
|||
width: 187.92px; |
|||
} |
|||
} |
|||
&.uppercase { |
|||
background: #ffffff; |
|||
} |
|||
&.del { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 90px; |
|||
line-height: initial; |
|||
background: rgba(0, 0, 0, 0.05); |
|||
box-shadow: inset 0px -1px 0px rgba(0, 0, 0, 0.1); |
|||
} |
|||
&.active { |
|||
background: #f1b33e; |
|||
color: #fff; |
|||
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.03), inset 0px -1px 0px rgba(177, 189, 220, 0.1); |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,73 +0,0 @@ |
|||
export const keyboard = [ |
|||
'粤', |
|||
'京', |
|||
'津', |
|||
'渝', |
|||
'冀', |
|||
'豫', |
|||
'云', |
|||
'辽', |
|||
'黑', |
|||
'A', |
|||
'B', |
|||
'C', |
|||
'D', |
|||
'E', |
|||
'F', |
|||
1, |
|||
2, |
|||
3, |
|||
'湘', |
|||
'皖', |
|||
'鲁', |
|||
'苏', |
|||
'浙', |
|||
'赣', |
|||
'鄂', |
|||
'桂', |
|||
'甘', |
|||
'G', |
|||
'H', |
|||
'J', |
|||
'K', |
|||
'L', |
|||
'M', |
|||
4, |
|||
5, |
|||
6, |
|||
'晋', |
|||
'蒙', |
|||
'陕', |
|||
'吉', |
|||
'闽', |
|||
'贵', |
|||
'沪', |
|||
'青', |
|||
'藏', |
|||
'N', |
|||
'P', |
|||
'Q', |
|||
'R', |
|||
'S', |
|||
'T', |
|||
7, |
|||
8, |
|||
9, |
|||
'川', |
|||
'宁', |
|||
'琼', |
|||
'港', |
|||
'澳', |
|||
'新', |
|||
'使', |
|||
'领', |
|||
'警', |
|||
'U', |
|||
'V', |
|||
'W', |
|||
'X', |
|||
'Y', |
|||
'Z', |
|||
'0', |
|||
'del' |
|||
] |
|||
@ -1,91 +0,0 @@ |
|||
<template> |
|||
<div class="row"> |
|||
<div class="back" :style="{ backgroundImage: `url(${theme.images.back})` }" v-if="$route.path !== '/index'" @click="() => $router.push('/index')"></div> |
|||
<div class="bar" @click="handleSearch"> |
|||
<div class="icon" :style="{ backgroundImage: `url(${theme.images.searchIcon})` }"></div> |
|||
<div class="stick"></div> |
|||
<div class="placeholder">精确查询品牌/公共设施</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { useStore } from '@/store/root' |
|||
import { storeToRefs } from 'pinia' |
|||
const store = useStore() |
|||
const handleSearch = () => store.SET_SHOW_SEARCH(true) |
|||
const { theme } = storeToRefs(store) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
@media (max-aspect-ratio: 1/1) { |
|||
.row { |
|||
position: fixed; |
|||
top: 260px; |
|||
left: 68px; |
|||
right: 68px; |
|||
height: 100px; |
|||
display: flex; |
|||
z-index: 100; |
|||
} |
|||
} |
|||
.row { |
|||
.back { |
|||
width: 130px; |
|||
height: 100px; |
|||
margin-right: 40px; |
|||
background: center / cover no-repeat; |
|||
box-shadow: 0px 15px 24px rgba(0, 0, 0, 0.05); |
|||
border-radius: var(--searchBar-backBorderRadius); |
|||
} |
|||
.bar { |
|||
flex: 1; |
|||
height: 100px; |
|||
background: var(--searchBar-background); |
|||
border: var(--searchBar-border); |
|||
box-shadow: 0px 15px 24px rgba(0, 0, 0, 0.05); |
|||
border-radius: var(--searchBar-borderRadius); |
|||
display: flex; |
|||
padding-left: 40px; |
|||
align-items: center; |
|||
.icon { |
|||
width: 56px; |
|||
height: 56px; |
|||
background: center / cover no-repeat; |
|||
} |
|||
.stick { |
|||
width: 4px; |
|||
height: 38px; |
|||
background: var(--searchBar-stickBg); |
|||
margin: 0 32px; |
|||
} |
|||
.placeholder { |
|||
font-family: 'HarmonyOS Sans SC'; |
|||
font-style: normal; |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
line-height: 23px; |
|||
color: var(--searchBar-placeholderColor); |
|||
} |
|||
} |
|||
} |
|||
@media (min-aspect-ratio: 1/1) { |
|||
.row { |
|||
.back { |
|||
position: fixed; |
|||
left: 68px; |
|||
top: 161px; |
|||
z-index: 100; |
|||
} |
|||
.bar { |
|||
position: fixed; |
|||
width: 698px; |
|||
top: 38px; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
z-index: 100; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,142 +0,0 @@ |
|||
<template> |
|||
<div class="tabs" v-if="sidebarList.find(({ path }) => path === $route.path)"> |
|||
<div :class="['item', tab.path === $route.path ? 'active' : '']" v-for="tab of sidebarList" :key="tab.title" @click="goPage(tab)"> |
|||
<div class="icon"><img :src="theme.images[tab.moduleName]" /></div> |
|||
<div class="title">{{ switchLanguage(tab, 'title') }}</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { useStore } from '@/store/root' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useRouter } from 'vue-router' |
|||
const router = useRouter() |
|||
const store = useStore() |
|||
const { sidebarList, theme } = storeToRefs(store) |
|||
const goPage = item => { |
|||
store.SET_SELECTED_MODULE(item.title) |
|||
router.push(item.path) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.tabs { |
|||
position: fixed; |
|||
top: 400px; |
|||
left: 68px; |
|||
right: 68px; |
|||
display: flex; |
|||
.item:nth-child(5n + 1) { |
|||
&.active { |
|||
.icon { |
|||
background: var(--menu-activeBg1); |
|||
} |
|||
} |
|||
.icon { |
|||
background: var(--menu-bg1); |
|||
} |
|||
} |
|||
.item:nth-child(5n + 2) { |
|||
&.active { |
|||
.icon { |
|||
background: var(--menu-activeBg2); |
|||
} |
|||
} |
|||
.icon { |
|||
background: var(--menu-bg2); |
|||
} |
|||
} |
|||
.item:nth-child(5n + 3) { |
|||
&.active { |
|||
.icon { |
|||
background: var(--menu-activeBg3); |
|||
} |
|||
} |
|||
.icon { |
|||
background: var(--menu-bg3); |
|||
} |
|||
} |
|||
.item:nth-child(5n + 4) { |
|||
&.active { |
|||
.icon { |
|||
background: var(--menu-activeBg4); |
|||
} |
|||
} |
|||
.icon { |
|||
background: var(--menu-bg4); |
|||
} |
|||
} |
|||
.item:nth-child(5n + 5) { |
|||
&.active { |
|||
.icon { |
|||
background: var(--menu-activeBg5); |
|||
} |
|||
} |
|||
.icon { |
|||
background: var(--menu-bg5); |
|||
} |
|||
} |
|||
.item { |
|||
position: relative; |
|||
display: flex; |
|||
flex-direction: column; |
|||
flex: 1; |
|||
height: 170px; |
|||
.icon { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 97px; |
|||
background: rgba(255, 255, 255, 0.4); |
|||
border-radius: var(--global-radius, 24px); |
|||
img { |
|||
width: 80px; |
|||
height: 80px; |
|||
} |
|||
} |
|||
.title { |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
line-height: 21px; |
|||
text-align: center; |
|||
color: var(--menu-color); |
|||
margin-top: 12px; |
|||
} |
|||
&.active { |
|||
.title { |
|||
color: var(--menu-activeColor); |
|||
} |
|||
&::after { |
|||
content: ''; |
|||
display: block; |
|||
position: absolute; |
|||
width: 124px; |
|||
height: 6px; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
margin: auto; |
|||
background: var(--menu-barBg); |
|||
border-radius: 2px 2px 0px 0px; |
|||
} |
|||
} |
|||
} |
|||
.item + .item { |
|||
margin-left: 24px; |
|||
} |
|||
} |
|||
@media (min-aspect-ratio: 1/1) { |
|||
.tabs { |
|||
top: 156px; |
|||
left: 456px; |
|||
right: 456px; |
|||
.item { |
|||
height: 124px; |
|||
.icon { |
|||
height: 80px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,92 +0,0 @@ |
|||
<template> |
|||
<div class="full-code"> |
|||
<div class="code-wrapper"> |
|||
<img :src="icon" class="img" alt="" v-if="icon.length" /> |
|||
<img src="../../assets/images/nodata.svg" class="img nodata" alt="" v-else /> |
|||
|
|||
<p class="youhui" v-if="icon.length">{{ title }}</p> |
|||
<slot /> |
|||
<div class="close" @click="handleClose"> |
|||
<img src="../../assets/images/detail/yellow_close.png" alt="" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
defineProps({ |
|||
title: { |
|||
type: String, |
|||
default: '扫码排队' |
|||
}, |
|||
icon: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}) |
|||
const emits = defineEmits(['close']) |
|||
|
|||
function handleClose() { |
|||
emits('close') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.full-code { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 10; |
|||
animation-duration: 0.2s; |
|||
} |
|||
.code-wrapper { |
|||
position: absolute; |
|||
top: 50%; |
|||
left: 50%; |
|||
width: 480px; |
|||
min-height: 366px; |
|||
transform: translate3d(-50%, -50%, 0); |
|||
background: #ffffff; |
|||
box-shadow: 0 40px 60px rgba(0, 0, 0, 0.08); |
|||
border-radius: 12px; |
|||
padding-top: 80px; |
|||
z-index: 10; |
|||
.img { |
|||
display: block; |
|||
margin: 0 auto 49px; |
|||
width: 150px; |
|||
height: 150px; |
|||
&.nodata { |
|||
width: 300px; |
|||
height: 300px; |
|||
} |
|||
} |
|||
.youhui { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 20px; |
|||
line-height: 23px; |
|||
text-align: center; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
|
|||
.close { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 12px; |
|||
right: 12px; |
|||
width: 56px; |
|||
height: 56px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
img { |
|||
width: 56px; |
|||
height: 56px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,125 +0,0 @@ |
|||
<template> |
|||
<div class="question-content"> |
|||
<div class="masker" @click="closeQuestionClassify"></div> |
|||
<div class="question-detail"> |
|||
<h1 class="title">商场相关常见问题</h1> |
|||
<h1 class="sub">全部分类</h1> |
|||
<ScrollView class="question-scroll" scrollbar> |
|||
<div class="scroll"> |
|||
<QuestionList /> |
|||
</div> |
|||
</ScrollView> |
|||
<div class="close" @click="closeQuestionClassify"> |
|||
<img src="../../assets/images/detail/yellow_close.png" alt="" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import QuestionList from '@/components/QuestionList/QuestionList.vue' |
|||
|
|||
const emits = defineEmits(['close']) |
|||
|
|||
function closeQuestionClassify() { |
|||
emits('close') |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.question-content { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 999; |
|||
animation-duration: 0.2s; |
|||
} |
|||
.masker { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
} |
|||
|
|||
.question-detail { |
|||
position: absolute; |
|||
width: 854px; |
|||
height: 964px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 40px 60px rgba(0, 0, 0, 0.08); |
|||
border-radius: 16px; |
|||
top: 462px; |
|||
left: 50%; |
|||
margin-left: -427px; |
|||
.title { |
|||
font-weight: 700; |
|||
font-size: 32px; |
|||
font-family: 'font_bold'; |
|||
text-align: center; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
padding-bottom: 40px; |
|||
padding-top: 56px; |
|||
} |
|||
.sub { |
|||
text-align: center; |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
margin-bottom: 24px; |
|||
} |
|||
.question-scroll { |
|||
position: relative; |
|||
padding-right: 16px; |
|||
overflow: hidden; |
|||
height: 788px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
.scroll { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
padding: 80px 80px 0 117px; |
|||
:deep(.question_item) { |
|||
margin-right: 16px; |
|||
margin-bottom: 40px; |
|||
} |
|||
} |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 6px !important; |
|||
right: 95px !important; |
|||
top: 80px !important; |
|||
background: rgba(0, 0, 0, 0.02) !important; |
|||
border-radius: 6px !important; |
|||
opacity: 1 !important; |
|||
height: 152px !important; |
|||
|
|||
.bscroll-indicator { |
|||
height: 95px !important; |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.1) !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.close { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 12px; |
|||
right: 12px; |
|||
width: 56px; |
|||
height: 56px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
img { |
|||
width: 56px; |
|||
height: 56px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,193 +0,0 @@ |
|||
<template> |
|||
<div class="question_item" @click="handleQuestion"> |
|||
<h1 class="prefix_title">停车相关</h1> |
|||
<h1 class="prefix_sub">如:停车如何收费</h1> |
|||
<p class="prefix_detail">MORE</p> |
|||
</div> |
|||
|
|||
<Teleport to="body"> |
|||
<Transition enter-active-class="animate__animated animate__fadeInDown" leave-active-class="animate__animated animate__fadeOutUp"> |
|||
<div class="question-content" v-if="showQuestion"> |
|||
<div class="masker" @click="closeQuestionDetail"></div> |
|||
<div class="question-detail"> |
|||
<h1 class="title">商场相关常见问题</h1> |
|||
<h1 class="sub">停车相关</h1> |
|||
<ScrollView class="question-scroll" scrollbar> |
|||
<div class="questions"> |
|||
<div class="question" v-for="item of 10" :key="item"> |
|||
<div class="ask">问:停车如何收费?</div> |
|||
<div class="answer"> |
|||
答:迪奥小姐仿佛一曲爱之赞歌,承袭Christian |
|||
Dior迪奥先生心中的玫瑰挚恋及DIOR迪奥的高订格调,曼妙香韵,尽现摩登时尚、自由洒脱、优雅从容的风格。迪奥小姐玫舞轻旋淡香水,活力花香调。 |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
<div class="close" @click="closeQuestionDetail"> |
|||
<img src="../../assets/images/detail/yellow_close.png" alt="" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</Transition> |
|||
</Teleport> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
|
|||
defineProps({ |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}) |
|||
|
|||
const showQuestion = ref(false) |
|||
function handleQuestion() { |
|||
showQuestion.value = true |
|||
} |
|||
function closeQuestionDetail() { |
|||
showQuestion.value = false |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.question_item { |
|||
width: 175px; |
|||
height: 225px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 20px 40px rgba(31, 46, 84, 0.04); |
|||
border-radius: 12px; |
|||
.prefix_title { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
font-family: 'font_bold'; |
|||
padding: 32px 20px 15px 32px; |
|||
@include no-wrap; |
|||
} |
|||
.prefix_sub { |
|||
font-size: 14px; |
|||
padding: 0 20px 75px 32px; |
|||
border-bottom: 1px solid rgba(0, 0, 0, 0.05); |
|||
color: rgba(0, 0, 0, 0.6); |
|||
@include no-wrap; |
|||
} |
|||
.prefix_detail { |
|||
padding-top: 23px; |
|||
font-family: 'font_bold'; |
|||
padding-left: 32px; |
|||
font-weight: 700; |
|||
font-size: 16px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
} |
|||
|
|||
.question-content { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 999; |
|||
animation-duration: 0.2s; |
|||
} |
|||
.masker { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
} |
|||
|
|||
.question-detail { |
|||
position: absolute; |
|||
width: 854px; |
|||
height: 964px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 40px 60px rgba(0, 0, 0, 0.08); |
|||
border-radius: 16px; |
|||
top: 462px; |
|||
left: 50%; |
|||
margin-left: -427px; |
|||
.title { |
|||
font-weight: 700; |
|||
font-size: 32px; |
|||
font-family: 'font_bold'; |
|||
text-align: center; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
padding-bottom: 40px; |
|||
padding-top: 56px; |
|||
} |
|||
.sub { |
|||
text-align: center; |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
margin-bottom: 24px; |
|||
} |
|||
.question-scroll { |
|||
position: relative; |
|||
margin-left: 56px; |
|||
margin-right: 34px; |
|||
padding-right: 16px; |
|||
overflow: hidden; |
|||
height: 788px; |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.02) !important; |
|||
border-radius: 6px !important; |
|||
opacity: 1 !important; |
|||
height: 152px !important; |
|||
|
|||
.bscroll-indicator { |
|||
height: 95px !important; |
|||
width: 6px !important; |
|||
background: rgba(0, 0, 0, 0.1) !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
.questions { |
|||
padding-bottom: 24px; |
|||
} |
|||
.question { |
|||
margin-bottom: 24px; |
|||
padding: 40px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
} |
|||
.ask { |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
margin-bottom: 16px; |
|||
} |
|||
.answer { |
|||
font-size: 16px; |
|||
line-height: 200%; |
|||
text-align: justify; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
} |
|||
} |
|||
.close { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 12px; |
|||
right: 12px; |
|||
width: 56px; |
|||
height: 56px; |
|||
background: rgba(0, 0, 0, 0.02); |
|||
border-radius: 12px; |
|||
img { |
|||
width: 56px; |
|||
height: 56px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,396 +0,0 @@ |
|||
<template> |
|||
<Dialog @close="close"> |
|||
<div class="bar"> |
|||
<div class="icon" :style="{ backgroundImage: `url(${theme.images.searchIcon})` }"></div> |
|||
<div class="stick"></div> |
|||
<div v-if="!keywords" class="placeholder">请输入中英文<span class="meta">首字母</span>查询,例如 XBK (星巴克)</div> |
|||
<input v-else @click="setSearch" v-model="keywords" type="text" readonly class="input" /> |
|||
<img :src="theme.images.searchClear" class="clear" v-if="keywords" @click="clear" /> |
|||
</div> |
|||
<div class="search-content"> |
|||
<div class="top" v-if="!showVoice"> |
|||
<div class="facs"> |
|||
<h1 class="title">公共设施</h1> |
|||
<div class="facility-list"> |
|||
<FacilityItem @click="_handleFacility(item)" class="margin" :facility="item" v-for="item of facilityList" :key="item.title" /> |
|||
</div> |
|||
</div> |
|||
<div class="keyboard-wrapper"> |
|||
<div class="tabs tabs-wrapper"> |
|||
<div class="tab" :class="{ active: tabIdx === index }" @click="handleTab(index)" v-for="(item, index) of list" :key="item.name"> |
|||
<img :src="tabIdx === index ? item.iconActive : item.icon" alt="" /> |
|||
{{ item.name }} |
|||
</div> |
|||
</div> |
|||
<KeyboardByLetter @del="del" @handle-letter="handleLetter" v-if="tabIdx === 0" /> |
|||
<KeyboardByWritten @del="del" @handle-word="handleLetter" v-else /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="recs" v-show="!keywords.length && !showVoice"> |
|||
<h1 class="title">大家都在找</h1> |
|||
<div class="hot-scroll"> |
|||
<div class="item" v-for="(item, i) of hotRecommend" :key="item.shopId" @click="handleShop(item)"> |
|||
<div class="text">{{ item.shopName }}</div> |
|||
<img class="medal" v-if="i === 0" src="@/views/Index/fir.svg" /> |
|||
<img class="medal" v-if="i === 1" src="@/views/Index/sec.svg" /> |
|||
<img class="medal" v-if="i === 2" src="@/views/Index/thi.svg" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<SearchResultList @handle-shop="handleShop" :list="searchShopListRef" :config="config" v-if="keywords.length && !showVoice" /> |
|||
|
|||
<Voice @handle-question="showClassify = true" v-if="showVoice" /> |
|||
</div> |
|||
<img :src="theme.images.searchClose" class="search-btn" @click="close" /> |
|||
</Dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed, defineAsyncComponent, ref, onBeforeUnmount } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
|
|||
import { useSearchShop } from '@/composables/useSearchShop' |
|||
import { useFacilityNav } from '@/composables/useFacilityNav' |
|||
import { useStatistics } from '@/composables/useStatistics' |
|||
import Dialog from '@/layouts/Dialog.vue' |
|||
import FacilityItem from '@/base/FacilityItem/FacilityItem.vue' |
|||
import SearchResultList from '@/components/SearchResultList/SearchResultList.vue' |
|||
|
|||
const KeyboardByLetter = defineAsyncComponent(() => import('@/components/KeyboardByLetter/KeyboardByLetter.vue')) |
|||
const KeyboardByWritten = defineAsyncComponent(() => import('@/components/KeyboardByWritten/KeyboardByWritten.vue')) |
|||
const Voice = defineAsyncComponent(() => import('@/components/Voice/Voice.vue')) |
|||
|
|||
const MAX_LENGTH = 7 |
|||
|
|||
const { _handleFacility } = useFacilityNav() |
|||
|
|||
const router = useRouter() |
|||
|
|||
const store = useStore() |
|||
const { indexList, shopList, facilityList, config, showVoice, theme } = storeToRefs(store) |
|||
|
|||
const list = computed(() => |
|||
theme.value |
|||
? [ |
|||
{ |
|||
name: '键盘输入', |
|||
nameEn: 'keyboard input', |
|||
icon: theme.value.images.keyboard, |
|||
iconActive: theme.value.images.keyboard_active |
|||
}, |
|||
{ |
|||
name: '手写输入', |
|||
nameEn: 'handwriting input', |
|||
icon: theme.value.images.write, |
|||
iconActive: theme.value.images.write_active |
|||
} |
|||
] |
|||
: [] |
|||
) |
|||
|
|||
const hotRecommend = computed(() => indexList.value.hotSearch ?? []) |
|||
const showClassify = ref(false) |
|||
|
|||
async function handleShop(item) { |
|||
useStatistics('brandSearch') |
|||
const shop = shopList.value.find(_shop => _shop.shopId === item.shopId) |
|||
store.SET_SHOP(shop) |
|||
if (router.currentRoute.value.fullPath !== '/guide') { |
|||
store.SET_SELECTED_MODULE('Guide') |
|||
await router.push('/guide') |
|||
} |
|||
store.SET_SHOW_SEARCH(false) |
|||
} |
|||
|
|||
const tabIdx = ref(0) |
|||
function handleTab(index) { |
|||
tabIdx.value = index |
|||
} |
|||
|
|||
const keywords = ref('') |
|||
const searchType = ref(0) //0: 键盘 1: 手写 |
|||
const { searchShopListRef } = useSearchShop(keywords, searchType) |
|||
function handleLetter(item) { |
|||
if (keywords.value.length >= MAX_LENGTH) return |
|||
keywords.value += item |
|||
} |
|||
function del() { |
|||
keywords.value = keywords.value.substring(0, keywords.value.length - 1) |
|||
} |
|||
const clear = () => { |
|||
keywords.value = '' |
|||
} |
|||
|
|||
function setSearch() { |
|||
showVoice.value && store.SET_SHOW_VOICE(false) |
|||
} |
|||
|
|||
function close() { |
|||
store.SET_SHOW_SEARCH(false) |
|||
} |
|||
|
|||
onBeforeUnmount(() => { |
|||
showVoice.value && store.SET_SHOW_VOICE(false) |
|||
}) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
:deep(.header-left) { |
|||
padding-left: 80px; |
|||
} |
|||
:deep(.view-container) { |
|||
position: relative; |
|||
z-index: 50; |
|||
} |
|||
.bar { |
|||
position: fixed; |
|||
top: 260px; |
|||
left: 68px; |
|||
right: 68px; |
|||
background: var(--search-barBackground); |
|||
border: var(--searchBar-border); |
|||
box-shadow: 0px 15px 24px rgba(0, 0, 0, 0.05); |
|||
border-radius: var(--searchBar-borderRadius); |
|||
display: flex; |
|||
align-items: center; |
|||
padding-right: 10px; |
|||
padding-left: 40px; |
|||
height: 100px; |
|||
z-index: 52; |
|||
.icon { |
|||
width: 56px; |
|||
height: 56px; |
|||
background: center / cover no-repeat; |
|||
} |
|||
.stick { |
|||
width: 4px; |
|||
height: 38px; |
|||
background: var(--searchBar-stickBg); |
|||
margin: 0 32px; |
|||
} |
|||
.placeholder { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
line-height: 23px; |
|||
color: var(--searchBar-placeholderColor); |
|||
.meta { |
|||
color: var(--search-placeholderMetaColor); |
|||
} |
|||
} |
|||
.input { |
|||
flex: 1; |
|||
border: none; |
|||
outline: none; |
|||
width: 262px; |
|||
background: transparent; |
|||
font-weight: 700; |
|||
font-size: 48px; |
|||
line-height: 59px; |
|||
color: var(--searchBar-color); |
|||
} |
|||
.clear { |
|||
display: flex; |
|||
width: 80px; |
|||
height: 80px; |
|||
} |
|||
.voice-icon { |
|||
width: 190px; |
|||
} |
|||
} |
|||
.search-content { |
|||
position: absolute; |
|||
top: 315px; |
|||
right: 40px; |
|||
bottom: 302px; |
|||
left: 40px; |
|||
background: var(--search-background); |
|||
backdrop-filter: blur(10px); |
|||
border-radius: var(--searchBar-borderRadius); |
|||
z-index: 2; |
|||
overflow: hidden; |
|||
|
|||
.top { |
|||
height: 460px; |
|||
background: var(--search-topBg, rgba(255, 255, 255, 0.6)); |
|||
border-radius: var(--searchBar-borderRadius); |
|||
margin: 10px 10px 48px 10px; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding-left: 46px; |
|||
overflow: hidden; |
|||
.facs { |
|||
.title { |
|||
font-weight: 900; |
|||
font-size: 24px; |
|||
line-height: 28px; |
|||
color: var(--search-facTitleColor); |
|||
} |
|||
width: 300px; |
|||
padding-top: 111px; |
|||
.facility-list { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr 1fr 1fr; |
|||
width: 264px; |
|||
margin-top: 40px; |
|||
gap: 12px 24px; |
|||
} |
|||
} |
|||
.tabs-wrapper { |
|||
display: flex; |
|||
width: 100%; |
|||
height: 64px; |
|||
background: var(--search-tabsBg, rgba(0, 0, 0, 0.05)); |
|||
border-radius: var(--global-radius, 12px); |
|||
overflow: hidden; |
|||
|
|||
.tab { |
|||
height: 100%; |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
color: var(--search-tabColor, rgba(0, 0, 0, 0.6)); |
|||
border-radius: var(--global-radius, 12px); |
|||
&.active { |
|||
background: var(--search-tabActiveBg, #ffffff); |
|||
color: var(--search-tabActiveColor, rgba(0, 0, 0, 0.8)); |
|||
} |
|||
} |
|||
|
|||
img { |
|||
width: 24px; |
|||
height: 24px; |
|||
margin-right: 12px; |
|||
} |
|||
} |
|||
.keyboard-wrapper { |
|||
flex: 1; |
|||
padding-top: 75px; |
|||
padding-left: 36px; |
|||
background: rgba(0, 0, 0, 0.05); |
|||
padding-right: 38px; |
|||
.tabs { |
|||
padding-right: 8px; |
|||
} |
|||
} |
|||
} |
|||
.recs { |
|||
padding-left: 56px; |
|||
.title { |
|||
color: var(--search-hotSearchTitleColor); |
|||
} |
|||
.hot-scroll { |
|||
padding-top: 16px; |
|||
white-space: nowrap; |
|||
width: 944px; |
|||
|
|||
.item { |
|||
position: relative; |
|||
display: inline-block; |
|||
max-width: 170px; |
|||
height: 52px; |
|||
background: var(--search-hotSearchBg); |
|||
border-radius: var(--global-radius, 100px); |
|||
.text { |
|||
text-align: center; |
|||
font-weight: 900; |
|||
font-size: 16px; |
|||
line-height: 52px; |
|||
color: var(--search-hotSearchColor); |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
padding: 0 32px; |
|||
} |
|||
.medal { |
|||
position: absolute; |
|||
width: 32px; |
|||
height: 32px; |
|||
left: 4px; |
|||
top: -10px; |
|||
} |
|||
} |
|||
.item + .item { |
|||
margin-left: 24px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.search-right { |
|||
position: relative; |
|||
background: rgba(255, 255, 255, 0.6); |
|||
padding-top: 180px; |
|||
padding-left: 64px; |
|||
width: 696px; |
|||
|
|||
.title, |
|||
.title-en { |
|||
margin-right: 76px; |
|||
} |
|||
} |
|||
.search-btn { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
position: fixed; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
bottom: 242px; |
|||
width: 120px; |
|||
height: 120px; |
|||
z-index: 52; |
|||
} |
|||
@media (min-aspect-ratio: 1/1) { |
|||
.search-content { |
|||
top: 87px; |
|||
right: 125px; |
|||
bottom: 87px; |
|||
left: 125px; |
|||
padding: 100px 670px 0 0; |
|||
.top { |
|||
position: absolute; |
|||
top: 10px; |
|||
right: 10px; |
|||
bottom: 10px; |
|||
width: 660px; |
|||
height: auto; |
|||
margin: 0; |
|||
padding-left: 0; |
|||
flex-direction: column; |
|||
.facs { |
|||
width: auto; |
|||
flex: 1; |
|||
padding-top: 90px; |
|||
padding: 90px 54px; |
|||
.facility-list { |
|||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; |
|||
} |
|||
} |
|||
.keyboard-wrapper { |
|||
flex: 0 0 456px; |
|||
} |
|||
} |
|||
} |
|||
.bar { |
|||
top: 32px; |
|||
width: 698px; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
} |
|||
.search-btn { |
|||
left: auto; |
|||
bottom: auto; |
|||
right: 145px; |
|||
top: 107px; |
|||
width: 87px; |
|||
height: 87px; |
|||
} |
|||
} |
|||
</style> |
|||
|
Before Width: | Height: | Size: 760 B |
|
Before Width: | Height: | Size: 5.2 KiB |
@ -1,40 +0,0 @@ |
|||
export const letter = [ |
|||
1, |
|||
2, |
|||
3, |
|||
4, |
|||
5, |
|||
6, |
|||
7, |
|||
8, |
|||
9, |
|||
0, |
|||
'Q', |
|||
'W', |
|||
'E', |
|||
'R', |
|||
'T', |
|||
'Y', |
|||
'U', |
|||
'I', |
|||
'O', |
|||
'P', |
|||
'A', |
|||
'S', |
|||
'D', |
|||
'F', |
|||
'G', |
|||
'H', |
|||
'J', |
|||
'K', |
|||
'L', |
|||
'Z', |
|||
'X', |
|||
'C', |
|||
'V', |
|||
'B', |
|||
'N', |
|||
'M', |
|||
'空格', |
|||
'del' |
|||
] |
|||
@ -1,84 +0,0 @@ |
|||
<template> |
|||
<div class="item" @click="handleShop"> |
|||
<div class="icon-wrapper"> |
|||
<img :src="config.sourceUrl + shop.logoUrl" class="icon" alt="" /> |
|||
</div> |
|||
<div class="item-bottom"> |
|||
<div class="left">{{ switchLanguage(shop, 'shopName') }}</div> |
|||
|
|||
<div class="right">{{ shop.floor }}</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
const props = defineProps({ |
|||
shop: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
}, |
|||
config: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
} |
|||
}) |
|||
|
|||
const emits = defineEmits(['click']) |
|||
function handleShop() { |
|||
emits('click', props.shop) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.item { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
width: 210px; |
|||
height: 200px; |
|||
background: var(--brand-background); |
|||
border-radius: var(--global-radius, 8px); |
|||
margin-right: 8px; |
|||
margin-top: 24px; |
|||
.icon-wrapper { |
|||
display: flex; |
|||
width: 210px; |
|||
height: 160px; |
|||
background: #ffffff; |
|||
border-radius: var(--global-radius, 8px); |
|||
justify-content: center; |
|||
align-items: center; |
|||
.icon { |
|||
width: 120px; |
|||
height: 120px; |
|||
object-fit: contain; |
|||
} |
|||
} |
|||
.item-bottom { |
|||
display: flex; |
|||
width: 100%; |
|||
flex: 1; |
|||
padding: 0 12px; |
|||
align-items: center; |
|||
|
|||
.left, |
|||
.right { |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
line-height: 16px; |
|||
} |
|||
.left { |
|||
flex: 1; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
color: var(--brand-color); |
|||
} |
|||
.right { |
|||
width: 40px; |
|||
text-align: right; |
|||
color: var(--brand-metaColor); |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,140 +0,0 @@ |
|||
<template> |
|||
<ScrollView :list="list" class="search-result-scroll" :scrollbar="true"> |
|||
<div class="scroll-result"> |
|||
<h1 class="title"> |
|||
搜索结果 <span class="meta">/ {{ list.length }}</span> |
|||
</h1> |
|||
<TransitionGroup name="zoom" tag="div" class="list"> |
|||
<SearchResultItem :config="config" @click="handleShop" :shop="item" v-for="item of list" :key="item.shopId" /> |
|||
</TransitionGroup> |
|||
</div> |
|||
</ScrollView> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import SearchResultItem from '@/components/SearchResultItem/SearchResultItem.vue' |
|||
defineProps({ |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
config: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
} |
|||
}) |
|||
const emits = defineEmits(['handle-shop']) |
|||
|
|||
function handleShop(item) { |
|||
emits('handle-shop', item) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.search-result-scroll { |
|||
position: relative; |
|||
height: 842px; |
|||
overflow: hidden; |
|||
margin-left: 68px; |
|||
margin-right: 7px; |
|||
.scroll-result { |
|||
padding-bottom: 200px; |
|||
} |
|||
|
|||
.list { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
margin-bottom: 44px; |
|||
} |
|||
.activity { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
.flex { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: space-between; |
|||
} |
|||
.pl-24 { |
|||
padding-left: 24px; |
|||
} |
|||
.activity-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 0 8px; |
|||
|
|||
width: 457px; |
|||
height: 84px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 12px; |
|||
margin-right: 6px; |
|||
margin-bottom: 8px; |
|||
.activity-name { |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
font-family: 'font_bold'; |
|||
padding-bottom: 16px; |
|||
} |
|||
.intro { |
|||
color: rgba(0, 0, 0, 0.6); |
|||
font-size: 14px; |
|||
} |
|||
.img-wrapper { |
|||
width: 120px; |
|||
height: 68px; |
|||
margin-right: 24px; |
|||
border-radius: 8px; |
|||
|
|||
.img { |
|||
width: 100%; |
|||
height: 100%; |
|||
border-radius: 8px; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.title { |
|||
font-style: normal; |
|||
font-weight: 900; |
|||
font-size: 24px; |
|||
line-height: 28px; |
|||
color: var(--search-resultTitleColor, rgba(0, 0, 0, 0.8)); |
|||
.meta { |
|||
font-weight: 500; |
|||
font-size: 20px; |
|||
line-height: 23px; |
|||
color: var(--search-resultMetaColor, rgba(0, 0, 0, 0.6)); |
|||
} |
|||
} |
|||
:deep(.bscroll-vertical-scrollbar) { |
|||
width: 48px !important; |
|||
background: center / 6px 250px no-repeat url(@/assets/images/scrollBar.png); |
|||
border-radius: 6px; |
|||
opacity: 1 !important; |
|||
height: 250px !important; |
|||
&::after { |
|||
position: absolute; |
|||
content: ''; |
|||
left: 0; |
|||
|
|||
top: 120px; |
|||
margin: auto; |
|||
width: 48px; |
|||
height: 61px; |
|||
background: center / cover no-repeat url(@/assets/images/scrollHand.png); |
|||
} |
|||
.bscroll-indicator { |
|||
height: 95px !important; |
|||
width: 6px !important; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
background: #ffffff !important; |
|||
border-radius: 6px !important; |
|||
border: none !important; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,86 +0,0 @@ |
|||
<template> |
|||
<ScrollView class="serve-scroll" :list="serveList"> |
|||
<TransitionGroup name="zoom" tag="div" class="serve-content"> |
|||
<div class="serve-item" v-for="item of serveList" :key="item.name"> |
|||
<div class="white-bg"> |
|||
<div class="icon-box"> |
|||
<img class="icon" :src="config.sourceUrl + item.fileUrl" alt="" /> |
|||
</div> |
|||
</div> |
|||
<p class="name">{{ item.name }}</p> |
|||
<p class="en">{{ item.nameEn }}</p> |
|||
</div> |
|||
</TransitionGroup> |
|||
</ScrollView> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
import { getServeList } from '@/http/api' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
|
|||
const store = useStore() |
|||
const { config } = storeToRefs(store) |
|||
|
|||
const serveList = ref([]) |
|||
getServeList().then(({ data }) => { |
|||
serveList.value = data?.serveList ?? [] |
|||
}) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.serve-scroll { |
|||
position: relative; |
|||
overflow: hidden; |
|||
margin-left: 170px; |
|||
margin-right: 24px; |
|||
margin-top: 58px; |
|||
height: 1560px; |
|||
.serve-content { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
.serve-item { |
|||
width: 279px; |
|||
height: 225px; |
|||
// TODO 需动态切换背景色 |
|||
background: #fcf8ec; |
|||
box-shadow: 0px 20px 40px rgba(31, 46, 84, 0.04); |
|||
border-radius: 12px; |
|||
margin-right: 16px; |
|||
margin-bottom: 29px; |
|||
.white-bg { |
|||
height: 147px; |
|||
background: #fff; |
|||
border-radius: 12px; |
|||
padding: 32px; |
|||
margin-bottom: 20px; |
|||
} |
|||
.icon-box { |
|||
width: 56px; |
|||
height: 56px; |
|||
.icon { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: contain; |
|||
} |
|||
} |
|||
.name { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 16px; |
|||
padding-left: 32px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-bottom: 6px; |
|||
} |
|||
.en { |
|||
font-weight: 400; |
|||
font-size: 12px; |
|||
padding-left: 32px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,104 +0,0 @@ |
|||
<template> |
|||
<div class="sidebar-wrapper"> |
|||
<div class="menu-list" @click="goPage(item)" :class="{ active: selectedModule === item.title }" v-for="item of sidebarList" :key="item.title"> |
|||
<img :src="item.icon" alt="" /> |
|||
<span class="text">{{ item.title }}</span> |
|||
<span class="text-en">{{ item.titleEn }}</span> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
import { useRouter } from 'vue-router' |
|||
|
|||
const router = useRouter() |
|||
const store = useStore() |
|||
const { sidebarList, selectedModule } = storeToRefs(store) |
|||
|
|||
function goPage(item) { |
|||
store.SET_SELECTED_MODULE(item.title) |
|||
router.push(item.path) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.sidebar-wrapper { |
|||
position: fixed; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
width: 130px; |
|||
height: 1920px; |
|||
left: 0px; |
|||
top: 0; |
|||
background: var(--color-white-opacity-8); |
|||
box-shadow: var(--shadow-seven); |
|||
backdrop-filter: blur(20px); |
|||
z-index: 50; |
|||
|
|||
.menu-list { |
|||
position: relative; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
width: 110px; |
|||
height: 140px; |
|||
margin-bottom: 10px; |
|||
|
|||
&::before, |
|||
&::after { |
|||
position: absolute; |
|||
content: ''; |
|||
width: 110px; |
|||
height: 140px; |
|||
left: 0; |
|||
bottom: 0; |
|||
border-radius: 8px; |
|||
transition: bottom 0.5s; |
|||
} |
|||
|
|||
&.active { |
|||
&::before { |
|||
background-color: #fff; |
|||
z-index: 3; |
|||
bottom: 4px; |
|||
} |
|||
|
|||
&::after { |
|||
background: var(--color-linear-lightgoldenyellow); |
|||
z-index: 2; |
|||
bottom: 0; |
|||
height: 136px; |
|||
} |
|||
} |
|||
|
|||
img { |
|||
position: relative; |
|||
width: 80px; |
|||
height: 80px; |
|||
z-index: 10; |
|||
} |
|||
|
|||
.text { |
|||
position: relative; |
|||
z-index: 10; |
|||
color: var(--color-black-opacity-6); |
|||
font-family: 'font_bold'; |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
padding: 4px 0; |
|||
} |
|||
|
|||
.text-en { |
|||
position: relative; |
|||
z-index: 10; |
|||
color: var(--color-black-opacity-4); |
|||
font-size: 12px; |
|||
transform: scale(0.83); |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,72 +0,0 @@ |
|||
export const sidebarList = [ |
|||
{ |
|||
icon: require('@/assets/images/sidebar/activity.png'), |
|||
title: '商场活动', |
|||
moduleName: 'activity', |
|||
titleEn: 'SELECTION', |
|||
path: '/activity' |
|||
}, |
|||
{ |
|||
icon: require('@/assets/images/sidebar/member.png'), |
|||
title: '尊享会员', |
|||
moduleName: 'member', |
|||
titleEn: 'MEMBER', |
|||
path: '/member' |
|||
}, |
|||
{ |
|||
icon: require('@/assets/images/sidebar/parking.png'), |
|||
title: '泊车缴费', |
|||
moduleName: 'parking', |
|||
titleEn: 'PARKING', |
|||
path: '/parking' |
|||
}, |
|||
{ |
|||
icon: require('@/assets/images/sidebar/movie.png'), |
|||
title: '影视天地', |
|||
moduleName: 'movie', |
|||
titleEn: 'MOVIE', |
|||
path: '/movie' |
|||
}, |
|||
{ |
|||
icon: require('@/assets/images/sidebar/mall.png'), |
|||
title: '商场介绍', |
|||
moduleName: 'mall', |
|||
titleEn: 'MALL', |
|||
path: '/mall' |
|||
} |
|||
// {
|
|||
// icon: require('@/assets/images/sidebar/index.png'),
|
|||
// title: '首页',
|
|||
// moduleName: 'home',
|
|||
// titleEn: 'HOME',
|
|||
// path: '/'
|
|||
// },
|
|||
// {
|
|||
// icon: require('@/assets/images/sidebar/guide.png'),
|
|||
// title: '地图导览',
|
|||
// moduleName: 'home',
|
|||
// titleEn: 'MAP',
|
|||
// path: '/guide'
|
|||
// },
|
|||
// {
|
|||
// icon: require('@/assets/images/sidebar/brand.png'),
|
|||
// title: '品牌列表',
|
|||
// moduleName: 'brand',
|
|||
// titleEn: 'BRAND',
|
|||
// path: '/brand'
|
|||
// }
|
|||
// {
|
|||
// icon: require('@/assets/images/sidebar/foods.png'),
|
|||
// title: '特色美食',
|
|||
// moduleName: 'food',
|
|||
// titleEn: 'FOOD',
|
|||
// path: '/foods'
|
|||
// },
|
|||
// {
|
|||
// icon: require('@/assets/images/sidebar/service.png'),
|
|||
// title: '商场服务',
|
|||
// titleEn: 'SERVICE',
|
|||
// moduleName: 'service',
|
|||
// path: '/service'
|
|||
// }
|
|||
] |
|||
@ -1,57 +0,0 @@ |
|||
<template> |
|||
<div class="tabs-wrapper"> |
|||
<div class="tab" :class="{ active: tabIdx === index }" @click="handleTab(index)" v-for="(item, index) of list" :key="item.name"> |
|||
<img :src="tabIdx === index ? item.iconActive : item.icon" alt="" /> |
|||
{{ item.name }} |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
|
|||
defineProps({ |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}) |
|||
const emits = defineEmits(['click']) |
|||
|
|||
const tabIdx = ref(0) |
|||
function handleTab(index) { |
|||
tabIdx.value = index |
|||
emits('click', index) |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.tabs-wrapper { |
|||
display: flex; |
|||
width: 100%; |
|||
height: 64px; |
|||
background: var(--search-tabsBg, rgba(0, 0, 0, 0.05)); |
|||
border-radius: var(--global-radius, 12px); |
|||
overflow: hidden; |
|||
|
|||
.tab { |
|||
height: 100%; |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
color: var(--search-tabColor, rgba(0, 0, 0, 0.6)); |
|||
border-radius: var(--global-radius, 12px); |
|||
&.active { |
|||
background: var(--search-tabActiveBg, #ffffff); |
|||
color: var(--search-tabActiveColor, rgba(0, 0, 0, 0.8)); |
|||
} |
|||
} |
|||
|
|||
img { |
|||
width: 24px; |
|||
height: 24px; |
|||
margin-right: 12px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,49 +0,0 @@ |
|||
<template> |
|||
<div class="carousel"> |
|||
<EffectFade :list="list"> |
|||
<template v-slot="{ item }"> |
|||
<div class="banner-wrapper"> |
|||
<img :src="config.sourceUrl + item" alt="" class="banner" /> |
|||
</div> |
|||
</template> |
|||
</EffectFade> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
import { storeToRefs } from 'pinia' |
|||
import { useStore } from '@/store/root' |
|||
import { getTrafficList } from '@/http/api' |
|||
import EffectFade from '../EffectFade/EffectFade.vue' |
|||
|
|||
const store = useStore() |
|||
const { config } = storeToRefs(store) |
|||
|
|||
const list = ref([]) |
|||
getTrafficList().then(({ data }) => { |
|||
list.value = data?.fileList ?? [] |
|||
}) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.carousel { |
|||
position: relative; |
|||
width: 870px; |
|||
height: 1300px; |
|||
margin-top: 58px; |
|||
margin-left: 170px; |
|||
margin-right: 40px; |
|||
} |
|||
.banner-wrapper { |
|||
width: 870px; |
|||
height: 1300px; |
|||
overflow: hidden; |
|||
} |
|||
.banner { |
|||
width: 100%; |
|||
height: 100%; |
|||
border-radius: 10px; |
|||
object-fit: cover; |
|||
} |
|||
</style> |
|||
@ -1,241 +0,0 @@ |
|||
<template> |
|||
<div class="speech-wrapper" :class="{ active: !startSpeech }"> |
|||
<div class="lottie-box"> |
|||
<Lottie :isLocale="true" ref="lottieInstance" :path="lottie" v-show="startSpeech" /> |
|||
</div> |
|||
<div class="start-btn" @click="handleSpeech"> |
|||
<img src="../../assets/images/search/speech.png" alt="" /> |
|||
<span class="text">点我开始说话</span> |
|||
</div> |
|||
</div> |
|||
<ScrollView class="voice-scroll"> |
|||
<div class="voice-content"> |
|||
<h1 class="title">试着问我一下这些问题吧</h1> |
|||
<div class="commons"> |
|||
<div class="common-question"> |
|||
<img class="img" src="/static/img/xsj.png" alt="" /> |
|||
<div class="common-right"> |
|||
<h1 class="sub">卫生间</h1> |
|||
<h1 class="desc">附近卫生间怎么走?</h1> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<h1 class="title">您还可查看更多商场相关问题</h1> |
|||
<div class="groups"> |
|||
<div class="box-group" @click="showCustomerDialog = true"> |
|||
<img src="../../assets/images/search/customer.png" class="icon" alt="" /> |
|||
<p class="text">转人工服务</p> |
|||
</div> |
|||
<div class="box-group" @click="handleMoreQuestion"> |
|||
<img src="../../assets/images/search/question.png" class="icon" alt="" /> |
|||
<p class="text">常见问题</p> |
|||
</div> |
|||
</div> |
|||
<div class="dialog flex"> |
|||
<div class="customer">我想开小票</div> |
|||
</div> |
|||
<div class="dialog"> |
|||
<p class="machine">您可以尝试换一种提问方式,导航到服务台,或是拨打400-888-8888,或转人工服务</p> |
|||
</div> |
|||
</div> |
|||
</ScrollView> |
|||
<Teleport to="body"> |
|||
<Transition enter-active-class="animate__aniamted animate__zoomIn" leave-active-class="animate__aniamted animate__zoomOut"> |
|||
<Customer @close="showCustomerDialog = false" v-if="showCustomerDialog" /> |
|||
</Transition> |
|||
</Teleport> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, nextTick, defineAsyncComponent } from 'vue' |
|||
import lottie from './voice.json' |
|||
import Lottie from '@/components/Lottie/Lottie.vue' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
const Customer = defineAsyncComponent(() => import('@/components/Customer/Customer.vue')) |
|||
|
|||
const startSpeech = ref(false) |
|||
const lottieInstance = ref(null) |
|||
function handleSpeech() { |
|||
startSpeech.value = !startSpeech.value |
|||
nextTick(() => { |
|||
if (!startSpeech.value) { |
|||
lottieInstance.value.lottieInstance.stop() |
|||
} else { |
|||
lottieInstance.value.lottieInstance.play() |
|||
} |
|||
}) |
|||
} |
|||
|
|||
const emits = defineEmits(['handle-question']) |
|||
function handleMoreQuestion() { |
|||
emits('handle-question') |
|||
} |
|||
|
|||
const showCustomerDialog = ref(false) |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.speech-wrapper { |
|||
position: absolute; |
|||
left: 16px; |
|||
right: 16px; |
|||
top: 416px; |
|||
height: 360px; |
|||
:deep(svg) { |
|||
height: 85px !important; |
|||
} |
|||
|
|||
.lottie-box { |
|||
position: relative; |
|||
height: 115px; |
|||
margin-top: -42px; |
|||
&::before, |
|||
&::after { |
|||
content: ''; |
|||
position: absolute; |
|||
width: 328px; |
|||
top: 42px; |
|||
height: 2px; |
|||
background: linear-gradient(90deg, #ffbd35 0%, #ffd260 100%); |
|||
} |
|||
&::before { |
|||
left: 0; |
|||
} |
|||
&::after { |
|||
right: 0; |
|||
} |
|||
} |
|||
:deep(svg) { |
|||
transform: scale(3.5) !important; |
|||
} |
|||
.start-btn { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 98px; |
|||
transform: translateX(-50%); |
|||
img { |
|||
width: 160px; |
|||
} |
|||
.text { |
|||
font-weight: 700; |
|||
font-size: 18px; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
font-family: 'font_bold'; |
|||
} |
|||
} |
|||
&.active { |
|||
&:before { |
|||
position: absolute; |
|||
content: ''; |
|||
left: 0; |
|||
right: 0; |
|||
height: 2px; |
|||
background: linear-gradient(90deg, #ffbd35 0%, #ffd260 100%); |
|||
} |
|||
} |
|||
} |
|||
.voice-scroll { |
|||
position: fixed; |
|||
top: 802px; |
|||
left: 80px; |
|||
right: 58px; |
|||
bottom: 0; |
|||
.title { |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-bottom: 24px; |
|||
} |
|||
.commons { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
margin-bottom: 56px; |
|||
} |
|||
.common-question { |
|||
display: flex; |
|||
align-items: center; |
|||
width: 352px; |
|||
height: 72px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 12px; |
|||
padding: 14px 24px; |
|||
margin-right: 8px; |
|||
margin-bottom: 8px; |
|||
.img { |
|||
width: 44px; |
|||
height: 44px; |
|||
margin-right: 24px; |
|||
} |
|||
.sub { |
|||
font-weight: 700; |
|||
font-size: 14px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-bottom: 6px; |
|||
} |
|||
.desc { |
|||
color: rgba(0, 0, 0, 0.4); |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
.groups { |
|||
display: flex; |
|||
} |
|||
.box-group { |
|||
width: 196px; |
|||
height: 177px; |
|||
background: #ffffff; |
|||
box-shadow: 0px 20px 40px rgba(31, 46, 84, 0.04); |
|||
border-radius: 12px; |
|||
margin-right: 16px; |
|||
margin-bottom: 24px; |
|||
.icon { |
|||
display: inline-block; |
|||
margin: 32px 0 32px 32px; |
|||
width: 48px; |
|||
} |
|||
.text { |
|||
font-weight: 700; |
|||
font-size: 16px; |
|||
line-height: 19px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
padding-left: 32px; |
|||
padding-top: 23px; |
|||
border-top: 1px solid rgba(0, 0, 0, 0.05); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.machine { |
|||
display: inline-block; |
|||
padding: 24px 40px; |
|||
background: rgba(0, 0, 0, 0.05); |
|||
border-radius: 0px 32px 32px 32px; |
|||
font-size: 18px; |
|||
line-height: 21px; |
|||
color: #605e74; |
|||
margin-bottom: 16px; |
|||
} |
|||
.flex { |
|||
display: flex; |
|||
flex-direction: row-reverse; |
|||
} |
|||
|
|||
.customer { |
|||
padding: 24px 40px; |
|||
background: #ffffff; |
|||
font-weight: 700; |
|||
font-size: 24px; |
|||
line-height: 28px; |
|||
font-family: 'font_bold'; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
border-radius: 32px 0px 32px 32px; |
|||
text-align: right; |
|||
margin-bottom: 24px; |
|||
} |
|||
</style> |
|||
@ -1,116 +0,0 @@ |
|||
<template> |
|||
<ScrollView class="waterfall-scroll" :list="list" observe-image> |
|||
<TransitionGroup name="zoom" tag="div" class="waterfall-content-scroll"> |
|||
<div class="waterfall-item" v-for="item of list" @click="handleWaterfall(item)" :key="item.name"> |
|||
<img :src="config.sourceUrl + item.fileUrl" alt="" class="waterfall-img" /> |
|||
<div class="title-wrapper"> |
|||
<h6 class="waterfall-title">{{ switchLanguage(item, 'name') }}</h6> |
|||
<h5 class="sub" v-if="item?.shopId"> |
|||
<h6 class="waterfall-name">{{ switchLanguage(item, 'shopName') }}</h6> |
|||
<h6 class="house-num pb-32">{{ item.houseNumber }}</h6> |
|||
</h5> |
|||
</div> |
|||
</div> |
|||
</TransitionGroup> |
|||
</ScrollView> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { storeToRefs } from 'pinia' |
|||
import { useRouter } from 'vue-router' |
|||
import { useStore } from '@/store/root' |
|||
import ScrollView from '@/base/ScrollView/ScrollView.vue' |
|||
import Shop from '@/utils/Class/Shop' |
|||
|
|||
defineProps({ |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
config: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
} |
|||
}) |
|||
|
|||
const router = useRouter() |
|||
const store = useStore() |
|||
const { shopList } = storeToRefs(store) |
|||
|
|||
function handleWaterfall(item) { |
|||
let shop |
|||
if (item?.shopId) { |
|||
shop = shopList.value.find(_shop => _shop.shopId === item.shopId) |
|||
if (shop) { |
|||
store.SET_SHOP(shop) |
|||
store.SET_SHOW_DETAIL(true) |
|||
} |
|||
} else { |
|||
const { name, floorOrder, floor, logoUrl, point } = item |
|||
shop = new Shop(name, floorOrder, floor, logoUrl, point) |
|||
if (shop) { |
|||
store.SET_SHOP(shop) |
|||
router.push('/nav') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.waterfall-scroll { |
|||
position: absolute; |
|||
left: 88px; |
|||
right: 70px; |
|||
top: 272px; |
|||
bottom: 0; |
|||
overflow: hidden; |
|||
z-index: 10; |
|||
border-radius: 12px; |
|||
|
|||
.waterfall-content-scroll { |
|||
column-count: 2; |
|||
padding-bottom: 16px; |
|||
} |
|||
.waterfall-item { |
|||
break-inside: avoid; |
|||
height: auto; |
|||
width: 440px; |
|||
background-color: var(--color-white-opacity); |
|||
margin-right: 24px; |
|||
margin-bottom: 16px; |
|||
overflow: hidden; |
|||
border-radius: 12px; |
|||
.waterfall-img { |
|||
width: 440px; |
|||
margin-bottom: 32px; |
|||
} |
|||
.title-wrapper { |
|||
padding-left: 32px; |
|||
padding-right: 32px; |
|||
} |
|||
.waterfall-title { |
|||
font-weight: 700; |
|||
font-size: 20px; |
|||
font-family: 'font_bold'; |
|||
color: var(--color-black-opacity-8); |
|||
padding-bottom: 13px; |
|||
@include no-wrap; |
|||
} |
|||
.sub { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
.waterfall-name, |
|||
.house-num { |
|||
font-weight: 700; |
|||
font-family: 'font_bold'; |
|||
font-size: 16px; |
|||
line-height: 19px; |
|||
color: var(--color-black-opacity-4); |
|||
} |
|||
.pb-32 { |
|||
padding-bottom: 32px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,171 +0,0 @@ |
|||
<template> |
|||
<canvas :style="{ backgroundColor: backgroundColor, borderRadius: borderRadius }" ref="inkCanvasRef" :width="width" :height="height" id="ink-canvas"></canvas> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { reactive, computed, onMounted, onBeforeUnmount, watch, ref } from 'vue' |
|||
import { getHandWriting } from '@/http/api' |
|||
|
|||
const props = defineProps({ |
|||
width: { |
|||
type: Number, |
|||
default: 800 |
|||
}, |
|||
height: { |
|||
type: Number, |
|||
default: 800 |
|||
}, |
|||
lang: { |
|||
type: String, |
|||
default: 'CN', |
|||
validator(value) { |
|||
return ['CN', 'EN'].includes(value) |
|||
} |
|||
}, |
|||
backgroundColor: { |
|||
type: String, |
|||
default: '#f2f2f2' |
|||
}, |
|||
borderRadius: { |
|||
type: String, |
|||
default: '10px' |
|||
}, |
|||
fillText: { |
|||
type: String, |
|||
default: '手写区域' |
|||
}, |
|||
fillFontSize: { |
|||
type: String, |
|||
default: '100px' |
|||
}, |
|||
strokeStyle: { |
|||
type: String, |
|||
default: '#000' |
|||
}, |
|||
fillStyle: { |
|||
type: String, |
|||
default: 'rgba(85, 73, 54, 0.1)' |
|||
} |
|||
}) |
|||
const emits = defineEmits(['result']) |
|||
|
|||
const state = reactive({ |
|||
handWrite: '', |
|||
isClick: false, |
|||
//轨迹X |
|||
clickX: [], |
|||
//轨迹Y |
|||
clickY: [], |
|||
//轨迹标志位,为1则是终点 |
|||
clickC: [], |
|||
X: 0, |
|||
Y: 0, |
|||
oldX: 0, |
|||
oldY: 0, |
|||
timer: 0, |
|||
list: [] |
|||
}) |
|||
|
|||
const inkCanvasRef = ref(null) |
|||
const ctxRef = computed(() => inkCanvasRef.value.getContext('2d')) |
|||
|
|||
function updateBound() { |
|||
const bound = inkCanvasRef.value.getBoundingClientRect() |
|||
state.X = bound.x |
|||
state.Y = bound.y |
|||
} |
|||
function down(ev) { |
|||
const cx = Math.floor(ev.clientX || ev.targetTouches[0].clientX) - state.X |
|||
|
|||
const cy = Math.floor(ev.clientY || ev.targetTouches[0].clientY) - state.Y |
|||
|
|||
clearTimeout(state.timer) |
|||
state.oldX = cx |
|||
state.oldY = cy |
|||
ctxRef.value.beginPath() |
|||
state.isClick = true |
|||
} |
|||
function move(ev) { |
|||
ev.preventDefault() |
|||
if (state.isClick) { |
|||
const cx = Math.floor(ev.clientX || ev.targetTouches[0].clientX) - state.X |
|||
const cy = Math.floor(ev.clientY || ev.targetTouches[0].clientY) - state.Y |
|||
|
|||
state.clickX.push(cx) |
|||
state.clickY.push(cy) |
|||
state.clickC.push(0) |
|||
//画图 |
|||
|
|||
ctxRef.value.lineWidth = 8 |
|||
ctxRef.value.lineCap = 'round' |
|||
ctxRef.value.moveTo(state.oldX, state.oldY) |
|||
ctxRef.value.lineTo(cx, cy) |
|||
ctxRef.value.stroke() |
|||
state.oldX = cx |
|||
state.oldY = cy |
|||
} |
|||
} |
|||
function mouseUp() { |
|||
if (state.isClick) { |
|||
state.isClick = false |
|||
state.timer = setTimeout(() => { |
|||
reload() |
|||
}, 1500) |
|||
//标记最后一点为终点 |
|||
state.clickC.pop() |
|||
state.clickC.push(1) |
|||
_getHandWriting() |
|||
} |
|||
} |
|||
|
|||
function reload() { |
|||
if (!inkCanvasRef.value) { |
|||
return |
|||
} |
|||
state.clickX = [] |
|||
state.clickY = [] |
|||
state.clickC = [] |
|||
ctxRef.value.strokeStyle = props.strokeStyle |
|||
ctxRef.value.fillStyle = props.fillStyle |
|||
ctxRef.value.clearRect(0, 0, props.width, props.height) |
|||
ctxRef.value.font = `bold ${props.fillFontSize} Arial` |
|||
ctxRef.value.textAlign = 'center' |
|||
ctxRef.value.textBaseline = 'middle' |
|||
ctxRef.value.fillText(props.fillText, props.width / 2, props.height / 2, 1000) |
|||
} |
|||
function _getHandWriting() { |
|||
const params = { |
|||
lib: props.lang, |
|||
lpXis: state.clickX, |
|||
lpYis: state.clickY, |
|||
lpCis: state.clickC |
|||
} |
|||
getHandWriting(params) |
|||
.then(res => { |
|||
state.list = res |
|||
}) |
|||
.catch(err => { |
|||
console.log(err) |
|||
}) |
|||
} |
|||
|
|||
watch( |
|||
() => state.list, |
|||
newVal => { |
|||
emits('result', newVal) |
|||
} |
|||
) |
|||
|
|||
onMounted(() => { |
|||
updateBound() |
|||
reload() |
|||
inkCanvasRef.value.addEventListener('touchstart', down) |
|||
inkCanvasRef.value.addEventListener('touchmove', move) |
|||
inkCanvasRef.value.addEventListener('touchend', mouseUp) |
|||
}) |
|||
onBeforeUnmount(() => { |
|||
inkCanvasRef.value.removeEventListener('touchstart', down) |
|||
inkCanvasRef.value.removeEventListener('touchmove', move) |
|||
inkCanvasRef.value.removeEventListener('touchend', mouseUp) |
|||
}) |
|||
</script> |
|||