Commit c8eb67f749aa9fdf67cd86d01a20c01be91ef8c3
1 parent
88906aca
feat(src/packages): 图表高德地图新增右上角弹窗筛选
Showing
4 changed files
with
242 additions
and
6 deletions
@@ -10,7 +10,9 @@ enum Api { | @@ -10,7 +10,9 @@ enum Api { | ||
10 | CONFIGURATION = '/configuration/center', | 10 | CONFIGURATION = '/configuration/center', |
11 | CONFIGURATION_SHARE = '/configuration/center/share/', | 11 | CONFIGURATION_SHARE = '/configuration/center/share/', |
12 | BASEORIGINATION = '/organization/me/list/', | 12 | BASEORIGINATION = '/organization/me/list/', |
13 | - VIDEO = '/video/list' | 13 | + VIDEO = '/video/list', |
14 | + DEVICE_PROFILE = '/device_profile/me/list', | ||
15 | + DEVICE = '/device' | ||
14 | } | 16 | } |
15 | 17 | ||
16 | export const getDictItemByCode = (value: string) => { | 18 | export const getDictItemByCode = (value: string) => { |
@@ -77,8 +79,23 @@ export const getOrganizationList = (params?: OrganizationListItem) => | @@ -77,8 +79,23 @@ export const getOrganizationList = (params?: OrganizationListItem) => | ||
77 | }) | 79 | }) |
78 | 80 | ||
79 | //获取视频列表 | 81 | //获取视频列表 |
80 | -export const getVideoList = (params?:object) => | 82 | +export const getVideoList = (params?: object) => |
81 | defHttp.get({ | 83 | defHttp.get({ |
82 | url: Api.VIDEO, | 84 | url: Api.VIDEO, |
83 | params | 85 | params |
84 | }) | 86 | }) |
87 | + | ||
88 | +//获取产品列表 | ||
89 | +export const getProfileList = (params?: object) => | ||
90 | + defHttp.get({ | ||
91 | + url: Api.DEVICE_PROFILE, | ||
92 | + params | ||
93 | + }) | ||
94 | + | ||
95 | +//获取设备列表 | ||
96 | +export const getDeviceList = (params: any, data?: object) => | ||
97 | + defHttp.post({ | ||
98 | + url: Api.DEVICE, | ||
99 | + params, | ||
100 | + data | ||
101 | + }) |
1 | +<template> | ||
2 | + <n-drawer display-directive="if" :show="modelShow" :width="502" :placement="placement"> | ||
3 | + <n-drawer-content title="设备筛选"> | ||
4 | + <n-space vertical> | ||
5 | + <span>组织</span> | ||
6 | + <n-tree-select | ||
7 | + placement="top-start" | ||
8 | + label-field="name" | ||
9 | + v-model:value="searchParams.organizationId" | ||
10 | + key-field="id" | ||
11 | + children-field="children" | ||
12 | + :options="originationOption" | ||
13 | + /> | ||
14 | + <span>产品</span> | ||
15 | + <n-select v-model:value="searchParams.deviceProfileIds" :options="deviceProfileOption" /> | ||
16 | + <span>设备</span> | ||
17 | + <n-input v-model:value="searchParams.name" type="text" placeholder="请输入设备名称" /> | ||
18 | + <span>设备状态</span> | ||
19 | + <n-radio-group v-model:value="searchParams.deviceState" name="radiogroup"> | ||
20 | + <n-space> | ||
21 | + <n-radio v-for="(item, index) in deviceStateGroup" :key="index" :value="item.value"> | ||
22 | + {{ item.label }} | ||
23 | + </n-radio> | ||
24 | + </n-space> | ||
25 | + </n-radio-group> | ||
26 | + <span>是否告警</span> | ||
27 | + <n-radio-group v-model:value="searchParams.alarmStatus" name="radiogroup"> | ||
28 | + <n-space> | ||
29 | + <n-radio v-for="(item, index) in alarmStatusGroup" :key="index" :value="item.value"> | ||
30 | + {{ item.label }} | ||
31 | + </n-radio> | ||
32 | + </n-space> | ||
33 | + </n-radio-group> | ||
34 | + <span>配置查询分页</span> | ||
35 | + <n-space justify="space-between"> | ||
36 | + <n-input-number :min="1" v-model:value="searchPage.page" clearable /> | ||
37 | + <n-input-number :step="10" :min="10" v-model:value="searchPage.pageSize" clearable /> | ||
38 | + </n-space> | ||
39 | + </n-space> | ||
40 | + <template #footer> | ||
41 | + <n-button @click="handleCancel" type="tertiary">取消</n-button> | ||
42 | + <div style="visibility: hidden; width: 10px">占位</div> | ||
43 | + <n-button @click="handleSubmit" type="success">确定</n-button> | ||
44 | + </template> | ||
45 | + </n-drawer-content> | ||
46 | + </n-drawer> | ||
47 | +</template> | ||
48 | + | ||
49 | +<script lang="ts" setup> | ||
50 | +import { ref, onMounted, reactive } from 'vue' | ||
51 | +import { NTreeSelect } from 'naive-ui' | ||
52 | +import { getOrganizationList, getProfileList } from '@/api/external/common/index' | ||
53 | + | ||
54 | +interface searchParamsInterface { | ||
55 | + organizationId: string | null | ||
56 | + deviceProfileIds: null | ||
57 | + name: string | ||
58 | + deviceState: string | null | ||
59 | + alarmStatus: number | ||
60 | +} | ||
61 | + | ||
62 | +defineProps({ | ||
63 | + modelShow: Boolean | ||
64 | +}) | ||
65 | + | ||
66 | +const emit = defineEmits(['searchParams', 'closeDrawer']) | ||
67 | + | ||
68 | +const placement = ref('right') | ||
69 | + | ||
70 | +//设备状态 | ||
71 | +const deviceStateGroup = [ | ||
72 | + { | ||
73 | + label: '全部', | ||
74 | + value: null | ||
75 | + }, | ||
76 | + { | ||
77 | + label: '待激活', | ||
78 | + value: 'INACTIVE' | ||
79 | + }, | ||
80 | + { | ||
81 | + label: '在线', | ||
82 | + value: 'ONLINE' | ||
83 | + }, | ||
84 | + { | ||
85 | + label: '离线', | ||
86 | + value: 'OFFLINE' | ||
87 | + } | ||
88 | +] | ||
89 | + | ||
90 | +//告警状态 | ||
91 | +const alarmStatusGroup = [ | ||
92 | + { | ||
93 | + label: '是', | ||
94 | + value: 1 | ||
95 | + }, | ||
96 | + { | ||
97 | + label: '否', | ||
98 | + value: 0 | ||
99 | + } | ||
100 | +] | ||
101 | + | ||
102 | +const searchPage = reactive<{ page: number; pageSize: number }>({ | ||
103 | + page: 1, | ||
104 | + pageSize: 10 | ||
105 | +}) | ||
106 | + | ||
107 | +const searchParams = reactive<searchParamsInterface>({ | ||
108 | + organizationId: null, | ||
109 | + deviceProfileIds: null, | ||
110 | + name: '', | ||
111 | + deviceState: null, | ||
112 | + alarmStatus: 0 | ||
113 | +}) | ||
114 | + | ||
115 | +const originationOption = ref([]) | ||
116 | + | ||
117 | +const deviceProfileOption = ref([]) | ||
118 | + | ||
119 | +const loadList = async () => { | ||
120 | + const resOrganization = await getOrganizationList() | ||
121 | + const resProfileList = await getProfileList() | ||
122 | + Promise.all([resOrganization, resProfileList]).then(res => { | ||
123 | + originationOption.value = res[0] | ||
124 | + deviceProfileOption.value = res[1].map((item: { name: string; tbProfileId: string }) => ({ | ||
125 | + label: item.name, | ||
126 | + value: item.tbProfileId | ||
127 | + })) | ||
128 | + }) | ||
129 | +} | ||
130 | + | ||
131 | +const handleSubmit = () => { | ||
132 | + searchParams.deviceProfileIds = [searchParams.deviceProfileIds] as any | ||
133 | + emit('searchParams', searchPage, searchParams) | ||
134 | + handleCancel() | ||
135 | +} | ||
136 | + | ||
137 | +const handleCancel = () => { | ||
138 | + for (let i in searchParams) Reflect.set(searchParams, i, null) | ||
139 | + searchParams.name = '' | ||
140 | + searchParams.alarmStatus = 0 | ||
141 | + searchPage.page = 1 | ||
142 | + searchPage.pageSize = 10 | ||
143 | + emit('closeDrawer') | ||
144 | +} | ||
145 | + | ||
146 | +onMounted(() => { | ||
147 | + loadList() | ||
148 | +}) | ||
149 | +</script> | ||
150 | + | ||
151 | +<style lang="scss" scoped></style> |
@@ -11,6 +11,30 @@ export type dataJsonType = typeof dataJson //data.json类型 | @@ -11,6 +11,30 @@ export type dataJsonType = typeof dataJson //data.json类型 | ||
11 | 11 | ||
12 | export type dataJsonMarkersType = typeof dataJson.markers[number] //data.json markers类型 | 12 | export type dataJsonMarkersType = typeof dataJson.markers[number] //data.json markers类型 |
13 | 13 | ||
14 | +//标注数据格式 | ||
15 | +export const fileterDevice = (items: any) => { | ||
16 | + const values = items.reduce((acc: any, curr: any) => { | ||
17 | + acc.push({ | ||
18 | + name: curr.alias, | ||
19 | + value: 10, | ||
20 | + position: [curr.deviceInfo.longitude, curr.deviceInfo.latitude], | ||
21 | + extraInfo: { | ||
22 | + tbDeviceId: curr.tbDeviceId, | ||
23 | + name: curr.name, | ||
24 | + alias: curr.alias, | ||
25 | + organizationDTO: curr.organizationDTO, | ||
26 | + deviceState: curr.deviceState, | ||
27 | + deviceProfile: curr.deviceProfile, | ||
28 | + deviceInfo: curr.deviceInfo | ||
29 | + } | ||
30 | + }) | ||
31 | + return [...acc] | ||
32 | + }, []) | ||
33 | + return { | ||
34 | + markers: values | ||
35 | + } | ||
36 | +} | ||
37 | + | ||
14 | export enum ThemeEnum { | 38 | export enum ThemeEnum { |
15 | NORMAL = 'normal', | 39 | NORMAL = 'normal', |
16 | DARK = 'dark', | 40 | DARK = 'dark', |
1 | <template> | 1 | <template> |
2 | - <div ref="vChartRef"></div> | 2 | + <div @mouseenter="handleMouseenter" @mouseleave="handleMouseleave" class="chart-amap" ref="vChartRef"> |
3 | + <div v-if="showSearchBox" @click.stop="handleOpenSearchBox" class="search-box"></div> | ||
4 | + <search-box :modelShow="modelShow" @searchParams="handleSearchParams" @closeDrawer="handleCloseDrawer"></search-box> | ||
5 | + </div> | ||
3 | </template> | 6 | </template> |
4 | 7 | ||
5 | <script setup lang="ts"> | 8 | <script setup lang="ts"> |
@@ -8,13 +11,14 @@ import AMapLoader from '@amap/amap-jsapi-loader' | @@ -8,13 +11,14 @@ import AMapLoader from '@amap/amap-jsapi-loader' | ||
8 | import { CreateComponentType } from '@/packages/index.d' | 11 | import { CreateComponentType } from '@/packages/index.d' |
9 | import { useChartDataFetch } from '@/hooks' | 12 | import { useChartDataFetch } from '@/hooks' |
10 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | 13 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
11 | -import { MarkerEnum, ThemeEnum, dataExtraInfoType, dataJsonType, dataJsonMarkersType } from './config' | 14 | +import { MarkerEnum, ThemeEnum, dataExtraInfoType, dataJsonType, dataJsonMarkersType, fileterDevice } from './config' |
12 | import { isArray } from '@/utils' | 15 | import { isArray } from '@/utils' |
13 | import djh from './images/djh.png' | 16 | import djh from './images/djh.png' |
14 | import online from './images/online.png' | 17 | import online from './images/online.png' |
15 | import lx1 from './images/lx1.png' | 18 | import lx1 from './images/lx1.png' |
16 | -import { getDeviceActiveTime } from '@/api/external/common/index' | 19 | +import { getDeviceActiveTime, getDeviceList } from '@/api/external/common/index' |
17 | import dayjs from 'dayjs' | 20 | import dayjs from 'dayjs' |
21 | +import SearchBox from './components/SearchBox.vue' | ||
18 | 22 | ||
19 | const props = defineProps({ | 23 | const props = defineProps({ |
20 | chartConfig: { | 24 | chartConfig: { |
@@ -23,6 +27,10 @@ const props = defineProps({ | @@ -23,6 +27,10 @@ const props = defineProps({ | ||
23 | } | 27 | } |
24 | }) | 28 | }) |
25 | 29 | ||
30 | +const modelShow = ref(false) | ||
31 | + | ||
32 | +const showSearchBox = ref(false) | ||
33 | + | ||
26 | let { | 34 | let { |
27 | amapKey, | 35 | amapKey, |
28 | amapStyleKey, | 36 | amapStyleKey, |
@@ -126,6 +134,25 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => { | @@ -126,6 +134,25 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => { | ||
126 | } | 134 | } |
127 | } | 135 | } |
128 | 136 | ||
137 | +const handleMouseenter = () => (showSearchBox.value = true) | ||
138 | + | ||
139 | +const handleMouseleave = () => (showSearchBox.value = false) | ||
140 | + | ||
141 | +const handleOpenSearchBox = () => (modelShow.value = true) | ||
142 | + | ||
143 | +const handleCloseDrawer = () => (modelShow.value = false) | ||
144 | + | ||
145 | +const handleSearchParams = async (searchPage: any, params: any) => { | ||
146 | + try { | ||
147 | + const { items } = await getDeviceList(searchPage, params) | ||
148 | + const values = fileterDevice(items) | ||
149 | + if (!values) return | ||
150 | + dataHandle(values) | ||
151 | + } finally { | ||
152 | + handleCloseDrawer() | ||
153 | + } | ||
154 | +} | ||
155 | + | ||
129 | //地图点击 | 156 | //地图点击 |
130 | const mapClick = (markerInstance: any, markerItem: dataJsonMarkersType) => { | 157 | const mapClick = (markerInstance: any, markerItem: dataJsonMarkersType) => { |
131 | markerInstance.setExtData({ | 158 | markerInstance.setExtData({ |
@@ -178,7 +205,7 @@ const dataHandle = (newData: dataJsonType) => { | @@ -178,7 +205,7 @@ const dataHandle = (newData: dataJsonType) => { | ||
178 | // markers.push(markerInstance) //原作者这种方式添加,属于JS API 1.4.8版本的 | 205 | // markers.push(markerInstance) //原作者这种方式添加,属于JS API 1.4.8版本的 |
179 | // markerInstance.setMap(mapIns) | 206 | // markerInstance.setMap(mapIns) |
180 | mapIns.add(markerInstance) | 207 | mapIns.add(markerInstance) |
181 | - mapClick(markerInstance, markerItem) | 208 | + mapClick(markerInstance, markerItem) // circle点击无效 |
182 | }) | 209 | }) |
183 | } | 210 | } |
184 | } | 211 | } |
@@ -215,3 +242,20 @@ useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => { | @@ -215,3 +242,20 @@ useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => { | ||
215 | dataHandle(newData) | 242 | dataHandle(newData) |
216 | }) | 243 | }) |
217 | </script> | 244 | </script> |
245 | + | ||
246 | +<style lang="scss" scoped> | ||
247 | +.chart-amap { | ||
248 | + position: relative; | ||
249 | + .search-box { | ||
250 | + cursor: pointer; | ||
251 | + position: absolute; | ||
252 | + right: -25px; | ||
253 | + top: 15px; | ||
254 | + z-index: 9999; | ||
255 | + width: 50px; | ||
256 | + height: 50px; | ||
257 | + border-radius: 50%; | ||
258 | + background-color: rgba(255, 255, 255, 0.2); | ||
259 | + } | ||
260 | +} | ||
261 | +</style> |