日程管理接口

parent 18e87f61
...@@ -96,7 +96,11 @@ export async function processDeviceData(message) { ...@@ -96,7 +96,11 @@ export async function processDeviceData(message) {
["name"] ["name"]
); );
// 调用空调控制(非文创区域才允许自动控温) // 调用空调控制(非文创区域才允许自动控温)
if (regionRow?.data && !regionRow.data.name?.includes("文创")) { if (regionRow?.data && !regionRow.data.name?.includes("文创")
&& !regionRow.data.name?.includes("原料厅")
&& !regionRow.data.name?.includes("社会责任厅")
&& !regionRow.data.name?.includes("新包装")
) {
await controlAcByEnvironment(devEUI, data); await controlAcByEnvironment(devEUI, data);
} }
} }
......
...@@ -70,3 +70,76 @@ export async function getRegionAllList( regionGroup: string ) { ...@@ -70,3 +70,76 @@ export async function getRegionAllList( regionGroup: string ) {
list: regionMap list: regionMap
}; };
} }
/**
* 获取区域设备树
* @returns 区域树
*/
export async function getRegionDevices() {
// 查询所有区域
let where: any = { "%orderAsc%": "sort_order" };
let regionList = await selectDataListByParam(
TABLENAME.区域表,
where,
["id", "room_id", "name", "type", "groups"],
);
const regions: any[] = regionList.data || [];
if (regions.length === 0) return [];
// 通过区域查询所有空调设备
const regionIds = regions.map((r: any) => r.id);
const deviceList = await selectDataListByParam(
TABLENAME.设备表,
{ region_key: { "%in%": regionIds }, device_type: "空调" },
["device_id", "device_name", "region_key", "control_params"],
);
const devices: any[] = deviceList.data || [];
// 将设备列表转成map形式:{regionKey:[{设备1},{设备2}]}
const deviceMap: { [regionKey: number]: any[] } = {};
for (const d of devices) {
const rk = d.region_key;
if (!deviceMap[rk]) deviceMap[rk] = [];
deviceMap[rk].push({
deviceId: d.device_id,
deviceName: d.device_name || d.device_id,
controlParams: d.control_params || null,
});
}
// 循环区域,将区域转成树结构,并通过设备map将设备加入区域
const groupMap: { [group: string]: { key: string; value: string; typeMap: { [type: string]: { key: string; value: string; sub: any[] } } } } = {};
for (const r of regions) {
const groupName = r.groups;
const typeName = r.type;
if (!groupMap[groupName]) {
groupMap[groupName] = { key: groupName, value: groupName, typeMap: {} };
}
if (!groupMap[groupName].typeMap[typeName]) {
groupMap[groupName].typeMap[typeName] = { key: typeName, value: typeName, sub: [] };
}
groupMap[groupName].typeMap[typeName].sub.push({
regionKey: r.id,
roomId: r.room_id,
regionName: r.name,
devices: deviceMap[r.id] || [],
});
}
// 返回区域树
const result: any[] = [];
const sortedGroups = Object.keys(groupMap).sort();
for (const groupName of sortedGroups) {
const group = groupMap[groupName];
const typeArr: any[] = [];
const sortedTypes = Object.keys(group.typeMap).sort();
for (const typeName of sortedTypes) {
typeArr.push(group.typeMap[typeName]);
}
result.push({ key: group.key, value: group.value, sub: typeArr });
}
return result;
}
\ No newline at end of file
/** /**
* 周报告模块 * 周报告模块
* - 查询上周各馆(A/B/C馆)的设备监测数据 * - 查询最近七天各馆(A/B/C馆)的设备监测数据
* - 提供周报告 JSON 数据接口 * - 提供周报告 JSON 数据接口
*/ */
...@@ -47,20 +47,18 @@ function formatDateStr(date: Date): string { ...@@ -47,20 +47,18 @@ function formatDateStr(date: Date): string {
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`; return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
} }
/** 计算指定周的起止时间(周一~周日) */ /** 计算最近七天的起止时间(今天往前推6天) */
function calcWeekRange(weekOffset: number = 0): { start: Date; end: Date; timer: string } { function calcWeekRange(weekOffset: number = 0): { start: Date; end: Date; timer: string } {
const now = new Date(); const now = new Date();
const dayOfWeek = now.getDay(); const end = new Date(now);
const daysToMonday = dayOfWeek === 0 ? 8 : dayOfWeek + 6; // 回溯到上周一 end.setDate(now.getDate() + weekOffset * 7);
const monday = new Date(now); end.setHours(23, 59, 59, 999);
monday.setDate(now.getDate() - daysToMonday + weekOffset * 7); const start = new Date(now);
monday.setHours(0, 0, 0, 0); start.setDate(now.getDate() - 6 + weekOffset * 7);
const sunday = new Date(monday); start.setHours(0, 0, 0, 0);
sunday.setDate(monday.getDate() + 6);
sunday.setHours(23, 59, 59, 999); const timer = `${formatChineseDate(start)}${formatChineseDate(end)}`;
return { start, end, timer };
const timer = `${formatChineseDate(monday)}${formatChineseDate(sunday)}`;
return { start: monday, end: sunday, timer };
} }
/** 格式化数字,不足时返回 "——" */ /** 格式化数字,不足时返回 "——" */
...@@ -217,8 +215,8 @@ function calcMeterDeviceDaily(records: any[]): number { ...@@ -217,8 +215,8 @@ function calcMeterDeviceDaily(records: any[]): number {
} }
/** /**
* 查询周报告 JSON 数据 * 查询周报告 JSON 数据(最近七天)
* @param weekOffset 0=上周(默认), -1=前一周, ... * @param weekOffset 0=最近七天(默认), -1=再往前七天, ...
*/ */
export async function getWeeklyReportData(weekOffset: number = 0): Promise<any> { export async function getWeeklyReportData(weekOffset: number = 0): Promise<any> {
const { start: monday, end: sunday, timer } = calcWeekRange(weekOffset); const { start: monday, end: sunday, timer } = calcWeekRange(weekOffset);
...@@ -374,3 +372,189 @@ export async function getWeeklyReportData(weekOffset: number = 0): Promise<any> ...@@ -374,3 +372,189 @@ export async function getWeeklyReportData(weekOffset: number = 0): Promise<any>
return { timer, dataTotal, runDatas }; return { timer, dataTotal, runDatas };
} }
// ======================= 九合一环境监测指标 7 天均值 =======================
/** 九合一核心指标(去掉 pir 人体感应 和 o3 臭氧) */
const ENV_INDICATOR_KEYS = [
{ key: "co2", name: "二氧化碳", unit: "ppm" },
{ key: "pm10", name: "PM10", unit: "μg/m³" },
{ key: "pm2_5", name: "PM2.5", unit: "μg/m³" },
{ key: "hcho", name: "甲醛", unit: "mg/m³" },
{ key: "tvoc", name: "TVOC", unit: "mg/m³" },
{ key: "temperature", name: "温度", unit: "℃" },
{ key: "humidity", name: "湿度", unit: "%" },
{ key: "pressure", name: "气压", unit: "hPa" },
{ key: "light_level", name: "光照度", unit: "lux" },
];
/**
* 查询九合一环境监测指标的 7 天均值(A馆 / B馆 / C馆)
* 对每个馆的环境监测设备,取近 7 天所有上报数据的算术平均
*/
export async function getEnvIndicatorsWeeklyAvg(): Promise<any> {
// 1. 计算七天时间范围
const now = new Date();
const end = new Date(now);
end.setHours(23, 59, 59, 999);
const start = new Date(now);
start.setDate(now.getDate() - 6);
start.setHours(0, 0, 0, 0);
const from = formatLocalTime(start);
const to = formatLocalTime(end);
const timer = `${formatChineseDate(start)}${formatChineseDate(end)}`;
console.log(`[九合一七日均值] 查询范围: ${timer}`);
// 2. 并行查询三馆区域
const hallRegionMap = await queryHallRegions();
// 3. 并行查询三馆的环境监测设备
const hallDeviceGroups = await Promise.all(
HALL_NAMES.map(h => queryHallDeviceGroup(hallRegionMap.get(h) || []))
);
// 4. 并行查询三馆近 7 天的设备数据
const hallResults = await Promise.all(
hallDeviceGroups.map(async (group) => {
const envDeviceIds = group.envDevices.map(d => d.device_id);
if (envDeviceIds.length === 0) return null;
const dayDataRes = await selectDataListByParam(TABLENAME.设备数据表, {
device_id: { "%in%": envDeviceIds },
device_time: { "%gte%": from, "%lte%": to },
}, ["device_id", "data"]);
return dayDataRes.data || [];
})
);
// 5. 计算每个馆的各指标均值
const result: any = { timer };
for (let idx = 0; idx < HALL_NAMES.length; idx++) {
const hallName = HALL_NAMES[idx];
const records = hallResults[idx];
const indicators: any = {};
if (!records || records.length === 0) {
// 无数据填 null
for (const ik of ENV_INDICATOR_KEYS) {
indicators[ik.key] = { name: ik.name, value: null, unit: ik.unit };
}
} else {
// 统计各指标累加值和计数
const sums: { [key: string]: number } = {};
const counts: { [key: string]: number } = {};
for (const ik of ENV_INDICATOR_KEYS) {
sums[ik.key] = 0;
counts[ik.key] = 0;
}
for (const rec of records) {
const d = rec.data || {};
for (const ik of ENV_INDICATOR_KEYS) {
const v = d[ik.key];
if (v !== undefined && v !== null && typeof v === "number") {
sums[ik.key] += v;
counts[ik.key]++;
}
}
}
for (const ik of ENV_INDICATOR_KEYS) {
const avg = counts[ik.key] > 0
? Math.round((sums[ik.key] / counts[ik.key]) * 100) / 100
: null;
indicators[ik.key] = { name: ik.name, value: avg, unit: ik.unit };
}
}
result[hallName] = { deviceCount: hallDeviceGroups[idx].envDevices.length, recordCount: records?.length || 0, indicators };
}
console.log(`[九合一七日均值] 完成`);
return result;
}
// ======================= 近 7 天故障信息(按 fault_code 分组) =======================
const STATUS_MAP: { [key: number]: string } = { 0: "未处理", 1: "处理中", 2: "已解决" };
const LEVEL_MAP: { [key: number]: string } = { 1: "一级", 2: "二级", 3: "三级" };
/**
* 查询近 7 天故障信息,按 fault_code 分组
* 每组展示:故障代码、风险内容、报警时间、处理状态、报警设备
*/
export async function getFaultInfoLast7Days(): Promise<any> {
const now = new Date();
const end = new Date(now);
end.setHours(23, 59, 59, 999);
const start = new Date(now);
start.setDate(now.getDate() - 6);
start.setHours(0, 0, 0, 0);
const from = formatLocalTime(start);
const to = formatLocalTime(end);
const timer = `${formatChineseDate(start)}${formatChineseDate(end)}`;
console.log(`[近7天故障] 查询范围: ${timer}`);
// 1. 查询近 7 天故障记录(按发生时间倒序)
const faultRes = await selectDataListByParam(TABLENAME.设备故障表, {
occurred_time: { "%gte%": from, "%lte%": to },
"%orderDesc%": "occurred_time",
});
const faultRecords = faultRes.data || [];
if (faultRecords.length === 0) {
return { timer, totalCount: 0, groups: [] };
}
// 2. 收集所有 device_id,查询设备名称
const deviceIds = [...new Set(faultRecords.map((f: any) => f.device_id).filter(Boolean))];
let deviceNameMap: Map<string, string> = new Map();
if (deviceIds.length > 0) {
const devRes = await selectDataListByParam(TABLENAME.设备表, {
device_id: { "%in%": deviceIds },
}, ["device_id", "device_name"]);
for (const d of (devRes.data || [])) {
deviceNameMap.set(d.device_id, d.device_name || d.device_id);
}
}
// 3. 按 fault_code 分组
const groupMap: { [code: string]: any[] } = {};
for (const f of faultRecords) {
const code = f.fault_code || "未分类";
if (!groupMap[code]) groupMap[code] = [];
groupMap[code].push({
id: f.id,
faultType: f.fault_type || "",
faultCode: code,
faultDesc: f.fault_description || "",
alarmTime: f.occurred_time
? (typeof f.occurred_time === "string" ? f.occurred_time : formatLocalTime(new Date(f.occurred_time)))
: "",
status: f.status ?? 0,
statusText: STATUS_MAP[f.status] ?? "未知",
level: f.level ?? 0,
levelText: LEVEL_MAP[f.level] ?? "未知",
deviceId: f.device_id,
deviceName: deviceNameMap.get(f.device_id) || f.device_id || "",
});
}
// 4. 构建分组结果
const groups = Object.entries(groupMap)
.sort((a, b) => b[1].length - a[1].length) // 按故障数量降序
.map(([code, items]) => ({
faultCode: code,
count: items.length,
items,
}));
const totalCount = faultRecords.length;
console.log(`[近7天故障] 共 ${totalCount} 条,${groupMap.size} 种故障码`);
return { timer, totalCount, groupCount: Object.keys(groupMap).length, groups };
}
...@@ -606,11 +606,13 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -606,11 +606,13 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
for (let devId of acDeviceIds) { for (let devId of acDeviceIds) {
let rec = await selectDataListByParam(TABLENAME.设备数据表, let rec = await selectDataListByParam(TABLENAME.设备数据表,
{ device_id: devId, "%orderDesc%": "device_time", "%limit%": 1 }, { device_id: devId, "%orderDesc%": "device_time", "%limit%": 1 },
["device_time"]); ["device_time", "data"]);
if (rec.data.length) { if (rec.data.length) {
let lastTime = new Date(rec.data[0].device_time); let lastTime = new Date(rec.data[0].device_time);
let lastData = rec.data[0].data;
let power = lastData.power ?? '';
let diffMinutes = (nowTime.getTime() - lastTime.getTime()) / 60000; let diffMinutes = (nowTime.getTime() - lastTime.getTime()) / 60000;
deviceLatestMap.set(devId, { lastTime, isOnline: diffMinutes <= 30 }); deviceLatestMap.set(devId, { lastTime, isOnline: power==='on' });
} else { } else {
deviceLatestMap.set(devId, { lastTime: null, isOnline: false }); deviceLatestMap.set(devId, { lastTime: null, isOnline: false });
} }
...@@ -710,11 +712,13 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -710,11 +712,13 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
for (let devId of deviceIds) { for (let devId of deviceIds) {
let rec = await selectDataListByParam(TABLENAME.设备数据表, let rec = await selectDataListByParam(TABLENAME.设备数据表,
{ device_id: devId, "%orderDesc%": "device_time", "%limit%": 1 }, { device_id: devId, "%orderDesc%": "device_time", "%limit%": 1 },
["device_time"]); ["device_time", "data"]);
if (rec.data.length) { if (rec.data.length) {
let lastTime = new Date(rec.data[0].device_time); let lastTime = new Date(rec.data[0].device_time);
let lastData = rec.data[0].data;
let power = lastData.power ?? '';
let diffMinutes = (nowTime.getTime() - lastTime.getTime()) / 60000; let diffMinutes = (nowTime.getTime() - lastTime.getTime()) / 60000;
deviceLatestMap.set(devId, { lastTime, isOnline: diffMinutes <= 30 }); deviceLatestMap.set(devId, { lastTime, isOnline: power === 'on' });
} else { } else {
deviceLatestMap.set(devId, { lastTime: null, isOnline: false }); deviceLatestMap.set(devId, { lastTime: null, isOnline: false });
} }
...@@ -1135,8 +1139,21 @@ async function controlAcRunningApi(acDevices?: any, workMode?: number, tempSet?: ...@@ -1135,8 +1139,21 @@ async function controlAcRunningApi(acDevices?: any, workMode?: number, tempSet?:
return controlResults; return controlResults;
} }
/**
* 设置开关机
* @param regionGroup
* @param regionFloor
* @param regionKey
* @param deviceId
* @param powerStatus
*/
export async function scheduledPowerOn(regionGroup:string, regionType:string, regionKey:number, deviceId:string, powerStatus:number) {
// 根据regionGroup\regionType\regionKey查询区域信息
// 根据deviceId查询空调设备
// 无传参时,查询region表,通过region表查询device表中device_type=空调的数据
// 循环查询的空调设备,组装空调控制需要参数
// 调用空调控制的第三方接口并记录device_log日志表
}
/** /**
* 数据集成 - 启动定时任务 * 数据集成 - 启动定时任务
......
...@@ -8,7 +8,9 @@ export enum TABLENAME { ...@@ -8,7 +8,9 @@ export enum TABLENAME {
区域表 = 'region', 区域表 = 'region',
设备故障表 = 'device_fault', 设备故障表 = 'device_fault',
用户信息表 = 'user_info', 用户信息表 = 'user_info',
设备日志表 = 'device_logs' 设备日志表 = 'device_logs',
日程表 = 'schedule',
日程设备关联表 = 'schedule_device'
}; };
/** /**
......
...@@ -337,5 +337,118 @@ export const TablesConfig = [ ...@@ -337,5 +337,118 @@ export const TablesConfig = [
association: [ association: [
] ]
}, },
// 日程表
{
tableNameCn: '日程表',
tableName: 'schedule',
schema: {
id: {
type: DataTypes.BIGINT,
allowNull: false,
primaryKey: true,
autoIncrement: true,
comment: '自增主键'
},
title: {
type: Sequelize.STRING(255),
allowNull: false,
comment: '日程标题'
},
schedule_date: {
type: DataTypes.DATE,
allowNull: false,
comment: '日期'
},
ac_controls: {
type: Sequelize.STRING(50),
allowNull: false,
comment: '操作状态:off关on开'
},
todo_item: {
type: DataTypes.JSON,
allowNull: true,
comment: '待办事项,除了开关以外可以设定模式、温度等。例:{"温度":"24.5","模式":"制冷","风速":"低风"}'
},
schedule_time: {
type: Sequelize.STRING(50),
allowNull: true,
comment: '定时时间,如08:30:00'
},
set_conditions: {
type: DataTypes.JSON,
allowNull: true,
comment: '设定条件,除了定时以外可以通过条件开启或关闭设备。例:{"温度":"≤26&≥22"}'
},
begin_validity: {
type: DataTypes.DATE,
allowNull: true,
comment: '有效时间起,不设置则为空'
},
end_validity: {
type: DataTypes.DATE,
allowNull: true,
comment: '有效时间止,不设置则为空'
},
outward_time: {
type: Sequelize.STRING(200),
allowNull: true,
comment: '有效除外时间,多个通过逗号分隔'
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
comment: '创建时间'
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
comment: '修改时间'
}
},
association: [
{ type: "hasMany", target: "schedule_device", foreignKey: "schedule_id" }
]
},
// 日程设备关联表
{
tableNameCn: '日程设备关联表',
tableName: 'schedule_device',
schema: {
id: {
type: DataTypes.BIGINT,
allowNull: false,
primaryKey: true,
autoIncrement: true,
comment: '自增主键'
},
schedule_id: {
type: DataTypes.BIGINT,
allowNull: false,
comment: '日程ID,关联schedule.id'
},
device_id: {
type: DataTypes.STRING(50),
allowNull: false,
comment: '设备ID,关联device.device_id'
},
region_key: {
type: DataTypes.BIGINT,
allowNull: false,
comment: '区域key,关联region.id,表示设备所属区域'
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '创建时间'
}
},
association: [
{ type: "hasMany", target: "device", foreignKey: "device_id" },
{ type: "hasMany", target: "region", foreignKey: "region_key" }
]
},
]; ];
/**
* 后端管理系统 路由
*/
import asyncHandler from "express-async-handler";
import * as reportBiz from "../biz/report";
import * as regionBiz from "../biz/region";
import * as scheduleBiz from "../biz/schedule";
export function setRouter(httpServer) {
/** 获取周报告JSON数据 */
httpServer.get("/api/qdm/report/weekly/data", asyncHandler(getReportData));
/** 获取九合一环境监测指标 7 天均值(A/B/C馆) */
httpServer.get("/api/qdm/report/env/weekly/avg", asyncHandler(getEnvWeeklyAvg));
/** 获取近 7 天故障信息(按 fault_code 分组) */
httpServer.get("/api/qdm/report/fault/weekly", asyncHandler(getFaultInfo));
/** 区域设备树 */
httpServer.get("/api/qdm/admin/region/device", asyncHandler(getRegionDevices));
/** 日程管理列表 */
httpServer.get("/api/qdm/admin/schedule/list", asyncHandler(getScheduleList));
/** 日程管理详情 */
httpServer.get("/api/qdm/admin/schedule/detail", asyncHandler(getScheduleDetail));
/** 日程管理新增 */
httpServer.post("/api/qdm/admin/schedule/add", asyncHandler(addSchedule));
/** 日程管理编辑 */
httpServer.post("/api/qdm/admin/schedule/edit", asyncHandler(editSchedule));
/** 日程管理删除 */
httpServer.post("/api/qdm/admin/schedule/delete", asyncHandler(deleteSchedule));
}
/**
* GET /api/qdm/report/weekly/data?weekOffset=0
* 返回周报告 JSON 数据供前端页面渲染
*/
async function getReportData(req, res) {
const weekOffset = Number(req.query?.weekOffset) || 0;
const data = await reportBiz.getWeeklyReportData(weekOffset);
res.success(data);
}
/**
* GET /api/qdm/report/env/weekly/avg
* 返回九合一环境监测指标 7 天均值(A馆 / B馆 / C馆)
*/
async function getEnvWeeklyAvg(req, res) {
const data = await reportBiz.getEnvIndicatorsWeeklyAvg();
res.success(data);
}
/**
* GET /api/qdm/report/fault/weekly
* 返回近 7 天故障信息,按 fault_code 分组
*/
async function getFaultInfo(req, res) {
const data = await reportBiz.getFaultInfoLast7Days();
res.success(data);
}
// ======================= 区域设备 =======================
/**
* GET /api/qdm/admin/region/device
* 获取区域设备树(馆 → 层 → 区域 → 设备)
*/
async function getRegionDevices(req, res) {
const data = await regionBiz.getRegionDevices();
res.success(data);
}
// ======================= 日程管理 =======================
/**
* GET /api/qdm/admin/schedule/list
* 日程列表(分页 + 有效期 + 区域过滤)
* query: pageNumber, pageSize, startDate, endDate, regionKey
*/
async function getScheduleList(req, res) {
const data = await scheduleBiz.getScheduleList({
pageNumber: Number(req.query?.pageNumber) || 1,
pageSize: Number(req.query?.pageSize) || 10,
startDate: req.query?.startDate,
endDate: req.query?.endDate,
regionKey: req.query?.regionKey ? Number(req.query.regionKey) : undefined,
});
res.success(data);
}
/**
* GET /api/qdm/admin/schedule/detail
* 日程详情(含关联区域/设备)
* query: scheduleId
*/
async function getScheduleDetail(req, res) {
const scheduleId = Number(req.query?.scheduleId);
if (!scheduleId) {
res.fail("缺少参数 scheduleId");
return;
}
const data = await scheduleBiz.getScheduleDetail(scheduleId);
if (!data) {
res.fail("日程不存在");
return;
}
res.success(data);
}
/**
* POST /api/qdm/admin/schedule/add
* 新增日程
* body: title, scheduleTime, acControls, beginValidity, endValidity, regionKeys
*/
async function addSchedule(req, res) {
const { title, scheduleTime, acControls, beginValidity, endValidity, regionKeys } = req.body || {};
if (!title || !scheduleTime || !acControls) {
res.fail("缺少必填参数:title, scheduleTime, acControls");
return;
}
if (!regionKeys || !Array.isArray(regionKeys) || regionKeys.length === 0) {
res.fail("至少选择一个区域");
return;
}
const data = await scheduleBiz.addSchedule({
title,
schedule_time: scheduleTime,
ac_controls: acControls,
begin_validity: beginValidity || undefined,
end_validity: endValidity || undefined,
regionKeys,
});
res.success(data);
}
/**
* POST /api/qdm/admin/schedule/edit
* 编辑日程
* body: scheduleId, title, scheduleTime, acControls, beginValidity, endValidity, regionKeys
*/
async function editSchedule(req, res) {
const { scheduleId, title, scheduleTime, acControls, beginValidity, endValidity, regionKeys } = req.body || {};
if (!scheduleId || !title || !scheduleTime || !acControls) {
res.fail("缺少必填参数:scheduleId, title, scheduleTime, acControls");
return;
}
if (!regionKeys || !Array.isArray(regionKeys) || regionKeys.length === 0) {
res.fail("至少选择一个区域");
return;
}
const data = await scheduleBiz.editSchedule({
scheduleId: Number(scheduleId),
title,
schedule_time: scheduleTime,
ac_controls: acControls,
begin_validity: beginValidity || undefined,
end_validity: endValidity || undefined,
regionKeys,
});
res.success(data);
}
/**
* POST /api/qdm/admin/schedule/delete
* 删除日程
* body: scheduleId
*/
async function deleteSchedule(req, res) {
const { scheduleId } = req.body || {};
if (!scheduleId) {
res.fail("缺少参数 scheduleId");
return;
}
const data = await scheduleBiz.deleteSchedule(Number(scheduleId));
res.success(data);
}
/**
* 周报告 API 路由
*/
import asyncHandler from "express-async-handler";
import * as reportBiz from "../biz/report";
export function setRouter(httpServer) {
/** 获取周报告JSON数据 */
httpServer.get("/api/qdm/report/weekly/data", asyncHandler(getReportData));
}
/**
* GET /api/qdm/report/weekly/data?weekOffset=0
* 返回周报告 JSON 数据供前端页面渲染
*/
async function getReportData(req, res) {
const weekOffset = Number(req.query?.weekOffset) || 0;
const data = await reportBiz.getWeeklyReportData(weekOffset);
res.success(data);
}
...@@ -5,13 +5,13 @@ ...@@ -5,13 +5,13 @@
import * as usersRouter from './users'; import * as usersRouter from './users';
import * as deviceRouter from './device'; import * as deviceRouter from './device';
import * as feiyiClientRouter from './feiyiClient'; import * as feiyiClientRouter from './feiyiClient';
import * as reportRouter from './report'; import * as adminRouter from './admin';
export function setRouter(httpServer) { export function setRouter(httpServer) {
usersRouter.setRouter(httpServer); usersRouter.setRouter(httpServer);
deviceRouter.setRouter(httpServer); deviceRouter.setRouter(httpServer);
feiyiClientRouter.setRouter(httpServer); feiyiClientRouter.setRouter(httpServer);
reportRouter.setRouter(httpServer); adminRouter.setRouter(httpServer);
} }
......
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