review:【antd】【iot】首页的迁移

This commit is contained in:
YunaiV
2025-11-23 18:51:16 +08:00
parent a32ff4a9c9
commit 42697ec614
9 changed files with 49 additions and 77 deletions

View File

@@ -1,6 +1,4 @@
/** /** 消息趋势图表配置 */
* 消息趋势图表配置
*/
export function getMessageTrendChartOptions( export function getMessageTrendChartOptions(
times: string[], times: string[],
upstreamData: number[], upstreamData: number[],

View File

@@ -1,16 +1,7 @@
/**
* IoT 首页数据配置文件
*
* 该文件只包含统计数据接口定义
*/
import type { IotStatisticsApi } from '#/api/iot/statistics'; import type { IotStatisticsApi } from '#/api/iot/statistics';
/** 统计数据接口 - 使用 API 定义的类型 */
export type StatsData = IotStatisticsApi.StatisticsSummary;
/** 默认统计数据 */ /** 默认统计数据 */
export const defaultStatsData: StatsData = { export const defaultStatsData: IotStatisticsApi.StatisticsSummary = {
productCategoryCount: 0, productCategoryCount: 0,
productCount: 0, productCount: 0,
deviceCount: 0, deviceCount: 0,

View File

@@ -16,20 +16,18 @@ defineOptions({ name: 'IoTHome' });
const loading = ref(true); const loading = ref(true);
const statsData = ref<StatsData>(defaultStatsData); const statsData = ref<StatsData>(defaultStatsData);
/** /** 加载统计数据 */
* 加载统计数据
* @returns Promise<StatsData>
*/
async function loadStatisticsData(): Promise<StatsData> { async function loadStatisticsData(): Promise<StatsData> {
try { try {
const data = await getStatisticsSummary(); return await getStatisticsSummary();
return data;
} catch (error) { } catch (error) {
// TODO @haohao后续记得删除下哈。catch 部分可以删除
// 开发环境:记录错误信息,便于调试 // 开发环境:记录错误信息,便于调试
console.error('获取统计数据出错:', error); console.error('获取统计数据出错:', error);
// 开发环境:提示使用 Mock 数据,提醒检查后端接口 // 开发环境:提示使用 Mock 数据,提醒检查后端接口
console.warn('使用 Mock 数据,请检查后端接口是否已实现'); console.warn('使用 Mock 数据,请检查后端接口是否已实现');
// TODO @haohao后续记得删除下哈。
// 开发调试:返回 Mock 数据,确保前端功能正常开发 // 开发调试:返回 Mock 数据,确保前端功能正常开发
// 生产环境:建议移除 Mock 数据,直接抛出错误或返回空数据 // 生产环境:建议移除 Mock 数据,直接抛出错误或返回空数据
return { return {
@@ -54,15 +52,13 @@ async function loadStatisticsData(): Promise<StatsData> {
} }
} }
/** /** 加载数据 */
* 加载数据
*/
async function loadData() { async function loadData() {
loading.value = true; loading.value = true;
try { try {
statsData.value = await loadStatisticsData(); statsData.value = await loadStatisticsData();
} catch (error) { } catch (error) {
// 开发环境:记录错误信息,便于调试 // TODO @haohao后续记得删除下哈。catch 部分可以删除
console.error('获取统计数据出错:', error); console.error('获取统计数据出错:', error);
} finally { } finally {
loading.value = false; loading.value = false;

View File

@@ -35,11 +35,10 @@ async function initChart() {
} }
await nextTick(); await nextTick();
const data = Object.entries( const data = Object.entries(props.statsData.productCategoryDeviceCounts).map(
props.statsData.productCategoryDeviceCounts, ([name, value]) => ({ name, value }),
).map(([name, value]) => ({ name, value })); );
await renderEcharts(getDeviceCountPieChartOptions(data));
renderEcharts(getDeviceCountPieChartOptions(data));
} }
/** 监听数据变化 */ /** 监听数据变化 */

View File

@@ -41,7 +41,7 @@ async function initCharts() {
await nextTick(); await nextTick();
const max = props.statsData.deviceCount || 100; const max = props.statsData.deviceCount || 100;
// 在线设备 // 在线设备
renderOnlineChart( await renderOnlineChart(
getDeviceStateGaugeChartOptions( getDeviceStateGaugeChartOptions(
props.statsData.deviceOnlineCount, props.statsData.deviceOnlineCount,
max, max,
@@ -50,7 +50,7 @@ async function initCharts() {
), ),
); );
// 离线设备 // 离线设备
renderOfflineChart( await renderOfflineChart(
getDeviceStateGaugeChartOptions( getDeviceStateGaugeChartOptions(
props.statsData.deviceOfflineCount, props.statsData.deviceOfflineCount,
max, max,
@@ -59,7 +59,7 @@ async function initCharts() {
), ),
); );
// 待激活设备 // 待激活设备
renderInactiveChart( await renderInactiveChart(
getDeviceStateGaugeChartOptions( getDeviceStateGaugeChartOptions(
props.statsData.deviceInactiveCount, props.statsData.deviceInactiveCount,
max, max,

View File

@@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Dayjs } from 'dayjs'; import type { Dayjs } from 'dayjs';
import type { IotStatisticsApi } from '#/api/iot/statistics'; import type { IotStatisticsApi } from '#/api/iot/statistics';
import { computed, nextTick, onMounted, reactive, ref } from 'vue'; import { computed, nextTick, onMounted, reactive, ref } from 'vue';
@@ -11,8 +12,8 @@ import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Card, Empty, Select } from 'ant-design-vue'; import { Card, Empty, Select } from 'ant-design-vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import ShortcutDateRangePicker from '#/components/shortcut-date-range-picker/shortcut-date-range-picker.vue';
import { getDeviceMessageSummaryByDate } from '#/api/iot/statistics'; import { getDeviceMessageSummaryByDate } from '#/api/iot/statistics';
import ShortcutDateRangePicker from '#/components/shortcut-date-range-picker/shortcut-date-range-picker.vue';
import { getMessageTrendChartOptions } from '../chart-options'; import { getMessageTrendChartOptions } from '../chart-options';
@@ -31,16 +32,9 @@ const dateRange = ref<[string, string]>([
dayjs().format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD'),
]); ]);
/** /** 将日期范围转换为带时分秒的格式 */
* 将日期范围转换为带时分秒的格式
* @param dates 日期范围 [开始日期, 结束日期],格式为 YYYY-MM-DD
* @returns 带时分秒的日期范围 [开始日期 00:00:00, 结束日期 23:59:59]
*/
function formatDateRangeWithTime(dates: [string, string]): [string, string] { function formatDateRangeWithTime(dates: [string, string]): [string, string] {
return [ return [`${dates[0]} 00:00:00`, `${dates[1]} 23:59:59`];
`${dates[0]} 00:00:00`,
`${dates[1]} 23:59:59`,
];
} }
/** 查询参数 */ /** 查询参数 */
@@ -69,7 +63,9 @@ function handleQuery() {
/** 处理时间范围变化 */ /** 处理时间范围变化 */
function handleDateRangeChange(times?: [Dayjs, Dayjs]) { function handleDateRangeChange(times?: [Dayjs, Dayjs]) {
if (!times || times.length !== 2) return; if (!times || times.length !== 2) {
return;
}
dateRange.value = [ dateRange.value = [
dayjs(times[0]).format('YYYY-MM-DD'), dayjs(times[0]).format('YYYY-MM-DD'),
dayjs(times[1]).format('YYYY-MM-DD'), dayjs(times[1]).format('YYYY-MM-DD'),
@@ -86,12 +82,15 @@ function handleIntervalChange() {
/** 获取消息统计数据 */ /** 获取消息统计数据 */
async function fetchMessageData() { async function fetchMessageData() {
if (!queryParams.times || queryParams.times.length !== 2) return; if (!queryParams.times || queryParams.times.length !== 2) {
return;
}
loading.value = true; loading.value = true;
try { try {
messageData.value = await getDeviceMessageSummaryByDate(queryParams); messageData.value = await getDeviceMessageSummaryByDate(queryParams);
} catch (error) { } catch (error) {
// TODO @haohaocatch 可以删除哈;
// 开发环境:记录错误信息,便于调试 // 开发环境:记录错误信息,便于调试
console.error('获取消息统计数据失败:', error); console.error('获取消息统计数据失败:', error);
// 错误时清空数据,避免显示错误的数据 // 错误时清空数据,避免显示错误的数据
@@ -105,12 +104,13 @@ async function fetchMessageData() {
/** 初始化图表 */ /** 初始化图表 */
function initChart() { function initChart() {
// 检查数据是否存在 // 检查数据是否存在
if (!hasData.value) return; if (!hasData.value) {
return;
}
const times = messageData.value.map((item) => item.time); const times = messageData.value.map((item) => item.time);
const upstreamData = messageData.value.map((item) => item.upstreamCount); const upstreamData = messageData.value.map((item) => item.upstreamCount);
const downstreamData = messageData.value.map((item) => item.downstreamCount); const downstreamData = messageData.value.map((item) => item.downstreamCount);
renderEcharts( renderEcharts(
getMessageTrendChartOptions(times, upstreamData, downstreamData), getMessageTrendChartOptions(times, upstreamData, downstreamData),
); );
@@ -118,7 +118,9 @@ function initChart() {
/** 确保图表容器已经可见后再渲染 */ /** 确保图表容器已经可见后再渲染 */
async function renderChartWhenReady() { async function renderChartWhenReady() {
if (!hasData.value) return; if (!hasData.value) {
return;
}
// 等待 Card loading 状态、v-show 等 DOM 更新完成 // 等待 Card loading 状态、v-show 等 DOM 更新完成
await nextTick(); await nextTick();
await nextTick(); await nextTick();
@@ -138,7 +140,9 @@ onMounted(() => {
<span class="text-base font-medium text-gray-600">消息量统计</span> <span class="text-base font-medium text-gray-600">消息量统计</span>
<div class="flex flex-wrap items-center gap-4"> <div class="flex flex-wrap items-center gap-4">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<span class="text-sm text-gray-500 whitespace-nowrap">时间范围</span> <span class="whitespace-nowrap text-sm text-gray-500"
>时间范围</span
>
<ShortcutDateRangePicker @change="handleDateRangeChange" /> <ShortcutDateRangePicker @change="handleDateRangeChange" />
</div> </div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@@ -175,7 +179,3 @@ onMounted(() => {
</div> </div>
</Card> </Card>
</template> </template>
<style scoped>
</style>

View File

@@ -16,6 +16,7 @@ defineOptions({ name: 'ComparisonCard' });
const props = defineProps<ComparisonCardProps>(); const props = defineProps<ComparisonCardProps>();
// TODO @haohao看看能不能用中立的 icon类似 ADD、EDIT 那种。目的:方便后续迁移到 ele 版本里。
const iconMap: Record<string, string> = { const iconMap: Record<string, string> = {
menu: 'ant-design:appstore-outlined', menu: 'ant-design:appstore-outlined',
box: 'ant-design:box-plot-outlined', box: 'ant-design:box-plot-outlined',
@@ -39,11 +40,7 @@ const iconName = computed(() => iconMap[props.icon] || iconMap.menu);
</span> </span>
<span class="text-3xl font-bold text-gray-800"> <span class="text-3xl font-bold text-gray-800">
<span v-if="value === -1">--</span> <span v-if="value === -1">--</span>
<VbenCountToAnimator <VbenCountToAnimator v-else :end-val="value" :duration="1000" />
v-else
:end-val="value"
:duration="1000"
/>
</span> </span>
</div> </div>
<div :class="`text-4xl ${iconColor || ''}`"> <div :class="`text-4xl ${iconColor || ''}`">
@@ -63,4 +60,3 @@ const iconName = computed(() => iconMap[props.icon] || iconMap.menu);
</CardContent> </CardContent>
</Card> </Card>
</template> </template>

View File

@@ -1,4 +1,3 @@
// add by 芋艿:对比卡片,目前 iot 模块在使用 // add by 芋艿:对比卡片,目前 iot 模块在使用
export { default as ComparisonCard } from './comparison-card.vue'; export { default as ComparisonCard } from './comparison-card.vue';
export * from './types'; export * from './types';

View File

@@ -1,15 +1,8 @@
export interface ComparisonCardProps { export interface ComparisonCardProps {
/** 图标名称 */ icon: string; // 图标名称
icon: string; iconColor?: string; // 图标颜色类名
/** 图标颜色类名 */ loading?: boolean; // 加载状态
iconColor?: string; title: string; // 标题
/** 加载状态 */ todayCount: number; // 今日新增数量
loading?: boolean; value: number; // 数值
/** 标题 */
title: string;
/** 今日新增数量 */
todayCount: number;
/** 数值 */
value: number;
} }