rentease-backend/controllers/rentalController.js

399 lines
11 KiB
JavaScript
Raw Normal View History

2026-03-02 12:36:41 +00:00
const { Rental, Room, Tenant, Contract, Apartment, Region } = require('../models');
const { Op } = require('sequelize');
// 格式化时间(考虑时区,转换为北京时间)
const formatDate = (date) => {
if (!date) return null;
// 创建一个新的Date对象加上8小时的时区偏移
const beijingDate = new Date(date.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().split('T')[0];
};
// 格式化租房数据
const formatRentalData = (rental) => {
const formattedRental = {
...rental.toJSON(),
startDate: formatDate(rental.startDate),
endDate: formatDate(rental.endDate),
2026-03-03 15:36:48 +00:00
createTime: formatDate(rental.createTime),
updateTime: formatDate(rental.updateTime)
2026-03-02 12:36:41 +00:00
};
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 格式化关联数据
if (formattedRental.Contract) {
formattedRental.Contract = {
...formattedRental.Contract,
startDate: formatDate(formattedRental.Contract.startDate),
endDate: formatDate(formattedRental.Contract.endDate),
2026-03-03 15:36:48 +00:00
createTime: formatDate(formattedRental.Contract.createTime),
updateTime: formatDate(formattedRental.Contract.updateTime)
2026-03-02 12:36:41 +00:00
};
}
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
return formattedRental;
};
// 检查并更新租房状态
const checkAndUpdateRentalStatus = async () => {
try {
// 获取当前日期
const currentDate = new Date();
// 计算10天后的日期
const tenDaysLater = new Date();
2026-03-04 05:03:31 +00:00
tenDaysLater.setDate(currentDate.getDate() + 30);
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 查找所有活跃的租房记录
const rentals = await Rental.findAll({
2026-03-03 15:36:48 +00:00
where: { status: 'active', isDeleted: 0 },
include: [
{
model: Room,
where: { isDeleted: 0 }
}
]
2026-03-02 12:36:41 +00:00
});
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 检查每个租房记录的状态
for (const rental of rentals) {
const endDate = new Date(rental.endDate);
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 检查是否已到期
if (endDate < currentDate) {
2026-03-04 05:03:31 +00:00
// 更新房间附属状态为已到期
const room = await Room.findByPk(rental.roomId);
if (room && room.status === 'rented') {
await room.update({ subStatus: 'expired' });
2026-03-02 12:36:41 +00:00
}
} else if (endDate <= tenDaysLater) {
2026-03-04 05:03:31 +00:00
// 更新房间附属状态为即将到期
const room = await Room.findByPk(rental.roomId);
if (room && room.status === 'rented') {
await room.update({ subStatus: 'soon_expire' });
}
} else {
// 更新房间附属状态为正常
const room = await Room.findByPk(rental.roomId);
if (room && room.status === 'rented') {
await room.update({ subStatus: 'normal' });
2026-03-02 12:36:41 +00:00
}
}
}
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
console.log('租房状态检查和更新完成');
} catch (error) {
console.error('检查和更新租房状态时出错:', error);
}
};
// 获取所有租房(支持搜索和分页)
const getAllRentals = async (req, res) => {
try {
// 先检查并更新租房状态
await checkAndUpdateRentalStatus();
2026-03-04 07:09:52 +00:00
const { roomId, tenantName, status, page = 1, pageSize = 10 } = req.query;
2026-03-02 12:36:41 +00:00
// 构建查询条件
2026-03-03 15:36:48 +00:00
const where = { isDeleted: 0 };
2026-03-02 12:36:41 +00:00
if (status) {
where.status = status;
}
2026-03-04 07:09:52 +00:00
if (roomId) {
where.roomId = roomId;
}
// 构建包含关系 - 关联租客信息和合同信息
2026-03-02 12:36:41 +00:00
const include = [
{
model: Tenant,
2026-03-03 15:36:48 +00:00
where: tenantName ? { name: { [Op.like]: `%${tenantName}%` }, isDeleted: 0 } : { isDeleted: 0 }
2026-03-02 12:36:41 +00:00
},
2026-03-03 15:36:48 +00:00
{
model: Contract,
where: { isDeleted: 0 }
}
2026-03-02 12:36:41 +00:00
];
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 计算偏移量
const offset = (page - 1) * pageSize;
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 查询租房数据
const { count, rows } = await Rental.findAndCountAll({
where,
include,
limit: parseInt(pageSize),
2026-03-04 07:09:52 +00:00
offset: parseInt(offset),
order: [['createTime', 'DESC']] // 按创建时间倒序排序
2026-03-02 12:36:41 +00:00
});
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 格式化数据
const formattedRentals = rows.map(formatRentalData);
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 返回结果
res.status(200).json({
data: formattedRentals,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 获取单个租房
const getRentalById = async (req, res) => {
try {
const { id } = req.params;
2026-03-03 15:36:48 +00:00
const rental = await Rental.findOne({
where: { id, isDeleted: 0 },
2026-03-02 12:36:41 +00:00
include: [
{
model: Room,
2026-03-03 15:36:48 +00:00
where: { isDeleted: 0 },
2026-03-02 12:36:41 +00:00
include: [
{
model: Apartment,
2026-03-03 15:36:48 +00:00
where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 }
}
]
2026-03-02 12:36:41 +00:00
}
]
},
2026-03-03 15:36:48 +00:00
{
model: Tenant,
where: { isDeleted: 0 }
},
{
model: Contract,
where: { isDeleted: 0 }
}
2026-03-02 12:36:41 +00:00
]
});
if (!rental) {
return res.status(404).json({ error: '租房记录不存在' });
}
const formattedRental = formatRentalData(rental);
res.status(200).json(formattedRental);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 创建租房
const createRental = async (req, res) => {
try {
console.log('接收到的请求数据:', req.body);
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 直接使用req.body中的数据
const body = req.body;
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 检查请求体是否存在
if (!body) {
return res.status(400).json({ error: '请求体不能为空' });
}
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 检查所有必要参数
if (!body.roomId) {
return res.status(400).json({ error: '缺少房间ID' });
}
if (!body.tenantName) {
return res.status(400).json({ error: '缺少租客姓名' });
}
if (!body.startDate) {
return res.status(400).json({ error: '缺少开始日期' });
}
if (!body.endDate) {
return res.status(400).json({ error: '缺少结束日期' });
}
if (!body.rent) {
return res.status(400).json({ error: '缺少租金' });
}
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 转换roomId为整数类型
const parsedRoomId = parseInt(body.roomId);
if (isNaN(parsedRoomId)) {
return res.status(400).json({ error: '无效的房间ID' });
}
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 先查找或创建租客
2026-03-04 07:09:52 +00:00
let tenant;
if (body.tenantIdCard) {
tenant = await Tenant.findOne({ where: { idCard: body.tenantIdCard } });
}
2026-03-02 12:36:41 +00:00
if (!tenant) {
console.log('创建新租客:', { name: body.tenantName, phone: body.tenantPhone, idCard: body.tenantIdCard });
2026-03-04 07:09:52 +00:00
tenant = await Tenant.create({
name: body.tenantName,
phone: body.tenantPhone,
idCard: body.tenantIdCard
2026-03-02 12:36:41 +00:00
});
}
console.log('租客信息:', tenant);
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 确保租客创建成功
if (!tenant || !tenant.id) {
return res.status(500).json({ error: '创建租客失败' });
}
2026-03-04 07:09:52 +00:00
// 处理押金为空时设置为0
const deposit = body.deposit || 0;
2026-03-02 12:36:41 +00:00
// 创建合同
2026-03-04 07:09:52 +00:00
console.log('创建合同:', {
roomId: parsedRoomId,
tenantId: tenant.id,
startDate: body.startDate,
endDate: body.endDate,
rent: body.rent,
deposit: deposit,
status: body.status || 'active'
2026-03-02 12:36:41 +00:00
});
2026-03-04 07:09:52 +00:00
const contract = await Contract.create({
roomId: parsedRoomId,
tenantId: tenant.id,
startDate: body.startDate,
endDate: body.endDate,
rent: body.rent,
deposit: deposit,
status: body.status || 'active'
2026-03-02 12:36:41 +00:00
});
console.log('合同信息:', contract);
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 确保合同创建成功
if (!contract || !contract.id) {
return res.status(500).json({ error: '创建合同失败' });
}
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 创建租房记录
2026-03-04 07:09:52 +00:00
console.log('创建租房记录:', {
roomId: parsedRoomId,
tenantId: tenant.id,
contractId: contract.id,
startDate: body.startDate,
endDate: body.endDate,
rent: body.rent,
deposit: deposit,
status: body.status || 'active'
2026-03-02 12:36:41 +00:00
});
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 直接使用具体的数值创建租房记录
const rental = await Rental.create({
roomId: parsedRoomId,
tenantId: tenant.id,
contractId: contract.id,
startDate: body.startDate,
endDate: body.endDate,
rent: body.rent,
2026-03-04 07:09:52 +00:00
deposit: deposit,
2026-03-02 12:36:41 +00:00
status: body.status || 'active'
});
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
console.log('租房记录:', rental);
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
// 更新房间状态为已租
await Room.update({ status: 'rented' }, { where: { id: parsedRoomId } });
2026-03-04 07:09:52 +00:00
2026-03-02 12:36:41 +00:00
res.status(201).json(rental);
} catch (error) {
console.error('创建租房记录时出错:', error);
res.status(500).json({ error: error.message });
}
};
// 更新租房
const updateRental = async (req, res) => {
try {
const { id } = req.params;
const { roomId, tenantId, contractId, startDate, endDate, rent, deposit, status } = req.body;
2026-03-03 15:36:48 +00:00
const rental = await Rental.findOne({
where: { id, isDeleted: 0 }
});
2026-03-02 12:36:41 +00:00
if (!rental) {
return res.status(404).json({ error: '租房记录不存在' });
}
2026-03-04 07:09:52 +00:00
// 处理押金为空时设置为0
const updateDeposit = deposit || 0;
await rental.update({ roomId, tenantId, contractId, startDate, endDate, rent, deposit: updateDeposit, status });
2026-03-02 12:36:41 +00:00
res.status(200).json(rental);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
2026-03-03 15:36:48 +00:00
// 删除租房(软删除)
2026-03-02 12:36:41 +00:00
const deleteRental = async (req, res) => {
try {
const { id } = req.params;
2026-03-03 15:36:48 +00:00
const rental = await Rental.findOne({
where: { id, isDeleted: 0 }
});
2026-03-02 12:36:41 +00:00
if (!rental) {
return res.status(404).json({ error: '租房记录不存在' });
}
2026-03-03 15:36:48 +00:00
await rental.update({ isDeleted: 1 });
2026-03-02 12:36:41 +00:00
res.status(200).json({ message: '租房记录删除成功' });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
2026-03-04 07:39:06 +00:00
// 获取所有租房(不分页)
const listRentals = async (req, res) => {
try {
// 先检查并更新租房状态
await checkAndUpdateRentalStatus();
const { roomId, tenantName, status } = req.query;
// 构建查询条件
const where = { isDeleted: 0 };
if (status) {
where.status = status;
}
if (roomId) {
where.roomId = roomId;
}
// 构建包含关系 - 关联租客信息和合同信息
const include = [
{
model: Tenant,
where: tenantName ? { name: { [Op.like]: `%${tenantName}%` }, isDeleted: 0 } : { isDeleted: 0 }
},
{
model: Contract,
where: { isDeleted: 0 }
}
];
// 查询租房数据
const rentals = await Rental.findAll({
where,
include,
order: [['createTime', 'DESC']] // 按创建时间倒序排序
});
// 格式化数据
const formattedRentals = rentals.map(formatRentalData);
// 返回结果
res.status(200).json(formattedRentals);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
2026-03-02 12:36:41 +00:00
module.exports = {
getAllRentals,
2026-03-04 07:39:06 +00:00
listRentals,
2026-03-02 12:36:41 +00:00
getRentalById,
createRental,
updateRental,
deleteRental
2026-03-04 07:09:52 +00:00
};