diff --git a/src/views/dashboard/workplace/components/content-publishing-source.vue b/src/views/dashboard/workplace/components/content-publishing-source.vue new file mode 100644 index 0000000..f1f7c1d --- /dev/null +++ b/src/views/dashboard/workplace/components/content-publishing-source.vue @@ -0,0 +1,403 @@ +<template> + <a-spin :loading="loading" style="width: 100%"> + <a-grid :cols="24" :row-gap="10" :col-gap="10" class="panel"> + <a-grid-item + class="panel-col" + :span="{ xs: 12, sm: 12, md: 12, lg: 8, xl: 8, xxl: 8 }" + > + <a-card + class="general-card" + > + <Chart style="width: 100%; height: 300px" :option="deviceSatusChartOption" /> + </a-card> + </a-grid-item> + <a-grid-item + class="panel-col" + :span="{ xs: 12, sm: 12, md: 12, lg: 8, xl: 8, xxl: 8 }" + > + <a-card + class="general-card" + > + <Chart style="width: 100%; height: 300px" :option="deviceTypeChartOption" /> + </a-card> + </a-grid-item> + <a-grid-item + class="panel-col" + :span="{ xs: 12, sm: 12, md: 12, lg: 8, xl: 8, xxl: 8 }" + > + <a-card + class="general-card" + > + <Chart style="width: 100%; height: 300px" :option="warringTypeChartOption" /> + </a-card> + </a-grid-item> + </a-grid> + </a-spin> +</template> + +<script lang="ts" setup> + import useLoading from '@/hooks/loading'; + import useChartOption from '@/hooks/chart-option'; + + const props = defineProps({ + deviceInfo: { + type: Object, + default: () => { + return {}; + }, + }, + alarmInfo: { + type: Object, + default: () => { + return {}; + }, + }, + productInfo: { + type: Object, + default: () => { + return {}; + }, + }, + }); + + const { chartOption: deviceSatusChartOption } = useChartOption((isDark) => { + const graphicElementStyle = { + textAlign: 'center', + fill: isDark ? 'rgba(255,255,255,0.7)' : '#4E5969', + fontSize: 14, + lineWidth: 10, + fontWeight: 'bold', + }; + return { + legend: { + left: 'center', + data: ['在线', '离线', '停用'], + bottom: 0, + icon: 'circle', + itemWidth: 8, + textStyle: { + color: isDark ? 'rgba(255,255,255,0.7)' : '#4E5969', + }, + itemStyle: { + borderWidth: 0, + }, + }, + tooltip: { + show: true, + trigger: 'item', + }, + graphic: { + elements: [ + { + type: 'text', + left: 'center', + top: 'center', + style: { + text: '设备状态', + ...graphicElementStyle, + }, + }, + ], + }, + series: [ + { + type: 'pie', + radius: ['50%', '70%'], + center: ['50%', '50%'], + label: { + formatter: '{d}% ', + color: isDark ? 'rgba(255, 255, 255, 0.7)' : '#4E5969', + }, + itemStyle: { + borderColor: isDark ? '#000' : '#fff', + borderWidth: 1, + }, + data: [ + { + value: props.deviceInfo.onlineCount, + name: '在线', + itemStyle: { + color: '#249EFF', + }, + }, + { + value: props.deviceInfo.offlineCount, + name: '离线', + itemStyle: { + color: '#846BCE', + }, + }, + { + value: props.deviceInfo.disableCount, + name: '停用', + itemStyle: { + color: '#21CCFF', + }, + }, + ], + }, + // { + // type: 'pie', + // radius: ['50%', '70%'], + // center: ['50%', '50%'], + // label: { + // formatter: '{d}% ', + // color: isDark ? 'rgba(255, 255, 255, 0.7)' : '#4E5969', + // }, + // itemStyle: { + // borderColor: isDark ? '#000' : '#fff', + // borderWidth: 1, + // }, + // data: [ + // { + // value: [148564], + // name: 'UGC原创', + // itemStyle: { + // color: '#249EFF', + // }, + // }, + // { + // value: [334271], + // name: '国外网站', + // itemStyle: { + // color: '#846BCE', + // }, + // }, + // { + // value: [445694], + // name: '转载文章', + // itemStyle: { + // color: '#21CCFF', + // }, + // }, + // { + // value: [445694], + // name: '行业报告', + // itemStyle: { + // color: '#0E42D2', + // }, + // }, + // { + // value: [445694], + // name: '其他', + // itemStyle: { + // color: '#86DF6C', + // }, + // }, + // ], + // }, + // { + // type: 'pie', + // radius: ['50%', '70%'], + // center: ['88%', '50%'], + // label: { + // formatter: '{d}% ', + // color: isDark ? 'rgba(255, 255, 255, 0.7)' : '#4E5969', + // }, + // itemStyle: { + // borderColor: isDark ? '#000' : '#fff', + // borderWidth: 1, + // }, + // data: [ + // { + // value: [148564], + // name: 'UGC原创', + // itemStyle: { + // color: '#249EFF', + // }, + // }, + // { + // value: [334271], + // name: '国外网站', + // itemStyle: { + // color: '#846BCE', + // }, + // }, + // { + // value: [445694], + // name: '转载文章', + // itemStyle: { + // color: '#21CCFF', + // }, + // }, + // { + // value: [445694], + // name: '行业报告', + // itemStyle: { + // color: '#0E42D2', + // }, + // }, + // { + // value: [445694], + // name: '其他', + // itemStyle: { + // color: '#86DF6C', + // }, + // }, + // ], + // }, + ], + }; + }); + const { chartOption: deviceTypeChartOption } = useChartOption((isDark) => { + const graphicElementStyle = { + textAlign: 'center', + fill: isDark ? 'rgba(255,255,255,0.7)' : '#4E5969', + fontSize: 14, + lineWidth: 10, + fontWeight: 'bold', + }; + return { + legend: { + left: 'center', + data: ['直连设备', '网关设备', '网关子设备'], + bottom: 0, + icon: 'circle', + itemWidth: 8, + textStyle: { + color: isDark ? 'rgba(255,255,255,0.7)' : '#4E5969', + }, + itemStyle: { + borderWidth: 0, + }, + }, + tooltip: { + show: true, + trigger: 'item', + }, + graphic: { + elements: [ + { + type: 'text', + left: 'center', + top: 'center', + style: { + text: '设备类型', + ...graphicElementStyle, + }, + } + ], + }, + series: [ + { + type: 'pie', + radius: ['50%', '70%'], + center: ['50%', '50%'], + label: { + formatter: '{d}% ', + color: isDark ? 'rgba(255, 255, 255, 0.7)' : '#4E5969', + }, + itemStyle: { + borderColor: isDark ? '#000' : '#fff', + borderWidth: 1, + }, + data: [ + { + value: props.deviceInfo.directCount, + name: '直连设备', + itemStyle: { + color: '#249EFF', + }, + }, + { + value: props.deviceInfo.gatewayCount, + name: '网关设备', + itemStyle: { + color: '#846BCE', + }, + }, + { + value: props.deviceInfo.gatewaySubCount, + name: '网关子设备', + itemStyle: { + color: '#21CCFF', + }, + }, + ], + }, + ], + }; + }); + const { chartOption: warringTypeChartOption } = useChartOption((isDark) => { + const graphicElementStyle = { + textAlign: 'center', + fill: isDark ? 'rgba(255,255,255,0.7)' : '#4E5969', + fontSize: 14, + lineWidth: 10, + fontWeight: 'bold', + }; + return { + legend: { + left: 'center', + data: ['注意', '告警', '严重'], + bottom: 0, + icon: 'circle', + itemWidth: 8, + textStyle: { + color: isDark ? 'rgba(255,255,255,0.7)' : '#4E5969', + }, + itemStyle: { + borderWidth: 0, + }, + }, + tooltip: { + show: true, + trigger: 'item', + }, + graphic: { + elements: [ + { + type: 'text', + left: 'center', + top: 'center', + style: { + text: '告警类型', + ...graphicElementStyle, + }, + } + ], + }, + series: [ + { + type: 'pie', + radius: ['50%', '70%'], + center: ['50%', '50%'], + label: { + formatter: '{d}% ', + color: isDark ? 'rgba(255, 255, 255, 0.7)' : '#4E5969', + }, + itemStyle: { + borderColor: isDark ? '#000' : '#fff', + borderWidth: 1, + }, + data: [ + { + value: props.alarmInfo.firstWarningCount, + name: '注意', + itemStyle: { + color: '#249EFF', + }, + }, + { + value: props.alarmInfo.secondWarningCount, + name: '告警', + itemStyle: { + color: '#846BCE', + }, + }, + { + value: props.alarmInfo.thirdWarningCount, + name: '严重', + itemStyle: { + color: '#ff2121', + }, + } + ], + }, + ], + }; + }); + const { loading } = useLoading(false); +</script> + +<style scoped lang="less"></style> diff --git a/src/views/dashboard/workplace/components/data-panel.vue b/src/views/dashboard/workplace/components/data-panel.vue index 53a677b..6ef6759 100644 --- a/src/views/dashboard/workplace/components/data-panel.vue +++ b/src/views/dashboard/workplace/components/data-panel.vue @@ -11,7 +11,7 @@ <a-statistic title="产品数" value-style="font-size:36px" - :value="365" + :value="props.productInfo.productCount" :value-from="0" animation > @@ -32,7 +32,7 @@ <!-- />--> </a-col> </a-row> - <a-descriptions :data="data" layout="inline-vertical" class="responsive-margin" /> + <a-descriptions :data="productData" layout="inline-vertical" class="responsive-margin" /> </a-card> @@ -47,7 +47,7 @@ <a-statistic title="设备数" value-style="font-size:36px" - :value="deviceInfo.deviceCount" + :value="props.deviceInfo.deviceCount" :value-from="0" animation > @@ -62,7 +62,7 @@ /> </a-col> </a-row> - <a-descriptions :data="data" layout="inline-vertical" class="responsive-margin" /> + <a-descriptions :data="deviceData" layout="inline-vertical" class="responsive-margin" /> </a-card> @@ -77,7 +77,7 @@ <a-statistic title="产品数" value-style="font-size:36px" - :value="365" + :value="props.alarmInfo.warningCount" :value-from="0" animation > @@ -92,7 +92,7 @@ /> </a-col> </a-row> - <a-descriptions :data="data" layout="inline-vertical" class="responsive-margin" /> + <a-descriptions :data="alarmData" layout="inline-vertical" class="responsive-margin" /> </a-card> @@ -107,97 +107,65 @@ <a-divider class="panel-border" /> </a-grid-item> </a-grid> - <a-grid :span="24" :row-gap="10" :col-gap="10" class="panel"> - <a-grid-item - class="panel-col" - :span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 8, xxl: 8 }"> - <ChainItem - title="分享总量" - quota="share" - chart-type="pie" - :card-style="{ - background: isDark - ? 'linear-gradient(180deg, #312565 0%, #201936 100%)' - : 'linear-gradient(180deg, #F7F7FF 0%, #ECECFF 100%)', - }" - /> - </a-grid-item> - <a-grid-item - class="panel-col" - :span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 8, xxl: 8 }"> - <ChainItem - title="分享总量" - quota="share" - chart-type="pie" - :card-style="{ - background: isDark - ? 'linear-gradient(180deg, #312565 0%, #201936 100%)' - : 'linear-gradient(180deg, #F7F7FF 0%, #ECECFF 100%)', - }" - /> - </a-grid-item> - <a-grid-item - class="panel-col" - :span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 8, xxl: 8 }"> - <ChainItem - title="分享总量" - quota="share" - chart-type="pie" - :card-style="{ - background: isDark - ? 'linear-gradient(180deg, #312565 0%, #201936 100%)' - : 'linear-gradient(180deg, #F7F7FF 0%, #ECECFF 100%)', - }" - /> - </a-grid-item> - <a-grid-item :span="24"> - <a-divider class="panel-border" /> - </a-grid-item> - </a-grid> </div> </template> <script lang="ts" setup> import Announcement from '@/views/dashboard/workplace/components/announcement.vue'; - import ChainItem from '@/views/dashboard/workplace/components/chain-item.vue'; - import useThemes from '@/hooks/themes'; - import { getDeviceInfo } from '@/api/dashboard'; - import { onMounted, ref } from 'vue'; + import { ref } from 'vue'; - const data = [{ - label: 'Name', - value: 'Socrates', + const props = defineProps( + { + deviceInfo: { + type: Object, + default: () => { + return {}; + }, + }, + alarmInfo: { + type: Object, + default: () => { + return {}; + }, + }, + productInfo: { + type: Object, + default: () => { + return {}; + }, + }, + } + ); + const productData = [{ + label: '启用', + value: props.productInfo.enabledCount, }, { - label: 'Mobile', - value: '123', - }, { - label: 'Residence', - value: 'Beijing' + label: '停用', + value: props.productInfo.disabledCount, }]; - const deviceInfo = ref({ - deviceCount: 0, - onlineCount: 0, - offlineCount: 0, - alarmCount: 0, - productCount: 0, - }) - const fetchData = async () => { - const res = await getDeviceInfo(); - deviceInfo.value = res.data; - } - const { isDark } = useThemes(); - onMounted(() => { - fetchData(); - }) + const deviceData = [ + { + label: '属性', + value: props.deviceInfo.propertyCount, + }, { + label: '服务', + value: props.deviceInfo.serveCount, + }, { + label: '事件', + value: props.deviceInfo.eventCount, + }]; + const alarmData = [{ + label: '今日新增', + value: props.alarmInfo.todayWarningCount, + }]; + console.log(props.deviceInfo, props.alarmInfo, props.productInfo); </script> <style lang="less" scoped> .arco-grid.panel { margin-bottom: 0; - padding: 10px 20px 0 0; } .panel-col { - padding-left: 20px; // 修改: 调整内边距以使卡片看起来更大 border-right: 1px solid rgb(var(--gray-2)); } .col-avatar { @@ -222,7 +190,6 @@ } .responsive-margin { margin-top: 20px; // 默认值 - } </style> diff --git a/src/views/dashboard/workplace/index.vue b/src/views/dashboard/workplace/index.vue index d916b37..4e45018 100644 --- a/src/views/dashboard/workplace/index.vue +++ b/src/views/dashboard/workplace/index.vue @@ -3,7 +3,8 @@ <div class="left-side"> <div class="panel"> <Banner /> - <DataPanel /> + <DataPanel v-if="computedDeviceInfo && alarmInfo && productInfo" :deviceInfo="computedDeviceInfo" :alarmInfo='alarmInfo' :productInfo='productInfo' /> + <ContentPublishingSource v-if="computedDeviceInfo && alarmInfo && productInfo" :deviceInfo="computedDeviceInfo" :alarmInfo='alarmInfo' :productInfo='productInfo' /> </div> <a-grid :cols="24" :col-gap="16" :row-gap="16" style="margin-top: 16px"> <a-grid-item @@ -16,32 +17,38 @@ </a-grid-item> </a-grid> </div> -<!-- <div class="right-side">--> -<!-- <a-grid :cols="24" :row-gap="16">--> -<!-- <a-grid-item :span="24">--> -<!-- <div class="panel moduler-wrap">--> -<!--<!– <QuickOperation />–>--> -<!--<!– <RecentlyVisited />–>--> -<!-- </div>--> -<!-- </a-grid-item>--> -<!-- <a-grid-item class="panel" :span="24">--> -<!-- <Announcement />--> -<!-- </a-grid-item>--> -<!-- <a-grid-item class="panel" :span="24">--> -<!-- <Announcement />--> -<!-- </a-grid-item>--> -<!-- <a-grid-item class="panel" :span="24"> </a-grid-item>--> -<!-- </a-grid>--> -<!-- </div>--> </div> </template> <script lang="ts" setup> + import { computed, onMounted, ref } from 'vue'; + import { getAlarmInfo, getDeviceInfo, getProductInfo } from '@/api/dashboard'; import Banner from './components/banner.vue'; import DataPanel from './components/data-panel.vue'; - import RecentlyVisited from './components/recently-visited.vue'; - import QuickOperation from './components/quick-operation.vue'; - import Announcement from './components/announcement.vue'; + import ContentPublishingSource from './components/content-publishing-source.vue'; + + const deviceInfo = ref<any>(); + const computedDeviceInfo = computed(() => { + return deviceInfo.value; // 返回 deviceInfo 的值 + }); + const alarmInfo = ref<any>(); + const productInfo = ref<any>(); + + const fetchData = async () => { + const res = await getDeviceInfo(); + deviceInfo.value = res.data; + const res1 = await getAlarmInfo(); + alarmInfo.value = res1.data; + const res2 = await getProductInfo(); + productInfo.value = res2.data; + console.log(computedDeviceInfo.value); + console.log(deviceInfo.value); + } + onMounted(() => { + fetchData(); + }) + + </script> <script lang="ts">