Commit edef147b3f2154a933ee65078f680ab988d455a1

Authored by xp.Huang
2 parents 9e0402d8 4601105b

Merge branch 'sqy_dev' into 'main'

feat:地理位置完成,首页条件判断完成,接口待调试,设备修改字段。

See merge request huang/yun-teng-iot-front!64
... ... @@ -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 +};
... ...
  1 +import { defHttp } from '/@/utils/http/axios';
  2 +enum HomeEnum {
  3 + home = '/homepage/left/top',
  4 +}
  5 +
  6 +export const getHomeData = () => {
  7 + return defHttp.get({
  8 + url: HomeEnum.home,
  9 + });
  10 +};
... ...
1 1 export enum RoleEnum {
2 2 ROLE_SYS_ADMIN = 'SYS_ADMIN',
3 3 ROLE_TENANT_ADMIN = 'TENANT_ADMIN',
4   - ROLE_NORMAL_USER = 'CUSTOMER_USER',
5 4 ROLE_PLATFORM_ADMIN = 'PLATFORM_ADMIN',
  5 + ROLE_NORMAL_USER = 'CUSTOMER_USER',
6 6 }
... ...
... ... @@ -51,7 +51,6 @@
51 51 severity: alarmLevel(data.severity),
52 52 status: statusType(data.status),
53 53 });
54   - console.log(data.status);
55 54 alarmStatus.value = data.status;
56 55 alarmId.value = data.id;
57 56 });
... ...
... ... @@ -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 +];
... ...
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 ];
... ...
... ... @@ -6,7 +6,7 @@
6 6 :destroyOnClose="true"
7 7 @close="closeDrawer"
8 8 :title="deviceDetail.name"
9   - width="78%"
  9 + width="70%"
10 10 >
11 11 <Tabs v-model:activeKey="activeKey" :size="size" type="card">
12 12 <TabPane key="1" tab="详情"
... ...
... ... @@ -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>
... ...