Showing
18 changed files
with
320 additions
and
148 deletions
@@ -8,10 +8,10 @@ VITE_PUBLIC_PATH = / | @@ -8,10 +8,10 @@ VITE_PUBLIC_PATH = / | ||
8 | # Please note that no line breaks | 8 | # Please note that no line breaks |
9 | 9 | ||
10 | # 本地 | 10 | # 本地 |
11 | -# VITE_PROXY = [["/api","http://localhost:8080/api"]] | 11 | +VITE_PROXY = [["/api","http://192.168.10.107:8080/api"]] |
12 | 12 | ||
13 | # 线上 | 13 | # 线上 |
14 | -VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]] | 14 | +# VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]] |
15 | 15 | ||
16 | # 实时数据的ws地址 | 16 | # 实时数据的ws地址 |
17 | VITE_WEB_SOCKET = ws://101.133.234.90:8080/api/ws/plugins/telemetry?token= | 17 | VITE_WEB_SOCKET = ws://101.133.234.90:8080/api/ws/plugins/telemetry?token= |
@@ -4,6 +4,7 @@ enum HomeEnum { | @@ -4,6 +4,7 @@ enum HomeEnum { | ||
4 | home = '/homepage/left/top', | 4 | home = '/homepage/left/top', |
5 | TenantExpireTimeList = '/homepage/right', | 5 | TenantExpireTimeList = '/homepage/right', |
6 | EntitiesQueryFind = '/entitiesQuery/find', | 6 | EntitiesQueryFind = '/entitiesQuery/find', |
7 | + TrendAPI = '/homepage/left/bottom', | ||
7 | } | 8 | } |
8 | 9 | ||
9 | export const getHomeData = () => { | 10 | export const getHomeData = () => { |
@@ -62,3 +63,17 @@ export const getEntitiesId = () => { | @@ -62,3 +63,17 @@ export const getEntitiesId = () => { | ||
62 | } | 63 | } |
63 | ); | 64 | ); |
64 | }; | 65 | }; |
66 | + | ||
67 | +interface TrendParamsType { | ||
68 | + startTs: number; | ||
69 | + endTs: number; | ||
70 | + interval: number; | ||
71 | + trend: 'CUSTOMER_TREND' | 'TENANT_TREND'; | ||
72 | +} | ||
73 | +// 获取租户趋势或者客户趋势数据 | ||
74 | +export const getTrendData = (params: TrendParamsType) => { | ||
75 | + return defHttp.get({ | ||
76 | + url: HomeEnum.TrendAPI, | ||
77 | + params, | ||
78 | + }); | ||
79 | +}; |
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | @menuEvent="handleMenuEvent" | 11 | @menuEvent="handleMenuEvent" |
12 | overlayClassName="app-locale-picker-overlay" | 12 | overlayClassName="app-locale-picker-overlay" |
13 | > | 13 | > |
14 | - <span class="cursor-pointer flex items-center"> | 14 | + <span class="cursor-pointer flex items-center" style="color: #fff"> |
15 | <Icon icon="ion:language" /> | 15 | <Icon icon="ion:language" /> |
16 | <span v-if="showText" class="ml-1">{{ getLocaleText }}</span> | 16 | <span v-if="showText" class="ml-1">{{ getLocaleText }}</span> |
17 | </span> | 17 | </span> |
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | class="ml-2 md:opacity-100" | 11 | class="ml-2 md:opacity-100" |
12 | :class="getTitleClass" | 12 | :class="getTitleClass" |
13 | v-show="showTitle" | 13 | v-show="showTitle" |
14 | - style="white-space: nowrap; font-size: small" | 14 | + style="white-space: nowrap; font-size: small; color: #f3f4fb" |
15 | > | 15 | > |
16 | {{ getTitle }} | 16 | {{ getTitle }} |
17 | </span> | 17 | </span> |
@@ -24,16 +24,20 @@ function itemRender({ page, type, originalElement }: ItemRender) { | @@ -24,16 +24,20 @@ function itemRender({ page, type, originalElement }: ItemRender) { | ||
24 | export function usePagination(refProps: ComputedRef<BasicTableProps>) { | 24 | export function usePagination(refProps: ComputedRef<BasicTableProps>) { |
25 | const { t } = useI18n(); | 25 | const { t } = useI18n(); |
26 | 26 | ||
27 | - const configRef = ref<PaginationProps>({}); | 27 | + const configRef = ref<PaginationProps>({ |
28 | + hideOnSinglePage:true | ||
29 | + }); | ||
28 | const show = ref(true); | 30 | const show = ref(true); |
29 | 31 | ||
30 | watchEffect(() => { | 32 | watchEffect(() => { |
31 | const { pagination } = unref(refProps); | 33 | const { pagination } = unref(refProps); |
34 | + | ||
32 | if (!isBoolean(pagination) && pagination) { | 35 | if (!isBoolean(pagination) && pagination) { |
33 | configRef.value = { | 36 | configRef.value = { |
34 | ...unref(configRef), | 37 | ...unref(configRef), |
35 | ...(pagination ?? {}), | 38 | ...(pagination ?? {}), |
36 | - }; | 39 | + }; |
40 | + | ||
37 | } | 41 | } |
38 | }); | 42 | }); |
39 | 43 |
1 | <template> | 1 | <template> |
2 | - 123 | ||
3 | <div ref="chartRef" :style="{ height, width }"></div> | 2 | <div ref="chartRef" :style="{ height, width }"></div> |
4 | </template> | 3 | </template> |
5 | <script lang="ts" setup> | 4 | <script lang="ts" setup> |
6 | - import { ref, Ref, withDefaults } from 'vue'; | 5 | + import { ref, Ref, withDefaults, onMounted, watch } from 'vue'; |
7 | import { useECharts } from '/@/hooks/web/useECharts'; | 6 | import { useECharts } from '/@/hooks/web/useECharts'; |
7 | + import { getTrendData } from '/@/api/dashboard'; | ||
8 | 8 | ||
9 | interface Props { | 9 | interface Props { |
10 | width?: string; | 10 | width?: string; |
11 | height?: string; | 11 | height?: string; |
12 | + customerTrendList?: Array<[number, string]>; | ||
12 | } | 13 | } |
13 | - withDefaults(defineProps<Props>(), { | 14 | + const props = withDefaults(defineProps<Props>(), { |
14 | width: '100%', | 15 | width: '100%', |
15 | height: '280px', | 16 | height: '280px', |
17 | + customerTrendList: () => [], | ||
16 | }); | 18 | }); |
19 | + watch( | ||
20 | + () => props.customerTrendList, | ||
21 | + (newValue) => { | ||
22 | + setOptions({ | ||
23 | + tooltip: { | ||
24 | + trigger: 'axis', | ||
25 | + axisPointer: { | ||
26 | + type: 'shadow', | ||
27 | + }, | ||
28 | + }, | ||
29 | + xAxis: { | ||
30 | + type: 'time', | ||
31 | + }, | ||
32 | + yAxis: {}, | ||
33 | + grid: { | ||
34 | + left: '3%', | ||
35 | + right: '4%', | ||
36 | + bottom: '3%', | ||
37 | + containLabel: true, | ||
38 | + }, | ||
39 | + series: [ | ||
40 | + { | ||
41 | + name: '当前趋势', | ||
42 | + type: 'line', | ||
43 | + data: newValue, | ||
44 | + }, | ||
45 | + ], | ||
46 | + }); | ||
47 | + } | ||
48 | + ); | ||
17 | 49 | ||
18 | const chartRef = ref<HTMLDivElement | null>(null); | 50 | const chartRef = ref<HTMLDivElement | null>(null); |
19 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | 51 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
52 | + onMounted(async () => { | ||
53 | + const endTs = Date.now(); | ||
54 | + const res = await getTrendData({ | ||
55 | + startTs: endTs - 2592000000, | ||
56 | + endTs, | ||
57 | + interval: 86400000, | ||
58 | + trend: 'CUSTOMER_TREND', | ||
59 | + }); | ||
60 | + const transferResult: [number, string][] = []; | ||
61 | + res.map((item) => { | ||
62 | + transferResult.push([item.ts, item.value]); | ||
63 | + }); | ||
64 | + console.log(transferResult); | ||
65 | + setOptions({ | ||
66 | + tooltip: { | ||
67 | + trigger: 'axis', | ||
68 | + axisPointer: { | ||
69 | + type: 'shadow', | ||
70 | + }, | ||
71 | + }, | ||
72 | + xAxis: { | ||
73 | + type: 'time', | ||
74 | + }, | ||
75 | + yAxis: {}, | ||
76 | + grid: { | ||
77 | + left: '3%', | ||
78 | + right: '4%', | ||
79 | + bottom: '3%', | ||
80 | + containLabel: true, | ||
81 | + }, | ||
82 | + series: [ | ||
83 | + { | ||
84 | + name: '当前趋势', | ||
85 | + type: 'line', | ||
86 | + data: transferResult, | ||
87 | + }, | ||
88 | + ], | ||
89 | + }); | ||
90 | + }); | ||
20 | </script> | 91 | </script> |
@@ -3,26 +3,26 @@ | @@ -3,26 +3,26 @@ | ||
3 | <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4"> | 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"> | 4 | <div class="flex" style="height: 100px"> |
5 | <div class="mr-4" | 5 | <div class="mr-4" |
6 | - ><img src="/src/assets/images/device-count.png" style="width: 5rem; height: 5rem" | 6 | + ><img src="/src/assets/images/device-count.png" style="width: 5.625rem; height: 5.625rem" |
7 | /></div> | 7 | /></div> |
8 | <div class="flex-auto"> | 8 | <div class="flex-auto"> |
9 | <div class="flex justify-between" style="align-items: center"> | 9 | <div class="flex justify-between" style="align-items: center"> |
10 | <div style="font-size: 1.625rem; color: #333">{{ | 10 | <div style="font-size: 1.625rem; color: #333">{{ |
11 | growCardList?.deviceInfo?.sumCount | 11 | growCardList?.deviceInfo?.sumCount |
12 | }}</div> | 12 | }}</div> |
13 | - <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | 13 | + <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" /> |
14 | </div> | 14 | </div> |
15 | <div> 设备数(个) </div> | 15 | <div> 设备数(个) </div> |
16 | - <div class="flex mt-2"> | ||
17 | - <div class="flex mr-1" style="align-items: center; font-size: 0.75rem" | 16 | + <div class="flex mt-2" style="font-size: 0.75rem"> |
17 | + <div class="flex mr-1" style="align-items: center" | ||
18 | ><img src="/src/assets/images/online.png" class="mr-1" /> | 18 | ><img src="/src/assets/images/online.png" class="mr-1" /> |
19 | <span>在线{{ growCardList?.deviceInfo?.onLine }}</span> | 19 | <span>在线{{ growCardList?.deviceInfo?.onLine }}</span> |
20 | </div> | 20 | </div> |
21 | - <div class="flex mr-1" style="align-items: center; font-size: 0.75rem"> | 21 | + <div class="flex mr-1" style="align-items: center"> |
22 | <img src="/src/assets/images/offline.png" class="mr-1" /> | 22 | <img src="/src/assets/images/offline.png" class="mr-1" /> |
23 | <span> 离线{{ growCardList?.deviceInfo?.offLine }} </span> | 23 | <span> 离线{{ growCardList?.deviceInfo?.offLine }} </span> |
24 | </div> | 24 | </div> |
25 | - <div class="flex mr-1" style="align-items: center; font-size: 0.75rem"> | 25 | + <div class="flex mr-1" style="align-items: center"> |
26 | <img src="/src/assets/images/inactive.png" class="mr-1" /> | 26 | <img src="/src/assets/images/inactive.png" class="mr-1" /> |
27 | <span> 未激活{{ growCardList?.deviceInfo?.inActive }} </span> | 27 | <span> 未激活{{ growCardList?.deviceInfo?.inActive }} </span> |
28 | </div> | 28 | </div> |
@@ -39,9 +39,9 @@ | @@ -39,9 +39,9 @@ | ||
39 | <img | 39 | <img |
40 | v-if="!isAdmin(role)" | 40 | v-if="!isAdmin(role)" |
41 | src="/src/assets/images/alarm-count.png" | 41 | src="/src/assets/images/alarm-count.png" |
42 | - style="width: 5rem; height: 5rem" | 42 | + style="width: 5.625rem; height: 5.625rem" |
43 | /> | 43 | /> |
44 | - <img v-else src="/src/assets/images/zh.png" style="width: 5rem; height: 5rem" /> | 44 | + <img v-else src="/src/assets/images/zh.png" style="width: 5.625rem; height: 5.625rem" /> |
45 | </div> | 45 | </div> |
46 | <div class="flex-auto"> | 46 | <div class="flex-auto"> |
47 | <div class="flex justify-between" style="align-items: center"> | 47 | <div class="flex justify-between" style="align-items: center"> |
@@ -51,7 +51,7 @@ | @@ -51,7 +51,7 @@ | ||
51 | <div style="font-size: 1.625rem; color: #333">{{ | 51 | <div style="font-size: 1.625rem; color: #333">{{ |
52 | growCardList?.tenantInfo?.sumCount | 52 | growCardList?.tenantInfo?.sumCount |
53 | }}</div> | 53 | }}</div> |
54 | - <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | 54 | + <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" /> |
55 | </div> | 55 | </div> |
56 | <div> {{ !isAdmin(role) ? `${currentMonth}月告警数(条)` : '租户总量(个)' }}</div> | 56 | <div> {{ !isAdmin(role) ? `${currentMonth}月告警数(条)` : '租户总量(个)' }}</div> |
57 | </div> | 57 | </div> |
@@ -69,8 +69,8 @@ | @@ -69,8 +69,8 @@ | ||
69 | ><img | 69 | ><img |
70 | v-if="!isAdmin(role)" | 70 | v-if="!isAdmin(role)" |
71 | src="/src/assets/images/msg-count.png" | 71 | src="/src/assets/images/msg-count.png" |
72 | - style="width: 5rem; height: 5rem" | ||
73 | - /><img v-else src="/src/assets/images/kf.png" style="width: 5rem; height: 5rem" /> | 72 | + style="width: 5.625rem; height: 5.625rem" |
73 | + /><img v-else src="/src/assets/images/kf.png" style="width: 5.625rem; height: 5.625rem" /> | ||
74 | </div> | 74 | </div> |
75 | <div v-if="!isAdmin(role)" style="display: flex; align-items: center"> | 75 | <div v-if="!isAdmin(role)" style="display: flex; align-items: center"> |
76 | <div> | 76 | <div> |
@@ -93,7 +93,7 @@ | @@ -93,7 +93,7 @@ | ||
93 | <div style="font-size: 1.625rem; color: #333">{{ | 93 | <div style="font-size: 1.625rem; color: #333">{{ |
94 | growCardList?.customerInfo?.sumCount | 94 | growCardList?.customerInfo?.sumCount |
95 | }}</div> | 95 | }}</div> |
96 | - <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | 96 | + <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" /> |
97 | </div> | 97 | </div> |
98 | <div>客户总量(个)</div> | 98 | <div>客户总量(个)</div> |
99 | </div> | 99 | </div> |
1 | <template> | 1 | <template> |
2 | <div> | 2 | <div> |
3 | - <Card title="帮助文档" v-if="!isAdmin(role)"> | 3 | + <div v-if="!isAdmin(role)"> |
4 | <div> | 4 | <div> |
5 | <template v-for="item in helpDoc" :key="item.title"> | 5 | <template v-for="item in helpDoc" :key="item.title"> |
6 | <AnchorLink v-bind="item" /> | 6 | <AnchorLink v-bind="item" /> |
7 | </template> | 7 | </template> |
8 | </div> | 8 | </div> |
9 | <Card | 9 | <Card |
10 | - v-if="!isAdmin(role)" | ||
11 | :tab-list="tabListTitle" | 10 | :tab-list="tabListTitle" |
12 | v-bind="$attrs" | 11 | v-bind="$attrs" |
13 | - :active-tab-key="activeKey" | ||
14 | :bordered="false" | 12 | :bordered="false" |
15 | - @tabChange="onTabChange" | ||
16 | :bodyStyle="{ padding: 0 }" | 13 | :bodyStyle="{ padding: 0 }" |
14 | + :headStyle="{ padding: 0 }" | ||
17 | > | 15 | > |
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" /> | 16 | + <List item-layout="horizontal" :dataSource="dataSource"> |
17 | + <template #renderItem="{ item }"> | ||
18 | + <ListItem> | ||
19 | + <ListItemMeta> | ||
20 | + <template #avatar> | ||
21 | + <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> | ||
41 | </template> | 22 | </template> |
42 | - </ListItem> | ||
43 | - </template> | ||
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> | 23 | + <template #description> |
24 | + <span | ||
25 | + class="cursor-pointer noticeTitle" | ||
26 | + @click="go('/stationnotification/mynotification')" | ||
27 | + >{{ item.sysNotice.title }} | ||
28 | + </span> | ||
29 | + </template> | ||
30 | + <template #title> | ||
31 | + <span>{{ item.user.realName }}</span> | ||
32 | + </template> | ||
33 | + </ListItemMeta> | ||
34 | + <template #extra> | ||
35 | + <Time :value="item.sysNotice.senderDate" /> | ||
54 | </template> | 36 | </template> |
55 | - </CardMeta> | ||
56 | - </Card> | ||
57 | - </div> | 37 | + </ListItem> |
38 | + </template> | ||
39 | + </List> | ||
58 | </Card> | 40 | </Card> |
59 | - </Card> | 41 | + <Card |
42 | + hoverable | ||
43 | + title="联系我们" | ||
44 | + :bordered="false" | ||
45 | + v-bind="$attrs" | ||
46 | + :headStyle="{ padding: 0 }" | ||
47 | + > | ||
48 | + <template #cover> | ||
49 | + <img :src="getQrCode" alt="" style="width: 150px; height: 150px; margin: 50px auto" /> | ||
50 | + </template> | ||
51 | + <CardMeta> | ||
52 | + <template #description> | ||
53 | + <p>联系人: {{ getContacts }}</p> | ||
54 | + <p>联系电话: {{ getTel }}</p> | ||
55 | + <p>联系地址: {{ getAddress }} </p> | ||
56 | + </template> | ||
57 | + </CardMeta> | ||
58 | + </Card> | ||
59 | + </div> | ||
60 | 60 | ||
61 | - <Card v-if="isAdmin(role)"> | 61 | + <Card v-else :bordered="false" :bodyStyle="{ padding: 0 }" v-bind="$attrs"> |
62 | <Descriptions title="租户消息量TOP10" :column="1"> | 62 | <Descriptions title="租户消息量TOP10" :column="1"> |
63 | - <template v-for="(item, index) in 10" :key="index"> | 63 | + <template v-for="index in 10" :key="index"> |
64 | <DescriptionsItem> | 64 | <DescriptionsItem> |
65 | <span | 65 | <span |
66 | class="mr-2" | 66 | class="mr-2" |
@@ -94,13 +94,12 @@ | @@ -94,13 +94,12 @@ | ||
94 | ? '#f8c296' | 94 | ? '#f8c296' |
95 | : '#0b55f1;', | 95 | : '#0b55f1;', |
96 | }" | 96 | }" |
97 | - >{{ index + 1 }}</span | 97 | + >{{ index }}</span |
98 | >兰州天兆猪业</DescriptionsItem | 98 | >兰州天兆猪业</DescriptionsItem |
99 | > | 99 | > |
100 | </template> | 100 | </template> |
101 | </Descriptions> | 101 | </Descriptions> |
102 | - </Card> | ||
103 | - <Card v-if="isAdmin(role)"> | 102 | + <Descriptions title="本月即将过期租户" class="mt-6" /> |
104 | <BasicTable @register="registerTable" /> | 103 | <BasicTable @register="registerTable" /> |
105 | </Card> | 104 | </Card> |
106 | </div> | 105 | </div> |
@@ -115,7 +114,6 @@ | @@ -115,7 +114,6 @@ | ||
115 | import { Time } from '/@/components/Time'; | 114 | import { Time } from '/@/components/Time'; |
116 | import { useGo } from '/@/hooks/web/usePage'; | 115 | import { useGo } from '/@/hooks/web/usePage'; |
117 | import { BasicTable, useTable } from '/@/components/Table'; | 116 | import { BasicTable, useTable } from '/@/components/Table'; |
118 | - import { columns } from './props'; | ||
119 | import { isAdmin } from '/@/enums/roleEnum'; | 117 | import { isAdmin } from '/@/enums/roleEnum'; |
120 | import { getTenantExpireTimeList } from '/@/api/dashboard'; | 118 | import { getTenantExpireTimeList } from '/@/api/dashboard'; |
121 | export default defineComponent({ | 119 | export default defineComponent({ |
@@ -169,16 +167,24 @@ | @@ -169,16 +167,24 @@ | ||
169 | tab: '我的通知', | 167 | tab: '我的通知', |
170 | }, | 168 | }, |
171 | ]; | 169 | ]; |
172 | - const onTabChange = (key) => { | ||
173 | - activeKey.value = key; | ||
174 | - }; | ||
175 | 170 | ||
176 | const [registerTable, { redoHeight }] = useTable({ | 171 | const [registerTable, { redoHeight }] = useTable({ |
177 | api: getTenantExpireTimeList, | 172 | api: getTenantExpireTimeList, |
178 | - title: '本月即将过期租户', | ||
179 | showIndexColumn: false, | 173 | showIndexColumn: false, |
180 | useSearchForm: false, | 174 | useSearchForm: false, |
181 | - columns, | 175 | + bordered: true, |
176 | + columns: [ | ||
177 | + { | ||
178 | + title: '租户名称', | ||
179 | + dataIndex: 'name', | ||
180 | + width: 120, | ||
181 | + }, | ||
182 | + { | ||
183 | + title: '过期时间', | ||
184 | + dataIndex: 'tenantExpireTime', | ||
185 | + width: 120, | ||
186 | + }, | ||
187 | + ], | ||
182 | fetchSetting: { | 188 | fetchSetting: { |
183 | listField: 'expireTenant.items', | 189 | listField: 'expireTenant.items', |
184 | totalField: 'expireTenant.total', | 190 | totalField: 'expireTenant.total', |
@@ -200,11 +206,10 @@ | @@ -200,11 +206,10 @@ | ||
200 | }); | 206 | }); |
201 | onMounted(async () => { | 207 | onMounted(async () => { |
202 | if (isAdmin(props.role)) return; | 208 | if (isAdmin(props.role)) return; |
203 | - | ||
204 | - const res = await getEnterPriseDetail(); | ||
205 | const notice = await notifyMyGetrPageApi({ page: 1, pageSize: 5 }); | 209 | const notice = await notifyMyGetrPageApi({ page: 1, pageSize: 5 }); |
206 | - userStore.setEnterPriseInfo(res); | 210 | + const res = await getEnterPriseDetail(); |
207 | dataSource.value = notice.items; | 211 | dataSource.value = notice.items; |
212 | + userStore.setEnterPriseInfo(res); | ||
208 | }); | 213 | }); |
209 | 214 | ||
210 | return { | 215 | return { |
@@ -216,7 +221,6 @@ | @@ -216,7 +221,6 @@ | ||
216 | getAddress, | 221 | getAddress, |
217 | getTel, | 222 | getTel, |
218 | dataSource, | 223 | dataSource, |
219 | - onTabChange, | ||
220 | go, | 224 | go, |
221 | registerTable, | 225 | registerTable, |
222 | isAdmin, | 226 | isAdmin, |
@@ -45,7 +45,7 @@ | @@ -45,7 +45,7 @@ | ||
45 | /> | 45 | /> |
46 | </div> | 46 | </div> |
47 | </template> | 47 | </template> |
48 | - <TenantTrend /> | 48 | + <TenantTrend :tenantTrendList="tenantTrendList" /> |
49 | </Card> | 49 | </Card> |
50 | <Card v-bind="$attrs" title="客户趋势"> | 50 | <Card v-bind="$attrs" title="客户趋势"> |
51 | <template #extra> | 51 | <template #extra> |
@@ -64,7 +64,7 @@ | @@ -64,7 +64,7 @@ | ||
64 | /> | 64 | /> |
65 | </div> | 65 | </div> |
66 | </template> | 66 | </template> |
67 | - <CustomerTrend /> | 67 | + <CustomerTrend :customerTrendList="customerTrendList" /> |
68 | </Card> | 68 | </Card> |
69 | </div> | 69 | </div> |
70 | </template> | 70 | </template> |
@@ -382,6 +382,8 @@ | @@ -382,6 +382,8 @@ | ||
382 | const { | 382 | const { |
383 | tenantDateValue, | 383 | tenantDateValue, |
384 | customerDateValue, | 384 | customerDateValue, |
385 | + tenantTrendList, | ||
386 | + customerTrendList, | ||
385 | activeTenantIndex, | 387 | activeTenantIndex, |
386 | activeCustomerIndex, | 388 | activeCustomerIndex, |
387 | TenantOrCustomerDateList, | 389 | TenantOrCustomerDateList, |
@@ -3,18 +3,89 @@ | @@ -3,18 +3,89 @@ | ||
3 | <div ref="chartRef" :style="{ height, width }"></div> | 3 | <div ref="chartRef" :style="{ height, width }"></div> |
4 | </template> | 4 | </template> |
5 | <script lang="ts" setup> | 5 | <script lang="ts" setup> |
6 | - import { ref, Ref, withDefaults } from 'vue'; | 6 | + import { ref, Ref, withDefaults, onMounted, watch } from 'vue'; |
7 | import { useECharts } from '/@/hooks/web/useECharts'; | 7 | import { useECharts } from '/@/hooks/web/useECharts'; |
8 | + import { getTrendData } from '/@/api/dashboard/index'; | ||
8 | 9 | ||
9 | interface Props { | 10 | interface Props { |
10 | width?: string; | 11 | width?: string; |
11 | height?: string; | 12 | height?: string; |
13 | + tenantTrendList?: Array<[number, string]>; | ||
12 | } | 14 | } |
13 | - withDefaults(defineProps<Props>(), { | 15 | + const props = withDefaults(defineProps<Props>(), { |
14 | width: '100%', | 16 | width: '100%', |
15 | height: '280px', | 17 | height: '280px', |
18 | + tenantTrendList: () => [], | ||
16 | }); | 19 | }); |
17 | 20 | ||
21 | + watch( | ||
22 | + () => props.tenantTrendList, | ||
23 | + (newValue) => { | ||
24 | + setOptions({ | ||
25 | + tooltip: { | ||
26 | + trigger: 'axis', | ||
27 | + axisPointer: { | ||
28 | + type: 'shadow', | ||
29 | + }, | ||
30 | + }, | ||
31 | + xAxis: { | ||
32 | + type: 'time', | ||
33 | + }, | ||
34 | + yAxis: {}, | ||
35 | + grid: { | ||
36 | + left: '3%', | ||
37 | + right: '4%', | ||
38 | + bottom: '3%', | ||
39 | + containLabel: true, | ||
40 | + }, | ||
41 | + series: [ | ||
42 | + { | ||
43 | + name: '当前趋势', | ||
44 | + type: 'line', | ||
45 | + data: newValue, | ||
46 | + }, | ||
47 | + ], | ||
48 | + }); | ||
49 | + } | ||
50 | + ); | ||
51 | + | ||
18 | const chartRef = ref<HTMLDivElement | null>(null); | 52 | const chartRef = ref<HTMLDivElement | null>(null); |
19 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | 53 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
54 | + onMounted(async () => { | ||
55 | + const endTs = Date.now(); | ||
56 | + const res = await getTrendData({ | ||
57 | + startTs: endTs - 2592000000, | ||
58 | + endTs, | ||
59 | + interval: 86400000, | ||
60 | + trend: 'TENANT_TREND', | ||
61 | + }); | ||
62 | + const transferResult = res.map((item) => { | ||
63 | + return [item.ts, item.value]; | ||
64 | + }); | ||
65 | + setOptions({ | ||
66 | + tooltip: { | ||
67 | + trigger: 'axis', | ||
68 | + axisPointer: { | ||
69 | + type: 'shadow', | ||
70 | + }, | ||
71 | + }, | ||
72 | + xAxis: { | ||
73 | + type: 'time', | ||
74 | + }, | ||
75 | + yAxis: {}, | ||
76 | + grid: { | ||
77 | + left: '3%', | ||
78 | + right: '4%', | ||
79 | + bottom: '3%', | ||
80 | + containLabel: true, | ||
81 | + }, | ||
82 | + series: [ | ||
83 | + { | ||
84 | + name: '当前趋势', | ||
85 | + type: 'line', | ||
86 | + data: transferResult, | ||
87 | + }, | ||
88 | + ], | ||
89 | + }); | ||
90 | + }); | ||
20 | </script> | 91 | </script> |
@@ -47,6 +47,7 @@ | @@ -47,6 +47,7 @@ | ||
47 | type: 'bar', | 47 | type: 'bar', |
48 | stack: 'Total', | 48 | stack: 'Total', |
49 | data: props.alarmList, | 49 | data: props.alarmList, |
50 | + color: '#3C78FF', | ||
50 | }, | 51 | }, |
51 | ], | 52 | ], |
52 | }); | 53 | }); |
@@ -77,6 +78,7 @@ | @@ -77,6 +78,7 @@ | ||
77 | name: '告警数', | 78 | name: '告警数', |
78 | type: 'bar', | 79 | type: 'bar', |
79 | stack: 'Total', | 80 | stack: 'Total', |
81 | + color: '#3C78FF', | ||
80 | data: newValue, | 82 | data: newValue, |
81 | }, | 83 | }, |
82 | ], | 84 | ], |
@@ -68,14 +68,14 @@ | @@ -68,14 +68,14 @@ | ||
68 | type: 'bar', | 68 | type: 'bar', |
69 | stack: 'total', | 69 | stack: 'total', |
70 | data: newValue, | 70 | data: newValue, |
71 | - color: '#9fe080', | 71 | + color: '#5AEEED', |
72 | }, | 72 | }, |
73 | { | 73 | { |
74 | name: '传输消息量', | 74 | name: '传输消息量', |
75 | type: 'bar', | 75 | type: 'bar', |
76 | stack: 'total', | 76 | stack: 'total', |
77 | data: newValue1, | 77 | data: newValue1, |
78 | - color: '#5c7bd9', | 78 | + color: '#3C78FF', |
79 | }, | 79 | }, |
80 | ], | 80 | ], |
81 | }); | 81 | }); |
1 | import { PropType } from 'vue'; | 1 | import { PropType } from 'vue'; |
2 | -import type { BasicColumn } from '/@/components/Table'; | ||
3 | export interface BasicProps { | 2 | export interface BasicProps { |
4 | width: string; | 3 | width: string; |
5 | height: string; | 4 | height: string; |
@@ -14,16 +13,3 @@ export const basicProps = { | @@ -14,16 +13,3 @@ export const basicProps = { | ||
14 | default: '280px', | 13 | default: '280px', |
15 | }, | 14 | }, |
16 | }; | 15 | }; |
17 | - | ||
18 | -export const columns: BasicColumn[] = [ | ||
19 | - { | ||
20 | - title: '租户名称', | ||
21 | - dataIndex: 'name', | ||
22 | - width: 120, | ||
23 | - }, | ||
24 | - { | ||
25 | - title: '过期时间', | ||
26 | - dataIndex: 'tenantExpireTime', | ||
27 | - width: 120, | ||
28 | - }, | ||
29 | -]; |
1 | import { ref } from 'vue'; | 1 | import { ref } from 'vue'; |
2 | +import { getTrendData } from '/@/api/dashboard'; | ||
2 | export function useDate() { | 3 | export function useDate() { |
3 | const tenantDateValue = ref([]); | 4 | const tenantDateValue = ref([]); |
4 | const customerDateValue = ref([]); | 5 | const customerDateValue = ref([]); |
6 | + const tenantTrendList = ref([]); | ||
7 | + const customerTrendList = ref([]); | ||
5 | const activeTenantIndex = ref(0); | 8 | const activeTenantIndex = ref(0); |
6 | const activeCustomerIndex = ref(0); | 9 | const activeCustomerIndex = ref(0); |
7 | const TenantOrCustomerDateList = ref([ | 10 | const TenantOrCustomerDateList = ref([ |
@@ -11,21 +14,34 @@ export function useDate() { | @@ -11,21 +14,34 @@ export function useDate() { | ||
11 | ]); | 14 | ]); |
12 | 15 | ||
13 | // 租户趋势和客户趋势快速选择时间 | 16 | // 租户趋势和客户趋势快速选择时间 |
14 | - function quickQueryTenantOrCustomerTime( | 17 | + async function quickQueryTenantOrCustomerTime( |
15 | index: number, | 18 | index: number, |
16 | value: number, | 19 | value: number, |
17 | flag: 'tenant' | 'customer' | 20 | flag: 'tenant' | 'customer' |
18 | ) { | 21 | ) { |
22 | + const endTs = Date.now(); | ||
19 | if (flag === 'tenant') { | 23 | if (flag === 'tenant') { |
20 | if (activeTenantIndex.value === index) return; | 24 | if (activeTenantIndex.value === index) return; |
21 | activeTenantIndex.value = index; | 25 | activeTenantIndex.value = index; |
22 | tenantDateValue.value = []; | 26 | tenantDateValue.value = []; |
23 | - console.log(value); | 27 | + const res = await getTrendData({ |
28 | + startTs: endTs - value, | ||
29 | + endTs, | ||
30 | + interval: value === 2592000000 ? 86400000 : value === 7776000000 ? 172800000 : 2592000000, | ||
31 | + trend: 'TENANT_TREND', | ||
32 | + }); | ||
33 | + tenantTrendList.value = res.map((item) => [item.ts, item.value]); | ||
24 | } else { | 34 | } else { |
25 | if (activeCustomerIndex.value === index) return; | 35 | if (activeCustomerIndex.value === index) return; |
26 | activeCustomerIndex.value = index; | 36 | activeCustomerIndex.value = index; |
27 | customerDateValue.value = []; | 37 | customerDateValue.value = []; |
28 | - console.log(value); | 38 | + const res = await getTrendData({ |
39 | + startTs: endTs - value, | ||
40 | + endTs, | ||
41 | + interval: value === 2592000000 ? 86400000 : value === 7776000000 ? 172800000 : 2592000000, | ||
42 | + trend: 'CUSTOMER_TREND', | ||
43 | + }); | ||
44 | + customerTrendList.value = res.map((item) => [item.ts, item.value]); | ||
29 | } | 45 | } |
30 | } | 46 | } |
31 | // 租户选择日期 | 47 | // 租户选择日期 |
@@ -41,6 +57,8 @@ export function useDate() { | @@ -41,6 +57,8 @@ export function useDate() { | ||
41 | return { | 57 | return { |
42 | tenantDateValue, | 58 | tenantDateValue, |
43 | customerDateValue, | 59 | customerDateValue, |
60 | + tenantTrendList, | ||
61 | + customerTrendList, | ||
44 | activeTenantIndex, | 62 | activeTenantIndex, |
45 | activeCustomerIndex, | 63 | activeCustomerIndex, |
46 | TenantOrCustomerDateList, | 64 | TenantOrCustomerDateList, |
@@ -10,7 +10,12 @@ | @@ -10,7 +10,12 @@ | ||
10 | </div> | 10 | </div> |
11 | </div> | 11 | </div> |
12 | <div class="md:w-3/10 w-full enter-y"> | 12 | <div class="md:w-3/10 w-full enter-y"> |
13 | - <HelpDoc :role="role" /> | 13 | + <Card |
14 | + :style="{ width: '100%', height: !isAdmin(role) ? '100%' : '98.5%' }" | ||
15 | + :title="!isAdmin(role) ? '帮助文档' : ''" | ||
16 | + > | ||
17 | + <HelpDoc :role="role" /> | ||
18 | + </Card> | ||
14 | </div> | 19 | </div> |
15 | </div> | 20 | </div> |
16 | </template> | 21 | </template> |
@@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
6 | :canFullscreen="false" | 6 | :canFullscreen="false" |
7 | centered | 7 | centered |
8 | @ok="dispatchCustomer" | 8 | @ok="dispatchCustomer" |
9 | + @cancel="resetFields" | ||
9 | :minHeight="150" | 10 | :minHeight="150" |
10 | okText="分配" | 11 | okText="分配" |
11 | > | 12 | > |
@@ -59,6 +60,7 @@ | @@ -59,6 +60,7 @@ | ||
59 | registerModal, | 60 | registerModal, |
60 | registerForm, | 61 | registerForm, |
61 | dispatchCustomer, | 62 | dispatchCustomer, |
63 | + resetFields, | ||
62 | }; | 64 | }; |
63 | }, | 65 | }, |
64 | }); | 66 | }); |
@@ -5,42 +5,27 @@ | @@ -5,42 +5,27 @@ | ||
5 | :alwaysShowTitle="true" | 5 | :alwaysShowTitle="true" |
6 | style="z-index: 99; position: absolute; width: 40px; height: 100px; left: 10%; top: -20px" | 6 | style="z-index: 99; position: absolute; width: 40px; height: 100px; left: 10%; top: -20px" |
7 | /> | 7 | /> |
8 | + | ||
9 | + <AppDarkModeToggle | ||
10 | + class="absolute top-3 right-10 enter-x" | ||
11 | + v-if="!sessionTimeout" | ||
12 | + @click="toggleDark" | ||
13 | + /> | ||
8 | <AppLocalePicker | 14 | <AppLocalePicker |
9 | class="absolute text-white top-4 right-4 enter-x xl:text-gray-600" | 15 | class="absolute text-white top-4 right-4 enter-x xl:text-gray-600" |
10 | :showText="false" | 16 | :showText="false" |
11 | v-if="!sessionTimeout && showLocale" | 17 | v-if="!sessionTimeout && showLocale" |
12 | /> | 18 | /> |
13 | - <AppDarkModeToggle | ||
14 | - class="absolute top-3 right-7 enter-x" | ||
15 | - v-if="!sessionTimeout" | ||
16 | - @click="toggleDark" | ||
17 | - /> | ||
18 | </div> | 19 | </div> |
19 | <div class="login-container" :class="{ light1: isDark, dark: !isDark }"> | 20 | <div class="login-container" :class="{ light1: isDark, dark: !isDark }"> |
20 | - <div class="login-description"> | ||
21 | - <h1>物联网平台</h1> | ||
22 | - <h2>输入您的个人详细信息开始使用!</h2> | ||
23 | - </div> | ||
24 | <div class="flex w-full h-full py-5 xl:h-auto xl:py-0 xl:my-0 xl:w-6/12"> | 21 | <div class="flex w-full h-full py-5 xl:h-auto xl:py-0 xl:my-0 xl:w-6/12"> |
22 | + <div class="login-description absolute right-65 top-30"> | ||
23 | + <h1>物联网平台</h1> | ||
24 | + <h2>输入您的个人详细信息开始使用!</h2> | ||
25 | + </div> | ||
25 | <div | 26 | <div |
26 | :class="`${prefixCls}-form`" | 27 | :class="`${prefixCls}-form`" |
27 | - class=" | ||
28 | - relative | ||
29 | - w-full | ||
30 | - px-5 | ||
31 | - py-8 | ||
32 | - mx-auto | ||
33 | - my-auto | ||
34 | - rounded-md | ||
35 | - shadow-md | ||
36 | - xl:ml-16 xl:bg-transparent | ||
37 | - sm:px-8 | ||
38 | - xl:p-4 xl:shadow-none | ||
39 | - sm:w-3/4 | ||
40 | - lg:w-2/4 | ||
41 | - xl:w-auto | ||
42 | - enter-x | ||
43 | - " | 28 | + class="relative w-full px-5 py-8 mx-auto my-auto rounded-md shadow-md xl:ml-16 xl:bg-transparent sm:px-8 xl:p-4 xl:shadow-none sm:w-3/4 lg:w-2/4 xl:w-auto enter-x" |
44 | :style="{ backgroundColor: isDark ? '#fff' : '#1a2030' }" | 29 | :style="{ backgroundColor: isDark ? '#fff' : '#1a2030' }" |
45 | > | 30 | > |
46 | <LoginForm /> | 31 | <LoginForm /> |
@@ -50,7 +35,17 @@ | @@ -50,7 +35,17 @@ | ||
50 | <QrCodeForm /> | 35 | <QrCodeForm /> |
51 | </div> | 36 | </div> |
52 | </div> | 37 | </div> |
53 | - <div style="position: absolute; bottom: 20px; left: 45%">{{ getCopyRight }}</div> | 38 | + <div |
39 | + style=" | ||
40 | + width: 100%; | ||
41 | + display: flex; | ||
42 | + justify-content: center; | ||
43 | + position: absolute; | ||
44 | + bottom: 1.25rem; | ||
45 | + color: #fff; | ||
46 | + " | ||
47 | + >{{ getCopyRight }}</div | ||
48 | + > | ||
54 | </div> | 49 | </div> |
55 | </div> | 50 | </div> |
56 | </template> | 51 | </template> |
@@ -82,7 +77,10 @@ | @@ -82,7 +77,10 @@ | ||
82 | }; | 77 | }; |
83 | const userStore = useUserStore(); | 78 | const userStore = useUserStore(); |
84 | const getCopyRight = computed(() => { | 79 | const getCopyRight = computed(() => { |
85 | - return (userStore.platInfo?.copyright ?? '') + (userStore.platInfo?.presentedOurselves ?? ''); | 80 | + return ( |
81 | + (userStore.platInfo?.copyright ?? 'Copyright@ 云腾五洲 蜀ICP') + | ||
82 | + (userStore.platInfo?.presentedOurselves ?? '') | ||
83 | + ); | ||
86 | }); | 84 | }); |
87 | </script> | 85 | </script> |
88 | <style lang="less"> | 86 | <style lang="less"> |
@@ -104,9 +102,6 @@ | @@ -104,9 +102,6 @@ | ||
104 | height: 60px; | 102 | height: 60px; |
105 | width: 100%; | 103 | width: 100%; |
106 | background-color: #1d3794; | 104 | background-color: #1d3794; |
107 | - .vben-dark-switch { | ||
108 | - margin-left: 1840px; | ||
109 | - } | ||
110 | } | 105 | } |
111 | 106 | ||
112 | .login-container { | 107 | .login-container { |
@@ -117,28 +112,25 @@ | @@ -117,28 +112,25 @@ | ||
117 | height: calc(100% - 60px); | 112 | height: calc(100% - 60px); |
118 | background-size: 100% 100%; | 113 | background-size: 100% 100%; |
119 | background-repeat: no-repeat; | 114 | background-repeat: no-repeat; |
120 | - .vben-login-form { | ||
121 | - position: absolute; | ||
122 | - | ||
123 | - width: 410px; | ||
124 | - right: 200px; | ||
125 | - top: 50%; | ||
126 | - margin-top: -180px; | ||
127 | - } | ||
128 | .login-description { | 115 | .login-description { |
129 | - position: absolute; | ||
130 | - right: 13%; | ||
131 | - top: 15%; | 116 | + text-align: center; |
132 | h1 { | 117 | h1 { |
133 | - font-size: 26px; | ||
134 | color: #5aeeed; | 118 | color: #5aeeed; |
135 | - text-align: center; | 119 | + |
120 | + font-size: 26px; | ||
136 | } | 121 | } |
137 | h2 { | 122 | h2 { |
138 | - font-size: 20px; | ||
139 | color: #5aeeed; | 123 | color: #5aeeed; |
124 | + font-size: 20px; | ||
140 | } | 125 | } |
141 | } | 126 | } |
127 | + .vben-login-form { | ||
128 | + position: absolute; | ||
129 | + width: 25.625rem; | ||
130 | + right: 12.5rem; | ||
131 | + top: 50%; | ||
132 | + margin-top: -11.25rem; | ||
133 | + } | ||
142 | } | 134 | } |
143 | } | 135 | } |
144 | </style> | 136 | </style> |