This commit is contained in:
wangxiaoxian 2026-05-09 17:01:41 +08:00
parent ed4ff56082
commit a4ed46d10a
13 changed files with 330 additions and 170 deletions

View File

@ -9,7 +9,7 @@ const dbConfig = {
local: { local: {
host: 'localhost', host: 'localhost',
user: 'root', user: 'root',
password: 'root', password: '123456',
database: 'rentease' database: 'rentease'
}, },
development: { development: {

View File

@ -6,19 +6,25 @@ const response = require('../utils/response');
// 格式化时间(考虑时区,转换为北京时间) // 格式化时间(考虑时区,转换为北京时间)
const formatDate = (date) => { const formatDate = (date) => {
if (!date) return null; if (!date) return null;
// 确保date是Date对象
const dateObj = date instanceof Date ? date : new Date(date); const dateObj = date instanceof Date ? date : new Date(date);
// 创建一个新的Date对象加上8小时的时区偏移
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000); const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().split('T')[0]; return beijingDate.toISOString().split('T')[0];
}; };
// 格式化日期时间(年月日时分秒)
const formatDateTime = (date) => {
if (!date) return null;
const dateObj = date instanceof Date ? date : new Date(date);
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().replace('T', ' ').slice(0, 19);
};
// 格式化公寓数据 // 格式化公寓数据
const formatApartmentData = (apartment) => { const formatApartmentData = (apartment) => {
return { return {
...apartment.toJSON(), ...apartment.toJSON(),
createTime: formatDate(apartment.createTime), createTime: formatDateTime(apartment.createTime),
updateTime: formatDate(apartment.updateTime) updateTime: formatDateTime(apartment.updateTime)
}; };
}; };
@ -28,7 +34,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 = { isDeleted: 0 }; const where = { tenantId: req.user.tenantId, isDeleted: 0 };
if (regionId) { if (regionId) {
where.regionId = regionId; where.regionId = regionId;
} }
@ -68,7 +74,7 @@ const getApartmentById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const apartment = await Apartment.findOne({ const apartment = await Apartment.findOne({
where: { id, isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!apartment) { if (!apartment) {
return response.notFound(res, '公寓不存在'); return response.notFound(res, '公寓不存在');
@ -135,7 +141,7 @@ const updateApartment = async (req, res) => {
const { id } = req.params; const { id } = req.params;
const { name, address, description } = req.body; const { name, address, description } = req.body;
const apartment = await Apartment.findOne({ const apartment = await Apartment.findOne({
where: { id, isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!apartment) { if (!apartment) {
return response.notFound(res, '公寓不存在'); return response.notFound(res, '公寓不存在');
@ -157,7 +163,7 @@ const deleteApartment = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const apartment = await Apartment.findOne({ const apartment = await Apartment.findOne({
where: { id, isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!apartment) { if (!apartment) {
return response.notFound(res, '公寓不存在'); return response.notFound(res, '公寓不存在');
@ -178,7 +184,7 @@ const listApartments = async (req, res) => {
const { regionId, name } = req.query; const { regionId, name } = req.query;
// 构建查询条件 // 构建查询条件
const where = { isDeleted: 0 }; const where = { tenantId: req.user.tenantId, isDeleted: 0 };
if (regionId) { if (regionId) {
where.regionId = regionId; where.regionId = regionId;
} }

View File

@ -3,6 +3,26 @@ const { Op } = require('sequelize');
const billingService = require('../services/billingService'); const billingService = require('../services/billingService');
const response = require('../utils/response'); const response = require('../utils/response');
// 格式化日期时间(年月日时分秒)
const formatDateTime = (date) => {
if (!date) return null;
const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null;
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().replace('T', ' ').slice(0, 19);
};
// 格式化订单数据
const formatOrderData = (order) => {
const data = order.toJSON ? order.toJSON() : order;
return {
...data,
createTime: formatDateTime(data.createTime),
updateTime: formatDateTime(data.updateTime),
paidTime: formatDateTime(data.paidTime)
};
};
// 获取所有套餐列表 // 获取所有套餐列表
const getAllPlans = async (req, res) => { const getAllPlans = async (req, res) => {
try { try {
@ -318,7 +338,7 @@ const getOrders = async (req, res) => {
}); });
response.success(res, '获取订单列表成功', { response.success(res, '获取订单列表成功', {
list: rows, list: rows.map(formatOrderData),
total: count, total: count,
page: parseInt(page), page: parseInt(page),
pageSize: parseInt(pageSize) pageSize: parseInt(pageSize)
@ -430,7 +450,7 @@ const createOrder = async (req, res) => {
}); });
response.created(res, '订单创建成功', { response.created(res, '订单创建成功', {
order: createdOrder.toJSON(), order: formatOrderData(createdOrder),
details: amountInfo.details details: amountInfo.details
}); });
} catch (error) { } catch (error) {
@ -476,7 +496,7 @@ const getOrderDetail = async (req, res) => {
return response.forbidden(res, '无权查看此订单'); return response.forbidden(res, '无权查看此订单');
} }
response.success(res, '获取订单详情成功', order); response.success(res, '获取订单详情成功', formatOrderData(order));
} catch (error) { } catch (error) {
console.error('获取订单详情失败:', error); console.error('获取订单详情失败:', error);
response.serverError(res, '获取订单详情失败', error); response.serverError(res, '获取订单详情失败', error);
@ -582,9 +602,9 @@ const payOrder = async (req, res) => {
response.success(res, '支付成功', { response.success(res, '支付成功', {
payment, payment,
order: { order: {
...order.toJSON(), ...formatOrderData(order),
status: 'paid', status: 'paid',
paidTime: paidTime paidTime: formatDateTime(paidTime)
}, },
tenant: paymentResult tenant: paymentResult
}); });
@ -632,7 +652,11 @@ const getPayments = async (req, res) => {
}); });
response.success(res, '获取支付记录成功', { response.success(res, '获取支付记录成功', {
list: rows, list: rows.map(r => ({
...(r.toJSON ? r.toJSON() : r),
createTime: formatDateTime(r.createTime),
paidAt: formatDateTime(r.paidAt)
})),
total: count, total: count,
page: parseInt(page), page: parseInt(page),
pageSize: parseInt(pageSize) pageSize: parseInt(pageSize)

View File

@ -4,6 +4,29 @@ const RoleMenu = require('../models/RoleMenu');
const { logOperation } = require('../utils/logger'); const { logOperation } = require('../utils/logger');
const response = require('../utils/response'); const response = require('../utils/response');
// 格式化日期时间(年月日时分秒)
const formatDateTime = (date) => {
if (!date) return null;
const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null;
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().replace('T', ' ').slice(0, 19);
};
// 格式化菜单数据递归处理children
const formatMenuData = (menu) => {
const data = menu.toJSON ? menu.toJSON() : menu;
const result = {
...data,
createTime: formatDateTime(data.createTime),
updateTime: formatDateTime(data.updateTime)
};
if (data.children && Array.isArray(data.children)) {
result.children = data.children.map(formatMenuData);
}
return result;
};
// 获取菜单树 // 获取菜单树
exports.getMenuTree = async (req, res) => { exports.getMenuTree = async (req, res) => {
try { try {
@ -61,7 +84,7 @@ exports.getMenuList = async (req, res) => {
}); });
response.success(res, '获取成功', { response.success(res, '获取成功', {
list: rows, list: rows.map(formatMenuData),
total: count, total: count,
page: parseInt(page), page: parseInt(page),
pageSize: parseInt(pageSize) pageSize: parseInt(pageSize)
@ -85,7 +108,7 @@ exports.getMenuById = async (req, res) => {
return response.notFound(res, '菜单不存在'); return response.notFound(res, '菜单不存在');
} }
response.success(res, '获取成功', menu); response.success(res, '获取成功', formatMenuData(menu));
} catch (error) { } catch (error) {
console.error('获取菜单详情失败:', error); console.error('获取菜单详情失败:', error);
response.serverError(res, '获取菜单详情失败', error); response.serverError(res, '获取菜单详情失败', error);
@ -149,7 +172,7 @@ exports.createMenu = async (req, res) => {
status: 'success' status: 'success'
}); });
response.success(res, '创建成功', menu); response.success(res, '创建成功', formatMenuData(menu));
} catch (error) { } catch (error) {
console.error('创建菜单失败:', error); console.error('创建菜单失败:', error);
response.serverError(res, '创建菜单失败', error); response.serverError(res, '创建菜单失败', error);
@ -221,7 +244,7 @@ exports.updateMenu = async (req, res) => {
status: 'success' status: 'success'
}); });
response.success(res, '更新成功', menu); response.success(res, '更新成功', formatMenuData(menu));
} catch (error) { } catch (error) {
console.error('更新菜单失败:', error); console.error('更新菜单失败:', error);
response.serverError(res, '更新菜单失败', error); response.serverError(res, '更新菜单失败', error);
@ -306,7 +329,7 @@ exports.getRoleMenus = async (req, res) => {
const menus = roleData ? roleData.menus : []; const menus = roleData ? roleData.menus : [];
response.success(res, '获取成功', menus); response.success(res, '获取成功', menus.map(formatMenuData));
} catch (error) { } catch (error) {
console.error('获取角色菜单失败:', error); console.error('获取角色菜单失败:', error);
response.serverError(res, '获取角色菜单失败', error); response.serverError(res, '获取角色菜单失败', error);
@ -446,7 +469,7 @@ function buildTree(menus, parentId = null) {
.filter(menu => menu.parentId === parentId) .filter(menu => menu.parentId === parentId)
.map(menu => { .map(menu => {
// 获取菜单的原始数据 // 获取菜单的原始数据
const menuData = menu.toJSON ? menu.toJSON() : menu; const menuData = formatMenuData(menu);
return { return {
...menuData, ...menuData,
children: buildTree(menus, menu.id) children: buildTree(menus, menu.id)

View File

@ -5,29 +5,36 @@ const response = require('../utils/response');
// 格式化时间(考虑时区,转换为北京时间) // 格式化时间(考虑时区,转换为北京时间)
const formatDate = (date) => { const formatDate = (date) => {
if (!date) return null; if (!date) return null;
// 确保 date 是 Date 对象
const dateObj = date instanceof Date ? date : new Date(date); const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null; if (isNaN(dateObj.getTime())) return null;
// 创建一个新的Date对象加上8小时的时区偏移
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000); const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().split('T')[0]; return beijingDate.toISOString().split('T')[0];
}; };
// 格式化日期时间(年月日时分秒)
const formatDateTime = (date) => {
if (!date) return null;
const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null;
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().replace('T', ' ').slice(0, 19);
};
// 格式化租房数据 // 格式化租房数据
const formatRentalData = (rental) => { const formatRentalData = (rental) => {
const formattedRental = { const formattedRental = {
...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: formatDateTime(rental.createTime),
updateTime: formatDate(rental.updateTime) updateTime: formatDateTime(rental.updateTime)
}; };
return formattedRental; return formattedRental;
}; };
// 检查并更新租房状态 // 检查并更新租房状态
const checkAndUpdateRentalStatus = async () => { const checkAndUpdateRentalStatus = async (tenantId) => {
try { try {
// 获取当前日期 // 获取当前日期
const currentDate = new Date(); const currentDate = new Date();
@ -35,9 +42,9 @@ const checkAndUpdateRentalStatus = async () => {
const fiveDaysLater = new Date(); const fiveDaysLater = new Date();
fiveDaysLater.setDate(currentDate.getDate() + 5); fiveDaysLater.setDate(currentDate.getDate() + 5);
// 查找所有活跃的租房记录 // 查找该租户下所有活跃的租房记录
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { status: 'active', isDeleted: 0 }, where: { tenantId, status: 'active', isDeleted: 0 },
include: [ include: [
{ {
model: Room, model: Room,
@ -82,7 +89,7 @@ const checkAndUpdateRentalStatus = async () => {
const getAllRentals = async (req, res) => { const getAllRentals = async (req, res) => {
try { try {
// 先检查并更新租房状态 // 先检查并更新租房状态
await checkAndUpdateRentalStatus(); await checkAndUpdateRentalStatus(req.user.tenantId);
const { const {
apartmentId, apartmentId,
@ -98,7 +105,7 @@ const getAllRentals = async (req, res) => {
} = req.query; } = req.query;
// 构建查询条件 // 构建查询条件
const where = { isDeleted: 0 }; const where = { tenantId: req.user.tenantId, isDeleted: 0 };
if (status) { if (status) {
where.status = status; where.status = status;
} }
@ -166,7 +173,7 @@ const getRentalById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const rental = await Rental.findOne({ const rental = await Rental.findOne({
where: { id, isDeleted: 0 }, where: { id, tenantId: req.user.tenantId, isDeleted: 0 },
include: [ include: [
{ {
model: Room, model: Room,
@ -269,6 +276,7 @@ const createRental = async (req, res) => {
electricityMeterStart: body.electricityMeterStart || null, electricityMeterStart: body.electricityMeterStart || null,
status: body.status || 'active', status: body.status || 'active',
remark: body.remark, remark: body.remark,
tenantId: req.user.tenantId,
createBy: req.user.id, createBy: req.user.id,
updateBy: req.user.id updateBy: req.user.id
}); });
@ -280,16 +288,17 @@ const createRental = async (req, res) => {
// 自动生成租金账单 // 自动生成租金账单
await Bill.create({ await Bill.create({
billNo: 'B' + Date.now(),
rentalId: rental.id, rentalId: rental.id,
roomId: parsedRoomId, roomId: parsedRoomId,
renterId: parsedRenterId,
type: 'income', type: 'income',
category: 'rent', category: 'rent',
amount: body.rent, receivableAmount: body.rent,
paidAmount: 0, receivedAmount: 0,
status: 'pending', status: 'unpaid',
dueDate: body.endDate, billDate: body.startDate,
periodStart: body.startDate, billMonth: body.startDate.substring(0, 7),
periodEnd: body.endDate,
remark: `租约租金 - ${renterName}`, remark: `租约租金 - ${renterName}`,
tenantId: req.user.tenantId, tenantId: req.user.tenantId,
createBy: req.user.id, createBy: req.user.id,
@ -299,14 +308,17 @@ const createRental = async (req, res) => {
// 自动生成押金账单(如果有押金) // 自动生成押金账单(如果有押金)
if (deposit > 0) { if (deposit > 0) {
await Bill.create({ await Bill.create({
billNo: 'B' + Date.now() + '1',
rentalId: rental.id, rentalId: rental.id,
roomId: parsedRoomId, roomId: parsedRoomId,
renterId: parsedRenterId,
type: 'income', type: 'income',
category: 'deposit', category: 'deposit',
amount: deposit, receivableAmount: deposit,
paidAmount: 0, receivedAmount: 0,
status: 'pending', status: 'unpaid',
dueDate: body.startDate, billDate: body.startDate,
billMonth: body.startDate.substring(0, 7),
remark: `租约押金 - ${renterName}`, remark: `租约押金 - ${renterName}`,
tenantId: req.user.tenantId, tenantId: req.user.tenantId,
createBy: req.user.id, createBy: req.user.id,
@ -327,7 +339,7 @@ const updateRental = async (req, res) => {
const { id } = req.params; const { id } = req.params;
const { roomId, renterId, startDate, endDate, paymentType, rent, deposit, operator, waterMeterStart, electricityMeterStart, waterMeterEnd, electricityMeterEnd, status, remark } = req.body; const { roomId, renterId, startDate, endDate, paymentType, rent, deposit, operator, waterMeterStart, electricityMeterStart, waterMeterEnd, electricityMeterEnd, status, remark } = req.body;
const rental = await Rental.findOne({ const rental = await Rental.findOne({
where: { id, isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!rental) { if (!rental) {
return response.notFound(res, '租房记录不存在'); return response.notFound(res, '租房记录不存在');
@ -362,7 +374,7 @@ const deleteRental = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const rental = await Rental.findOne({ const rental = await Rental.findOne({
where: { id, isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!rental) { if (!rental) {
return response.notFound(res, '租房记录不存在'); return response.notFound(res, '租房记录不存在');
@ -384,7 +396,7 @@ const terminateRental = async (req, res) => {
const { waterMeterEnd, electricityMeterEnd, remark } = req.body; const { waterMeterEnd, electricityMeterEnd, remark } = req.body;
const rental = await Rental.findOne({ const rental = await Rental.findOne({
where: { id, isDeleted: 0 }, where: { id, tenantId: req.user.tenantId, isDeleted: 0 },
include: [ include: [
{ {
model: Room, model: Room,
@ -429,13 +441,16 @@ const terminateRental = async (req, res) => {
if (waterUsage > 0 && apartment.waterPrice) { if (waterUsage > 0 && apartment.waterPrice) {
const waterAmount = waterUsage * parseFloat(apartment.waterPrice); const waterAmount = waterUsage * parseFloat(apartment.waterPrice);
await Bill.create({ await Bill.create({
billNo: 'B' + Date.now(),
rentalId: rental.id, rentalId: rental.id,
roomId: room.id, roomId: room.id,
renterId: rental.renterId,
type: 'income', type: 'income',
category: 'water', category: 'water',
amount: waterAmount, receivableAmount: waterAmount,
paidAmount: 0, receivedAmount: 0,
status: 'pending', status: 'unpaid',
billDate: new Date(),
remark: `退租水费 - ${renterName}(用量:${waterUsage.toFixed(2)}吨)`, remark: `退租水费 - ${renterName}(用量:${waterUsage.toFixed(2)}吨)`,
tenantId: req.user.tenantId, tenantId: req.user.tenantId,
createBy: req.user.id, createBy: req.user.id,
@ -449,13 +464,16 @@ const terminateRental = async (req, res) => {
if (electricityUsage > 0 && apartment.electricityPrice) { if (electricityUsage > 0 && apartment.electricityPrice) {
const electricityAmount = electricityUsage * parseFloat(apartment.electricityPrice); const electricityAmount = electricityUsage * parseFloat(apartment.electricityPrice);
await Bill.create({ await Bill.create({
billNo: 'B' + Date.now() + '1',
rentalId: rental.id, rentalId: rental.id,
roomId: room.id, roomId: room.id,
renterId: rental.renterId,
type: 'income', type: 'income',
category: 'electricity', category: 'electricity',
amount: electricityAmount, receivableAmount: electricityAmount,
paidAmount: 0, receivedAmount: 0,
status: 'pending', status: 'unpaid',
billDate: new Date(),
remark: `退租电费 - ${renterName}(用量:${electricityUsage.toFixed(2)}度)`, remark: `退租电费 - ${renterName}(用量:${electricityUsage.toFixed(2)}度)`,
tenantId: req.user.tenantId, tenantId: req.user.tenantId,
createBy: req.user.id, createBy: req.user.id,
@ -481,7 +499,7 @@ const terminateRental = async (req, res) => {
const listRentals = async (req, res) => { const listRentals = async (req, res) => {
try { try {
// 先检查并更新租房状态 // 先检查并更新租房状态
await checkAndUpdateRentalStatus(); await checkAndUpdateRentalStatus(req.user.tenantId);
const { const {
apartmentId, apartmentId,
@ -495,7 +513,7 @@ const listRentals = async (req, res) => {
} = req.query; } = req.query;
// 构建查询条件 // 构建查询条件
const where = { isDeleted: 0 }; const where = { tenantId: req.user.tenantId, isDeleted: 0 };
if (status) { if (status) {
where.status = status; where.status = status;
} }

View File

@ -2,6 +2,25 @@ const { Renter, Rental, Room, Apartment } = require('../models');
const { Op } = require('sequelize'); const { Op } = require('sequelize');
const response = require('../utils/response'); const response = require('../utils/response');
// 格式化日期时间(年月日时分秒)
const formatDateTime = (date) => {
if (!date) return null;
const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null;
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().replace('T', ' ').slice(0, 19);
};
// 格式化租客数据
const formatRenterData = (renter) => {
const data = renter.toJSON ? renter.toJSON() : renter;
return {
...data,
createTime: formatDateTime(data.createTime),
updateTime: formatDateTime(data.updateTime)
};
};
// 获取租客列表(分页) // 获取租客列表(分页)
const getRenters = async (req, res) => { const getRenters = async (req, res) => {
try { try {
@ -30,7 +49,7 @@ const getRenters = async (req, res) => {
}); });
response.success(res, '获取成功', { response.success(res, '获取成功', {
list: rows, list: rows.map(formatRenterData),
total: count, total: count,
page: parseInt(page), page: parseInt(page),
pageSize: parseInt(pageSize) pageSize: parseInt(pageSize)
@ -66,7 +85,7 @@ const getRenterList = async (req, res) => {
order: [['createTime', 'DESC']] order: [['createTime', 'DESC']]
}); });
response.success(res, '获取成功', rows); response.success(res, '获取成功', rows.map(formatRenterData));
} catch (error) { } catch (error) {
console.error('获取租客列表失败:', error); console.error('获取租客列表失败:', error);
response.serverError(res, '获取租客列表失败', error); response.serverError(res, '获取租客列表失败', error);
@ -107,7 +126,13 @@ const getRenterById = async (req, res) => {
response.success(res, '获取成功', { response.success(res, '获取成功', {
...renter.toJSON(), ...renter.toJSON(),
rentals createTime: formatDateTime(renter.createTime),
updateTime: formatDateTime(renter.updateTime),
rentals: rentals.map(r => ({
...r.toJSON(),
createTime: formatDateTime(r.createTime),
updateTime: formatDateTime(r.updateTime)
}))
}); });
} catch (error) { } catch (error) {
console.error('获取租客详情失败:', error); console.error('获取租客详情失败:', error);
@ -167,7 +192,7 @@ const createRenter = async (req, res) => {
status: 'active' status: 'active'
}); });
response.created(res, '创建成功', renter); response.created(res, '创建成功', formatRenterData(renter));
} catch (error) { } catch (error) {
console.error('创建租客失败:', error); console.error('创建租客失败:', error);
response.serverError(res, '创建租客失败', error); response.serverError(res, '创建租客失败', error);
@ -230,7 +255,7 @@ const updateRenter = async (req, res) => {
updateBy updateBy
}); });
response.success(res, '更新成功', renter); response.success(res, '更新成功', formatRenterData(renter));
} catch (error) { } catch (error) {
console.error('更新租客失败:', error); console.error('更新租客失败:', error);
response.serverError(res, '更新租客失败', error); response.serverError(res, '更新租客失败', error);
@ -254,7 +279,7 @@ const deleteRenter = async (req, res) => {
// 检查是否有进行中的租赁 // 检查是否有进行中的租赁
const activeRentals = await Rental.count({ const activeRentals = await Rental.count({
where: { where: {
tenantName: renter.name, renterId: id,
tenantId, tenantId,
status: 'active' status: 'active'
} }

View File

@ -6,28 +6,35 @@ const response = require('../utils/response');
// 格式化时间(考虑时区,转换为北京时间) // 格式化时间(考虑时区,转换为北京时间)
const formatDate = (date) => { const formatDate = (date) => {
if (!date) return null; if (!date) return null;
// 确保 date 是 Date 对象
const dateObj = date instanceof Date ? date : new Date(date); const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null; if (isNaN(dateObj.getTime())) return null;
// 创建一个新的Date对象加上8小时的时区偏移
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000); const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().split('T')[0]; return beijingDate.toISOString().split('T')[0];
}; };
// 格式化日期时间(年月日时分秒)
const formatDateTime = (date) => {
if (!date) return null;
const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null;
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().replace('T', ' ').slice(0, 19);
};
// 格式化房间数据 // 格式化房间数据
const formatRoomData = (room) => { const formatRoomData = (room) => {
const formattedRoom = { const formattedRoom = {
...room.toJSON(), ...room.toJSON(),
createTime: formatDate(room.createTime), createTime: formatDateTime(room.createTime),
updateTime: formatDate(room.updateTime) updateTime: formatDateTime(room.updateTime)
}; };
// 格式化关联数据 // 格式化关联数据
if (formattedRoom.Apartment) { if (formattedRoom.Apartment) {
formattedRoom.Apartment = { formattedRoom.Apartment = {
...formattedRoom.Apartment, ...formattedRoom.Apartment,
createTime: formatDate(formattedRoom.Apartment.createTime), createTime: formatDateTime(formattedRoom.Apartment.createTime),
updateTime: formatDate(formattedRoom.Apartment.updateTime) updateTime: formatDateTime(formattedRoom.Apartment.updateTime)
}; };
} }
@ -38,8 +45,8 @@ 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: formatDateTime(rental.createTime),
updateTime: formatDate(rental.updateTime) updateTime: formatDateTime(rental.updateTime)
}; };
return formattedRental; return formattedRental;
@ -50,7 +57,7 @@ const formatRoomData = (room) => {
}; };
// 检查并更新租房状态 // 检查并更新租房状态
const checkAndUpdateRentalStatus = async () => { const checkAndUpdateRentalStatus = async (tenantId) => {
try { try {
// 获取当前日期 // 获取当前日期
const currentDate = new Date(); const currentDate = new Date();
@ -58,9 +65,9 @@ const checkAndUpdateRentalStatus = async () => {
const fiveDaysLater = new Date(); const fiveDaysLater = new Date();
fiveDaysLater.setDate(currentDate.getDate() + 5); fiveDaysLater.setDate(currentDate.getDate() + 5);
// 查找所有在租的租房记录 // 查找该租户下所有在租的租房记录
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { status: 'active', isDeleted: 0 } where: { tenantId, status: 'active', isDeleted: 0 }
}); });
// 检查每个租房记录的状态 // 检查每个租房记录的状态
@ -99,12 +106,12 @@ const checkAndUpdateRentalStatus = async () => {
const getAllRooms = async (req, res) => { const getAllRooms = async (req, res) => {
try { try {
// 先检查并更新租房状态 // 先检查并更新租房状态
await checkAndUpdateRentalStatus(); await checkAndUpdateRentalStatus(req.user.tenantId);
const { apartmentId, roomNumber, status, rentalStatus, page = 1, pageSize = 10 } = req.query; const { apartmentId, roomNumber, status, rentalStatus, page = 1, pageSize = 10 } = req.query;
// 构建查询条件 // 构建查询条件
const where = { isDeleted: 0 }; const where = { tenantId: req.user.tenantId, isDeleted: 0 };
if (apartmentId) { if (apartmentId) {
where.apartmentId = apartmentId; where.apartmentId = apartmentId;
} }
@ -142,6 +149,7 @@ const getAllRooms = async (req, res) => {
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { where: {
roomId: room.id, roomId: room.id,
tenantId: req.user.tenantId,
status: { [Op.ne]: 'expired' }, status: { [Op.ne]: 'expired' },
isDeleted: 0 isDeleted: 0
}, },
@ -195,11 +203,11 @@ const getAllRooms = async (req, res) => {
const getRoomById = async (req, res) => { const getRoomById = async (req, res) => {
try { try {
// 先检查并更新租房状态 // 先检查并更新租房状态
await checkAndUpdateRentalStatus(); await checkAndUpdateRentalStatus(req.user.tenantId);
const { id } = req.params; const { id } = req.params;
const room = await Room.findOne({ const room = await Room.findOne({
where: { id, isDeleted: 0 }, where: { id, tenantId: req.user.tenantId, isDeleted: 0 },
include: [Apartment] include: [Apartment]
}); });
if (!room) { if (!room) {
@ -213,6 +221,7 @@ const getRoomById = async (req, res) => {
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { where: {
roomId: room.id, roomId: room.id,
tenantId: req.user.tenantId,
status: { [Op.ne]: 'expired' }, status: { [Op.ne]: 'expired' },
isDeleted: 0 isDeleted: 0
}, },
@ -232,7 +241,7 @@ const getRoomById = async (req, res) => {
...rentalData, ...rentalData,
startDate: formatDate(rental.startDate), startDate: formatDate(rental.startDate),
endDate: formatDate(rental.endDate), endDate: formatDate(rental.endDate),
createTime: formatDate(rental.createTime), createTime: formatDateTime(rental.createTime),
// 兼容前端显示的字段 // 兼容前端显示的字段
tenantName: rentalData.Renter ? rentalData.Renter.name : '', tenantName: rentalData.Renter ? rentalData.Renter.name : '',
tenantPhone: rentalData.Renter ? rentalData.Renter.phone : '' tenantPhone: rentalData.Renter ? rentalData.Renter.phone : ''
@ -314,7 +323,7 @@ const updateRoom = async (req, res) => {
const { id } = req.params; const { id } = req.params;
const { apartmentId, roomNumber, floor, roomType, area, monthlyPrice, yearlyPrice, deposit, sortOrder, status, rentalStatus } = req.body; const { apartmentId, roomNumber, floor, roomType, area, monthlyPrice, yearlyPrice, deposit, sortOrder, status, rentalStatus } = req.body;
const room = await Room.findOne({ const room = await Room.findOne({
where: { id, isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!room) { if (!room) {
return response.notFound(res, '房间不存在'); return response.notFound(res, '房间不存在');
@ -346,7 +355,7 @@ const deleteRoom = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const room = await Room.findOne({ const room = await Room.findOne({
where: { id, isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!room) { if (!room) {
return response.notFound(res, '房间不存在'); return response.notFound(res, '房间不存在');
@ -365,12 +374,12 @@ const deleteRoom = async (req, res) => {
const listRooms = async (req, res) => { const listRooms = async (req, res) => {
try { try {
// 先检查并更新租房状态 // 先检查并更新租房状态
await checkAndUpdateRentalStatus(); await checkAndUpdateRentalStatus(req.user.tenantId);
const { apartmentId, roomNumber, status, rentalStatus } = req.query; const { apartmentId, roomNumber, status, rentalStatus } = req.query;
// 构建查询条件 // 构建查询条件
const where = { isDeleted: 0 }; const where = { tenantId: req.user.tenantId, isDeleted: 0 };
if (apartmentId) { if (apartmentId) {
where.apartmentId = apartmentId; where.apartmentId = apartmentId;
} }
@ -403,6 +412,7 @@ const listRooms = async (req, res) => {
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { where: {
roomId: room.id, roomId: room.id,
tenantId: req.user.tenantId,
status: { [Op.ne]: 'expired' }, status: { [Op.ne]: 'expired' },
isDeleted: 0 isDeleted: 0
}, },
@ -423,7 +433,7 @@ const listRooms = async (req, res) => {
...rentalData, ...rentalData,
startDate: formatDate(rental.startDate), startDate: formatDate(rental.startDate),
endDate: formatDate(rental.endDate), endDate: formatDate(rental.endDate),
createTime: formatDate(rental.createTime), createTime: formatDateTime(rental.createTime),
// 兼容前端显示的字段 // 兼容前端显示的字段
tenantName: rentalData.Renter ? rentalData.Renter.name : '', tenantName: rentalData.Renter ? rentalData.Renter.name : '',
tenantPhone: rentalData.Renter ? rentalData.Renter.phone : '' tenantPhone: rentalData.Renter ? rentalData.Renter.phone : ''

View File

@ -1,4 +1,5 @@
const { Setting, Category } = require('../models'); const { Setting, Category } = require('../models');
const { Op } = require('sequelize');
const response = require('../utils/response'); const response = require('../utils/response');
/** /**

View File

@ -1,4 +1,4 @@
const { Room, Rental, Apartment, Bill } = require('../models'); const { Room, Rental, Apartment, Bill, Renter } = require('../models');
const { Op } = require('sequelize'); const { Op } = require('sequelize');
const response = require('../utils/response'); const response = require('../utils/response');
@ -27,9 +27,8 @@ const getRentStatistics = async (req, res) => {
try { try {
rentals = await Rental.findAll({ rentals = await Rental.findAll({
where: { where: {
createTime: { tenantId: req.user.tenantId,
[Op.gte]: startDate createTime: { [Op.gte]: startDate },
},
isDeleted: 0 isDeleted: 0
} }
}); });
@ -66,10 +65,9 @@ const getRentStatistics = async (req, res) => {
try { try {
const expenses = await Bill.findAll({ const expenses = await Bill.findAll({
where: { where: {
tenantId: req.user.tenantId,
type: 'expense', type: 'expense',
billDate: { billDate: { [Op.gte]: startDate },
[Op.gte]: startDate
},
isDeleted: 0 isDeleted: 0
} }
}); });
@ -117,7 +115,7 @@ const getRentStatistics = async (req, res) => {
const getRoomStatusStatistics = async (req, res) => { const getRoomStatusStatistics = async (req, res) => {
try { try {
// 获取所有房间(排除已删除的) // 获取所有房间(排除已删除的)
const rooms = await Room.findAll({ where: { isDeleted: 0 } }); const rooms = await Room.findAll({ where: { tenantId: req.user.tenantId, isDeleted: 0 } });
// 初始化统计数据 // 初始化统计数据
let empty = 0; let empty = 0;
@ -162,26 +160,26 @@ const getRoomStatusStatistics = async (req, res) => {
// Dashboard统计数据 // Dashboard统计数据
const getDashboardStatistics = async (req, res) => { const getDashboardStatistics = async (req, res) => {
try { try {
// 导入所有需要的模型 const tenantId = req.user.tenantId;
const { Apartment, Room, WaterBill, Rental, Bill } = require('../models'); const baseWhere = { tenantId, isDeleted: 0 };
// 并行查询所有统计数据 // 并行查询所有统计数据
const [apartmentCount, roomCount, emptyRoomCount, reservedRoomCount, rentedRoomCount, soonExpireRoomCount, expiredRoomCount] = await Promise.all([ const [apartmentCount, roomCount, emptyRoomCount, reservedRoomCount, rentedRoomCount, soonExpireRoomCount, expiredRoomCount] = await Promise.all([
Apartment.count({ where: { isDeleted: 0 } }), Apartment.count({ where: baseWhere }),
Room.count({ where: { isDeleted: 0 } }), Room.count({ where: baseWhere }),
Room.count({ where: { status: 'empty', isDeleted: 0 } }), Room.count({ where: { ...baseWhere, status: 'empty' } }),
Room.count({ where: { status: 'reserved', isDeleted: 0 } }), Room.count({ where: { ...baseWhere, status: 'reserved' } }),
Room.count({ where: { status: 'rented', isDeleted: 0 } }), Room.count({ where: { ...baseWhere, status: 'rented' } }),
Room.count({ where: { status: 'rented', rentalStatus: 'soon_expire', isDeleted: 0 } }), Room.count({ where: { ...baseWhere, status: 'rented', rentalStatus: 'soon_expire' } }),
Room.count({ where: { status: 'rented', rentalStatus: 'expired', isDeleted: 0 } }) Room.count({ where: { ...baseWhere, status: 'rented', rentalStatus: 'expired' } })
]); ]);
// 安全地获取sum统计,处理表不存在或为空的情况 // 安全地获取sum统计
let collectedRentAmount = 0; let collectedRentAmount = 0;
let collectedWaterAmount = 0; let collectedWaterAmount = 0;
try { try {
const rentResult = await Rental.sum('rent', { where: { isDeleted: 0 } }); const rentResult = await Rental.sum('rent', { where: { tenantId, isDeleted: 0 } });
collectedRentAmount = rentResult || 0; collectedRentAmount = rentResult || 0;
} catch (e) { } catch (e) {
console.warn('统计租金失败:', e.message); console.warn('统计租金失败:', e.message);
@ -189,13 +187,8 @@ const getDashboardStatistics = async (req, res) => {
} }
try { try {
// 尝试从Bill表统计水费收入
const waterResult = await Bill.sum('receivedAmount', { const waterResult = await Bill.sum('receivedAmount', {
where: { where: { tenantId, category: 'water', status: 'paid', isDeleted: 0 }
category: 'water',
status: 'paid',
isDeleted: 0
}
}); });
collectedWaterAmount = waterResult || 0; collectedWaterAmount = waterResult || 0;
} catch (e) { } catch (e) {
@ -227,10 +220,10 @@ const getDashboardStatistics = async (req, res) => {
const getApartmentRoomStatusStatistics = async (req, res) => { const getApartmentRoomStatusStatistics = async (req, res) => {
try { try {
// 获取所有公寓(排除已删除的) // 获取所有公寓(排除已删除的)
const apartments = await Apartment.findAll({ where: { isDeleted: 0 } }); const apartments = await Apartment.findAll({ where: { tenantId: req.user.tenantId, isDeleted: 0 } });
// 获取所有房间(排除已删除的) // 获取所有房间(排除已删除的)
const rooms = await Room.findAll({ where: { isDeleted: 0 } }); const rooms = await Room.findAll({ where: { tenantId: req.user.tenantId, isDeleted: 0 } });
// 构建公寓房间状态分布数据 // 构建公寓房间状态分布数据
const apartmentRoomStatusStatistics = apartments.map(apartment => { const apartmentRoomStatusStatistics = apartments.map(apartment => {
@ -280,11 +273,12 @@ const getApartmentRoomStatusStatistics = async (req, res) => {
const getEmptyRoomsByApartment = async (req, res) => { const getEmptyRoomsByApartment = async (req, res) => {
try { try {
// 获取所有公寓(排除已删除的) // 获取所有公寓(排除已删除的)
const apartments = await Apartment.findAll({ where: { isDeleted: 0 } }); const apartments = await Apartment.findAll({ where: { tenantId: req.user.tenantId, isDeleted: 0 } });
// 获取所有空房(排除已删除的) // 获取所有空房(排除已删除的)
const emptyRooms = await Room.findAll({ const emptyRooms = await Room.findAll({
where: { where: {
tenantId: req.user.tenantId,
status: 'empty', status: 'empty',
isDeleted: 0 isDeleted: 0
} }
@ -319,11 +313,12 @@ const getEmptyRoomsByApartment = async (req, res) => {
const getRentedRoomsByApartment = async (req, res) => { const getRentedRoomsByApartment = async (req, res) => {
try { try {
// 获取所有公寓(排除已删除的) // 获取所有公寓(排除已删除的)
const apartments = await Apartment.findAll({ where: { isDeleted: 0 } }); const apartments = await Apartment.findAll({ where: { tenantId: req.user.tenantId, isDeleted: 0 } });
// 获取所有在租房(排除已删除的) // 获取所有在租房(排除已删除的)
const rentedRooms = await Room.findAll({ const rentedRooms = await Room.findAll({
where: { where: {
tenantId: req.user.tenantId,
status: 'rented', status: 'rented',
isDeleted: 0 isDeleted: 0
} }
@ -357,26 +352,32 @@ const getRentedRoomsByApartment = async (req, res) => {
// 租客在租统计 // 租客在租统计
const getTenantRentalStats = async (req, res) => { const getTenantRentalStats = async (req, res) => {
try { try {
const tenantId = req.user.tenantId;
// 获取所有在租的租赁记录(排除已删除的) // 获取所有在租的租赁记录(排除已删除的)
const rentals = await Rental.findAll({ const rentals = await Rental.findAll({
where: { where: {
tenantId,
status: 'active', status: 'active',
isDeleted: 0 isDeleted: 0
}, },
include: [{ include: [{
model: Room, model: Room,
where: { isDeleted: 0 } where: { isDeleted: 0 }
}, {
model: Renter,
attributes: ['id', 'name']
}] }]
}); });
// 获取所有公寓(排除已删除的) // 获取所有公寓(排除已删除的)
const apartments = await Apartment.findAll({ where: { isDeleted: 0 } }); const apartments = await Apartment.findAll({ where: { tenantId, isDeleted: 0 } });
// 按租客分组 // 按租客分组
const tenantMap = new Map(); const tenantMap = new Map();
rentals.forEach(rental => { rentals.forEach(rental => {
const tenantName = rental.tenantName; const tenantName = rental.Renter ? rental.Renter.name : '未知租客';
const room = rental.Room; const room = rental.Room;
if (!tenantMap.has(tenantName)) { if (!tenantMap.has(tenantName)) {
@ -425,11 +426,12 @@ const getTenantRentalStats = async (req, res) => {
const getSoonExpireRoomsByApartment = async (req, res) => { const getSoonExpireRoomsByApartment = async (req, res) => {
try { try {
// 获取所有公寓(排除已删除的) // 获取所有公寓(排除已删除的)
const apartments = await Apartment.findAll({ where: { isDeleted: 0 } }); const apartments = await Apartment.findAll({ where: { tenantId: req.user.tenantId, isDeleted: 0 } });
// 获取所有即将到期的房间(排除已删除的) // 获取所有即将到期的房间(排除已删除的)
const soonExpireRooms = await Room.findAll({ const soonExpireRooms = await Room.findAll({
where: { where: {
tenantId: req.user.tenantId,
status: 'rented', status: 'rented',
rentalStatus: 'soon_expire', rentalStatus: 'soon_expire',
isDeleted: 0 isDeleted: 0
@ -465,11 +467,12 @@ const getSoonExpireRoomsByApartment = async (req, res) => {
const getExpiredRoomsByApartment = async (req, res) => { const getExpiredRoomsByApartment = async (req, res) => {
try { try {
// 获取所有公寓(排除已删除的) // 获取所有公寓(排除已删除的)
const apartments = await Apartment.findAll({ where: { isDeleted: 0 } }); const apartments = await Apartment.findAll({ where: { tenantId: req.user.tenantId, isDeleted: 0 } });
// 获取所有已到期的房间(排除已删除的) // 获取所有已到期的房间(排除已删除的)
const expiredRooms = await Room.findAll({ const expiredRooms = await Room.findAll({
where: { where: {
tenantId: req.user.tenantId,
status: 'rented', status: 'rented',
rentalStatus: 'expired', rentalStatus: 'expired',
isDeleted: 0 isDeleted: 0

View File

@ -1,6 +1,25 @@
const { Tenant, User, Apartment, Room, Category, Setting } = require('../models'); const { Tenant, User, Apartment, Room, Category, Setting } = require('../models');
const bcrypt = require('bcryptjs'); const bcrypt = require('bcryptjs');
// 格式化日期时间(年月日时分秒)
const formatDateTime = (date) => {
if (!date) return null;
const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null;
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().replace('T', ' ').slice(0, 19);
};
// 格式化租户数据
const formatTenantData = (tenant) => {
const data = tenant.toJSON ? tenant.toJSON() : tenant;
return {
...data,
createTime: formatDateTime(data.createTime),
updateTime: formatDateTime(data.updateTime)
};
};
// 获取租户列表(超级管理员) // 获取租户列表(超级管理员)
const getTenantList = async (req, res) => { const getTenantList = async (req, res) => {
try { try {
@ -66,7 +85,7 @@ const getTenantDetail = async (req, res) => {
res.json({ res.json({
code: 200, code: 200,
data: { data: {
...tenant.toJSON(), ...formatTenantData(tenant),
stats: { stats: {
userCount, userCount,
apartmentCount, apartmentCount,
@ -297,7 +316,7 @@ const getCurrentTenant = async (req, res) => {
res.json({ res.json({
code: 200, code: 200,
data: { data: {
...tenant.toJSON(), ...formatTenantData(tenant),
stats: { stats: {
userCount, userCount,
apartmentCount, apartmentCount,

View File

@ -6,13 +6,32 @@ const Tenant = require('../models/Tenant');
const { logOperation } = require('../utils/logger'); const { logOperation } = require('../utils/logger');
const response = require('../utils/response'); const response = require('../utils/response');
// 格式化日期时间(年月日时分秒)
const formatDateTime = (date) => {
if (!date) return null;
const dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj.getTime())) return null;
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
return beijingDate.toISOString().replace('T', ' ').slice(0, 19);
};
// 格式化用户数据
const formatUserData = (user) => {
const data = user.toJSON ? user.toJSON() : user;
return {
...data,
createTime: formatDateTime(data.createTime),
updateTime: formatDateTime(data.updateTime)
};
};
// 获取用户列表 // 获取用户列表
exports.getUserList = async (req, res) => { exports.getUserList = async (req, res) => {
try { try {
const { page = 1, pageSize = 10, username, roleId, status } = req.query; const { page = 1, pageSize = 10, username, roleId, status } = req.query;
// 构建查询条件 - 只查询普通用户(不包括系统管理员) // 构建查询条件 - 只查询普通用户(不包括系统管理员)
const where = { isDeleted: 0, userType: 'user' }; const where = { tenantId: req.user.tenantId, isDeleted: 0, userType: 'user' };
if (username) { if (username) {
where.username = { [Op.like]: `%${username}%` }; where.username = { [Op.like]: `%${username}%` };
} }
@ -38,7 +57,7 @@ exports.getUserList = async (req, res) => {
}); });
response.success(res, '获取成功', { response.success(res, '获取成功', {
list: rows, list: rows.map(formatUserData),
total: count, total: count,
page: parseInt(page), page: parseInt(page),
pageSize: parseInt(pageSize) pageSize: parseInt(pageSize)
@ -54,8 +73,8 @@ exports.getUserById = async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const user = await User.findByPk(id, { const user = await User.findOne({
where: { isDeleted: 0 }, where: { id, tenantId: req.user.tenantId, isDeleted: 0 },
attributes: ['id', 'username', 'nickname', 'roleId', 'status', 'createTime', 'updateTime'], attributes: ['id', 'username', 'nickname', 'roleId', 'status', 'createTime', 'updateTime'],
include: [{ include: [{
model: Role, model: Role,
@ -68,7 +87,7 @@ exports.getUserById = async (req, res) => {
return response.notFound(res, '用户不存在'); return response.notFound(res, '用户不存在');
} }
response.success(res, '获取成功', user); response.success(res, '获取成功', formatUserData(user));
// 记录操作日志 // 记录操作日志
await logOperation({ await logOperation({
@ -147,8 +166,8 @@ exports.createUser = async (req, res) => {
return response.badRequest(res, '角色不存在或已禁用'); return response.badRequest(res, '角色不存在或已禁用');
} }
// 检查用户名是否已存在 // 检查用户名是否已存在(同一租户下)
const existingUser = await User.findOne({ where: { username, isDeleted: 0 } }); const existingUser = await User.findOne({ where: { username, tenantId: req.user.tenantId, isDeleted: 0 } });
if (existingUser) { if (existingUser) {
return response.badRequest(res, '用户名已存在'); return response.badRequest(res, '用户名已存在');
} }
@ -172,7 +191,7 @@ exports.createUser = async (req, res) => {
username: user.username, username: user.username,
nickname: user.nickname, nickname: user.nickname,
roleId: user.roleId, roleId: user.roleId,
createTime: user.createTime, createTime: formatDateTime(user.createTime),
warning: isOverage && tenant ? `当前已超出套餐限制(${tenant.maxUsers}人),续费时将收取超额费用` : null warning: isOverage && tenant ? `当前已超出套餐限制(${tenant.maxUsers}人),续费时将收取超额费用` : null
}); });
@ -201,8 +220,8 @@ exports.updateUser = async (req, res) => {
const { nickname, roleId, status } = req.body; const { nickname, roleId, status } = req.body;
// 查找用户 // 查找用户
const user = await User.findByPk(id, { const user = await User.findOne({
where: { isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!user) { if (!user) {
return response.notFound(res, '用户不存在'); return response.notFound(res, '用户不存在');
@ -235,7 +254,7 @@ exports.updateUser = async (req, res) => {
nickname: user.nickname, nickname: user.nickname,
roleId: user.roleId, roleId: user.roleId,
status: user.status, status: user.status,
updateTime: user.updateTime updateTime: formatDateTime(user.updateTime)
}); });
// 记录操作日志 // 记录操作日志
@ -267,8 +286,8 @@ exports.deleteUser = async (req, res) => {
} }
// 查找用户 // 查找用户
const user = await User.findByPk(id, { const user = await User.findOne({
where: { isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!user) { if (!user) {
return response.notFound(res, '用户不存在'); return response.notFound(res, '用户不存在');
@ -307,8 +326,8 @@ exports.resetUserPassword = async (req, res) => {
const defaultPassword = '123456'; const defaultPassword = '123456';
// 查找用户 // 查找用户
const user = await User.findByPk(id, { const user = await User.findOne({
where: { isDeleted: 0 } where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
}); });
if (!user) { if (!user) {
return response.notFound(res, '用户不存在'); return response.notFound(res, '用户不存在');
@ -349,11 +368,11 @@ exports.resetUserPassword = async (req, res) => {
exports.getAllUsers = async (req, res) => { exports.getAllUsers = async (req, res) => {
try { try {
const users = await User.findAll({ const users = await User.findAll({
where: { isDeleted: 0, status: 'active' }, where: { tenantId: req.user.tenantId, isDeleted: 0, status: 'active' },
attributes: ['id', 'username', 'nickname'] attributes: ['id', 'username', 'nickname']
}); });
response.success(res, '获取用户列表成功', users); response.success(res, '获取用户列表成功', users.map(formatUserData));
} catch (error) { } catch (error) {
console.error('获取用户列表错误:', error); console.error('获取用户列表错误:', error);
response.serverError(res, '获取用户列表失败', error); response.serverError(res, '获取用户列表失败', error);
@ -376,7 +395,7 @@ exports.getCurrentUserInfo = async (req, res) => {
return response.notFound(res, '用户不存在'); return response.notFound(res, '用户不存在');
} }
response.success(res, '获取用户信息成功', user); response.success(res, '获取用户信息成功', formatUserData(user));
} catch (error) { } catch (error) {
console.error('获取用户信息失败:', error); console.error('获取用户信息失败:', error);
response.serverError(res, '获取用户信息失败', error); response.serverError(res, '获取用户信息失败', error);
@ -422,8 +441,8 @@ exports.updateUserProfile = async (req, res) => {
username: user.username, username: user.username,
nickname: user.nickname, nickname: user.nickname,
status: user.status, status: user.status,
createTime: user.createTime, createTime: formatDateTime(user.createTime),
updateTime: user.updateTime updateTime: formatDateTime(user.updateTime)
}); });
} catch (error) { } catch (error) {
console.error('更新个人资料失败:', error); console.error('更新个人资料失败:', error);

View File

@ -1,15 +1,23 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const settingController = require('../controllers/settingController'); const settingController = require('../controllers/settingController');
const { authMiddleware, adminMiddleware } = require('../middleware/auth');
// 设置相关接口 // 所有设置接口都需要认证
router.use(authMiddleware);
// 设置相关接口(读取)
router.get('/', settingController.getSettings); router.get('/', settingController.getSettings);
router.put('/', settingController.updateSettings);
// 类目相关接口 // 设置相关接口(写入需要管理员权限)
router.put('/', adminMiddleware, settingController.updateSettings);
// 类目相关接口(读取)
router.get('/categories', settingController.getCategories); router.get('/categories', settingController.getCategories);
router.post('/categories', settingController.createCategory);
router.put('/categories/:id', settingController.updateCategory); // 类目相关接口(写入需要管理员权限)
router.delete('/categories/:id', settingController.deleteCategory); router.post('/categories', adminMiddleware, settingController.createCategory);
router.put('/categories/:id', adminMiddleware, settingController.updateCategory);
router.delete('/categories/:id', adminMiddleware, settingController.deleteCategory);
module.exports = router; module.exports = router;

View File

@ -1,6 +1,10 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const statisticsController = require('../controllers/statisticsController'); const statisticsController = require('../controllers/statisticsController');
const { authMiddleware } = require('../middleware/auth');
// 所有统计接口都需要认证
router.use(authMiddleware);
// 路由 // 路由
router.get('/rent', statisticsController.getRentStatistics); router.get('/rent', statisticsController.getRentStatistics);