This commit is contained in:
parent
ed4ff56082
commit
a4ed46d10a
|
|
@ -9,7 +9,7 @@ const dbConfig = {
|
|||
local: {
|
||||
host: 'localhost',
|
||||
user: 'root',
|
||||
password: 'root',
|
||||
password: '123456',
|
||||
database: 'rentease'
|
||||
},
|
||||
development: {
|
||||
|
|
|
|||
|
|
@ -6,19 +6,25 @@ const response = require('../utils/response');
|
|||
// 格式化时间(考虑时区,转换为北京时间)
|
||||
const formatDate = (date) => {
|
||||
if (!date) return null;
|
||||
// 确保date是Date对象
|
||||
const dateObj = date instanceof Date ? date : new Date(date);
|
||||
// 创建一个新的Date对象,加上8小时的时区偏移
|
||||
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
|
||||
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) => {
|
||||
return {
|
||||
...apartment.toJSON(),
|
||||
createTime: formatDate(apartment.createTime),
|
||||
updateTime: formatDate(apartment.updateTime)
|
||||
createTime: formatDateTime(apartment.createTime),
|
||||
updateTime: formatDateTime(apartment.updateTime)
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -28,7 +34,7 @@ const getAllApartments = async (req, res) => {
|
|||
const { regionId, name, page = 1, pageSize = 10 } = req.query;
|
||||
|
||||
// 构建查询条件
|
||||
const where = { isDeleted: 0 };
|
||||
const where = { tenantId: req.user.tenantId, isDeleted: 0 };
|
||||
if (regionId) {
|
||||
where.regionId = regionId;
|
||||
}
|
||||
|
|
@ -37,10 +43,10 @@ const getAllApartments = async (req, res) => {
|
|||
[Op.like]: `%${name}%`
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// 计算偏移量
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
|
||||
// 查询公寓数据
|
||||
const { count, rows } = await Apartment.findAndCountAll({
|
||||
where,
|
||||
|
|
@ -68,7 +74,7 @@ const getApartmentById = async (req, res) => {
|
|||
try {
|
||||
const { id } = req.params;
|
||||
const apartment = await Apartment.findOne({
|
||||
where: { id, isDeleted: 0 }
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!apartment) {
|
||||
return response.notFound(res, '公寓不存在');
|
||||
|
|
@ -135,7 +141,7 @@ const updateApartment = async (req, res) => {
|
|||
const { id } = req.params;
|
||||
const { name, address, description } = req.body;
|
||||
const apartment = await Apartment.findOne({
|
||||
where: { id, isDeleted: 0 }
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!apartment) {
|
||||
return response.notFound(res, '公寓不存在');
|
||||
|
|
@ -157,7 +163,7 @@ const deleteApartment = async (req, res) => {
|
|||
try {
|
||||
const { id } = req.params;
|
||||
const apartment = await Apartment.findOne({
|
||||
where: { id, isDeleted: 0 }
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!apartment) {
|
||||
return response.notFound(res, '公寓不存在');
|
||||
|
|
@ -178,7 +184,7 @@ const listApartments = async (req, res) => {
|
|||
const { regionId, name } = req.query;
|
||||
|
||||
// 构建查询条件
|
||||
const where = { isDeleted: 0 };
|
||||
const where = { tenantId: req.user.tenantId, isDeleted: 0 };
|
||||
if (regionId) {
|
||||
where.regionId = regionId;
|
||||
}
|
||||
|
|
@ -187,7 +193,7 @@ const listApartments = async (req, res) => {
|
|||
[Op.like]: `%${name}%`
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// 查询公寓数据
|
||||
const apartments = await Apartment.findAll({
|
||||
where
|
||||
|
|
|
|||
|
|
@ -3,6 +3,26 @@ const { Op } = require('sequelize');
|
|||
const billingService = require('../services/billingService');
|
||||
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) => {
|
||||
try {
|
||||
|
|
@ -318,7 +338,7 @@ const getOrders = async (req, res) => {
|
|||
});
|
||||
|
||||
response.success(res, '获取订单列表成功', {
|
||||
list: rows,
|
||||
list: rows.map(formatOrderData),
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
|
|
@ -430,7 +450,7 @@ const createOrder = async (req, res) => {
|
|||
});
|
||||
|
||||
response.created(res, '订单创建成功', {
|
||||
order: createdOrder.toJSON(),
|
||||
order: formatOrderData(createdOrder),
|
||||
details: amountInfo.details
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
@ -476,7 +496,7 @@ const getOrderDetail = async (req, res) => {
|
|||
return response.forbidden(res, '无权查看此订单');
|
||||
}
|
||||
|
||||
response.success(res, '获取订单详情成功', order);
|
||||
response.success(res, '获取订单详情成功', formatOrderData(order));
|
||||
} catch (error) {
|
||||
console.error('获取订单详情失败:', error);
|
||||
response.serverError(res, '获取订单详情失败', error);
|
||||
|
|
@ -582,9 +602,9 @@ const payOrder = async (req, res) => {
|
|||
response.success(res, '支付成功', {
|
||||
payment,
|
||||
order: {
|
||||
...order.toJSON(),
|
||||
...formatOrderData(order),
|
||||
status: 'paid',
|
||||
paidTime: paidTime
|
||||
paidTime: formatDateTime(paidTime)
|
||||
},
|
||||
tenant: paymentResult
|
||||
});
|
||||
|
|
@ -632,7 +652,11 @@ const getPayments = async (req, 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,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,29 @@ const RoleMenu = require('../models/RoleMenu');
|
|||
const { logOperation } = require('../utils/logger');
|
||||
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) => {
|
||||
try {
|
||||
|
|
@ -61,7 +84,7 @@ exports.getMenuList = async (req, res) => {
|
|||
});
|
||||
|
||||
response.success(res, '获取成功', {
|
||||
list: rows,
|
||||
list: rows.map(formatMenuData),
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
|
|
@ -85,7 +108,7 @@ exports.getMenuById = async (req, res) => {
|
|||
return response.notFound(res, '菜单不存在');
|
||||
}
|
||||
|
||||
response.success(res, '获取成功', menu);
|
||||
response.success(res, '获取成功', formatMenuData(menu));
|
||||
} catch (error) {
|
||||
console.error('获取菜单详情失败:', error);
|
||||
response.serverError(res, '获取菜单详情失败', error);
|
||||
|
|
@ -149,7 +172,7 @@ exports.createMenu = async (req, res) => {
|
|||
status: 'success'
|
||||
});
|
||||
|
||||
response.success(res, '创建成功', menu);
|
||||
response.success(res, '创建成功', formatMenuData(menu));
|
||||
} catch (error) {
|
||||
console.error('创建菜单失败:', error);
|
||||
response.serverError(res, '创建菜单失败', error);
|
||||
|
|
@ -221,7 +244,7 @@ exports.updateMenu = async (req, res) => {
|
|||
status: 'success'
|
||||
});
|
||||
|
||||
response.success(res, '更新成功', menu);
|
||||
response.success(res, '更新成功', formatMenuData(menu));
|
||||
} catch (error) {
|
||||
console.error('更新菜单失败:', error);
|
||||
response.serverError(res, '更新菜单失败', error);
|
||||
|
|
@ -306,7 +329,7 @@ exports.getRoleMenus = async (req, res) => {
|
|||
|
||||
const menus = roleData ? roleData.menus : [];
|
||||
|
||||
response.success(res, '获取成功', menus);
|
||||
response.success(res, '获取成功', menus.map(formatMenuData));
|
||||
} catch (error) {
|
||||
console.error('获取角色菜单失败:', error);
|
||||
response.serverError(res, '获取角色菜单失败', error);
|
||||
|
|
@ -446,7 +469,7 @@ function buildTree(menus, parentId = null) {
|
|||
.filter(menu => menu.parentId === parentId)
|
||||
.map(menu => {
|
||||
// 获取菜单的原始数据
|
||||
const menuData = menu.toJSON ? menu.toJSON() : menu;
|
||||
const menuData = formatMenuData(menu);
|
||||
return {
|
||||
...menuData,
|
||||
children: buildTree(menus, menu.id)
|
||||
|
|
|
|||
|
|
@ -5,29 +5,36 @@ const response = require('../utils/response');
|
|||
// 格式化时间(考虑时区,转换为北京时间)
|
||||
const formatDate = (date) => {
|
||||
if (!date) return null;
|
||||
// 确保 date 是 Date 对象
|
||||
const dateObj = date instanceof Date ? date : new Date(date);
|
||||
if (isNaN(dateObj.getTime())) return null;
|
||||
// 创建一个新的Date对象,加上8小时的时区偏移
|
||||
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
|
||||
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 formattedRental = {
|
||||
...rental.toJSON(),
|
||||
startDate: formatDate(rental.startDate),
|
||||
endDate: formatDate(rental.endDate),
|
||||
createTime: formatDate(rental.createTime),
|
||||
updateTime: formatDate(rental.updateTime)
|
||||
createTime: formatDateTime(rental.createTime),
|
||||
updateTime: formatDateTime(rental.updateTime)
|
||||
};
|
||||
|
||||
return formattedRental;
|
||||
};
|
||||
|
||||
// 检查并更新租房状态
|
||||
const checkAndUpdateRentalStatus = async () => {
|
||||
const checkAndUpdateRentalStatus = async (tenantId) => {
|
||||
try {
|
||||
// 获取当前日期
|
||||
const currentDate = new Date();
|
||||
|
|
@ -35,9 +42,9 @@ const checkAndUpdateRentalStatus = async () => {
|
|||
const fiveDaysLater = new Date();
|
||||
fiveDaysLater.setDate(currentDate.getDate() + 5);
|
||||
|
||||
// 查找所有活跃的租房记录
|
||||
// 查找该租户下所有活跃的租房记录
|
||||
const rentals = await Rental.findAll({
|
||||
where: { status: 'active', isDeleted: 0 },
|
||||
where: { tenantId, status: 'active', isDeleted: 0 },
|
||||
include: [
|
||||
{
|
||||
model: Room,
|
||||
|
|
@ -82,7 +89,7 @@ const checkAndUpdateRentalStatus = async () => {
|
|||
const getAllRentals = async (req, res) => {
|
||||
try {
|
||||
// 先检查并更新租房状态
|
||||
await checkAndUpdateRentalStatus();
|
||||
await checkAndUpdateRentalStatus(req.user.tenantId);
|
||||
|
||||
const {
|
||||
apartmentId,
|
||||
|
|
@ -98,7 +105,7 @@ const getAllRentals = async (req, res) => {
|
|||
} = req.query;
|
||||
|
||||
// 构建查询条件
|
||||
const where = { isDeleted: 0 };
|
||||
const where = { tenantId: req.user.tenantId, isDeleted: 0 };
|
||||
if (status) {
|
||||
where.status = status;
|
||||
}
|
||||
|
|
@ -166,7 +173,7 @@ const getRentalById = async (req, res) => {
|
|||
try {
|
||||
const { id } = req.params;
|
||||
const rental = await Rental.findOne({
|
||||
where: { id, isDeleted: 0 },
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 },
|
||||
include: [
|
||||
{
|
||||
model: Room,
|
||||
|
|
@ -269,6 +276,7 @@ const createRental = async (req, res) => {
|
|||
electricityMeterStart: body.electricityMeterStart || null,
|
||||
status: body.status || 'active',
|
||||
remark: body.remark,
|
||||
tenantId: req.user.tenantId,
|
||||
createBy: req.user.id,
|
||||
updateBy: req.user.id
|
||||
});
|
||||
|
|
@ -280,16 +288,17 @@ const createRental = async (req, res) => {
|
|||
|
||||
// 自动生成租金账单
|
||||
await Bill.create({
|
||||
billNo: 'B' + Date.now(),
|
||||
rentalId: rental.id,
|
||||
roomId: parsedRoomId,
|
||||
renterId: parsedRenterId,
|
||||
type: 'income',
|
||||
category: 'rent',
|
||||
amount: body.rent,
|
||||
paidAmount: 0,
|
||||
status: 'pending',
|
||||
dueDate: body.endDate,
|
||||
periodStart: body.startDate,
|
||||
periodEnd: body.endDate,
|
||||
receivableAmount: body.rent,
|
||||
receivedAmount: 0,
|
||||
status: 'unpaid',
|
||||
billDate: body.startDate,
|
||||
billMonth: body.startDate.substring(0, 7),
|
||||
remark: `租约租金 - ${renterName}`,
|
||||
tenantId: req.user.tenantId,
|
||||
createBy: req.user.id,
|
||||
|
|
@ -299,14 +308,17 @@ const createRental = async (req, res) => {
|
|||
// 自动生成押金账单(如果有押金)
|
||||
if (deposit > 0) {
|
||||
await Bill.create({
|
||||
billNo: 'B' + Date.now() + '1',
|
||||
rentalId: rental.id,
|
||||
roomId: parsedRoomId,
|
||||
renterId: parsedRenterId,
|
||||
type: 'income',
|
||||
category: 'deposit',
|
||||
amount: deposit,
|
||||
paidAmount: 0,
|
||||
status: 'pending',
|
||||
dueDate: body.startDate,
|
||||
receivableAmount: deposit,
|
||||
receivedAmount: 0,
|
||||
status: 'unpaid',
|
||||
billDate: body.startDate,
|
||||
billMonth: body.startDate.substring(0, 7),
|
||||
remark: `租约押金 - ${renterName}`,
|
||||
tenantId: req.user.tenantId,
|
||||
createBy: req.user.id,
|
||||
|
|
@ -327,7 +339,7 @@ const updateRental = async (req, res) => {
|
|||
const { id } = req.params;
|
||||
const { roomId, renterId, startDate, endDate, paymentType, rent, deposit, operator, waterMeterStart, electricityMeterStart, waterMeterEnd, electricityMeterEnd, status, remark } = req.body;
|
||||
const rental = await Rental.findOne({
|
||||
where: { id, isDeleted: 0 }
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!rental) {
|
||||
return response.notFound(res, '租房记录不存在');
|
||||
|
|
@ -362,7 +374,7 @@ const deleteRental = async (req, res) => {
|
|||
try {
|
||||
const { id } = req.params;
|
||||
const rental = await Rental.findOne({
|
||||
where: { id, isDeleted: 0 }
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!rental) {
|
||||
return response.notFound(res, '租房记录不存在');
|
||||
|
|
@ -384,7 +396,7 @@ const terminateRental = async (req, res) => {
|
|||
const { waterMeterEnd, electricityMeterEnd, remark } = req.body;
|
||||
|
||||
const rental = await Rental.findOne({
|
||||
where: { id, isDeleted: 0 },
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 },
|
||||
include: [
|
||||
{
|
||||
model: Room,
|
||||
|
|
@ -429,13 +441,16 @@ const terminateRental = async (req, res) => {
|
|||
if (waterUsage > 0 && apartment.waterPrice) {
|
||||
const waterAmount = waterUsage * parseFloat(apartment.waterPrice);
|
||||
await Bill.create({
|
||||
billNo: 'B' + Date.now(),
|
||||
rentalId: rental.id,
|
||||
roomId: room.id,
|
||||
renterId: rental.renterId,
|
||||
type: 'income',
|
||||
category: 'water',
|
||||
amount: waterAmount,
|
||||
paidAmount: 0,
|
||||
status: 'pending',
|
||||
receivableAmount: waterAmount,
|
||||
receivedAmount: 0,
|
||||
status: 'unpaid',
|
||||
billDate: new Date(),
|
||||
remark: `退租水费 - ${renterName}(用量:${waterUsage.toFixed(2)}吨)`,
|
||||
tenantId: req.user.tenantId,
|
||||
createBy: req.user.id,
|
||||
|
|
@ -449,13 +464,16 @@ const terminateRental = async (req, res) => {
|
|||
if (electricityUsage > 0 && apartment.electricityPrice) {
|
||||
const electricityAmount = electricityUsage * parseFloat(apartment.electricityPrice);
|
||||
await Bill.create({
|
||||
billNo: 'B' + Date.now() + '1',
|
||||
rentalId: rental.id,
|
||||
roomId: room.id,
|
||||
renterId: rental.renterId,
|
||||
type: 'income',
|
||||
category: 'electricity',
|
||||
amount: electricityAmount,
|
||||
paidAmount: 0,
|
||||
status: 'pending',
|
||||
receivableAmount: electricityAmount,
|
||||
receivedAmount: 0,
|
||||
status: 'unpaid',
|
||||
billDate: new Date(),
|
||||
remark: `退租电费 - ${renterName}(用量:${electricityUsage.toFixed(2)}度)`,
|
||||
tenantId: req.user.tenantId,
|
||||
createBy: req.user.id,
|
||||
|
|
@ -481,7 +499,7 @@ const terminateRental = async (req, res) => {
|
|||
const listRentals = async (req, res) => {
|
||||
try {
|
||||
// 先检查并更新租房状态
|
||||
await checkAndUpdateRentalStatus();
|
||||
await checkAndUpdateRentalStatus(req.user.tenantId);
|
||||
|
||||
const {
|
||||
apartmentId,
|
||||
|
|
@ -495,7 +513,7 @@ const listRentals = async (req, res) => {
|
|||
} = req.query;
|
||||
|
||||
// 构建查询条件
|
||||
const where = { isDeleted: 0 };
|
||||
const where = { tenantId: req.user.tenantId, isDeleted: 0 };
|
||||
if (status) {
|
||||
where.status = status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,25 @@ const { Renter, Rental, Room, Apartment } = require('../models');
|
|||
const { Op } = require('sequelize');
|
||||
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) => {
|
||||
try {
|
||||
|
|
@ -30,7 +49,7 @@ const getRenters = async (req, res) => {
|
|||
});
|
||||
|
||||
response.success(res, '获取成功', {
|
||||
list: rows,
|
||||
list: rows.map(formatRenterData),
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
|
|
@ -66,7 +85,7 @@ const getRenterList = async (req, res) => {
|
|||
order: [['createTime', 'DESC']]
|
||||
});
|
||||
|
||||
response.success(res, '获取成功', rows);
|
||||
response.success(res, '获取成功', rows.map(formatRenterData));
|
||||
} catch (error) {
|
||||
console.error('获取租客列表失败:', error);
|
||||
response.serverError(res, '获取租客列表失败', error);
|
||||
|
|
@ -107,7 +126,13 @@ const getRenterById = async (req, res) => {
|
|||
|
||||
response.success(res, '获取成功', {
|
||||
...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) {
|
||||
console.error('获取租客详情失败:', error);
|
||||
|
|
@ -167,7 +192,7 @@ const createRenter = async (req, res) => {
|
|||
status: 'active'
|
||||
});
|
||||
|
||||
response.created(res, '创建成功', renter);
|
||||
response.created(res, '创建成功', formatRenterData(renter));
|
||||
} catch (error) {
|
||||
console.error('创建租客失败:', error);
|
||||
response.serverError(res, '创建租客失败', error);
|
||||
|
|
@ -230,7 +255,7 @@ const updateRenter = async (req, res) => {
|
|||
updateBy
|
||||
});
|
||||
|
||||
response.success(res, '更新成功', renter);
|
||||
response.success(res, '更新成功', formatRenterData(renter));
|
||||
} catch (error) {
|
||||
console.error('更新租客失败:', error);
|
||||
response.serverError(res, '更新租客失败', error);
|
||||
|
|
@ -254,7 +279,7 @@ const deleteRenter = async (req, res) => {
|
|||
// 检查是否有进行中的租赁
|
||||
const activeRentals = await Rental.count({
|
||||
where: {
|
||||
tenantName: renter.name,
|
||||
renterId: id,
|
||||
tenantId,
|
||||
status: 'active'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,28 +6,35 @@ const response = require('../utils/response');
|
|||
// 格式化时间(考虑时区,转换为北京时间)
|
||||
const formatDate = (date) => {
|
||||
if (!date) return null;
|
||||
// 确保 date 是 Date 对象
|
||||
const dateObj = date instanceof Date ? date : new Date(date);
|
||||
if (isNaN(dateObj.getTime())) return null;
|
||||
// 创建一个新的Date对象,加上8小时的时区偏移
|
||||
const beijingDate = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
|
||||
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 formattedRoom = {
|
||||
...room.toJSON(),
|
||||
createTime: formatDate(room.createTime),
|
||||
updateTime: formatDate(room.updateTime)
|
||||
createTime: formatDateTime(room.createTime),
|
||||
updateTime: formatDateTime(room.updateTime)
|
||||
};
|
||||
|
||||
// 格式化关联数据
|
||||
if (formattedRoom.Apartment) {
|
||||
formattedRoom.Apartment = {
|
||||
...formattedRoom.Apartment,
|
||||
createTime: formatDate(formattedRoom.Apartment.createTime),
|
||||
updateTime: formatDate(formattedRoom.Apartment.updateTime)
|
||||
createTime: formatDateTime(formattedRoom.Apartment.createTime),
|
||||
updateTime: formatDateTime(formattedRoom.Apartment.updateTime)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -38,8 +45,8 @@ const formatRoomData = (room) => {
|
|||
...rental,
|
||||
startDate: formatDate(rental.startDate),
|
||||
endDate: formatDate(rental.endDate),
|
||||
createTime: formatDate(rental.createTime),
|
||||
updateTime: formatDate(rental.updateTime)
|
||||
createTime: formatDateTime(rental.createTime),
|
||||
updateTime: formatDateTime(rental.updateTime)
|
||||
};
|
||||
|
||||
return formattedRental;
|
||||
|
|
@ -50,7 +57,7 @@ const formatRoomData = (room) => {
|
|||
};
|
||||
|
||||
// 检查并更新租房状态
|
||||
const checkAndUpdateRentalStatus = async () => {
|
||||
const checkAndUpdateRentalStatus = async (tenantId) => {
|
||||
try {
|
||||
// 获取当前日期
|
||||
const currentDate = new Date();
|
||||
|
|
@ -58,9 +65,9 @@ const checkAndUpdateRentalStatus = async () => {
|
|||
const fiveDaysLater = new Date();
|
||||
fiveDaysLater.setDate(currentDate.getDate() + 5);
|
||||
|
||||
// 查找所有在租的租房记录
|
||||
// 查找该租户下所有在租的租房记录
|
||||
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) => {
|
||||
try {
|
||||
// 先检查并更新租房状态
|
||||
await checkAndUpdateRentalStatus();
|
||||
await checkAndUpdateRentalStatus(req.user.tenantId);
|
||||
|
||||
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) {
|
||||
where.apartmentId = apartmentId;
|
||||
}
|
||||
|
|
@ -142,6 +149,7 @@ const getAllRooms = async (req, res) => {
|
|||
const rentals = await Rental.findAll({
|
||||
where: {
|
||||
roomId: room.id,
|
||||
tenantId: req.user.tenantId,
|
||||
status: { [Op.ne]: 'expired' },
|
||||
isDeleted: 0
|
||||
},
|
||||
|
|
@ -195,11 +203,11 @@ const getAllRooms = async (req, res) => {
|
|||
const getRoomById = async (req, res) => {
|
||||
try {
|
||||
// 先检查并更新租房状态
|
||||
await checkAndUpdateRentalStatus();
|
||||
await checkAndUpdateRentalStatus(req.user.tenantId);
|
||||
|
||||
const { id } = req.params;
|
||||
const room = await Room.findOne({
|
||||
where: { id, isDeleted: 0 },
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 },
|
||||
include: [Apartment]
|
||||
});
|
||||
if (!room) {
|
||||
|
|
@ -213,6 +221,7 @@ const getRoomById = async (req, res) => {
|
|||
const rentals = await Rental.findAll({
|
||||
where: {
|
||||
roomId: room.id,
|
||||
tenantId: req.user.tenantId,
|
||||
status: { [Op.ne]: 'expired' },
|
||||
isDeleted: 0
|
||||
},
|
||||
|
|
@ -232,7 +241,7 @@ const getRoomById = async (req, res) => {
|
|||
...rentalData,
|
||||
startDate: formatDate(rental.startDate),
|
||||
endDate: formatDate(rental.endDate),
|
||||
createTime: formatDate(rental.createTime),
|
||||
createTime: formatDateTime(rental.createTime),
|
||||
// 兼容前端显示的字段
|
||||
tenantName: rentalData.Renter ? rentalData.Renter.name : '',
|
||||
tenantPhone: rentalData.Renter ? rentalData.Renter.phone : ''
|
||||
|
|
@ -314,7 +323,7 @@ const updateRoom = async (req, res) => {
|
|||
const { id } = req.params;
|
||||
const { apartmentId, roomNumber, floor, roomType, area, monthlyPrice, yearlyPrice, deposit, sortOrder, status, rentalStatus } = req.body;
|
||||
const room = await Room.findOne({
|
||||
where: { id, isDeleted: 0 }
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!room) {
|
||||
return response.notFound(res, '房间不存在');
|
||||
|
|
@ -346,7 +355,7 @@ const deleteRoom = async (req, res) => {
|
|||
try {
|
||||
const { id } = req.params;
|
||||
const room = await Room.findOne({
|
||||
where: { id, isDeleted: 0 }
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!room) {
|
||||
return response.notFound(res, '房间不存在');
|
||||
|
|
@ -365,12 +374,12 @@ const deleteRoom = async (req, res) => {
|
|||
const listRooms = async (req, res) => {
|
||||
try {
|
||||
// 先检查并更新租房状态
|
||||
await checkAndUpdateRentalStatus();
|
||||
await checkAndUpdateRentalStatus(req.user.tenantId);
|
||||
|
||||
const { apartmentId, roomNumber, status, rentalStatus } = req.query;
|
||||
|
||||
// 构建查询条件
|
||||
const where = { isDeleted: 0 };
|
||||
const where = { tenantId: req.user.tenantId, isDeleted: 0 };
|
||||
if (apartmentId) {
|
||||
where.apartmentId = apartmentId;
|
||||
}
|
||||
|
|
@ -403,6 +412,7 @@ const listRooms = async (req, res) => {
|
|||
const rentals = await Rental.findAll({
|
||||
where: {
|
||||
roomId: room.id,
|
||||
tenantId: req.user.tenantId,
|
||||
status: { [Op.ne]: 'expired' },
|
||||
isDeleted: 0
|
||||
},
|
||||
|
|
@ -423,7 +433,7 @@ const listRooms = async (req, res) => {
|
|||
...rentalData,
|
||||
startDate: formatDate(rental.startDate),
|
||||
endDate: formatDate(rental.endDate),
|
||||
createTime: formatDate(rental.createTime),
|
||||
createTime: formatDateTime(rental.createTime),
|
||||
// 兼容前端显示的字段
|
||||
tenantName: rentalData.Renter ? rentalData.Renter.name : '',
|
||||
tenantPhone: rentalData.Renter ? rentalData.Renter.phone : ''
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const { Setting, Category } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const response = require('../utils/response');
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const { Room, Rental, Apartment, Bill } = require('../models');
|
||||
const { Room, Rental, Apartment, Bill, Renter } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const response = require('../utils/response');
|
||||
|
||||
|
|
@ -27,9 +27,8 @@ const getRentStatistics = async (req, res) => {
|
|||
try {
|
||||
rentals = await Rental.findAll({
|
||||
where: {
|
||||
createTime: {
|
||||
[Op.gte]: startDate
|
||||
},
|
||||
tenantId: req.user.tenantId,
|
||||
createTime: { [Op.gte]: startDate },
|
||||
isDeleted: 0
|
||||
}
|
||||
});
|
||||
|
|
@ -66,10 +65,9 @@ const getRentStatistics = async (req, res) => {
|
|||
try {
|
||||
const expenses = await Bill.findAll({
|
||||
where: {
|
||||
tenantId: req.user.tenantId,
|
||||
type: 'expense',
|
||||
billDate: {
|
||||
[Op.gte]: startDate
|
||||
},
|
||||
billDate: { [Op.gte]: startDate },
|
||||
isDeleted: 0
|
||||
}
|
||||
});
|
||||
|
|
@ -117,7 +115,7 @@ const getRentStatistics = async (req, res) => {
|
|||
const getRoomStatusStatistics = async (req, res) => {
|
||||
try {
|
||||
// 获取所有房间(排除已删除的)
|
||||
const rooms = await Room.findAll({ where: { isDeleted: 0 } });
|
||||
const rooms = await Room.findAll({ where: { tenantId: req.user.tenantId, isDeleted: 0 } });
|
||||
|
||||
// 初始化统计数据
|
||||
let empty = 0;
|
||||
|
|
@ -162,40 +160,35 @@ const getRoomStatusStatistics = async (req, res) => {
|
|||
// Dashboard统计数据
|
||||
const getDashboardStatistics = async (req, res) => {
|
||||
try {
|
||||
// 导入所有需要的模型
|
||||
const { Apartment, Room, WaterBill, Rental, Bill } = require('../models');
|
||||
|
||||
const tenantId = req.user.tenantId;
|
||||
const baseWhere = { tenantId, isDeleted: 0 };
|
||||
|
||||
// 并行查询所有统计数据
|
||||
const [apartmentCount, roomCount, emptyRoomCount, reservedRoomCount, rentedRoomCount, soonExpireRoomCount, expiredRoomCount] = await Promise.all([
|
||||
Apartment.count({ where: { isDeleted: 0 } }),
|
||||
Room.count({ where: { isDeleted: 0 } }),
|
||||
Room.count({ where: { status: 'empty', isDeleted: 0 } }),
|
||||
Room.count({ where: { status: 'reserved', isDeleted: 0 } }),
|
||||
Room.count({ where: { status: 'rented', isDeleted: 0 } }),
|
||||
Room.count({ where: { status: 'rented', rentalStatus: 'soon_expire', isDeleted: 0 } }),
|
||||
Room.count({ where: { status: 'rented', rentalStatus: 'expired', isDeleted: 0 } })
|
||||
Apartment.count({ where: baseWhere }),
|
||||
Room.count({ where: baseWhere }),
|
||||
Room.count({ where: { ...baseWhere, status: 'empty' } }),
|
||||
Room.count({ where: { ...baseWhere, status: 'reserved' } }),
|
||||
Room.count({ where: { ...baseWhere, status: 'rented' } }),
|
||||
Room.count({ where: { ...baseWhere, status: 'rented', rentalStatus: 'soon_expire' } }),
|
||||
Room.count({ where: { ...baseWhere, status: 'rented', rentalStatus: 'expired' } })
|
||||
]);
|
||||
|
||||
// 安全地获取sum统计,处理表不存在或为空的情况
|
||||
|
||||
// 安全地获取sum统计
|
||||
let collectedRentAmount = 0;
|
||||
let collectedWaterAmount = 0;
|
||||
|
||||
|
||||
try {
|
||||
const rentResult = await Rental.sum('rent', { where: { isDeleted: 0 } });
|
||||
const rentResult = await Rental.sum('rent', { where: { tenantId, isDeleted: 0 } });
|
||||
collectedRentAmount = rentResult || 0;
|
||||
} catch (e) {
|
||||
console.warn('统计租金失败:', e.message);
|
||||
collectedRentAmount = 0;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// 尝试从Bill表统计水费收入
|
||||
const waterResult = await Bill.sum('receivedAmount', {
|
||||
where: {
|
||||
category: 'water',
|
||||
status: 'paid',
|
||||
isDeleted: 0
|
||||
}
|
||||
const waterResult = await Bill.sum('receivedAmount', {
|
||||
where: { tenantId, category: 'water', status: 'paid', isDeleted: 0 }
|
||||
});
|
||||
collectedWaterAmount = waterResult || 0;
|
||||
} catch (e) {
|
||||
|
|
@ -227,10 +220,10 @@ const getDashboardStatistics = async (req, res) => {
|
|||
const getApartmentRoomStatusStatistics = async (req, res) => {
|
||||
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 => {
|
||||
|
|
@ -280,14 +273,15 @@ const getApartmentRoomStatusStatistics = async (req, res) => {
|
|||
const getEmptyRoomsByApartment = async (req, res) => {
|
||||
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({
|
||||
where: {
|
||||
status: 'empty',
|
||||
isDeleted: 0
|
||||
}
|
||||
const emptyRooms = await Room.findAll({
|
||||
where: {
|
||||
tenantId: req.user.tenantId,
|
||||
status: 'empty',
|
||||
isDeleted: 0
|
||||
}
|
||||
});
|
||||
|
||||
// 构建按公寓分组的空房数据
|
||||
|
|
@ -319,14 +313,15 @@ const getEmptyRoomsByApartment = async (req, res) => {
|
|||
const getRentedRoomsByApartment = async (req, res) => {
|
||||
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({
|
||||
where: {
|
||||
status: 'rented',
|
||||
isDeleted: 0
|
||||
}
|
||||
const rentedRooms = await Room.findAll({
|
||||
where: {
|
||||
tenantId: req.user.tenantId,
|
||||
status: 'rented',
|
||||
isDeleted: 0
|
||||
}
|
||||
});
|
||||
|
||||
// 构建按公寓分组的在租数据
|
||||
|
|
@ -357,26 +352,32 @@ const getRentedRoomsByApartment = async (req, res) => {
|
|||
// 租客在租统计
|
||||
const getTenantRentalStats = async (req, res) => {
|
||||
try {
|
||||
const tenantId = req.user.tenantId;
|
||||
|
||||
// 获取所有在租的租赁记录(排除已删除的)
|
||||
const rentals = await Rental.findAll({
|
||||
where: {
|
||||
tenantId,
|
||||
status: 'active',
|
||||
isDeleted: 0
|
||||
},
|
||||
include: [{
|
||||
model: Room,
|
||||
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();
|
||||
|
||||
|
||||
rentals.forEach(rental => {
|
||||
const tenantName = rental.tenantName;
|
||||
const tenantName = rental.Renter ? rental.Renter.name : '未知租客';
|
||||
const room = rental.Room;
|
||||
|
||||
if (!tenantMap.has(tenantName)) {
|
||||
|
|
@ -425,15 +426,16 @@ const getTenantRentalStats = async (req, res) => {
|
|||
const getSoonExpireRoomsByApartment = async (req, res) => {
|
||||
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({
|
||||
where: {
|
||||
const soonExpireRooms = await Room.findAll({
|
||||
where: {
|
||||
tenantId: req.user.tenantId,
|
||||
status: 'rented',
|
||||
rentalStatus: 'soon_expire',
|
||||
isDeleted: 0
|
||||
}
|
||||
isDeleted: 0
|
||||
}
|
||||
});
|
||||
|
||||
// 构建按公寓分组的即将到期房间数据
|
||||
|
|
@ -465,15 +467,16 @@ const getSoonExpireRoomsByApartment = async (req, res) => {
|
|||
const getExpiredRoomsByApartment = async (req, res) => {
|
||||
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({
|
||||
where: {
|
||||
const expiredRooms = await Room.findAll({
|
||||
where: {
|
||||
tenantId: req.user.tenantId,
|
||||
status: 'rented',
|
||||
rentalStatus: 'expired',
|
||||
isDeleted: 0
|
||||
}
|
||||
isDeleted: 0
|
||||
}
|
||||
});
|
||||
|
||||
// 构建按公寓分组的已到期房间数据
|
||||
|
|
|
|||
|
|
@ -1,6 +1,25 @@
|
|||
const { Tenant, User, Apartment, Room, Category, Setting } = require('../models');
|
||||
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) => {
|
||||
try {
|
||||
|
|
@ -66,7 +85,7 @@ const getTenantDetail = async (req, res) => {
|
|||
res.json({
|
||||
code: 200,
|
||||
data: {
|
||||
...tenant.toJSON(),
|
||||
...formatTenantData(tenant),
|
||||
stats: {
|
||||
userCount,
|
||||
apartmentCount,
|
||||
|
|
@ -297,7 +316,7 @@ const getCurrentTenant = async (req, res) => {
|
|||
res.json({
|
||||
code: 200,
|
||||
data: {
|
||||
...tenant.toJSON(),
|
||||
...formatTenantData(tenant),
|
||||
stats: {
|
||||
userCount,
|
||||
apartmentCount,
|
||||
|
|
|
|||
|
|
@ -6,13 +6,32 @@ const Tenant = require('../models/Tenant');
|
|||
const { logOperation } = require('../utils/logger');
|
||||
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) => {
|
||||
try {
|
||||
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) {
|
||||
where.username = { [Op.like]: `%${username}%` };
|
||||
}
|
||||
|
|
@ -38,7 +57,7 @@ exports.getUserList = async (req, res) => {
|
|||
});
|
||||
|
||||
response.success(res, '获取成功', {
|
||||
list: rows,
|
||||
list: rows.map(formatUserData),
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
|
|
@ -54,8 +73,8 @@ exports.getUserById = async (req, res) => {
|
|||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const user = await User.findByPk(id, {
|
||||
where: { isDeleted: 0 },
|
||||
const user = await User.findOne({
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 },
|
||||
attributes: ['id', 'username', 'nickname', 'roleId', 'status', 'createTime', 'updateTime'],
|
||||
include: [{
|
||||
model: Role,
|
||||
|
|
@ -68,7 +87,7 @@ exports.getUserById = async (req, res) => {
|
|||
return response.notFound(res, '用户不存在');
|
||||
}
|
||||
|
||||
response.success(res, '获取成功', user);
|
||||
response.success(res, '获取成功', formatUserData(user));
|
||||
|
||||
// 记录操作日志
|
||||
await logOperation({
|
||||
|
|
@ -147,8 +166,8 @@ exports.createUser = async (req, 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) {
|
||||
return response.badRequest(res, '用户名已存在');
|
||||
}
|
||||
|
|
@ -172,7 +191,7 @@ exports.createUser = async (req, res) => {
|
|||
username: user.username,
|
||||
nickname: user.nickname,
|
||||
roleId: user.roleId,
|
||||
createTime: user.createTime,
|
||||
createTime: formatDateTime(user.createTime),
|
||||
warning: isOverage && tenant ? `当前已超出套餐限制(${tenant.maxUsers}人),续费时将收取超额费用` : null
|
||||
});
|
||||
|
||||
|
|
@ -201,8 +220,8 @@ exports.updateUser = async (req, res) => {
|
|||
const { nickname, roleId, status } = req.body;
|
||||
|
||||
// 查找用户
|
||||
const user = await User.findByPk(id, {
|
||||
where: { isDeleted: 0 }
|
||||
const user = await User.findOne({
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!user) {
|
||||
return response.notFound(res, '用户不存在');
|
||||
|
|
@ -235,7 +254,7 @@ exports.updateUser = async (req, res) => {
|
|||
nickname: user.nickname,
|
||||
roleId: user.roleId,
|
||||
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, {
|
||||
where: { isDeleted: 0 }
|
||||
const user = await User.findOne({
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!user) {
|
||||
return response.notFound(res, '用户不存在');
|
||||
|
|
@ -307,8 +326,8 @@ exports.resetUserPassword = async (req, res) => {
|
|||
const defaultPassword = '123456';
|
||||
|
||||
// 查找用户
|
||||
const user = await User.findByPk(id, {
|
||||
where: { isDeleted: 0 }
|
||||
const user = await User.findOne({
|
||||
where: { id, tenantId: req.user.tenantId, isDeleted: 0 }
|
||||
});
|
||||
if (!user) {
|
||||
return response.notFound(res, '用户不存在');
|
||||
|
|
@ -349,11 +368,11 @@ exports.resetUserPassword = async (req, res) => {
|
|||
exports.getAllUsers = async (req, res) => {
|
||||
try {
|
||||
const users = await User.findAll({
|
||||
where: { isDeleted: 0, status: 'active' },
|
||||
where: { tenantId: req.user.tenantId, isDeleted: 0, status: 'active' },
|
||||
attributes: ['id', 'username', 'nickname']
|
||||
});
|
||||
|
||||
response.success(res, '获取用户列表成功', users);
|
||||
response.success(res, '获取用户列表成功', users.map(formatUserData));
|
||||
} catch (error) {
|
||||
console.error('获取用户列表错误:', error);
|
||||
response.serverError(res, '获取用户列表失败', error);
|
||||
|
|
@ -376,7 +395,7 @@ exports.getCurrentUserInfo = async (req, res) => {
|
|||
return response.notFound(res, '用户不存在');
|
||||
}
|
||||
|
||||
response.success(res, '获取用户信息成功', user);
|
||||
response.success(res, '获取用户信息成功', formatUserData(user));
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
response.serverError(res, '获取用户信息失败', error);
|
||||
|
|
@ -422,8 +441,8 @@ exports.updateUserProfile = async (req, res) => {
|
|||
username: user.username,
|
||||
nickname: user.nickname,
|
||||
status: user.status,
|
||||
createTime: user.createTime,
|
||||
updateTime: user.updateTime
|
||||
createTime: formatDateTime(user.createTime),
|
||||
updateTime: formatDateTime(user.updateTime)
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新个人资料失败:', error);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,23 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const settingController = require('../controllers/settingController');
|
||||
const { authMiddleware, adminMiddleware } = require('../middleware/auth');
|
||||
|
||||
// 设置相关接口
|
||||
// 所有设置接口都需要认证
|
||||
router.use(authMiddleware);
|
||||
|
||||
// 设置相关接口(读取)
|
||||
router.get('/', settingController.getSettings);
|
||||
router.put('/', settingController.updateSettings);
|
||||
|
||||
// 类目相关接口
|
||||
// 设置相关接口(写入需要管理员权限)
|
||||
router.put('/', adminMiddleware, settingController.updateSettings);
|
||||
|
||||
// 类目相关接口(读取)
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const statisticsController = require('../controllers/statisticsController');
|
||||
const { authMiddleware } = require('../middleware/auth');
|
||||
|
||||
// 所有统计接口都需要认证
|
||||
router.use(authMiddleware);
|
||||
|
||||
// 路由
|
||||
router.get('/rent', statisticsController.getRentStatistics);
|
||||
|
|
|
|||
Loading…
Reference in New Issue