generated from huangmh/client_iot-daoshi-template-v
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
482 lines
13 KiB
482 lines
13 KiB
<template>
|
|
<View>
|
|
<Teleport to="body">
|
|
<ScrollView :list="currentBuildingFloorsList" class="floors-list animate__fast animate__animated animate__fadeIn">
|
|
<div>
|
|
<div class="floors-item all" @click="showAll = true" :class="{ active: showAll }">全部楼层</div>
|
|
<div
|
|
@click="handleSelectFloor(index)"
|
|
:class="{ active: !showAll && floorIdx === index, current: currentFloor.floorCode === item.floorCode }"
|
|
class="floors-item"
|
|
v-for="(item, index) of currentBuildingFloorsList"
|
|
:key="item.floorCode"
|
|
>
|
|
{{ item.floor }}
|
|
</div>
|
|
</div>
|
|
</ScrollView>
|
|
<div class="allFloors" animate__fast animate__animated animate__fadeInUp v-if="showAll">
|
|
<ScrollView>
|
|
<div>
|
|
<div class="row" :class="{ current: currentFloor.floorCode === item.floorCode }" v-for="item of currentBuildingFloorsList" :key="item.floorCode">
|
|
<div class="left">{{ item.floor }}</div>
|
|
<div class="right">
|
|
<div class="format">{{ formatMap[item.floor] }}</div>
|
|
<div class="facs">
|
|
<div class="fac" v-for="fac of facMap[item.floorOrder]" :key="fac.type">
|
|
<img :src="fac.imgUrl" alt="" />
|
|
{{ fac.title }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ScrollView>
|
|
</div>
|
|
</Teleport>
|
|
|
|
<Teleport to="body">
|
|
<div class="control-area">
|
|
<div class="map-control-wrapper animate__fast animate__animated animate__fadeInUp">
|
|
<div class="map-item" @click="handleMapIcon(item, index)" v-for="(item, index) of buttonList" :key="item.name">
|
|
<img :src="mapIdx === index ? item.iconActive : item.icon" alt="" class="map-icon" />
|
|
<span class="map-name">{{ switchLanguage(item, 'name') }}</span>
|
|
</div>
|
|
</div>
|
|
<img src="../../assets/images/map/hands.svg" alt="" class="hands" />
|
|
</div>
|
|
</Teleport>
|
|
|
|
<div class="shop-list-wrapper">
|
|
<BrandScroll v-if="initiated" :shop="shop" :need-focus="true" @click="handleShop" :list="selectedShopList" :isRow="isRow" :config="config" />
|
|
<div class="switch">
|
|
<div :class="{ btn: true, active: !isRow }" @click="isRow = false">
|
|
<img v-if="isRow" src="./grid.svg" />
|
|
<img v-else src="./gridActive.svg" />
|
|
</div>
|
|
<div :class="{ btn: true, active: isRow }" @click="isRow = true">
|
|
<img v-if="!isRow" src="./row.svg" />
|
|
<img v-else src="./rowActive.svg" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</View>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch, onBeforeUnmount, computed, nextTick } from 'vue'
|
|
import { storeToRefs } from 'pinia'
|
|
import { useStore } from '@/store/root'
|
|
import { RESET, DIRECTION, ACTIVITY_BRAND, list as buttonList } from './list'
|
|
import View from '@/layouts/View.vue'
|
|
import { hideMapDialog, setShopActive, setShopInactive } from '@/composables/useInitMap'
|
|
import { getBrandListByFormat, getBrandListByFloor } from '@/http/brand/api'
|
|
import BrandScroll from '@/components/BrandScroll/BrandScroll.vue'
|
|
import ScrollView from '@/base/ScrollView/ScrollView.vue'
|
|
|
|
const shopList = ref([])
|
|
const showAll = ref(false)
|
|
const isRow = ref(false)
|
|
const store = useStore()
|
|
const formatMap = ref({})
|
|
const facMap = ref({})
|
|
const { currentBuildingFloorsList, currentFloor, config, currentFloorShopMap, shop } = storeToRefs(store)
|
|
|
|
try {
|
|
const facs = window.Map_QM.getAllIcon()
|
|
|
|
facMap.value = facs[0].map(list => Object.values(list.reduce((acc, nxt) => ({ ...acc, [nxt.type]: nxt }), {})))
|
|
} catch (error) {
|
|
console.log('error: ', error)
|
|
}
|
|
|
|
getBrandListByFloor().then(({ data }) => {
|
|
formatMap.value = data.list
|
|
.map(({ name, shopList: list }) => ({ name, format: Object.keys(list.reduce((acc, nxt) => ({ ...acc, [nxt.industryFatherName]: true }), {})).join('/') }))
|
|
.reduce((acc, nxt) => ({ ...acc, [nxt.name]: nxt.format }), {})
|
|
})
|
|
getBrandListByFormat().then(({ data }) => {
|
|
shopList.value = data.list
|
|
})
|
|
const selectedShopList = ref([])
|
|
const idle = ref(null)
|
|
|
|
const mapIdx = ref(-1)
|
|
const mapTimer = ref(null)
|
|
const mapIconTimer = ref(null)
|
|
//我的方向
|
|
function onClickMeDirect() {
|
|
window.Map_QM.showFloor(currentFloor.value.floorOrder)
|
|
hideMapDialog()
|
|
window.Map_QM.onShowMeDir()
|
|
filterAboutCurrentInfo()
|
|
}
|
|
//我的位置
|
|
function onClickDeviceSite() {
|
|
hideMapDialog()
|
|
window.Map_QM.onShowDeviceSite()
|
|
}
|
|
function handleMapIcon(item, index) {
|
|
clearTimeout(mapIconTimer.value)
|
|
window.Map_QM.changeStateShopPro(false)
|
|
mapIdx.value = index
|
|
switch (item.name) {
|
|
case RESET:
|
|
window.Map_QM.showFloor(currentFloor.value.floorOrder)
|
|
onClickDeviceSite()
|
|
filterAboutCurrentInfo()
|
|
break
|
|
case DIRECTION:
|
|
onClickMeDirect()
|
|
break
|
|
case ACTIVITY_BRAND:
|
|
window.Map_QM.onShowDeviceSite()
|
|
mapIconTimer.value = setTimeout(() => {
|
|
window.Map_QM.changeStateShopPro(true)
|
|
clearTimeout(mapIconTimer.value)
|
|
mapIconTimer.value = null
|
|
}, 50)
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
clearTimeout(mapTimer.value)
|
|
if (item.name === RESET) {
|
|
mapTimer.value = setTimeout(() => {
|
|
mapIdx.value = -1
|
|
mapTimer.value = -1
|
|
clearTimeout(mapTimer.value)
|
|
}, 300)
|
|
}
|
|
}
|
|
|
|
function handleShop(item) {
|
|
mapIdx.value = -1
|
|
store.SET_SHOP(item)
|
|
}
|
|
watch(shop, async nxt => {
|
|
if (!nxt) {
|
|
setShopInactive()
|
|
} else if (nxt && initiated.value) {
|
|
if (currentBuildingFloorsList.value[floorIdx.value].floorOrder !== nxt.floorOrder) {
|
|
const index = currentBuildingFloorsList.value.findIndex(item => item.floorOrder === nxt.floorOrder)
|
|
await changeFloor(index)
|
|
setTimeout(() => setShopActive(nxt), 500)
|
|
} else setShopActive(nxt)
|
|
}
|
|
})
|
|
|
|
const floorIdx = ref(-1)
|
|
function changeFloor(index) {
|
|
return new Promise(resolve => {
|
|
const floor = currentBuildingFloorsList.value[index]
|
|
showAll.value = false
|
|
hideMapDialog()
|
|
mapIdx.value = -1
|
|
cancelIdleCallback(idle.value)
|
|
window.Map_QM.showFloor(floor.floorOrder)
|
|
idle.value = requestIdleCallback(() => {
|
|
floorIdx.value = index
|
|
selectedShopList.value = shopList.value.map(brand => ({
|
|
...brand,
|
|
shopList: brand.shopList
|
|
.filter(item => item.floor === floor.floor)
|
|
.map(item => {
|
|
const meta = currentFloorShopMap.value[item.shopId]
|
|
return { ...item, ...(meta ? meta : {}) }
|
|
})
|
|
}))
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
const handleSelectFloor = index => {
|
|
store.SET_SHOP(null)
|
|
nextTick(() => {
|
|
changeFloor(index)
|
|
})
|
|
}
|
|
//筛选当前楼层所需数据
|
|
function filterAboutCurrentInfo() {
|
|
const floorCode = shop.value ? shop.value.floorCode : currentFloor.value.floorCode
|
|
const floor = shop.value ? shop.value.floor : currentFloor.value.floor
|
|
const floorOrder = shop.value ? shop.value.floorOrder : currentFloor.value.floorOrder
|
|
window.Map_QM.showFloor(floorOrder)
|
|
cancelIdleCallback(idle.value)
|
|
idle.value = requestIdleCallback(() => {
|
|
floorIdx.value = currentBuildingFloorsList.value.findIndex(item => item.floorCode === floorCode)
|
|
selectedShopList.value = shopList.value.map(brand => ({
|
|
...brand,
|
|
shopList: brand.shopList
|
|
.filter(item => item.floor === floor)
|
|
.map(item => {
|
|
const meta = currentFloorShopMap.value[item.shopId]
|
|
return { ...item, ...(meta ? meta : {}) }
|
|
})
|
|
}))
|
|
})
|
|
nextTick(() => {
|
|
if (shop.value) {
|
|
setShopActive(shop.value)
|
|
}
|
|
})
|
|
}
|
|
const initiated = computed(() => selectedShopList.value && selectedShopList.value.length)
|
|
onBeforeUnmount(() => {
|
|
cancelIdleCallback(idle.value)
|
|
clearTimeout(mapTimer.value)
|
|
clearTimeout(mapIconTimer.value)
|
|
hideMapDialog()
|
|
store.SET_SHOP(null)
|
|
})
|
|
|
|
watch(
|
|
[shopList, currentFloor],
|
|
([_shopList, _currentFloor]) => {
|
|
if (_shopList.length && Reflect.ownKeys(_currentFloor).length) {
|
|
console.log('guide page initiated')
|
|
filterAboutCurrentInfo()
|
|
}
|
|
},
|
|
{
|
|
immediate: true
|
|
}
|
|
)
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.allFloors {
|
|
position: absolute;
|
|
top: 408px;
|
|
left: 0;
|
|
right: 0;
|
|
height: 642px;
|
|
background: left / 150px 100% no-repeat linear-gradient(180deg, #6c7ca6 0%, #879aca 100%), #dee6f6;
|
|
z-index: 100;
|
|
.row {
|
|
height: 76px;
|
|
display: flex;
|
|
&.current {
|
|
.left {
|
|
position: relative;
|
|
color: rgba(0, 0, 0, 0.8);
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.8) 0%, #ffffff 100%);
|
|
&::after {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
height: 20px;
|
|
display: flex;
|
|
content: '您在本层';
|
|
background: linear-gradient(99.5deg, #f0b92b 0%, #f9d556 100%);
|
|
font-weight: 700;
|
|
font-size: 12px;
|
|
color: rgba(0, 0, 0, 0.8);
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
}
|
|
.right {
|
|
background: #fff;
|
|
}
|
|
}
|
|
.left {
|
|
flex: 0 0 150px;
|
|
font-family: 'Montserrat';
|
|
font-style: normal;
|
|
font-weight: 700;
|
|
font-size: 28px;
|
|
line-height: 96%;
|
|
|
|
display: flex;
|
|
align-items: center;
|
|
text-align: center;
|
|
justify-content: center;
|
|
|
|
/* W/100% */
|
|
|
|
color: #ffffff;
|
|
}
|
|
.right {
|
|
flex: 1;
|
|
display: flex;
|
|
padding: 0 68px;
|
|
border-bottom: 1px solid #fff;
|
|
.format {
|
|
flex: 1;
|
|
font-weight: 700;
|
|
font-size: 20px;
|
|
line-height: 23px;
|
|
display: flex;
|
|
align-items: center;
|
|
color: rgba(0, 0, 0, 0.8);
|
|
}
|
|
.facs {
|
|
flex: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
|
|
.fac {
|
|
display: flex;
|
|
flex-direction: column;
|
|
img {
|
|
width: 36px;
|
|
height: 36px;
|
|
margin-bottom: 8px;
|
|
}
|
|
font-weight: 700;
|
|
font-size: 12px;
|
|
line-height: 14px;
|
|
text-align: center;
|
|
color: rgba(0, 0, 0, 0.6);
|
|
align-items: center;
|
|
}
|
|
.fac + .fac {
|
|
margin-left: 16px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.floors-list {
|
|
position: absolute;
|
|
right: 510px;
|
|
width: 100px;
|
|
top: 280px;
|
|
height: calc(100vh - 280px);
|
|
z-index: 60;
|
|
display: block;
|
|
overflow: hidden;
|
|
background: linear-gradient(113.71deg, #435acd 0%, #749cf3 100%);
|
|
|
|
&::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
.floors-item {
|
|
width: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: relative;
|
|
height: 94.44px;
|
|
font-family: 'Montserrat';
|
|
font-style: normal;
|
|
font-weight: 700;
|
|
font-size: 28px;
|
|
line-height: 96%;
|
|
text-align: center;
|
|
color: #ffffff;
|
|
transition: all 0.5s;
|
|
&.all {
|
|
font-weight: 700;
|
|
font-size: 18px;
|
|
line-height: 96%;
|
|
vertical-align: bottom;
|
|
}
|
|
&.current {
|
|
background: rgba(0, 0, 0, 0.1);
|
|
&::after {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
height: 20px;
|
|
display: flex;
|
|
content: '您在本层';
|
|
background: linear-gradient(99.5deg, #f0b92b 0%, #f9d556 100%);
|
|
font-weight: 700;
|
|
font-size: 12px;
|
|
color: rgba(0, 0, 0, 0.8);
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
}
|
|
&.active {
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.8) 0%, #ffffff 100%);
|
|
color: rgba(0, 0, 0, 0.8);
|
|
}
|
|
}
|
|
}
|
|
.shop-list-wrapper {
|
|
position: absolute;
|
|
width: 510px;
|
|
height: calc(100vh - 280px);
|
|
right: 0px;
|
|
bottom: 0;
|
|
background: linear-gradient(180deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0) 100%);
|
|
.switch {
|
|
display: flex;
|
|
position: absolute;
|
|
top: 24px;
|
|
right: 68px;
|
|
.btn {
|
|
display: flex;
|
|
width: 48px;
|
|
height: 48px;
|
|
background: rgba(255, 255, 255, 0.4);
|
|
border-radius: 8px;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
img {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
&.active {
|
|
background: #ffffff;
|
|
}
|
|
}
|
|
.btn + .btn {
|
|
margin-left: 8px;
|
|
}
|
|
}
|
|
.shop-scroll {
|
|
height: 100%;
|
|
overflow: hidden;
|
|
margin-left: 54px;
|
|
}
|
|
}
|
|
|
|
.control-area {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
left: 68px;
|
|
bottom: 40px;
|
|
z-index: 51;
|
|
|
|
.hands {
|
|
position: fixed;
|
|
top: 280px;
|
|
left: 68px;
|
|
width: 246px;
|
|
height: 80px;
|
|
z-index: 51;
|
|
}
|
|
}
|
|
|
|
.map-control-wrapper {
|
|
display: flex;
|
|
}
|
|
.map-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-left: 12px;
|
|
}
|
|
.map-icon {
|
|
margin-bottom: 8px;
|
|
width: 52px;
|
|
}
|
|
.map-name {
|
|
font-weight: 700;
|
|
font-size: 12px;
|
|
line-height: 14px;
|
|
text-align: center;
|
|
color: rgba(0, 0, 0, 0.6);
|
|
}
|
|
</style>
|
|
|