Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Q
qingdaoMuseumPlatform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
node_server
qingdaoMuseumPlatform
Commits
a11cbed3
Commit
a11cbed3
authored
May 21, 2026
by
PC-20251223ZVQQ\Administrator
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
一类页面和二类页面部分解析数据
parent
4456e3b0
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
492 additions
and
16 deletions
+492
-16
region.ts
src/biz/region.ts
+479
-11
mysqlTableConfig.ts
src/config/mysqlTableConfig.ts
+5
-0
device.ts
src/routers/device.ts
+8
-5
No files found.
src/biz/region.ts
View file @
a11cbed3
...
...
@@ -5,6 +5,7 @@ import { BizError } from "../util/bizError";
import
{
ERRORENUM
}
from
"../config/errorEnum"
;
import
{
addData
}
from
"../data/addData"
;
import
{
updateManyData
}
from
"../data/updateData"
;
import
{
region
}
from
"tencentcloud-sdk-nodejs"
;
/**
* 注册或更新设备信息
...
...
@@ -125,29 +126,496 @@ export async function handleDeviceFaultPush( deviceId: string, faultType: string
/**
* 智能管控-运行分析
* @param region
Name 区域名称(可选),如“A馆1F
”,如果提供则返回该区域的分析数据
* @param region
Key 区域标识(可选),如“A馆1F对应1
”,如果提供则返回该区域的分析数据
* @param regionType 区域类型(可选),如“A馆”,如果提供则返回该类型下所有区域的分析数据
* @returns 大屏所需的所有指标数据
*/
export
async
function
getRunAnalysis
(
region
Name
:
String
,
regionType
:
String
)
{
export
async
function
getRunAnalysis
(
region
Key
:
String
,
regionType
:
String
)
{
// 根据区域类型和名称筛选设备ID列表(如果提供了区域信息)
let
regionKey
=
[];
let
regionKey
s
:
any
=
[];
if
(
regionType
)
{
let
regionInfo
:
any
=
await
selectDataListByParam
(
TABLENAME
.
区域表
,
{
type
:
regionType
},
[
"id"
]);
regionKey
=
regionInfo
.
data
.
map
((
r
:
any
)
=>
r
.
id
);
regionKey
s
=
regionInfo
.
data
.
map
((
r
:
any
)
=>
r
.
id
);
}
if
(
regionName
)
{
let
regionInfo
:
any
=
await
selectDataListByParam
(
TABLENAME
.
区域表
,
{
name
:
regionName
},
[
"id"
]);
regionKey
=
regionInfo
.
data
.
map
((
r
:
any
)
=>
r
.
id
);
if
(
regionKey
)
{
regionKeys
.
push
(
regionKey
);
}
console
.
log
(
"筛选区域Key:"
,
regionKeys
);
// 1.1 获取所选区域三相电表及电能监测设备的用电数据(用于能耗管理)
let
powerParams
:
any
=
{
device_type
:
{
"%in%"
:
[
"三相电表"
,
"电能监测"
]
}};
if
(
regionKeys
.
length
>
0
)
{
powerParams
.
region_key
=
{
"%in%"
:
regionKeys
};
}
let
energyDevices
=
await
selectDataListByParam
(
TABLENAME
.
设备表
,
powerParams
,
[
"device_id"
]);
let
energyDeviceIds
=
energyDevices
.
data
.
map
((
d
:
any
)
=>
d
.
device_id
);
// 1.2 获取今日、昨日、本月、上月用电量
let
todayStart
=
new
Date
();
todayStart
.
setHours
(
0
,
0
,
0
,
0
);
let
todayEnd
=
new
Date
();
let
yesterdayStart
=
new
Date
(
Date
.
now
()
-
86400000
);
yesterdayStart
.
setHours
(
0
,
0
,
0
,
0
);
let
yesterdayEnd
=
new
Date
(
Date
.
now
()
-
86400000
);
yesterdayEnd
.
setHours
(
23
,
59
,
59
,
999
);
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
lastMonthEnd
=
new
Date
(
currentMonthStart
.
getTime
()
-
1
);
// 辅助函数:查询某个时间段内的总用电量(单位 kwh)
async
function
getTotalEnergy
(
deviceIds
:
string
[],
startTime
:
Date
,
endTime
:
Date
):
Promise
<
number
>
{
if
(
deviceIds
.
length
===
0
)
return
0
;
let
records
=
await
selectDataListByParam
(
TABLENAME
.
设备数据表
,
{
device_id
:
{
"%in%"
:
deviceIds
},
received_time
:
{
"%gte%"
:
startTime
.
toISOString
().
slice
(
0
,
19
).
replace
(
'T'
,
' '
),
"%lte%"
:
endTime
.
toISOString
().
slice
(
0
,
19
).
replace
(
'T'
,
' '
)
},
"%orderAsc%"
:
"received_time"
},
[
"device_id"
,
"data"
,
"received_time"
]);
let
total
=
0
;
let
deviceEnergyMap
=
new
Map
();
for
(
let
rec
of
records
.
data
)
{
let
data
=
rec
.
data
;
let
energy
=
data
.
energy
??
data
.
total_energy
;
if
(
energy
===
undefined
)
continue
;
if
(
!
deviceEnergyMap
.
has
(
rec
.
device_id
))
{
deviceEnergyMap
.
set
(
rec
.
device_id
,
{
min
:
energy
,
max
:
energy
});
}
else
{
let
cur
=
deviceEnergyMap
.
get
(
rec
.
device_id
);
if
(
energy
<
cur
.
min
)
cur
.
min
=
energy
;
if
(
energy
>
cur
.
max
)
cur
.
max
=
energy
;
}
}
for
(
let
{
min
,
max
}
of
deviceEnergyMap
.
values
())
{
total
+=
(
max
-
min
);
}
return
total
;
}
let
todayEnergy
=
await
getTotalEnergy
(
energyDeviceIds
,
todayStart
,
todayEnd
);
let
yesterdayEnergy
=
await
getTotalEnergy
(
energyDeviceIds
,
yesterdayStart
,
yesterdayEnd
);
let
currentMonthEnergy
=
await
getTotalEnergy
(
energyDeviceIds
,
currentMonthStart
,
new
Date
());
let
previousMonthEnergy
=
await
getTotalEnergy
(
energyDeviceIds
,
lastMonthStart
,
lastMonthEnd
);
let
dailyYearOnYear
=
yesterdayEnergy
===
0
?
'0%'
:
`
${(((
todayEnergy
-
yesterdayEnergy
)
/
yesterdayEnergy
)
*
100
).
toFixed
(
2
)}
%`
;
let
monthlyYearOnYear
=
previousMonthEnergy
===
0
?
'0%'
:
`
${(((
currentMonthEnergy
-
previousMonthEnergy
)
/
previousMonthEnergy
)
*
100
).
toFixed
(
2
)}
%`
;
// 1.3 用电趋势:过去24小时(按小时)、过去7天、过去30天、过去一年(按月)
let
nowTime
=
new
Date
();
let
last24hStart
=
new
Date
(
nowTime
.
getTime
()
-
24
*
3600000
);
let
hourlyEnergy
=
await
getEnergyTrend
(
energyDeviceIds
,
last24hStart
,
nowTime
,
'hour'
);
let
last7DaysStart
=
new
Date
(
nowTime
.
getTime
()
-
7
*
86400000
);
let
dailyEnergy7
=
await
getEnergyTrend
(
energyDeviceIds
,
last7DaysStart
,
nowTime
,
'day'
);
let
last30DaysStart
=
new
Date
(
nowTime
.
getTime
()
-
30
*
86400000
);
let
dailyEnergy30
=
await
getEnergyTrend
(
energyDeviceIds
,
last30DaysStart
,
nowTime
,
'day'
);
let
lastYearStart
=
new
Date
(
nowTime
.
getFullYear
()
-
1
,
nowTime
.
getMonth
(),
1
);
let
monthlyEnergyYear
=
await
getEnergyTrend
(
energyDeviceIds
,
lastYearStart
,
nowTime
,
'month'
);
// 2.1 获取所选区域空调设备运行状态数据(如空调数、在线率、故障率等)
let
acParams
:
any
=
{
device_type
:
"空调"
};
if
(
regionKeys
.
length
>
0
)
{
acParams
.
region_key
=
{
"%in%"
:
regionKeys
};
}
let
acDevices
=
await
selectDataListByParam
(
TABLENAME
.
设备表
,
acParams
,
[
"device_id"
]);
let
acDeviceIds
=
acDevices
.
data
.
map
((
d
:
any
)
=>
d
.
device_id
);
let
acCount
=
acDeviceIds
.
length
;
let
acOfflineCount
=
0
;
let
acOnlineCount
=
acCount
-
acOfflineCount
;
let
acFaultRecords
=
await
selectDataListByParam
(
TABLENAME
.
设备故障表
,
{
status
:
{
"%ne%"
:
2
},
device_id
:
{
"%in%"
:
acDeviceIds
}
},
[
"device_id"
]
);
let
acFaultDeviceIds
=
new
Set
(
acFaultRecords
.
data
.
map
((
r
:
any
)
=>
r
.
device_id
));
let
acFaultDevices
=
acFaultDeviceIds
.
size
;
let
acNormalRate
=
acCount
===
0
?
'100%'
:
(((
acCount
-
acFaultDevices
)
/
acCount
)
*
100
).
toFixed
(
2
)
+
'%'
;
let
acFaultCount
=
acFaultRecords
.
data
.
length
;
//所有未解决的故障单数量(含同一设备多个故障)
// 2.2 获取今日空调在线趋势分析数据
let
acOnlineTrend
=
[];
if
(
acDeviceIds
.
length
)
{
// 2.2.1 获取过去24小时设备数据
let
last24h
=
new
Date
(
nowTime
.
getTime
()
-
24
*
3600000
);
let
acHistory
=
await
selectDataListByParam
(
TABLENAME
.
设备数据表
,
{
device_id
:
{
"%in%"
:
acDeviceIds
},
received_time
:
{
"%gte%"
:
last24h
.
toISOString
().
slice
(
0
,
19
).
replace
(
'T'
,
' '
)
}
},
[
"device_id"
,
"data"
,
"received_time"
]);
// 2.2.2 按小时统计在线设备数和总设备数
let
hourlyData
=
new
Map
();
for
(
let
rec
of
acHistory
.
data
)
{
let
d
=
new
Date
(
rec
.
received_time
);
let
hourKey
=
`
${
d
.
getHours
()}
时`
;
let
data
=
rec
.
data
;
console
.
log
(
data
);
if
(
!
hourlyData
.
has
(
hourKey
))
{
let
totalNum
=
1
;
let
onlineNum
=
data
.
power
===
"on"
?
1
:
0
;
hourlyData
.
set
(
hourKey
,
{
online
:
onlineNum
,
total
:
totalNum
});
}
else
{
let
totalNum
=
hourlyData
.
get
(
hourKey
).
total
;
let
onlineNum
=
hourlyData
.
get
(
hourKey
).
online
;
if
(
data
.
power
===
"on"
)
onlineNum
+=
1
;
hourlyData
.
set
(
hourKey
,
{
online
:
onlineNum
,
total
:
totalNum
+
1
});
}
}
console
.
log
(
"空调在线数据(过去24小时):"
,
hourlyData
);
// 2.2.3 填充24小时空调在线数据,没有在线数据的小时段则设为零,并计算每小时的空调在线率
for
(
let
i
=
0
;
i
<
24
;
i
++
)
{
let
key
=
`
${
i
}
时`
;
let
val
=
hourlyData
.
get
(
key
);
acOnlineTrend
.
push
({
time
:
`
${
i
}
:00`
,
value
:
val
?
((
val
.
online
/
val
.
total
)
*
100
).
toFixed
(
2
)
:
'0'
});
}
// 2.3. 设备监测情况:在线/离线(根据最后数据时间是否超过30分钟)
let
deviceLatestMap
=
new
Map
();
for
(
let
devId
of
acDeviceIds
)
{
let
rec
=
await
selectDataListByParam
(
TABLENAME
.
设备数据表
,
{
device_id
:
devId
,
"%orderDesc%"
:
"received_time"
,
"%limit%"
:
1
},
[
"received_time"
]);
if
(
rec
.
data
.
length
)
{
let
lastTime
=
new
Date
(
rec
.
data
[
0
].
received_time
);
let
diffMinutes
=
(
nowTime
.
getTime
()
-
lastTime
.
getTime
())
/
60000
;
deviceLatestMap
.
set
(
devId
,
{
lastTime
,
isOnline
:
diffMinutes
<=
30
});
}
else
{
deviceLatestMap
.
set
(
devId
,
{
lastTime
:
null
,
isOnline
:
false
});
}
}
acOnlineCount
=
Array
.
from
(
deviceLatestMap
.
values
()).
filter
(
v
=>
v
.
isOnline
).
length
;
acOfflineCount
=
acCount
-
acOnlineCount
;
}
// 3.1 新风运行监控
let
fanParams
:
any
=
{
device_type
:
"新风"
};
if
(
regionKeys
.
length
>
0
)
{
fanParams
.
region_key
=
{
"%in%"
:
regionKeys
};
}
let
fanDevices
=
await
selectDataListByParam
(
TABLENAME
.
设备表
,
fanParams
,
[
"device_id"
]);
let
fanDeviceIds
=
fanDevices
.
data
.
map
((
d
:
any
)
=>
d
.
device_id
);
let
fanCount
=
fanDeviceIds
.
length
;
let
fanOfflineCount
=
0
;
let
fanOnlineCount
=
fanCount
-
fanOfflineCount
;
let
fanFaultRecords
=
await
selectDataListByParam
(
TABLENAME
.
设备故障表
,
{
status
:
{
"%ne%"
:
2
},
device_id
:
{
"%in%"
:
fanDeviceIds
}
},
[
"device_id"
]
);
let
fanFaultDeviceIds
=
new
Set
(
fanFaultRecords
.
data
.
map
((
r
:
any
)
=>
r
.
device_id
));
let
fanFaultDevices
=
fanFaultDeviceIds
.
size
;
let
fanNormalRate
=
fanCount
===
0
?
'100%'
:
(((
fanCount
-
fanFaultDevices
)
/
fanCount
)
*
100
).
toFixed
(
2
)
+
'%'
;
let
fanFaultCount
=
fanFaultRecords
.
data
.
length
;
//所有未解决的故障单数量(含同一设备多个故障)
// 3.2 新风风量运行监测趋势分析数据(如果有风量数据)
let
fanOnlineTrend
=
[];
if
(
fanDeviceIds
.
length
)
{
let
fanDeviceDatas
=
await
selectDataListByParam
(
TABLENAME
.
设备数据表
,
{
device_id
:
{
"%in%"
:
fanDeviceIds
},
received_time
:
{
"%gte%"
:
last24hStart
.
toISOString
().
slice
(
0
,
19
).
replace
(
'T'
,
' '
),
"%lte%"
:
nowTime
.
toISOString
().
slice
(
0
,
19
).
replace
(
'T'
,
' '
)
},
"%orderAsc%"
:
"received_time"
},
[
"device_id"
,
"data"
,
"received_time"
]);
// 3.2.1 按小时统计新风送风量(换气次数=送风量/房间体积)
let
hourlyData
=
new
Map
();
// {key: 00:00, ly: 0, ry: 0 }
for
(
let
rec
of
fanDeviceDatas
.
data
)
{
let
d
=
new
Date
(
rec
.
received_time
);
let
hourKey
=
`
${
d
.
getHours
()}
时`
;
let
data
=
rec
.
data
;
if
(
!
hourlyData
.
has
(
hourKey
))
{
hourlyData
.
set
(
hourKey
,
{
airSupply
:
data
.
airSupply
});
}
}
// 3.2.2 填充24小时新风监控数据,没有在线数据的小时段则设为零,并计算每小时的新风送风量
for
(
let
i
=
0
;
i
<
24
;
i
++
)
{
let
key
=
`
${
i
}
时`
;
let
val
=
hourlyData
.
get
(
key
);
fanOnlineTrend
.
push
({
time
:
`
${
i
}
:00`
,
value
:
val
?
val
.
airSupply
:
'0'
});
}
}
// 4.1 环境监测九合一
let
airParams
:
any
=
{
device_type
:
"环境监测"
};
if
(
regionKeys
.
length
>
0
)
{
airParams
.
region_key
=
{
"%in%"
:
regionKeys
};
}
let
airQualityDevices
=
await
selectDataListByParam
(
TABLENAME
.
设备表
,
airParams
,
[
"device_id"
]);
let
airDeviceIds
=
airQualityDevices
.
data
.
map
(
d
=>
d
.
device_id
);
let
qualityIndex
=
300
;
let
co2Trend
=
[];
let
currentCo2
=
'21ppm'
;
let
currentTemperature
=
'21℃'
;
let
temperatureTrend
=
[];
let
currentHumidity
=
'47%'
;
let
humidityTrend
=
[];
let
currentPm25
=
'21μg/m³'
;
let
pm25Trend
=
[];
let
co2TrendDetail
=
[];
if
(
airDeviceIds
.
length
)
{
// 最新数据
let
latestAir
=
await
selectDataListByParam
(
TABLENAME
.
设备数据表
,
{
device_id
:
{
"%in%"
:
airDeviceIds
},
"%orderDesc%"
:
"received_time"
,
"%limit%"
:
1
},
[
"data"
]);
if
(
latestAir
.
data
.
length
)
{
let
airData
=
latestAir
.
data
[
0
].
data
;
currentTemperature
=
`
${
airData
.
temperature
??
21
}
℃
`;
currentHumidity = `
$
{
airData
.
humidity
??
47
}
%
`;
currentPm25 = `
$
{
airData
.
pm25
??
21
}
μ
g
/
m
³
`;
currentCo2 = `
$
{
airData
.
co2
??
400
}
ppm
`;
qualityIndex = 500 - (airData.pm25 ?? 0);
}
// 过去24小时趋势
let last24h = new Date(nowTime.getTime() - 24*3600000);
let airHistory = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": airDeviceIds },
received_time: { "%gte%": last24h.toISOString().slice(0,19).replace('T',' ') }
}, ["data", "received_time"]);
let hourlyData = new Map();
for (let rec of airHistory.data) {
let d = new Date(rec.received_time);
let hourKey = `
$
{
d
.
getHours
()}
时
`;
let data = rec.data;
if (!hourlyData.has(hourKey)) {
hourlyData.set(hourKey, { temp: data.temperature, hum: data.humidity, pm: data.pm25, co2: data.co2 });
}
}
for (let i = 0; i < 24; i++) {
let key = `
$
{
i
}
时
`;
let val = hourlyData.get(key);
temperatureTrend.push({ time: `
$
{
i
}:
00
`, value: val?.temp?.toString() ?? '21' });
humidityTrend.push({ time: `
$
{
i
}:
00
`, value: val?.hum?.toString() ?? '47' });
pm25Trend.push({ time: `
$
{
i
}:
00
`, value: val?.pm?.toString() ?? '21' });
let co2Val = val?.co2 ?? 400;
co2TrendDetail.push({ time: `
$
{
i
}:
00
`, value: (co2Val / 100).toFixed(1) });
co2Trend.push({ time: `
$
{
i
}
时
`, value: co2Val.toString() });
}
}
// 5.1 预警监控和预警工单处理进度分析
// 6.1 人流监控及客流量趋势分析
let regionInfos: any = [];
if (regionKeys.length === 0) {
// 6.1.1 若没有选择区域,则查询区域表获取所有区域类型
regionInfos = await selectDataListByParam(TABLENAME.区域表, {}, ["id", "name", "type"]);
} else {
// 6.1.2 若选择了区域,则查询选择的区域
regionInfos = await selectDataListByParam(TABLENAME.区域表, { id: { "%in%": regionKeys } }, ["id", "name", "type"]);
}
// 6.2 循环区域查询客流传感器设备,获取过去24小时每个区域的客流量
let totalRegionCustomerNum = 0; // 所有区域的总客流量
let regionMaxCustomerMap = new Map(); // {regionName: customerMaxNum}
let regionCustomerMap = new Map(); // {regionName: customerNum}
let regionCustomerTable = []; // [{regionName: A馆, customerNum: 5000, saturation: '80%'}]
for (let regionInfo of regionInfos.data) {
let customerDevices = await selectDataListByParam(TABLENAME.设备表, {
device_type: "客流传感器", region_key: regionInfo.id
}, ["device_type", "device_id"]);
let customerDeviceIds = customerDevices.data.map((d: any) => d.device_id);
// 获取今日的客流量数据
if (customerDeviceIds) {
let customerDeviceDatas = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": customerDeviceIds },
received_time: { "%gte%": todayStart.toISOString().slice(0,19).replace('T',' '), "%lte%": todayEnd.toISOString().slice(0,19).replace('T',' ') },
"%orderAsc%": "received_time"
}, ["device_id", "data", "received_time"]);
// 统计区域类型的客流量
for (let rec of customerDeviceDatas.data) {
let data = rec.data;
if (data.presence === '进') {
totalRegionCustomerNum += 1;
// 区分楼栋与楼层
let regionName = regionKeys.length === 0 ? regionInfo.type : regionInfo.name;
if (!regionCustomerMap.has(regionName)) {
regionCustomerMap.set(regionName, 1);
// 如果是按区域类型统计,则最大承载量取该类型下所有区域的总和;如果是按区域名称统计,则取该区域的最大承载量
let maxCapacity = regionKeys.length === 0 ? regionMaxCustomerMap.get(regionName) : regionInfo.max_capacity;
regionMaxCustomerMap.set(regionName, maxCapacity); // 区域最大承载量
} else {
let totalNum = regionCustomerMap.get(regionName);
regionCustomerMap.set(regionName, totalNum + 1);
}
}
}
}
}
// 计算每个区域的饱和度(客流量/区域最大承载量),并转换成表格
for (let [regionName, customerNum] of regionCustomerMap.entries()) {
let regionMaxCustomer = regionMaxCustomerMap.get(regionName) || 10000; // 默认最大承载量为10000
let saturation = `
$
{((
customerNum
/
regionMaxCustomer
)
*
100
).
toFixed
(
2
)}
%
`;
regionCustomerTable.push({ regionName, customerNum, saturation });
}
// 6.3 客流量趋势分析:根据查询到的客流传感器数据,统计所选区域过去24小时客流量变化趋势
let customerTrend = [];
let customerParams: any = { device_type: "客流传感器" };
if (regionKeys.length > 0) {
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 },
received_time: { "%gte%": last24hStart.toISOString().slice(0,19).replace('T',' '), "%lte%": nowTime.toISOString().slice(0,19).replace('T',' ') },
"%orderAsc%": "received_time"
}, ["device_id", "data", "received_time"]);
let hourlyCustomerMap = new Map();
for (let rec of customerDeviceDatas.data) {
let d = new Date(rec.received_time);
let hourKey = `
$
{
d
.
getHours
()}
时
`;
let data = rec.data;
let customerNum = data.presence === '进' ? 1 : 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++) {
let key = `
$
{
i
}
时
`;
let val = hourlyCustomerMap.get(key) ?? 0;
customerTrend.push({ time: `
$
{
i
}:
00
`, value: val });
}
}
// 最终组装返回数据
return {
// 运行监控总数据(一年)
mainRunningManagement: {
totalCustomerNumber: 10000,
totalDeviceOnlineRate: '99.8%',
totalElectricity: `
360
kwh
`,
},
// 能耗监控数据
energyManagement: {
todayElectricity: `
$
{
todayEnergy
.
toFixed
(
0
)}
kwh
`,
yesterdayElectricity: `
$
{
yesterdayEnergy
.
toFixed
(
0
)}
kwh
`,
dailyYearOnYear,
currentMonthElectricity: `
$
{
currentMonthEnergy
.
toFixed
(
0
)}
kwh
`,
previousMonthElectricity: `
$
{
previousMonthEnergy
.
toFixed
(
0
)}
kwh
`,
monthlyYearOnYear
},
// 能耗监控趋势图数据
electricityTrend: {
last24Hours: hourlyEnergy,
last7Days: dailyEnergy7,
last30Days: dailyEnergy30,
lastYear: monthlyEnergyYear
},
// 空调设备在线趋势图数据
acDeviceOnlineTrend: {
acCount: acDeviceIds.length,
acOnlineCount: acOnlineCount,
acOfflineCount: acOfflineCount,
acFaultCount: acFaultCount,
acOnlineTrend: acOnlineTrend
},
// 新风设备在线趋势图数据
fanDeviceOnlineTrend: {
fanCount: fanDeviceIds.length,
fanOnlineCount: fanOnlineCount,
fanOfflineCount: fanOfflineCount,
fanFaultCount: fanFaultCount,
fanOnlineTrend: fanOnlineTrend
},
// 环境监测趋势图数据
environmentalTrend: {
currentTemperature: currentTemperature,
currentHumidity: currentHumidity,
currentPm25: currentPm25,
currentCo2: currentCo2,
temperatureTrend: temperatureTrend,
humidityTrend: humidityTrend,
pm25Trend: pm25Trend,
co2Trend: co2Trend,
qualityIndex: qualityIndex
},
// 人流监控实时数据和趋势图数据
customerOnlineTrend: {
passengerFlowTable: regionCustomerTable,
customerTrend: customerTrend
}
}
console
.
log
(
"筛选区域Key:"
,
regionKey
);
}
// 辅助函数:获取用电趋势(按间隔分组)
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 },
received_time: { "%gte%": startTime.toISOString().slice(0,19).replace('T',' '), "%lte%": endTime.toISOString().slice(0,19).replace('T',' ') },
"%orderAsc%": "received_time"
}, ["device_id", "data", "received_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;
if (energy === undefined) continue;
let intervalKey: string;
let d = new Date(rec.received_time);
if (granularity === 'hour') {
intervalKey = `
$
{
d
.
getFullYear
()}
-
$
{
d
.
getMonth
()
+
1
}
-
$
{
d
.
getDate
()}
$
{
d
.
getHours
()}
时
`;
} else if (granularity === 'day') {
intervalKey = `
$
{
d
.
getFullYear
()}
/${d.getMonth
()
+1}/
$
{
d
.
getDate
()}
`;
} else {
intervalKey = `
$
{
d
.
getFullYear
()}
-
$
{
d
.
getMonth
()
+
1
}
`;
}
if (!intervalMap.has(intervalKey)) {
intervalMap.set(intervalKey, { deviceMin: new Map(), deviceMax: new Map() });
}
let entry = intervalMap.get(intervalKey);
if (!entry.deviceMin.has(rec.device_id)) {
entry.deviceMin.set(rec.device_id, energy);
entry.deviceMax.set(rec.device_id, energy);
} else {
let curMin = entry.deviceMin.get(rec.device_id);
let curMax = entry.deviceMax.get(rec.device_id);
if (energy < curMin) entry.deviceMin.set(rec.device_id, energy);
if (energy > curMax) entry.deviceMax.set(rec.device_id, energy);
}
}
let result = [];
for (let [key, { deviceMin, deviceMax }] of intervalMap.entries()) {
let total = 0;
for (let [deviceId, minVal] of deviceMin.entries()) {
let maxVal = deviceMax.get(deviceId);
total += (maxVal - minVal);
}
result.push({ key, value: total.toFixed(0) });
}
result.sort((a,b) => a.key.localeCompare(b.key));
return result;
}
/**
* 设备类型中文到英文Key的映射
*/
let deviceTypeKeyMap: { [key: string]: string } = {
// "灯光": "lighting",
// "窗帘": "curtain",
// "推窗器": "windowOpener",
"空调": "hvac",
"新风": "freshAir",
// "音乐": "music",
"人体传感": "occupancySensor",
"人体传感器": "occupancySensor",
"空气质量传感": "airSensor",
// "燃气表": "gasMeter",
// "水表": "waterMeter",
"三相电表": "electricityMeter",
"电表": "electricityMeter",
"电能监测": "electricityMeter"
};
/**
* 获取所有区域列表(供前端下拉选择)
* @returns 区域列表,按 sort_order 排序
...
...
@@ -163,7 +631,7 @@ export async function getRegionList() {
if (regionMap[r.type]) {
regionArr = regionMap[r.type];
}
regionArr
.
push
(
r
.
name
);
regionArr.push(
{regionKey: r.id, regionName: r.name}
);
regionMap[r.type] = regionArr;
});
console.log("区域列表:", regionMap);
...
...
src/config/mysqlTableConfig.ts
View file @
a11cbed3
...
...
@@ -23,6 +23,11 @@ export const TablesConfig = [
allowNull
:
false
,
comment
:
'所属楼栋'
},
max_capacity
:
{
type
:
DataTypes
.
NUMBER
(
10
,
2
),
allowNull
:
false
,
comment
:
'最大承载量'
},
sort_order
:
{
type
:
DataTypes
.
INTEGER
,
allowNull
:
false
,
...
...
src/routers/device.ts
View file @
a11cbed3
...
...
@@ -20,6 +20,9 @@ export function setRouter(httpServer) {
/** 运行分析 */
httpServer
.
post
(
'/api/zc/run/analysis'
,
asyncHandler
(
getRunAnalysis
));
httpServer
.
post
(
'/api/zc/run/analysis/building'
,
asyncHandler
(
getRunAnalysisByBuilding
));
httpServer
.
post
(
'/api/zc/run/analysis/Floor'
,
asyncHandler
(
getRunAnalysisByFloor
));
/**运行分析-弹窗 */
httpServer
.
post
(
'/api/zc/run/analysis/pop'
,
asyncHandler
(
getRunAnalysisPop
));
...
...
@@ -87,8 +90,8 @@ async function deviceFaultPush(req, res) {
async
function
getRunAnalysisByBuilding
(
req
,
res
)
{
let
reqConf
=
{
regionType
:
'String'
};
const
NotMustHaveKeys
=
[];
let
{
t
ype
}
=
eccReqParamater
(
reqConf
,
req
.
body
,
NotMustHaveKeys
);
const
result
=
await
regionBiz
.
getRunAnalysis
(
""
,
t
ype
);
let
{
regionT
ype
}
=
eccReqParamater
(
reqConf
,
req
.
body
,
NotMustHaveKeys
);
const
result
=
await
regionBiz
.
getRunAnalysis
(
""
,
regionT
ype
);
res
.
success
(
result
);
}
...
...
@@ -96,10 +99,10 @@ async function deviceFaultPush(req, res) {
* 运行分析-楼层
*/
async
function
getRunAnalysisByFloor
(
req
,
res
)
{
let
reqConf
=
{
region
Name
:
'String'
};
let
reqConf
=
{
region
Key
:
'String'
};
const
NotMustHaveKeys
=
[];
let
{
name
}
=
eccReqParamater
(
reqConf
,
req
.
body
,
NotMustHaveKeys
);
const
result
=
await
regionBiz
.
getRunAnalysis
(
name
,
""
);
let
{
regionKey
}
=
eccReqParamater
(
reqConf
,
req
.
body
,
NotMustHaveKeys
);
const
result
=
await
regionBiz
.
getRunAnalysis
(
regionKey
,
""
);
res
.
success
(
result
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment