| | |
| | | <template> |
| | | <div class="searchBox" ref="searchBoxRef"> |
| | | <div class="searchInput"> |
| | | <el-select v-model="optionsValue" @change="optionChange" placeholder="请选择查询"> |
| | | <el-option |
| | | v-for="item in options" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | <div class="searchBox" ref="searchBoxRef"> |
| | | <div class="searchInput"> |
| | | <el-select v-model="optionsValue" @change="optionChange" placeholder="请选择查询"> |
| | | <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | |
| | | <el-input v-model="searchKey" @focus="handleFocus" placeholder="请输入搜索关键字"></el-input> |
| | | </div> |
| | | <div class="searchBtn" @click="searchClick"></div> |
| | | <div class="region"> |
| | | <el-tree-select |
| | | v-model="treeValue" |
| | | check-strictly |
| | | lazy |
| | | :load="load" |
| | | :props="props" |
| | | style="width: 240px" |
| | | @node-click="handleNodeClick" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="select-down-list" ref="selectDownRef" v-show="isSelectDown"> |
| | | <div class="item" v-for="item in downList" @click="selectedValue(item)">{{ item.nickname || item.name }}</div> |
| | | </div> |
| | | <el-input |
| | | v-model="searchKey" |
| | | @input="handlerInput" |
| | | @focus="handleFocus" |
| | | placeholder="请输入搜索关键字" |
| | | ></el-input> |
| | | </div> |
| | | <div class="searchBtn" @click="searchClick"></div> |
| | | <div class="region"> |
| | | <el-tree-select |
| | | v-model="treeValue" |
| | | check-strictly |
| | | lazy |
| | | :load="load" |
| | | :props="props" |
| | | style="width: 240px" |
| | | @node-click="handleNodeClick" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="select-down-list" ref="selectDownRef" v-show="isSelectDown"> |
| | | <div class="item" v-for="item in downList" @click="selectedValue(item)">{{ item.nickname || item.name }}</div> |
| | | </div> |
| | | </template> |
| | | <script setup> |
| | | import { getRegion } from '@/api/home'; |
| | | import { searchByKeyword, selectDeviceList } from '@/api/home/common'; |
| | | import { useStore } from 'vuex'; |
| | | import _ from 'lodash' |
| | | import { getRegion } from '@/api/home' |
| | | import { searchByKeyword, selectDeviceList } from '@/api/home/common' |
| | | import { useStore } from 'vuex' |
| | | import cesiumOperation from '@/utils/cesium-tsa' |
| | | |
| | | const { flyTo } = cesiumOperation() |
| | | |
| | | const store = useStore(); |
| | | const searchKey = ref(''); |
| | | const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode); |
| | | const selectedAreaCode = computed(() => store.state.user.selectedAreaCode); |
| | | const areaValue = ref('江西省'); |
| | | const treeValue = ref(userAreaCode.value); |
| | | let first = true; |
| | | const searchBoxRef = ref(null); |
| | | const selectDownRef = ref(null); |
| | | const store = useStore() |
| | | const searchKey = ref('') |
| | | const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode) |
| | | const selectedAreaCode = computed(() => store.state.user.selectedAreaCode) |
| | | const areaValue = ref('江西省') |
| | | const treeValue = ref(userAreaCode.value) |
| | | let first = true |
| | | const searchBoxRef = ref(null) |
| | | const selectDownRef = ref(null) |
| | | |
| | | function handleNodeClick(data) { |
| | | areaValue.value = data.name; |
| | | store.commit('setSelectedAreaCode', data.code); |
| | | areaValue.value = data.name |
| | | store.commit('setSelectedAreaCode', data.code) |
| | | } |
| | | |
| | | const props = { |
| | | label: 'name', |
| | | value: 'code', |
| | | children: 'children', |
| | | }; |
| | | label: 'name', |
| | | value: 'code', |
| | | children: 'children', |
| | | } |
| | | const load = async (node, resolve) => { |
| | | if (first) { |
| | | first = false; |
| | | const res = await getRegion(userAreaCode.value); |
| | | const { provinceCode, provinceName } = res?.data?.data?.[0] || {}; |
| | | resolve([{ code: provinceCode, name: provinceName }]); |
| | | return; |
| | | } |
| | | const code = node?.data?.code || userAreaCode.value; |
| | | if ((node?.data?.regionLevel || 0) > 2) return resolve([]); |
| | | getRegion(code).then(res => { |
| | | resolve(res?.data?.data || []); |
| | | }); |
| | | }; |
| | | if (first) { |
| | | first = false |
| | | const res = await getRegion(userAreaCode.value) |
| | | const { provinceCode, provinceName } = res?.data?.data?.[0] || {} |
| | | resolve([{ code: provinceCode, name: provinceName }]) |
| | | return |
| | | } |
| | | const code = node?.data?.code || userAreaCode.value |
| | | if ((node?.data?.regionLevel || 0) > 2) return resolve([]) |
| | | getRegion(code).then(res => { |
| | | resolve(res?.data?.data || []) |
| | | }) |
| | | } |
| | | |
| | | const optionsValue = ref('1'); |
| | | const optionsValue = ref('1') |
| | | const options = [ |
| | | { |
| | | value: '1', |
| | | label: '机巢', |
| | | }, |
| | | { |
| | | value: '2', |
| | | label: '地址', |
| | | }, |
| | | ]; |
| | | { |
| | | value: '1', |
| | | label: '机巢', |
| | | }, |
| | | { |
| | | value: '2', |
| | | label: '地址', |
| | | }, |
| | | ] |
| | | |
| | | const isSelectDown = ref(false); |
| | | // 下拉数据列表 |
| | | const machineNestList = ref([]); |
| | | const isSelectDown = ref(false) |
| | | |
| | | // 地址搜索结果 |
| | | const downList = ref([]); |
| | | const position = ref({}); |
| | | const downList = ref([]) |
| | | const position = ref({}) |
| | | |
| | | // 获取机巢搜索结果 |
| | | const getDeviceList = async () => { |
| | | const res = await selectDeviceList({nickname: searchKey.value}); |
| | | if (res.data.code !== 0) return; |
| | | machineNestList.value = res?.data?.data || []; |
| | | downList.value = res?.data?.data || []; |
| | | }; |
| | | const res = await selectDeviceList({ nickname: searchKey.value }) |
| | | if (res.data.code !== 0) return |
| | | downList.value = res?.data?.data || [] |
| | | } |
| | | // 获取地址搜索结果 |
| | | const getAddressList = async () => { |
| | | const res = await searchByKeyword(encodeURIComponent(`${areaValue.value}+${searchKey.value}`)); |
| | | if (res.data.code !== 0) return; |
| | | downList.value = res?.data?.data.tips || []; |
| | | if (downList.value.length > 0) { |
| | | isSelectDown.value = true; |
| | | } |
| | | }; |
| | | const res = await searchByKeyword(encodeURIComponent(`${areaValue.value}+${searchKey.value}`)) |
| | | if (res.data.code !== 0) return |
| | | downList.value = res?.data?.data.tips || [] |
| | | if (downList.value.length > 0) { |
| | | isSelectDown.value = true |
| | | } |
| | | } |
| | | // 搜索结果 |
| | | const searchClick = () => { |
| | | const longitude = Number(position.value.longitude) |
| | | const latitude = Number(position.value.latitude) |
| | | flyTo({ longitude, latitude }, 1, 1000) |
| | | }; |
| | | } |
| | | |
| | | // 地址和机巢的切换 |
| | | const optionChange = () => { |
| | | searchKey.value = ''; |
| | | downList.value = []; |
| | | }; |
| | | searchKey.value = '' |
| | | downList.value = [] |
| | | |
| | | inputSelect() |
| | | } |
| | | |
| | | // input对应下拉数据初始化 |
| | | const inputSelect = () => { |
| | | if (optionsValue.value === '2') { |
| | | getAddressList() |
| | | } else { |
| | | getDeviceList() |
| | | } |
| | | } |
| | | |
| | | inputSelect() |
| | | |
| | | // 输入框input事件 |
| | | const handlerInput = _.debounce(inputSelect, 1000) |
| | | |
| | | // 输入框获取焦点 |
| | | const handleFocus = () => { |
| | | if (optionsValue.value === '1') { |
| | | isSelectDown.value = true; |
| | | downList.value = machineNestList.value; |
| | | } |
| | | }; |
| | | isSelectDown.value = true |
| | | } |
| | | // 机巢下拉获取值 |
| | | const selectedValue = item => { |
| | | searchKey.value = item.nickname || item.name; |
| | | if (optionsValue.value === '1') { |
| | | position.value = item; |
| | | } else { |
| | | position.value = { longitude: item.location.split(',')[0], latitude: item.location.split(',')[1] }; |
| | | } |
| | | |
| | | isSelectDown.value = false; |
| | | }; |
| | | searchKey.value = item.nickname || item.name |
| | | if (optionsValue.value === '1') { |
| | | position.value = item |
| | | } else { |
| | | position.value = { longitude: item.location.split(',')[0], latitude: item.location.split(',')[1] } |
| | | } |
| | | |
| | | // 监听搜索关键字变化 |
| | | watch(searchKey, async (newVal) => { |
| | | if (optionsValue.value === '2') { |
| | | await getAddressList(); |
| | | } else { |
| | | await getDeviceList(); |
| | | } |
| | | }, { immediate: false }); |
| | | isSelectDown.value = false |
| | | } |
| | | |
| | | onMounted(() => { |
| | | document.addEventListener('click', handleClickOutside); |
| | | }); |
| | | document.addEventListener('click', handleClickOutside) |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | document.removeEventListener('click', handleClickOutside); |
| | | }); |
| | | document.removeEventListener('click', handleClickOutside) |
| | | }) |
| | | |
| | | const handleClickOutside = (event) => { |
| | | if (!searchBoxRef.value?.contains(event.target) && !selectDownRef.value?.contains(event.target)) { |
| | | isSelectDown.value = false; |
| | | } |
| | | }; |
| | | const handleClickOutside = event => { |
| | | if (!searchBoxRef.value?.contains(event.target) && !selectDownRef.value?.contains(event.target)) { |
| | | isSelectDown.value = false |
| | | } |
| | | } |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .select-down-list { |
| | | position: absolute; |
| | | top: 188px; |
| | | left: 44%; |
| | | transform: translateX(-40%); |
| | | width: 220px; |
| | | height: 256px; |
| | | overflow-y: auto; |
| | | background: linear-gradient( 180deg, #0D3556 0%, #012350 100%); |
| | | border-radius: 0px 0px 8px 8px; |
| | | border: 1px solid; |
| | | border-image: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(115, 192, 255, 1)) 1 1; |
| | | opacity: 0.8; |
| | | &::-webkit-scrollbar { |
| | | width: 0; |
| | | display: none; |
| | | } |
| | | -ms-overflow-style: none; /* IE and Edge */ |
| | | scrollbar-width: none; /* Firefox */ |
| | | .item { |
| | | color: #FFFFFF; |
| | | height: 32px; |
| | | line-height: 32px; |
| | | text-align: center; |
| | | cursor: pointer; |
| | | &:hover { |
| | | background: linear-gradient( 90deg, rgba(0,122,255,0) 0%, rgba(0,98,204,0.6) 50%, rgba(0,73,153,0) 100%); |
| | | border: 1px solid; |
| | | border-image: linear-gradient(90deg, rgba(0, 199, 190, 0), rgba(48, 176, 199, 1), rgba(0, 199, 190, 0)) 1 1; |
| | | } |
| | | } |
| | | position: absolute; |
| | | top: 188px; |
| | | left: 44%; |
| | | transform: translateX(-40%); |
| | | width: 220px; |
| | | height: 256px; |
| | | overflow-y: auto; |
| | | background: linear-gradient(180deg, #0d3556 0%, #012350 100%); |
| | | border-radius: 0px 0px 8px 8px; |
| | | border: 1px solid; |
| | | border-image: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(115, 192, 255, 1)) 1 1; |
| | | opacity: 0.8; |
| | | &::-webkit-scrollbar { |
| | | width: 0; |
| | | display: none; |
| | | } |
| | | -ms-overflow-style: none; /* IE and Edge */ |
| | | scrollbar-width: none; /* Firefox */ |
| | | .item { |
| | | color: #ffffff; |
| | | height: 32px; |
| | | line-height: 32px; |
| | | text-align: center; |
| | | cursor: pointer; |
| | | &:hover { |
| | | background: linear-gradient(90deg, rgba(0, 122, 255, 0) 0%, rgba(0, 98, 204, 0.6) 50%, rgba(0, 73, 153, 0) 100%); |
| | | border: 1px solid; |
| | | border-image: linear-gradient(90deg, rgba(0, 199, 190, 0), rgba(48, 176, 199, 1), rgba(0, 199, 190, 0)) 1 1; |
| | | } |
| | | } |
| | | } |
| | | .searchBox { |
| | | width: 420px; |
| | | height: 43px; |
| | | position: absolute; |
| | | top: 145px; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | display: flex; |
| | | width: 420px; |
| | | height: 43px; |
| | | position: absolute; |
| | | top: 145px; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | display: flex; |
| | | |
| | | .el-select { |
| | | width: 130px; |
| | | height: 100%; |
| | | .el-select { |
| | | width: 130px; |
| | | height: 100%; |
| | | |
| | | :deep() { |
| | | .el-select__wrapper { |
| | | background: transparent; |
| | | border: none; |
| | | box-shadow: none; |
| | | height: 100%; |
| | | padding-left: 20px; |
| | | } |
| | | :deep() { |
| | | .el-select__wrapper { |
| | | background: transparent; |
| | | border: none; |
| | | box-shadow: none; |
| | | height: 100%; |
| | | padding-left: 20px; |
| | | } |
| | | |
| | | .el-select__selected-item { |
| | | font-family: Source Han Sans CN, Source Han Sans CN, serif; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #ffffff; |
| | | line-height: 18px; |
| | | } |
| | | } |
| | | } |
| | | .el-select__selected-item { |
| | | font-family: Source Han Sans CN, Source Han Sans CN, serif; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #ffffff; |
| | | line-height: 18px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .searchInput { |
| | | width: 243px; |
| | | height: 100%; |
| | | background: url('@/assets/images/home/searchBox/searchBg1.png') no-repeat center / 100% 100%; |
| | | display: flex; |
| | | .searchInput { |
| | | width: 243px; |
| | | height: 100%; |
| | | background: url('@/assets/images/home/searchBox/searchBg1.png') no-repeat center / 100% 100%; |
| | | display: flex; |
| | | |
| | | .el-input { |
| | | height: 100%; |
| | | .el-input { |
| | | height: 100%; |
| | | |
| | | :deep() { |
| | | .el-input__wrapper { |
| | | background: transparent; |
| | | border: none; |
| | | box-shadow: none; |
| | | height: 100%; |
| | | } |
| | | :deep() { |
| | | .el-input__wrapper { |
| | | background: transparent; |
| | | border: none; |
| | | box-shadow: none; |
| | | height: 100%; |
| | | } |
| | | |
| | | .el-input__inner { |
| | | font-family: Source Han Sans CN, Source Han Sans CN, serif; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #ffffff; |
| | | line-height: 18px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .el-input__inner { |
| | | font-family: Source Han Sans CN, Source Han Sans CN, serif; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #ffffff; |
| | | line-height: 18px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .searchBtn { |
| | | width: 67px; |
| | | height: 100%; |
| | | background: url('@/assets/images/home/searchBox/searchBg2.png') no-repeat center / 100% 100%; |
| | | cursor: pointer; |
| | | } |
| | | .searchBtn { |
| | | width: 67px; |
| | | height: 100%; |
| | | background: url('@/assets/images/home/searchBox/searchBg2.png') no-repeat center / 100% 100%; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .region { |
| | | width: 0; |
| | | flex-grow: 1; |
| | | background: url('@/assets/images/home/searchBox/searchBg3.png') no-repeat center / 100% 100%; |
| | | .region { |
| | | width: 0; |
| | | flex-grow: 1; |
| | | background: url('@/assets/images/home/searchBox/searchBg3.png') no-repeat center / 100% 100%; |
| | | |
| | | :deep() { |
| | | .el-select__wrapper { |
| | | width: 100px; |
| | | padding-left: 20px; |
| | | } |
| | | } |
| | | } |
| | | :deep() { |
| | | .el-select__wrapper { |
| | | width: 100px; |
| | | padding-left: 20px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |