Commit edef147b3f2154a933ee65078f680ab988d455a1
Merge branch 'sqy_dev' into 'main'
feat:地理位置完成,首页条件判断完成,接口待调试,设备修改字段。 See merge request huang/yun-teng-iot-front!64
Showing
17 changed files
with
389 additions
and
216 deletions
... | ... | @@ -30,3 +30,14 @@ export const getDeviceDataKeys = (id: string) => { |
30 | 30 | } |
31 | 31 | ); |
32 | 32 | }; |
33 | +// 获取设备状态,在线 or 离线时间 | |
34 | +export const getDeviceActiveTime = (entityId: string) => { | |
35 | + return defHttp.get( | |
36 | + { | |
37 | + url: `/plugins/telemetry/DEVICE/${entityId}/values/attributes?keys=active`, | |
38 | + }, | |
39 | + { | |
40 | + joinPrefix: false, | |
41 | + } | |
42 | + ); | |
43 | +}; | ... | ... |
src/api/dashboard/index.ts
0 → 100644
src/assets/images/kf.png
0 → 100644
1.1 KB
src/assets/images/zh.png
0 → 100644
1.45 KB
... | ... | @@ -34,8 +34,16 @@ |
34 | 34 | :canFullscreen="false" |
35 | 35 | > |
36 | 36 | <BasicForm @register="registerForm" /> |
37 | - <div ref="chartRef" :style="{ height: '600px', width }"></div> | |
37 | + <Alert | |
38 | + v-if="!isNull" | |
39 | + message="当前时间节点暂无历史数据" | |
40 | + description="请尝试选择其他时间段查询历史数据" | |
41 | + type="warning" | |
42 | + show-icon | |
43 | + /> | |
44 | + <div v-show="isNull" ref="chartRef" :style="{ height: '600px', width }"></div> | |
38 | 45 | </BasicModal> |
46 | + <DeviceDetailDrawer @register="registerDetailDrawer" /> | |
39 | 47 | </div> |
40 | 48 | </template> |
41 | 49 | <script lang="ts"> |
... | ... | @@ -44,22 +52,30 @@ |
44 | 52 | import { formSchema, columns } from './config.data'; |
45 | 53 | import { BasicTable, useTable } from '/@/components/Table'; |
46 | 54 | import { devicePage } from '/@/api/alarm/contact/alarmContact'; |
47 | - import { Tag } from 'ant-design-vue'; | |
55 | + import { Tag, Alert } from 'ant-design-vue'; | |
48 | 56 | import { DeviceState } from '/@/api/device/model/deviceModel'; |
49 | 57 | import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; |
50 | 58 | import { useModal, BasicModal } from '/@/components/Modal'; |
51 | 59 | import { BasicForm, useForm } from '/@/components/Form'; |
52 | 60 | import { schemas } from './config.data'; |
53 | 61 | import { useECharts } from '/@/hooks/web/useECharts'; |
54 | - import { getDeviceHistoryInfo, getDeviceDataKeys } from '/@/api/alarm/position'; | |
62 | + import { | |
63 | + getDeviceHistoryInfo, | |
64 | + getDeviceDataKeys, | |
65 | + getDeviceActiveTime, | |
66 | + } from '/@/api/alarm/position'; | |
67 | + import { useDrawer } from '/@/components/Drawer'; | |
68 | + import DeviceDetailDrawer from '/@/views/device/manage/cpns/modal/DeviceDetailDrawer.vue'; | |
55 | 69 | import moment from 'moment'; |
56 | 70 | export default defineComponent({ |
57 | 71 | name: 'BaiduMap', |
58 | 72 | components: { |
59 | 73 | BasicTable, |
60 | 74 | Tag, |
75 | + Alert, | |
61 | 76 | BasicModal, |
62 | 77 | BasicForm, |
78 | + DeviceDetailDrawer, | |
63 | 79 | }, |
64 | 80 | props: { |
65 | 81 | width: { |
... | ... | @@ -74,7 +90,10 @@ |
74 | 90 | setup() { |
75 | 91 | const wrapRef = ref<HTMLDivElement | null>(null); |
76 | 92 | const { toPromise } = useScript({ src: BAI_DU_MAP_URL }); |
77 | - const entityId = ref(''); | |
93 | + const [registerDetailDrawer, { openDrawer }] = useDrawer(); | |
94 | + | |
95 | + let entityId = ''; | |
96 | + let globalRecord: any = {}; | |
78 | 97 | async function initMap() { |
79 | 98 | await toPromise(); |
80 | 99 | await nextTick(); |
... | ... | @@ -101,13 +120,14 @@ |
101 | 120 | }, |
102 | 121 | }); |
103 | 122 | // 点击表格某一行触发 |
104 | - const deviceRowClick = (record) => { | |
105 | - entityId.value = record.tbDeviceId; | |
123 | + const deviceRowClick = async (record) => { | |
124 | + entityId = record.tbDeviceId; | |
125 | + globalRecord = record; | |
106 | 126 | const BMap = (window as any).BMap; |
107 | 127 | const wrapEl = unref(wrapRef); |
108 | 128 | const map = new BMap.Map(wrapEl); |
109 | 129 | if (record.deviceInfo.address) { |
110 | - const { name, organizationDTO, updateTime, deviceState, deviceProfile } = record; | |
130 | + const { name, organizationDTO, deviceState, deviceProfile } = record; | |
111 | 131 | const { longitude, latitude, address } = record.deviceInfo; |
112 | 132 | const point = new BMap.Point(longitude, latitude); |
113 | 133 | let options = { |
... | ... | @@ -117,6 +137,10 @@ |
117 | 137 | map.centerAndZoom(point, 15); |
118 | 138 | map.enableScrollWheelZoom(true); |
119 | 139 | // 创建信息窗口对象 |
140 | + const res = await getDeviceActiveTime(entityId); | |
141 | + | |
142 | + let { value: activeStatus, lastUpdateTs } = res[0]; | |
143 | + lastUpdateTs = moment(lastUpdateTs).format('YYYY-MM-DD HH:mm:ss'); | |
120 | 144 | let infoWindow = new BMap.InfoWindow( |
121 | 145 | ` |
122 | 146 | <div style="display:flex;justify-content:space-between; margin:20px 0px;"> |
... | ... | @@ -132,10 +156,9 @@ |
132 | 156 | <div>所属组织:${organizationDTO.name}</div> |
133 | 157 | <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div> |
134 | 158 | <div style="margin-top:6px;">设备位置:${address}</div> |
135 | - <div style="margin-top:6px;">下线时间:${updateTime}</div> | |
136 | - <div style="display:flex;justify-content:space-between; margin-top:10px"> | |
137 | - <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button> | |
138 | - <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">报警记录</button> | |
159 | + <div style="margin-top:6px;">${activeStatus ? '在' : '离'}线时间:${lastUpdateTs}</div> | |
160 | + <div style="display:flex;justify-content:end; margin-top:10px"> | |
161 | + <button onclick="openDeviceInfoDrawer()" style="margin-right:10px;color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button> | |
139 | 162 | <button onclick="openHistoryModal()" style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">历史数据</button> |
140 | 163 | </div> |
141 | 164 | `, |
... | ... | @@ -185,13 +208,20 @@ |
185 | 208 | endTs = Date.now(); |
186 | 209 | // 发送请求 |
187 | 210 | const res = await getDeviceHistoryInfo({ |
188 | - entityId: entityId.value, | |
211 | + entityId, | |
189 | 212 | keys: keys.join(), |
190 | 213 | startTs, |
191 | 214 | endTs, |
192 | 215 | interval, |
193 | 216 | agg, |
194 | 217 | }); |
218 | + // 判断对象是否为空 | |
219 | + if (Object.keys(res).length === 0) { | |
220 | + isNull.value = false; | |
221 | + return; | |
222 | + } else { | |
223 | + isNull.value = true; | |
224 | + } | |
195 | 225 | // 处理数据 |
196 | 226 | for (const key in res) { |
197 | 227 | for (const item1 of res[key]) { |
... | ... | @@ -250,24 +280,38 @@ |
250 | 280 | |
251 | 281 | const chartRef = ref<HTMLDivElement | null>(null); |
252 | 282 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
253 | - | |
283 | + const isNull = ref(true); | |
284 | + // 设备信息 | |
285 | + const openDeviceInfoDrawer = async () => { | |
286 | + const { id, tbDeviceId } = globalRecord; | |
287 | + openDrawer(true, { | |
288 | + id, | |
289 | + tbDeviceId, | |
290 | + }); | |
291 | + }; | |
254 | 292 | const openHistoryModal = async () => { |
255 | 293 | openModal(true); |
256 | - | |
257 | 294 | // 收集参数 |
258 | 295 | const dataArray: any[] = []; |
259 | 296 | const startTs = Date.now() - 86400000; //最近一天 |
260 | 297 | const endTs = Date.now(); |
261 | 298 | // 发送请求 |
262 | - keys = await getDeviceDataKeys(entityId.value); | |
299 | + keys = await getDeviceDataKeys(entityId); | |
263 | 300 | const res = await getDeviceHistoryInfo({ |
264 | - entityId: entityId.value, | |
301 | + entityId, | |
265 | 302 | keys: keys.join(), |
266 | 303 | startTs, |
267 | 304 | endTs, |
268 | 305 | interval: 7200000, //间隔两小时 |
269 | 306 | agg: 'AVG', |
270 | 307 | }); |
308 | + // 判断对象是否为空 | |
309 | + if (Object.keys(res).length === 0) { | |
310 | + isNull.value = false; | |
311 | + return; | |
312 | + } else { | |
313 | + isNull.value = true; | |
314 | + } | |
271 | 315 | // 处理数据 |
272 | 316 | for (const key in res) { |
273 | 317 | for (const item1 of res[key]) { |
... | ... | @@ -327,12 +371,14 @@ |
327 | 371 | agg: 'AVG', |
328 | 372 | }); |
329 | 373 | }; |
374 | + | |
330 | 375 | const cancelHistoryModal = () => { |
331 | 376 | resetFields(); |
332 | 377 | setOptions({}); |
333 | 378 | }; |
334 | 379 | onMounted(() => { |
335 | 380 | initMap(); |
381 | + (window as any).openDeviceInfoDrawer = openDeviceInfoDrawer; | |
336 | 382 | (window as any).openHistoryModal = openHistoryModal; |
337 | 383 | }); |
338 | 384 | return { |
... | ... | @@ -343,7 +389,9 @@ |
343 | 389 | registerModal, |
344 | 390 | registerForm, |
345 | 391 | chartRef, |
392 | + isNull, | |
346 | 393 | cancelHistoryModal, |
394 | + registerDetailDrawer, | |
347 | 395 | }; |
348 | 396 | }, |
349 | 397 | }); | ... | ... |
1 | 1 | <template> |
2 | - <div class="md:flex justify-between"> | |
3 | - <template v-for="(item, index) in growCardList" :key="item.title"> | |
4 | - <div | |
5 | - class="growCardItem md:w-1/3 w-full !md:mt-0 !mt-4 bg-white" | |
6 | - :class="index === 0 ? '!md:ml-0' : '!md:ml-4'" | |
7 | - > | |
8 | - <div | |
9 | - class=" | |
10 | - growCardItem-top | |
11 | - border border-solid border-t-0 border-r-0 border-l-0 border-b-1 | |
12 | - dark:border-#ccc | |
13 | - light:border-#F2F2F5 | |
14 | - " | |
15 | - > | |
16 | - <img :src="item.imgUrl" style="width: 5rem; height: 5rem" /> | |
17 | - <div class="growCardItem-right"> | |
18 | - <div class="flex justify-between ml-3"> | |
19 | - <div style="font-size: 1.625rem; color: #333">{{ item.value }}</div> | |
20 | - <img src="../../../../assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | |
2 | + <div class="md:flex"> | |
3 | + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4"> | |
4 | + <div class="flex" style="height: 100px"> | |
5 | + <div class="mr-4" | |
6 | + ><img src="/src/assets/images/device-count.png" style="width: 5rem; height: 5rem" | |
7 | + /></div> | |
8 | + <div class="flex-auto"> | |
9 | + <div class="flex justify-between" style="align-items: center"> | |
10 | + <div style="font-size: 1.625rem; color: #333">{{ | |
11 | + growCardList?.deviceInfo?.sumCount | |
12 | + }}</div> | |
13 | + <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | |
14 | + </div> | |
15 | + <div> 设备数(个) </div> | |
16 | + <div class="flex mt-2"> | |
17 | + <div class="flex mr-1" style="align-items: center; font-size: 0.75rem" | |
18 | + ><img src="/src/assets/images/online.png" class="mr-1" /> | |
19 | + <span>在线{{ growCardList?.deviceInfo?.onLine }}</span> | |
21 | 20 | </div> |
22 | - <div class="ml-3">{{ item.title }}</div> | |
23 | - <div class="ml-1.5 mt-3 flex flex-nowrap" style="width: 15rem" v-if="item.offLine"> | |
24 | - <div class="count"> | |
25 | - <img | |
26 | - src="../../../../assets/images/online.png" | |
27 | - style="width: 0.6rem; height: 0.6rem" | |
28 | - class="mr-1" | |
29 | - /> | |
30 | - 在线 {{ item.onLine }} | |
31 | - </div> | |
32 | - <div class="count"> | |
33 | - <img | |
34 | - src="../../../../assets/images/offline.png" | |
35 | - style="width: 0.6rem; height: 0.6rem" | |
36 | - class="mr-1" | |
37 | - /> | |
38 | - 离线 {{ item.offLine }} | |
39 | - </div> | |
40 | - <div class="count"> | |
41 | - <img | |
42 | - src="../../../../assets/images/inactive.png" | |
43 | - style="width: 0.6rem; height: 0.6rem" | |
44 | - class="mr-1" | |
45 | - /> | |
46 | - 未激活 {{ item.inactive }} | |
47 | - </div> | |
21 | + <div class="flex mr-1" style="align-items: center; font-size: 0.75rem"> | |
22 | + <img src="/src/assets/images/offline.png" class="mr-1" /> | |
23 | + <span> 离线{{ growCardList?.deviceInfo?.offLine }} </span> | |
48 | 24 | </div> |
25 | + <div class="flex mr-1" style="align-items: center; font-size: 0.75rem"> | |
26 | + <img src="/src/assets/images/inactive.png" class="mr-1" /> | |
27 | + <span> 未激活{{ growCardList?.deviceInfo?.inActive }} </span> | |
28 | + </div> | |
29 | + </div> | |
30 | + </div> | |
31 | + </div> | |
32 | + <div class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5"> | |
33 | + 今日新增 {{ growCardList?.deviceInfo?.todayAdd }}</div | |
34 | + > | |
35 | + </Card> | |
36 | + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4"> | |
37 | + <div class="flex" style="height: 100px"> | |
38 | + <div class="mr-4" | |
39 | + ><img | |
40 | + :src=" | |
41 | + role === 'TENANT_ADMIN' | |
42 | + ? '/src/assets/images/alarm-count.png' | |
43 | + : '/src/assets/images/zh.png' | |
44 | + " | |
45 | + style="width: 5rem; height: 5rem" | |
46 | + /></div> | |
47 | + <div class="flex-auto"> | |
48 | + <div class="flex justify-between" style="align-items: center"> | |
49 | + <div style="font-size: 1.625rem; color: #333">{{ | |
50 | + growCardList?.tenantInfo?.sumCount | |
51 | + }}</div> | |
52 | + <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | |
49 | 53 | </div> |
54 | + <div> {{ role === 'TENANT_ADMIN' ? '11月告警数(条)' : '租户总量(个)' }}</div> | |
50 | 55 | </div> |
51 | - <div class="growCardItem-bottom"> 今日新增 {{ item.newDay }}</div> | |
52 | 56 | </div> |
53 | - </template> | |
57 | + <div class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5"> | |
58 | + 今日新增 {{ growCardList?.tenantInfo?.todayAdd }}</div | |
59 | + > | |
60 | + </Card> | |
61 | + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4"> | |
62 | + <div class="flex" style="height: 100px"> | |
63 | + <div class="mr-4" | |
64 | + ><img | |
65 | + :src=" | |
66 | + role === 'TENANT_ADMIN' | |
67 | + ? '/src/assets/images/msg-count.png' | |
68 | + : '/src/assets/images/kf.png' | |
69 | + " | |
70 | + style="width: 5rem; height: 5rem" | |
71 | + /></div> | |
72 | + <div class="flex-auto"> | |
73 | + <div class="flex justify-between" style="align-items: center"> | |
74 | + <div style="font-size: 1.625rem; color: #333">{{ | |
75 | + growCardList?.customerInfo?.sumCount | |
76 | + }}</div> | |
77 | + <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | |
78 | + </div> | |
79 | + <div> {{ role === 'TENANT_ADMIN' ? '11月消息量(条)' : '客户总量(个)' }} </div> | |
80 | + </div> | |
81 | + </div> | |
82 | + <div class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5"> | |
83 | + 今日新增 {{ growCardList?.customerInfo?.todayAdd }}</div | |
84 | + > | |
85 | + </Card> | |
54 | 86 | </div> |
55 | 87 | </template> |
56 | 88 | <script lang="ts" setup> |
57 | - import { growCardList } from '../data'; | |
58 | -</script> | |
59 | - | |
60 | -<style scoped lang="less"> | |
61 | - .growCardItem { | |
62 | - height: 11.187rem; | |
63 | - color: #666; | |
64 | - .growCardItem-top { | |
65 | - display: flex; | |
66 | - margin: 1.25rem; | |
67 | - padding-bottom: 0.625rem; | |
68 | - .growCardItem-right { | |
69 | - width: 18.75rem; | |
70 | - .count { | |
71 | - display: flex; | |
72 | - font-size: 0.75rem; | |
73 | - align-items: center; | |
74 | - margin-left: 0.5rem; | |
75 | - } | |
76 | - } | |
77 | - } | |
78 | - .growCardItem-bottom { | |
79 | - margin-left: 1.25rem; | |
80 | - } | |
89 | + import { defineProps, ref, onMounted } from 'vue'; | |
90 | + import { Card } from 'ant-design-vue'; | |
91 | + import { getHomeData } from '/@/api/dashboard'; | |
92 | + interface CardList { | |
93 | + deviceInfo: { | |
94 | + sumCount: number; | |
95 | + onLine: number; | |
96 | + offLine: number; | |
97 | + inActive: number; | |
98 | + todayAdd: number; | |
99 | + }; | |
100 | + tenantInfo: { sumCount: number; todayAdd: number }; | |
101 | + customerInfo: { sumCount: number; todayAdd: number }; | |
81 | 102 | } |
82 | -</style> | |
103 | + const growCardList = ref<CardList>(); | |
104 | + onMounted(async () => { | |
105 | + const res = await getHomeData(); | |
106 | + growCardList.value = res; | |
107 | + console.log(growCardList.value); | |
108 | + }); | |
109 | + defineProps<{ | |
110 | + role: string; | |
111 | + }>(); | |
112 | +</script> | ... | ... |
1 | 1 | <template> |
2 | - <Card title="帮助文档"> | |
3 | - <div> | |
4 | - <template v-for="item in helpDoc" :key="item.title"> | |
5 | - <AnchorLink v-bind="item" /> | |
6 | - </template> | |
7 | - </div> | |
8 | - <Card | |
9 | - :tab-list="tabListTitle" | |
10 | - v-bind="$attrs" | |
11 | - :active-tab-key="activeKey" | |
12 | - :bordered="false" | |
13 | - @tabChange="onTabChange" | |
14 | - :bodyStyle="{ padding: 0 }" | |
15 | - > | |
16 | - <div v-if="activeKey === 'tab1'"> | |
17 | - <List item-layout="horizontal" :dataSource="dataSource"> | |
18 | - <template #renderItem="{ item }"> | |
19 | - <ListItem> | |
20 | - <ListItemMeta> | |
21 | - <template #avatar> | |
22 | - <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> | |
23 | - </template> | |
24 | - <template #description> | |
25 | - <span | |
26 | - @click="go('/stationnotification/mynotification')" | |
27 | - class="cursor-pointer noticeTitle" | |
28 | - >{{ item.sysNotice.title }} | |
29 | - </span> | |
30 | - </template> | |
31 | - <template #title> | |
32 | - <span>{{ item.user.realName }}</span> | |
2 | + <div> | |
3 | + <Card title="帮助文档" v-if="role === 'TENANT_ADMIN'"> | |
4 | + <div> | |
5 | + <template v-for="item in helpDoc" :key="item.title"> | |
6 | + <AnchorLink v-bind="item" /> | |
7 | + </template> | |
8 | + </div> | |
9 | + <Card | |
10 | + v-if="role === 'TENANT_ADMIN'" | |
11 | + :tab-list="tabListTitle" | |
12 | + v-bind="$attrs" | |
13 | + :active-tab-key="activeKey" | |
14 | + :bordered="false" | |
15 | + @tabChange="onTabChange" | |
16 | + :bodyStyle="{ padding: 0 }" | |
17 | + > | |
18 | + <div v-if="activeKey === 'tab1'"> | |
19 | + <List item-layout="horizontal" :dataSource="dataSource"> | |
20 | + <template #renderItem="{ item }"> | |
21 | + <ListItem> | |
22 | + <ListItemMeta> | |
23 | + <template #avatar> | |
24 | + <Avatar | |
25 | + src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" | |
26 | + /> | |
27 | + </template> | |
28 | + <template #description> | |
29 | + <span | |
30 | + class="cursor-pointer noticeTitle" | |
31 | + @click="go('/stationnotification/mynotification')" | |
32 | + >{{ item.sysNotice.title }} | |
33 | + </span> | |
34 | + </template> | |
35 | + <template #title> | |
36 | + <span>{{ item.user.realName }}</span> | |
37 | + </template> | |
38 | + </ListItemMeta> | |
39 | + <template #extra> | |
40 | + <Time :value="item.sysNotice.senderDate" /> | |
33 | 41 | </template> |
34 | - </ListItemMeta> | |
35 | - <template #extra> | |
36 | - <Time :value="item.sysNotice.senderDate" /> | |
37 | - </template> | |
38 | - </ListItem> | |
39 | - </template> | |
40 | - </List> | |
41 | - <Card hoverable title="联系我们" :bordered="false"> | |
42 | - <template #cover> | |
43 | - <img :src="getQrCode" alt="" style="width: 150px; height: 150px; margin: 50px auto" /> | |
44 | - </template> | |
45 | - <CardMeta> | |
46 | - <template #description> | |
47 | - <p>联系人: {{ getContacts }}</p> | |
48 | - <p>联系电话: {{ getTel }}</p> | |
49 | - <p>联系地址: {{ getAddress }} </p> | |
42 | + </ListItem> | |
50 | 43 | </template> |
51 | - </CardMeta> | |
52 | - </Card> | |
53 | - </div> | |
44 | + </List> | |
45 | + <Card hoverable title="联系我们" :bordered="false"> | |
46 | + <template #cover> | |
47 | + <img :src="getQrCode" alt="" style="width: 150px; height: 150px; margin: 50px auto" /> | |
48 | + </template> | |
49 | + <CardMeta> | |
50 | + <template #description> | |
51 | + <p>联系人: {{ getContacts }}</p> | |
52 | + <p>联系电话: {{ getTel }}</p> | |
53 | + <p>联系地址: {{ getAddress }} </p> | |
54 | + </template> | |
55 | + </CardMeta> | |
56 | + </Card> | |
57 | + </div> | |
58 | + </Card> | |
54 | 59 | </Card> |
55 | - </Card> | |
60 | + | |
61 | + <Card v-if="role !== 'TENANT_ADMIN'"> | |
62 | + <Descriptions title="租户消息量TOP10" :column="1"> | |
63 | + <template v-for="(item, index) in 10" :key="index"> | |
64 | + <DescriptionsItem> | |
65 | + <span | |
66 | + class="mr-2" | |
67 | + style=" | |
68 | + width: 1.25rem; | |
69 | + height: 1.25rem; | |
70 | + border: 1px solid; | |
71 | + color: #0b55f1; | |
72 | + border-radius: 50%; | |
73 | + display: flex; | |
74 | + align-items: center; | |
75 | + justify-content: center; | |
76 | + " | |
77 | + :style="{ | |
78 | + color: | |
79 | + index === 0 | |
80 | + ? '#f0a16e' | |
81 | + : index === 1 | |
82 | + ? '#868585' | |
83 | + : index === 2 | |
84 | + ? '#e78739' | |
85 | + : '#4e84f5', | |
86 | + backgroundColor: | |
87 | + index === 0 ? '#fed36a' : index === 1 ? '#CBCAC9' : index === 2 ? '#F1B889' : '', | |
88 | + borderColor: | |
89 | + index === 0 | |
90 | + ? '#fdee7d' | |
91 | + : index === 1 | |
92 | + ? '#e6e6e5' | |
93 | + : index === 2 | |
94 | + ? '#f8c296' | |
95 | + : '#0b55f1;', | |
96 | + }" | |
97 | + >{{ index + 1 }}</span | |
98 | + >兰州天兆猪业</DescriptionsItem | |
99 | + > | |
100 | + </template> | |
101 | + </Descriptions> | |
102 | + </Card> | |
103 | + <BasicTable @register="registerTable" v-if="role !== 'TENANT_ADMIN'" /> | |
104 | + </div> | |
56 | 105 | </template> |
57 | 106 | |
58 | 107 | <script lang="ts"> |
59 | 108 | import { defineComponent, ref, computed, onMounted } from 'vue'; |
60 | - import { Card, AnchorLink, List, ListItem, ListItemMeta, Avatar, CardMeta } from 'ant-design-vue'; | |
109 | + import { | |
110 | + Card, | |
111 | + AnchorLink, | |
112 | + List, | |
113 | + ListItem, | |
114 | + ListItemMeta, | |
115 | + Avatar, | |
116 | + CardMeta, | |
117 | + Descriptions, | |
118 | + DescriptionsItem, | |
119 | + } from 'ant-design-vue'; | |
61 | 120 | import { useUserStore } from '/@/store/modules/user'; |
62 | 121 | import { getEnterPriseDetail } from '/@/api/oem'; |
63 | 122 | import { notifyMyGetrPageApi } from '/@/api/stationnotification/stationnotifyApi'; |
64 | 123 | import { Time } from '/@/components/Time'; |
65 | 124 | import { useGo } from '/@/hooks/web/usePage'; |
125 | + import { BasicTable, useTable } from '/@/components/Table'; | |
126 | + import { columns } from './props'; | |
66 | 127 | export default defineComponent({ |
67 | 128 | components: { |
68 | 129 | Card, |
... | ... | @@ -73,12 +134,18 @@ |
73 | 134 | Avatar, |
74 | 135 | Time, |
75 | 136 | CardMeta, |
137 | + BasicTable, | |
138 | + Descriptions, | |
139 | + DescriptionsItem, | |
76 | 140 | }, |
77 | - setup() { | |
78 | - onMounted(async () => { | |
79 | - const res = await getEnterPriseDetail(); | |
80 | - userStore.setEnterPriseInfo(res); | |
81 | - }); | |
141 | + props: { | |
142 | + role: String, | |
143 | + }, | |
144 | + setup(props) { | |
145 | + // 通知数据 | |
146 | + const dataSource = ref([]); | |
147 | + const go = useGo(); | |
148 | + | |
82 | 149 | const helpDoc = ref([ |
83 | 150 | { |
84 | 151 | title: '如何接入设备?', |
... | ... | @@ -108,6 +175,12 @@ |
108 | 175 | const onTabChange = (key) => { |
109 | 176 | activeKey.value = key; |
110 | 177 | }; |
178 | + const [registerTable] = useTable({ | |
179 | + title: '本月即将过期租户', | |
180 | + showIndexColumn: false, | |
181 | + useSearchForm: false, | |
182 | + columns, | |
183 | + }); | |
111 | 184 | |
112 | 185 | const userStore = useUserStore(); |
113 | 186 | const getContacts = computed(() => { |
... | ... | @@ -122,13 +195,12 @@ |
122 | 195 | const getQrCode = computed(() => { |
123 | 196 | return userStore.enterPriseInfo?.qrCode; |
124 | 197 | }); |
125 | - | |
126 | - // 通知数据 | |
127 | - const dataSource = ref([]); | |
128 | - const go = useGo(); | |
129 | 198 | onMounted(async () => { |
130 | - const res = await notifyMyGetrPageApi({ page: 1, pageSize: 5 }); | |
131 | - dataSource.value = res.items; | |
199 | + if (props.role !== 'TENANT_ADMIN') return; | |
200 | + const res = await getEnterPriseDetail(); | |
201 | + const notice = await notifyMyGetrPageApi({ page: 1, pageSize: 5 }); | |
202 | + userStore.setEnterPriseInfo(res); | |
203 | + dataSource.value = notice.items; | |
132 | 204 | }); |
133 | 205 | |
134 | 206 | return { |
... | ... | @@ -142,6 +214,7 @@ |
142 | 214 | getTel, |
143 | 215 | dataSource, |
144 | 216 | go, |
217 | + registerTable, | |
145 | 218 | }; |
146 | 219 | }, |
147 | 220 | }); | ... | ... |
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | :active-tab-key="activeKey" |
6 | 6 | @tabChange="onTabChange" |
7 | 7 | > |
8 | - <template #tabBarExtraContent> | |
8 | + <template #tabBarExtraContent v-if="role === 'TENANT_ADMIN'"> | |
9 | 9 | <div class="extra-date"> |
10 | 10 | <template v-for="(item, index) in dateList" :key="item"> |
11 | 11 | <span @click="changeDate(index)" :class="{ active: index === activeIndex }">{{ |
... | ... | @@ -16,8 +16,9 @@ |
16 | 16 | </div> |
17 | 17 | </template> |
18 | 18 | <div v-if="activeKey === 'tab1'"> |
19 | - <p class="center">告警数</p> | |
20 | - <VisitAnalysis /> | |
19 | + <p class="center">{{ role === 'TENANT_ADMIN' ? '告警数' : '租户趋势' }}</p> | |
20 | + <VisitAnalysis v-if="role === 'TENANT_ADMIN'" /> | |
21 | + <VisitAnalysisBar v-else /> | |
21 | 22 | </div> |
22 | 23 | <div v-else> |
23 | 24 | <p class="center">消息数</p> |
... | ... | @@ -30,19 +31,33 @@ |
30 | 31 | import { Card, DatePicker } from 'ant-design-vue'; |
31 | 32 | import VisitAnalysis from './VisitAnalysis.vue'; |
32 | 33 | import VisitAnalysisBar from './VisitAnalysisBar.vue'; |
34 | + import { defineProps } from 'vue'; | |
33 | 35 | |
36 | + const props = defineProps<{ | |
37 | + role: string; | |
38 | + }>(); | |
34 | 39 | const activeKey = ref('tab1'); |
35 | 40 | |
36 | - const tabListTitle = [ | |
37 | - { | |
38 | - key: 'tab1', | |
39 | - tab: '告警数统计', | |
40 | - }, | |
41 | - { | |
42 | - key: 'tab2', | |
43 | - tab: '消息量统计', | |
44 | - }, | |
45 | - ]; | |
41 | + // 动态根据登录角色来判断 | |
42 | + const tabListTitle = | |
43 | + props.role === 'TENANT_ADMIN' | |
44 | + ? [ | |
45 | + { | |
46 | + key: 'tab1', | |
47 | + tab: '告警数统计', | |
48 | + }, | |
49 | + { | |
50 | + key: 'tab2', | |
51 | + tab: '消息量统计', | |
52 | + }, | |
53 | + ] | |
54 | + : [ | |
55 | + { | |
56 | + key: 'tab1', | |
57 | + tab: '租户', | |
58 | + }, | |
59 | + ]; | |
60 | + | |
46 | 61 | const dateList = ref(['1小时', '1天', '7天', '30天']); |
47 | 62 | const activeIndex = ref(0); |
48 | 63 | function onTabChange(key) { | ... | ... |
1 | 1 | import { PropType } from 'vue'; |
2 | - | |
2 | +import type { BasicColumn } from '/@/components/Table'; | |
3 | 3 | export interface BasicProps { |
4 | 4 | width: string; |
5 | 5 | height: string; |
... | ... | @@ -14,3 +14,16 @@ export const basicProps = { |
14 | 14 | default: '280px', |
15 | 15 | }, |
16 | 16 | }; |
17 | + | |
18 | +export const columns: BasicColumn[] = [ | |
19 | + { | |
20 | + title: '租户名称', | |
21 | + dataIndex: 'tenantName', | |
22 | + width: 120, | |
23 | + }, | |
24 | + { | |
25 | + title: '过期时间', | |
26 | + dataIndex: 'createdTime', | |
27 | + width: 120, | |
28 | + }, | |
29 | +]; | ... | ... |
src/views/dashboard/workbench/data.ts
deleted
100644 → 0
1 | -export interface GrowCardItem { | |
2 | - imgUrl: string; | |
3 | - title: string; | |
4 | - value: string; | |
5 | - onLine?: number; | |
6 | - offLine?: number; | |
7 | - inactive?: number; | |
8 | - newDay: string; | |
9 | -} | |
10 | - | |
11 | -export const growCardList: GrowCardItem[] = [ | |
12 | - { | |
13 | - imgUrl: '/src/assets/images/device-count.png', | |
14 | - title: '设备数(个)', | |
15 | - value: '10,000', | |
16 | - onLine: 2000, | |
17 | - offLine: 3000, | |
18 | - inactive: 4000, | |
19 | - newDay: '123,45', | |
20 | - }, | |
21 | - { | |
22 | - imgUrl: '/src/assets/images/alarm-count.png', | |
23 | - title: '11月告警数(条)', | |
24 | - value: '11,000', | |
25 | - newDay: '167,45', | |
26 | - }, | |
27 | - { | |
28 | - imgUrl: '/src/assets/images/msg-count.png', | |
29 | - title: '11月消息量(条)', | |
30 | - value: '12,000', | |
31 | - newDay: '198,45', | |
32 | - }, | |
33 | -]; |
1 | 1 | <template> |
2 | 2 | <div class="p-4 md:flex"> |
3 | 3 | <div class="md:w-7/10 w-full !mr-4 enter-y"> |
4 | - <GrowCard :loading="loading" class="enter-y" /> | |
5 | - <SiteAnalysis class="!my-4 enter-y" :loading="loading" /> | |
6 | - <div class="md:flex enter-y"> | |
4 | + <GrowCard :loading="loading" class="enter-y" :role="role" /> | |
5 | + <SiteAnalysis class="!my-4 enter-y" :loading="loading" :role="role" /> | |
6 | + <div class="md:flex enter-y" v-if="role === 'TENANT_ADMIN'"> | |
7 | 7 | <Card title="核心流程指南" style="width: 100%"> |
8 | 8 | <img alt="核心流程指南" src="../../../assets/images/flow.png" /> |
9 | 9 | </Card> |
10 | 10 | </div> |
11 | 11 | </div> |
12 | 12 | <div class="md:w-3/10 w-full enter-y"> |
13 | - <HelpDoc /> | |
13 | + <HelpDoc :role="role" /> | |
14 | 14 | </div> |
15 | 15 | </div> |
16 | 16 | </template> |
... | ... | @@ -20,7 +20,11 @@ |
20 | 20 | import SiteAnalysis from './components/SiteAnalysis.vue'; |
21 | 21 | import { Card } from 'ant-design-vue'; |
22 | 22 | import HelpDoc from './components/HelpDoc.vue'; |
23 | - | |
23 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
24 | + import { getAuthCache } from '/@/utils/auth'; | |
25 | + const userInfo: any = getAuthCache(USER_INFO_KEY); | |
26 | + const role = userInfo.roles[0]; | |
27 | + console.log(role); | |
24 | 28 | const loading = ref(true); |
25 | 29 | setTimeout(() => { |
26 | 30 | loading.value = false; | ... | ... |
1 | 1 | import { formatToDateTime } from '/@/utils/dateUtil'; |
2 | 2 | import { FormSchema } from '/@/components/Form'; |
3 | 3 | import { BasicColumn } from '/@/components/Table'; |
4 | + | |
4 | 5 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
5 | 6 | |
6 | 7 | export const columns: BasicColumn[] = [ |
... | ... | @@ -8,25 +9,20 @@ export const columns: BasicColumn[] = [ |
8 | 9 | title: '设备名称', |
9 | 10 | dataIndex: 'name', |
10 | 11 | width: 120, |
11 | - key: 'name', | |
12 | 12 | }, |
13 | 13 | { |
14 | 14 | title: '设备标签', |
15 | 15 | dataIndex: 'label', |
16 | 16 | width: 100, |
17 | - key: 'label', | |
18 | 17 | }, |
19 | 18 | { |
20 | 19 | title: '设备配置', |
21 | 20 | dataIndex: 'deviceProfile.name', |
22 | 21 | width: 160, |
23 | - key: 'deviceProfile.name', | |
24 | 22 | }, |
25 | - | |
26 | 23 | { |
27 | 24 | title: '设备类型', |
28 | 25 | dataIndex: 'deviceType', |
29 | - key: 'deviceType', | |
30 | 26 | customRender({ text }) { |
31 | 27 | return text === DeviceTypeEnum.GATEWAY |
32 | 28 | ? '网关设备' |
... | ... | @@ -39,7 +35,6 @@ export const columns: BasicColumn[] = [ |
39 | 35 | title: '描述', |
40 | 36 | dataIndex: 'description', |
41 | 37 | width: 180, |
42 | - key: 'description', | |
43 | 38 | }, |
44 | 39 | ]; |
45 | 40 | // 实时数据表格 | ... | ... |
1 | +import { formatToDate } from '/@/utils/dateUtil'; | |
1 | 2 | import { BasicColumn } from '/@/components/Table'; |
2 | 3 | import { FormSchema } from '/@/components/Table'; |
3 | 4 | import { DeviceTypeEnum, DeviceState } from '/@/api/device/model/deviceModel'; |
... | ... | @@ -19,6 +20,7 @@ export const columns: BasicColumn[] = [ |
19 | 20 | dataIndex: 'deviceProfile.name', |
20 | 21 | width: 160, |
21 | 22 | slots: { customRender: 'deviceProfile' }, |
23 | + ellipsis: true, | |
22 | 24 | }, |
23 | 25 | |
24 | 26 | { |
... | ... | @@ -36,10 +38,16 @@ export const columns: BasicColumn[] = [ |
36 | 38 | width: 120, |
37 | 39 | slots: { customRender: 'deviceState' }, |
38 | 40 | }, |
39 | - | |
40 | 41 | { |
41 | 42 | title: '最后连接时间', |
42 | - dataIndex: 'lastConnectTime', | |
43 | + dataIndex: 'lastOnlineTime', | |
44 | + format: (text) => formatToDate(text, 'YYYY-MM-DD HH:mm:ss'), | |
45 | + width: 180, | |
46 | + }, | |
47 | + { | |
48 | + title: '最后断开时间', | |
49 | + dataIndex: 'lastOfflineTime', | |
50 | + format: (text) => formatToDate(text, 'YYYY-MM-DD HH:mm:ss'), | |
43 | 51 | width: 180, |
44 | 52 | }, |
45 | 53 | ]; | ... | ... |
... | ... | @@ -10,8 +10,8 @@ |
10 | 10 | bordered |
11 | 11 | :columns="columns" |
12 | 12 | :data-source="[deviceDetail]" |
13 | + :rowKey="(_, index) => index" | |
13 | 14 | :pagination="false" |
14 | - rowKey="tbDeviceId" | |
15 | 15 | style="width: 800px" |
16 | 16 | /> |
17 | 17 | </div> |
... | ... | @@ -23,7 +23,7 @@ |
23 | 23 | </div> |
24 | 24 | <div v-if="deviceDetail?.deviceInfo?.address" class="mt-4"> |
25 | 25 | <p>设备位置</p> |
26 | - <div ref="wrapRef" style="height: 400px; width: 90%"></div> | |
26 | + <div ref="wrapRef" style="height: 400px; width: 100%"></div> | |
27 | 27 | </div> |
28 | 28 | </div> |
29 | 29 | </template> | ... | ... |