GrowCard.vue 10.1 KB
<template>
  <div>
    <!-- 首页基础信息 -->
    <section class="flex gap-4">
      <StatisticalCard
        :style="{ width: `${100 / statisticalPanelList.length}%` }"
        v-for="(item, index) in statisticalPanelList"
        :key="index"
        :value="item"
      />
    </section>
    <!-- 首页饼图 -->
    <div class="md:flex mt-4" v-if="!isAdmin(role)">
      <Card
        size="small"
        class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4"
        style="color: #666; width: 50%"
        title="设备数量统计"
      >
        <a-row type="flex" justify="space-between" align="middle">
          <a-col :span="12">
            <PieChartDeviceSub
              v-if="seriesData.length > 0"
              :legendData="legendData"
              :seriesData="seriesData"
              :isCircle="false"
          /></a-col>
          <a-col :span="12">
            <a-row type="flex" justify="space-between" align="middle" style="row-gap: 30px">
              <a-col :offset="8" class="flex items-center">
                <span class="left-icon-d-color"></span>
                直连设备:
                <span class="bold-text">{{ growCardList?.deviceInfo?.directConnection ?? 0 }}</span
                >个</a-col
              >
              <a-col :offset="8" class="flex items-center">
                <span class="left-icon-g-color"></span>
                网关设备:
                <span class="bold-text">{{ growCardList?.deviceInfo?.gateWay ?? 0 }}</span
                >个</a-col
              >
              <a-col :offset="8" class="flex items-center">
                <span class="left-icon-s-color"></span>
                网关子设备:<span class="bold-text">{{
                  growCardList?.deviceInfo?.sensor ?? 0
                }}</span
                >个</a-col
              >
            </a-row>
          </a-col>
        </a-row>
      </Card>
      <Card
        size="small"
        class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:ml-1"
        style="color: #666; width: 50%"
        title="设备状态统计"
      >
        <a-row type="flex" justify="space-between" align="middle">
          <a-col :span="12">
            <PieChartDeviceStatus
              v-if="seriesStatusData.length > 0"
              :seriesStatusData="seriesStatusData"
            />
            <div class="empty-box" v-else><Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" /></div>
          </a-col>
          <a-col :span="12">
            <a-row type="flex" justify="space-between" align="middle" style="row-gap: 30px">
              <a-col :offset="8" class="flex items-center">
                <span class="right-icon-d-color"></span>
                待激活设备:
                <span class="bold-text">{{ growCardList?.deviceInfo?.inActive ?? 0 }}</span
                >个</a-col
              >
              <a-col :offset="8" class="flex items-center">
                <span class="right-icon-g-color"></span>
                在线设备:<span class="bold-text">{{ growCardList?.deviceInfo?.onLine ?? 0 }}</span
                >个</a-col
              >
              <a-col :offset="8" class="flex items-center">
                <span class="right-icon-s-color"></span>
                离线设备:<span class="bold-text">{{ growCardList?.deviceInfo?.offLine ?? 0 }}</span
                >个</a-col
              >
            </a-row>
          </a-col>
        </a-row>
      </Card>
    </div>
  </div>
</template>
<script lang="ts" setup>
  import { ref, onMounted, defineComponent, Ref } from 'vue';
  import { Card } from 'ant-design-vue';
  import { getHomeData } from '/@/api/dashboard';
  import { isAdmin } from '/@/enums/roleEnum';
  import { toThousands } from '/@/utils/fnUtils';
  import { CardList, seriesDataT } from './props';
  import PieChartDeviceSub from './PieChartDeviceSub.vue';
  import PieChartDeviceStatus from './PieChartDeviceStatus.vue';
  import { Empty } from 'ant-design-vue';
  import StatisticalCard from './StatisticalCard.vue';
  import { HomeStatisticsRecordType } from '/@/api/dashboard/model';
  import { useRole } from '/@/hooks/business/useRole';
  import { unref } from 'vue';
  import productPicture from '/@/assets/images/product.png';
  import devicePicture from '/@/assets/images/device-count.png';
  import alarmPicture from '/@/assets/images/alarm-count.png';
  import msgPicture from '/@/assets/images/msg-count.png';
  import tenantPicture from '/@/assets/images/zh.png';
  import customerPicture from '/@/assets/images/kf.png';

  interface RecordType {
    value: number;
    label: string;
  }

  interface StatisticalItemType {
    images: string;
    totals: RecordType[];
    tooltips: RecordType[];
    todayTotals: RecordType[];
    withUnit?: boolean;
  }

  defineProps<{
    role: string;
  }>();

  defineExpose({
    isAdmin,
    toThousands,
  });

  defineComponent({
    Card,
  });

  const legendData = ref(['网关设备', '直连设备', '网关子设备']);

  const seriesData: Ref<seriesDataT[]> = ref([]);

  const seriesStatusData: Ref<seriesDataT[]> = ref([]);

  const growCardList = ref<CardList>();

  const statisticalPanelList = ref<StatisticalItemType[]>([]);

  const devicePieColor = [
    { key: 'directConnection', itemStyle: { color: '#5C7BD9' }, value: '直连设备' },
    { key: 'gateWay', itemStyle: { color: '#91CC75' }, value: '网关设备' },
    { key: 'sensor', itemStyle: { color: '#FAC859' }, value: '网关子设备' },
    { key: 'inActive', itemStyle: { color: '#5C7BD9' }, value: '待激活' },
    { key: 'onLine', itemStyle: { color: '#91CC75 ' }, value: '在线' },
    { key: 'offLine', itemStyle: { color: '#EC4040' }, value: '离线' },
  ];

  const { isSysadmin, isPlatformAdmin } = useRole();
  const handleTransformStatisticalInfo = (record: HomeStatisticsRecordType) => {
    const { deviceInfo, productInfo, alarmInfo, messageInfo, customerInfo, tenantInfo } = record;

    const productTotal: StatisticalItemType = {
      images: productPicture,
      totals: [{ label: '产品数', value: productInfo?.sumCount }],
      tooltips: [
        { label: '产品数', value: productInfo?.sumCount },
        { label: '今日新增', value: productInfo?.todayAdd },
      ],
      todayTotals: [{ label: '今日新增', value: productInfo?.todayAdd }],
    };

    const deviceTotal: StatisticalItemType = {
      images: devicePicture,
      totals: [{ label: '设备数', value: deviceInfo?.sumCount }],
      tooltips: [
        { label: '设备数', value: deviceInfo?.sumCount },
        { label: '今日新增', value: deviceInfo?.todayAdd },
      ],
      todayTotals: [{ label: '今日新增', value: deviceInfo?.todayAdd }],
    };

    const alarmTotal: StatisticalItemType = {
      images: alarmPicture,
      totals: [{ label: '告警数', value: alarmInfo?.sumCount }],
      tooltips: [
        { label: '告警数', value: alarmInfo?.sumCount },
        { label: '今日新增', value: alarmInfo?.todayAdd },
      ],
      todayTotals: [{ label: '今日新增', value: alarmInfo?.todayAdd }],
    };

    const messageTotal: StatisticalItemType = {
      images: msgPicture,
      withUnit: true,
      totals: [
        { label: '消息数', value: messageInfo?.messageCount },
        { label: '消息点数', value: messageInfo?.dataPointsCount },
      ],
      tooltips: [
        { label: '今日消息数', value: messageInfo?.todayMessageAdd },
        { label: '今日消息点数', value: messageInfo?.todayDataPointsAdd },
      ],
      todayTotals: [
        { label: '今日消息数', value: messageInfo?.todayMessageAdd },
        { label: '今日消息点数', value: messageInfo?.todayDataPointsAdd },
      ],
    };

    const tenantTotal: StatisticalItemType = {
      images: tenantPicture,
      totals: [{ label: '租户总量', value: tenantInfo?.sumCount }],
      tooltips: [
        { label: '租户总量', value: tenantInfo?.sumCount },
        { label: '今日新增', value: tenantInfo?.todayAdd },
      ],
      todayTotals: [{ label: '今日新增', value: tenantInfo?.todayAdd }],
    };

    const customerTotal: StatisticalItemType = {
      images: customerPicture,
      totals: [{ label: '客户总量', value: customerInfo?.sumCount }],
      tooltips: [
        { label: '客户总量', value: customerInfo?.sumCount },
        { label: '今日新增', value: customerInfo?.todayAdd },
      ],
      todayTotals: [{ label: '今日新增', value: customerInfo?.todayAdd }],
    };

    if (unref(isSysadmin) || unref(isPlatformAdmin)) {
      statisticalPanelList.value = [deviceTotal, tenantTotal, customerTotal];
    } else {
      statisticalPanelList.value = [productTotal, deviceTotal, alarmTotal, messageTotal];
    }
  };

  onMounted(async () => {
    const res = await getHomeData();
    growCardList.value = res;
    handleTransformStatisticalInfo(res);
    const { deviceInfo } = growCardList.value!;
    let data = Object.entries(deviceInfo).map(([key, value]) => {
      const name = devicePieColor?.find((f) => f.key === key)?.value;
      const itemStyle = devicePieColor?.find((f) => f.key === key)?.itemStyle;
      return { key, value, itemStyle, name };
    });
    seriesData.value = data.filter(
      (f) => f.key === 'directConnection' || f.key === 'gateWay' || f.key === 'sensor'
    );
    seriesStatusData.value = data.filter(
      (f) => f.key === 'inActive' || f.key === 'onLine' || f.key === 'offLine'
    );
  });
</script>
<style lang="less">
  .text {
    color: #333;
    display: flex;
    flex-wrap: nowrap;
  }

  .bold-text {
    font-weight: bold;
  }

  .base-left-icon-color {
    border-radius: 50%;
    width: 0.75rem;
    height: 0.75rem;
    display: block;
    position: relative;
    right: 0.5rem;
  }

  .left-icon-d-color :extend(.base-left-icon-color) {
    background-color: #5c7bd9 !important;
  }
  .left-icon-g-color :extend(.base-left-icon-color) {
    background-color: #91cc75 !important;
  }
  .left-icon-s-color :extend(.base-left-icon-color) {
    background-color: #fac859 !important;
  }
  .right-icon-d-color :extend(.base-left-icon-color) {
    background-color: #5c7bd9;
  }
  .right-icon-g-color :extend(.base-left-icon-color) {
    background-color: #91cc75;
  }
  .right-icon-s-color :extend(.base-left-icon-color) {
    background-color: #ec4040;
  }
</style>