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
4114c762
Commit
4114c762
authored
Jun 09, 2026
by
PC-20251223ZVQQ\Administrator
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
数据集成和定时任务
parent
0d91348d
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
363 additions
and
2 deletions
+363
-2
dataIntegration.ts
src/biz/dataIntegration.ts
+0
-0
feiyiClient.ts
src/biz/feiyiClient.ts
+179
-2
running.ts
src/biz/running.ts
+17
-0
schedule.ts
src/config/schedule.ts
+144
-0
main.ts
src/main.ts
+3
-0
device.ts
src/routers/device.ts
+20
-0
No files found.
src/biz/dataIntegration.ts
0 → 100644
View file @
4114c762
This diff is collapsed.
Click to expand it.
src/biz/feiyiClient.ts
View file @
4114c762
...
...
@@ -177,6 +177,37 @@ export async function getGatewayDeviceList(page: number = 1, limit: number = 10)
/**
* 内机列表分页查询
* @param params
* @returns
{
"code": "00000", //状态码 00000 为正常 其他为异常
"message": "success", //返回状态 success 为成功, 其他为失败
"data": { // 返回数据
"page": 1, //当前页码
"limit": 0, //每页条数
"total": 579, //总数
"rows": [{
"indoorUnitId": "98566729709518848", //内机 ID
"roomId": "98452624688414720", //房间 ID
"floorId": "98452624680026112", //楼层 ID
"buildingId": "34390184208629760", //楼栋 ID
"indoorUnitAddressFull": "11-1-1-1", //内机四段地址
"onOffLock": 1, //是否开关锁定 1 锁定 0 未锁定
"onOff": 0, //开关状态 1 开 0 关
"workModeLock": 0, //是否工作模式锁定 1 锁定 0 未锁定
"workMode": 2, //工作模式 1 制冷 2 制热 3 送风 4 除湿
"tempSetLock": 0, //是否温度锁定 1 锁定 0 未锁定
"tempSet": 16.0, // 设定温度
"tempSetLo": 16.0, // 锁定下限温度
"tempSetHi": 32.0, // 锁定下限温度
"fanSpeed": 4, // 风速 1 高风 2 中风 4 低风
"hasTimingTasks": 0, //是否有定时任务
"alarmCode": "LOST", //空调故障码
"roomTemp": 27 //室内温度(实际为空调回风温度,有一定的误差仅做参考)
"lockedSwitch": 0, // 锁定的开关:0 关 1 开
"lockedMode": 0, // 锁定模式 1 制冷 2 制热 3 送风 4 除湿 10 制热/送风 11 制冷/送风 12 制冷/除湿 13 制冷/除湿/送风 14 除湿/送风
}]
}
}
*/
export
async
function
getIndoorUnitList
(
params
:
any
):
Promise
<
any
>
{
const
path
=
'/openApi/indoorUnit/list'
;
...
...
@@ -200,4 +231,151 @@ export async function controlIndoorUnit(params: any): Promise<any> {
console
.
log
(
'控制内机响应:'
,
result
);
let
success
=
result
.
code
===
'00000'
?
true
:
false
;
return
{
success
,
data
:
result
.
message
};
}
\ No newline at end of file
}
/**
* 建筑物树结构查询
* @param params
* @returns
{
"code": "00000", //状态码 00000 为正常,其他为异常
"message": "success", //状态信息 success 为成功,其他为异常
"data": [{
"buildingId": "97474765970866176", //建筑物 ID
"parentId": "0", //建筑物父 ID
"buildingName": "飞奕 1", // 建筑物名称
"buildingType": 1, //建筑物类型 1 楼栋 2 楼层 3 房间
"children": [ //子建筑物
{
"buildingId": "97474766339964928",
"parentId": "97474765970866176",
"buildingName": "1 层",
"buildingType": 2,
"children": [{
"buildingId": "97474766696480768",
"parentId": "97474766339964928",
"buildingName": "1-0",
"buildingType": 3,
"children": []
}]
}
]
}],
"timestamp": 1714290880301
}
*/
export
async
function
getRegionTree
():
Promise
<
any
>
{
const
path
=
'/openApi/building/tree'
;
const
body
=
{
};
const
result
=
await
feiYiPost
(
path
,
body
);
return
result
.
data
;
}
/**
* 电表分页查询
* @param params
* @returns
{
"code": "00000", //状态码 00000 为成功,其他为失败
"message": "success", //提示信息 success 为成功 其他为失败
"data": {
"page": 0, //当前页码
"limit": 0, //每页条数
"total": 6, //总条数
"rows": [{
"meterId": "110510431701041152", //电表 ID
"gatewayComId": , //电表网关设备通信 ID
"gatewayCode": , //电表网关设备编码
"protocolType": "DLT645-2007", //电表协议类型
"ammeterReadingAfterTransformationRatio": 6547.68, //电表变比后读数
"transformationRatio": 80.0, //电表变比
"meterComId": "210505015447" //电表地址
}, {
"gatewayComId": , //电表网关设备通信 ID
"gatewayCode": , //电表网关设备编码
"meterId": "110510346153885697",
"transformationRatio": 50.0,
"meterComId": "210505015560"
}]
},
"timestamp": 1713245734235
}
*/
export
async
function
getElectricMaterList
(
params
:
any
):
Promise
<
any
>
{
const
path
=
'/openApi/electricMeter/getAll'
;
const
body
=
{
...
params
};
const
result
=
await
feiYiPost
(
path
,
body
);
return
result
.
data
;
}
/**
* 抄表记录查询
* @param params
* @returns
{
"code": "00000", //状态码 00000 表示成功,其他为失败
"message": "success", //提示信息 success 为成功,其他为失败
"data": {
"page": 1, //当前页码
"limit": 0, //每页条数
"total": 6, //总条数
"rows": [{
"electricMeterStateId": "112111594590437376", //抄表记录 ID
"gatewayId": "97477557167063040", //主机设备 ID
"gatewayCode": "fa000001400001240231212000200026" //主机设备编码
"meterComId": "210505015595", //电表地址
"gatewayComId": 11, // 电表网关通信 ID
"transformationRatio": 100.0, //电表变比
"powerConsumptionAfterTransformationRatio": 0.08, //电表变比后用电量
"ammeterReadingAfterTransformationRatio": 19167.4, // 电表变比后读数
"ammeterReadingBeforeTransformationRatio": 191.67, //电表变比前读数
"energyLoss": 0.00, //损耗电量
"deviceTime": 1706371200000, //设备时间
}]
},
"timestamp": 1713145563759
}
*/
export
async
function
getMaterStateList
(
params
:
any
):
Promise
<
any
>
{
const
path
=
'/openApi/electricMeterState/list'
;
const
body
=
{
...
params
};
const
result
=
await
feiYiPost
(
path
,
body
);
return
result
.
data
;
}
/**
* 内机开关机记录查询
* @param params
* @returns
{
"code": "00000",
"message": "success",
"path": null,
"data": {
"page": 1,
"limit": 0,
"total": 278,
"rows": [{
"indoorUnitEventId": "140718238987321344", //内机事件 ID
"indoorUnitId": "97478680942739586", //内机 ID
"gatewayComId": 1, //主机通信 ID
"roomId": "97474774841819136", //内机所在房间 ID
"floorId": "97474774485303296", //内机所在楼层 ID
"buildingId": "97474765970866176", //内机所在楼栋 ID
"indoorUnitAddressFull": "1-8-128-16", //内机四段地址
"onOff": 0, //内机开关标志 0 关 1 开
"workMode": 4, //工作模式 1 制冷 2 制热 3 送风 4 除湿
"tempSet": 18.0, //内机温度设置
"fanSpeed": 2, //内机风速 风速 1 高风 2 中风 4 低风
"createTime": 1713173801018 //事件发生时间
}]
},
"timestamp": 1713173831195
}
*/
export
async
function
getIndoorUnitStateList
(
params
:
any
):
Promise
<
any
>
{
const
path
=
'/openApi/indoorUnit/event/switch'
;
const
body
=
{
...
params
};
const
result
=
await
feiYiPost
(
path
,
body
);
return
result
.
data
;
}
src/biz/running.ts
View file @
4114c762
...
...
@@ -5,6 +5,7 @@ import { selectOneDataByParam, selectDataListByParam } from "../data/findData";
import
{
BizError
}
from
"../util/bizError"
;
import
{
controlIndoorUnit
}
from
"./feiyiClient"
;
import
{
getRegionList
}
from
"./region"
;
import
{
startSchedule
,
stopSchedule
}
from
"../config/schedule"
;
/**
* 智能管控-运行分析
...
...
@@ -200,6 +201,7 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
{ count: 8, name: "安全事件", proportion: '18%' }];
// 5.2. 预警监控数据
resultAny.alertManagement = {
alertStatus: alertStatus,
alertWorkLevel: alertWorkLevel,
alertWorkType: alertWorkType,
alertWorkOrders: alertWorkOrders
...
...
@@ -732,6 +734,21 @@ async function controlAcRunningApi(acDevices?: any, temperature?: number, worker
}
/**
* 数据集成 - 启动定时任务
*/
export async function startScheduleTask() {
await startSchedule();
return { success: true };
}
/**
* 数据集成 - 停止定时任务
*/
export async function stopScheduleTask() {
await stopSchedule();
return { success: true };
}
/**
* 空调中文到Key的映射
* 1 制冷 2 制热 3 送风 4 除湿
* 0 关-off 1 开-on
...
...
src/config/schedule.ts
0 → 100644
View file @
4114c762
/**
* 定时任务调度器
* - 每分钟执行一次任务
* - 内置锁机制,防止任务重叠执行
* - 任务锁死时(超时未释放),会主动强制释放锁,确保后续任务能正常执行
*/
import
{
dataintegration
}
from
"tencentcloud-sdk-nodejs"
;
import
{
region
,
device
,
deviceData
}
from
"../biz/dataIntegration"
;
// 锁超时时间(毫秒),任务执行超过此时间视为锁死
const
LOCK_TIMEOUT_MS
=
55
*
1000
;
// 55秒,留5秒余量给下一次执行
// 定时器执行间隔(毫秒)
const
TASK_INTERVAL_MS
=
60
*
1000
;
// 1分钟
interface
TaskLock
{
locked
:
boolean
;
lockTime
:
number
;
// 加锁时的时间戳
lockKey
:
string
;
// 锁标识,用于追踪
}
const
taskLock
:
TaskLock
=
{
locked
:
false
,
lockTime
:
0
,
lockKey
:
''
,
};
/**
* 尝试获取任务锁
* @returns 是否成功获取锁
*/
function
tryAcquireLock
():
boolean
{
if
(
taskLock
.
locked
)
{
const
elapsed
=
Date
.
now
()
-
taskLock
.
lockTime
;
if
(
elapsed
>
LOCK_TIMEOUT_MS
)
{
// 锁已超时,强制释放
console
.
warn
(
`[定时任务] 检测到锁死,强制释放锁。已锁定
${
elapsed
}
ms,锁标识:
${
taskLock
.
lockKey
}
`
);
releaseLock
();
return
tryAcquireLock
();
}
// 上一次任务还在执行中,跳过本次
console
.
log
(
`[定时任务] 上一次任务尚未完成,跳过本次执行。已锁定
${
elapsed
}
ms`
);
return
false
;
}
taskLock
.
locked
=
true
;
taskLock
.
lockTime
=
Date
.
now
();
taskLock
.
lockKey
=
`
${
Date
.
now
()}
_
${
Math
.
random
().
toString
(
36
).
substring
(
2
,
8
)}
`
;
return
true
;
}
/**
* 释放任务锁
*/
function
releaseLock
():
void
{
taskLock
.
locked
=
false
;
taskLock
.
lockTime
=
0
;
taskLock
.
lockKey
=
''
;
}
/**
* 获取当前锁状态(供外部查询)
*/
export
function
getLockStatus
():
{
locked
:
boolean
;
lockDuration
:
number
;
lockKey
:
string
}
{
return
{
locked
:
taskLock
.
locked
,
lockDuration
:
taskLock
.
locked
?
Date
.
now
()
-
taskLock
.
lockTime
:
0
,
lockKey
:
taskLock
.
lockKey
,
};
}
/**
* 主动强制释放锁(供外部调用,用于紧急情况手动释放)
*/
export
function
forceReleaseLock
():
void
{
if
(
taskLock
.
locked
)
{
const
elapsed
=
Date
.
now
()
-
taskLock
.
lockTime
;
console
.
warn
(
`[定时任务] 外部主动强制释放锁。已锁定
${
elapsed
}
ms,锁标识:
${
taskLock
.
lockKey
}
`
);
releaseLock
();
}
}
/**
* 定时任务的具体业务逻辑
* 在这里编写需要定时执行的任务代码
*/
async
function
scheduledTask
():
Promise
<
void
>
{
// 尝试获取锁,未获取到则跳过
if
(
!
tryAcquireLock
())
{
return
;
}
try
{
// ====== 在此处编写定时任务的具体逻辑 ======
console
.
log
(
`[定时任务] 开始执行 -
${
new
Date
().
toLocaleString
()}
`
);
// TODO: 替换为实际的业务逻辑
// 例如:数据备份、缓存清理、定时同步等
await
region
();
await
device
();
await
deviceData
();
console
.
log
(
`[定时任务] 执行完成 -
${
new
Date
().
toLocaleString
()}
`
);
// =========================================
}
catch
(
err
)
{
console
.
error
(
'[定时任务] 执行异常:'
,
err
);
}
finally
{
// 无论任务成功或失败,都要释放锁
releaseLock
();
}
}
// 定时器句柄
let
timerHandle
:
NodeJS
.
Timeout
|
null
=
null
;
/**
* 启动定时任务
* 在项目启动时调用
*/
export
function
startSchedule
():
void
{
if
(
timerHandle
)
{
console
.
warn
(
'[定时任务] 定时器已在运行中,无需重复启动'
);
return
;
}
console
.
log
(
`[定时任务] 定时器已启动,间隔
${
TASK_INTERVAL_MS
/
1000
}
秒`
);
// 使用 setInterval 实现每分钟执行一次
timerHandle
=
setInterval
(()
=>
{
scheduledTask
();
},
TASK_INTERVAL_MS
);
}
/**
* 停止定时任务
*/
export
function
stopSchedule
():
void
{
if
(
timerHandle
)
{
clearInterval
(
timerHandle
);
timerHandle
=
null
;
console
.
log
(
'[定时任务] 定时器已停止'
);
}
}
src/main.ts
View file @
4114c762
...
...
@@ -2,6 +2,7 @@ import { initConfig, systemConfig} from "./config/serverConfig";
import
*
as
mysqlDB
from
"./db/mysqlInit"
;
import
{
initMysqlModel
}
from
"./model/sqlModelBind"
;
import
{
httpServer
}
from
"./net/http_server"
;
import
{
startSchedule
}
from
"./config/schedule"
;
async
function
lanuch
()
{
...
...
@@ -12,6 +13,8 @@ async function lanuch() {
await
initMysqlModel
();
/**创建http服务 */
httpServer
.
createServer
(
systemConfig
.
port
);
/**启动定时任务 */
startSchedule
();
console
.
log
(
'This indicates that the server is started successfully.'
);
...
...
src/routers/device.ts
View file @
4114c762
...
...
@@ -33,6 +33,11 @@ export function setRouter(httpServer) {
/** 空调开关 */
httpServer
.
post
(
'/api/qdm/run/monitor/acRun'
,
asyncHandler
(
controlAcRunning
));
/** 启动数据集成 */
httpServer
.
post
(
'/api/qdm/run/start/schedule'
,
asyncHandler
(
startSchedule
));
/** 停止数据集成 */
httpServer
.
post
(
'/api/qdm/run/stop/schedule'
,
asyncHandler
(
stopSchedule
));
}
/**
...
...
@@ -137,6 +142,21 @@ async function controlAcRunning(req, res) {
res
.
success
(
result
);
}
/**
* 启动定时任务
*/
async
function
startSchedule
(
req
,
res
)
{
const
result
=
await
runningBiz
.
startScheduleTask
();
res
.
success
(
result
);
}
/**
* 停止定时任务
*/
async
function
stopSchedule
(
req
,
res
)
{
const
result
=
await
runningBiz
.
stopScheduleTask
();
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