This commit is contained in:
wangxiaoxian 2026-03-03 23:36:48 +08:00
parent f912a0373d
commit 79160aae9b
22 changed files with 516 additions and 99 deletions

53
add_fields.js Normal file
View File

@ -0,0 +1,53 @@
const mysql = require('mysql2/promise');
async function addFields() {
try {
// 连接到数据库
const connection = await mysql.createConnection({
host: '8.152.207.41',
user: 'rentease',
password: 'Wxx@123!',
database: 'rentease'
});
console.log('成功连接到数据库');
// 检查 subStatus 字段是否存在
const [subStatusResult] = await connection.query(`
SHOW COLUMNS FROM rooms LIKE 'subStatus'
`);
// 如果 subStatus 字段不存在,则添加
if (subStatusResult.length === 0) {
await connection.query(`
ALTER TABLE rooms ADD COLUMN subStatus ENUM('normal', 'soon_expire', 'expired') NOT NULL DEFAULT 'normal'
`);
console.log('添加 subStatus 字段成功');
} else {
console.log('subStatus 字段已存在');
}
// 检查 otherStatus 字段是否存在
const [otherStatusResult] = await connection.query(`
SHOW COLUMNS FROM rooms LIKE 'otherStatus'
`);
// 如果 otherStatus 字段不存在,则添加
if (otherStatusResult.length === 0) {
await connection.query(`
ALTER TABLE rooms ADD COLUMN otherStatus ENUM('', 'cleaning', 'maintenance') NOT NULL DEFAULT ''
`);
console.log('添加 otherStatus 字段成功');
} else {
console.log('otherStatus 字段已存在');
}
// 关闭连接
await connection.end();
console.log('数据库连接已关闭');
} catch (error) {
console.error('添加字段时出错:', error);
}
}
addFields();

31
add_fields.sql Normal file
View File

@ -0,0 +1,31 @@
-- 为 rooms 表添加字段
ALTER TABLE rooms ADD COLUMN updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE rooms ADD COLUMN isDeleted INT NOT NULL DEFAULT 0;
-- 为 tenants 表添加字段
ALTER TABLE tenants ADD COLUMN updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE tenants ADD COLUMN isDeleted INT NOT NULL DEFAULT 0;
-- 为 regions 表添加字段
ALTER TABLE regions ADD COLUMN updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE regions ADD COLUMN isDeleted INT NOT NULL DEFAULT 0;
-- 为 apartments 表添加字段
ALTER TABLE apartments ADD COLUMN updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE apartments ADD COLUMN isDeleted INT NOT NULL DEFAULT 0;
-- 为 contracts 表添加字段
ALTER TABLE contracts ADD COLUMN updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE contracts ADD COLUMN isDeleted INT NOT NULL DEFAULT 0;
-- 为 rentals 表添加字段
ALTER TABLE rentals ADD COLUMN updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE rentals ADD COLUMN isDeleted INT NOT NULL DEFAULT 0;
-- 为 water_bills 表添加字段
ALTER TABLE water_bills ADD COLUMN updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE water_bills ADD COLUMN isDeleted INT NOT NULL DEFAULT 0;
-- 为 electricity_bills 表添加字段
ALTER TABLE electricity_bills ADD COLUMN updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE electricity_bills ADD COLUMN isDeleted INT NOT NULL DEFAULT 0;

View File

@ -6,7 +6,7 @@ const createDatabase = async () => {
try { try {
// 连接到MySQL服务器 // 连接到MySQL服务器
const connection = await mysql.createConnection({ const connection = await mysql.createConnection({
host: 'localhost', host: '8.152.207.41',
user: 'rentease', user: 'rentease',
password: 'Wxx@123!' password: 'Wxx@123!'
}); });
@ -28,7 +28,7 @@ const sequelize = new Sequelize(
'rentease', // 用户名 'rentease', // 用户名
'Wxx@123!', // 密码 'Wxx@123!', // 密码
{ {
host: 'localhost', host: '8.152.207.41',
dialect: 'mysql', dialect: 'mysql',
logging: false, logging: false,
timezone: '+08:00' timezone: '+08:00'
@ -45,7 +45,7 @@ const testConnection = async () => {
'rentease', // 用户名 'rentease', // 用户名
'Wxx@123!', // 密码 'Wxx@123!', // 密码
{ {
host: 'localhost', host: '8.152.207.41',
dialect: 'mysql', dialect: 'mysql',
logging: false, logging: false,
timezone: '+08:00' timezone: '+08:00'

View File

@ -13,14 +13,16 @@ const formatDate = (date) => {
const formatApartmentData = (apartment) => { const formatApartmentData = (apartment) => {
const formattedApartment = { const formattedApartment = {
...apartment.toJSON(), ...apartment.toJSON(),
createTime: formatDate(apartment.createTime) createTime: formatDate(apartment.createTime),
updateTime: formatDate(apartment.updateTime)
}; };
// 格式化关联数据 // 格式化关联数据
if (formattedApartment.Region) { if (formattedApartment.Region) {
formattedApartment.Region = { formattedApartment.Region = {
...formattedApartment.Region, ...formattedApartment.Region,
createTime: formatDate(formattedApartment.Region.createTime) createTime: formatDate(formattedApartment.Region.createTime),
updateTime: formatDate(formattedApartment.Region.updateTime)
}; };
} }
@ -33,7 +35,7 @@ const getAllApartments = async (req, res) => {
const { regionId, name, page = 1, pageSize = 10 } = req.query; const { regionId, name, page = 1, pageSize = 10 } = req.query;
// 构建查询条件 // 构建查询条件
const where = {}; const where = { isDeleted: 0 };
if (regionId) { if (regionId) {
where.regionId = regionId; where.regionId = regionId;
} }
@ -73,7 +75,8 @@ const getAllApartments = async (req, res) => {
const getApartmentById = async (req, res) => { const getApartmentById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const apartment = await Apartment.findByPk(id, { const apartment = await Apartment.findOne({
where: { id, isDeleted: 0 },
include: [Region] include: [Region]
}); });
if (!apartment) { if (!apartment) {
@ -102,7 +105,9 @@ const updateApartment = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const { regionId, name, address } = req.body; const { regionId, name, address } = req.body;
const apartment = await Apartment.findByPk(id); const apartment = await Apartment.findOne({
where: { id, isDeleted: 0 }
});
if (!apartment) { if (!apartment) {
return res.status(404).json({ error: '公寓不存在' }); return res.status(404).json({ error: '公寓不存在' });
} }
@ -113,15 +118,17 @@ const updateApartment = async (req, res) => {
} }
}; };
// 删除公寓 // 删除公寓(软删除)
const deleteApartment = async (req, res) => { const deleteApartment = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const apartment = await Apartment.findByPk(id); const apartment = await Apartment.findOne({
where: { id, isDeleted: 0 }
});
if (!apartment) { if (!apartment) {
return res.status(404).json({ error: '公寓不存在' }); return res.status(404).json({ error: '公寓不存在' });
} }
await apartment.destroy(); await apartment.update({ isDeleted: 1 });
res.status(200).json({ message: '公寓删除成功' }); res.status(200).json({ message: '公寓删除成功' });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });

View File

@ -14,26 +14,30 @@ const formatContractData = (contract) => {
...contract.toJSON(), ...contract.toJSON(),
startDate: formatDate(contract.startDate), startDate: formatDate(contract.startDate),
endDate: formatDate(contract.endDate), endDate: formatDate(contract.endDate),
createTime: formatDate(contract.createTime) createTime: formatDate(contract.createTime),
updateTime: formatDate(contract.updateTime)
}; };
// 格式化关联数据 // 格式化关联数据
if (formattedContract.Room) { if (formattedContract.Room) {
formattedContract.Room = { formattedContract.Room = {
...formattedContract.Room, ...formattedContract.Room,
createTime: formatDate(formattedContract.Room.createTime) createTime: formatDate(formattedContract.Room.createTime),
updateTime: formatDate(formattedContract.Room.updateTime)
}; };
if (formattedContract.Room.Apartment) { if (formattedContract.Room.Apartment) {
formattedContract.Room.Apartment = { formattedContract.Room.Apartment = {
...formattedContract.Room.Apartment, ...formattedContract.Room.Apartment,
createTime: formatDate(formattedContract.Room.Apartment.createTime) createTime: formatDate(formattedContract.Room.Apartment.createTime),
updateTime: formatDate(formattedContract.Room.Apartment.updateTime)
}; };
if (formattedContract.Room.Apartment.Region) { if (formattedContract.Room.Apartment.Region) {
formattedContract.Room.Apartment.Region = { formattedContract.Room.Apartment.Region = {
...formattedContract.Room.Apartment.Region, ...formattedContract.Room.Apartment.Region,
createTime: formatDate(formattedContract.Room.Apartment.Region.createTime) createTime: formatDate(formattedContract.Room.Apartment.Region.createTime),
updateTime: formatDate(formattedContract.Room.Apartment.Region.updateTime)
}; };
} }
} }
@ -42,7 +46,8 @@ const formatContractData = (contract) => {
if (formattedContract.Tenant) { if (formattedContract.Tenant) {
formattedContract.Tenant = { formattedContract.Tenant = {
...formattedContract.Tenant, ...formattedContract.Tenant,
createTime: formatDate(formattedContract.Tenant.createTime) createTime: formatDate(formattedContract.Tenant.createTime),
updateTime: formatDate(formattedContract.Tenant.updateTime)
}; };
} }
@ -53,17 +58,28 @@ const formatContractData = (contract) => {
const getAllContracts = async (req, res) => { const getAllContracts = async (req, res) => {
try { try {
const contracts = await Contract.findAll({ const contracts = await Contract.findAll({
where: { isDeleted: 0 },
include: [ include: [
{ {
model: Room, model: Room,
where: { isDeleted: 0 },
include: [ include: [
{ {
model: Apartment, model: Apartment,
include: [Region] where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 }
}
]
} }
] ]
}, },
Tenant {
model: Tenant,
where: { isDeleted: 0 }
}
] ]
}); });
const formattedContracts = contracts.map(formatContractData); const formattedContracts = contracts.map(formatContractData);
@ -77,18 +93,29 @@ const getAllContracts = async (req, res) => {
const getContractById = async (req, res) => { const getContractById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const contract = await Contract.findByPk(id, { const contract = await Contract.findOne({
where: { id, isDeleted: 0 },
include: [ include: [
{ {
model: Room, model: Room,
where: { isDeleted: 0 },
include: [ include: [
{ {
model: Apartment, model: Apartment,
include: [Region] where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 }
}
]
} }
] ]
}, },
Tenant {
model: Tenant,
where: { isDeleted: 0 }
}
] ]
}); });
if (!contract) { if (!contract) {
@ -117,7 +144,9 @@ const updateContract = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const { roomId, tenantId, startDate, endDate, rent, deposit, status } = req.body; const { roomId, tenantId, startDate, endDate, rent, deposit, status } = req.body;
const contract = await Contract.findByPk(id); const contract = await Contract.findOne({
where: { id, isDeleted: 0 }
});
if (!contract) { if (!contract) {
return res.status(404).json({ error: '合同不存在' }); return res.status(404).json({ error: '合同不存在' });
} }
@ -128,15 +157,17 @@ const updateContract = async (req, res) => {
} }
}; };
// 删除合同 // 删除合同(软删除)
const deleteContract = async (req, res) => { const deleteContract = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const contract = await Contract.findByPk(id); const contract = await Contract.findOne({
where: { id, isDeleted: 0 }
});
if (!contract) { if (!contract) {
return res.status(404).json({ error: '合同不存在' }); return res.status(404).json({ error: '合同不存在' });
} }
await contract.destroy(); await contract.update({ isDeleted: 1 });
res.status(200).json({ message: '合同删除成功' }); res.status(200).json({ message: '合同删除成功' });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });

View File

@ -15,14 +15,16 @@ const formatElectricityBillData = (bill) => {
...bill.toJSON(), ...bill.toJSON(),
startDate: formatDate(bill.startDate), startDate: formatDate(bill.startDate),
endDate: formatDate(bill.endDate), endDate: formatDate(bill.endDate),
createTime: formatDate(bill.createTime) createTime: formatDate(bill.createTime),
updateTime: formatDate(bill.updateTime)
}; };
// 格式化关联数据 // 格式化关联数据
if (formattedBill.Room) { if (formattedBill.Room) {
formattedBill.Room = { formattedBill.Room = {
...formattedBill.Room, ...formattedBill.Room,
createTime: formatDate(formattedBill.Room.createTime) createTime: formatDate(formattedBill.Room.createTime),
updateTime: formatDate(formattedBill.Room.updateTime)
}; };
} }
@ -35,7 +37,7 @@ const getAllElectricityBills = async (req, res) => {
const { roomId, status, startDate, endDate, page = 1, pageSize = 10 } = req.query; const { roomId, status, startDate, endDate, page = 1, pageSize = 10 } = req.query;
// 构建查询条件 // 构建查询条件
const where = {}; const where = { isDeleted: 0 };
if (roomId) { if (roomId) {
where.roomId = roomId; where.roomId = roomId;
} }
@ -55,7 +57,12 @@ const getAllElectricityBills = async (req, res) => {
// 查询电费数据 // 查询电费数据
const { count, rows } = await ElectricityBill.findAndCountAll({ const { count, rows } = await ElectricityBill.findAndCountAll({
where, where,
include: [Room], include: [
{
model: Room,
where: { isDeleted: 0 }
}
],
limit: parseInt(pageSize), limit: parseInt(pageSize),
offset: parseInt(offset) offset: parseInt(offset)
}); });
@ -79,8 +86,14 @@ const getAllElectricityBills = async (req, res) => {
const getElectricityBillById = async (req, res) => { const getElectricityBillById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const bill = await ElectricityBill.findByPk(id, { const bill = await ElectricityBill.findOne({
include: [Room] where: { id, isDeleted: 0 },
include: [
{
model: Room,
where: { isDeleted: 0 }
}
]
}); });
if (!bill) { if (!bill) {
return res.status(404).json({ error: '电费记录不存在' }); return res.status(404).json({ error: '电费记录不存在' });
@ -125,7 +138,9 @@ const updateElectricityBill = async (req, res) => {
const { id } = req.params; const { id } = req.params;
const { startDate, endDate, startReading, endReading, unitPrice, status } = req.body; const { startDate, endDate, startReading, endReading, unitPrice, status } = req.body;
const bill = await ElectricityBill.findByPk(id); const bill = await ElectricityBill.findOne({
where: { id, isDeleted: 0 }
});
if (!bill) { if (!bill) {
return res.status(404).json({ error: '电费记录不存在' }); return res.status(404).json({ error: '电费记录不存在' });
} }
@ -156,15 +171,17 @@ const updateElectricityBill = async (req, res) => {
} }
}; };
// 删除电费记录 // 删除电费记录(软删除)
const deleteElectricityBill = async (req, res) => { const deleteElectricityBill = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const bill = await ElectricityBill.findByPk(id); const bill = await ElectricityBill.findOne({
where: { id, isDeleted: 0 }
});
if (!bill) { if (!bill) {
return res.status(404).json({ error: '电费记录不存在' }); return res.status(404).json({ error: '电费记录不存在' });
} }
await bill.destroy(); await bill.update({ isDeleted: 1 });
res.status(200).json({ message: '电费记录删除成功' }); res.status(200).json({ message: '电费记录删除成功' });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });

View File

@ -12,14 +12,17 @@ const formatDate = (date) => {
const formatRegionData = (region) => { const formatRegionData = (region) => {
return { return {
...region.toJSON(), ...region.toJSON(),
createTime: formatDate(region.createTime) createTime: formatDate(region.createTime),
updateTime: formatDate(region.updateTime)
}; };
}; };
// 获取所有区域 // 获取所有区域
const getAllRegions = async (req, res) => { const getAllRegions = async (req, res) => {
try { try {
const regions = await Region.findAll(); const regions = await Region.findAll({
where: { isDeleted: 0 }
});
const formattedRegions = regions.map(formatRegionData); const formattedRegions = regions.map(formatRegionData);
res.status(200).json(formattedRegions); res.status(200).json(formattedRegions);
} catch (error) { } catch (error) {
@ -31,7 +34,9 @@ const getAllRegions = async (req, res) => {
const getRegionById = async (req, res) => { const getRegionById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const region = await Region.findByPk(id); const region = await Region.findOne({
where: { id, isDeleted: 0 }
});
if (!region) { if (!region) {
return res.status(404).json({ error: '区域不存在' }); return res.status(404).json({ error: '区域不存在' });
} }
@ -58,7 +63,9 @@ const updateRegion = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const { name, description } = req.body; const { name, description } = req.body;
const region = await Region.findByPk(id); const region = await Region.findOne({
where: { id, isDeleted: 0 }
});
if (!region) { if (!region) {
return res.status(404).json({ error: '区域不存在' }); return res.status(404).json({ error: '区域不存在' });
} }
@ -69,15 +76,17 @@ const updateRegion = async (req, res) => {
} }
}; };
// 删除区域 // 删除区域(软删除)
const deleteRegion = async (req, res) => { const deleteRegion = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const region = await Region.findByPk(id); const region = await Region.findOne({
where: { id, isDeleted: 0 }
});
if (!region) { if (!region) {
return res.status(404).json({ error: '区域不存在' }); return res.status(404).json({ error: '区域不存在' });
} }
await region.destroy(); await region.update({ isDeleted: 1 });
res.status(200).json({ message: '区域删除成功' }); res.status(200).json({ message: '区域删除成功' });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });

View File

@ -15,7 +15,8 @@ const formatRentalData = (rental) => {
...rental.toJSON(), ...rental.toJSON(),
startDate: formatDate(rental.startDate), startDate: formatDate(rental.startDate),
endDate: formatDate(rental.endDate), endDate: formatDate(rental.endDate),
createTime: formatDate(rental.createTime) createTime: formatDate(rental.createTime),
updateTime: formatDate(rental.updateTime)
}; };
// 格式化关联数据 // 格式化关联数据
@ -24,7 +25,8 @@ const formatRentalData = (rental) => {
...formattedRental.Contract, ...formattedRental.Contract,
startDate: formatDate(formattedRental.Contract.startDate), startDate: formatDate(formattedRental.Contract.startDate),
endDate: formatDate(formattedRental.Contract.endDate), endDate: formatDate(formattedRental.Contract.endDate),
createTime: formatDate(formattedRental.Contract.createTime) createTime: formatDate(formattedRental.Contract.createTime),
updateTime: formatDate(formattedRental.Contract.updateTime)
}; };
} }
@ -42,8 +44,13 @@ const checkAndUpdateRentalStatus = async () => {
// 查找所有活跃的租房记录 // 查找所有活跃的租房记录
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { status: 'active' }, where: { status: 'active', isDeleted: 0 },
include: [Room] include: [
{
model: Room,
where: { isDeleted: 0 }
}
]
}); });
// 检查每个租房记录的状态 // 检查每个租房记录的状态
@ -81,7 +88,7 @@ const getAllRentals = async (req, res) => {
const { roomNumber, tenantName, status, page = 1, pageSize = 10 } = req.query; const { roomNumber, tenantName, status, page = 1, pageSize = 10 } = req.query;
// 构建查询条件 // 构建查询条件
const where = {}; const where = { isDeleted: 0 };
if (status) { if (status) {
where.status = status; where.status = status;
} }
@ -90,19 +97,28 @@ const getAllRentals = async (req, res) => {
const include = [ const include = [
{ {
model: Room, model: Room,
where: roomNumber ? { roomNumber: { [Op.like]: `%${roomNumber}%` }, isDeleted: 0 } : { isDeleted: 0 },
include: [ include: [
{ {
model: Apartment, model: Apartment,
include: [Region] where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 }
}
]
} }
], ]
where: roomNumber ? { roomNumber: { [Op.like]: `%${roomNumber}%` } } : {}
}, },
{ {
model: Tenant, model: Tenant,
where: tenantName ? { name: { [Op.like]: `%${tenantName}%` } } : {} where: tenantName ? { name: { [Op.like]: `%${tenantName}%` }, isDeleted: 0 } : { isDeleted: 0 }
}, },
Contract {
model: Contract,
where: { isDeleted: 0 }
}
]; ];
// 计算偏移量 // 计算偏移量
@ -135,19 +151,33 @@ const getAllRentals = async (req, res) => {
const getRentalById = async (req, res) => { const getRentalById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const rental = await Rental.findByPk(id, { const rental = await Rental.findOne({
where: { id, isDeleted: 0 },
include: [ include: [
{ {
model: Room, model: Room,
where: { isDeleted: 0 },
include: [ include: [
{ {
model: Apartment, model: Apartment,
include: [Region] where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 }
}
]
} }
] ]
}, },
Tenant, {
Contract model: Tenant,
where: { isDeleted: 0 }
},
{
model: Contract,
where: { isDeleted: 0 }
}
] ]
}); });
if (!rental) { if (!rental) {
@ -286,7 +316,9 @@ const updateRental = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const { roomId, tenantId, contractId, startDate, endDate, rent, deposit, status } = req.body; const { roomId, tenantId, contractId, startDate, endDate, rent, deposit, status } = req.body;
const rental = await Rental.findByPk(id); const rental = await Rental.findOne({
where: { id, isDeleted: 0 }
});
if (!rental) { if (!rental) {
return res.status(404).json({ error: '租房记录不存在' }); return res.status(404).json({ error: '租房记录不存在' });
} }
@ -297,15 +329,17 @@ const updateRental = async (req, res) => {
} }
}; };
// 删除租房 // 删除租房(软删除)
const deleteRental = async (req, res) => { const deleteRental = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const rental = await Rental.findByPk(id); const rental = await Rental.findOne({
where: { id, isDeleted: 0 }
});
if (!rental) { if (!rental) {
return res.status(404).json({ error: '租房记录不存在' }); return res.status(404).json({ error: '租房记录不存在' });
} }
await rental.destroy(); await rental.update({ isDeleted: 1 });
res.status(200).json({ message: '租房记录删除成功' }); res.status(200).json({ message: '租房记录删除成功' });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });

View File

@ -13,14 +13,16 @@ const formatDate = (date) => {
const formatRoomData = (room) => { const formatRoomData = (room) => {
const formattedRoom = { const formattedRoom = {
...room.toJSON(), ...room.toJSON(),
createTime: formatDate(room.createTime) createTime: formatDate(room.createTime),
updateTime: formatDate(room.updateTime)
}; };
// 格式化关联数据 // 格式化关联数据
if (formattedRoom.Apartment) { if (formattedRoom.Apartment) {
formattedRoom.Apartment = { formattedRoom.Apartment = {
...formattedRoom.Apartment, ...formattedRoom.Apartment,
createTime: formatDate(formattedRoom.Apartment.createTime) createTime: formatDate(formattedRoom.Apartment.createTime),
updateTime: formatDate(formattedRoom.Apartment.updateTime)
}; };
} }
@ -31,14 +33,16 @@ const formatRoomData = (room) => {
...rental, ...rental,
startDate: formatDate(rental.startDate), startDate: formatDate(rental.startDate),
endDate: formatDate(rental.endDate), endDate: formatDate(rental.endDate),
createTime: formatDate(rental.createTime) createTime: formatDate(rental.createTime),
updateTime: formatDate(rental.updateTime)
}; };
// 格式化租客信息 // 格式化租客信息
if (formattedRental.Tenant) { if (formattedRental.Tenant) {
formattedRental.Tenant = { formattedRental.Tenant = {
...formattedRental.Tenant, ...formattedRental.Tenant,
createTime: formatDate(formattedRental.Tenant.createTime) createTime: formatDate(formattedRental.Tenant.createTime),
updateTime: formatDate(formattedRental.Tenant.updateTime)
}; };
} }
@ -60,7 +64,7 @@ const checkAndUpdateRentalStatus = async () => {
// 查找所有活跃的租房记录 // 查找所有活跃的租房记录
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { status: 'active' } where: { status: 'active', isDeleted: 0 }
}); });
// 检查每个租房记录的状态 // 检查每个租房记录的状态
@ -73,14 +77,20 @@ const checkAndUpdateRentalStatus = async () => {
await rental.update({ status: 'expired' }); await rental.update({ status: 'expired' });
// 更新房间状态为空房 // 更新房间状态为空房
const room = await Room.findByPk(rental.roomId); const room = await Room.findByPk(rental.roomId);
if (room) { if (room && room.status === 'rented') {
await room.update({ status: 'empty' }); await room.update({ status: 'empty', subStatus: 'normal' });
} }
} else if (endDate <= tenDaysLater) { } else if (endDate <= tenDaysLater) {
// 更新房间状态为即将到期 // 更新房间附属状态为即将到期
const room = await Room.findByPk(rental.roomId); const room = await Room.findByPk(rental.roomId);
if (room && room.status === 'rented') { if (room && room.status === 'rented') {
await room.update({ status: 'soon_expire' }); await room.update({ subStatus: 'soon_expire' });
}
} else {
// 更新房间附属状态为正常
const room = await Room.findByPk(rental.roomId);
if (room && room.status === 'rented') {
await room.update({ subStatus: 'normal' });
} }
} }
} }
@ -97,10 +107,10 @@ const getAllRooms = async (req, res) => {
// 先检查并更新租房状态 // 先检查并更新租房状态
await checkAndUpdateRentalStatus(); await checkAndUpdateRentalStatus();
const { apartmentId, roomNumber, status, page = 1, pageSize = 10 } = req.query; const { apartmentId, roomNumber, status, otherStatus, subStatus, page = 1, pageSize = 10 } = req.query;
// 构建查询条件 // 构建查询条件
const where = {}; const where = { isDeleted: 0 };
if (apartmentId) { if (apartmentId) {
where.apartmentId = apartmentId; where.apartmentId = apartmentId;
} }
@ -112,6 +122,12 @@ const getAllRooms = async (req, res) => {
if (status) { if (status) {
where.status = status; where.status = status;
} }
if (otherStatus) {
where.otherStatus = otherStatus;
}
if (subStatus) {
where.subStatus = subStatus;
}
// 计算偏移量 // 计算偏移量
const offset = (page - 1) * pageSize; const offset = (page - 1) * pageSize;
@ -187,7 +203,8 @@ const getRoomById = async (req, res) => {
await checkAndUpdateRentalStatus(); await checkAndUpdateRentalStatus();
const { id } = req.params; const { id } = req.params;
const room = await Room.findByPk(id, { const room = await Room.findOne({
where: { id, isDeleted: 0 },
include: [Apartment] include: [Apartment]
}); });
if (!room) { if (!room) {
@ -238,8 +255,8 @@ const getRoomById = async (req, res) => {
// 创建房间 // 创建房间
const createRoom = async (req, res) => { const createRoom = async (req, res) => {
try { try {
const { apartmentId, roomNumber, area, price, status } = req.body; const { apartmentId, roomNumber, area, monthlyPrice, yearlyPrice, status, subStatus, otherStatus } = req.body;
const room = await Room.create({ apartmentId, roomNumber, area, price, status }); const room = await Room.create({ apartmentId, roomNumber, area, monthlyPrice, yearlyPrice, status, subStatus, otherStatus });
res.status(201).json(room); res.status(201).json(room);
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });
@ -250,27 +267,31 @@ const createRoom = async (req, res) => {
const updateRoom = async (req, res) => { const updateRoom = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const { apartmentId, roomNumber, area, price, status } = req.body; const { apartmentId, roomNumber, area, monthlyPrice, yearlyPrice, status, subStatus, otherStatus } = req.body;
const room = await Room.findByPk(id); const room = await Room.findOne({
where: { id, isDeleted: 0 }
});
if (!room) { if (!room) {
return res.status(404).json({ error: '房间不存在' }); return res.status(404).json({ error: '房间不存在' });
} }
await room.update({ apartmentId, roomNumber, area, price, status }); await room.update({ apartmentId, roomNumber, area, monthlyPrice, yearlyPrice, status, subStatus, otherStatus });
res.status(200).json(room); res.status(200).json(room);
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });
} }
}; };
// 删除房间 // 删除房间(软删除)
const deleteRoom = async (req, res) => { const deleteRoom = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const room = await Room.findByPk(id); const room = await Room.findOne({
where: { id, isDeleted: 0 }
});
if (!room) { if (!room) {
return res.status(404).json({ error: '房间不存在' }); return res.status(404).json({ error: '房间不存在' });
} }
await room.destroy(); await room.update({ isDeleted: 1 });
res.status(200).json({ message: '房间删除成功' }); res.status(200).json({ message: '房间删除成功' });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });

View File

@ -12,14 +12,17 @@ const formatDate = (date) => {
const formatTenantData = (tenant) => { const formatTenantData = (tenant) => {
return { return {
...tenant.toJSON(), ...tenant.toJSON(),
createTime: formatDate(tenant.createTime) createTime: formatDate(tenant.createTime),
updateTime: formatDate(tenant.updateTime)
}; };
}; };
// 获取所有租客 // 获取所有租客
const getAllTenants = async (req, res) => { const getAllTenants = async (req, res) => {
try { try {
const tenants = await Tenant.findAll(); const tenants = await Tenant.findAll({
where: { isDeleted: 0 }
});
const formattedTenants = tenants.map(formatTenantData); const formattedTenants = tenants.map(formatTenantData);
res.status(200).json(formattedTenants); res.status(200).json(formattedTenants);
} catch (error) { } catch (error) {
@ -31,7 +34,9 @@ const getAllTenants = async (req, res) => {
const getTenantById = async (req, res) => { const getTenantById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const tenant = await Tenant.findByPk(id); const tenant = await Tenant.findOne({
where: { id, isDeleted: 0 }
});
if (!tenant) { if (!tenant) {
return res.status(404).json({ error: '租客不存在' }); return res.status(404).json({ error: '租客不存在' });
} }
@ -58,7 +63,9 @@ const updateTenant = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const { name, phone, idCard } = req.body; const { name, phone, idCard } = req.body;
const tenant = await Tenant.findByPk(id); const tenant = await Tenant.findOne({
where: { id, isDeleted: 0 }
});
if (!tenant) { if (!tenant) {
return res.status(404).json({ error: '租客不存在' }); return res.status(404).json({ error: '租客不存在' });
} }
@ -69,15 +76,17 @@ const updateTenant = async (req, res) => {
} }
}; };
// 删除租客 // 删除租客(软删除)
const deleteTenant = async (req, res) => { const deleteTenant = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const tenant = await Tenant.findByPk(id); const tenant = await Tenant.findOne({
where: { id, isDeleted: 0 }
});
if (!tenant) { if (!tenant) {
return res.status(404).json({ error: '租客不存在' }); return res.status(404).json({ error: '租客不存在' });
} }
await tenant.destroy(); await tenant.update({ isDeleted: 1 });
res.status(200).json({ message: '租客删除成功' }); res.status(200).json({ message: '租客删除成功' });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });

View File

@ -15,14 +15,16 @@ const formatWaterBillData = (bill) => {
...bill.toJSON(), ...bill.toJSON(),
startDate: formatDate(bill.startDate), startDate: formatDate(bill.startDate),
endDate: formatDate(bill.endDate), endDate: formatDate(bill.endDate),
createTime: formatDate(bill.createTime) createTime: formatDate(bill.createTime),
updateTime: formatDate(bill.updateTime)
}; };
// 格式化关联数据 // 格式化关联数据
if (formattedBill.Room) { if (formattedBill.Room) {
formattedBill.Room = { formattedBill.Room = {
...formattedBill.Room, ...formattedBill.Room,
createTime: formatDate(formattedBill.Room.createTime) createTime: formatDate(formattedBill.Room.createTime),
updateTime: formatDate(formattedBill.Room.updateTime)
}; };
} }
@ -35,7 +37,7 @@ const getAllWaterBills = async (req, res) => {
const { roomId, status, startDate, endDate, page = 1, pageSize = 10 } = req.query; const { roomId, status, startDate, endDate, page = 1, pageSize = 10 } = req.query;
// 构建查询条件 // 构建查询条件
const where = {}; const where = { isDeleted: 0 };
if (roomId) { if (roomId) {
where.roomId = roomId; where.roomId = roomId;
} }
@ -55,7 +57,12 @@ const getAllWaterBills = async (req, res) => {
// 查询水费数据 // 查询水费数据
const { count, rows } = await WaterBill.findAndCountAll({ const { count, rows } = await WaterBill.findAndCountAll({
where, where,
include: [Room], include: [
{
model: Room,
where: { isDeleted: 0 }
}
],
limit: parseInt(pageSize), limit: parseInt(pageSize),
offset: parseInt(offset) offset: parseInt(offset)
}); });
@ -79,8 +86,14 @@ const getAllWaterBills = async (req, res) => {
const getWaterBillById = async (req, res) => { const getWaterBillById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const bill = await WaterBill.findByPk(id, { const bill = await WaterBill.findOne({
include: [Room] where: { id, isDeleted: 0 },
include: [
{
model: Room,
where: { isDeleted: 0 }
}
]
}); });
if (!bill) { if (!bill) {
return res.status(404).json({ error: '水费记录不存在' }); return res.status(404).json({ error: '水费记录不存在' });
@ -125,7 +138,9 @@ const updateWaterBill = async (req, res) => {
const { id } = req.params; const { id } = req.params;
const { startDate, endDate, startReading, endReading, unitPrice, status } = req.body; const { startDate, endDate, startReading, endReading, unitPrice, status } = req.body;
const bill = await WaterBill.findByPk(id); const bill = await WaterBill.findOne({
where: { id, isDeleted: 0 }
});
if (!bill) { if (!bill) {
return res.status(404).json({ error: '水费记录不存在' }); return res.status(404).json({ error: '水费记录不存在' });
} }
@ -156,15 +171,17 @@ const updateWaterBill = async (req, res) => {
} }
}; };
// 删除水费记录 // 删除水费记录(软删除)
const deleteWaterBill = async (req, res) => { const deleteWaterBill = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const bill = await WaterBill.findByPk(id); const bill = await WaterBill.findOne({
where: { id, isDeleted: 0 }
});
if (!bill) { if (!bill) {
return res.status(404).json({ error: '水费记录不存在' }); return res.status(404).json({ error: '水费记录不存在' });
} }
await bill.destroy(); await bill.update({ isDeleted: 1 });
res.status(200).json({ message: '水费记录删除成功' }); res.status(200).json({ message: '水费记录删除成功' });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });

View File

@ -27,6 +27,16 @@ const Apartment = sequelize.define('Apartment', {
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
} }
}, { }, {
tableName: 'apartments', tableName: 'apartments',

View File

@ -49,6 +49,16 @@ const Contract = sequelize.define('Contract', {
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
} }
}, { }, {
tableName: 'contracts', tableName: 'contracts',

View File

@ -52,6 +52,16 @@ const ElectricityBill = sequelize.define('ElectricityBill', {
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
} }
}, { }, {
tableName: 'electricity_bills', tableName: 'electricity_bills',

View File

@ -19,6 +19,16 @@ const Region = sequelize.define('Region', {
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
} }
}, { }, {
tableName: 'regions', tableName: 'regions',

View File

@ -62,6 +62,16 @@ const Rental = sequelize.define('Rental', {
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
} }
}, { }, {
tableName: 'rentals', tableName: 'rentals',

View File

@ -24,18 +24,42 @@ const Room = sequelize.define('Room', {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false
}, },
price: { monthlyPrice: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false
},
yearlyPrice: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false
}, },
status: { status: {
type: DataTypes.ENUM('empty', 'rented', 'soon_expire', 'expired', 'cleaning', 'maintenance'), type: DataTypes.ENUM('empty', 'rented'),
allowNull: false, allowNull: false,
defaultValue: 'empty' defaultValue: 'empty'
}, },
subStatus: {
type: DataTypes.ENUM('normal', 'soon_expire', 'expired'),
allowNull: false,
defaultValue: 'normal'
},
otherStatus: {
type: DataTypes.ENUM('', 'cleaning', 'maintenance'),
allowNull: false,
defaultValue: ''
},
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
} }
}, { }, {
tableName: 'rooms', tableName: 'rooms',

View File

@ -23,6 +23,16 @@ const Tenant = sequelize.define('Tenant', {
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
} }
}, { }, {
tableName: 'tenants', tableName: 'tenants',

View File

@ -52,6 +52,16 @@ const WaterBill = sequelize.define('WaterBill', {
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
} }
}, { }, {
tableName: 'water_bills', tableName: 'water_bills',

37
update_db.js Normal file
View File

@ -0,0 +1,37 @@
const mysql = require('mysql2/promise');
const fs = require('fs');
async function updateDatabase() {
try {
// 连接到数据库
const connection = await mysql.createConnection({
host: '8.152.207.41',
user: 'rentease',
password: 'Wxx@123!',
database: 'rentease'
});
console.log('成功连接到数据库');
// 读取 SQL 文件
const sqlContent = fs.readFileSync('add_fields.sql', 'utf8');
// 执行 SQL 语句
const statements = sqlContent.split(';').filter(statement => statement.trim());
for (const statement of statements) {
await connection.query(statement);
console.log(`执行 SQL: ${statement.substring(0, 50)}...`);
}
console.log('数据库表结构更新完成');
// 关闭连接
await connection.end();
console.log('数据库连接已关闭');
} catch (error) {
console.error('更新数据库表结构时出错:', error);
}
}
updateDatabase();

41
update_room_price.js Normal file
View File

@ -0,0 +1,41 @@
const mysql = require('mysql2/promise');
const fs = require('fs');
// 数据库连接配置
const dbConfig = {
host: '8.152.207.41',
user: 'root',
password: '123456',
database: 'rentease',
port: 3306
};
// 读取 SQL 文件
const sqlFilePath = './update_room_price_fields.sql';
const sqlContent = fs.readFileSync(sqlFilePath, 'utf8');
// 执行 SQL 语句
const executeSql = async () => {
let connection;
try {
// 连接数据库
connection = await mysql.createConnection(dbConfig);
console.log('成功连接到数据库');
// 执行 SQL 语句
const [results] = await connection.execute(sqlContent);
console.log('数据库表结构更新成功');
} catch (error) {
console.error('更新数据库表结构时出错:', error);
} finally {
// 关闭数据库连接
if (connection) {
await connection.end();
console.log('数据库连接已关闭');
}
}
};
// 执行脚本
executeSql();

View File

@ -0,0 +1,16 @@
-- 更新房间表结构,将原来的 price 字段改为 monthlyPrice 和 yearlyPrice 两个字段
-- 添加 monthlyPrice 字段
ALTER TABLE rooms ADD COLUMN monthlyPrice DECIMAL(10, 2) NOT NULL DEFAULT 0 AFTER area;
-- 添加 yearlyPrice 字段
ALTER TABLE rooms ADD COLUMN yearlyPrice DECIMAL(10, 2) NOT NULL DEFAULT 0 AFTER monthlyPrice;
-- 将原来的 price 字段值复制到 monthlyPrice 字段
UPDATE rooms SET monthlyPrice = price;
-- 计算年租金并更新 yearlyPrice 字段(月租金 * 12
UPDATE rooms SET yearlyPrice = monthlyPrice * 12;
-- 删除原来的 price 字段
ALTER TABLE rooms DROP COLUMN price;