diff --git a/controllers/roomController.js b/controllers/roomController.js index 4b50459..bfaad92 100644 --- a/controllers/roomController.js +++ b/controllers/roomController.js @@ -60,7 +60,7 @@ const checkAndUpdateRentalStatus = async () => { const currentDate = new Date(); // 计算10天后的日期 const tenDaysLater = new Date(); - tenDaysLater.setDate(currentDate.getDate() + 10); + tenDaysLater.setDate(currentDate.getDate() + 30); // 查找所有活跃的租房记录 const rentals = await Rental.findAll({ @@ -73,12 +73,10 @@ const checkAndUpdateRentalStatus = async () => { // 检查是否已到期 if (endDate < currentDate) { - // 更新租房状态为已到期 - await rental.update({ status: 'expired' }); - // 更新房间状态为空房 + // 更新房间附属状态为已到期 const room = await Room.findByPk(rental.roomId); if (room && room.status === 'rented') { - await room.update({ status: 'empty', subStatus: 'normal' }); + await room.update({ subStatus: 'expired' }); } } else if (endDate <= tenDaysLater) { // 更新房间附属状态为即将到期 diff --git a/controllers/statisticsController.js b/controllers/statisticsController.js index 33a38b7..92feb62 100644 --- a/controllers/statisticsController.js +++ b/controllers/statisticsController.js @@ -4,67 +4,53 @@ const { Op } = require('sequelize'); // 租金统计 const getRentStatistics = async (req, res) => { try { - // 获取当前年份 - const currentYear = new Date().getFullYear(); + // 导入Contract模型 + const { Contract } = require('../models'); - // 从数据库查询所有租房记录(包括活跃和已到期的) - const rentals = await Rental.findAll({ - include: [Room] - }); + // 计算过去12个月的开始日期 + const now = new Date(); + const startDate = new Date(now.getFullYear(), now.getMonth() - 11, 1); // 12个月前的第一天 - // 按月份统计租金 + // 初始化过去12个月的数据 const monthlyRent = {}; - - // 初始化12个月的数据 - for (let i = 1; i <= 12; i++) { - const monthKey = `${currentYear}-${i.toString().padStart(2, '0')}`; + for (let i = 0; i < 12; i++) { + const date = new Date(now.getFullYear(), now.getMonth() - i, 1); + const monthKey = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}`; monthlyRent[monthKey] = 0; } - // 计算每个月的租金收入 - rentals.forEach(rental => { - if (rental.Room) { - // 检查租金是否有效 - const rentAmount = parseFloat(rental.rent) || 0; - if (rentAmount > 0 && rental.startDate && rental.endDate) { - // 解析开始和结束日期 - const startDate = new Date(rental.startDate); - const endDate = new Date(rental.endDate); - - // 计算当前年份的开始和结束日期 - const yearStart = new Date(currentYear, 0, 1); // 1月1日 - const yearEnd = new Date(currentYear, 11, 31); // 12月31日 - - // 确定实际的开始和结束日期(考虑年份范围) - const actualStart = startDate > yearStart ? startDate : yearStart; - const actualEnd = endDate < yearEnd ? endDate : yearEnd; - - // 如果实际开始日期晚于实际结束日期,跳过 - if (actualStart > actualEnd) { - return; - } - - // 遍历当前年份的每个月 - for (let i = 1; i <= 12; i++) { - const monthKey = `${currentYear}-${i.toString().padStart(2, '0')}`; - const monthStart = new Date(currentYear, i - 1, 1); // 当月1日 - const monthEnd = new Date(currentYear, i, 0); // 当月最后一天 - - // 检查租赁期是否与当前月份重叠 - if (actualStart <= monthEnd && actualEnd >= monthStart) { - // 如果重叠,添加当月租金 - monthlyRent[monthKey] += rentAmount; - } - } + // 从数据库查询过去12个月的合同记录 + const contracts = await Contract.findAll({ + where: { + createTime: { + [Op.gte]: startDate } } }); - // 转换为数组格式 - const rentStatistics = Object.entries(monthlyRent).map(([month, amount]) => ({ - month, - amount: Math.round(amount * 100) / 100 // 保留两位小数 - })); + // 按月份统计已收租金 + contracts.forEach(contract => { + // 检查租金是否有效 + const rentAmount = parseFloat(contract.rent) || 0; + if (rentAmount > 0 && contract.createTime) { + // 解析创建时间 + const createDate = new Date(contract.createTime); + const monthKey = `${createDate.getFullYear()}-${(createDate.getMonth() + 1).toString().padStart(2, '0')}`; + + // 如果该月份在我们的统计范围内,添加租金 + if (monthlyRent.hasOwnProperty(monthKey)) { + monthlyRent[monthKey] += rentAmount; + } + } + }); + + // 转换为数组格式并按月份倒序排序 + const rentStatistics = Object.entries(monthlyRent) + .map(([month, amount]) => ({ + month, + amount: Math.round(amount * 100) / 100 // 保留两位小数 + })) + .sort((a, b) => b.month.localeCompare(a.month)); res.status(200).json(rentStatistics); } catch (error) { @@ -76,23 +62,46 @@ const getRentStatistics = async (req, res) => { // 房间状态统计 const getRoomStatusStatistics = async (req, res) => { try { - const statusCounts = await Room.count({ - group: ['status'] + // 获取所有房间 + const rooms = await Room.findAll(); + + // 初始化统计数据 + let empty = 0; + let rented = 0; + let soon_expire = 0; + let expired = 0; + let cleaning = 0; + let maintenance = 0; + + // 统计各状态房间数量 + rooms.forEach(room => { + if (room.status === 'empty') { + empty++; + } else if (room.status === 'rented') { + rented++; + // 统计附属状态 + if (room.subStatus === 'soon_expire') { + soon_expire++; + } else if (room.subStatus === 'expired') { + expired++; + } + // 统计其他状态 + if (room.otherStatus === 'cleaning') { + cleaning++; + } else if (room.otherStatus === 'maintenance') { + maintenance++; + } + } }); - const statusMap = { - empty: '空房', - rented: '在租', - soon_expire: '即将到期', - expired: '到期', - cleaning: '打扫中', - maintenance: '维修中' - }; - - const roomStatusStatistics = Object.entries(statusMap).map(([status, label]) => { - const count = statusCounts.find(item => item.status === status)?.count || 0; - return { status: label, count }; - }); + const roomStatusStatistics = [ + { status: '空房', count: empty }, + { status: '在租', count: rented }, + { status: '即将到期', count: soon_expire }, + { status: '到期', count: expired }, + { status: '打扫中', count: cleaning }, + { status: '维修中', count: maintenance } + ]; res.status(200).json(roomStatusStatistics); } catch (error) { @@ -122,19 +131,22 @@ const getRegionHouseStatistics = async (req, res) => { region.Apartments.forEach(apartment => { apartment.Rooms.forEach(room => { - switch (room.status) { - case 'empty': empty++; - break; - case 'rented': rented++; - break; - case 'soon_expire': soon_expire++; - break; - case 'expired': expired++; - break; - case 'cleaning': cleaning++; - break; - case 'maintenance': maintenance++; - break; + if (room.status === 'empty') { + empty++; + } else if (room.status === 'rented') { + rented++; + // 统计附属状态 + if (room.subStatus === 'soon_expire') { + soon_expire++; + } else if (room.subStatus === 'expired') { + expired++; + } + // 统计其他状态 + if (room.otherStatus === 'cleaning') { + cleaning++; + } else if (room.otherStatus === 'maintenance') { + maintenance++; + } } }); }); @@ -147,7 +159,7 @@ const getRegionHouseStatistics = async (req, res) => { expired, cleaning, maintenance, - total: empty + rented + soon_expire + expired + cleaning + maintenance + total: empty + rented }; }); @@ -181,19 +193,22 @@ const getRegionApartmentHouseStatistics = async (req, res) => { let maintenance = 0; apartment.Rooms.forEach(room => { - switch (room.status) { - case 'empty': empty++; - break; - case 'rented': rented++; - break; - case 'soon_expire': soon_expire++; - break; - case 'expired': expired++; - break; - case 'cleaning': cleaning++; - break; - case 'maintenance': maintenance++; - break; + if (room.status === 'empty') { + empty++; + } else if (room.status === 'rented') { + rented++; + // 统计附属状态 + if (room.subStatus === 'soon_expire') { + soon_expire++; + } else if (room.subStatus === 'expired') { + expired++; + } + // 统计其他状态 + if (room.otherStatus === 'cleaning') { + cleaning++; + } else if (room.otherStatus === 'maintenance') { + maintenance++; + } } }); @@ -206,7 +221,7 @@ const getRegionApartmentHouseStatistics = async (req, res) => { expired, cleaning, maintenance, - total: empty + rented + soon_expire + expired + cleaning + maintenance + total: empty + rented }); }); }); @@ -217,9 +232,51 @@ const getRegionApartmentHouseStatistics = async (req, res) => { } }; +// Dashboard统计数据 +const getDashboardStatistics = async (req, res) => { + try { + // 导入所有需要的模型 + const { Region, Apartment, Room, Tenant, Contract, WaterBill, Rental } = require('../models'); + + // 并行查询所有统计数据 + const [regionCount, apartmentCount, roomCount, tenantCount, contractCount, emptyRoomCount, rentedRoomCount, collectedRentAmount, collectedWaterAmount] = await Promise.all([ + Region.count(), + Apartment.count(), + Room.count(), + Tenant.count(), + Contract.count(), + Room.count({ where: { status: 'empty' } }), + Room.count({ where: { status: 'rented' } }), + // 统计已收租金 + Rental.sum('rent', { where: { status: 'active' } }), + // 统计已收水费 + WaterBill.sum('amount', { where: { status: 'paid' } }) + ]); + + // 构造响应数据 + const dashboardStatistics = { + regionCount, + apartmentCount, + roomCount, + tenantCount, + contractCount, + emptyRoomCount, + rentedRoomCount, + collectedRentAmount: parseFloat(collectedRentAmount) || 0, + collectedWaterAmount: parseFloat(collectedWaterAmount) || 0 + }; + + res.status(200).json(dashboardStatistics); + } catch (error) { + console.error('获取Dashboard统计数据时出错:', error); + res.status(500).json({ error: error.message }); + } +}; + module.exports = { getRentStatistics, getRoomStatusStatistics, getRegionHouseStatistics, - getRegionApartmentHouseStatistics + getRegionApartmentHouseStatistics, + getDashboardStatistics }; \ No newline at end of file diff --git a/routes/statistics.js b/routes/statistics.js index f87c78e..4c56805 100644 --- a/routes/statistics.js +++ b/routes/statistics.js @@ -7,5 +7,6 @@ router.get('/rent', statisticsController.getRentStatistics); router.get('/room-status', statisticsController.getRoomStatusStatistics); router.get('/region-house', statisticsController.getRegionHouseStatistics); router.get('/region-apartment-house', statisticsController.getRegionApartmentHouseStatistics); +router.get('/dashboard', statisticsController.getDashboardStatistics); module.exports = router; \ No newline at end of file