吉安感知网项目-前端
chenyao
2026-01-14 b527660845ffd57614357f27292a8c5338a5e9b1
添加区域信息功能
2 files added
336 ■■■■■ changed files
applications/mobile-web-view/src/appPages/AirMap/index.vue 24 ●●●●● patch | view | raw | blame | history
applications/mobile-web-view/src/appPages/AirMap/searchBar.vue 312 ●●●●● patch | view | raw | blame | history
applications/mobile-web-view/src/appPages/AirMap/index.vue
New file
@@ -0,0 +1,24 @@
<template>
    <div class="wrapper" :style="{ paddingTop: route.query.topMargin + 'px' }">
        <leaflet-map :weatherShow="true" :layerShow="true" :locationShow="true">
            <template #searchBar>
                <SearchBar />
            </template>
        </leaflet-map>
    </div>
</template>
<script setup>
import LeafletMap from '@/appComponents/LeafletMap/index.vue'
import SearchBar from './searchBar.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
</script>
<style lang="scss" scoped>
.wrapper {
    width: 100%;
    height: 100%;
}
</style>
applications/mobile-web-view/src/appPages/AirMap/searchBar.vue
New file
@@ -0,0 +1,312 @@
<template>
    <van-floating-panel v-model:height="height" :anchors="anchors">
        <template #header>
            <div class="custom-header">
                <div class="bar"></div>
                <van-field
                    v-model="searchVal"
                    placeholder="搜索"
                    @focus="height === anchors[0] ? (height = anchors[1]) : null"
                    @update:model-value="handlerInput"
                    @clear="handlerClear"
                    clearable
                    :border="false"
                >
                    <!-- <template #left-icon>
                        <div class="search-left-box">
                            <van-image width="16" height="16" :src="switchoverIcon" />
                            <div class="search-type">地址</div>
                        </div>
                    </template> -->
                </van-field>
            </div>
        </template>
        <div class="list-tooltip" v-if="loadingTest">
            <van-loading />
        </div>
        <div class="list-tooltip" v-else-if="!list.length">
            {{ tooltipText }}
        </div>
        <van-list v-else :finished="finished" :finished-text="finishedText">
            <div class="list-item" v-for="item in list" :key="item" @click="flyToAddress(item)">
                <div class="name">{{ item.airspaceName }}</div>
                <div class="item">
                    <div class="laber">空域管制时间</div>
                    <div class="value">{{item.createTime}}</div>
                </div>
                <div class="item">
                    <div class="laber">空域管制类型</div>
                    <div class="value">{{item.airspaceType === '1' ? '禁飞区' : item.airspaceType === '2' ? '危险区' : item.airspaceType === '3' ? '限制区' : item.airspaceType === '0' ? '适飞区' : '未知'}}</div>
                </div>
            </div>
        </van-list>
    </van-floating-panel>
</template>
<script setup>
import switchoverIcon from '@/appDataSource/leafletMapIcon/addressSearch.svg'
import { showToast } from 'vant'
import _ from 'lodash'
import { searchWithPlugin } from '@/utils/util'
import { getAirspaceDetail } from '@/api/map/address'
import { useStore } from 'vuex'
import EventBus from '@/utils/eventBus'
import { gcj02ToWgs84 } from '@/utils/coordinateTransformation'
import { useRoute } from 'vue-router'
const route = useRoute()
const isWeb = ref(true)
const store = useStore()
const selectedAreaCode = computed(() => store.state.user.selectedAreaCode)
const searchVal = ref('')
const list = ref([])
const finished = ref(false)
const loadingTest = ref(false)
const finishedText = ref('')
const anchors = [70, Math.round(0.6 * window.innerHeight)]
const height = ref(anchors[0])
const curSearchType = ref(1) // 固定为地址搜索
// 使用插件搜索地址
const searchWithPluginAPI = () => {
    searchWithPlugin(searchVal.value, selectedAreaCode.value, (err, data) => {
        if (data && data.length > 0) {
            list.value = data
            finishedText.value = ''
        } else {
            finishedText.value = '暂无数据'
        }
        setTimeout(() => {
            finished.value = true
            loadingTest.value = false
        }, 800)
    })
}
// 使用新接口搜索地址
const searchWithNewAPI = () => {
    // 构建请求参数,搜索框为空时不传递airspaceName
    const params = {
        current: 1,
        size: 9999
    }
    if (searchVal.value.trim() !== '') {
        params.airspaceName = searchVal.value
    }
    getAirspaceDetail(params).then(res => {
        const data = res.data.data.records || []
        if (data && data.length > 0) {
            list.value = data
            finishedText.value = ''
            EventBus.emit('mapAddAirMarker', list.value)
        } else {
            finishedText.value = '暂无数据'
            EventBus.emit('mapClearAirMarker')
        }
        setTimeout(() => {
            finished.value = true
            loadingTest.value = false
        }, 800)
    }).catch(err => {
        console.error('区域搜索失败:', err)
        finishedText.value = '搜索失败'
        setTimeout(() => {
            finished.value = true
            loadingTest.value = false
        }, 800)
    })
}
// 获取地址搜索结果
const getAddressList = () => {
    searchWithNewAPI()
}
const tooltipText = computed(() => {
    if (loadingTest.value) {
        return ''
    }
    return finishedText.value || ''
})
// input对应下拉数据初始化
const inputSelect = () => {
    list.value = []
    finished.value = false
    loadingTest.value = true
    EventBus.emit('mapClearMarker')
    getAddressList()
}
// 输入框input事件
const handlerInput = _.debounce(() => {
    inputSelect()
}, 300)
// 输入框clear事件
const handlerClear = () => {
    EventBus.emit('mapClearAirMarker')
    // 请求接口查全部
    getAddressList()
}
const flyToAddress = item => {
    // if (!item.location) {
    //     showToast('当前地址无坐标信息')
    //     return
    // }
    // EventBus.emit('mapClearMarker')
    // const location = typeof item.location === 'string'
    //     ? item.location.split(',').map(Number)
    //     : [item.location.lng, item.location.lat];
    // const [longitude, latitude] = gcj02ToWgs84(location[0], location[1])
    // height.value = anchors[0]
    // searchVal.value = item.name
    // EventBus.emit('mapAddMarker', {
    //     lat: latitude,
    //     lng: longitude,
    //     name: searchVal.value,
    //     customClassName: 'address-marker',
    // })
    EventBus.emit('signFlyToMarker', item)
}
watch(
    () => route.query,
    (newValue, oldValue) => {
        if (newValue.updateKey) {
            height.value = anchors[0]
        }
    },
    { deep: true }
)
onMounted(() => {
    const hash = window.location.hash.slice(1)
    const [hashPath, hashParamsStr] = hash.split('?')
    if (hashParamsStr) {
        const urlParams = new URLSearchParams(hashParamsStr)
        const isWebParam = urlParams.get('isWeb')
        if (isWebParam !== null) {
            isWeb.value = isWebParam === 'true'
        }
    }
    getAddressList()
})
</script>
<style lang="scss" scoped>
.van-floating-panel {
    background: transparent;
    ::v-deep(.custom-header) {
        // border: 2px solid red;
        .bar {
            margin: 0 auto;
            width: 42px;
            height: 4px;
            background: rgba(0, 0, 0, 0.5);
            border-radius: 2px;
        }
        .van-field {
            margin: 0 8px;
            margin-top: 4px;
            padding: 0 12px !important;
            display: flex;
            align-items: center;
            position: sticky;
            top: 0;
            width: calc(100% - 16px);
            height: 44px;
            background: #fff;
            box-sizing: border-box;
            z-index: 9;
            border-radius: 8px;
            box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.05);
            .search-left-box,
            .search-right-box {
                display: flex;
                align-items: center;
                justify-content: space-between;
                .search-type {
                    margin: 0 4px;
                    color: #282828;
                }
            }
        }
    }
    ::v-deep(.van-floating-panel__content) {
        margin-top: -4px;
        position: relative;
        background: #f1f1f1;
        box-shadow: 0 -20px 20px #f1f1f1;
        .van-list {
            background: white;
            .van-cell {
                background: white;
            }
        }
        .list-tooltip {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            color: #000;
        }
    }
    .list-item {
        padding: 12px;
        border-bottom: 1px solid #e5e5e5;
        font-family: Source Han Sans CN, Source Han Sans CN;
        .name {
            font-weight: bold;
            font-size: 16px;
            color: #222324;
        }
        .item {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .laber {
            font-weight: 400;
            font-size: 15px;
            color: #222324;
        }
        .value {
            font-weight: 400;
            font-size: 14px;
            color: #7B7B7B;
        }
    }
    :deep(.van-loading) {
        text-align: center;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        text-align: center;
        color: #000;
    }
}
</style>