运行分析响应速度优化

parent addb30b5
...@@ -50,7 +50,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -50,7 +50,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
} }
let regionInfo: any = await selectDataListByParam(TABLENAME.区域表, regionParam, ["id"]); let regionInfo: any = await selectDataListByParam(TABLENAME.区域表, regionParam, ["id"]);
let regionKeys = regionInfo.data.map((r: any) => r.id); let regionKeys = regionInfo.data.map((r: any) => r.id);
console.log("筛选区域Key:", regionKeys.length);
// 1.1 获取所选区域三相电表及电能监测设备的用电数据(用于能耗管理) // 1.1 获取所选区域三相电表及电能监测设备的用电数据(用于能耗管理)
let powerParams: any = {device_type: { "%in%": ["三相电表", "电能监测"] }}; let powerParams: any = {device_type: { "%in%": ["三相电表", "电能监测"] }};
...@@ -60,7 +59,8 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -60,7 +59,8 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
let energyDevices = await selectDataListByParam(TABLENAME.设备表, powerParams, ["device_id"]); let energyDevices = await selectDataListByParam(TABLENAME.设备表, powerParams, ["device_id"]);
let energyDeviceIds = energyDevices.data.map((d: any) => d.device_id); let energyDeviceIds = energyDevices.data.map((d: any) => d.device_id);
// 1.2 获取今日、昨日、本月、上月用电量 // === 前提:公共时间变量,后续并行模块都会用到 ===
let nowTime = new Date();
let todayStart = new Date(); todayStart.setHours(0, 0, 0, 0); let todayStart = new Date(); todayStart.setHours(0, 0, 0, 0);
let todayEnd = new Date(); let todayEnd = new Date();
let yesterdayStart = new Date(Date.now() - 86400000); yesterdayStart.setHours(0,0,0,0); let yesterdayStart = new Date(Date.now() - 86400000); yesterdayStart.setHours(0,0,0,0);
...@@ -68,58 +68,98 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -68,58 +68,98 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
let currentMonthStart = new Date(); currentMonthStart.setDate(1); currentMonthStart.setHours(0,0,0,0); let currentMonthStart = new Date(); currentMonthStart.setDate(1); currentMonthStart.setHours(0,0,0,0);
let lastMonthStart = new Date(); lastMonthStart.setMonth(lastMonthStart.getMonth() - 1); lastMonthStart.setDate(1); lastMonthStart.setHours(0,0,0,0); let lastMonthStart = new Date(); lastMonthStart.setMonth(lastMonthStart.getMonth() - 1); lastMonthStart.setDate(1); lastMonthStart.setHours(0,0,0,0);
let lastMonthEnd = new Date(currentMonthStart.getTime() - 1); let lastMonthEnd = new Date(currentMonthStart.getTime() - 1);
let last24hStart = new Date(nowTime.getTime() - 24 * 3600000);
let last7DaysStart = new Date(nowTime.getTime() - 7 * 86400000);
let last30DaysStart = new Date(nowTime.getTime() - 30 * 86400000);
let lastYearStart = new Date(nowTime.getFullYear() - 1, nowTime.getMonth(), 1);
// 辅助函数:查询某个时间段内的总用电量(单位 kwh) // === 并行执行:能耗、环境、预警、客流 四个独立模块 ===
async function getTotalEnergy(deviceIds: string[], startTime: Date, endTime: Date): Promise<number> { const parallelResults = await Promise.all([
if (deviceIds.length === 0) return 0; // 模块1:能耗管理
let records = await selectDataListByParam(TABLENAME.设备数据表, { (async () => {
device_id: { "%in%": deviceIds }, // 一次查询覆盖所有时间范围
device_time: { "%gte%": formatLocalTime(startTime), "%lte%": formatLocalTime(endTime) }, let allEnergyRecords = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": energyDeviceIds },
device_time: { "%gte%": formatLocalTime(lastYearStart), "%lte%": formatLocalTime(nowTime) },
"%orderAsc%": "device_time" "%orderAsc%": "device_time"
}, ["device_id", "data", "device_time"]); }, ["device_id", "data", "device_time"]);
let total = 0; // 一次遍历,同时产出:4个时段总量 + 4组趋势数据
let deviceEnergyMap = new Map(); let todayTotal = 0, yesterdayTotal = 0, currentMonthTotal = 0, previousMonthTotal = 0;
for (let rec of records.data) { let deviceTodayMap = new Map<string, number>();
let data = rec.data; let deviceYesterdayMap = new Map<string, number>();
// let energy = data.energy ?? data.total_energy; let deviceMonthMap = new Map<string, number>();
let energy = data.current; let devicePrevMonthMap = new Map<string, number>();
let hourlyMap = new Map<string, number>();
let daily7Map = new Map<string, number>();
let daily30Map = new Map<string, number>();
let monthlyMap = new Map<string, number>();
const padFn = (n: number) => String(n).padStart(2, '0');
for (let rec of allEnergyRecords.data) {
let energy = rec.data?.current;
if (energy === undefined) continue; if (energy === undefined) continue;
if (!deviceEnergyMap.has(rec.device_id)) { let d = new Date(rec.device_time);
// deviceEnergyMap.set(rec.device_id, { min: energy, max: energy }); let ts = d.getTime();
deviceEnergyMap.set(rec.device_id, energy); let deviceId = rec.device_id;
} else {
let cur = deviceEnergyMap.get(rec.device_id); // --- 总量分组 ---
// if (energy < cur.min) cur.min = energy; if (ts >= todayStart.getTime()) {
// if (energy > cur.max) cur.max = energy; deviceTodayMap.set(deviceId, (deviceTodayMap.get(deviceId) || 0) + energy);
energy += cur;
deviceEnergyMap.set(rec.device_id, energy);
} }
if (ts >= yesterdayStart.getTime() && ts <= yesterdayEnd.getTime()) {
deviceYesterdayMap.set(deviceId, (deviceYesterdayMap.get(deviceId) || 0) + energy);
} }
for (let energy of deviceEnergyMap.values()) { if (ts >= currentMonthStart.getTime()) {
total += energy; deviceMonthMap.set(deviceId, (deviceMonthMap.get(deviceId) || 0) + energy);
} }
return total; if (ts >= lastMonthStart.getTime() && ts <= lastMonthEnd.getTime()) {
devicePrevMonthMap.set(deviceId, (devicePrevMonthMap.get(deviceId) || 0) + energy);
} }
let todayEnergy = await getTotalEnergy(energyDeviceIds, todayStart, todayEnd); // --- 趋势分组 ---
let yesterdayEnergy = await getTotalEnergy(energyDeviceIds, yesterdayStart, yesterdayEnd); if (ts >= last24hStart.getTime()) {
let currentMonthEnergy = await getTotalEnergy(energyDeviceIds, currentMonthStart, new Date()); let key = `${d.getFullYear()}-${padFn(d.getMonth()+1)}-${padFn(d.getDate())} ${padFn(d.getHours())}时`;
let previousMonthEnergy = await getTotalEnergy(energyDeviceIds, lastMonthStart, lastMonthEnd); hourlyMap.set(key, (hourlyMap.get(key) || 0) + energy);
}
if (ts >= last7DaysStart.getTime()) {
let key = `${d.getFullYear()}/${padFn(d.getMonth()+1)}/${padFn(d.getDate())}`;
daily7Map.set(key, (daily7Map.get(key) || 0) + energy);
}
if (ts >= last30DaysStart.getTime()) {
let key = `${d.getFullYear()}/${padFn(d.getMonth()+1)}/${padFn(d.getDate())}`;
daily30Map.set(key, (daily30Map.get(key) || 0) + energy);
}
let monthKey = `${d.getFullYear()}-${padFn(d.getMonth()+1)}`;
monthlyMap.set(monthKey, (monthlyMap.get(monthKey) || 0) + energy);
}
let dailyYearOnYear = yesterdayEnergy === 0 ? 0 : (((todayEnergy - yesterdayEnergy) / yesterdayEnergy) * 100).toFixed(2); // 汇总各时段总量
let monthlyYearOnYear = previousMonthEnergy === 0 ? 0 : (((currentMonthEnergy - previousMonthEnergy) / previousMonthEnergy) * 100).toFixed(2); for (let v of deviceTodayMap.values()) todayTotal += v;
for (let v of deviceYesterdayMap.values()) yesterdayTotal += v;
for (let v of deviceMonthMap.values()) currentMonthTotal += v;
for (let v of devicePrevMonthMap.values()) previousMonthTotal += v;
// 1.3 用电趋势:过去24小时(按小时)、过去7天、过去30天、过去一年(按月) // map 转为排序后的数组
let nowTime = new Date(); let hourlyEnergy: { key: string, value: string }[] = [];
let last24hStart = new Date(nowTime.getTime() - 24 * 3600000); hourlyMap.forEach((v, k) => hourlyEnergy.push({ key: k, value: v.toFixed(0) }));
let hourlyEnergy = await getEnergyTrend(energyDeviceIds, last24hStart, nowTime, 'hour'); hourlyEnergy.sort((a, b) => a.key.localeCompare(b.key));
let last7DaysStart = new Date(nowTime.getTime() - 7 * 86400000);
let dailyEnergy7 = await getEnergyTrend(energyDeviceIds, last7DaysStart, nowTime, 'day'); let dailyEnergy7: { key: string, value: string }[] = [];
let last30DaysStart = new Date(nowTime.getTime() - 30 * 86400000); daily7Map.forEach((v, k) => dailyEnergy7.push({ key: k, value: v.toFixed(0) }));
let dailyEnergy30 = await getEnergyTrend(energyDeviceIds, last30DaysStart, nowTime, 'day'); dailyEnergy7.sort((a, b) => a.key.localeCompare(b.key));
let lastYearStart = new Date(nowTime.getFullYear() - 1, nowTime.getMonth(), 1);
let monthlyEnergyYear = await getEnergyTrend(energyDeviceIds, lastYearStart, nowTime, 'month'); let dailyEnergy30: { key: string, value: string }[] = [];
daily30Map.forEach((v, k) => dailyEnergy30.push({ key: k, value: v.toFixed(0) }));
dailyEnergy30.sort((a, b) => a.key.localeCompare(b.key));
let monthlyEnergyYear: { key: string, value: string }[] = [];
monthlyMap.forEach((v, k) => monthlyEnergyYear.push({ key: k, value: v.toFixed(0) }));
monthlyEnergyYear.sort((a, b) => a.key.localeCompare(b.key));
let dailyYearOnYear = yesterdayTotal === 0 ? 0 : (((todayTotal - yesterdayTotal) / yesterdayTotal) * 100).toFixed(2);
let monthlyYearOnYear = previousMonthTotal === 0 ? 0 : (((currentMonthTotal - previousMonthTotal) / previousMonthTotal) * 100).toFixed(2);
// 补全 x 轴坐标的工具函数 // 补全 x 轴坐标的工具函数
function padTrend(trend: any[], allKeys: string[]): any[] { function padTrend(trend: any[], allKeys: string[]): any[] {
...@@ -155,11 +195,11 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -155,11 +195,11 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
// 1.4. 能耗监控数据和能耗监控趋势图数据 // 1.4. 能耗监控数据和能耗监控趋势图数据
resultAny.energyManagement = { resultAny.energyManagement = {
todayElectricity: todayEnergy.toFixed(0), todayElectricity: todayTotal.toFixed(0),
yesterdayElectricity: yesterdayEnergy.toFixed(0), yesterdayElectricity: yesterdayTotal.toFixed(0),
dailyYearOnYear, dailyYearOnYear,
currentMonthElectricity: currentMonthEnergy.toFixed(0), currentMonthElectricity: currentMonthTotal.toFixed(0),
previousMonthElectricity: previousMonthEnergy.toFixed(0), previousMonthElectricity: previousMonthTotal.toFixed(0),
monthlyYearOnYear monthlyYearOnYear
}; };
resultAny.electricityTrend = { resultAny.electricityTrend = {
...@@ -174,10 +214,11 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -174,10 +214,11 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
}; };
// 1.5. 过去24时运行能耗 // 1.5. 过去24时运行能耗
let last24hRunningEnergy = hourlyEnergy.reduce((sum: number, item: any) => sum + Number(item.value), 0); return { last24hRunningEnergy: hourlyEnergy.reduce((sum: number, item: any) => sum + Number(item.value), 0) };
})(),
// 4.1 环境监测九合一 // 模块2:环境监测
(async () => {
let airParams: any = {device_type: "环境监测" }; let airParams: any = {device_type: "环境监测" };
if (regionGroup) { if (regionGroup) {
airParams.region_key = { "%in%": regionKeys }; airParams.region_key = { "%in%": regionKeys };
...@@ -186,39 +227,51 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -186,39 +227,51 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
let airDeviceIds = airQualityDevices.data.map(d => d.device_id); let airDeviceIds = airQualityDevices.data.map(d => d.device_id);
let qualityIndex = 300; let qualityIndex = 300;
// 今日环境质量:{co2:660,hcho:0.01,humidity:70.5,light_level:0,pir:1,pm10:33,pm2_5:31,pressure:1011.7,temperature:21.6,tvoc:1}
let todayEnvironmental = '优秀'; let todayEnvironmental = '优秀';
let currentCo2 = 0; // 当前二氧化氮 let currentCo2 = 0;
let co2Trend = []; let co2Trend = [];
let currentTemperature = '0℃'; // 当前温度 let currentTemperature = '0℃';
let temperatureTrend = []; let temperatureTrend = [];
let currentHumidity = '0%'; // 当前湿度 let currentHumidity = '0%';
let humidityTrend = []; let humidityTrend = [];
let currentPm25 = 0; // 当前PM2.5 let currentPm25 = 0;
let pm25Trend = []; let pm25Trend = [];
let co2TrendDetail = []; let co2TrendDetail = [];
let currentHcho = 0; // 当前甲醛浓度 let currentHcho = 0;
let hchoTrend = []; let hchoTrend = [];
let currentLightLevel = 0; // 当前光照强度 let currentLightLevel = 0;
let lightLevelTrend = []; let lightLevelTrend = [];
let currentPir = ''; // 当前红外感应 let currentPir = '';
let pirTrend = []; let pirTrend = [];
let currentPm10 = 0; // 当前PM10 let currentPm10 = 0;
let pm10Trend = []; let pm10Trend = [];
let currentPressure = 0; // 当前大气压强 let currentPressure = 0;
let pressureTrend = []; let pressureTrend = [];
let currentTvoc = 0; // 当前有机物浓度 let currentTvoc = 0;
let tvocTrend = []; let tvocTrend = [];
if (airDeviceIds.length) { if (airDeviceIds.length) {
// 最新数据 // 并行查询每个环境监测设备的最新一条数据(拆分 IN+ORDER BY 为 N 个精准索引查询)
let latestAir = await selectDataListByParam(TABLENAME.设备数据表, { let latestResults = await Promise.all(
device_id: { "%in%": airDeviceIds }, airDeviceIds.map((deviceId: string) =>
selectDataListByParam(TABLENAME.设备数据表, {
device_id: deviceId,
"%orderDesc%": "device_time", "%orderDesc%": "device_time",
"%limit%": 1 "%limit%": 1
}, ["data"]); }, ["data", "device_time"])
)
);
// 找出时间最新的一条记录
let latestAir: any = null;
for (let res of latestResults) {
if (res.data.length > 0) {
if (!latestAir || new Date(res.data[0].device_time) > new Date(latestAir.data[0].device_time)) {
latestAir = res;
}
}
}
if (latestAir.data.length) { if (latestAir.data.length) {
let airData = latestAir.data[0].data; let airData = latestAir.data[0].data;
currentTemperature = `${airData.temperature ?? 0}`; currentTemperature = `${airData.temperature ?? 0}`;
...@@ -233,12 +286,11 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -233,12 +286,11 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
currentPressure = airData.pressure??0; currentPressure = airData.pressure??0;
currentTvoc = airData.tvoc??0; currentTvoc = airData.tvoc??0;
} }
// 今天 00:00 ~ 当前时刻 let todayStartEnv = new Date(nowTime);
let todayStart = new Date(nowTime); todayStartEnv.setHours(0, 0, 0, 0);
todayStart.setHours(0, 0, 0, 0);
let airHistory = await selectDataListByParam(TABLENAME.设备数据表, { let airHistory = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": airDeviceIds }, device_id: { "%in%": airDeviceIds },
device_time: { "%gte%": formatLocalTime(todayStart), "%lte%": formatLocalTime(nowTime) } device_time: { "%gte%": formatLocalTime(todayStartEnv), "%lte%": formatLocalTime(nowTime) }
}, ["data", "device_time"]); }, ["data", "device_time"]);
let hourlyData = new Map(); let hourlyData = new Map();
for (let rec of airHistory.data) { for (let rec of airHistory.data) {
...@@ -255,7 +307,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -255,7 +307,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
let key = `${i}`; let key = `${i}`;
let val = hourlyData.get(key); let val = hourlyData.get(key);
if (i <= currentHour) { if (i <= currentHour) {
// 已过去的小时:有数据则用,无数据填 '0'
temperatureTrend.push({ time: `${i}:00`, value: val?.temp?.toString() ?? '0' }); temperatureTrend.push({ time: `${i}:00`, value: val?.temp?.toString() ?? '0' });
humidityTrend.push({ time: `${i}:00`, value: val?.hum?.toString() ?? '0' }); humidityTrend.push({ time: `${i}:00`, value: val?.hum?.toString() ?? '0' });
pm25Trend.push({ time: `${i}:00`, value: val?.pm?.toString() ?? '0' }); pm25Trend.push({ time: `${i}:00`, value: val?.pm?.toString() ?? '0' });
...@@ -269,7 +320,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -269,7 +320,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
pressureTrend.push({ time: `${i}:00`, value: val?.pressure?.toString() ?? '0' }); pressureTrend.push({ time: `${i}:00`, value: val?.pressure?.toString() ?? '0' });
tvocTrend.push({ time: `${i}:00`, value: val?.tvoc?.toString() ?? '0' }); tvocTrend.push({ time: `${i}:00`, value: val?.tvoc?.toString() ?? '0' });
} else { } else {
// 未来的小时:填充 null,图表不画折线
temperatureTrend.push({ time: `${i}:00`, value: null }); temperatureTrend.push({ time: `${i}:00`, value: null });
humidityTrend.push({ time: `${i}:00`, value: null }); humidityTrend.push({ time: `${i}:00`, value: null });
pm25Trend.push({ time: `${i}:00`, value: null }); pm25Trend.push({ time: `${i}:00`, value: null });
...@@ -285,20 +335,13 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -285,20 +335,13 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
} }
} }
// 计算今日环境质量
if (currentCo2 && currentPm25) { if (currentCo2 && currentPm25) {
// 优秀:CO2< 800ppm; PM2.5≤35; 甲醛≤0.055
todayEnvironmental = currentCo2<800 && currentPm25<=35 ? '优秀': todayEnvironmental = currentCo2<800 && currentPm25<=35 ? '优秀':
// 优秀:CO2< 1000ppm; PM2.5≤45; TVOC≤0.4
currentCo2<1000 && currentPm25<=45 ? '优秀': currentCo2<1000 && currentPm25<=45 ? '优秀':
// 良好:CO2≤ 1000ppm; PM2.5≤50; 甲醛≤0.08
currentCo2<=1000 && currentPm25<=50 ? '良好': currentCo2<=1000 && currentPm25<=50 ? '良好':
// 一般:CO2:1000~1500; PM2.5:50~75
currentCo2>1000 && currentCo2<1500 && currentPm25>50 && currentPm25<75 ? '一般': '差' currentCo2>1000 && currentCo2<1500 && currentPm25>50 && currentPm25<75 ? '一般': '差'
} }
// 4.2. 环境监测趋势图数据
resultAny.environmentalTrend = { resultAny.environmentalTrend = {
todayEnvironmental: todayEnvironmental, todayEnvironmental: todayEnvironmental,
currentTemperature: currentTemperature, currentTemperature: currentTemperature,
...@@ -322,29 +365,27 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -322,29 +365,27 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
pressureTrend: pressureTrend, pressureTrend: pressureTrend,
tvocTrend: tvocTrend tvocTrend: tvocTrend
}; };
})(),
// 5.1 预警监控和预警工单处理进度分析(从 device_fault 表获取,近30天) // 模块3:预警监控
(async () => {
const faultStatusTextMap: { [key: number]: string } = { 0: "未处理", 1: "已响应", 2: "已解决" }; const faultStatusTextMap: { [key: number]: string } = { 0: "未处理", 1: "已响应", 2: "已解决" };
// 降级默认值:查询或统计失败时使用,保证其他模块不受影响
let alertStatus = { totalAlerts: 0, resolved: 0, responded: 0, unresolved: 0 }; let alertStatus = { totalAlerts: 0, resolved: 0, responded: 0, unresolved: 0 };
let alertWorkLevel: { [key: string]: number } = { "一级预警": 0, "二级预警": 0, "三级预警": 0 }; let alertWorkLevel: { [key: string]: number } = { "一级预警": 0, "二级预警": 0, "三级预警": 0 };
let alertWorkType: any[] = []; let alertWorkType: any[] = [];
let alertWorkOrders: any[] = []; let alertWorkOrders: any[] = [];
try { try {
// 时间范围:近30天
const thirtyDaysAgo = new Date(nowTime.getTime() - 30 * 86400000); const thirtyDaysAgo = new Date(nowTime.getTime() - 30 * 86400000);
const timeFilter = { "%gte%": formatLocalTime(thirtyDaysAgo) }; const timeFilter = { "%gte%": formatLocalTime(thirtyDaysAgo) };
// ---- 统计查询:只取 status/level/fault_type,避免传输无用字段 ----
const statsRes = await selectDataListByParam(TABLENAME.设备故障表, const statsRes = await selectDataListByParam(TABLENAME.设备故障表,
{ occurred_time: timeFilter }, { occurred_time: timeFilter },
["status", "level", "fault_type"]); ["status", "level", "fault_type"]);
const statsFaults: any[] = Array.isArray(statsRes.data) ? statsRes.data : []; const statsFaults: any[] = Array.isArray(statsRes.data) ? statsRes.data : [];
const totalAlerts = statsFaults.length; const totalAlerts = statsFaults.length;
// alertStatus:按处理状态一次遍历统计
let resolved = 0, responded = 0, unresolved = 0; let resolved = 0, responded = 0, unresolved = 0;
for (const f of statsFaults) { for (const f of statsFaults) {
if (f.status === 2) resolved++; if (f.status === 2) resolved++;
...@@ -353,14 +394,12 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -353,14 +394,12 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
} }
alertStatus = { totalAlerts, resolved, responded, unresolved }; alertStatus = { totalAlerts, resolved, responded, unresolved };
// alertWorkLevel:按故障等级统计
for (const f of statsFaults) { for (const f of statsFaults) {
if (f.level === 1) alertWorkLevel["一级预警"]++; if (f.level === 1) alertWorkLevel["一级预警"]++;
else if (f.level === 2) alertWorkLevel["二级预警"]++; else if (f.level === 2) alertWorkLevel["二级预警"]++;
else if (f.level === 3) alertWorkLevel["三级预警"]++; else if (f.level === 3) alertWorkLevel["三级预警"]++;
} }
// alertWorkType:按故障类型统计
let faultTypeCountMap = new Map<string, number>(); let faultTypeCountMap = new Map<string, number>();
for (const f of statsFaults) { for (const f of statsFaults) {
const typeName = f.fault_type || "其他"; const typeName = f.fault_type || "其他";
...@@ -374,7 +413,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -374,7 +413,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
}); });
} }
// ---- 工单列表查询:DB 层倒序 + LIMIT 10,避免全量拉到内存排序 ----
const ordersRes = await selectDataListByParam(TABLENAME.设备故障表, const ordersRes = await selectDataListByParam(TABLENAME.设备故障表,
{ {
occurred_time: timeFilter, occurred_time: timeFilter,
...@@ -384,7 +422,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -384,7 +422,6 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
["id", "device_id", "fault_type", "fault_code", "fault_description", "occurred_time", "level", "status"]); ["id", "device_id", "fault_type", "fault_code", "fault_description", "occurred_time", "level", "status"]);
const sortedFaults: any[] = Array.isArray(ordersRes.data) ? [...ordersRes.data] : []; const sortedFaults: any[] = Array.isArray(ordersRes.data) ? [...ordersRes.data] : [];
// 三级页面需要展示 alertAddress,需查设备表和区域表
let deviceRegionMap = new Map<string, string>(); let deviceRegionMap = new Map<string, string>();
if (regionType && sortedFaults.length > 0) { if (regionType && sortedFaults.length > 0) {
const faultUniqueDeviceIds = [...new Set(sortedFaults.map((f: any) => f.device_id))]; const faultUniqueDeviceIds = [...new Set(sortedFaults.map((f: any) => f.device_id))];
...@@ -435,146 +472,138 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -435,146 +472,138 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
alertWorkType, alertWorkType,
alertWorkOrders, alertWorkOrders,
}; };
})(),
// 6.1 人流监控及客流量趋势分析 // 模块4:客流监控(批量查询优化:N 次 per-region 查询 → 3 次 DB 查询)
(async () => {
let regionInfos: any = []; let regionInfos: any = [];
if (regionKeys.length === 0) { if (regionKeys.length === 0) {
// 6.1.1 若没有选择区域,则查询区域表获取所有区域类型
regionInfos = await selectDataListByParam(TABLENAME.区域表, { "%orderAsc%": "sort_order" }, ["id", "room_id", "name", "type", "groups"]); regionInfos = await selectDataListByParam(TABLENAME.区域表, { "%orderAsc%": "sort_order" }, ["id", "room_id", "name", "type", "groups"]);
} else { } else {
// 6.1.2 若选择了区域,则查询选择的区域
regionInfos = await selectDataListByParam(TABLENAME.区域表, { id: { "%in%": regionKeys }, "%orderAsc%": "sort_order" }, ["id", "room_id", "name", "type", "groups"]); regionInfos = await selectDataListByParam(TABLENAME.区域表, { id: { "%in%": regionKeys }, "%orderAsc%": "sort_order" }, ["id", "room_id", "name", "type", "groups"]);
} }
// 6.2 循环区域查询客流传感器设备,获取过去24小时每个区域的客流量 const allRegionIds = regionInfos.data.map((r: any) => r.id);
let totalRegionCustomerNum = 0; // 所有区域的总客流量
let regionMaxCustomerMap = new Map(); // {regionName: customerMaxNum} // 建立 regionKey -> 显示名称 / maxCapacity 映射
let regionCustomerMap = new Map(); // {regionName: customerNum} const regionKeyToName = new Map<string, string>();
let regionCustomerTable = []; // [{regionName: A馆, customerNum: 5000, saturation: '80%'}] const regionMaxCustomerMap = new Map<string, number>();
for (let regionInfo of regionInfos.data) { for (let r of regionInfos.data) {
// 区分楼栋与楼层 let name = regionKeys.length === 0 ? r.groups : r.type;
let regionName = regionKeys.length === 0 ? regionInfo.groups : regionInfo.type; regionKeyToName.set(r.id, name);
// 如果是按区域类型统计,则最大承载量取该类型下所有区域的总和;如果是按区域名称统计,则取该区域的最大承载量 let maxCap = regionKeys.length === 0 ? regionMaxCustomerMap.get(name) : r.max_capacity;
let maxCapacity = regionKeys.length === 0 ? regionMaxCustomerMap.get(regionName) : regionInfo.max_capacity; regionMaxCustomerMap.set(name, maxCap);
regionMaxCustomerMap.set(regionName, maxCapacity); // 区域最大承载量 }
// 初始化客流量
let totalNum = regionCustomerMap.get(regionName) ? regionCustomerMap.get(regionName) : 0; // 1. 批量查询所有客流传感器设备(1 次 DB 查询替代 N 次)
let allCustomerDevices = await selectDataListByParam(TABLENAME.设备表, {
let customerDevices = await selectDataListByParam(TABLENAME.设备表, { device_type: "客流传感器",
device_type: "客流传感器", region_key: regionInfo.id region_key: { "%in%": allRegionIds }
}, ["device_type", "device_id"]); }, ["device_type", "device_id", "region_key"]);
let customerDeviceIds = customerDevices.data.map((d: any) => d.device_id);
// 获取今日的客流量数据 const deviceRegionMap = new Map<string, string>();
if (customerDeviceIds && customerDeviceIds.length > 0) { const allCustomerDeviceIds: string[] = [];
let customerDeviceDatas = await selectDataListByParam(TABLENAME.设备数据表, { for (let d of allCustomerDevices.data) {
device_id: { "%in%": customerDeviceIds }, allCustomerDeviceIds.push(d.device_id);
deviceRegionMap.set(d.device_id, d.region_key);
}
let regionCustomerMap = new Map<string, number>();
let totalRegionCustomerNum = 0;
let todayCustomer = 0;
let yesterdayCustomer = 0;
let customerTrend: { time: string; value: number }[] = [];
let regionCustomerTable: any[] = [];
if (allCustomerDeviceIds.length > 0) {
// 2. 批量查询今日设备数据(合并 per-region 统计 + 趋势图,1 次 DB 查询)
let todayDatas = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": allCustomerDeviceIds },
device_time: { "%gte%": formatLocalTime(todayStart), "%lte%": formatLocalTime(todayEnd) }, device_time: { "%gte%": formatLocalTime(todayStart), "%lte%": formatLocalTime(todayEnd) },
"%orderAsc%": "device_time" "%orderAsc%": "device_time"
}, ["device_id", "data", "device_time"]); }, ["device_id", "data", "device_time"]);
// 统计区域类型的客流量(新格式使用 in/out) // 3. 批量查询昨日设备数据(1 次 DB 查询)
for (let rec of customerDeviceDatas.data) { let yesterdayDatas = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": allCustomerDeviceIds },
device_time: { "%gte%": formatLocalTime(yesterdayStart), "%lte%": formatLocalTime(yesterdayEnd) },
"%orderAsc%": "device_time"
}, ["device_id", "data", "device_time"]);
// 一次遍历今日数据:按区域统计 + 按小时聚合趋势
let hourlyCustomerMap = new Map<string, number>();
for (let rec of todayDatas.data) {
let data = rec.data; let data = rec.data;
// ====== 旧格式(已弃用,保留备用) ====== let netVisitor = data.in ?? 0;
// if (data.current_total) { // 区域统计(只统计 >0 的值)
// totalRegionCustomerNum += data.current_total;
// if (!regionCustomerMap.has(regionName)) {
// regionCustomerMap.set(regionName, data.current_total);
// } else {
// regionCustomerMap.set(regionName, totalNum + data.current_total);
// }
// }
const netVisitor = (data.in ?? 0);
if (netVisitor > 0) { if (netVisitor > 0) {
totalRegionCustomerNum += netVisitor; totalRegionCustomerNum += netVisitor;
if (!regionCustomerMap.has(regionName)) { let rk = deviceRegionMap.get(rec.device_id) || '';
regionCustomerMap.set(regionName, netVisitor); let regionName = regionKeyToName.get(rk) || rk;
} else { regionCustomerMap.set(regionName, (regionCustomerMap.get(regionName) || 0) + netVisitor);
totalNum = regionCustomerMap.get(regionName);
regionCustomerMap.set(regionName, totalNum + netVisitor);
} }
// 趋势聚合(所有值,含 0)
let d = new Date(rec.device_time);
let hourKey = `${d.getHours()}时`;
hourlyCustomerMap.set(hourKey, (hourlyCustomerMap.get(hourKey) || 0) + netVisitor);
} }
// 昨日汇总
for (let rec of yesterdayDatas.data) {
yesterdayCustomer += (rec.data?.in ?? 0);
} }
} else {
regionCustomerMap.set(regionName, totalNum); // 补全无传感器区域为 0
for (let r of regionInfos.data) {
let name = regionKeyToName.get(r.id) || '';
if (!regionCustomerMap.has(name)) {
regionCustomerMap.set(name, 0);
} }
} }
// 当日客流
let todayCustomer = 0;
let yesterdayCustomer = 0; // 构建区域饱和度表格
// 计算每个区域的饱和度(客流量/区域最大承载量),并转换成表格
for (let [regionName, customerNum] of regionCustomerMap.entries()) { for (let [regionName, customerNum] of regionCustomerMap.entries()) {
let regionMaxCustomer = regionMaxCustomerMap.get(regionName) || 1000; // 默认最大承载量为1000 let maxCap = regionMaxCustomerMap.get(regionName) || 1000;
let saturation = `${((customerNum / regionMaxCustomer) * 100)>100?100:((customerNum / regionMaxCustomer) * 100).toFixed(2)}%`; let saturation = `${Math.min(((customerNum / maxCap) * 100), 100).toFixed(2)}%`;
regionCustomerTable.push({ regionName, customerNum, saturation }); regionCustomerTable.push({ regionName, customerNum, saturation });
todayCustomer += customerNum; todayCustomer += customerNum;
} }
// 6.3 客流量趋势分析:根据查询到的客流传感器数据,统计所选区域过去24小时客流量变化趋势 // 构建24小时趋势
let customerTrend = [];
let customerParams: any = { device_type: "客流传感器" };
if (regionGroup) {
customerParams.region_key = { "%in%": regionKeys };
}
let customerDevices = await selectDataListByParam(TABLENAME.设备表, customerParams, ["device_type", "device_id"]);
if (customerDevices.data.length > 0) {
let customerDeviceIds = customerDevices.data.map((d: any) => d.device_id);
// 获取过去24小时客流量数据
let customerDeviceDatas = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": customerDeviceIds },
device_time: { "%gte%": formatLocalTime(todayStart), "%lte%": formatLocalTime(todayEnd) },
"%orderAsc%": "device_time"
}, ["device_id", "data", "device_time"]);
let hourlyCustomerMap = new Map();
for (let rec of customerDeviceDatas.data) {
let d = new Date(rec.device_time);
let hourKey = `${d.getHours()}时`;
let data = rec.data;
// ====== 旧格式(已弃用,保留备用) ======
// let customerNum = data.current_total;
// ====== 新格式使用 in ======
let customerNum = data.in ?? 0;
if (!hourlyCustomerMap.has(hourKey)) {
hourlyCustomerMap.set(hourKey, customerNum);
} else {
let totalNum = hourlyCustomerMap.get(hourKey);
hourlyCustomerMap.set(hourKey, totalNum + customerNum);
}
}
// 填充过去24小时的客流量趋势数据
for (let i = 0; i < 24; i++) { for (let i = 0; i < 24; i++) {
let key = `${i}时`; customerTrend.push({ time: `${i}:00`, value: hourlyCustomerMap.get(`${i}时`) ?? 0 });
let val = hourlyCustomerMap.get(key) ?? 0;
customerTrend.push({ time: `${i}:00`, value: val });
} }
} else {
// 获取昨日客流量数据 // 无客流传感器,所有区域填 0
let yesterdayDatas = await selectDataListByParam(TABLENAME.设备数据表, { for (let r of regionInfos.data) {
device_id: { "%in%": customerDeviceIds }, let name = regionKeyToName.get(r.id) || '';
device_time: { "%gte%": formatLocalTime(yesterdayStart), "%lte%": formatLocalTime(yesterdayEnd) }, regionCustomerMap.set(name, 0);
"%orderAsc%": "device_time" regionCustomerTable.push({ regionName: name, customerNum: 0, saturation: '0%' });
}, ["device_id", "data", "device_time"]);
for (let rec of yesterdayDatas.data) {
let data = rec.data;
// ====== 旧格式(已弃用,保留备用) ======
// let customerNum = data.current_total;
// ====== 新格式使用 in ======
let customerNum = data.in ?? 0;
yesterdayCustomer += customerNum;
} }
} }
// 6.4. 人流监控实时数据和趋势图数据
resultAny.customerOnlineTrend = { resultAny.customerOnlineTrend = {
todayCustomer: todayCustomer, todayCustomer: todayCustomer,
customerCompare: (todayCustomer - yesterdayCustomer) / yesterdayCustomer * 100, // 同比昨日(今日人流量-昨日人流量)÷昨日人流量x100% customerCompare: yesterdayCustomer > 0 ? ((todayCustomer - yesterdayCustomer) / yesterdayCustomer * 100) : 0,
passengerFlowTable: regionCustomerTable, passengerFlowTable: regionCustomerTable,
customerTrend: customerTrend customerTrend: customerTrend
}; };
return { todayCustomer, yesterdayCustomer, totalRegionCustomerNum };
})(),
]);
const energyResult = parallelResults[0] as { last24hRunningEnergy: number };
const customerResult = parallelResults[3] as { totalRegionCustomerNum: number };
const last24hRunningEnergy = energyResult.last24hRunningEnergy;
const totalRegionCustomerNum = customerResult.totalRegionCustomerNum;
// 三级页面不需要执行此逻辑 // 三级页面不需要执行此逻辑
if (!regionType) { if (!regionType) {
// 2.1 获取所选区域空调设备运行状态数据(如空调数、在线率、故障率等) // AC + Fan + RegionList 彼此独立,并行执行
let [acResult, fanResult, regionMap] = await Promise.all([
// 2. 空调设备运行监控
(async () => {
let acParams: any = { device_type: "空调" }; let acParams: any = { device_type: "空调" };
if (regionGroup) { if (regionGroup) {
acParams.region_key = { "%in%": regionKeys }; acParams.region_key = { "%in%": regionKeys };
...@@ -585,6 +614,7 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -585,6 +614,7 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
let acCount = acDeviceIds.length; let acCount = acDeviceIds.length;
let acOfflineCount = acDevices.data.filter((d: any) => isDeviceOffline(d.device_state ?? 0)).length; let acOfflineCount = acDevices.data.filter((d: any) => isDeviceOffline(d.device_state ?? 0)).length;
let acOnlineCount = acCount - acOfflineCount; let acOnlineCount = acCount - acOfflineCount;
let acFaultRecords = await selectDataListByParam( let acFaultRecords = await selectDataListByParam(
TABLENAME.设备故障表, TABLENAME.设备故障表,
{ status: { "%ne%": 2 }, device_id: { "%in%": acDeviceIds } }, { status: { "%ne%": 2 }, device_id: { "%in%": acDeviceIds } },
...@@ -592,55 +622,39 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -592,55 +622,39 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
); );
let acFaultDeviceIds = new Set(acFaultRecords.data.map((r: any) => r.device_id)); let acFaultDeviceIds = new Set(acFaultRecords.data.map((r: any) => r.device_id));
let acFaultDevices = acFaultDeviceIds.size; let acFaultDevices = acFaultDeviceIds.size;
let acNormalRate = acCount === 0 ? '100%' : (((acCount - acFaultDevices) / acCount) * 100).toFixed(2) + '%'; let acFaultCount = acFaultRecords.data.length;
let acFaultCount = acFaultRecords.data.length; //所有未解决的故障单数量(含同一设备多个故障)
// 2.2 获取今日空调在线趋势分析数据 let acOnlineTrend: { time: string; value: string }[] = [];
let acOnlineTrend = [];
if (acDeviceIds.length) { if (acDeviceIds.length) {
// 2.2.1 获取过去24小时设备数据
let last24h = new Date(nowTime.getTime() - 24 * 3600000); let last24h = new Date(nowTime.getTime() - 24 * 3600000);
let acHistory = await selectDataListByParam(TABLENAME.设备数据表, { let acHistory = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": acDeviceIds }, device_id: { "%in%": acDeviceIds },
device_time: { "%gte%": formatLocalTime(last24h) } device_time: { "%gte%": formatLocalTime(last24h) }
}, ["device_id", "data", "device_time"]); }, ["device_id", "data", "device_time"]);
// 2.2.2 按小时统计在线设备数和总设备数
let hourlyData = new Map(); let hourlyData = new Map();
for (let rec of acHistory.data) { for (let rec of acHistory.data) {
let d = new Date(rec.device_time); let d = new Date(rec.device_time);
let hourKey = `${d.getHours()}时`; let hourKey = `${d.getHours()}时`;
let data = rec.data; let data = rec.data;
// console.log(data);
if (!hourlyData.has(hourKey)) { if (!hourlyData.has(hourKey)) {
let totalNum = 1; hourlyData.set(hourKey, { online: data.power === "on" ? 1 : 0, total: 1 });
let onlineNum = data.power === "on" ? 1 : 0;
hourlyData.set(hourKey, { online: onlineNum, total: totalNum });
} else { } else {
let totalNum = hourlyData.get(hourKey).total; let v = hourlyData.get(hourKey);
let onlineNum = hourlyData.get(hourKey).online; if (data.power === "on") v.online += 1;
if (data.power === "on") onlineNum += 1; v.total += 1;
hourlyData.set(hourKey, { online: onlineNum, total: totalNum + 1 }); hourlyData.set(hourKey, v);
} }
} }
console.log("空调在线数据(过去24小时):", hourlyData.size);
// 2.2.3 填充24小时空调在线数据,没有在线数据的小时段则设为零,并计算每小时的空调在线率
for (let i = 0; i < 24; i++) { for (let i = 0; i < 24; i++) {
let key = `${i}时`; let key = `${i}时`;
let val = hourlyData.get(key); let val = hourlyData.get(key);
acOnlineTrend.push({ time: `${i}:00`, value: val ? ((val.online / val.total) * 100).toFixed(2) : '0' }); acOnlineTrend.push({ time: `${i}:00`, value: val ? ((val.online / val.total) * 100).toFixed(2) : '0' });
} }
} }
// 2.4. 空调设备在线趋势图数据 return { acDeviceIds, acCount, acOnlineCount, acOfflineCount, acFaultCount, acOnlineTrend };
resultAny.acDeviceOnlineTrend = { })(),
acCount: acDeviceIds.length, // 3. 新风运行监控
acOnlineCount: acOnlineCount, (async () => {
acOfflineCount: acOfflineCount,
acFaultCount: acFaultCount,
acOnlineTrend: acOnlineTrend
};
// 3.1 新风运行监控
let fanParams: any = { device_type: "新风" }; let fanParams: any = { device_type: "新风" };
if (regionGroup) { if (regionGroup) {
fanParams.region_key = { "%in%": regionKeys }; fanParams.region_key = { "%in%": regionKeys };
...@@ -651,26 +665,23 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -651,26 +665,23 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
let fanCount = fanDeviceIds.length; let fanCount = fanDeviceIds.length;
let fanOfflineCount = fanDevices.data.filter((d: any) => isDeviceOffline(d.device_state ?? 0)).length; let fanOfflineCount = fanDevices.data.filter((d: any) => isDeviceOffline(d.device_state ?? 0)).length;
let fanOnlineCount = fanCount - fanOfflineCount; let fanOnlineCount = fanCount - fanOfflineCount;
let fanFaultRecords = await selectDataListByParam( let fanFaultRecords = await selectDataListByParam(
TABLENAME.设备故障表, TABLENAME.设备故障表,
{ status: { "%ne%": 2 }, device_id: { "%in%": fanDeviceIds } }, { status: { "%ne%": 2 }, device_id: { "%in%": fanDeviceIds } },
["device_id"] ["device_id"]
); );
let fanFaultDeviceIds = new Set(fanFaultRecords.data.map((r: any) => r.device_id)); let fanFaultDeviceIds = new Set(fanFaultRecords.data.map((r: any) => r.device_id));
let fanFaultDevices = fanFaultDeviceIds.size; let fanFaultCount = fanFaultRecords.data.length;
let fanNormalRate = fanCount === 0 ? '100%' : (((fanCount - fanFaultDevices) / fanCount) * 100).toFixed(2) + '%';
let fanFaultCount = fanFaultRecords.data.length; //所有未解决的故障单数量(含同一设备多个故障)
// 3.2 新风风量运行监测趋势分析数据(如果有风量数据) let fanOnlineTrend: { time: string; value: string }[] = [];
let fanOnlineTrend = [];
if (fanDeviceIds.length) { if (fanDeviceIds.length) {
let fanDeviceDatas = await selectDataListByParam(TABLENAME.设备数据表, { let fanDeviceDatas = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": fanDeviceIds }, device_id: { "%in%": fanDeviceIds },
device_time: { "%gte%": formatLocalTime(last24hStart), "%lte%": formatLocalTime(nowTime) }, device_time: { "%gte%": formatLocalTime(last24hStart), "%lte%": formatLocalTime(nowTime) },
"%orderAsc%": "device_time" "%orderAsc%": "device_time"
}, ["device_id", "data", "device_time"]); }, ["device_id", "data", "device_time"]);
// 3.2.1 按小时统计新风送风量(换气次数=送风量/房间体积) let hourlyData = new Map();
let hourlyData = new Map(); // {key: 00:00, ly: 0, ry: 0 }
for (let rec of fanDeviceDatas.data) { for (let rec of fanDeviceDatas.data) {
let d = new Date(rec.device_time); let d = new Date(rec.device_time);
let hourKey = `${d.getHours()}时`; let hourKey = `${d.getHours()}时`;
...@@ -679,36 +690,46 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -679,36 +690,46 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
hourlyData.set(hourKey, { airSupply: airSupplyKeyMap[data.fanSpeed] }); hourlyData.set(hourKey, { airSupply: airSupplyKeyMap[data.fanSpeed] });
} }
} }
// 3.2.2 填充24小时新风监控数据,没有在线数据的小时段则设为零,并计算每小时的新风送风量
for (let i = 0; i < 24; i++) { for (let i = 0; i < 24; i++) {
let key = `${i}时`; let key = `${i}时`;
let val = hourlyData.get(key); let val = hourlyData.get(key);
fanOnlineTrend.push({ time: `${i}:00`, value: val ? val.airSupply : '0' }); fanOnlineTrend.push({ time: `${i}:00`, value: val ? val.airSupply : '0' });
} }
} }
return { fanDeviceIds, fanCount, fanOnlineCount, fanOfflineCount, fanFaultCount, fanOnlineTrend };
})(),
// 7. 区域列表
getRegionList(regionGroup)
]);
// 2.4. 空调设备在线趋势图数据
resultAny.acDeviceOnlineTrend = {
acCount: acResult.acCount,
acOnlineCount: acResult.acOnlineCount,
acOfflineCount: acResult.acOfflineCount,
acFaultCount: acResult.acFaultCount,
acOnlineTrend: acResult.acOnlineTrend
};
// 3.3. 新风设备在线趋势图数据 // 3.3. 新风设备在线趋势图数据
resultAny.fanDeviceOnlineTrend = { resultAny.fanDeviceOnlineTrend = {
fanCount: fanDeviceIds.length, fanCount: fanResult.fanCount,
fanOnlineCount: fanOnlineCount, fanOnlineCount: fanResult.fanOnlineCount,
fanOfflineCount: fanOfflineCount, fanOfflineCount: fanResult.fanOfflineCount,
fanFaultCount: fanFaultCount, fanFaultCount: fanResult.fanFaultCount,
fanOnlineTrend: fanOnlineTrend fanOnlineTrend: fanResult.fanOnlineTrend
}; };
// 7.1 获取区域列表接口,供前端下拉选择区域类型和区域名称
let regionMap: any = await getRegionList(regionGroup);
// 7.2. 区域列表数据 // 7.2. 区域列表数据
resultAny.regionData = regionMap; resultAny.regionData = regionMap;
// 运行监控总数据(一天) // 运行监控总数据(一天)
resultAny.mainRunningManagement = { resultAny.mainRunningManagement = {
totalCustomerNumber: totalRegionCustomerNum, totalCustomerNumber: totalRegionCustomerNum,
totalDeviceOnlineRate: (acOnlineCount/acCount*100)>=100?'100':(acOnlineCount/acCount*100).toFixed(1), totalDeviceOnlineRate: (acResult.acOnlineCount / acResult.acCount * 100) >= 100 ? '100' : (acResult.acOnlineCount / acResult.acCount * 100).toFixed(1),
// totalElectricity: last24hRunningEnergy.toFixed(0).slice(0, 5),
totalElectricity: last24hRunningEnergy.toFixed(0), totalElectricity: last24hRunningEnergy.toFixed(0),
}; };
} else { } else {
// 设备监控总数据
let devices = await selectDataListByParam(TABLENAME.设备表, { let devices = await selectDataListByParam(TABLENAME.设备表, {
region_key: { "%in%": regionKeys } region_key: { "%in%": regionKeys }
}, ["device_id", "device_state"]); }, ["device_id", "device_state"]);
...@@ -902,46 +923,6 @@ export async function controlAcRunning(params: {}) { ...@@ -902,46 +923,6 @@ export async function controlAcRunning(params: {}) {
return result; return result;
} }
// 辅助函数:获取用电趋势(按间隔分组)
async function getEnergyTrend(deviceIds: string[], startTime: Date, endTime: Date, granularity: 'hour' | 'day' | 'month') {
if (deviceIds.length === 0) return [];
let records = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": deviceIds },
device_time: { "%gte%": formatLocalTime(startTime), "%lte%": formatLocalTime(endTime) },
"%orderAsc%": "device_time"
}, ["device_id", "data", "device_time"]);
let intervalMap = new Map(); // key: 时间字符串, value: { deviceMin, deviceMax }
for (let rec of records.data) {
let data = rec.data;
// let energy = data.energy ?? data.total_energy;
let energy = data.current;
if (energy === undefined) continue;
let intervalKey: string;
let d = new Date(rec.device_time);
const pad = (n: number) => String(n).padStart(2, '0');
if (granularity === 'hour') {
intervalKey = `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}时`;
} else if (granularity === 'day') {
intervalKey = `${d.getFullYear()}/${pad(d.getMonth()+1)}/${pad(d.getDate())}`;
} else {
intervalKey = `${d.getFullYear()}-${pad(d.getMonth()+1)}`;
}
if (!intervalMap.has(intervalKey)) {
intervalMap.set(intervalKey, energy);
} else {
energy = intervalMap.get(intervalKey) + energy;
intervalMap.set(intervalKey, energy);
}
}
let result = [];
for (let [key, energy] of intervalMap.entries()) {
result.push({ key, value: energy.toFixed(0) });
}
result.sort((a, b) => a.key.localeCompare(b.key));
return result;
}
/** /**
* 获取本月累计用电(按天) * 获取本月累计用电(按天)
* 查询三相电表/电能监测设备的每日用电量,补全当月 1 日到今天的 x 轴 * 查询三相电表/电能监测设备的每日用电量,补全当月 1 日到今天的 x 轴
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment