Commit 10c47882cbd98ebf7315a67a61032a7435d731cf

Authored by fengwotao
1 parent 02df0669

pref:修改首页饼图为圆环图

1   -<template>
2   - <div>
3   - <!-- 首页基础信息 -->
4   - <div class="md:flex">
5   - <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4" style="color: #666">
6   - <div class="flex" style="height: 100px">
7   - <div class="mr-4"
8   - ><img
9   - src="/src/assets/images/device-count.png"
10   - style="width: 5.625rem; height: 5.625rem"
11   - /></div>
12   - <div class="flex-auto">
13   - <div class="flex justify-between" style="align-items: center">
14   - <div style="font-size: 1.625rem; color: #333; font-weight: bold">
15   - <CountTo
16   - v-if="growCardList?.deviceInfo?.sumCount"
17   - :endVal="growCardList.deviceInfo.sumCount"
18   - />
19   - <CountTo v-else :endVal="0" />
20   - </div>
21   - <Tooltip>
22   - <template #title>
23   - 设备数 : {{ growCardList?.deviceInfo.sumCount }} 今日新增
24   - {{ toThousands(growCardList?.deviceInfo?.todayAdd) }}
25   - </template>
26   - <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" />
27   - </Tooltip>
28   - </div>
29   - <div> 设备数 </div>
30   - </div>
31   - </div>
32   - <div class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
33   - 今日新增 {{ toThousands(growCardList?.deviceInfo?.todayAdd) }}
34   - </div>
35   - </Card>
36   - <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4" style="color: #666">
37   - <div class="flex" style="height: 100px">
38   - <div class="mr-4">
39   - <img
40   - v-if="!isAdmin(role)"
41   - src="/src/assets/images/alarm-count.png"
42   - style="width: 5.625rem; height: 5.625rem"
43   - />
44   - <img v-else src="/src/assets/images/zh.png" style="width: 5.625rem; height: 5.625rem" />
45   - </div>
46   - <div class="flex-auto">
47   - <div class="flex justify-between" style="align-items: center">
48   - <div
49   - v-if="!isAdmin(role)"
50   - style="font-size: 1.625rem; color: #333; font-weight: bold"
51   - >
52   - <CountTo
53   - v-if="growCardList?.alarmInfo?.sumCount"
54   - :end-val="growCardList.alarmInfo.sumCount"
55   - />
56   - <CountTo v-else :end-val="0" />
57   - </div>
58   - <div style="font-size: 1.625rem; color: #333; font-weight: bold" v-else>
59   - <CountTo
60   - v-if="growCardList?.tenantInfo?.sumCount"
61   - :end-val="growCardList.tenantInfo.sumCount"
62   - />
63   - <CountTo v-else :end-val="0" />
64   - </div>
65   - <Tooltip>
66   - <template #title>
67   - {{
68   - !isAdmin(role)
69   - ? `告警数:${growCardList?.alarmInfo?.sumCount} 今日新增 ${toThousands(
70   - growCardList?.alarmInfo?.todayAdd
71   - )}`
72   - : `租户总量:${growCardList?.tenantInfo?.sumCount} 今日新增 ${toThousands(
73   - growCardList?.alarmInfo?.todayAdd
74   - )}`
75   - }}
76   - </template>
77   - <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" />
78   - </Tooltip>
79   - </div>
80   - <div> {{ !isAdmin(role) ? `告警数` : '租户总量' }}</div>
81   - </div>
82   - </div>
83   - <div v-if="!isAdmin(role)" class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
84   - 今日新增 {{ toThousands(growCardList?.alarmInfo?.todayAdd) }}</div
85   - >
86   - <div v-else class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
87   - 今日新增 {{ toThousands(growCardList?.tenantInfo?.todayAdd) }}</div
88   - >
89   - </Card>
90   - <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4" style="color: #666">
91   - <div class="flex" style="height: 100px">
92   - <div class="mr-4">
93   - <img
94   - v-if="!isAdmin(role)"
95   - src="/src/assets/images/msg-count.png"
96   - style="width: 5.625rem; height: 5.625rem"
97   - />
98   - <img v-else src="/src/assets/images/kf.png" style="width: 5.625rem; height: 5.625rem" />
99   - </div>
100   - <div class="flex-auto">
101   - <div class="flex justify-between" style="align-items: center">
102   - <div
103   - v-if="!isAdmin(role)"
104   - style="font-size: 1.625rem; color: #333; font-weight: bold"
105   - >
106   - <CountTo
107   - v-if="growCardList?.messageInfo?.messageCount"
108   - :end-val="growCardList.messageInfo.messageCount"
109   - />
110   - <CountTo v-else :end-val="0" />
111   - </div>
112   - <div style="font-size: 1.625rem; color: #333; font-weight: bold" v-else>
113   - <CountTo
114   - v-if="growCardList?.customerInfo?.sumCount"
115   - :end-val="growCardList.customerInfo.sumCount"
116   - />
117   - <CountTo v-else :end-val="0" />
118   - </div>
119   - <Tooltip>
120   - <template #title>
121   - {{
122   - !isAdmin(role)
123   - ? `消息数:${growCardList?.messageInfo?.messageCount} 今日新增 ${toThousands(
124   - growCardList?.messageInfo?.todayMessageAdd
125   - )}`
126   - : `客户总量:${growCardList?.customerInfo?.sumCount} 今日新增 ${toThousands(
127   - growCardList?.messageInfo?.todayMessageAdd
128   - )}`
129   - }}
130   - </template>
131   - <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" />
132   - </Tooltip>
133   - </div>
134   - <div> {{ !isAdmin(role) ? `消息数` : '客户总量' }}</div>
135   - </div>
136   - </div>
137   - <div v-if="!isAdmin(role)" class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
138   - 今日新增 {{ toThousands(growCardList?.messageInfo?.todayMessageAdd) }}</div
139   - >
140   - <div v-else class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
141   - 今日新增 {{ toThousands(growCardList?.customerInfo?.todayAdd) }}</div
142   - >
143   - </Card>
144   - <Card
145   - v-if="!isAdmin(role)"
146   - size="small"
147   - class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:ml-4"
148   - style="color: #666"
149   - >
150   - <div class="flex" style="height: 100px">
151   - <div class="mr-4">
152   - <img
153   - v-if="!isAdmin(role)"
154   - src="/src/assets/images/product.png"
155   - style="width: 5.625rem; height: 5.625rem"
156   - />
157   - <img
158   - v-else
159   - src="/src/assets/images/product.png"
160   - style="width: 5.625rem; height: 5.625rem"
161   - />
162   - </div>
163   - <div class="flex-auto">
164   - <div class="flex justify-between" style="align-items: center">
165   - <div
166   - v-if="!isAdmin(role)"
167   - style="font-size: 1.625rem; color: #333; font-weight: bold"
168   - >
169   - <CountTo
170   - v-if="growCardList?.productInfo?.sumCount"
171   - :end-val="growCardList.productInfo.sumCount"
172   - />
173   - <CountTo v-else :end-val="0" />
174   - </div>
175   - <div style="font-size: 1.625rem; color: #333; font-weight: bold" v-else>
176   - <CountTo
177   - v-if="growCardList?.productInfo?.sumCount"
178   - :end-val="growCardList.productInfo?.sumCount"
179   - />
180   - <CountTo v-else :end-val="0" />
181   - </div>
182   - <Tooltip>
183   - <template #title>
184   - {{
185   - !isAdmin(role)
186   - ? `产品数:${growCardList?.productInfo?.sumCount} 今日新增 ${toThousands(
187   - growCardList?.productInfo?.todayAdd
188   - )}`
189   - : `产品数:${growCardList?.customerInfo?.sumCount} 今日新增 ${toThousands(
190   - growCardList?.productInfo?.todayAdd
191   - )}`
192   - }}
193   - </template>
194   - <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" />
195   - </Tooltip>
196   - </div>
197   - <div> {{ !isAdmin(role) ? `产品数` : '产品数' }}</div>
198   - </div>
199   - </div>
200   - <div v-if="!isAdmin(role)" class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
201   - 今日新增 {{ toThousands(growCardList?.productInfo?.todayAdd) }}</div
202   - >
203   - <div v-else class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
204   - 今日新增 {{ toThousands(growCardList?.productInfo?.todayAdd) }}</div
205   - >
206   - </Card>
207   - </div>
208   - <!-- 首页饼图 -->
209   - <div class="md:flex mt-4" v-if="!isAdmin(role)">
210   - <Card
211   - size="small"
212   - class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4"
213   - style="color: #666; width: 50%"
214   - >
215   - <div class="flex container ml-4">
216   - <div class="mr-4 flex chart-top">
217   - <PieChartDeviceSub
218   - v-if="seriesData.length > 0"
219   - :legendData="legendData"
220   - :seriesData="seriesData"
221   - :isCircle="true"
222   - />
223   - </div>
224   - <div class="ml-20 flex justify-around right-text">
225   - <div class="text">
226   - 直连设备:{{ growCardList?.deviceInfo?.directConnection ?? 0 }}个
227   - </div>
228   - <div class="text"> 网关设备:{{ growCardList?.deviceInfo?.gateWay ?? 0 }}个 </div>
229   - <div class="text"> 网关子设备:{{ growCardList?.deviceInfo?.sensor ?? 0 }}个 </div>
230   - </div>
231   - </div>
232   - </Card>
233   - <Card
234   - size="small"
235   - class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:ml-1"
236   - style="color: #666; width: 50%"
237   - >
238   - <div class="flex container ml-4">
239   - <div class="mr-4 flex chart-top">
240   - <PieChartDeviceSub
241   - v-if="seriesStatusData.length > 0"
242   - :legendData="legendStatusData"
243   - :seriesData="seriesStatusData"
244   - :isCircle="false"
245   - />
246   - </div>
247   - <div class="ml-20 flex justify-around right-text">
248   - <div class="text"> 待激活设备:{{ growCardList?.deviceInfo?.inActive ?? 0 }}个 </div>
249   - <div class="text"> 在线设备:{{ growCardList?.deviceInfo?.onLine ?? 0 }}个 </div>
250   - <div class="text"> 离线设备:{{ growCardList?.deviceInfo?.offLine ?? 0 }}个 </div>
251   - </div>
252   - </div>
253   - </Card>
254   - </div>
255   - </div>
256   -</template>
257   -<script lang="ts" setup>
258   - import { ref, onMounted, defineComponent, Ref } from 'vue';
259   - import { Card } from 'ant-design-vue';
260   - import { getHomeData } from '/@/api/dashboard';
261   - import { isAdmin } from '/@/enums/roleEnum';
262   - import { toThousands } from '/@/utils/fnUtils';
263   - import { CountTo } from '/@/components/CountTo/index';
264   - import { Tooltip } from 'ant-design-vue';
265   - import { CardList, seriesDataT } from './props';
266   - import PieChartDeviceSub from './PieChartDeviceSub.vue';
267   -
268   - defineProps<{
269   - role: string;
270   - }>();
271   -
272   - defineExpose({
273   - isAdmin,
274   - toThousands,
275   - });
276   -
277   - defineComponent({
278   - Card,
279   - });
280   -
281   - const legendData = ref(['网关设备', '直连设备', '网关子设备']);
282   -
283   - const seriesData: Ref<seriesDataT[]> = ref([]);
284   -
285   - const legendStatusData = ref(['待激活', '在线', '离线']);
286   -
287   - const seriesStatusData: Ref<seriesDataT[]> = ref([]);
288   -
289   - const growCardList = ref<CardList>();
290   -
291   - const devicePieColor = [
292   - { key: 'directConnection', itemStyle: { color: '#5C7BD9' }, value: '直连设备' },
293   - { key: 'gateWay', itemStyle: { color: '#91CC75' }, value: '网关设备' },
294   - { key: 'sensor', itemStyle: { color: '#FAC859' }, value: '网关子设备' },
295   - { key: 'inActive', itemStyle: { color: '#5C7BD9' }, value: '待激活' },
296   - { key: 'onLine', itemStyle: { color: '#91CC75 ' }, value: '在线' },
297   - { key: 'offLine', itemStyle: { color: '#EC4040' }, value: '离线' },
298   - ];
299   -
300   - onMounted(async () => {
301   - const res = await getHomeData();
302   - growCardList.value = res;
303   - const { deviceInfo } = growCardList.value!;
304   - let data = Object.entries(deviceInfo).map(([key, value]) => {
305   - const name = devicePieColor?.find((f) => f.key === key)?.value;
306   - const itemStyle = devicePieColor?.find((f) => f.key === key)?.itemStyle;
307   - return { key, value, itemStyle, name };
308   - });
309   - seriesData.value = data.filter(
310   - (f) => f.key === 'directConnection' || f.key === 'gateWay' || f.key === 'sensor'
311   - );
312   - seriesStatusData.value = data.filter(
313   - (f) => f.key === 'inActive' || f.key === 'onLine' || f.key === 'offLine'
314   - );
315   - });
316   -</script>
317   -<style lang="css">
318   - .right-text {
319   - width: 40%;
320   - flex-direction: column;
321   - height: 240px;
322   - margin: 10px 0 10px 50px;
323   - }
324   -
325   - .text {
326   - color: #333;
327   - font-weight: bold;
328   - display: flex;
329   - flex-wrap: nowrap;
330   - }
331   -
332   - .chart-top {
333   - width: 60%;
334   - height: 300px;
335   - align-items: center;
336   - margin-top: -30px;
337   - }
338   -
339   - .container {
340   - width: 100%;
341   - }
342   -</style>
  1 +<template>
  2 + <div>
  3 + <!-- 首页基础信息 -->
  4 + <div class="md:flex">
  5 + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4" style="color: #666">
  6 + <div class="flex" style="height: 100px">
  7 + <div class="mr-4"
  8 + ><img
  9 + src="/src/assets/images/device-count.png"
  10 + style="width: 5.625rem; height: 5.625rem"
  11 + /></div>
  12 + <div class="flex-auto">
  13 + <div class="flex justify-between" style="align-items: center">
  14 + <div style="font-size: 1.625rem; color: #333; font-weight: bold">
  15 + <CountTo
  16 + v-if="growCardList?.deviceInfo?.sumCount"
  17 + :endVal="growCardList.deviceInfo.sumCount"
  18 + />
  19 + <CountTo v-else :endVal="0" />
  20 + </div>
  21 + <Tooltip>
  22 + <template #title>
  23 + 设备数 : {{ growCardList?.deviceInfo.sumCount }} 今日新增
  24 + {{ toThousands(growCardList?.deviceInfo?.todayAdd) }}
  25 + </template>
  26 + <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" />
  27 + </Tooltip>
  28 + </div>
  29 + <div> 设备数 </div>
  30 + </div>
  31 + </div>
  32 + <div class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
  33 + 今日新增 {{ toThousands(growCardList?.deviceInfo?.todayAdd) }}
  34 + </div>
  35 + </Card>
  36 + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4" style="color: #666">
  37 + <div class="flex" style="height: 100px">
  38 + <div class="mr-4">
  39 + <img
  40 + v-if="!isAdmin(role)"
  41 + src="/src/assets/images/alarm-count.png"
  42 + style="width: 5.625rem; height: 5.625rem"
  43 + />
  44 + <img v-else src="/src/assets/images/zh.png" style="width: 5.625rem; height: 5.625rem" />
  45 + </div>
  46 + <div class="flex-auto">
  47 + <div class="flex justify-between" style="align-items: center">
  48 + <div
  49 + v-if="!isAdmin(role)"
  50 + style="font-size: 1.625rem; color: #333; font-weight: bold"
  51 + >
  52 + <CountTo
  53 + v-if="growCardList?.alarmInfo?.sumCount"
  54 + :end-val="growCardList.alarmInfo.sumCount"
  55 + />
  56 + <CountTo v-else :end-val="0" />
  57 + </div>
  58 + <div style="font-size: 1.625rem; color: #333; font-weight: bold" v-else>
  59 + <CountTo
  60 + v-if="growCardList?.tenantInfo?.sumCount"
  61 + :end-val="growCardList.tenantInfo.sumCount"
  62 + />
  63 + <CountTo v-else :end-val="0" />
  64 + </div>
  65 + <Tooltip>
  66 + <template #title>
  67 + {{
  68 + !isAdmin(role)
  69 + ? `告警数:${growCardList?.alarmInfo?.sumCount} 今日新增 ${toThousands(
  70 + growCardList?.alarmInfo?.todayAdd
  71 + )}`
  72 + : `租户总量:${growCardList?.tenantInfo?.sumCount} 今日新增 ${toThousands(
  73 + growCardList?.alarmInfo?.todayAdd
  74 + )}`
  75 + }}
  76 + </template>
  77 + <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" />
  78 + </Tooltip>
  79 + </div>
  80 + <div> {{ !isAdmin(role) ? `告警数` : '租户总量' }}</div>
  81 + </div>
  82 + </div>
  83 + <div v-if="!isAdmin(role)" class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
  84 + 今日新增 {{ toThousands(growCardList?.alarmInfo?.todayAdd) }}</div
  85 + >
  86 + <div v-else class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
  87 + 今日新增 {{ toThousands(growCardList?.tenantInfo?.todayAdd) }}</div
  88 + >
  89 + </Card>
  90 + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4" style="color: #666">
  91 + <div class="flex" style="height: 100px">
  92 + <div class="mr-4">
  93 + <img
  94 + v-if="!isAdmin(role)"
  95 + src="/src/assets/images/msg-count.png"
  96 + style="width: 5.625rem; height: 5.625rem"
  97 + />
  98 + <img v-else src="/src/assets/images/kf.png" style="width: 5.625rem; height: 5.625rem" />
  99 + </div>
  100 + <div class="flex-auto">
  101 + <div class="flex justify-between" style="align-items: center">
  102 + <div
  103 + v-if="!isAdmin(role)"
  104 + style="font-size: 1.625rem; color: #333; font-weight: bold"
  105 + >
  106 + <CountTo
  107 + v-if="growCardList?.messageInfo?.messageCount"
  108 + :end-val="growCardList.messageInfo.messageCount"
  109 + />
  110 + <CountTo v-else :end-val="0" />
  111 + </div>
  112 + <div style="font-size: 1.625rem; color: #333; font-weight: bold" v-else>
  113 + <CountTo
  114 + v-if="growCardList?.customerInfo?.sumCount"
  115 + :end-val="growCardList.customerInfo.sumCount"
  116 + />
  117 + <CountTo v-else :end-val="0" />
  118 + </div>
  119 + <Tooltip>
  120 + <template #title>
  121 + {{
  122 + !isAdmin(role)
  123 + ? `消息数:${growCardList?.messageInfo?.messageCount} 今日新增 ${toThousands(
  124 + growCardList?.messageInfo?.todayMessageAdd
  125 + )}`
  126 + : `客户总量:${growCardList?.customerInfo?.sumCount} 今日新增 ${toThousands(
  127 + growCardList?.messageInfo?.todayMessageAdd
  128 + )}`
  129 + }}
  130 + </template>
  131 + <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" />
  132 + </Tooltip>
  133 + </div>
  134 + <div> {{ !isAdmin(role) ? `消息数` : '客户总量' }}</div>
  135 + </div>
  136 + </div>
  137 + <div v-if="!isAdmin(role)" class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
  138 + 今日新增 {{ toThousands(growCardList?.messageInfo?.todayMessageAdd) }}</div
  139 + >
  140 + <div v-else class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
  141 + 今日新增 {{ toThousands(growCardList?.customerInfo?.todayAdd) }}</div
  142 + >
  143 + </Card>
  144 + <Card
  145 + v-if="!isAdmin(role)"
  146 + size="small"
  147 + class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:ml-4"
  148 + style="color: #666"
  149 + >
  150 + <div class="flex" style="height: 100px">
  151 + <div class="mr-4">
  152 + <img
  153 + v-if="!isAdmin(role)"
  154 + src="/src/assets/images/product.png"
  155 + style="width: 5.625rem; height: 5.625rem"
  156 + />
  157 + <img
  158 + v-else
  159 + src="/src/assets/images/product.png"
  160 + style="width: 5.625rem; height: 5.625rem"
  161 + />
  162 + </div>
  163 + <div class="flex-auto">
  164 + <div class="flex justify-between" style="align-items: center">
  165 + <div
  166 + v-if="!isAdmin(role)"
  167 + style="font-size: 1.625rem; color: #333; font-weight: bold"
  168 + >
  169 + <CountTo
  170 + v-if="growCardList?.productInfo?.sumCount"
  171 + :end-val="growCardList.productInfo.sumCount"
  172 + />
  173 + <CountTo v-else :end-val="0" />
  174 + </div>
  175 + <div style="font-size: 1.625rem; color: #333; font-weight: bold" v-else>
  176 + <CountTo
  177 + v-if="growCardList?.productInfo?.sumCount"
  178 + :end-val="growCardList.productInfo?.sumCount"
  179 + />
  180 + <CountTo v-else :end-val="0" />
  181 + </div>
  182 + <Tooltip>
  183 + <template #title>
  184 + {{
  185 + !isAdmin(role)
  186 + ? `产品数:${growCardList?.productInfo?.sumCount} 今日新增 ${toThousands(
  187 + growCardList?.productInfo?.todayAdd
  188 + )}`
  189 + : `产品数:${growCardList?.customerInfo?.sumCount} 今日新增 ${toThousands(
  190 + growCardList?.productInfo?.todayAdd
  191 + )}`
  192 + }}
  193 + </template>
  194 + <img src="/src/assets/images/tip.png" style="width: 1.125rem; height: 1.125rem" />
  195 + </Tooltip>
  196 + </div>
  197 + <div> {{ !isAdmin(role) ? `产品数` : '产品数' }}</div>
  198 + </div>
  199 + </div>
  200 + <div v-if="!isAdmin(role)" class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
  201 + 今日新增 {{ toThousands(growCardList?.productInfo?.todayAdd) }}</div
  202 + >
  203 + <div v-else class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5">
  204 + 今日新增 {{ toThousands(growCardList?.productInfo?.todayAdd) }}</div
  205 + >
  206 + </Card>
  207 + </div>
  208 + <!-- 首页饼图 -->
  209 + <div class="md:flex mt-4" v-if="!isAdmin(role)">
  210 + <Card
  211 + size="small"
  212 + class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4"
  213 + style="color: #666; width: 50%"
  214 + title="设备数量统计"
  215 + >
  216 + <div class="flex container ml-4">
  217 + <div class="mr-4 flex chart-top">
  218 + <PieChartDeviceSub
  219 + v-if="seriesData.length > 0"
  220 + :legendData="legendData"
  221 + :seriesData="seriesData"
  222 + :isCircle="false"
  223 + />
  224 + </div>
  225 + <div class="ml-20 flex justify-around right-text">
  226 + <div class="text flex items-center">
  227 + <span class="left-icon-d-color"></span>
  228 + 直连设备:{{ growCardList?.deviceInfo?.directConnection ?? 0 }}个
  229 + </div>
  230 + <div class="text flex items-center">
  231 + <span class="left-icon-g-color"></span>
  232 + 网关设备:{{ growCardList?.deviceInfo?.gateWay ?? 0 }}个
  233 + </div>
  234 + <div class="text flex items-center">
  235 + <span class="left-icon-s-color"></span>
  236 + 网关子设备:{{ growCardList?.deviceInfo?.sensor ?? 0 }}个
  237 + </div>
  238 + </div>
  239 + </div>
  240 + </Card>
  241 + <Card
  242 + size="small"
  243 + class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:ml-1"
  244 + style="color: #666; width: 50%"
  245 + title="设备状态统计"
  246 + >
  247 + <div class="flex container ml-4">
  248 + <div class="mr-4 flex chart-top-status">
  249 + <PieChartDeviceStatus
  250 + v-if="seriesStatusData.length > 0"
  251 + :seriesStatusData="seriesStatusData"
  252 + />
  253 + <div class="empty-box" v-else><Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" /></div>
  254 + </div>
  255 + <div class="ml-20 flex justify-around right-text">
  256 + <div class="text flex items-center">
  257 + <span class="right-icon-d-color"></span>
  258 + 待激活设备:{{ growCardList?.deviceInfo?.inActive ?? 0 }}个
  259 + </div>
  260 + <div class="text flex items-center">
  261 + <span class="right-icon-g-color"></span>
  262 + 在线设备:{{ growCardList?.deviceInfo?.onLine ?? 0 }}个
  263 + </div>
  264 + <div class="text flex items-center">
  265 + <span class="right-icon-s-color"></span>
  266 + 离线设备:{{ growCardList?.deviceInfo?.offLine ?? 0 }}个
  267 + </div>
  268 + </div>
  269 + </div>
  270 + </Card>
  271 + </div>
  272 + </div>
  273 +</template>
  274 +<script lang="ts" setup>
  275 + import { ref, onMounted, defineComponent, Ref } from 'vue';
  276 + import { Card } from 'ant-design-vue';
  277 + import { getHomeData } from '/@/api/dashboard';
  278 + import { isAdmin } from '/@/enums/roleEnum';
  279 + import { toThousands } from '/@/utils/fnUtils';
  280 + import { CountTo } from '/@/components/CountTo/index';
  281 + import { Tooltip } from 'ant-design-vue';
  282 + import { CardList, seriesDataT } from './props';
  283 + import PieChartDeviceSub from './PieChartDeviceSub.vue';
  284 + import PieChartDeviceStatus from './PieChartDeviceStatus.vue';
  285 + import { Empty } from 'ant-design-vue';
  286 +
  287 + defineProps<{
  288 + role: string;
  289 + }>();
  290 +
  291 + defineExpose({
  292 + isAdmin,
  293 + toThousands,
  294 + });
  295 +
  296 + defineComponent({
  297 + Card,
  298 + });
  299 +
  300 + const legendData = ref(['网关设备', '直连设备', '网关子设备']);
  301 +
  302 + const seriesData: Ref<seriesDataT[]> = ref([]);
  303 +
  304 + const seriesStatusData: Ref<seriesDataT[]> = ref([]);
  305 +
  306 + const growCardList = ref<CardList>();
  307 +
  308 + const devicePieColor = [
  309 + { key: 'directConnection', itemStyle: { color: '#5C7BD9' }, value: '直连设备' },
  310 + { key: 'gateWay', itemStyle: { color: '#91CC75' }, value: '网关设备' },
  311 + { key: 'sensor', itemStyle: { color: '#FAC859' }, value: '网关子设备' },
  312 + { key: 'inActive', itemStyle: { color: '#5C7BD9' }, value: '待激活' },
  313 + { key: 'onLine', itemStyle: { color: '#91CC75 ' }, value: '在线' },
  314 + { key: 'offLine', itemStyle: { color: '#EC4040' }, value: '离线' },
  315 + ];
  316 +
  317 + onMounted(async () => {
  318 + const res = await getHomeData();
  319 + growCardList.value = res;
  320 + const { deviceInfo } = growCardList.value!;
  321 + let data = Object.entries(deviceInfo).map(([key, value]) => {
  322 + const name = devicePieColor?.find((f) => f.key === key)?.value;
  323 + const itemStyle = devicePieColor?.find((f) => f.key === key)?.itemStyle;
  324 + return { key, value, itemStyle, name };
  325 + });
  326 + seriesData.value = data.filter(
  327 + (f) => f.key === 'directConnection' || f.key === 'gateWay' || f.key === 'sensor'
  328 + );
  329 + seriesStatusData.value = data.filter(
  330 + (f) => f.key === 'inActive' || f.key === 'onLine' || f.key === 'offLine'
  331 + );
  332 + });
  333 +</script>
  334 +<style lang="less">
  335 + .right-text {
  336 + width: 40%;
  337 + flex-direction: column;
  338 + height: 240px;
  339 + margin: 10px 0 10px 50px;
  340 + }
  341 +
  342 + .text {
  343 + color: #333;
  344 + font-weight: bold;
  345 + display: flex;
  346 + flex-wrap: nowrap;
  347 + }
  348 +
  349 + .chart-top {
  350 + width: 60%;
  351 + height: 300px;
  352 + align-items: center;
  353 + margin-top: -30px;
  354 + }
  355 +
  356 + .container {
  357 + width: 100%;
  358 + }
  359 +
  360 + .chart-top-status {
  361 + height: 300px;
  362 + align-items: center;
  363 + margin-top: -40px;
  364 + }
  365 +
  366 + .base-left-icon-color {
  367 + border-radius: 50%;
  368 + width: 15px;
  369 + height: 15px;
  370 + position: relative;
  371 + right: 10px;
  372 + }
  373 + .left-icon-d-color :extend(.base-left-icon-color) {
  374 + background-color: #5c7bd9;
  375 + }
  376 + .left-icon-g-color :extend(.base-left-icon-color) {
  377 + background-color: #91cc75;
  378 + }
  379 + .left-icon-s-color :extend(.base-left-icon-color) {
  380 + background-color: #fac859;
  381 + }
  382 + .right-icon-d-color :extend(.base-left-icon-color) {
  383 + background-color: #5c7bd9;
  384 + }
  385 + .right-icon-g-color :extend(.base-left-icon-color) {
  386 + background-color: #91cc75;
  387 + }
  388 + .right-icon-s-color :extend(.base-left-icon-color) {
  389 + background-color: #ec4040;
  390 + }
  391 +</style>
... ...
  1 +<template>
  2 + <div v-for="(item, index) in seriesStatusData" :key="index">
  3 + <div :id="`chartPie${item.key}`" style="width: 150px; height: 200px"></div>
  4 + </div>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent, PropType, onMounted, toRefs } from 'vue';
  8 + import * as echarts from 'echarts';
  9 + import { seriesDataT } from './props';
  10 +
  11 + export default defineComponent({
  12 + props: {
  13 + seriesStatusData: {
  14 + type: Array as PropType<seriesDataT[]>,
  15 + default: () => [],
  16 + },
  17 + },
  18 +
  19 + setup(props) {
  20 + const { seriesStatusData } = toRefs(props);
  21 + const total = seriesStatusData.value
  22 + .map((m) => m.value)
  23 + .reduce((prev, cur) => prev! + cur!, 0);
  24 + onMounted(() => {
  25 + seriesStatusData.value.forEach((item) => {
  26 + initEchart(item.key, item, item.value);
  27 + });
  28 + });
  29 +
  30 + const initEchart = (id, item, value) => {
  31 + //牵引线条颜色
  32 + const labelLine = {
  33 + normal: {
  34 + show: true,
  35 + length: 20,
  36 + length2: 20,
  37 + lineStyle: {
  38 + color: '#808080',
  39 + },
  40 + },
  41 + } as any;
  42 + const legendKey = item.key == 'onLine' ? '在线' : item.key == 'offLine' ? '离线' : '待激活';
  43 + const echartInstance = echarts.init(
  44 + document.getElementById(`chartPie${id}`) as HTMLElement
  45 + );
  46 + echartInstance.setOption({
  47 + backgroundColor: '#ffffff',
  48 + tooltip: {
  49 + trigger: 'item',
  50 + formatter: `${legendKey}设备${((value / total!) * 100).toFixed(2)}%`,
  51 + },
  52 + legend: {
  53 + bottom: 0,
  54 + left: 'center',
  55 + data: [legendKey],
  56 + },
  57 + graphic: [
  58 + {
  59 + type: 'text',
  60 + left: '42%',
  61 + top: '48%',
  62 + z: 10,
  63 + style: {
  64 + fill: '#1a1a1a',
  65 + text: value + '个',
  66 + font: '14px Microsoft YaHei',
  67 + },
  68 + },
  69 + ],
  70 + series: [
  71 + {
  72 + data: [item],
  73 + avoidLabelOverlap: false,
  74 + type: 'pie',
  75 + radius: ['40%', '60%'],
  76 + label: {
  77 + normal: {
  78 + show: true,
  79 + position: 'outer',
  80 + formatter: `${legendKey}${((value / total!) * 100).toFixed(2)}%`,
  81 + borderWidth: 5,
  82 + borderRadius: 0,
  83 + padding: [90, -60],
  84 + },
  85 + },
  86 + labelLine,
  87 + },
  88 + ],
  89 + });
  90 + window.addEventListener('resize', () => echartInstance.resize());
  91 + };
  92 + },
  93 + });
  94 +</script>
... ...
1   -<template>
2   - <div v-show="dataSeries.length" ref="chartRef" :style="{ height, width }"></div>
3   - <div class="empty-box" v-show="!dataSeries.length"
4   - ><Empty :image="Empty.PRESENTED_IMAGE_SIMPLE"
5   - /></div>
6   -</template>
7   -<script lang="ts">
8   - import { defineComponent, PropType, ref, Ref, onMounted, toRefs } from 'vue';
9   - import { useECharts } from '/@/hooks/web/useECharts';
10   - import { Empty } from 'ant-design-vue';
11   - import { seriesDataT } from './props';
12   -
13   - export default defineComponent({
14   - components: { Empty },
15   - props: {
16   - width: {
17   - type: String as PropType<string>,
18   - default: '100%',
19   - },
20   - height: {
21   - type: String as PropType<string>,
22   - default: '200px',
23   - },
24   - legendData: {
25   - type: Array,
26   - default: () => [],
27   - },
28   - seriesData: {
29   - type: Array,
30   - default: () => [],
31   - },
32   - isCircle: {
33   - type: Boolean,
34   - default: true,
35   - },
36   - },
37   - setup(props) {
38   - const { legendData, seriesData } = toRefs(props);
39   - const dataSeries: Ref<seriesDataT[]> = ref([]);
40   - const legendDatas: Ref<seriesDataT[]> = ref([]);
41   - dataSeries.value = seriesData.value as unknown as seriesDataT[];
42   - legendDatas.value = legendData.value as unknown as seriesDataT[];
43   -
44   - const chartRef = ref<HTMLDivElement | null>(null);
45   - const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
46   - const labelLine = {
47   - normal: {
48   - show: true,
49   - length2: 1,
50   - },
51   - } as any;
52   - onMounted(() => {
53   - setOptions({
54   - backgroundColor: '#ffffff',
55   - tooltip: {
56   - trigger: 'item',
57   - formatter: '{b} {d}%',
58   - },
59   - legend: {
60   - bottom: 0,
61   - width: 500,
62   - height: 200,
63   - left: 'center',
64   - data: legendDatas.value,
65   - },
66   - series: [
67   - {
68   - avoidLabelOverlap: false,
69   - type: 'pie',
70   - radius: props.isCircle ? '60%' : ['40%', '60%'],
71   - data: dataSeries.value,
72   - emphasis: {
73   - itemStyle: {
74   - shadowBlur: 10,
75   - shadowOffsetX: 0,
76   - shadowColor: 'rgba(0, 0, 0, 0.5)',
77   - },
78   - },
79   - labelLine,
80   - },
81   - ],
82   - });
83   - //自适应
84   - window.addEventListener('resize', () => resize());
85   - });
86   - return { chartRef, Empty, dataSeries };
87   - },
88   - });
89   -</script>
90   -
91   -<style>
92   - .empty-box {
93   - display: flex;
94   - align-items: center;
95   - margin: 0 120px;
96   - }
97   -</style>
  1 +<template>
  2 + <div v-show="dataSeries.length" ref="chartRef" :style="{ height, width }"></div>
  3 + <div class="empty-box" v-show="!dataSeries.length"
  4 + ><Empty :image="Empty.PRESENTED_IMAGE_SIMPLE"
  5 + /></div>
  6 +</template>
  7 +<script lang="ts">
  8 + import { defineComponent, PropType, ref, Ref, onMounted, toRefs } from 'vue';
  9 + import { useECharts } from '/@/hooks/web/useECharts';
  10 + import { Empty } from 'ant-design-vue';
  11 + import { seriesDataT } from './props';
  12 +
  13 + export default defineComponent({
  14 + components: { Empty },
  15 + props: {
  16 + width: {
  17 + type: String as PropType<string>,
  18 + default: '100%',
  19 + },
  20 + height: {
  21 + type: String as PropType<string>,
  22 + default: '200px',
  23 + },
  24 + legendData: {
  25 + type: Array,
  26 + default: () => [],
  27 + },
  28 + seriesData: {
  29 + type: Array,
  30 + default: () => [],
  31 + },
  32 + isCircle: {
  33 + type: Boolean,
  34 + default: true,
  35 + },
  36 + },
  37 + setup(props) {
  38 + const { legendData, seriesData } = toRefs(props);
  39 + const dataSeries: Ref<seriesDataT[]> = ref([]);
  40 + const legendDatas: Ref<seriesDataT[]> = ref([]);
  41 + dataSeries.value = seriesData.value as unknown as seriesDataT[];
  42 + legendDatas.value = legendData.value as unknown as seriesDataT[];
  43 +
  44 + const chartRef = ref<HTMLDivElement | null>(null);
  45 + const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
  46 + const labelLine = {
  47 + normal: {
  48 + show: true,
  49 + length2: 1,
  50 + },
  51 + } as any;
  52 + onMounted(() => {
  53 + setOptions({
  54 + backgroundColor: '#ffffff',
  55 + tooltip: {
  56 + trigger: 'item',
  57 + formatter: '{b} {d}%',
  58 + },
  59 + legend: {
  60 + bottom: 0,
  61 + left: 'center',
  62 + data: legendDatas.value,
  63 + },
  64 + series: [
  65 + {
  66 + avoidLabelOverlap: false,
  67 + type: 'pie',
  68 + radius: props.isCircle ? '60%' : ['40%', '60%'],
  69 + data: dataSeries.value,
  70 + emphasis: {
  71 + itemStyle: {
  72 + shadowBlur: 10,
  73 + shadowOffsetX: 0,
  74 + shadowColor: 'rgba(0, 0, 0, 0.5)',
  75 + },
  76 + },
  77 + labelLine,
  78 + },
  79 + ],
  80 + });
  81 + //自适应
  82 + window.addEventListener('resize', () => resize());
  83 + });
  84 + return { chartRef, Empty, dataSeries };
  85 + },
  86 + });
  87 +</script>
  88 +
  89 +<style>
  90 + .empty-box {
  91 + display: flex;
  92 + align-items: center;
  93 + margin: 0 120px;
  94 + }
  95 +</style>
... ...
1   -import { PropType } from 'vue';
2   -export interface BasicProps {
3   - width: string;
4   - height: string;
5   -}
6   -export const basicProps = {
7   - width: {
8   - type: String as PropType<string>,
9   - default: '100%',
10   - },
11   - height: {
12   - type: String as PropType<string>,
13   - default: '280px',
14   - },
15   -};
16   -
17   -export interface CardList {
18   - deviceInfo: {
19   - sumCount: number;
20   - onLine: number;
21   - offLine: number;
22   - inActive: number;
23   - todayAdd: number;
24   - directConnection: number;
25   - gateWay: number;
26   - sensor: number;
27   - };
28   - tenantInfo?: { sumCount: number; todayAdd: number };
29   - customerInfo?: { sumCount: number; todayAdd: number };
30   - alarmInfo?: {
31   - sumCount: number;
32   - todayAdd: number;
33   - };
34   - messageInfo?: {
35   - dataPointsCount: number;
36   - messageCount: number;
37   - todayDataPointsAdd: number;
38   - todayMessageAdd: number;
39   - };
40   - productInfo?: {
41   - sumCount: number;
42   - todayAdd: number;
43   - };
44   -}
45   -export type seriesDataT = {
46   - value: number | undefined;
47   - name: string | undefined;
48   - itemStyle: object | undefined;
49   - key?: string | undefined;
50   -};
  1 +import { PropType } from 'vue';
  2 +export interface BasicProps {
  3 + width: string;
  4 + height: string;
  5 +}
  6 +export const basicProps = {
  7 + width: {
  8 + type: String as PropType<string>,
  9 + default: '100%',
  10 + },
  11 + height: {
  12 + type: String as PropType<string>,
  13 + default: '280px',
  14 + },
  15 +};
  16 +
  17 +export interface CardList {
  18 + deviceInfo: {
  19 + sumCount: number;
  20 + onLine: number;
  21 + offLine: number;
  22 + inActive: number;
  23 + todayAdd: number;
  24 + directConnection: number;
  25 + gateWay: number;
  26 + sensor: number;
  27 + };
  28 + tenantInfo?: { sumCount: number; todayAdd: number };
  29 + customerInfo?: { sumCount: number; todayAdd: number };
  30 + alarmInfo?: {
  31 + sumCount: number;
  32 + todayAdd: number;
  33 + };
  34 + messageInfo?: {
  35 + dataPointsCount: number;
  36 + messageCount: number;
  37 + todayDataPointsAdd: number;
  38 + todayMessageAdd: number;
  39 + };
  40 + productInfo?: {
  41 + sumCount: number;
  42 + todayAdd: number;
  43 + };
  44 +}
  45 +export type seriesDataT = {
  46 + value: number | undefined;
  47 + name: string | undefined;
  48 + itemStyle: object | undefined;
  49 + key?: string | undefined;
  50 +};
... ...