fix:【iot 物联网】linter 报错

This commit is contained in:
YunaiV
2025-10-10 20:26:17 +08:00
parent b6fee5c05b
commit f740461c2a
107 changed files with 7161 additions and 5905 deletions

View File

@@ -1,9 +1,40 @@
<script setup lang="ts">
import { computed } from 'vue';
import { CountTo } from '@vben/common-ui';
import { createIconifyIcon } from '@vben/icons';
import { Card } from 'ant-design-vue';
defineOptions({ name: 'ComparisonCard' });
const props = defineProps<{
icon: string;
iconColor?: string;
loading?: boolean;
title: string;
todayCount: number;
value: number;
}>();
const iconMap: Record<string, any> = {
menu: createIconifyIcon('ant-design:appstore-outlined'),
box: createIconifyIcon('ant-design:box-plot-outlined'),
cpu: createIconifyIcon('ant-design:cluster-outlined'),
message: createIconifyIcon('ant-design:message-outlined'),
};
const IconComponent = computed(() => iconMap[props.icon] || iconMap.menu);
</script>
<template>
<Card class="stat-card" :loading="loading">
<div class="flex flex-col h-full">
<div class="flex justify-between items-start mb-4">
<div class="flex flex-col flex-1">
<span class="text-gray-500 text-sm font-medium mb-2">{{ title }}</span>
<div class="flex h-full flex-col">
<div class="mb-4 flex items-start justify-between">
<div class="flex flex-1 flex-col">
<span class="mb-2 text-sm font-medium text-gray-500">{{
title
}}</span>
<span class="text-3xl font-bold text-gray-800">
<span v-if="value === -1">--</span>
<CountTo v-else :end-val="value" :duration="1000" />
@@ -13,45 +44,20 @@
<IconComponent />
</div>
</div>
<div class="mt-auto pt-3 border-t border-gray-100">
<div class="flex justify-between items-center text-sm">
<div class="mt-auto border-t border-gray-100 pt-3">
<div class="flex items-center justify-between text-sm">
<span class="text-gray-400">今日新增</span>
<span v-if="todayCount === -1" class="text-gray-400">--</span>
<span v-else class="text-green-500 font-medium">+{{ todayCount }}</span>
<span v-else class="font-medium text-green-500"
>+{{ todayCount }}</span
>
</div>
</div>
</div>
</Card>
</template>
<script setup lang="ts">
import { Card } from 'ant-design-vue';
import { CountTo } from '@vben/common-ui';
import { createIconifyIcon } from '@vben/icons';
import { computed } from 'vue';
defineOptions({ name: 'ComparisonCard' });
const props = defineProps<{
title: string;
value: number;
todayCount: number;
icon: string;
iconColor?: string;
loading?: boolean;
}>();
const iconMap: Record<string, any> = {
'menu': createIconifyIcon('ant-design:appstore-outlined'),
'box': createIconifyIcon('ant-design:box-plot-outlined'),
'cpu': createIconifyIcon('ant-design:cluster-outlined'),
'message': createIconifyIcon('ant-design:message-outlined'),
};
const IconComponent = computed(() => iconMap[props.icon] || iconMap.menu);
</script>
<style scoped>
.stat-card {
height: 160px;

View File

@@ -1,28 +1,17 @@
<template>
<Card title="设备数量统计" :loading="loading" class="chart-card">
<div v-if="loading && !hasData" class="h-[300px] flex justify-center items-center">
<Empty description="加载中..." />
</div>
<div v-else-if="!hasData" class="h-[300px] flex justify-center items-center">
<Empty description="暂无数据" />
</div>
<div v-else>
<EchartsUI ref="deviceCountChartRef" class="h-[400px] w-full" />
</div>
</Card>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue';
import { Card, Empty } from 'ant-design-vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import type { IotStatisticsApi } from '#/api/iot/statistics';
import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Card, Empty } from 'ant-design-vue';
defineOptions({ name: 'DeviceCountCard' });
const props = defineProps<{
statsData: IotStatisticsApi.StatisticsSummary;
loading?: boolean;
statsData: IotStatisticsApi.StatisticsSummary;
}>();
const deviceCountChartRef = ref();
@@ -31,18 +20,20 @@ const { renderEcharts } = useEcharts(deviceCountChartRef);
/** 是否有数据 */
const hasData = computed(() => {
if (!props.statsData) return false;
const categories = Object.entries(props.statsData.productCategoryDeviceCounts || {});
const categories = Object.entries(
props.statsData.productCategoryDeviceCounts || {},
);
return categories.length > 0 && props.statsData.deviceCount !== 0;
});
/** 初始化图表 */
const initChart = () => {
if (!hasData.value) return;
nextTick(() => {
const data = Object.entries(props.statsData.productCategoryDeviceCounts).map(
([name, value]) => ({ name, value })
);
const data = Object.entries(
props.statsData.productCategoryDeviceCounts,
).map(([name, value]) => ({ name, value }));
renderEcharts({
tooltip: {
@@ -98,7 +89,7 @@ const initChart = () => {
labelLine: {
show: false,
},
data: data,
data,
},
],
});
@@ -111,7 +102,7 @@ watch(
() => {
initChart();
},
{ deep: true }
{ deep: true },
);
/** 组件挂载时初始化图表 */
@@ -120,6 +111,26 @@ onMounted(() => {
});
</script>
<template>
<Card title="设备数量统计" :loading="loading" class="chart-card">
<div
v-if="loading && !hasData"
class="flex h-[300px] items-center justify-center"
>
<Empty description="加载中..." />
</div>
<div
v-else-if="!hasData"
class="flex h-[300px] items-center justify-center"
>
<Empty description="暂无数据" />
</div>
<div v-else>
<EchartsUI ref="deviceCountChartRef" class="h-[400px] w-full" />
</div>
</Card>
</template>
<style scoped>
.chart-card {
height: 100%;

View File

@@ -1,36 +1,17 @@
<template>
<Card title="设备状态统计" :loading="loading" class="chart-card">
<div v-if="loading && !hasData" class="h-[300px] flex justify-center items-center">
<Empty description="加载中..." />
</div>
<div v-else-if="!hasData" class="h-[300px] flex justify-center items-center">
<Empty description="暂无数据" />
</div>
<Row v-else class="h-[280px]">
<Col :span="8" class="flex items-center justify-center">
<EchartsUI ref="deviceOnlineChartRef" class="h-[250px] w-full" />
</Col>
<Col :span="8" class="flex items-center justify-center">
<EchartsUI ref="deviceOfflineChartRef" class="h-[250px] w-full" />
</Col>
<Col :span="8" class="flex items-center justify-center">
<EchartsUI ref="deviceInactiveChartRef" class="h-[250px] w-full" />
</Col>
</Row>
</Card>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue';
import { Card, Empty, Row, Col } from 'ant-design-vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import type { IotStatisticsApi } from '#/api/iot/statistics';
import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Card, Col, Empty, Row } from 'ant-design-vue';
defineOptions({ name: 'DeviceStateCountCard' });
const props = defineProps<{
statsData: IotStatisticsApi.StatisticsSummary;
loading?: boolean;
statsData: IotStatisticsApi.StatisticsSummary;
}>();
const deviceOnlineChartRef = ref();
@@ -39,7 +20,9 @@ const deviceInactiveChartRef = ref();
const { renderEcharts: renderOnlineChart } = useEcharts(deviceOnlineChartRef);
const { renderEcharts: renderOfflineChart } = useEcharts(deviceOfflineChartRef);
const { renderEcharts: renderInactiveChart } = useEcharts(deviceInactiveChartRef);
const { renderEcharts: renderInactiveChart } = useEcharts(
deviceInactiveChartRef,
);
/** 是否有数据 */
const hasData = computed(() => {
@@ -63,7 +46,7 @@ const getGaugeOption = (value: number, color: string, title: string): any => {
show: true,
width: 12,
itemStyle: {
color: color,
color,
},
},
axisLine: {
@@ -86,11 +69,11 @@ const getGaugeOption = (value: number, color: string, title: string): any => {
valueAnimation: true,
fontSize: 32,
fontWeight: 'bold',
color: color,
color,
offsetCenter: [0, '10%'],
formatter: (val: number) => `${val}`,
},
data: [{ value: value, name: title }],
data: [{ value, name: title }],
},
],
};
@@ -103,15 +86,19 @@ const initCharts = () => {
nextTick(() => {
// 在线设备
renderOnlineChart(
getGaugeOption(props.statsData.deviceOnlineCount, '#52c41a', '在线设备')
getGaugeOption(props.statsData.deviceOnlineCount, '#52c41a', '在线设备'),
);
// 离线设备
renderOfflineChart(
getGaugeOption(props.statsData.deviceOfflineCount, '#ff4d4f', '离线设备')
getGaugeOption(props.statsData.deviceOfflineCount, '#ff4d4f', '离线设备'),
);
// 待激活设备
renderInactiveChart(
getGaugeOption(props.statsData.deviceInactiveCount, '#1890ff', '待激活设备')
getGaugeOption(
props.statsData.deviceInactiveCount,
'#1890ff',
'待激活设备',
),
);
});
};
@@ -122,7 +109,7 @@ watch(
() => {
initCharts();
},
{ deep: true }
{ deep: true },
);
/** 组件挂载时初始化图表 */
@@ -131,6 +118,34 @@ onMounted(() => {
});
</script>
<template>
<Card title="设备状态统计" :loading="loading" class="chart-card">
<div
v-if="loading && !hasData"
class="flex h-[300px] items-center justify-center"
>
<Empty description="加载中..." />
</div>
<div
v-else-if="!hasData"
class="flex h-[300px] items-center justify-center"
>
<Empty description="暂无数据" />
</div>
<Row v-else class="h-[280px]">
<Col :span="8" class="flex items-center justify-center">
<EchartsUI ref="deviceOnlineChartRef" class="h-[250px] w-full" />
</Col>
<Col :span="8" class="flex items-center justify-center">
<EchartsUI ref="deviceOfflineChartRef" class="h-[250px] w-full" />
</Col>
<Col :span="8" class="flex items-center justify-center">
<EchartsUI ref="deviceInactiveChartRef" class="h-[250px] w-full" />
</Col>
</Row>
</Card>
</template>
<style scoped>
.chart-card {
height: 100%;

View File

@@ -1,70 +1,24 @@
<template>
<Card class="chart-card" :loading="loading">
<template #title>
<div class="flex items-center justify-between flex-wrap gap-2">
<span class="text-base font-medium">上下行消息量统计</span>
<Space :size="8">
<Button
:type="activeTimeRange === '1h' ? 'primary' : 'default'"
size="small"
@click="setTimeRange('1h')"
>
最近1小时
</Button>
<Button
:type="activeTimeRange === '24h' ? 'primary' : 'default'"
size="small"
@click="setTimeRange('24h')"
>
最近24小时
</Button>
<Button
:type="activeTimeRange === '7d' ? 'primary' : 'default'"
size="small"
@click="setTimeRange('7d')"
>
近一周
</Button>
<RangePicker
v-model:value="dateRange"
format="YYYY-MM-DD"
:placeholder="['开始时间', '结束时间']"
@change="handleDateChange"
size="small"
style="width: 240px"
/>
</Space>
</div>
</template>
<div v-if="loading" class="h-[350px] flex justify-center items-center">
<Empty description="加载中..." />
</div>
<div v-else-if="!hasData" class="h-[350px] flex justify-center items-center">
<Empty description="暂无数据" />
</div>
<div v-else>
<EchartsUI ref="messageChartRef" class="h-[350px] w-full" />
</div>
</Card>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, nextTick } from 'vue';
import { Card, Empty, Space, DatePicker, Button } from 'ant-design-vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';
import {
StatisticsApi,
type IotStatisticsDeviceMessageSummaryByDateRespVO,
type IotStatisticsDeviceMessageReqVO,
import type {
IotStatisticsDeviceMessageReqVO,
IotStatisticsDeviceMessageSummaryByDateRespVO,
} from '#/api/iot/statistics';
const { RangePicker } = DatePicker;
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Button, Card, DatePicker, Empty, Space } from 'ant-design-vue';
import dayjs from 'dayjs';
import { StatisticsApi } from '#/api/iot/statistics';
defineOptions({ name: 'MessageTrendCard' });
const { RangePicker } = DatePicker;
const messageChartRef = ref();
const { renderEcharts } = useEcharts(messageChartRef);
@@ -87,33 +41,37 @@ const hasData = computed(() => {
const setTimeRange = (range: string) => {
activeTimeRange.value = range;
dateRange.value = undefined; // 清空自定义时间选择
let start: Dayjs;
let end = dayjs();
const end = dayjs();
switch (range) {
case '1h':
case '1h': {
start = dayjs().subtract(1, 'hour');
queryParams.interval = 1; // 按分钟
break;
case '24h':
start = dayjs().subtract(24, 'hour');
queryParams.interval = 1; // 按小时
break;
case '7d':
}
case '7d': {
start = dayjs().subtract(7, 'day');
queryParams.interval = 1; // 按天
break;
default:
}
case '24h': {
start = dayjs().subtract(24, 'hour');
queryParams.interval = 1; // 按小时
break;
}
default: {
start = dayjs().subtract(7, 'day');
queryParams.interval = 1;
}
}
queryParams.times = [
start.format('YYYY-MM-DD HH:mm:ss'),
end.format('YYYY-MM-DD HH:mm:ss'),
];
fetchMessageData();
};
@@ -133,10 +91,11 @@ const handleDateChange = () => {
// 获取消息统计数据
const fetchMessageData = async () => {
if (!queryParams.times || queryParams.times.length !== 2) return;
loading.value = true;
try {
messageData.value = await StatisticsApi.getDeviceMessageSummaryByDate(queryParams);
messageData.value =
await StatisticsApi.getDeviceMessageSummaryByDate(queryParams);
await nextTick();
initChart();
} catch (error) {
@@ -230,6 +189,60 @@ onMounted(() => {
});
</script>
<template>
<Card class="chart-card" :loading="loading">
<template #title>
<div class="flex flex-wrap items-center justify-between gap-2">
<span class="text-base font-medium">上下行消息量统计</span>
<Space :size="8">
<Button
:type="activeTimeRange === '1h' ? 'primary' : 'default'"
size="small"
@click="setTimeRange('1h')"
>
最近1小时
</Button>
<Button
:type="activeTimeRange === '24h' ? 'primary' : 'default'"
size="small"
@click="setTimeRange('24h')"
>
最近24小时
</Button>
<Button
:type="activeTimeRange === '7d' ? 'primary' : 'default'"
size="small"
@click="setTimeRange('7d')"
>
近一周
</Button>
<RangePicker
v-model:value="dateRange"
format="YYYY-MM-DD"
:placeholder="['开始时间', '结束时间']"
@change="handleDateChange"
size="small"
style="width: 240px"
/>
</Space>
</div>
</template>
<div v-if="loading" class="flex h-[350px] items-center justify-center">
<Empty description="加载中..." />
</div>
<div
v-else-if="!hasData"
class="flex h-[350px] items-center justify-center"
>
<Empty description="暂无数据" />
</div>
<div v-else>
<EchartsUI ref="messageChartRef" class="h-[350px] w-full" />
</div>
</Card>
</template>
<style scoped>
.chart-card {
height: 100%;