Browse Source

feat: 导航

dev
jiannibang 3 years ago
parent
commit
c81888da65
  1. 27
      src/base/ShopItem/ShopItem.vue
  2. 9
      src/components/BrandScroll/BrandScroll.vue
  3. 33
      src/components/Map/Map.vue
  4. BIN
      src/components/Map/bg.png
  5. 11
      src/components/PublicComponent/PublicComponent.vue
  6. BIN
      src/components/PublicComponent/logo.png
  7. 57
      src/views/Guide/Guide.vue
  8. 148
      src/views/Nav/Nav.vue
  9. BIN
      src/views/Nav/back.png

27
src/base/ShopItem/ShopItem.vue

@ -1,14 +1,13 @@
<template>
<div :id="shop.houseNumber" class="group-item isRow" @click="handleShop">
<div :id="shop.houseNumber" class="group-item isRow" :class="{ isActive }" @click="handleShop">
<p class="name">
<span class="shop-name">{{ switchLanguage(shop, 'shopName') }}</span>
<span class="name-right">导览</span>
<span class="name-right" @click="handleShopNav">导航</span>
</p>
</div>
</template>
<script setup>
import QRCodeFromText from '@/components/QRCodeFromText/QRCodeFromText.vue'
import { storeToRefs } from 'pinia'
import { useStore } from '@/store/root'
@ -23,11 +22,13 @@ const props = defineProps({
isActive: Boolean
})
const emits = defineEmits(['click'])
function handleShop() {
const emits = defineEmits(['click', 'nav'])
const handleShop = () => {
emits('click', props.shop)
}
const deactivate = () => store.SET_SHOP(null)
const handleShopNav = e => {
emits('nav', props.shop)
}
</script>
<style lang="scss" scoped>
@ -41,11 +42,6 @@ const deactivate = () => store.SET_SHOP(null)
padding-left: 12px;
align-items: center;
.shop-logo {
width: 100%;
height: 100%;
object-fit: contain;
}
.name {
display: flex;
align-items: center;
@ -73,5 +69,14 @@ const deactivate = () => store.SET_SHOP(null)
color: #516dd8;
justify-content: center;
}
&.isActive {
background: linear-gradient(113.71deg, #435acd 0%, #749cf3 100%);
.shop-name {
color: #ffffff;
}
.name-right {
color: #ffffff;
}
}
}
</style>

9
src/components/BrandScroll/BrandScroll.vue

@ -8,10 +8,9 @@
<TransitionGroup name="zoom" mode="out-in" tag="div" :class="{ group: true }">
<ShopItem
:config="config"
:isGuide="$route.path === '/guide' && !isRow"
:isFood="isFood"
:shop="el"
@click="handleShop(el)"
@nav="handleShopNav(el)"
v-for="el of item.shopList"
:isActive="shop && shop.shopId === el.shopId"
:key="el.shopId"
@ -40,11 +39,13 @@ const props = defineProps({
needFocus: Boolean
})
const emits = defineEmits(['click'])
const emits = defineEmits(['click', 'nav'])
function handleShop(item) {
emits('click', item)
}
function handleShopNav(item) {
emits('nav', item)
}
watch(
() => props.list,
() =>

33
src/components/Map/Map.vue

@ -5,7 +5,8 @@
<!-- 地图弹框 -->
<div id="shopInfo" class="boxShop">
<div>{{ shop ? switchLanguage(shop, 'shopName') : '' }}</div>
<div class="name">{{ shop ? switchLanguage(shop, 'shopName') : '' }}</div>
<div class="btn" @click="$router.push('/nav')">导航</div>
</div>
<img src="./fac.png" id="fac" class="boxShop" />
@ -51,19 +52,35 @@ const { shop } = storeToRefs(store)
position: absolute;
z-index: 9000 !important;
visibility: hidden;
height: 36px;
width: 130px;
height: 65.14px;
background: center / 100% 100% no-repeat url(./bg.png);
div {
.name {
font-weight: 700;
font-size: 12px;
line-height: 30px;
font-size: 14px;
line-height: 16px;
text-align: center;
border-radius: 100px;
color: #ffffff;
padding: 0 12px;
color: #516dd8;
padding: 7px 6px;
@include no-wrap;
z-index: 1;
}
.btn {
position: absolute;
left: 0;
right: 0;
top: 30px;
margin: auto;
width: 118px;
height: 24px;
background: #516dd8;
border-radius: 8px;
font-weight: 700;
font-size: 12px;
line-height: 24px;
color: #ffffff;
text-align: center;
}
}
#moveFloorBG {
position: absolute;

BIN
src/components/Map/bg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

11
src/components/PublicComponent/PublicComponent.vue

@ -1,5 +1,6 @@
<template>
<div class="box" @click="addTotalClick"></div>
<img src="./logo.png" class="logo" alt="" />
<!-- 地图容器 -->
<Map v-show="$route.meta.showMap" @handle-GO="handleGO" @handle-Detail="handleDetail" />
@ -11,7 +12,6 @@
<Temperature />
<Time />
<SearchBar v-if="$route.path !== '/billboard'" />
</template>
<script setup>
@ -75,6 +75,15 @@ watch(route, to => {
}
})
</script>
<style lang="scss" scoped>
.logo {
position: absolute;
width: 101px;
height: 103px;
left: 60px;
top: 32px;
}
</style>
<style>
.box {
position: absolute;

BIN
src/components/PublicComponent/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

57
src/views/Guide/Guide.vue

@ -28,7 +28,7 @@
</Teleport>
<div class="shop-list-wrapper">
<BrandScroll v-if="initiated" :shop="shop" :need-focus="true" @click="handleShop" :list="selectedShopList" :config="config" />
<BrandScroll v-if="initiated" :shop="shop" :need-focus="true" @click="handleShop" @nav="handleShopNav" :list="selectedShopList" :config="config" />
</div>
</View>
</template>
@ -43,17 +43,23 @@ import { hideMapDialog, setShopActive, setShopInactive, showFacility } from '@/c
import { getBrandListByFormat } from '@/http/brand/api'
import BrandScroll from '@/components/BrandScroll/BrandScroll.vue'
import ScrollView from '@/base/ScrollView/ScrollView.vue'
import { getIndexList } from '@/http/api'
import { useRouter } from 'vue-router'
const router = useRouter()
const shopList = ref([])
const store = useStore()
const { currentBuildingFloorsList, currentFloor, config, shop, facility } = storeToRefs(store)
getIndexList().then(({ data }) => {
store.SET_INDEX_LIST(data)
})
getBrandListByFormat().then(({ data }) => {
shopList.value = data.list
})
const selectedShopList = ref([])
const idle = ref(null)
const mapIdx = ref(-1)
const mapTimer = ref(null)
@ -108,6 +114,13 @@ function handleShop(item) {
mapIdx.value = -1
store.SET_SHOP(item)
}
function handleShopNav(item) {
console.log(item)
mapIdx.value = -1
router.push('/nav')
store.SET_SHOP(item)
}
watch(shop, async nxt => {
if (!nxt) {
setShopInactive()
@ -126,16 +139,14 @@ function changeFloor(index) {
const floor = currentBuildingFloorsList.value[index]
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)
}))
resolve()
})
floorIdx.value = index
selectedShopList.value = shopList.value.map(brand => ({
...brand,
shopList: brand.shopList.filter(item => item.floor === floor.floor)
}))
resolve()
})
}
const handleSelectFloor = index => {
@ -149,15 +160,18 @@ 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)
}))
})
try {
window.Map_QM.showFloor(floorOrder)
} catch (error) {
console.warn(error)
}
floorIdx.value = currentBuildingFloorsList.value.findIndex(item => item.floorCode === floorCode)
selectedShopList.value = shopList.value.map(brand => ({
...brand,
shopList: brand.shopList.filter(item => item.floor === floor)
}))
nextTick(() => {
if (shop.value) {
setShopActive(shop.value)
@ -168,12 +182,9 @@ function filterAboutCurrentInfo() {
}
const initiated = computed(() => selectedShopList.value && selectedShopList.value.length)
onBeforeUnmount(() => {
cancelIdleCallback(idle.value)
clearTimeout(mapTimer.value)
clearTimeout(mapIconTimer.value)
hideMapDialog()
store.SET_SHOP(null)
store.SET_FACILITY(null)
})
watch(

148
src/views/Nav/Nav.vue

@ -1,34 +1,23 @@
<template>
<View title="地图导览" sub-title="map guide" :show-input="false">
<img src="../../assets/images/map/hands.svg" class="hands" alt="" />
<div class="top-right-wrapper">
<Time />
<Temperature />
<img src="../../assets/images/nav/back.png" class="back-icon" @click="$router.back()" alt="" />
<!-- <QRCode />-->
</div>
<View>
<div class="nav-methods animate__animated animate__fadeInUp animate__faster">
<div class="box w-200 mr-8" @click="handleControl(item.name, index)" v-for="(item, index) of methodsList" :key="item.name" :class="{ active: methodIdx === index }">
<img :src="item.icon" class="box-icon mr-20 z-index" alt="" />
<div class="box-right z-index">
<p class="name">{{ item.name }}</p>
<p class="en" :class="'en-middle' + index">{{ item.nameEn }}</p>
<div class="r1">导航到</div>
<div class="r2">{{ shop.shopName }}</div>
<div class="r3">
<div
class="box w-200 mr-8"
@click="handleControl(item.name, index)"
v-for="(item, index) of methodsList"
:key="item.name"
:class="{ active: methodIdx === index }"
>
<img :src="item.icon" class="box-icon mr-20 z-index" alt="" />
<div class="box-right z-index">
<p class="name">{{ item.name }}</p>
</div>
</div>
</div>
<div class="box w-168 mr-8" @click="handleReplay">
<Refresh :size="34" fill="rgba(0, 0, 0, 0.6)" :class="{ rotate: replay }" class="box-icon z-index" />
</div>
<div class="box w-168 mr-8" :class="{ active: pause }" @click="togglePause">
<img :src="pause ? require('../../assets/images/nav/trigle.svg') : require('../../assets/images/nav/double_line.svg')" class="box-icon z-index" alt="" />
</div>
<div class="box w-168 mr-8" :class="{ active: speedUp }" @click="handleSpeedUp">
<img :src="!speedUp ? require('../../assets/images/nav/double_trigle.svg') : require('../../assets/images/nav/pause.svg')" class="box-icon z-index" alt="" />
</div>
<div class="box w-100" @click="setCameraViews">
<img :src="cameraViews.image" class="box-icon z-index" alt="" />
</div>
<div class="back" @click="$router.back()"></div>
</div>
<PassShop :shop="shop" :current-floor="currentFloor" :direction="directionInfo" :config="config" :list="pathShopList" />
@ -36,7 +25,6 @@
</template>
<script setup>
import { onBeforeUnmount } from 'vue'
import { storeToRefs } from 'pinia'
import { useStore } from '@/store/root'
import View from '@/layouts/View.vue'
@ -44,28 +32,17 @@ import { methodsList } from './methodsList'
import { useMapNavControl } from '@/composables/useMapNavControl'
import { useChangeNavMethod } from '@/composables/useChangeNavMethod'
import { useStartNavi } from '@/composables/useStartNavi'
import { useSetCameraViews } from '@/composables/useSetCameraViews'
import { Refresh } from '@/base/Svg'
import PassShop from './children/PassShop.vue'
import Temperature from '@/base/Temperature/Temperature.vue'
import Time from '@/base/Time/Time.vue'
import { useStatistics } from '@/composables/useStatistics'
const store = useStore()
const { shop, currentFloor, config } = storeToRefs(store)
const { replay, pause, speedUp, handleReplay, togglePause, handleSpeedUp, setPause } = useMapNavControl()
const { setPause } = useMapNavControl()
const { directionInfo, pathShopList, backPathArray } = useStartNavi(shop, currentFloor, setPause)
const { methodIdx, handleControl } = useChangeNavMethod(backPathArray)
const { cameraViews, setCameraViews } = useSetCameraViews(setPause)
useStatistics('navigation')
window.Map_QM.changeWindowResize(1366, 1080)
onBeforeUnmount(() => {
window.Map_QM.changeWindowResize(1486, 920)
})
</script>
<style lang="scss" scoped>
@ -99,18 +76,37 @@ onBeforeUnmount(() => {
}
.nav-methods {
position: absolute;
display: flex;
left: 40px;
bottom: 812px;
width: 100vw;
height: 260px;
left: 0;
background: linear-gradient(113.71deg, #435acd 0%, #749cf3 100%);
bottom: 688px;
z-index: 51;
padding-top: 30px;
padding-left: 68px;
.r1 {
font-weight: 700;
font-size: 24px;
line-height: 28px;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 10px;
}
.r2 {
font-weight: 700;
font-size: 40px;
line-height: 47px;
color: #ffffff;
margin-bottom: 25px;
}
.r3 {
}
.back {
display: flex;
align-items: center;
justify-content: center;
width: 132px;
height: 80px;
background: var(--color-linear-goldenyellow);
border-radius: 12px;
position: absolute;
width: 180px;
height: 180px;
left: 832px;
top: 40px;
background: center / cover no-repeat url(./back.png);
}
.rotate {
@ -118,18 +114,15 @@ onBeforeUnmount(() => {
animation-duration: 0.5s;
}
.box {
display: flex;
display: inline-flex;
align-items: center;
justify-content: center;
position: relative;
height: 80px;
text-align: center;
border-radius: 8px;
background: #ffffff;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.8) 0%, #ffffff 100%);
&:nth-child(3) {
margin-right: 14px;
}
.box-icon {
position: relative;
display: block;
@ -145,54 +138,19 @@ onBeforeUnmount(() => {
}
.name {
font-weight: 700;
font-family: 'font_bold';
font-size: 14px;
color: var(--color-black-opacity-6);
padding-bottom: 2px;
padding-top: 5px;
}
.en {
font-size: 12px;
transform: scale(0.83);
transform-origin: 0 0;
text-transform: uppercase;
color: var(--color-black-opacity-4);
font-size: 16px;
line-height: 19px;
color: rgba(0, 0, 0, 0.8);
}
&::before,
&::after {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
content: '';
border-radius: 8px;
transition: bottom 0.5s;
}
&::before {
background-color: var(--color-white-opacity);
z-index: 2;
}
&:after {
background-color: #ffd360;
z-index: 1;
}
&.active {
&::before {
bottom: 4px;
}
background: linear-gradient(99.5deg, #f0b92b 0%, #f9d556 100%);
}
}
.w-168 {
width: 80px;
}
.mr-8 {
margin-right: 8px;
}
.w-100 {
width: 100px;
}
.w-200 {
width: 200px;

BIN
src/views/Nav/back.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Loading…
Cancel
Save