数据集成和定时任务

parent 0d91348d
import {
getRegionTree,
getIndoorUnitList,
getElectricMaterList,
getIndoorUnitStateList,
getMaterStateList,
} from "./feiyiClient";
import { mysqlModelMap } from "../model/sqlModelBind";
// ==================== 分页拉取辅助函数 ====================
/**
* 分页拉取所有数据(通用)
* @param fetchFn 分页查询函数,入参 { page, limit },返回 { page, limit, total, rows }
* @param limit 每页条数,默认 100
*/
async function fetchAllPages(fetchFn: (page: number, limit: number) => Promise<any>, limit: number = 100): Promise<any[]> {
const allRows: any[] = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const result = await fetchFn(page, limit);
if (!result || !result.rows || result.rows.length === 0) {
hasMore = false;
break;
}
allRows.push(...result.rows);
// 判断是否还有下一页
if (page * limit >= result.total) {
hasMore = false;
} else {
page++;
}
}
return allRows;
}
// ==================== 区域集成 ====================
/**
* 递归遍历建筑物树,提取所有房间节点(buildingType === 3)
* 同时追溯父节点获取楼层和楼栋信息
*/
function extractRoomsFromTree(
tree: any[],
parentFloor: { floorId: string; floorName: string } | null = null,
parentBuilding: { buildingId: string; buildingName: string } | null = null,
): Array<{
roomId: string;
roomName: string;
floorId: string;
floorName: string;
buildingId: string;
buildingName: string;
}> {
const rooms: any[] = [];
for (const node of tree) {
const buildingType = node.buildingType;
const buildingId = node.buildingId;
const buildingName = node.buildingName;
const children = node.children || [];
if (buildingType === 1) {
// 楼栋节点
const building = { buildingId, buildingName };
rooms.push(...extractRoomsFromTree(children, null, building));
} else if (buildingType === 2) {
// 楼层节点
const floor = { floorId: buildingId, floorName: buildingName };
rooms.push(...extractRoomsFromTree(children, floor, parentBuilding));
} else if (buildingType === 3) {
// 房间节点
rooms.push({
roomId: buildingId,
roomName: buildingName,
floorId: parentFloor?.floorId || '',
floorName: parentFloor?.floorName || '',
buildingId: parentBuilding?.buildingId || '',
buildingName: parentBuilding?.buildingName || '',
});
}
}
return rooms;
}
/**
* 数据集成-区域集成
* 按最小节点(房间)平铺集成,一条数据对应一个房间
*/
export async function region() {
console.log('[区域集成] 开始执行...');
try {
const regionModel = mysqlModelMap['region'];
if (!regionModel) {
console.error('[区域集成] region 表模型未初始化,跳过');
return;
}
// 1. 获取建筑物树结构
const treeData = await getRegionTree();
if (!treeData || !Array.isArray(treeData)) {
console.warn('[区域集成] 未获取到建筑物树数据');
return;
}
// 2. 提取所有房间节点
const rooms = extractRoomsFromTree(treeData);
console.log(`[区域集成] 共提取到 ${rooms.length} 个房间节点`);
// 3. 逐房间检查并插入
let insertCount = 0;
let skipCount = 0;
for (const room of rooms) {
// 校验是否已存在(通过 room_id)
const existing = await regionModel.findOne({ where: { room_id: room.roomId } });
if (existing) {
skipCount++;
continue;
}
// 插入新区域记录
await regionModel.create({
room_id: room.roomId,
name: room.roomName,
floor_id: room.floorId,
type: room.floorName, // type 对应楼层名称
building_id: room.buildingId,
groups: room.buildingName, // groups 对应楼栋名称
sort_order: 0,
});
insertCount++;
}
console.log(`[区域集成] 完成,新增 ${insertCount} 条,跳过 ${skipCount} 条已存在`);
} catch (err) {
console.error('[区域集成] 执行异常:', err);
}
}
// ==================== 设备集成 ====================
/** 空调控制参数模板(按设备数据结构.md) */
const AC_CONTROL_PARAMS = {
power: ["on", "off"],
mode: ["制冷", "制热", "送风", "除湿"],
fanSpeed: ["自动", "低", "中", "高"],
setTemp: "16~30",
roomTemp: "-20~50",
maxTemp: "20~40",
minTemp: "-10~20",
autoControl: ["生效", "解除"],
};
/** 电表控制参数模板(按设备数据结构.md) */
const METER_CONTROL_PARAMS = {
current: "0~9999",
voltage: "0~500",
power: "0~99999",
energy: "0~999999",
switch: ["closed", "open"],
};
/**
* 数据集成-设备集成
* 包含:空调设备集成 + 电表设备集成
*/
export async function device() {
console.log('[设备集成] 开始执行...');
try {
await integrateAcDevices();
await integrateMeterDevices();
console.log('[设备集成] 完成');
} catch (err) {
console.error('[设备集成] 执行异常:', err);
}
}
/**
* 空调设备集成
* device_id = indoorUnitAddressFull
* device_ad = indoorUnitId
*/
async function integrateAcDevices() {
console.log('[空调设备集成] 开始...');
const deviceModel = mysqlModelMap['device'];
if (!deviceModel) {
console.error('[空调设备集成] device 表模型未初始化,跳过');
return;
}
// 分页拉取所有内机数据
const rows = await fetchAllPages((page, limit) => getIndoorUnitList({ page, limit }));
console.log(`[空调设备集成] 共获取 ${rows.length} 条内机数据`);
let insertCount = 0;
let skipCount = 0;
for (const item of rows) {
const deviceId = item.indoorUnitAddressFull; // device_id 用四段地址
if (!deviceId) {
skipCount++;
continue;
}
// 校验是否已存在
const existing = await deviceModel.findOne({ where: { device_id: deviceId } });
if (existing) {
skipCount++;
continue;
}
// 查找对应的 region_key
let regionKey = 0;
if (item.roomId) {
const regionModel = mysqlModelMap['region'];
if (regionModel) {
const region = await regionModel.findOne({ where: { room_id: item.roomId } });
if (region) {
regionKey = region.id;
}
}
}
// 插入新设备
await deviceModel.create({
device_id: deviceId,
device_ad: item.indoorUnitId || '',
region_key: regionKey,
device_type: '空调',
device_name: `空调内机-${deviceId}`,
control_params: AC_CONTROL_PARAMS,
});
insertCount++;
}
console.log(`[空调设备集成] 完成,新增 ${insertCount} 条,跳过 ${skipCount} 条已存在`);
}
/**
* 电表设备集成
* device_id = gatewayCode
* device_ad = meterId
*/
async function integrateMeterDevices() {
console.log('[电表设备集成] 开始...');
const deviceModel = mysqlModelMap['device'];
if (!deviceModel) {
console.error('[电表设备集成] device 表模型未初始化,跳过');
return;
}
// 分页拉取所有电表数据
const rows = await fetchAllPages((page, limit) => getElectricMaterList({ page, limit }));
console.log(`[电表设备集成] 共获取 ${rows.length} 条电表数据`);
let insertCount = 0;
let skipCount = 0;
for (const item of rows) {
const deviceId = item.gatewayCode; // device_id 用 gatewayCode
if (!deviceId) {
skipCount++;
continue;
}
// 校验是否已存在
const existing = await deviceModel.findOne({ where: { device_id: deviceId } });
if (existing) {
skipCount++;
continue;
}
// 插入新设备
await deviceModel.create({
device_id: deviceId,
device_ad: item.meterId || '',
region_key: 0, // 电表无房间关联
device_type: '电能监测',
device_name: `电表-${item.meterComId || item.meterId || ''}`,
control_params: METER_CONTROL_PARAMS,
});
insertCount++;
}
console.log(`[电表设备集成] 完成,新增 ${insertCount} 条,跳过 ${skipCount} 条已存在`);
}
// ==================== 设备数据集成 ====================
/** 工作模式映射:1=制冷 2=制热 3=送风 4=除湿 */
const WORK_MODE_MAP: Record<number, string> = {
1: '制冷',
2: '制热',
3: '送风',
4: '除湿',
};
/** 风速映射:1=高风 2=中风 4=低风 */
const FAN_SPEED_MAP: Record<number, string> = {
1: '高',
2: '中',
4: '低',
};
/**
* 数据集成-空调内机、电表设备数据集成
*/
export async function deviceData() {
console.log('[设备数据集成] 开始执行...');
try {
await integrateAcDeviceData();
await integrateMeterDeviceData();
console.log('[设备数据集成] 完成');
} catch (err) {
console.error('[设备数据集成] 执行异常:', err);
}
}
/**
* 空调设备数据集成(开关机记录)
* 用 indoorUnitAddressFull 匹配 device 表的 device_id
*/
async function integrateAcDeviceData() {
console.log('[空调设备数据集成] 开始...');
const deviceModel = mysqlModelMap['device'];
const deviceDataModel = mysqlModelMap['device_data'];
if (!deviceModel || !deviceDataModel) {
console.error('[空调设备数据集成] device 或 device_data 表模型未初始化,跳过');
return;
}
// 分页拉取所有内机开关机记录
const rows = await fetchAllPages((page, limit) => getIndoorUnitStateList({ page, limit }));
console.log(`[空调设备数据集成] 共获取 ${rows.length} 条开关机记录`);
let insertCount = 0;
let skipCount = 0;
for (const item of rows) {
const deviceId = item.indoorUnitAddressFull;
if (!deviceId) {
skipCount++;
continue;
}
// 查找对应设备
const device = await deviceModel.findOne({ where: { device_id: deviceId } });
if (!device) {
skipCount++;
continue;
}
// 构造数据(按设备数据结构.md 空调设备数据格式)
const data = {
power: item.onOff === 1 ? 'on' : 'off',
mode: WORK_MODE_MAP[item.workMode] || '未知',
fanSpeed: FAN_SPEED_MAP[item.fanSpeed] || '自动',
setTemp: item.tempSet || 0,
roomTemp: item.roomTemp || 0,
maxTemp: item.tempSetHi || 0,
minTemp: item.tempSetLo || 0,
autoControl: '生效',
};
await deviceDataModel.create({
device_id: deviceId,
data: data,
received_time: new Date(),
device_time: item.createTime ? new Date(item.createTime) : null,
});
insertCount++;
}
console.log(`[空调设备数据集成] 完成,新增 ${insertCount} 条,跳过 ${skipCount} 条`);
}
/**
* 电表设备数据集成(抄表记录)
* 用 gatewayCode 匹配 device 表的 device_id
*/
async function integrateMeterDeviceData() {
console.log('[电表设备数据集成] 开始...');
const deviceModel = mysqlModelMap['device'];
const deviceDataModel = mysqlModelMap['device_data'];
if (!deviceModel || !deviceDataModel) {
console.error('[电表设备数据集成] device 或 device_data 表模型未初始化,跳过');
return;
}
// 分页拉取所有抄表记录
const rows = await fetchAllPages((page, limit) => getMaterStateList({ page, limit }));
console.log(`[电表设备数据集成] 共获取 ${rows.length} 条抄表记录`);
let insertCount = 0;
let skipCount = 0;
for (const item of rows) {
const deviceId = item.gatewayCode;
if (!deviceId) {
skipCount++;
continue;
}
// 查找对应设备
const device = await deviceModel.findOne({ where: { device_id: deviceId } });
if (!device) {
skipCount++;
continue;
}
// 构造数据(按设备数据结构.md 电表设备数据格式)
const data = {
current: item.powerConsumptionAfterTransformationRatio || 0,
voltage: 0,
power: item.ammeterReadingAfterTransformationRatio || 0,
energy: item.ammeterReadingAfterTransformationRatio || 0,
switch: 'open',
};
await deviceDataModel.create({
device_id: deviceId,
data: data,
received_time: new Date(),
device_time: item.deviceTime ? new Date(item.deviceTime) : null,
});
insertCount++;
}
console.log(`[电表设备数据集成] 完成,新增 ${insertCount} 条,跳过 ${skipCount} 条`);
}
// ==================== 暂无对应接口的集成函数(保留空实现) ====================
/**
* 数据集成-九合一环境设备数据集成
*/
export async function airDeviceData() {
// TODO: 暂无对应接口
}
/**
* 数据集成-客流监测设备数据集成
*/
export async function customerDeviceData() {
// TODO: 暂无对应接口
}
/**
* 数据集成-预警工单数据集成
*/
export async function alertWorkData() {
// TODO: 暂无对应接口
}
...@@ -177,6 +177,37 @@ export async function getGatewayDeviceList(page: number = 1, limit: number = 10) ...@@ -177,6 +177,37 @@ export async function getGatewayDeviceList(page: number = 1, limit: number = 10)
/** /**
* 内机列表分页查询 * 内机列表分页查询
* @param params * @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> { export async function getIndoorUnitList(params: any): Promise<any> {
const path = '/openApi/indoorUnit/list'; const path = '/openApi/indoorUnit/list';
...@@ -200,4 +231,151 @@ export async function controlIndoorUnit(params: any): Promise<any> { ...@@ -200,4 +231,151 @@ export async function controlIndoorUnit(params: any): Promise<any> {
console.log('控制内机响应:', result); console.log('控制内机响应:', result);
let success = result.code === '00000'? true : false; let success = result.code === '00000'? true : false;
return { success, data: result.message }; 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;
}
...@@ -5,6 +5,7 @@ import { selectOneDataByParam, selectDataListByParam } from "../data/findData"; ...@@ -5,6 +5,7 @@ import { selectOneDataByParam, selectDataListByParam } from "../data/findData";
import { BizError } from "../util/bizError"; import { BizError } from "../util/bizError";
import { controlIndoorUnit } from "./feiyiClient"; import { controlIndoorUnit } from "./feiyiClient";
import { getRegionList } from "./region"; import { getRegionList } from "./region";
import { startSchedule, stopSchedule } from "../config/schedule";
/** /**
* 智能管控-运行分析 * 智能管控-运行分析
...@@ -200,6 +201,7 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -200,6 +201,7 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
{ count: 8, name: "安全事件", proportion: '18%' }]; { count: 8, name: "安全事件", proportion: '18%' }];
// 5.2. 预警监控数据 // 5.2. 预警监控数据
resultAny.alertManagement = { resultAny.alertManagement = {
alertStatus: alertStatus,
alertWorkLevel: alertWorkLevel, alertWorkLevel: alertWorkLevel,
alertWorkType: alertWorkType, alertWorkType: alertWorkType,
alertWorkOrders: alertWorkOrders alertWorkOrders: alertWorkOrders
...@@ -732,6 +734,21 @@ async function controlAcRunningApi(acDevices?: any, temperature?: number, worker ...@@ -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的映射 * 空调中文到Key的映射
* 1 制冷 2 制热 3 送风 4 除湿 * 1 制冷 2 制热 3 送风 4 除湿
* 0 关-off 1 开-on * 0 关-off 1 开-on
......
/**
* 定时任务调度器
* - 每分钟执行一次任务
* - 内置锁机制,防止任务重叠执行
* - 任务锁死时(超时未释放),会主动强制释放锁,确保后续任务能正常执行
*/
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('[定时任务] 定时器已停止');
}
}
...@@ -2,6 +2,7 @@ import { initConfig, systemConfig} from "./config/serverConfig"; ...@@ -2,6 +2,7 @@ import { initConfig, systemConfig} from "./config/serverConfig";
import * as mysqlDB from "./db/mysqlInit"; import * as mysqlDB from "./db/mysqlInit";
import { initMysqlModel } from "./model/sqlModelBind"; import { initMysqlModel } from "./model/sqlModelBind";
import { httpServer } from "./net/http_server"; import { httpServer } from "./net/http_server";
import { startSchedule } from "./config/schedule";
async function lanuch() { async function lanuch() {
...@@ -12,6 +13,8 @@ async function lanuch() { ...@@ -12,6 +13,8 @@ async function lanuch() {
await initMysqlModel(); await initMysqlModel();
/**创建http服务 */ /**创建http服务 */
httpServer.createServer(systemConfig.port); httpServer.createServer(systemConfig.port);
/**启动定时任务 */
startSchedule();
console.log('This indicates that the server is started successfully.'); console.log('This indicates that the server is started successfully.');
......
...@@ -33,6 +33,11 @@ export function setRouter(httpServer) { ...@@ -33,6 +33,11 @@ export function setRouter(httpServer) {
/** 空调开关 */ /** 空调开关 */
httpServer.post('/api/qdm/run/monitor/acRun', asyncHandler(controlAcRunning)); 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) { ...@@ -137,6 +142,21 @@ async function controlAcRunning(req, res) {
res.success(result); 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);
}
......
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