Commit 1717e6bb696f26a79cbf93fd2c8b1042b8b13047

Authored by sqy
1 parent e763f5cf

fix:首页逻辑改动,待完成,暂存拉代码

  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,128 +4,82 @@
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
  11 + <template v-for="(item, index) in dateList" :key="item.value">
  12 + <span @click="changeDate(index, item.value)" :class="{ active: index === activeIndex }">{{
  13 + item.label
13 14 }}</span>
14 15 </template>
15 16 <DatePicker @change="onDateChange" />
16 17 </div>
17 18 </template>
18 19 <div v-if="activeKey === '1'">
19   - <p class="center">{{ !isAdmin(role) ? '告警数' : '租户趋势' }}</p>
  20 + <p class="center">告警数</p>
  21 + <!-- 折线图 -->
20 22 <VisitAnalysis v-if="!isAdmin(role)" :alarmList="state.alarmList" />
21   - <VisitAnalysisBar v-else />
22 23 </div>
23 24 <div v-if="activeKey === '2'">
24 25 <p class="center">消息量</p>
25   - <VisitAnalysisBar :dataPointList="state.dataPointList" :messageList="state.messageList" />
  26 + <!-- 柱形图 -->
  27 + <VisitAnalysisBar
  28 + v-if="!isAdmin(role)"
  29 + :dataPointList="state.dataPointList"
  30 + :messageList="state.messageList"
  31 + />
26 32 </div>
27 33 </Card>
28   - <Card v-bind="$attrs" :tab-list="tab1ListTitle" v-if="isAdmin(role)">
29   - <p class="center">客户趋势</p>
30   - <VisitAnalysis
31   - /></Card>
  34 + <Card v-bind="$attrs" v-if="isAdmin(role)" title="租户趋势">
  35 + <TenantTrend />
  36 + </Card>
  37 + <Card v-bind="$attrs" v-if="isAdmin(role)" title="客户趋势">
  38 + <CustomerTrend />
  39 + </Card>
32 40 </template>
33 41 <script lang="ts" setup>
34   - import { ref, defineExpose, reactive } from 'vue';
  42 + import { ref, reactive } from 'vue';
35 43 import { Card, DatePicker } from 'ant-design-vue';
36 44 import VisitAnalysis from './VisitAnalysis.vue';
37 45 import VisitAnalysisBar from './VisitAnalysisBar.vue';
38   - import { defineProps } from 'vue';
39 46 import { isAdmin } from '/@/enums/roleEnum';
40 47 import { useWebSocket } from '@vueuse/core';
41 48 import { getAuthCache } from '/@/utils/auth';
  49 + import CustomerTrend from './CustomerTrend.vue';
  50 + import TenantTrend from './TenantTrend.vue';
42 51 import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum';
43   -
  52 + import { formatToDateTime } from '/@/utils/dateUtil';
  53 + import { getEntitiesId } from '/@/api/dashboard/index';
44 54 defineExpose({
45 55 isAdmin,
46 56 });
47   - const props = defineProps<{
  57 + defineProps<{
48 58 role: string;
49 59 }>();
50 60 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 = [
  61 + let entityId = null;
  62 + // 图表tab切换选项卡
  63 + const tabListTitle = [
72 64 {
73 65 key: '1',
74   - tab: '客户',
  66 + tab: '告警数统计',
  67 + },
  68 + {
  69 + key: '2',
  70 + tab: '消息量统计',
75 71 },
76 72 ];
77   -
78   - const dateList = ref(['1小时', '1天', '7天', '30天']);
  73 + const activeIndex = ref(0);
  74 + const dateList = ref([
  75 + { label: '1小时', value: 3600000 },
  76 + { label: '1天', value: 86400000 },
  77 + { label: '7天', value: 604800000 },
  78 + { label: '30天', value: 2592000000 },
  79 + ]);
79 80 // web Socket
80 81 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);
  82 +
129 83 const state = reactive({
130 84 server: `${import.meta.env.VITE_WEB_SOCKET}${token}`,
131 85 alarmList: new Array<[number, string]>(),
... ... @@ -136,7 +90,53 @@
136 90 MsgCount: new Array<[number, string]>(),
137 91 });
138 92 const { send, close } = useWebSocket(state.server, {
139   - onConnected() {
  93 + async onConnected() {
  94 + const res = await getEntitiesId();
  95 + entityId = res.data[0].entityId;
  96 + const sendValue = JSON.stringify({
  97 + entityDataCmds: [
  98 + {
  99 + query: {
  100 + entityFilter: {
  101 + type: 'singleEntity',
  102 + singleEntity: entityId,
  103 + },
  104 + pageLink: {
  105 + pageSize: 1024,
  106 + page: 0,
  107 + sortOrder: {
  108 + key: {
  109 + type: 'ENTITY_FIELD',
  110 + key: 'createdTime',
  111 + },
  112 + direction: 'DESC',
  113 + },
  114 + },
  115 + entityFields: [
  116 + {
  117 + type: 'ENTITY_FIELD',
  118 + key: 'name',
  119 + },
  120 + {
  121 + type: 'ENTITY_FIELD',
  122 + key: 'label',
  123 + },
  124 + {
  125 + type: 'ENTITY_FIELD',
  126 + key: 'additionalInfo',
  127 + },
  128 + ],
  129 + latestValues: [
  130 + {
  131 + type: 'TIME_SERIES',
  132 + key: 'createdAlarmsCountHourly',
  133 + },
  134 + ],
  135 + },
  136 + cmdId: activeKey.value,
  137 + },
  138 + ],
  139 + });
140 140 send(sendValue);
141 141 console.log('建立连接了');
142 142 },
... ... @@ -144,9 +144,12 @@
144 144 const { data, update } = JSON.parse(e.data);
145 145 if (activeKey.value === '1') {
146 146 if (data) {
147   - const { createdAlarmsCountHourly } = data.data[0].latest.TIME_SERIES;
148   - state.alarmItem = [createdAlarmsCountHourly.ts, createdAlarmsCountHourly.value];
149   - state.alarmList.push([createdAlarmsCountHourly.ts, createdAlarmsCountHourly.value]);
  147 + const alarmData = data.data[0]?.latest.TIME_SERIES;
  148 + if (alarmData?.createdAlarmsCountHourly) {
  149 + const { createdAlarmsCountHourly } = alarmData;
  150 + state.alarmItem = [createdAlarmsCountHourly.ts, createdAlarmsCountHourly.value];
  151 + state.alarmList.push([createdAlarmsCountHourly.ts, createdAlarmsCountHourly.value]);
  152 + }
150 153 }
151 154 if (update) {
152 155 const { createdAlarmsCountHourly } = update[0].timeseries;
... ... @@ -177,8 +180,9 @@
177 180 }
178 181 if (update) {
179 182 const { transportDataPointsCountHourly, transportMsgCountHourly } = update[0].timeseries;
180   - const newArray: any = [];
181   - const newArray1: any = [];
  183 + const newArray: any[] = [];
  184 + const newArray1: any[] = [];
  185 + console.log(update[0]);
182 186 for (const item of transportDataPointsCountHourly) {
183 187 newArray.push([item.ts, item.value]);
184 188 }
... ... @@ -208,7 +212,7 @@
208 212 endTs: 1641370336692,
209 213 interval: 43200000,
210 214 limit: 60,
211   - agg: 'SUM',
  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,
... ... @@ -285,11 +286,42 @@
285 286 send(sendMessageValue2);
286 287 }
287 288 }
288   - function onDateChange(date, dateString) {
289   - console.log(date, dateString);
  289 + function onDateChange(_, dateString) {
  290 + const dateTime = formatToDateTime(dateString, 'x');
  291 + console.log(dateTime);
290 292 }
291   - function changeDate(index: number) {
  293 + function changeDate(index: number, value: number) {
292 294 activeIndex.value = index;
  295 + let limit;
  296 + if (value === 3600000 || value === 86400000) {
  297 + limit = 12;
  298 + } else if (value === 604800000) {
  299 + limit = 7;
  300 + } else if (value === 2592000000) {
  301 + limit = 30;
  302 + }
  303 + // 动态发送ws数据
  304 + const sendValue = JSON.stringify({
  305 + entityDataCmds: [
  306 + {
  307 + cmdId: activeKey.value,
  308 + historyCmd: {
  309 + keys:
  310 + activeKey.value === '1'
  311 + ? ['createdAlarmsCountHourly']
  312 + : ['transportMsgCountHourly', 'transportDataPointsCountHourly'],
  313 + startTs: Date.now() - value,
  314 + endTs: Date.now(),
  315 + interval: value > 3600000 ? 7200000 : 300000,
  316 + limit,
  317 + agg: 'COUNT',
  318 + },
  319 + },
  320 + ],
  321 + });
  322 + send(sendValue);
  323 +
  324 + console.log(value);
293 325 }
294 326 </script>
295 327
... ...
  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,13 @@
23 23 () => [props.dataPointList, props.messageList],
24 24 ([newValue, newValue1]) => {
25 25 setOptions({
26   - tooltip: {},
  26 + tooltip: {
  27 + trigger: 'axis',
  28 + axisPointer: {
  29 + // Use axis to trigger tooltip
  30 + type: 'shadow', // 'shadow' as default; can also be 'line' or 'shadow'
  31 + },
  32 + },
27 33 xAxis: {
28 34 type: 'time',
29 35 },
... ... @@ -39,13 +45,14 @@
39 45 {
40 46 name: '传输数据点',
41 47 type: 'bar',
42   - stack: 'one',
  48 + stack: 'total',
43 49 data: newValue,
44 50 },
45 51 {
46 52 name: '传输消息量',
47 53 type: 'bar',
48   - stack: 'one',
  54 + stack: 'total',
  55 +
49 56 data: newValue1,
50 57 },
51 58 ],
... ...
... ... @@ -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 ];
... ...
... ... @@ -10,7 +10,7 @@
10 10 </div>
11 11 </div>
12 12 <div class="md:w-3/10 w-full enter-y">
13   - <HelpDoc :role="role" />
  13 + <HelpDoc :role="role" ref="helpDocRef" />
14 14 </div>
15 15 </div>
16 16 </template>
... ... @@ -29,9 +29,22 @@
29 29
30 30 const userInfo: any = getAuthCache(USER_INFO_KEY);
31 31 const role = userInfo.roles[0];
  32 +
32 33 console.log(role);
33 34 const loading = ref(true);
  35 + const helpDocRef = ref();
34 36 setTimeout(() => {
35 37 loading.value = false;
36 38 }, 1500);
  39 + window.addEventListener(
  40 + 'scroll',
  41 + () => {
  42 + const scrollBottom =
  43 + document.body.scrollHeight - document.body.scrollTop - document.body.clientHeight;
  44 + if (scrollBottom <= 0) {
  45 + helpDocRef.value.redoHeight();
  46 + }
  47 + },
  48 + true
  49 + );
37 50 </script>
... ...