Commit 47352daa37e5c7d253e9a7e63da63888d4accf98

Authored by xp.Huang
2 parents 1d9d4605 812f07d4

Merge branch 'sqy_dev' into 'main'

修改首页的图表

See merge request huang/yun-teng-iot-front!70
  1 +import { BasicPageParams } from './../model/baseModel';
1 2 import { defHttp } from '/@/utils/http/axios';
2 3 enum HomeEnum {
3 4 home = '/homepage/left/top',
  5 + TenantExpireTimeList = '/homepage/right',
  6 + EntitiesQueryFind = '/entitiesQuery/find',
4 7 }
5 8
6 9 export const getHomeData = () => {
... ... @@ -8,3 +11,54 @@ export const getHomeData = () => {
8 11 url: HomeEnum.home,
9 12 });
10 13 };
  14 +
  15 +// 获取即将过期租户列表
  16 +export const getTenantExpireTimeList = (params: BasicPageParams) => {
  17 + return defHttp.get({
  18 + url: HomeEnum.TenantExpireTimeList,
  19 + params,
  20 + });
  21 +};
  22 +
  23 +// 获取entities实体ID
  24 +export const getEntitiesId = () => {
  25 + return defHttp.post(
  26 + {
  27 + url: HomeEnum.EntitiesQueryFind,
  28 + data: {
  29 + entityFilter: {
  30 + type: 'apiUsageState',
  31 + resolveMultiple: false,
  32 + },
  33 + pageLink: {
  34 + pageSize: 1,
  35 + page: 0,
  36 + sortOrder: {
  37 + key: {
  38 + type: 'ENTITY_FIELD',
  39 + key: 'createdTime',
  40 + },
  41 + direction: 'DESC',
  42 + },
  43 + },
  44 + entityFields: [
  45 + {
  46 + type: 'ENTITY_FIELD',
  47 + key: 'name',
  48 + },
  49 + {
  50 + type: 'ENTITY_FIELD',
  51 + key: 'label',
  52 + },
  53 + {
  54 + type: 'ENTITY_FIELD',
  55 + key: 'additionalInfo',
  56 + },
  57 + ],
  58 + },
  59 + },
  60 + {
  61 + joinPrefix: false,
  62 + }
  63 + );
  64 +};
... ...
1   -import { defHttp } from '/@/utils/http/axios';
2   -
3   -enum Api {
4   - // The address does not exist
5   - Error = '/error',
6   -}
7   -
8   -/**
9   - * @description: Trigger ajax error
10   - */
11   -
12   -export const fireErrorApi = () => defHttp.get({ url: Api.Error });
1   -import { defHttp } from '/@/utils/http/axios';
2   -
3   -enum Api {
4   - TREE_OPTIONS_LIST = '/tree/getDemoOptions',
5   -}
6   -
7   -/**
8   - * @description: Get sample options value
9   - */
10   -export const treeOptionsListApi = (params?: Recordable) =>
11   - defHttp.get<Recordable[]>({ url: Api.TREE_OPTIONS_LIST, params });
  1 +<template>
  2 + <div ref="chartRef" :style="{ height, width }"></div>
  3 +</template>
  4 +<script lang="ts" setup>
  5 + import { ref, Ref, withDefaults, defineProps } from 'vue';
  6 + import { useECharts } from '/@/hooks/web/useECharts';
  7 +
  8 + interface Props {
  9 + width?: string;
  10 + height?: string;
  11 + }
  12 + withDefaults(defineProps<Props>(), {
  13 + width: '100%',
  14 + height: '280px',
  15 + });
  16 +
  17 + const chartRef = ref<HTMLDivElement | null>(null);
  18 + const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
  19 +</script>
... ...
... ... @@ -100,7 +100,9 @@
100 100 </template>
101 101 </Descriptions>
102 102 </Card>
103   - <BasicTable @register="registerTable" v-if="isAdmin(role)" />
  103 + <Card v-if="isAdmin(role)">
  104 + <BasicTable @register="registerTable" />
  105 + </Card>
104 106 </div>
105 107 </template>
106 108
... ... @@ -125,6 +127,7 @@
125 127 import { BasicTable, useTable } from '/@/components/Table';
126 128 import { columns } from './props';
127 129 import { isAdmin } from '/@/enums/roleEnum';
  130 + import { getTenantExpireTimeList } from '/@/api/dashboard';
128 131 export default defineComponent({
129 132 components: {
130 133 Card,
... ... @@ -179,11 +182,17 @@
179 182 const onTabChange = (key) => {
180 183 activeKey.value = key;
181 184 };
182   - const [registerTable] = useTable({
  185 +
  186 + const [registerTable, { redoHeight }] = useTable({
  187 + api: getTenantExpireTimeList,
183 188 title: '本月即将过期租户',
184 189 showIndexColumn: false,
185 190 useSearchForm: false,
186 191 columns,
  192 + fetchSetting: {
  193 + listField: 'expireTenant.items',
  194 + totalField: 'expireTenant.total',
  195 + },
187 196 });
188 197
189 198 const userStore = useUserStore();
... ... @@ -201,6 +210,7 @@
201 210 });
202 211 onMounted(async () => {
203 212 if (isAdmin(props.role)) return;
  213 +
204 214 const res = await getEnterPriseDetail();
205 215 const notice = await notifyMyGetrPageApi({ page: 1, pageSize: 5 });
206 216 userStore.setEnterPriseInfo(res);
... ... @@ -220,6 +230,7 @@
220 230 go,
221 231 registerTable,
222 232 isAdmin,
  233 + redoHeight,
223 234 };
224 235 },
225 236 });
... ...
... ... @@ -4,43 +4,55 @@
4 4 v-bind="$attrs"
5 5 :active-tab-key="activeKey"
6 6 @tabChange="onTabChange"
  7 + v-if="!isAdmin(role)"
7 8 >
8   - <template #tabBarExtraContent v-if="!isAdmin(role)">
  9 + <template #tabBarExtraContent>
9 10 <div class="extra-date">
10   - <template v-for="(item, index) in dateList" :key="item">
11   - <span @click="changeDate(index)" :class="{ active: index === activeIndex }">{{
12   - item
13   - }}</span>
  11 + <template v-for="(item, index) in dateList" :key="item.value">
  12 + <span
  13 + @click="quickQueryDate(index, item.value)"
  14 + :class="{ active: index === activeIndex }"
  15 + >{{ item.label }}</span
  16 + >
14 17 </template>
15 18 <DatePicker @change="onDateChange" />
16 19 </div>
17 20 </template>
18 21 <div v-if="activeKey === '1'">
19   - <p class="center">{{ !isAdmin(role) ? '告警数' : '租户趋势' }}</p>
  22 + <p class="center">告警数</p>
  23 + <!-- 折线图 -->
20 24 <VisitAnalysis v-if="!isAdmin(role)" :alarmList="state.alarmList" />
21   - <VisitAnalysisBar v-else />
22 25 </div>
23 26 <div v-if="activeKey === '2'">
24 27 <p class="center">消息量</p>
25   - <VisitAnalysisBar :dataPointList="state.dataPointList" :messageList="state.messageList" />
  28 + <!-- 柱形图 -->
  29 + <VisitAnalysisBar
  30 + v-if="!isAdmin(role)"
  31 + :dataPointList="state.dataPointList"
  32 + :messageList="state.messageList"
  33 + />
26 34 </div>
27 35 </Card>
28   - <Card v-bind="$attrs" :tab-list="tab1ListTitle" v-if="isAdmin(role)">
29   - <p class="center">客户趋势</p>
30   - <VisitAnalysis
31   - /></Card>
  36 + <Card v-bind="$attrs" v-if="isAdmin(role)" title="租户趋势">
  37 + <TenantTrend />
  38 + </Card>
  39 + <Card v-bind="$attrs" v-if="isAdmin(role)" title="客户趋势">
  40 + <CustomerTrend />
  41 + </Card>
32 42 </template>
33 43 <script lang="ts" setup>
34   - import { ref, defineExpose, reactive } from 'vue';
  44 + import { ref, reactive } from 'vue';
35 45 import { Card, DatePicker } from 'ant-design-vue';
36 46 import VisitAnalysis from './VisitAnalysis.vue';
37 47 import VisitAnalysisBar from './VisitAnalysisBar.vue';
38   - import { defineProps } from 'vue';
39 48 import { isAdmin } from '/@/enums/roleEnum';
40 49 import { useWebSocket } from '@vueuse/core';
41 50 import { getAuthCache } from '/@/utils/auth';
  51 + import CustomerTrend from './CustomerTrend.vue';
  52 + import TenantTrend from './TenantTrend.vue';
42 53 import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum';
43   -
  54 + import { formatToDateTime } from '/@/utils/dateUtil';
  55 + import { getEntitiesId } from '/@/api/dashboard/index';
44 56 defineExpose({
45 57 isAdmin,
46 58 });
... ... @@ -48,84 +60,29 @@
48 60 role: string;
49 61 }>();
50 62 const activeKey = ref('1');
51   -
52   - // 动态根据登录角色来判断
53   - const tabListTitle = !isAdmin(props.role)
54   - ? [
55   - {
56   - key: '1',
57   - tab: '告警数统计',
58   - },
59   - {
60   - key: '2',
61   - tab: '消息量统计',
62   - },
63   - ]
64   - : [
65   - {
66   - key: '1',
67   - tab: '租户',
68   - },
69   - ];
70   -
71   - const tab1ListTitle = [
  63 + let entityId = null;
  64 + // 图表tab切换选项卡
  65 + const tabListTitle = [
72 66 {
73 67 key: '1',
74   - tab: '客户',
  68 + tab: '告警数统计',
  69 + },
  70 + {
  71 + key: '2',
  72 + tab: '消息量统计',
75 73 },
76 74 ];
77   -
78   - const dateList = ref(['1小时', '1天', '7天', '30天']);
  75 + // 快速选择日期
  76 + const activeIndex = ref(1);
  77 + const dateList = ref([
  78 + { label: '1小时', value: 3600000 },
  79 + { label: '1天', value: 86400000 },
  80 + { label: '7天', value: 604800000 },
  81 + { label: '30天', value: 2592000000 },
  82 + ]);
79 83 // web Socket
80 84 const token: string = getAuthCache(JWT_TOKEN_KEY);
81   - const sendValue = JSON.stringify({
82   - entityDataCmds: [
83   - {
84   - query: {
85   - entityFilter: {
86   - type: 'singleEntity',
87   - singleEntity: {
88   - id: '33782740-5d97-11ec-8ac9-f38ed935ea2a',
89   - entityType: 'API_USAGE_STATE',
90   - },
91   - },
92   - pageLink: {
93   - pageSize: 1024,
94   - page: 0,
95   - sortOrder: {
96   - key: {
97   - type: 'ENTITY_FIELD',
98   - key: 'createdTime',
99   - },
100   - direction: 'DESC',
101   - },
102   - },
103   - entityFields: [
104   - {
105   - type: 'ENTITY_FIELD',
106   - key: 'name',
107   - },
108   - {
109   - type: 'ENTITY_FIELD',
110   - key: 'label',
111   - },
112   - {
113   - type: 'ENTITY_FIELD',
114   - key: 'additionalInfo',
115   - },
116   - ],
117   - latestValues: [
118   - {
119   - type: 'TIME_SERIES',
120   - key: 'createdAlarmsCountHourly',
121   - },
122   - ],
123   - },
124   - cmdId: activeKey.value,
125   - },
126   - ],
127   - });
128   - const activeIndex = ref(0);
  85 +
129 86 const state = reactive({
130 87 server: `${import.meta.env.VITE_WEB_SOCKET}${token}`,
131 88 alarmList: new Array<[number, string]>(),
... ... @@ -136,12 +93,60 @@
136 93 MsgCount: new Array<[number, string]>(),
137 94 });
138 95 const { send, close } = useWebSocket(state.server, {
139   - onConnected() {
  96 + async onConnected() {
  97 + if (isAdmin(props.role)) return;
  98 + const res = await getEntitiesId();
  99 + entityId = res.data[0].entityId;
  100 + const sendValue = JSON.stringify({
  101 + entityDataCmds: [
  102 + {
  103 + query: {
  104 + entityFilter: {
  105 + type: 'singleEntity',
  106 + singleEntity: entityId,
  107 + },
  108 + pageLink: {
  109 + pageSize: 1024,
  110 + page: 0,
  111 + sortOrder: {
  112 + key: {
  113 + type: 'ENTITY_FIELD',
  114 + key: 'createdTime',
  115 + },
  116 + direction: 'DESC',
  117 + },
  118 + },
  119 + entityFields: [
  120 + {
  121 + type: 'ENTITY_FIELD',
  122 + key: 'name',
  123 + },
  124 + {
  125 + type: 'ENTITY_FIELD',
  126 + key: 'label',
  127 + },
  128 + {
  129 + type: 'ENTITY_FIELD',
  130 + key: 'additionalInfo',
  131 + },
  132 + ],
  133 + latestValues: [
  134 + {
  135 + type: 'TIME_SERIES',
  136 + key: 'createdAlarmsCountHourly',
  137 + },
  138 + ],
  139 + },
  140 + cmdId: activeKey.value,
  141 + },
  142 + ],
  143 + });
140 144 send(sendValue);
141 145 console.log('建立连接了');
142 146 },
143 147 onMessage(_, e) {
144 148 const { data, update } = JSON.parse(e.data);
  149 + console.log('来新消息了', data, update);
145 150 if (activeKey.value === '1') {
146 151 if (data) {
147 152 const { createdAlarmsCountHourly } = data.data[0].latest.TIME_SERIES;
... ... @@ -154,7 +159,7 @@
154 159 for (const item of createdAlarmsCountHourly) {
155 160 newArray.push([item.ts, item.value]);
156 161 }
157   - state.alarmList = [state.alarmItem, ...newArray];
  162 + state.alarmList = [[...state.alarmItem], ...newArray];
158 163 }
159 164 } else {
160 165 if (data) {
... ... @@ -164,7 +169,6 @@
164 169 transportDataPointsCountHourly.ts,
165 170 transportDataPointsCountHourly.value,
166 171 ];
167   -
168 172 state.MsgCount = [
169 173 transportDataPointsCountHourly.ts,
170 174 transportDataPointsCountHourly.value,
... ... @@ -177,16 +181,16 @@
177 181 }
178 182 if (update) {
179 183 const { transportDataPointsCountHourly, transportMsgCountHourly } = update[0].timeseries;
180   - const newArray: any = [];
181   - const newArray1: any = [];
  184 + const newArray: any[] = [];
  185 + const newArray1: any[] = [];
182 186 for (const item of transportDataPointsCountHourly) {
183 187 newArray.push([item.ts, item.value]);
184 188 }
185 189 for (const item of transportMsgCountHourly) {
186 190 newArray1.push([item.ts, item.value]);
187 191 }
188   - state.dataPointList = [state.dataPoint, ...newArray];
189   - state.messageList = [state.MsgCount, ...newArray1];
  192 + state.dataPointList = [[...state.dataPoint], ...newArray];
  193 + state.messageList = [[...state.MsgCount], ...newArray1];
190 194 }
191 195 }
192 196 },
... ... @@ -204,11 +208,11 @@
204 208 cmdId: activeKey.value,
205 209 historyCmd: {
206 210 keys: ['createdAlarmsCountHourly'],
207   - startTs: 1638778336692,
208   - endTs: 1641370336692,
209   - interval: 43200000,
210   - limit: 60,
211   - agg: 'SUM',
  211 + startTs: Date.now() - 86400000,
  212 + endTs: Date.now(),
  213 + interval: 7200000,
  214 + limit: 12,
  215 + agg: 'COUNT',
212 216 },
213 217 },
214 218 ],
... ... @@ -221,10 +225,7 @@
221 225 query: {
222 226 entityFilter: {
223 227 type: 'singleEntity',
224   - singleEntity: {
225   - id: '33782740-5d97-11ec-8ac9-f38ed935ea2a',
226   - entityType: 'API_USAGE_STATE',
227   - },
  228 + singleEntity: entityId,
228 229 },
229 230 pageLink: {
230 231 pageSize: 1024,
... ... @@ -272,11 +273,11 @@
272 273 cmdId: activeKey.value,
273 274 historyCmd: {
274 275 keys: ['transportMsgCountHourly', 'transportDataPointsCountHourly'],
275   - startTs: 1641283221226,
276   - endTs: 1641369621226,
  276 + startTs: Date.now() - 86400000,
  277 + endTs: Date.now(),
277 278 interval: 7200000,
278 279 limit: 12,
279   - agg: 'AVG',
  280 + agg: 'COUNT',
280 281 },
281 282 },
282 283 ],
... ... @@ -285,11 +286,62 @@
285 286 send(sendMessageValue2);
286 287 }
287 288 }
288   - function onDateChange(date, dateString) {
289   - console.log(date, dateString);
  289 + // 选择日期
  290 + function onDateChange(_, dateString) {
  291 + activeIndex.value = -1;
  292 + const dateTime = Number(formatToDateTime(dateString, 'x'));
  293 + // 动态发送ws数据
  294 + const sendValue = JSON.stringify({
  295 + entityDataCmds: [
  296 + {
  297 + cmdId: activeKey.value,
  298 + historyCmd: {
  299 + keys:
  300 + activeKey.value === '1'
  301 + ? ['createdAlarmsCountHourly']
  302 + : ['transportMsgCountHourly', 'transportDataPointsCountHourly'],
  303 + startTs: dateTime,
  304 + endTs: dateTime + 86400000,
  305 + interval: 7200000,
  306 + limit: 12,
  307 + agg: 'COUNT',
  308 + },
  309 + },
  310 + ],
  311 + });
  312 + send(sendValue);
290 313 }
291   - function changeDate(index: number) {
  314 + // 快速选择时间
  315 + function quickQueryDate(index: number, value: number) {
292 316 activeIndex.value = index;
  317 + let limit = 12;
  318 + if (value === 604800000) {
  319 + limit = 7;
  320 + } else if (value === 2592000000) {
  321 + limit = 30;
  322 + }
  323 + // 动态发送ws数据
  324 + const sendValue = JSON.stringify({
  325 + entityDataCmds: [
  326 + {
  327 + cmdId: activeKey.value,
  328 + historyCmd: {
  329 + keys:
  330 + activeKey.value === '1'
  331 + ? ['createdAlarmsCountHourly']
  332 + : ['transportMsgCountHourly', 'transportDataPointsCountHourly'],
  333 + startTs: Date.now() - value,
  334 + endTs: Date.now(),
  335 + interval: value > 3600000 ? 7200000 : 300000,
  336 + limit,
  337 + agg: 'COUNT',
  338 + },
  339 + },
  340 + ],
  341 + });
  342 + send(sendValue);
  343 +
  344 + console.log(value);
293 345 }
294 346 </script>
295 347
... ...
  1 +<template>
  2 + <div ref="chartRef" :style="{ height, width }"></div>
  3 +</template>
  4 +<script lang="ts" setup>
  5 + import { ref, Ref, withDefaults, defineProps } from 'vue';
  6 + import { useECharts } from '/@/hooks/web/useECharts';
  7 +
  8 + interface Props {
  9 + width?: string;
  10 + height?: string;
  11 + }
  12 + withDefaults(defineProps<Props>(), {
  13 + width: '100%',
  14 + height: '280px',
  15 + });
  16 +
  17 + const chartRef = ref<HTMLDivElement | null>(null);
  18 + const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
  19 +</script>
... ...
... ... @@ -23,7 +23,12 @@
23 23 () => [props.dataPointList, props.messageList],
24 24 ([newValue, newValue1]) => {
25 25 setOptions({
26   - tooltip: {},
  26 + tooltip: {
  27 + trigger: 'axis',
  28 + axisPointer: {
  29 + type: 'shadow',
  30 + },
  31 + },
27 32 xAxis: {
28 33 type: 'time',
29 34 },
... ... @@ -39,13 +44,14 @@
39 44 {
40 45 name: '传输数据点',
41 46 type: 'bar',
42   - stack: 'one',
  47 + stack: 'total',
43 48 data: newValue,
44 49 },
45 50 {
46 51 name: '传输消息量',
47 52 type: 'bar',
48   - stack: 'one',
  53 + stack: 'total',
  54 +
49 55 data: newValue1,
50 56 },
51 57 ],
... ...
... ... @@ -18,12 +18,12 @@ export const basicProps = {
18 18 export const columns: BasicColumn[] = [
19 19 {
20 20 title: '租户名称',
21   - dataIndex: 'tenantName',
  21 + dataIndex: 'name',
22 22 width: 120,
23 23 },
24 24 {
25 25 title: '过期时间',
26   - dataIndex: 'createdTime',
  26 + dataIndex: 'tenantExpireTime',
27 27 width: 120,
28 28 },
29 29 ];
... ...
... ... @@ -15,7 +15,7 @@
15 15 </div>
16 16 </template>
17 17 <script lang="ts" setup>
18   - import { ref, defineExpose } from 'vue';
  18 + import { ref } from 'vue';
19 19 import GrowCard from './components/GrowCard.vue';
20 20 import SiteAnalysis from './components/SiteAnalysis.vue';
21 21 import { Card } from 'ant-design-vue';
... ... @@ -28,9 +28,11 @@
28 28 });
29 29
30 30 const userInfo: any = getAuthCache(USER_INFO_KEY);
31   - const role = userInfo.roles[0];
32   - console.log(role);
  31 + const role: string = userInfo.roles[0];
33 32 const loading = ref(true);
  33 +
  34 + console.log(role);
  35 +
34 36 setTimeout(() => {
35 37 loading.value = false;
36 38 }, 1500);
... ...