This commit is contained in:
wangxiaoxian 2026-03-05 23:26:13 +08:00
parent 6195a34212
commit 05cfcc1809
33 changed files with 279 additions and 1493 deletions

View File

@ -1,53 +0,0 @@
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();

View File

@ -1,31 +0,0 @@
-- 为 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;

4
app.js
View File

@ -6,8 +6,6 @@ const sequelize = require('./config/db');
const regionRoutes = require('./routes/region'); const regionRoutes = require('./routes/region');
const apartmentRoutes = require('./routes/apartment'); const apartmentRoutes = require('./routes/apartment');
const roomRoutes = require('./routes/room'); const roomRoutes = require('./routes/room');
const tenantRoutes = require('./routes/tenant');
const contractRoutes = require('./routes/contract');
const rentalRoutes = require('./routes/rental'); const rentalRoutes = require('./routes/rental');
const statisticsRoutes = require('./routes/statistics'); const statisticsRoutes = require('./routes/statistics');
const waterBillRoutes = require('./routes/waterBill'); const waterBillRoutes = require('./routes/waterBill');
@ -25,8 +23,6 @@ app.use(express.urlencoded({ extended: true }));
app.use('/api/regions', regionRoutes); app.use('/api/regions', regionRoutes);
app.use('/api/apartments', apartmentRoutes); app.use('/api/apartments', apartmentRoutes);
app.use('/api/rooms', roomRoutes); app.use('/api/rooms', roomRoutes);
app.use('/api/tenants', tenantRoutes);
app.use('/api/contracts', contractRoutes);
app.use('/api/rentals', rentalRoutes); app.use('/api/rentals', rentalRoutes);
app.use('/api/statistics', statisticsRoutes); app.use('/api/statistics', statisticsRoutes);
app.use('/api/water-bills', waterBillRoutes); app.use('/api/water-bills', waterBillRoutes);

View File

@ -1,61 +0,0 @@
const sequelize = require('./config/db');
const { Region, Apartment, Room, Tenant, Contract, Rental } = require('./models');
// 检查数据库数据的函数
async function checkData() {
try {
console.log('开始检查数据库数据...');
// 检查区域数据
const regions = await Region.findAll();
console.log(`区域数据数量: ${regions.length}`);
regions.forEach(region => {
console.log(`区域: ${region.name}`);
});
// 检查公寓数据
const apartments = await Apartment.findAll();
console.log(`\n公寓数据数量: ${apartments.length}`);
apartments.forEach(apartment => {
console.log(`公寓: ${apartment.name}`);
});
// 检查房间数据
const rooms = await Room.findAll();
console.log(`\n房间数据数量: ${rooms.length}`);
rooms.forEach(room => {
console.log(`房间: ${room.roomNumber}`);
});
// 检查租客数据
const tenants = await Tenant.findAll();
console.log(`\n租客数据数量: ${tenants.length}`);
tenants.forEach(tenant => {
console.log(`租客: ${tenant.name}`);
});
// 检查合同数据
const contracts = await Contract.findAll();
console.log(`\n合同数据数量: ${contracts.length}`);
contracts.forEach(contract => {
console.log(`合同 ID: ${contract.id}`);
});
// 检查租房数据
const rentals = await Rental.findAll();
console.log(`\n租房数据数量: ${rentals.length}`);
rentals.forEach(rental => {
console.log(`租房 ID: ${rental.id}`);
});
console.log('\n数据检查完成');
} catch (error) {
console.error('检查数据时出错:', error);
} finally {
// 关闭数据库连接
await sequelize.close();
}
}
// 执行检查操作
checkData();

View File

@ -1,36 +0,0 @@
const sequelize = require('./config/db');
const { Room, Rental, Tenant, Contract } = require('./models');
// 清空数据的函数
async function clearData() {
try {
console.log('开始清空数据...');
// 按照依赖关系的顺序删除数据
// 先删除租房记录(依赖于房间、租客和合同)
await Rental.destroy({ where: {} });
console.log('租房数据已删除');
// 删除合同记录(依赖于房间和租客)
await Contract.destroy({ where: {} });
console.log('合同数据已删除');
// 删除房间记录(依赖于公寓)
await Room.destroy({ where: {} });
console.log('房间数据已删除');
// 删除租客记录(无依赖)
await Tenant.destroy({ where: {} });
console.log('租客数据已删除');
console.log('数据清空完成!');
} catch (error) {
console.error('清空数据时出错:', error);
} finally {
// 关闭数据库连接
await sequelize.close();
}
}
// 执行清空操作
clearData();

View File

@ -1,18 +1,40 @@
const { Sequelize } = require('sequelize'); const { Sequelize } = require('sequelize');
const mysql = require('mysql2/promise'); const mysql = require('mysql2/promise');
// 环境配置
const NODE_ENV = 'development';
// 数据库配置
const dbConfig = {
development: {
host: 'localhost',
user: 'root',
password: '123456',
database: 'rentease'
},
production: {
host: '8.152.207.41',
user: 'rentease',
password: 'Wxx@123!',
database: 'rentease'
}
};
// 获取当前环境的配置
const currentConfig = dbConfig[NODE_ENV];
// 先创建数据库 // 先创建数据库
const createDatabase = async () => { const createDatabase = async () => {
try { try {
// 连接到MySQL服务器 // 连接到MySQL服务器
const connection = await mysql.createConnection({ const connection = await mysql.createConnection({
host: '8.152.207.41', host: currentConfig.host,
user: 'rentease', user: currentConfig.user,
password: 'Wxx@123!' password: currentConfig.password
}); });
// 创建数据库 // 创建数据库
await connection.query('CREATE DATABASE IF NOT EXISTS rentease'); await connection.query(`CREATE DATABASE IF NOT EXISTS ${currentConfig.database}`);
console.log('数据库创建成功'); console.log('数据库创建成功');
await connection.end(); await connection.end();
return true; return true;
@ -24,11 +46,11 @@ const createDatabase = async () => {
// 创建数据库连接 - 使用MySQL // 创建数据库连接 - 使用MySQL
const sequelize = new Sequelize( const sequelize = new Sequelize(
'rentease', // 数据库名称 currentConfig.database, // 数据库名称
'rentease', // 用户名 currentConfig.user, // 用户名
'Wxx@123!', // 密码 currentConfig.password, // 密码
{ {
host: '8.152.207.41', host: currentConfig.host,
dialect: 'mysql', dialect: 'mysql',
logging: false, logging: false,
timezone: '+08:00' timezone: '+08:00'
@ -41,11 +63,11 @@ const testConnection = async () => {
await createDatabase(); await createDatabase();
// 重新创建sequelize实例确保连接管理器是活跃的 // 重新创建sequelize实例确保连接管理器是活跃的
const newSequelize = new Sequelize( const newSequelize = new Sequelize(
'rentease', // 数据库名称 currentConfig.database, // 数据库名称
'rentease', // 用户名 currentConfig.user, // 用户名
'Wxx@123!', // 密码 currentConfig.password, // 密码
{ {
host: '8.152.207.41', host: currentConfig.host,
dialect: 'mysql', dialect: 'mysql',
logging: false, logging: false,
timezone: '+08:00' timezone: '+08:00'

View File

@ -1,5 +1,5 @@
const sequelize = require('./db'); const sequelize = require('./db');
const { Region, Apartment, Room, Tenant, Contract, Rental } = require('../models'); const { Region, Apartment, Room, Rental } = require('../models');
// 同步数据库表结构 // 同步数据库表结构
const syncDatabase = async () => { const syncDatabase = async () => {

View File

@ -1,183 +0,0 @@
const { Contract, Room, Tenant, Apartment, Region } = require('../models');
// 格式化时间(考虑时区,转换为北京时间)
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 formatContractData = (contract) => {
const formattedContract = {
...contract.toJSON(),
startDate: formatDate(contract.startDate),
endDate: formatDate(contract.endDate),
createTime: formatDate(contract.createTime),
updateTime: formatDate(contract.updateTime)
};
// 格式化关联数据
if (formattedContract.Room) {
formattedContract.Room = {
...formattedContract.Room,
createTime: formatDate(formattedContract.Room.createTime),
updateTime: formatDate(formattedContract.Room.updateTime)
};
if (formattedContract.Room.Apartment) {
formattedContract.Room.Apartment = {
...formattedContract.Room.Apartment,
createTime: formatDate(formattedContract.Room.Apartment.createTime),
updateTime: formatDate(formattedContract.Room.Apartment.updateTime)
};
if (formattedContract.Room.Apartment.Region) {
formattedContract.Room.Apartment.Region = {
...formattedContract.Room.Apartment.Region,
createTime: formatDate(formattedContract.Room.Apartment.Region.createTime),
updateTime: formatDate(formattedContract.Room.Apartment.Region.updateTime)
};
}
}
}
if (formattedContract.Tenant) {
formattedContract.Tenant = {
...formattedContract.Tenant,
createTime: formatDate(formattedContract.Tenant.createTime),
updateTime: formatDate(formattedContract.Tenant.updateTime)
};
}
return formattedContract;
};
// 获取所有合同
const getAllContracts = async (req, res) => {
try {
const contracts = await Contract.findAll({
where: { isDeleted: 0 },
include: [
{
model: Room,
where: { isDeleted: 0 },
include: [
{
model: Apartment,
where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 }
}
]
}
]
},
{
model: Tenant,
where: { isDeleted: 0 }
}
]
});
const formattedContracts = contracts.map(formatContractData);
res.status(200).json(formattedContracts);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 获取单个合同
const getContractById = async (req, res) => {
try {
const { id } = req.params;
const contract = await Contract.findOne({
where: { id, isDeleted: 0 },
include: [
{
model: Room,
where: { isDeleted: 0 },
include: [
{
model: Apartment,
where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 }
}
]
}
]
},
{
model: Tenant,
where: { isDeleted: 0 }
}
]
});
if (!contract) {
return res.status(404).json({ error: '合同不存在' });
}
const formattedContract = formatContractData(contract);
res.status(200).json(formattedContract);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 创建合同
const createContract = async (req, res) => {
try {
const { roomId, tenantId, startDate, endDate, rent, deposit, status } = req.body;
const contract = await Contract.create({ roomId, tenantId, startDate, endDate, rent, deposit, status });
res.status(201).json(contract);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 更新合同
const updateContract = async (req, res) => {
try {
const { id } = req.params;
const { roomId, tenantId, startDate, endDate, rent, deposit, status } = req.body;
const contract = await Contract.findOne({
where: { id, isDeleted: 0 }
});
if (!contract) {
return res.status(404).json({ error: '合同不存在' });
}
await contract.update({ roomId, tenantId, startDate, endDate, rent, deposit, status });
res.status(200).json(contract);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 删除合同(软删除)
const deleteContract = async (req, res) => {
try {
const { id } = req.params;
const contract = await Contract.findOne({
where: { id, isDeleted: 0 }
});
if (!contract) {
return res.status(404).json({ error: '合同不存在' });
}
await contract.update({ isDeleted: 1 });
res.status(200).json({ message: '合同删除成功' });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
module.exports = {
getAllContracts,
getContractById,
createContract,
updateContract,
deleteContract
};

View File

@ -1,4 +1,4 @@
const { Rental, Room, Tenant, Contract, Apartment, Region } = require('../models'); const { Rental, Room, Apartment, Region } = require('../models');
const { Op } = require('sequelize'); const { Op } = require('sequelize');
// 格式化时间(考虑时区,转换为北京时间) // 格式化时间(考虑时区,转换为北京时间)
@ -19,17 +19,6 @@ const formatRentalData = (rental) => {
updateTime: formatDate(rental.updateTime) updateTime: formatDate(rental.updateTime)
}; };
// 格式化关联数据
if (formattedRental.Contract) {
formattedRental.Contract = {
...formattedRental.Contract,
startDate: formatDate(formattedRental.Contract.startDate),
endDate: formatDate(formattedRental.Contract.endDate),
createTime: formatDate(formattedRental.Contract.createTime),
updateTime: formatDate(formattedRental.Contract.updateTime)
};
}
return formattedRental; return formattedRental;
}; };
@ -101,17 +90,28 @@ const getAllRentals = async (req, res) => {
if (roomId) { if (roomId) {
where.roomId = roomId; where.roomId = roomId;
} }
if (tenantName) {
where.tenantName = { [Op.like]: `%${tenantName}%` };
}
// 构建包含关系 - 关联租客信息和合同信息 // 构建包含关系
const include = [ const include = [
{ {
model: Tenant, model: Room,
where: tenantName ? { name: { [Op.like]: `%${tenantName}%` }, isDeleted: 0 } : { isDeleted: 0 } where: { isDeleted: 0 },
}, include: [
{ {
model: Contract, model: Apartment,
where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 } where: { isDeleted: 0 }
} }
]
}
]
}
]; ];
// 计算偏移量 // 计算偏移量
@ -163,14 +163,6 @@ const getRentalById = async (req, res) => {
] ]
} }
] ]
},
{
model: Tenant,
where: { isDeleted: 0 }
},
{
model: Contract,
where: { isDeleted: 0 }
} }
] ]
}); });
@ -220,60 +212,13 @@ const createRental = async (req, res) => {
return res.status(400).json({ error: '无效的房间ID' }); return res.status(400).json({ error: '无效的房间ID' });
} }
// 先查找或创建租客
let tenant;
if (body.tenantIdCard) {
tenant = await Tenant.findOne({ where: { idCard: body.tenantIdCard } });
}
if (!tenant) {
console.log('创建新租客:', { name: body.tenantName, phone: body.tenantPhone, idCard: body.tenantIdCard });
tenant = await Tenant.create({
name: body.tenantName,
phone: body.tenantPhone,
idCard: body.tenantIdCard
});
}
console.log('租客信息:', tenant);
// 确保租客创建成功
if (!tenant || !tenant.id) {
return res.status(500).json({ error: '创建租客失败' });
}
// 处理押金为空时设置为0 // 处理押金为空时设置为0
const deposit = body.deposit || 0; const deposit = body.deposit || 0;
// 创建合同
console.log('创建合同:', {
roomId: parsedRoomId,
tenantId: tenant.id,
startDate: body.startDate,
endDate: body.endDate,
rent: body.rent,
deposit: deposit,
status: body.status || 'active'
});
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'
});
console.log('合同信息:', contract);
// 确保合同创建成功
if (!contract || !contract.id) {
return res.status(500).json({ error: '创建合同失败' });
}
// 创建租房记录 // 创建租房记录
console.log('创建租房记录:', { console.log('创建租房记录:', {
roomId: parsedRoomId, roomId: parsedRoomId,
tenantId: tenant.id, tenantName: body.tenantName,
contractId: contract.id,
startDate: body.startDate, startDate: body.startDate,
endDate: body.endDate, endDate: body.endDate,
rent: body.rent, rent: body.rent,
@ -281,11 +226,9 @@ const createRental = async (req, res) => {
status: body.status || 'active' status: body.status || 'active'
}); });
// 直接使用具体的数值创建租房记录
const rental = await Rental.create({ const rental = await Rental.create({
roomId: parsedRoomId, roomId: parsedRoomId,
tenantId: tenant.id, tenantName: body.tenantName,
contractId: contract.id,
startDate: body.startDate, startDate: body.startDate,
endDate: body.endDate, endDate: body.endDate,
rent: body.rent, rent: body.rent,
@ -309,7 +252,7 @@ const createRental = async (req, res) => {
const updateRental = async (req, res) => { 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, tenantName, startDate, endDate, rent, deposit, status } = req.body;
const rental = await Rental.findOne({ const rental = await Rental.findOne({
where: { id, isDeleted: 0 } where: { id, isDeleted: 0 }
}); });
@ -318,7 +261,7 @@ const updateRental = async (req, res) => {
} }
// 处理押金为空时设置为0 // 处理押金为空时设置为0
const updateDeposit = deposit || 0; const updateDeposit = deposit || 0;
await rental.update({ roomId, tenantId, contractId, startDate, endDate, rent, deposit: updateDeposit, status }); await rental.update({ roomId, tenantName, startDate, endDate, rent, deposit: updateDeposit, status });
res.status(200).json(rental); res.status(200).json(rental);
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });
@ -358,17 +301,28 @@ const listRentals = async (req, res) => {
if (roomId) { if (roomId) {
where.roomId = roomId; where.roomId = roomId;
} }
if (tenantName) {
where.tenantName = { [Op.like]: `%${tenantName}%` };
}
// 构建包含关系 - 关联租客信息和合同信息 // 构建包含关系
const include = [ const include = [
{ {
model: Tenant, model: Room,
where: tenantName ? { name: { [Op.like]: `%${tenantName}%` }, isDeleted: 0 } : { isDeleted: 0 } where: { isDeleted: 0 },
}, include: [
{ {
model: Contract, model: Apartment,
where: { isDeleted: 0 },
include: [
{
model: Region,
where: { isDeleted: 0 } where: { isDeleted: 0 }
} }
]
}
]
}
]; ];
// 查询租房数据 // 查询租房数据

View File

@ -37,15 +37,6 @@ const formatRoomData = (room) => {
updateTime: formatDate(rental.updateTime) updateTime: formatDate(rental.updateTime)
}; };
// 格式化租客信息
if (formattedRental.Tenant) {
formattedRental.Tenant = {
...formattedRental.Tenant,
createTime: formatDate(formattedRental.Tenant.createTime),
updateTime: formatDate(formattedRental.Tenant.updateTime)
};
}
return formattedRental; return formattedRental;
}); });
} }
@ -62,7 +53,7 @@ const checkAndUpdateRentalStatus = async () => {
const tenDaysLater = new Date(); const tenDaysLater = new Date();
tenDaysLater.setDate(currentDate.getDate() + 30); tenDaysLater.setDate(currentDate.getDate() + 30);
// 查找所有活跃的租房记录 // 查找所有在租的租房记录
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { status: 'active', isDeleted: 0 } where: { status: 'active', isDeleted: 0 }
}); });
@ -149,8 +140,7 @@ const getAllRooms = async (req, res) => {
where: { where: {
roomId: room.id, roomId: room.id,
status: { [Op.ne]: 'expired' } status: { [Op.ne]: 'expired' }
}, }
include: ['Tenant']
}); });
// 格式化租房信息 // 格式化租房信息
@ -163,14 +153,6 @@ const getAllRooms = async (req, res) => {
createTime: formatDate(rental.createTime) createTime: formatDate(rental.createTime)
}; };
// 格式化租客信息
if (formattedRental.Tenant) {
formattedRental.Tenant = {
...formattedRental.Tenant,
createTime: formatDate(formattedRental.Tenant.createTime)
};
}
return formattedRental; return formattedRental;
}); });
} else { } else {
@ -217,8 +199,7 @@ const getRoomById = async (req, res) => {
where: { where: {
roomId: room.id, roomId: room.id,
status: { [Op.ne]: 'expired' } status: { [Op.ne]: 'expired' }
}, }
include: ['Tenant']
}); });
// 格式化租房信息 // 格式化租房信息
@ -231,14 +212,6 @@ const getRoomById = async (req, res) => {
createTime: formatDate(rental.createTime) createTime: formatDate(rental.createTime)
}; };
// 格式化租客信息
if (formattedRental.Tenant) {
formattedRental.Tenant = {
...formattedRental.Tenant,
createTime: formatDate(formattedRental.Tenant.createTime)
};
}
return formattedRental; return formattedRental;
}); });
} else { } else {
@ -254,7 +227,18 @@ const getRoomById = async (req, res) => {
const createRoom = async (req, res) => { const createRoom = async (req, res) => {
try { try {
const { apartmentId, roomNumber, area, monthlyPrice, yearlyPrice, status, subStatus, otherStatus } = req.body; const { apartmentId, roomNumber, area, monthlyPrice, yearlyPrice, status, subStatus, otherStatus } = req.body;
const room = await Room.create({ apartmentId, roomNumber, area, monthlyPrice, yearlyPrice, status, subStatus, otherStatus }); // 处理空值
const processedData = {
apartmentId,
roomNumber,
area: area === '' ? null : area,
monthlyPrice: monthlyPrice === '' ? null : monthlyPrice,
yearlyPrice: yearlyPrice === '' ? null : yearlyPrice,
status,
subStatus,
otherStatus
};
const room = await Room.create(processedData);
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 });
@ -272,7 +256,18 @@ const updateRoom = async (req, res) => {
if (!room) { if (!room) {
return res.status(404).json({ error: '房间不存在' }); return res.status(404).json({ error: '房间不存在' });
} }
await room.update({ apartmentId, roomNumber, area, monthlyPrice, yearlyPrice, status, subStatus, otherStatus }); // 处理空值
const processedData = {
apartmentId,
roomNumber,
area: area === '' ? null : area,
monthlyPrice: monthlyPrice === '' ? null : monthlyPrice,
yearlyPrice: yearlyPrice === '' ? null : yearlyPrice,
status,
subStatus,
otherStatus
};
await room.update(processedData);
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 });

View File

@ -4,9 +4,6 @@ const { Op } = require('sequelize');
// 租金统计 // 租金统计
const getRentStatistics = async (req, res) => { const getRentStatistics = async (req, res) => {
try { try {
// 导入Contract模型
const { Contract } = require('../models');
// 计算过去12个月的开始日期 // 计算过去12个月的开始日期
const now = new Date(); const now = new Date();
const startDate = new Date(now.getFullYear(), now.getMonth() - 11, 1); // 12个月前的第一天 const startDate = new Date(now.getFullYear(), now.getMonth() - 11, 1); // 12个月前的第一天
@ -19,22 +16,23 @@ const getRentStatistics = async (req, res) => {
monthlyRent[monthKey] = 0; monthlyRent[monthKey] = 0;
} }
// 从数据库查询过去12个月的合同记录 // 从数据库查询过去12个月的租赁记录(排除已删除的)
const contracts = await Contract.findAll({ const rentals = await Rental.findAll({
where: { where: {
createTime: { createTime: {
[Op.gte]: startDate [Op.gte]: startDate
} },
isDeleted: 0
} }
}); });
// 按月份统计已收租金 // 按月份统计已收租金
contracts.forEach(contract => { rentals.forEach(rental => {
// 检查租金是否有效 // 检查租金是否有效
const rentAmount = parseFloat(contract.rent) || 0; const rentAmount = parseFloat(rental.rent) || 0;
if (rentAmount > 0 && contract.createTime) { if (rentAmount > 0 && rental.createTime) {
// 解析创建时间 // 解析创建时间
const createDate = new Date(contract.createTime); const createDate = new Date(rental.createTime);
const monthKey = `${createDate.getFullYear()}-${(createDate.getMonth() + 1).toString().padStart(2, '0')}`; const monthKey = `${createDate.getFullYear()}-${(createDate.getMonth() + 1).toString().padStart(2, '0')}`;
// 如果该月份在我们的统计范围内,添加租金 // 如果该月份在我们的统计范围内,添加租金
@ -62,8 +60,8 @@ const getRentStatistics = async (req, res) => {
// 房间状态统计 // 房间状态统计
const getRoomStatusStatistics = async (req, res) => { const getRoomStatusStatistics = async (req, res) => {
try { try {
// 获取所有房间 // 获取所有房间(排除已删除的)
const rooms = await Room.findAll(); const rooms = await Room.findAll({ where: { isDeleted: 0 } });
// 初始化统计数据 // 初始化统计数据
let empty = 0; let empty = 0;
@ -113,10 +111,15 @@ const getRoomStatusStatistics = async (req, res) => {
const getRegionHouseStatistics = async (req, res) => { const getRegionHouseStatistics = async (req, res) => {
try { try {
const regions = await Region.findAll({ const regions = await Region.findAll({
where: { isDeleted: 0 },
include: [ include: [
{ {
model: Apartment, model: Apartment,
include: [Room] where: { isDeleted: 0 },
include: [{
model: Room,
where: { isDeleted: 0 }
}]
} }
] ]
}); });
@ -173,10 +176,15 @@ const getRegionHouseStatistics = async (req, res) => {
const getRegionApartmentHouseStatistics = async (req, res) => { const getRegionApartmentHouseStatistics = async (req, res) => {
try { try {
const regions = await Region.findAll({ const regions = await Region.findAll({
where: { isDeleted: 0 },
include: [ include: [
{ {
model: Apartment, model: Apartment,
include: [Room] where: { isDeleted: 0 },
include: [{
model: Room,
where: { isDeleted: 0 }
}]
} }
] ]
}); });
@ -236,21 +244,21 @@ const getRegionApartmentHouseStatistics = async (req, res) => {
const getDashboardStatistics = async (req, res) => { const getDashboardStatistics = async (req, res) => {
try { try {
// 导入所有需要的模型 // 导入所有需要的模型
const { Region, Apartment, Room, Tenant, Contract, WaterBill, Rental } = require('../models'); const { Region, Apartment, Room, WaterBill, Rental } = require('../models');
// 并行查询所有统计数据 // 并行查询所有统计数据
const [regionCount, apartmentCount, roomCount, tenantCount, contractCount, emptyRoomCount, rentedRoomCount, collectedRentAmount, collectedWaterAmount] = await Promise.all([ const [regionCount, apartmentCount, roomCount, emptyRoomCount, rentedRoomCount, soonExpireRoomCount, expiredRoomCount, collectedRentAmount, collectedWaterAmount] = await Promise.all([
Region.count(), Region.count({ where: { isDeleted: 0 } }),
Apartment.count(), Apartment.count({ where: { isDeleted: 0 } }),
Room.count(), Room.count({ where: { isDeleted: 0 } }),
Tenant.count(), Room.count({ where: { status: 'empty', isDeleted: 0 } }),
Contract.count(), Room.count({ where: { status: 'rented', isDeleted: 0 } }),
Room.count({ where: { status: 'empty' } }), Room.count({ where: { status: 'rented', subStatus: 'soon_expire', isDeleted: 0 } }),
Room.count({ where: { status: 'rented' } }), Room.count({ where: { status: 'rented', subStatus: 'expired', isDeleted: 0 } }),
// 统计已收租金 // 统计已收租金(排除已删除的)
Rental.sum('rent', { where: { status: 'active' } }), Rental.sum('rent', { where: { isDeleted: 0 } }),
// 统计已收水费 // 统计已收水费(排除已删除的)
WaterBill.sum('amount', { where: { status: 'paid' } }) WaterBill.sum('amount', { where: { status: 'paid', isDeleted: 0 } })
]); ]);
// 构造响应数据 // 构造响应数据
@ -258,10 +266,10 @@ const getDashboardStatistics = async (req, res) => {
regionCount, regionCount,
apartmentCount, apartmentCount,
roomCount, roomCount,
tenantCount,
contractCount,
emptyRoomCount, emptyRoomCount,
rentedRoomCount, rentedRoomCount,
soonExpireRoomCount,
expiredRoomCount,
collectedRentAmount: parseFloat(collectedRentAmount) || 0, collectedRentAmount: parseFloat(collectedRentAmount) || 0,
collectedWaterAmount: parseFloat(collectedWaterAmount) || 0 collectedWaterAmount: parseFloat(collectedWaterAmount) || 0
}; };

View File

@ -1,135 +0,0 @@
const { Tenant } = 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 formatTenantData = (tenant) => {
return {
...tenant.toJSON(),
createTime: formatDate(tenant.createTime),
updateTime: formatDate(tenant.updateTime)
};
};
// 获取所有租客
const getAllTenants = async (req, res) => {
try {
const tenants = await Tenant.findAll({
where: { isDeleted: 0 }
});
const formattedTenants = tenants.map(formatTenantData);
res.status(200).json(formattedTenants);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 获取单个租客
const getTenantById = async (req, res) => {
try {
const { id } = req.params;
const tenant = await Tenant.findOne({
where: { id, isDeleted: 0 }
});
if (!tenant) {
return res.status(404).json({ error: '租客不存在' });
}
const formattedTenant = formatTenantData(tenant);
res.status(200).json(formattedTenant);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 创建租客
const createTenant = async (req, res) => {
try {
const { name, phone, idCard } = req.body;
const tenant = await Tenant.create({ name, phone, idCard });
res.status(201).json(tenant);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 更新租客
const updateTenant = async (req, res) => {
try {
const { id } = req.params;
const { name, phone, idCard } = req.body;
const tenant = await Tenant.findOne({
where: { id, isDeleted: 0 }
});
if (!tenant) {
return res.status(404).json({ error: '租客不存在' });
}
await tenant.update({ name, phone, idCard });
res.status(200).json(tenant);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 删除租客(软删除)
const deleteTenant = async (req, res) => {
try {
const { id } = req.params;
const tenant = await Tenant.findOne({
where: { id, isDeleted: 0 }
});
if (!tenant) {
return res.status(404).json({ error: '租客不存在' });
}
await tenant.update({ isDeleted: 1 });
res.status(200).json({ message: '租客删除成功' });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 获取所有租客(不分页)
const listTenants = async (req, res) => {
try {
const { name, phone, idCard } = req.query;
// 构建查询条件
const where = { isDeleted: 0 };
if (name) {
where.name = {
[Op.like]: `%${name}%`
};
}
if (phone) {
where.phone = {
[Op.like]: `%${phone}%`
};
}
if (idCard) {
where.idCard = {
[Op.like]: `%${idCard}%`
};
}
const tenants = await Tenant.findAll({ where });
const formattedTenants = tenants.map(formatTenantData);
res.status(200).json(formattedTenants);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
module.exports = {
getAllTenants,
listTenants,
getTenantById,
createTenant,
updateTenant,
deleteTenant
};

View File

@ -6,7 +6,8 @@ const Apartment = sequelize.define('Apartment', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true,
comment: '公寓ID'
}, },
regionId: { regionId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
@ -14,29 +15,35 @@ const Apartment = sequelize.define('Apartment', {
references: { references: {
model: Region, model: Region,
key: 'id' key: 'id'
} },
comment: '所属区域ID'
}, },
name: { name: {
type: DataTypes.STRING(50), type: DataTypes.STRING(50),
allowNull: false allowNull: false,
comment: '公寓名称'
}, },
address: { address: {
type: DataTypes.STRING(255), type: DataTypes.STRING(255),
allowNull: true allowNull: true,
comment: '公寓地址'
}, },
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW,
comment: '创建时间'
}, },
updateTime: { updateTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW, defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW onUpdate: DataTypes.NOW,
comment: '更新时间'
}, },
isDeleted: { isDeleted: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: 0 defaultValue: 0,
comment: '删除状态0未删除1已删除'
} }
}, { }, {
tableName: 'apartments', tableName: 'apartments',

View File

@ -1,72 +0,0 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/db');
const Room = require('./Room');
const Tenant = require('./Tenant');
const Contract = sequelize.define('Contract', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
roomId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: Room,
key: 'id'
}
},
tenantId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: Tenant,
key: 'id'
}
},
startDate: {
type: DataTypes.DATE,
allowNull: false
},
endDate: {
type: DataTypes.DATE,
allowNull: false
},
rent: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false
},
deposit: {
type: DataTypes.DECIMAL(10, 2),
allowNull: true
},
status: {
type: DataTypes.ENUM('active', 'expired'),
allowNull: false,
defaultValue: 'active'
},
createTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
}
}, {
tableName: 'contracts',
timestamps: false
});
// 建立关联
Contract.belongsTo(Room, { foreignKey: 'roomId' });
Contract.belongsTo(Tenant, { foreignKey: 'tenantId' });
module.exports = Contract;

View File

@ -6,7 +6,8 @@ const ElectricityBill = sequelize.define('ElectricityBill', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true,
comment: '电费账单ID'
}, },
roomId: { roomId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
@ -14,54 +15,66 @@ const ElectricityBill = sequelize.define('ElectricityBill', {
references: { references: {
model: Room, model: Room,
key: 'id' key: 'id'
} },
comment: '房间ID'
}, },
startDate: { startDate: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: false allowNull: false,
comment: '开始日期'
}, },
endDate: { endDate: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: false allowNull: false,
comment: '结束日期'
}, },
startReading: { startReading: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '起始读数'
}, },
endReading: { endReading: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '结束读数'
}, },
usage: { usage: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '用电量'
}, },
unitPrice: { unitPrice: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '单价'
}, },
amount: { amount: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '金额'
}, },
status: { status: {
type: DataTypes.ENUM('unpaid', 'paid'), type: DataTypes.ENUM('unpaid', 'paid'),
allowNull: false, allowNull: false,
defaultValue: 'unpaid' defaultValue: 'unpaid',
comment: '状态unpaid未支付paid已支付'
}, },
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW,
comment: '创建时间'
}, },
updateTime: { updateTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW, defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW onUpdate: DataTypes.NOW,
comment: '更新时间'
}, },
isDeleted: { isDeleted: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: 0 defaultValue: 0,
comment: '删除状态0未删除1已删除'
} }
}, { }, {
tableName: 'electricity_bills', tableName: 'electricity_bills',

View File

@ -5,30 +5,36 @@ const Region = sequelize.define('Region', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true,
comment: '区域ID'
}, },
name: { name: {
type: DataTypes.STRING(50), type: DataTypes.STRING(50),
allowNull: false, allowNull: false,
unique: true unique: true,
comment: '区域名称'
}, },
description: { description: {
type: DataTypes.TEXT, type: DataTypes.TEXT,
allowNull: true allowNull: true,
comment: '区域描述'
}, },
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW,
comment: '创建时间'
}, },
updateTime: { updateTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW, defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW onUpdate: DataTypes.NOW,
comment: '更新时间'
}, },
isDeleted: { isDeleted: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: 0 defaultValue: 0,
comment: '删除状态0未删除1已删除'
} }
}, { }, {
tableName: 'regions', tableName: 'regions',

View File

@ -1,14 +1,13 @@
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const sequelize = require('../config/db'); const sequelize = require('../config/db');
const Room = require('./Room'); const Room = require('./Room');
const Tenant = require('./Tenant');
const Contract = require('./Contract');
const Rental = sequelize.define('Rental', { const Rental = sequelize.define('Rental', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true,
comment: '租赁记录ID'
}, },
roomId: { roomId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
@ -16,62 +15,61 @@ const Rental = sequelize.define('Rental', {
references: { references: {
model: Room, model: Room,
key: 'id' key: 'id'
}
}, },
tenantId: { comment: '房间ID'
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: Tenant,
key: 'id'
}
}, },
contractId: { tenantName: {
type: DataTypes.INTEGER, type: DataTypes.STRING(50),
allowNull: false, allowNull: false,
references: { comment: '租客姓名'
model: Contract,
key: 'id'
}
}, },
startDate: { startDate: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: false allowNull: false,
comment: '开始日期'
}, },
endDate: { endDate: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: false allowNull: false,
comment: '结束日期'
}, },
rent: { rent: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '租金'
}, },
deposit: { deposit: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: true allowNull: true,
comment: '押金'
}, },
status: { status: {
type: DataTypes.ENUM('active', 'expired'), type: DataTypes.ENUM('active', 'expired'),
allowNull: false, allowNull: false,
defaultValue: 'active' defaultValue: 'active',
comment: '租赁状态active在租expired已过期'
}, },
remark: { remark: {
type: DataTypes.TEXT, type: DataTypes.TEXT,
allowNull: true allowNull: true,
comment: '备注'
}, },
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW,
comment: '创建时间'
}, },
updateTime: { updateTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW, defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW onUpdate: DataTypes.NOW,
comment: '更新时间'
}, },
isDeleted: { isDeleted: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: 0 defaultValue: 0,
comment: '删除状态0未删除1已删除'
} }
}, { }, {
tableName: 'rentals', tableName: 'rentals',
@ -80,7 +78,5 @@ const Rental = sequelize.define('Rental', {
// 建立关联 // 建立关联
Rental.belongsTo(Room, { foreignKey: 'roomId' }); Rental.belongsTo(Room, { foreignKey: 'roomId' });
Rental.belongsTo(Tenant, { foreignKey: 'tenantId' });
Rental.belongsTo(Contract, { foreignKey: 'contractId' });
module.exports = Rental; module.exports = Rental;

View File

@ -6,7 +6,8 @@ const Room = sequelize.define('Room', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true,
comment: '房间ID'
}, },
apartmentId: { apartmentId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
@ -14,52 +15,63 @@ const Room = sequelize.define('Room', {
references: { references: {
model: Apartment, model: Apartment,
key: 'id' key: 'id'
} },
comment: '所属公寓ID'
}, },
roomNumber: { roomNumber: {
type: DataTypes.STRING(20), type: DataTypes.STRING(20),
allowNull: false allowNull: false,
comment: '房间编号'
}, },
area: { area: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: true,
comment: '房间面积'
}, },
monthlyPrice: { monthlyPrice: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: true,
comment: '月租金'
}, },
yearlyPrice: { yearlyPrice: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: true,
comment: '年租金'
}, },
status: { status: {
type: DataTypes.ENUM('empty', 'rented'), type: DataTypes.ENUM('empty', 'rented'),
allowNull: false, allowNull: false,
defaultValue: 'empty' defaultValue: 'empty',
comment: '房间状态empty空房rented在租'
}, },
subStatus: { subStatus: {
type: DataTypes.ENUM('normal', 'soon_expire', 'expired'), type: DataTypes.ENUM('normal', 'soon_expire', 'expired'),
allowNull: false, allowNull: false,
defaultValue: 'normal' defaultValue: 'normal',
comment: '附属状态normal正常soon_expire即将到期expired已到期'
}, },
otherStatus: { otherStatus: {
type: DataTypes.ENUM('', 'cleaning', 'maintenance'), type: DataTypes.ENUM('', 'cleaning', 'maintenance'),
allowNull: false, allowNull: false,
defaultValue: '' defaultValue: '',
comment: '其他状态cleaning打扫中maintenance维修中'
}, },
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW,
comment: '创建时间'
}, },
updateTime: { updateTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW, defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW onUpdate: DataTypes.NOW,
comment: '更新时间'
}, },
isDeleted: { isDeleted: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: 0 defaultValue: 0,
comment: '删除状态0未删除1已删除'
} }
}, { }, {
tableName: 'rooms', tableName: 'rooms',

View File

@ -1,42 +0,0 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/db');
const Tenant = sequelize.define('Tenant', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING(50),
allowNull: false
},
phone: {
type: DataTypes.STRING(20),
allowNull: true
},
idCard: {
type: DataTypes.STRING(20),
allowNull: true,
unique: true
},
createTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
updateTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW
},
isDeleted: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
}
}, {
tableName: 'tenants',
timestamps: false
});
module.exports = Tenant;

View File

@ -6,7 +6,8 @@ const WaterBill = sequelize.define('WaterBill', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true,
comment: '水费账单ID'
}, },
roomId: { roomId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
@ -14,54 +15,66 @@ const WaterBill = sequelize.define('WaterBill', {
references: { references: {
model: Room, model: Room,
key: 'id' key: 'id'
} },
comment: '房间ID'
}, },
startDate: { startDate: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: false allowNull: false,
comment: '开始日期'
}, },
endDate: { endDate: {
type: DataTypes.DATE, type: DataTypes.DATE,
allowNull: false allowNull: false,
comment: '结束日期'
}, },
startReading: { startReading: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '起始读数'
}, },
endReading: { endReading: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '结束读数'
}, },
usage: { usage: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '用水量'
}, },
unitPrice: { unitPrice: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '单价'
}, },
amount: { amount: {
type: DataTypes.DECIMAL(10, 2), type: DataTypes.DECIMAL(10, 2),
allowNull: false allowNull: false,
comment: '金额'
}, },
status: { status: {
type: DataTypes.ENUM('unpaid', 'paid'), type: DataTypes.ENUM('unpaid', 'paid'),
allowNull: false, allowNull: false,
defaultValue: 'unpaid' defaultValue: 'unpaid',
comment: '状态unpaid未支付paid已支付'
}, },
createTime: { createTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW defaultValue: DataTypes.NOW,
comment: '创建时间'
}, },
updateTime: { updateTime: {
type: DataTypes.DATE, type: DataTypes.DATE,
defaultValue: DataTypes.NOW, defaultValue: DataTypes.NOW,
onUpdate: DataTypes.NOW onUpdate: DataTypes.NOW,
comment: '更新时间'
}, },
isDeleted: { isDeleted: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: 0 defaultValue: 0,
comment: '删除状态0未删除1已删除'
} }
}, { }, {
tableName: 'water_bills', tableName: 'water_bills',

View File

@ -1,8 +1,6 @@
const Region = require('./Region'); const Region = require('./Region');
const Apartment = require('./Apartment'); const Apartment = require('./Apartment');
const Room = require('./Room'); const Room = require('./Room');
const Tenant = require('./Tenant');
const Contract = require('./Contract');
const Rental = require('./Rental'); const Rental = require('./Rental');
const WaterBill = require('./WaterBill'); const WaterBill = require('./WaterBill');
const ElectricityBill = require('./ElectricityBill'); const ElectricityBill = require('./ElectricityBill');
@ -11,8 +9,6 @@ module.exports = {
Region, Region,
Apartment, Apartment,
Room, Room,
Tenant,
Contract,
Rental, Rental,
WaterBill, WaterBill,
ElectricityBill ElectricityBill

View File

@ -1,12 +0,0 @@
const express = require('express');
const router = express.Router();
const contractController = require('../controllers/contractController');
// 路由
router.get('/', contractController.getAllContracts);
router.get('/:id', contractController.getContractById);
router.post('/', contractController.createContract);
router.put('/:id', contractController.updateContract);
router.delete('/:id', contractController.deleteContract);
module.exports = router;

View File

@ -1,13 +0,0 @@
const express = require('express');
const router = express.Router();
const tenantController = require('../controllers/tenantController');
// 路由
router.get('/', tenantController.getAllTenants);
router.get('/list', tenantController.listTenants);
router.get('/:id', tenantController.getTenantById);
router.post('/', tenantController.createTenant);
router.put('/:id', tenantController.updateTenant);
router.delete('/:id', tenantController.deleteTenant);
module.exports = router;

View File

@ -1,72 +0,0 @@
const { Region, Apartment, Room } = require('../models');
// 房间列表
const roomNumbers = [
'201', '202', '203', '205', '206', '208', '209',
'301', '302', '303', '305', '306', '308', '309',
'401', '402', '403', '405', '406', '408', '409',
'501', '502', '503', '505', '506', '508', '509'
];
async function addRooms() {
try {
console.log('开始添加房间...');
// 查找或创建碧云公寓
let apartment = await Apartment.findOne({ where: { name: '碧云公寓' } });
if (!apartment) {
console.log('碧云公寓不存在,创建中...');
// 查找或创建大商汇区域
let region = await Region.findOne({ where: { name: '大商汇' } });
if (!region) {
region = await Region.create({ name: '大商汇', description: '大商汇区域' });
console.log('创建了大商汇区域');
}
// 创建碧云公寓
apartment = await Apartment.create({
regionId: region.id,
name: '碧云公寓',
address: '大商汇区域'
});
console.log('创建了碧云公寓');
} else {
console.log('找到碧云公寓ID:', apartment.id);
}
// 添加房间
console.log('开始添加房间...');
for (const roomNumber of roomNumbers) {
// 检查房间是否已存在
const existingRoom = await Room.findOne({
where: {
apartmentId: apartment.id,
roomNumber: roomNumber
}
});
if (!existingRoom) {
await Room.create({
apartmentId: apartment.id,
roomNumber: roomNumber,
area: 25, // 默认面积
price: 2000, // 默认价格
status: 'empty' // 空房状态
});
console.log(`添加了房间: ${roomNumber}`);
} else {
console.log(`房间 ${roomNumber} 已存在,跳过`);
}
}
console.log('房间添加完成!');
process.exit(0);
} catch (error) {
console.error('添加房间时出错:', error);
process.exit(1);
}
}
// 执行脚本
addRooms();

View File

@ -1,72 +0,0 @@
const { Region, Apartment, Room } = require('../models');
// 房间列表
const roomNumbers = [
'301', '302', '303', '304', '305', '306', '307',
'401', '402', '403', '404', '405', '406', '407',
'501', '502', '503', '504', '505', '506', '507',
'601', '602', '603', '604', '605', '606', '607'
];
async function addRooms() {
try {
console.log('开始添加房间...');
// 查找或创建谷景公寓
let apartment = await Apartment.findOne({ where: { name: '谷景公寓' } });
if (!apartment) {
console.log('谷景公寓不存在,创建中...');
// 查找或创建大商汇区域
let region = await Region.findOne({ where: { name: '大商汇' } });
if (!region) {
region = await Region.create({ name: '大商汇', description: '大商汇区域' });
console.log('创建了大商汇区域');
}
// 创建谷景公寓
apartment = await Apartment.create({
regionId: region.id,
name: '谷景公寓',
address: '大商汇区域'
});
console.log('创建了谷景公寓');
} else {
console.log('找到谷景公寓ID:', apartment.id);
}
// 添加房间
console.log('开始添加房间...');
for (const roomNumber of roomNumbers) {
// 检查房间是否已存在
const existingRoom = await Room.findOne({
where: {
apartmentId: apartment.id,
roomNumber: roomNumber
}
});
if (!existingRoom) {
await Room.create({
apartmentId: apartment.id,
roomNumber: roomNumber,
area: 25, // 默认面积
price: 2000, // 默认价格
status: 'empty' // 空房状态
});
console.log(`添加了房间: ${roomNumber}`);
} else {
console.log(`房间 ${roomNumber} 已存在,跳过`);
}
}
console.log('房间添加完成!');
process.exit(0);
} catch (error) {
console.error('添加房间时出错:', error);
process.exit(1);
}
}
// 执行脚本
addRooms();

View File

@ -1,71 +0,0 @@
const { Region, Apartment, Room } = require('../models');
// 房间列表
const roomNumbers = [
'201', '202', '203', '205', '206',
'301', '302', '303', '305', '306',
'401', '402', '403', '405', '406'
];
async function addRooms() {
try {
console.log('开始添加房间...');
// 查找或创建沐航公寓
let apartment = await Apartment.findOne({ where: { name: '沐航公寓' } });
if (!apartment) {
console.log('沐航公寓不存在,创建中...');
// 查找或创建丰源市场区域
let region = await Region.findOne({ where: { name: '丰源市场' } });
if (!region) {
region = await Region.create({ name: '丰源市场', description: '丰源市场区域' });
console.log('创建了丰源市场区域');
}
// 创建沐航公寓
apartment = await Apartment.create({
regionId: region.id,
name: '沐航公寓',
address: '丰源市场区域'
});
console.log('创建了沐航公寓');
} else {
console.log('找到沐航公寓ID:', apartment.id);
}
// 添加房间
console.log('开始添加房间...');
for (const roomNumber of roomNumbers) {
// 检查房间是否已存在
const existingRoom = await Room.findOne({
where: {
apartmentId: apartment.id,
roomNumber: roomNumber
}
});
if (!existingRoom) {
await Room.create({
apartmentId: apartment.id,
roomNumber: roomNumber,
area: 25, // 默认面积
price: 2000, // 默认价格
status: 'empty' // 空房状态
});
console.log(`添加了房间: ${roomNumber}`);
} else {
console.log(`房间 ${roomNumber} 已存在,跳过`);
}
}
console.log('房间添加完成!');
process.exit(0);
} catch (error) {
console.error('添加房间时出错:', error);
process.exit(1);
}
}
// 执行脚本
addRooms();

View File

@ -1,72 +0,0 @@
const { Region, Apartment, Room } = require('../models');
// 房间列表
const roomNumbers = [
'201', '202', '203', '204',
'301', '302', '303', '304', '305', '306', '307',
'401', '402', '403', '404',
'501', '502'
];
async function addRooms() {
try {
console.log('开始添加房间...');
// 查找或创建千妗公寓
let apartment = await Apartment.findOne({ where: { name: '千妗公寓' } });
if (!apartment) {
console.log('千妗公寓不存在,创建中...');
// 查找或创建丰源市场区域
let region = await Region.findOne({ where: { name: '丰源市场' } });
if (!region) {
region = await Region.create({ name: '丰源市场', description: '丰源市场区域' });
console.log('创建了丰源市场区域');
}
// 创建千妗公寓
apartment = await Apartment.create({
regionId: region.id,
name: '千妗公寓',
address: '丰源市场区域'
});
console.log('创建了千妗公寓');
} else {
console.log('找到千妗公寓ID:', apartment.id);
}
// 添加房间
console.log('开始添加房间...');
for (const roomNumber of roomNumbers) {
// 检查房间是否已存在
const existingRoom = await Room.findOne({
where: {
apartmentId: apartment.id,
roomNumber: roomNumber
}
});
if (!existingRoom) {
await Room.create({
apartmentId: apartment.id,
roomNumber: roomNumber,
area: 25, // 默认面积
price: 2000, // 默认价格
status: 'empty' // 空房状态
});
console.log(`添加了房间: ${roomNumber}`);
} else {
console.log(`房间 ${roomNumber} 已存在,跳过`);
}
}
console.log('房间添加完成!');
process.exit(0);
} catch (error) {
console.error('添加房间时出错:', error);
process.exit(1);
}
}
// 执行脚本
addRooms();

View File

@ -1,71 +0,0 @@
const { Region, Apartment, Room } = require('../models');
// 房间列表
const roomNumbers = [
'301', '302', '303', '304', '305', '306', '307',
'401', '402', '403', '404', '405', '406', '407',
'501', '502', '503', '504', '505', '506', '507'
];
async function addRooms() {
try {
console.log('开始添加房间...');
// 查找或创建归宿公寓
let apartment = await Apartment.findOne({ where: { name: '归宿公寓' } });
if (!apartment) {
console.log('归宿公寓不存在,创建中...');
// 查找或创建丰源市场区域
let region = await Region.findOne({ where: { name: '丰源市场' } });
if (!region) {
region = await Region.create({ name: '丰源市场', description: '丰源市场区域' });
console.log('创建了丰源市场区域');
}
// 创建归宿公寓
apartment = await Apartment.create({
regionId: region.id,
name: '归宿公寓',
address: '丰源市场区域'
});
console.log('创建了归宿公寓');
} else {
console.log('找到归宿公寓ID:', apartment.id);
}
// 添加房间
console.log('开始添加房间...');
for (const roomNumber of roomNumbers) {
// 检查房间是否已存在
const existingRoom = await Room.findOne({
where: {
apartmentId: apartment.id,
roomNumber: roomNumber
}
});
if (!existingRoom) {
await Room.create({
apartmentId: apartment.id,
roomNumber: roomNumber,
area: 25, // 默认面积
price: 2000, // 默认价格
status: 'empty' // 空房状态
});
console.log(`添加了房间: ${roomNumber}`);
} else {
console.log(`房间 ${roomNumber} 已存在,跳过`);
}
}
console.log('房间添加完成!');
process.exit(0);
} catch (error) {
console.error('添加房间时出错:', error);
process.exit(1);
}
}
// 执行脚本
addRooms();

View File

@ -1,72 +0,0 @@
const { Region, Apartment, Room } = require('../models');
// 房间列表
const roomNumbers = [
'201', '202', '203', '205', '206',
'301', '302', '303', '305', '306',
'401', '402', '403', '405', '406',
'501', '502', '503', '505'
];
async function addRooms() {
try {
console.log('开始添加房间...');
// 查找或创建义和公寓
let apartment = await Apartment.findOne({ where: { name: '义和公寓' } });
if (!apartment) {
console.log('义和公寓不存在,创建中...');
// 查找或创建丰源市场区域
let region = await Region.findOne({ where: { name: '丰源市场' } });
if (!region) {
region = await Region.create({ name: '丰源市场', description: '丰源市场区域' });
console.log('创建了丰源市场区域');
}
// 创建义和公寓
apartment = await Apartment.create({
regionId: region.id,
name: '义和公寓',
address: '丰源市场区域'
});
console.log('创建了义和公寓');
} else {
console.log('找到义和公寓ID:', apartment.id);
}
// 添加房间
console.log('开始添加房间...');
for (const roomNumber of roomNumbers) {
// 检查房间是否已存在
const existingRoom = await Room.findOne({
where: {
apartmentId: apartment.id,
roomNumber: roomNumber
}
});
if (!existingRoom) {
await Room.create({
apartmentId: apartment.id,
roomNumber: roomNumber,
area: 25, // 默认面积
price: 2000, // 默认价格
status: 'empty' // 空房状态
});
console.log(`添加了房间: ${roomNumber}`);
} else {
console.log(`房间 ${roomNumber} 已存在,跳过`);
}
}
console.log('房间添加完成!');
process.exit(0);
} catch (error) {
console.error('添加房间时出错:', error);
process.exit(1);
}
}
// 执行脚本
addRooms();

View File

@ -1,70 +0,0 @@
const { Region, Apartment, Room } = require('../models');
// 房间列表
const roomNumbers = [
'402', '403', '404', '405', '406', '407', '408', '409', '410', '411', '412', '413',
'501', '502', '503', '504', '505', '506', '507', '508', '509', '510', '511', '512', '513'
];
async function addRooms() {
try {
console.log('开始添加房间...');
// 查找或创建爱奇艺公寓
let apartment = await Apartment.findOne({ where: { name: '爱奇艺公寓' } });
if (!apartment) {
console.log('爱奇艺公寓不存在,创建中...');
// 查找或创建大商汇区域
let region = await Region.findOne({ where: { name: '大商汇' } });
if (!region) {
region = await Region.create({ name: '大商汇', description: '大商汇区域' });
console.log('创建了大商汇区域');
}
// 创建爱奇艺公寓
apartment = await Apartment.create({
regionId: region.id,
name: '爱奇艺公寓',
address: '大商汇区域'
});
console.log('创建了爱奇艺公寓');
} else {
console.log('找到爱奇艺公寓ID:', apartment.id);
}
// 添加房间
console.log('开始添加房间...');
for (const roomNumber of roomNumbers) {
// 检查房间是否已存在
const existingRoom = await Room.findOne({
where: {
apartmentId: apartment.id,
roomNumber: roomNumber
}
});
if (!existingRoom) {
await Room.create({
apartmentId: apartment.id,
roomNumber: roomNumber,
area: 25, // 默认面积
price: 2000, // 默认价格
status: 'empty' // 空房状态
});
console.log(`添加了房间: ${roomNumber}`);
} else {
console.log(`房间 ${roomNumber} 已存在,跳过`);
}
}
console.log('房间添加完成!');
process.exit(0);
} catch (error) {
console.error('添加房间时出错:', error);
process.exit(1);
}
}
// 执行脚本
addRooms();

View File

@ -1,37 +0,0 @@
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();

View File

@ -1,41 +0,0 @@
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

@ -1,16 +0,0 @@
-- 更新房间表结构,将原来的 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;