统一api返回

This commit is contained in:
wangxiaoxian 2026-04-22 14:48:32 +08:00
parent 5faf92593f
commit ed4ff56082
22 changed files with 654 additions and 2053 deletions

View File

@ -2,7 +2,7 @@ const { Sequelize } = require('sequelize');
const mysql = require('mysql2/promise');
// 环境配置
const NODE_ENV = process.env.NODE_ENV || 'development';
const NODE_ENV = process.env.NODE_ENV || 'local';
// 数据库配置
const dbConfig = {

View File

@ -1,6 +1,7 @@
const { Apartment, Tenant } = require('../models');
const { Op } = require('sequelize');
const { logOperation } = require('../utils/logger');
const response = require('../utils/response');
// 格式化时间(考虑时区,转换为北京时间)
const formatDate = (date) => {
@ -51,14 +52,14 @@ const getAllApartments = async (req, res) => {
const formattedApartments = rows.map(formatApartmentData);
// 返回结果
res.status(200).json({
data: formattedApartments,
response.success(res, '获取成功', {
list: formattedApartments,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
res.status(500).json({ error: error.message });
response.serverError(res, '获取公寓列表失败', error);
}
};
@ -70,16 +71,12 @@ const getApartmentById = async (req, res) => {
where: { id, isDeleted: 0 }
});
if (!apartment) {
return res.status(404).json({ error: '公寓不存在' });
return response.notFound(res, '公寓不存在');
}
const formattedApartment = formatApartmentData(apartment);
res.status(200).json({
code: 200,
data: formattedApartment,
message: 'success'
});
response.success(res, '获取成功', formattedApartment);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取公寓详情失败', error);
}
};
@ -90,9 +87,10 @@ const createApartment = async (req, res) => {
// 检查租户资源使用情况(仅记录日志,不阻止创建)
const tenant = await Tenant.findByPk(req.user.tenantId);
let currentApartmentCount = 0;
if (tenant) {
// 获取当前公寓数量
const currentApartmentCount = await Apartment.count({
currentApartmentCount = await Apartment.count({
where: { tenantId: req.user.tenantId, isDeleted: 0 }
});
@ -122,14 +120,12 @@ const createApartment = async (req, res) => {
createBy: req.user.id,
updateBy: req.user.id
});
res.status(201).json({
code: 201,
data: apartment,
message: '创建成功',
response.created(res, '创建成功', {
apartment,
warning: tenant && currentApartmentCount >= tenant.maxApartments ? `当前已超出套餐限制(${tenant.maxApartments}栋),续费时将收取超额费用` : null
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '创建公寓失败', error);
}
};
@ -142,7 +138,7 @@ const updateApartment = async (req, res) => {
where: { id, isDeleted: 0 }
});
if (!apartment) {
return res.status(404).json({ error: '公寓不存在' });
return response.notFound(res, '公寓不存在');
}
await apartment.update({
name,
@ -150,13 +146,9 @@ const updateApartment = async (req, res) => {
description,
updateBy: req.user.id
});
res.status(200).json({
code: 200,
data: apartment,
message: '更新成功'
});
response.success(res, '更新成功', apartment);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '更新公寓失败', error);
}
};
@ -168,18 +160,15 @@ const deleteApartment = async (req, res) => {
where: { id, isDeleted: 0 }
});
if (!apartment) {
return res.status(404).json({ error: '公寓不存在' });
return response.notFound(res, '公寓不存在');
}
await apartment.update({
isDeleted: 1,
updateBy: req.user.id
});
res.status(200).json({
code: 200,
message: '公寓删除成功'
});
response.success(res, '公寓删除成功');
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '删除公寓失败', error);
}
};
@ -208,13 +197,9 @@ const listApartments = async (req, res) => {
const formattedApartments = apartments.map(formatApartmentData);
// 返回结果
res.status(200).json({
code: 200,
data: formattedApartments,
message: 'success'
});
response.success(res, '获取成功', formattedApartments);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取公寓列表失败', error);
}
};
@ -225,4 +210,4 @@ module.exports = {
createApartment,
updateApartment,
deleteApartment
};
};

View File

@ -8,6 +8,7 @@ const Setting = require('../models/Setting');
const { SubscriptionPlan } = require('../models');
const { generateToken } = require('../middleware/auth');
const { logLogin, getClientIp } = require('../utils/logger');
const response = require('../utils/response');
// 登录
exports.login = async (req, res) => {
@ -28,10 +29,7 @@ exports.login = async (req, res) => {
status: 'fail',
message: '用户名和密码不能为空'
});
return res.status(400).json({
code: 400,
message: '用户名和密码不能为空'
});
return response.badRequest(res, '用户名和密码不能为空');
}
// 查找用户
@ -58,10 +56,7 @@ exports.login = async (req, res) => {
status: 'fail',
message: '用户名或密码错误'
});
return res.status(401).json({
code: 401,
message: '用户名或密码错误'
});
return response.unauthorized(res, '用户名或密码错误');
}
// 检查用户状态
@ -75,10 +70,7 @@ exports.login = async (req, res) => {
status: 'fail',
message: '账号已被禁用'
});
return res.status(401).json({
code: 401,
message: '账号已被禁用'
});
return response.unauthorized(res, '账号已被禁用');
}
// 验证密码
@ -93,10 +85,7 @@ exports.login = async (req, res) => {
status: 'fail',
message: '用户名或密码错误'
});
return res.status(401).json({
code: 401,
message: '用户名或密码错误'
});
return response.unauthorized(res, '用户名或密码错误');
}
// 检查租户计费状态(仅非系统管理员需要检查)
@ -112,15 +101,11 @@ exports.login = async (req, res) => {
status: 'fail',
message: '账户已过期,请续费'
});
return res.status(403).json({
code: 403,
message: '您的账户已过期,请前往续费',
data: {
expired: true,
billingStatus: billingStatus,
trialEndDate: user.tenant.trialEndDate,
paidEndDate: user.tenant.paidEndDate
}
return response.forbidden(res, '您的账户已过期,请前往续费', {
expired: true,
billingStatus: billingStatus,
trialEndDate: user.tenant.trialEndDate,
paidEndDate: user.tenant.paidEndDate
});
}
}
@ -172,22 +157,18 @@ exports.login = async (req, res) => {
});
// 返回用户信息和 Token
res.json({
code: 200,
message: '登录成功',
data: {
token,
userInfo: {
id: user.id,
username: user.username,
nickname: user.nickname,
role: user.role,
tenantId: user.tenantId,
userType: user.userType
},
tenant: user.tenant,
menus
}
response.success(res, '登录成功', {
token,
userInfo: {
id: user.id,
username: user.username,
nickname: user.nickname,
role: user.role,
tenantId: user.tenantId,
userType: user.userType
},
tenant: user.tenant,
menus
});
} catch (error) {
console.error('登录错误:', error);
@ -199,11 +180,7 @@ exports.login = async (req, res) => {
status: 'fail',
message: error.message
});
res.status(500).json({
code: 500,
message: '登录失败',
error: error.message
});
response.serverError(res, '登录失败', error);
}
};
@ -222,16 +199,10 @@ exports.logout = async (req, res) => {
message: '登出成功'
});
res.json({
code: 200,
message: '登出成功'
});
response.success(res, '登出成功');
} catch (error) {
console.error('登出错误:', error);
res.json({
code: 200,
message: '登出成功'
});
response.success(res, '登出成功');
}
};
@ -264,18 +235,10 @@ function buildMenuTree(menus, parentId = null) {
exports.getCurrentUser = async (req, res) => {
try {
// req.user 由 authMiddleware 附加
res.json({
code: 200,
message: '获取成功',
data: req.user
});
response.success(res, '获取成功', req.user);
} catch (error) {
console.error('获取用户信息错误:', error);
res.status(500).json({
code: 500,
message: '获取用户信息失败',
error: error.message
});
response.serverError(res, '获取用户信息失败', error);
}
};
@ -287,35 +250,23 @@ exports.changePassword = async (req, res) => {
// 参数验证
if (!oldPassword || !newPassword) {
return res.status(400).json({
code: 400,
message: '原密码和新密码不能为空'
});
return response.badRequest(res, '原密码和新密码不能为空');
}
if (newPassword.length < 6) {
return res.status(400).json({
code: 400,
message: '新密码长度不能少于6位'
});
return response.badRequest(res, '新密码长度不能少于6位');
}
// 查找用户
const user = await User.findByPk(userId);
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
});
return response.notFound(res, '用户不存在');
}
// 验证原密码
const isPasswordValid = await bcrypt.compare(oldPassword, user.password);
if (!isPasswordValid) {
return res.status(400).json({
code: 400,
message: '原密码错误'
});
return response.badRequest(res, '原密码错误');
}
// 加密新密码
@ -324,17 +275,10 @@ exports.changePassword = async (req, res) => {
// 更新密码
await user.update({ password: hashedPassword });
res.json({
code: 200,
message: '密码修改成功'
});
response.success(res, '密码修改成功');
} catch (error) {
console.error('修改密码错误:', error);
res.status(500).json({
code: 500,
message: '修改密码失败',
error: error.message
});
response.serverError(res, '修改密码失败', error);
}
};
@ -351,19 +295,13 @@ exports.registerTenant = async (req, res) => {
try {
// 参数验证
if (!contactName || !contactPhone || !contactEmail || !adminUsername || !adminPassword) {
return res.status(400).json({
code: 400,
message: '请填写所有必填项'
});
return response.badRequest(res, '请填写所有必填项');
}
// 检查管理员账号是否已存在
const existingUser = await User.findOne({ where: { username: adminUsername } });
if (existingUser) {
return res.status(400).json({
code: 400,
message: '管理员账号已存在'
});
return response.badRequest(res, '管理员账号已存在');
}
// 查询默认套餐
@ -375,10 +313,7 @@ exports.registerTenant = async (req, res) => {
});
if (!defaultPlan) {
return res.status(500).json({
code: 500,
message: '系统未配置默认套餐,请联系管理员'
});
return response.serverError(res, '系统未配置默认套餐,请联系管理员');
}
// 生成租户编码:时间戳 + 随机数
@ -489,21 +424,13 @@ exports.registerTenant = async (req, res) => {
});
}
res.json({
code: 200,
message: '注册成功,欢迎试用',
data: {
tenantId: tenant.id,
code: tenant.code,
status: tenant.status
}
response.success(res, '注册成功,欢迎试用', {
tenantId: tenant.id,
code: tenant.code,
status: tenant.status
});
} catch (error) {
console.error('租户注册失败:', error);
res.status(500).json({
code: 500,
message: '注册失败',
error: error.message
});
response.serverError(res, '注册失败', error);
}
};

View File

@ -1,5 +1,6 @@
const { Bill, MeterReading, Room, Renter, Rental, BillPayment } = require('../models');
const { Op } = require('sequelize');
const response = require('../utils/response');
// 生成账单编号
const generateBillNo = () => {
@ -141,16 +142,15 @@ const getAllBills = async (req, res) => {
const formattedBills = rows.map(formatBillData);
// 返回结果
res.status(200).json({
code: 200,
data: formattedBills,
response.success(res, '获取成功', {
list: formattedBills,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取账单列表失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取账单列表失败', error);
}
};
@ -170,13 +170,10 @@ const getBillsList = async (req, res) => {
const formattedBills = rows.map(formatBillData);
// 返回结果
res.status(200).json({
code: 200,
data: formattedBills
});
response.success(res, '获取成功', formattedBills);
} catch (error) {
console.error('获取账单列表失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取账单列表失败', error);
}
};
@ -211,19 +208,15 @@ const getBillById = async (req, res) => {
});
if (!bill) {
return res.status(404).json({ code: 404, error: '账单不存在' });
return response.notFound(res, '账单不存在');
}
const formattedBill = formatBillData(bill);
res.status(200).json({
code: 200,
data: formattedBill,
message: 'success'
});
response.success(res, '获取成功', formattedBill);
} catch (error) {
console.error('获取账单详情失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取账单详情失败', error);
}
};
@ -261,14 +254,10 @@ const createBill = async (req, res) => {
});
const formattedBill = formatBillData(bill);
res.status(201).json({
code: 201,
data: formattedBill,
message: '创建成功'
});
response.created(res, '创建成功', formattedBill);
} catch (error) {
console.error('创建账单失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '创建账单失败', error);
}
};
@ -293,7 +282,7 @@ const updateBill = async (req, res) => {
});
if (!bill) {
return res.status(404).json({ code: 404, error: '账单不存在' });
return response.notFound(res, '账单不存在');
}
await bill.update({
@ -309,14 +298,10 @@ const updateBill = async (req, res) => {
updateBy: req.user.id
});
res.status(200).json({
code: 200,
data: formatBillData(bill),
message: '更新成功'
});
response.success(res, '更新成功', formatBillData(bill));
} catch (error) {
console.error('更新账单失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '更新账单失败', error);
}
};
@ -329,7 +314,7 @@ const deleteBill = async (req, res) => {
});
if (!bill) {
return res.status(404).json({ code: 404, error: '账单不存在' });
return response.notFound(res, '账单不存在');
}
await bill.update({
@ -337,13 +322,10 @@ const deleteBill = async (req, res) => {
updateBy: req.user.id
});
res.status(200).json({
code: 200,
message: '账单删除成功'
});
response.success(res, '账单删除成功');
} catch (error) {
console.error('删除账单失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '删除账单失败', error);
}
};
@ -358,7 +340,7 @@ const receivePayment = async (req, res) => {
});
if (!bill) {
return res.status(404).json({ code: 404, error: '账单不存在' });
return response.notFound(res, '账单不存在');
}
const newReceivedAmount = parseFloat(bill.receivedAmount) + parseFloat(amount);
@ -378,14 +360,10 @@ const receivePayment = async (req, res) => {
updateBy: req.user.id
});
res.status(200).json({
code: 200,
data: formatBillData(bill),
message: '收款成功'
});
response.success(res, '收款成功', formatBillData(bill));
} catch (error) {
console.error('账单收款失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '账单收款失败', error);
}
};
@ -443,22 +421,19 @@ const getBillStatistics = async (req, res) => {
const totalReceivable = await Bill.sum('receivableAmount', { where });
const totalReceived = await Bill.sum('receivedAmount', { where });
res.status(200).json({
code: 200,
data: {
summary: {
totalReceivable: totalReceivable || 0,
totalReceived: totalReceived || 0,
totalUnreceived: (totalReceivable || 0) - (totalReceived || 0)
},
income: incomeStats,
expense: expenseStats,
status: statusStats
}
response.success(res, '获取成功', {
summary: {
totalReceivable: totalReceivable || 0,
totalReceived: totalReceived || 0,
totalUnreceived: (totalReceivable || 0) - (totalReceived || 0)
},
income: incomeStats,
expense: expenseStats,
status: statusStats
});
} catch (error) {
console.error('获取账单统计失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取账单统计失败', error);
}
};

View File

@ -1,5 +1,6 @@
const { BillPayment, Bill } = require('../models');
const { Op } = require('sequelize');
const response = require('../utils/response');
// 获取账单的所有支付流水
const getPaymentsByBillId = async (req, res) => {
@ -16,14 +17,10 @@ const getPaymentsByBillId = async (req, res) => {
order: [['paymentTime', 'DESC']]
});
res.status(200).json({
code: 200,
data: payments,
message: 'success'
});
response.success(res, '获取成功', payments);
} catch (error) {
console.error('获取支付流水失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取支付流水失败', error);
}
};
@ -41,15 +38,15 @@ const createPayment = async (req, res) => {
});
if (!bill) {
return res.status(404).json({ code: 404, error: '账单不存在' });
return response.notFound(res, '账单不存在');
}
if (bill.status === 'paid') {
return res.status(400).json({ code: 400, error: '该账单已收清,无法继续收款' });
return response.badRequest(res, '该账单已收清,无法继续收款');
}
if (bill.status === 'cancelled') {
return res.status(400).json({ code: 400, error: '该账单已取消,无法收款' });
return response.badRequest(res, '该账单已取消,无法收款');
}
// 计算剩余应收金额
@ -60,14 +57,11 @@ const createPayment = async (req, res) => {
// 验证支付金额
const paymentAmount = parseFloat(amount);
if (paymentAmount <= 0) {
return res.status(400).json({ code: 400, error: '支付金额必须大于0' });
return response.badRequest(res, '支付金额必须大于0');
}
if (paymentAmount > remainingAmount) {
return res.status(400).json({
code: 400,
error: `支付金额不能超过剩余应收金额 ¥${remainingAmount.toFixed(2)}`
});
return response.badRequest(res, `支付金额不能超过剩余应收金额 ¥${remainingAmount.toFixed(2)}`);
}
// 创建支付流水
@ -99,21 +93,17 @@ const createPayment = async (req, res) => {
updateBy: createBy
});
res.status(201).json({
code: 201,
data: {
payment,
bill: {
id: bill.id,
receivedAmount: newReceivedAmount,
status: newStatus
}
},
message: '收款成功'
response.created(res, '收款成功', {
payment,
bill: {
id: bill.id,
receivedAmount: newReceivedAmount,
status: newStatus
}
});
} catch (error) {
console.error('创建支付流水失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '创建支付流水失败', error);
}
};
@ -129,7 +119,7 @@ const deletePayment = async (req, res) => {
});
if (!payment) {
return res.status(404).json({ code: 404, error: '支付流水不存在' });
return response.notFound(res, '支付流水不存在');
}
// 查找关联账单
@ -138,7 +128,7 @@ const deletePayment = async (req, res) => {
});
if (!bill) {
return res.status(404).json({ code: 404, error: '关联账单不存在' });
return response.notFound(res, '关联账单不存在');
}
// 软删除支付流水
@ -170,20 +160,16 @@ const deletePayment = async (req, res) => {
updateBy
});
res.status(200).json({
code: 200,
data: {
bill: {
id: bill.id,
receivedAmount: newReceivedAmount,
status: newStatus
}
},
message: '支付流水已删除,账单状态已更新'
response.success(res, '支付流水已删除,账单状态已更新', {
bill: {
id: bill.id,
receivedAmount: newReceivedAmount,
status: newStatus
}
});
} catch (error) {
console.error('删除支付流水失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '删除支付流水失败', error);
}
};
@ -210,14 +196,10 @@ const getPaymentStatistics = async (req, res) => {
group: ['paymentMethod']
});
res.status(200).json({
code: 200,
data: payments,
message: 'success'
});
response.success(res, '获取成功', payments);
} catch (error) {
console.error('获取支付统计失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取支付统计失败', error);
}
};

View File

@ -1,6 +1,7 @@
const { SubscriptionPlan, PricingConfig, Order, Payment, Tenant, User, Apartment, Room, PaymentSetting } = require('../models');
const { Op } = require('sequelize');
const billingService = require('../services/billingService');
const response = require('../utils/response');
// 获取所有套餐列表
const getAllPlans = async (req, res) => {
@ -10,17 +11,9 @@ const getAllPlans = async (req, res) => {
order: [['sort', 'ASC']]
});
res.status(200).json({
code: 200,
message: '获取套餐列表成功',
data: plans
});
response.success(res, '获取套餐列表成功', plans);
} catch (error) {
res.status(500).json({
code: 500,
message: '获取套餐列表失败',
error: error.message
});
response.serverError(res, '获取套餐列表失败', error);
}
};
@ -31,10 +24,7 @@ const createPlan = async (req, res) => {
// 验证必填字段
if (!name) {
return res.status(400).json({
code: 400,
message: '套餐名称不能为空'
});
return response.badRequest(res, '套餐名称不能为空');
}
// 检查是否是第一个套餐
@ -52,17 +42,9 @@ const createPlan = async (req, res) => {
isDefault
});
res.status(201).json({
code: 200,
message: '套餐创建成功',
data: plan
});
response.created(res, '套餐创建成功', plan);
} catch (error) {
res.status(500).json({
code: 500,
message: '创建套餐失败',
error: error.message
});
response.serverError(res, '创建套餐失败', error);
}
};
@ -78,10 +60,7 @@ const updatePlan = async (req, res) => {
});
if (!plan) {
return res.status(400).json({
code: 400,
message: '套餐不存在'
});
return response.badRequest(res, '套餐不存在');
}
// 更新套餐信息
@ -96,17 +75,9 @@ const updatePlan = async (req, res) => {
sort: sort !== undefined ? sort : plan.sort
});
res.status(200).json({
code: 200,
message: '套餐更新成功',
data: plan
});
response.success(res, '套餐更新成功', plan);
} catch (error) {
res.status(500).json({
code: 500,
message: '更新套餐失败',
error: error.message
});
response.serverError(res, '更新套餐失败', error);
}
};
@ -121,33 +92,20 @@ const deletePlan = async (req, res) => {
});
if (!plan) {
return res.status(400).json({
code: 400,
message: '套餐不存在'
});
return response.badRequest(res, '套餐不存在');
}
// 不能删除默认套餐
if (plan.isDefault) {
return res.status(400).json({
code: 400,
message: '不能删除默认套餐'
});
return response.badRequest(res, '不能删除默认套餐');
}
// 软删除
await plan.update({ isDeleted: 1 });
res.status(200).json({
code: 200,
message: '套餐删除成功'
});
response.success(res, '套餐删除成功');
} catch (error) {
res.status(500).json({
code: 500,
message: '删除套餐失败',
error: error.message
});
response.serverError(res, '删除套餐失败', error);
}
};
@ -162,10 +120,7 @@ const setDefaultPlan = async (req, res) => {
});
if (!plan) {
return res.status(400).json({
code: 400,
message: '套餐不存在'
});
return response.badRequest(res, '套餐不存在');
}
// 将其他套餐 isDefault 设为 false
@ -177,17 +132,9 @@ const setDefaultPlan = async (req, res) => {
// 将指定套餐 isDefault 设为 true
await plan.update({ isDefault: true });
res.status(200).json({
code: 200,
message: '设置默认套餐成功',
data: plan
});
response.success(res, '设置默认套餐成功', plan);
} catch (error) {
res.status(500).json({
code: 500,
message: '设置默认套餐失败',
error: error.message
});
response.serverError(res, '设置默认套餐失败', error);
}
};
@ -202,29 +149,17 @@ const getPricingConfig = async (req, res) => {
// 如果没有则返回默认配置
if (!config) {
return res.status(200).json({
code: 200,
message: '获取价格配置成功',
data: {
overageApartmentPrice: 10.00,
overageRoomPrice: 2.00,
overageUserPrice: 5.00,
currency: 'CNY'
}
return response.success(res, '获取价格配置成功', {
overageApartmentPrice: 10.00,
overageRoomPrice: 2.00,
overageUserPrice: 5.00,
currency: 'CNY'
});
}
res.status(200).json({
code: 200,
message: '获取价格配置成功',
data: config
});
response.success(res, '获取价格配置成功', config);
} catch (error) {
res.status(500).json({
code: 500,
message: '获取价格配置失败',
error: error.message
});
response.serverError(res, '获取价格配置失败', error);
}
};
@ -247,17 +182,9 @@ const updatePricingConfig = async (req, res) => {
isActive: true
});
res.status(200).json({
code: 200,
message: '价格配置更新成功',
data: config
});
response.success(res, '价格配置更新成功', config);
} catch (error) {
res.status(500).json({
code: 500,
message: '更新价格配置失败',
error: error.message
});
response.serverError(res, '更新价格配置失败', error);
}
};
@ -267,10 +194,7 @@ const initDefaultPlans = async (req, res) => {
// 检查是否已有套餐
const existingCount = await SubscriptionPlan.count({ where: { isDeleted: 0 } });
if (existingCount > 0) {
return res.status(400).json({
code: 400,
message: '套餐数据已存在,无需初始化'
});
return response.badRequest(res, '套餐数据已存在,无需初始化');
}
// 默认套餐数据
@ -320,17 +244,9 @@ const initDefaultPlans = async (req, res) => {
// 批量创建套餐
const plans = await SubscriptionPlan.bulkCreate(defaultPlans);
res.status(200).json({
code: 200,
message: '默认套餐初始化成功',
data: plans
});
response.success(res, '默认套餐初始化成功', plans);
} catch (error) {
res.status(500).json({
code: 500,
message: '初始化默认套餐失败',
error: error.message
});
response.serverError(res, '初始化默认套餐失败', error);
}
};
@ -343,10 +259,7 @@ const initDefaultPricing = async (req, res) => {
});
if (existingConfig) {
return res.status(400).json({
code: 400,
message: '价格配置已存在,无需初始化'
});
return response.badRequest(res, '价格配置已存在,无需初始化');
}
// 创建默认价格配置
@ -357,17 +270,9 @@ const initDefaultPricing = async (req, res) => {
isActive: true
});
res.status(200).json({
code: 200,
message: '默认价格配置初始化成功',
data: config
});
response.success(res, '默认价格配置初始化成功', config);
} catch (error) {
res.status(500).json({
code: 500,
message: '初始化默认价格配置失败',
error: error.message
});
response.serverError(res, '初始化默认价格配置失败', error);
}
};
@ -412,23 +317,15 @@ const getOrders = async (req, res) => {
]
});
res.json({
code: 200,
data: {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
},
message: '获取订单列表成功'
response.success(res, '获取订单列表成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取订单列表失败:', error);
res.status(500).json({
code: 500,
message: '获取订单列表失败',
error: error.message
});
response.serverError(res, '获取订单列表失败', error);
}
};
@ -440,17 +337,11 @@ const calculatePrice = async (req, res) => {
// 验证必填字段
if (!planId || !months) {
return res.status(400).json({
code: 400,
message: '套餐ID和购买月数不能为空'
});
return response.badRequest(res, '套餐ID和购买月数不能为空');
}
if (months < 1 || months > 36) {
return res.status(400).json({
code: 400,
message: '购买月数必须在1-36之间'
});
return response.badRequest(res, '购买月数必须在1-36之间');
}
// 获取套餐信息
@ -459,27 +350,16 @@ const calculatePrice = async (req, res) => {
});
if (!plan) {
return res.status(400).json({
code: 400,
message: '套餐不存在'
});
return response.badRequest(res, '套餐不存在');
}
// 计算订单金额(含超额费用)
const amountInfo = await billingService.calculateRenewalAmount(tenantId, planId, months);
res.json({
code: 200,
message: '计算成功',
data: amountInfo
});
response.success(res, '计算成功', amountInfo);
} catch (error) {
console.error('计算价格失败:', error);
res.status(500).json({
code: 500,
message: '计算价格失败',
error: error.message
});
response.serverError(res, '计算价格失败', error);
}
};
@ -491,17 +371,11 @@ const createOrder = async (req, res) => {
// 验证必填字段
if (!planId || !months) {
return res.status(400).json({
code: 400,
message: '套餐ID和购买月数不能为空'
});
return response.badRequest(res, '套餐ID和购买月数不能为空');
}
if (months < 1 || months > 36) {
return res.status(400).json({
code: 400,
message: '购买月数必须在1-36之间'
});
return response.badRequest(res, '购买月数必须在1-36之间');
}
// 获取套餐信息
@ -510,10 +384,7 @@ const createOrder = async (req, res) => {
});
if (!plan) {
return res.status(400).json({
code: 400,
message: '套餐不存在'
});
return response.badRequest(res, '套餐不存在');
}
// 计算订单金额
@ -558,21 +429,13 @@ const createOrder = async (req, res) => {
]
});
res.status(201).json({
code: 200,
message: '订单创建成功',
data: {
order: createdOrder.toJSON(),
details: amountInfo.details
}
response.created(res, '订单创建成功', {
order: createdOrder.toJSON(),
details: amountInfo.details
});
} catch (error) {
console.error('创建订单失败:', error);
res.status(500).json({
code: 500,
message: '创建订单失败',
error: error.message
});
response.serverError(res, '创建订单失败', error);
}
};
@ -605,32 +468,18 @@ const getOrderDetail = async (req, res) => {
});
if (!order) {
return res.status(404).json({
code: 404,
message: '订单不存在'
});
return response.notFound(res, '订单不存在');
}
// 权限检查:普通租户只能查看自己的订单
if (!isSystemAdmin && order.tenantId !== currentTenantId) {
return res.status(403).json({
code: 403,
message: '无权查看此订单'
});
return response.forbidden(res, '无权查看此订单');
}
res.json({
code: 200,
data: order,
message: '获取订单详情成功'
});
response.success(res, '获取订单详情成功', order);
} catch (error) {
console.error('获取订单详情失败:', error);
res.status(500).json({
code: 500,
message: '获取订单详情失败',
error: error.message
});
response.serverError(res, '获取订单详情失败', error);
}
};
@ -646,41 +495,25 @@ const cancelOrder = async (req, res) => {
});
if (!order) {
return res.status(404).json({
code: 404,
message: '订单不存在'
});
return response.notFound(res, '订单不存在');
}
// 权限检查:普通租户只能取消自己的订单
if (!isSystemAdmin && order.tenantId !== currentTenantId) {
return res.status(403).json({
code: 403,
message: '无权取消此订单'
});
return response.forbidden(res, '无权取消此订单');
}
// 只能取消待支付的订单
if (order.status !== 'pending') {
return res.status(400).json({
code: 400,
message: '只能取消待支付的订单'
});
return response.badRequest(res, '只能取消待支付的订单');
}
await order.update({ status: 'cancelled' });
res.json({
code: 200,
message: '订单取消成功'
});
response.success(res, '订单取消成功');
} catch (error) {
console.error('取消订单失败:', error);
res.status(500).json({
code: 500,
message: '取消订单失败',
error: error.message
});
response.serverError(res, '取消订单失败', error);
}
};
@ -690,21 +523,14 @@ const payOrder = async (req, res) => {
const { id: orderId } = req.params;
const { paymentMethod = 'other', amount, transactionId: customTransactionId, remark } = req.body || {};
const isSystemAdmin = req.user.userType === 'super_admin';
const currentTenantId = req.tenantId;
if (!orderId) {
return res.status(400).json({
code: 400,
message: '订单ID不能为空'
});
return response.badRequest(res, '订单ID不能为空');
}
// 只有管理员可以确认支付
if (!isSystemAdmin) {
return res.status(403).json({
code: 403,
message: '无权操作,请联系管理员'
});
return response.forbidden(res, '无权操作,请联系管理员');
}
// 查询订单
@ -713,27 +539,18 @@ const payOrder = async (req, res) => {
});
if (!order) {
return res.status(404).json({
code: 404,
message: '订单不存在'
});
return response.notFound(res, '订单不存在');
}
// 验证订单状态
if (order.status !== 'pending') {
return res.status(400).json({
code: 400,
message: '订单状态异常,无法支付'
});
return response.badRequest(res, '订单状态异常,无法支付');
}
// 验证金额
const paymentAmount = parseFloat(amount) || order.actualAmount;
if (paymentAmount <= 0) {
return res.status(400).json({
code: 400,
message: '支付金额必须大于0'
});
return response.badRequest(res, '支付金额必须大于0');
}
// 生成或使用自定义交易流水号
@ -762,26 +579,18 @@ const payOrder = async (req, res) => {
// 使用订单的months字段和planId更新资源配置
const paymentResult = await billingService.processPaymentSuccess(order.tenantId, order.months, order.planId);
res.json({
code: 200,
message: '支付成功',
data: {
payment,
order: {
...order.toJSON(),
status: 'paid',
paidTime: paidTime
},
tenant: paymentResult
}
response.success(res, '支付成功', {
payment,
order: {
...order.toJSON(),
status: 'paid',
paidTime: paidTime
},
tenant: paymentResult
});
} catch (error) {
console.error('支付订单失败:', error);
res.status(500).json({
code: 500,
message: '支付订单失败',
error: error.message
});
response.serverError(res, '支付订单失败', error);
}
};
@ -822,23 +631,15 @@ const getPayments = async (req, res) => {
]
});
res.json({
code: 200,
data: {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
},
message: '获取支付记录成功'
response.success(res, '获取支付记录成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取支付记录失败:', error);
res.status(500).json({
code: 500,
message: '获取支付记录失败',
error: error.message
});
response.serverError(res, '获取支付记录失败', error);
}
};
@ -859,10 +660,7 @@ const getBillingInfo = async (req, res) => {
});
if (!tenant) {
return res.status(404).json({
code: 404,
message: '租户不存在'
});
return response.notFound(res, '租户不存在');
}
// 获取当前使用量
@ -872,37 +670,29 @@ const getBillingInfo = async (req, res) => {
User.count({ where: { tenantId, isDeleted: 0 } })
]);
res.json({
code: 200,
data: {
tenant: {
id: tenant.id,
name: tenant.name,
code: tenant.code,
billingStatus: tenant.billingStatus,
trialStartDate: tenant.trialStartDate,
trialEndDate: tenant.trialEndDate,
paidStartDate: tenant.paidStartDate,
paidEndDate: tenant.paidEndDate,
currentPeriodStart: tenant.currentPeriodStart,
currentPeriodEnd: tenant.currentPeriodEnd
},
plan: tenant.subscriptionPlan,
usage: {
apartments: apartmentCount,
rooms: roomCount,
users: userCount
}
response.success(res, '获取计费信息成功', {
tenant: {
id: tenant.id,
name: tenant.name,
code: tenant.code,
billingStatus: tenant.billingStatus,
trialStartDate: tenant.trialStartDate,
trialEndDate: tenant.trialEndDate,
paidStartDate: tenant.paidStartDate,
paidEndDate: tenant.paidEndDate,
currentPeriodStart: tenant.currentPeriodStart,
currentPeriodEnd: tenant.currentPeriodEnd
},
message: '获取计费信息成功'
plan: tenant.subscriptionPlan,
usage: {
apartments: apartmentCount,
rooms: roomCount,
users: userCount
}
});
} catch (error) {
console.error('获取计费信息失败:', error);
res.status(500).json({
code: 500,
message: '获取计费信息失败',
error: error.message
});
response.serverError(res, '获取计费信息失败', error);
}
};
@ -913,18 +703,10 @@ const getUsageStats = async (req, res) => {
const usageStats = await billingService.calculateOverage(tenantId);
res.json({
code: 200,
data: usageStats,
message: '获取资源使用情况成功'
});
response.success(res, '获取资源使用情况成功', usageStats);
} catch (error) {
console.error('获取资源使用情况失败:', error);
res.status(500).json({
code: 500,
message: '获取资源使用情况失败',
error: error.message
});
response.serverError(res, '获取资源使用情况失败', error);
}
};
@ -934,10 +716,7 @@ const getBillingStats = async (req, res) => {
const isSystemAdmin = req.user.userType === 'super_admin';
if (!isSystemAdmin) {
return res.status(403).json({
code: 403,
message: '无权访问此接口'
});
return response.forbidden(res, '无权访问此接口');
}
// 各计费状态租户数量
@ -1009,28 +788,20 @@ const getBillingStats = async (req, res) => {
}
});
res.json({
code: 200,
data: {
billingStatusStats: billingStatusStats.reduce((acc, item) => {
acc[item.billingStatus] = parseInt(item.get('count'));
return acc;
}, {}),
totalRevenue: totalRevenue || 0,
monthRevenue: monthRevenue || 0,
upcomingExpiredCount,
expiredCount,
pendingOrdersCount
},
message: '获取计费统计成功'
response.success(res, '获取计费统计成功', {
billingStatusStats: billingStatusStats.reduce((acc, item) => {
acc[item.billingStatus] = parseInt(item.get('count'));
return acc;
}, {}),
totalRevenue: totalRevenue || 0,
monthRevenue: monthRevenue || 0,
upcomingExpiredCount,
expiredCount,
pendingOrdersCount
});
} catch (error) {
console.error('获取计费统计失败:', error);
res.status(500).json({
code: 500,
message: '获取计费统计失败',
error: error.message
});
response.serverError(res, '获取计费统计失败', error);
}
};
@ -1044,25 +815,13 @@ const getPaymentSettings = async (req, res) => {
// 如果没有记录,返回空对象
if (!settings) {
return res.json({
code: 200,
message: '获取支付设置成功',
data: {}
});
return response.success(res, '获取支付设置成功', {});
}
res.json({
code: 200,
message: '获取支付设置成功',
data: settings
});
response.success(res, '获取支付设置成功', settings);
} catch (error) {
console.error('获取支付设置失败:', error);
res.status(500).json({
code: 500,
message: '获取支付设置失败',
error: error.message
});
response.serverError(res, '获取支付设置失败', error);
}
};
@ -1073,10 +832,7 @@ const updatePaymentSettings = async (req, res) => {
// 只有超级管理员可以修改支付设置
if (!isSystemAdmin) {
return res.status(403).json({
code: 403,
message: '无权操作,请联系管理员'
});
return response.forbidden(res, '无权操作,请联系管理员');
}
const {
@ -1124,18 +880,10 @@ const updatePaymentSettings = async (req, res) => {
});
}
res.json({
code: 200,
message: '支付设置更新成功',
data: settings
});
response.success(res, '支付设置更新成功', settings);
} catch (error) {
console.error('更新支付设置失败:', error);
res.status(500).json({
code: 500,
message: '更新支付设置失败',
error: error.message
});
response.serverError(res, '更新支付设置失败', error);
}
};

View File

@ -1,214 +0,0 @@
const { ElectricityBill, Room } = require('../models');
const { Op } = require('sequelize');
// 格式化时间(考虑时区,转换为北京时间)
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 formatElectricityBillData = (bill) => {
const formattedBill = {
...bill.toJSON(),
startDate: formatDate(bill.startDate),
endDate: formatDate(bill.endDate),
createTime: formatDate(bill.createTime),
updateTime: formatDate(bill.updateTime)
};
// 格式化关联数据
if (formattedBill.Room) {
formattedBill.Room = {
...formattedBill.Room,
createTime: formatDate(formattedBill.Room.createTime),
updateTime: formatDate(formattedBill.Room.updateTime)
};
}
return formattedBill;
};
// 获取所有电费记录(支持搜索和分页)
const getAllElectricityBills = async (req, res) => {
try {
const { roomId, status, startDate, endDate, page = 1, pageSize = 10 } = req.query;
// 构建查询条件
const where = { isDeleted: 0 };
if (roomId) {
where.roomId = roomId;
}
if (status) {
where.status = status;
}
if (startDate) {
where.startDate = { [Op.gte]: new Date(startDate) };
}
if (endDate) {
where.endDate = { [Op.lte]: new Date(endDate) };
}
// 计算偏移量
const offset = (page - 1) * pageSize;
// 查询电费数据
const { count, rows } = await ElectricityBill.findAndCountAll({
where,
include: [
{
model: Room,
where: { isDeleted: 0 }
}
],
limit: parseInt(pageSize),
offset: parseInt(offset)
});
// 格式化数据
const formattedBills = rows.map(formatElectricityBillData);
// 返回结果
res.status(200).json({
data: formattedBills,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 获取单个电费记录
const getElectricityBillById = async (req, res) => {
try {
const { id } = req.params;
const bill = await ElectricityBill.findOne({
where: { id, isDeleted: 0 },
include: [
{
model: Room,
where: { isDeleted: 0 }
}
]
});
if (!bill) {
return res.status(404).json({ error: '电费记录不存在' });
}
const formattedBill = formatElectricityBillData(bill);
res.status(200).json({
code: 200,
data: formattedBill,
message: 'success'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
// 创建电费记录
const createElectricityBill = async (req, res) => {
try {
const { roomId, startDate, endDate, startReading, endReading, unitPrice } = req.body;
// 计算用电量和费用
const usage = parseFloat(endReading) - parseFloat(startReading);
const amount = usage * parseFloat(unitPrice);
const bill = await ElectricityBill.create({
roomId,
startDate,
endDate,
startReading,
endReading,
usage,
unitPrice,
amount
});
const formattedBill = formatElectricityBillData(bill);
res.status(201).json({
code: 201,
data: formattedBill,
message: '创建成功'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
// 更新电费记录
const updateElectricityBill = async (req, res) => {
try {
const { id } = req.params;
const { startDate, endDate, startReading, endReading, unitPrice, status } = req.body;
const bill = await ElectricityBill.findOne({
where: { id, isDeleted: 0 }
});
if (!bill) {
return res.status(404).json({ error: '电费记录不存在' });
}
// 计算用电量和费用
let usage = bill.usage;
let amount = bill.amount;
if (startReading && endReading && unitPrice) {
usage = parseFloat(endReading) - parseFloat(startReading);
amount = usage * parseFloat(unitPrice);
}
await bill.update({
startDate,
endDate,
startReading,
endReading,
usage,
unitPrice,
amount,
status
});
const formattedBill = formatElectricityBillData(bill);
res.status(200).json({
code: 200,
data: formattedBill,
message: '更新成功'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
// 删除电费记录(软删除)
const deleteElectricityBill = async (req, res) => {
try {
const { id } = req.params;
const bill = await ElectricityBill.findOne({
where: { id, isDeleted: 0 }
});
if (!bill) {
return res.status(404).json({ error: '电费记录不存在' });
}
await bill.update({ isDeleted: 1 });
res.status(200).json({
code: 200,
message: '电费记录删除成功'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
module.exports = {
getAllElectricityBills,
getElectricityBillById,
createElectricityBill,
updateElectricityBill,
deleteElectricityBill
};

View File

@ -1,6 +1,7 @@
const { Op } = require('sequelize');
const OperationLog = require('../models/OperationLog');
const LoginLog = require('../models/LoginLog');
const response = require('../utils/response');
// 获取操作日志列表
exports.getOperationLogs = async (req, res) => {
@ -35,23 +36,15 @@ exports.getOperationLogs = async (req, res) => {
limit: parseInt(pageSize)
});
res.json({
code: 200,
message: '获取成功',
data: {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
}
response.success(res, '获取成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取操作日志错误:', error);
res.status(500).json({
code: 500,
message: '获取操作日志失败',
error: error.message
});
response.serverError(res, '获取操作日志失败', error);
}
};
@ -85,23 +78,15 @@ exports.getLoginLogs = async (req, res) => {
limit: parseInt(pageSize)
});
res.json({
code: 200,
message: '获取成功',
data: {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
}
response.success(res, '获取成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取登录日志错误:', error);
res.status(500).json({
code: 500,
message: '获取登录日志失败',
error: error.message
});
response.serverError(res, '获取登录日志失败', error);
}
};
@ -119,17 +104,10 @@ exports.clearOperationLogs = async (req, res) => {
await OperationLog.destroy({ where });
res.json({
code: 200,
message: '清空成功'
});
response.success(res, '清空成功');
} catch (error) {
console.error('清空操作日志错误:', error);
res.status(500).json({
code: 500,
message: '清空操作日志失败',
error: error.message
});
response.serverError(res, '清空操作日志失败', error);
}
};
@ -147,16 +125,9 @@ exports.clearLoginLogs = async (req, res) => {
await LoginLog.destroy({ where });
res.json({
code: 200,
message: '清空成功'
});
response.success(res, '清空成功');
} catch (error) {
console.error('清空登录日志错误:', error);
res.status(500).json({
code: 500,
message: '清空登录日志失败',
error: error.message
});
response.serverError(res, '清空登录日志失败', error);
}
};

View File

@ -2,6 +2,7 @@ const { Op } = require('sequelize');
const Menu = require('../models/Menu');
const RoleMenu = require('../models/RoleMenu');
const { logOperation } = require('../utils/logger');
const response = require('../utils/response');
// 获取菜单树
exports.getMenuTree = async (req, res) => {
@ -29,18 +30,10 @@ exports.getMenuTree = async (req, res) => {
const menuTree = buildTree(menus);
res.json({
code: 200,
message: '获取成功',
data: menuTree
});
response.success(res, '获取成功', menuTree);
} catch (error) {
console.error('获取菜单树失败:', error);
res.status(500).json({
code: 500,
message: '获取菜单树失败',
error: error.message
});
response.serverError(res, '获取菜单树失败', error);
}
};
@ -67,23 +60,15 @@ exports.getMenuList = async (req, res) => {
limit: parseInt(pageSize)
});
res.json({
code: 200,
message: '获取成功',
data: {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
}
response.success(res, '获取成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取菜单列表失败:', error);
res.status(500).json({
code: 500,
message: '获取菜单列表失败',
error: error.message
});
response.serverError(res, '获取菜单列表失败', error);
}
};
@ -97,24 +82,13 @@ exports.getMenuById = async (req, res) => {
});
if (!menu) {
return res.status(404).json({
code: 404,
message: '菜单不存在'
});
return response.notFound(res, '菜单不存在');
}
res.json({
code: 200,
message: '获取成功',
data: menu
});
response.success(res, '获取成功', menu);
} catch (error) {
console.error('获取菜单详情失败:', error);
res.status(500).json({
code: 500,
message: '获取菜单详情失败',
error: error.message
});
response.serverError(res, '获取菜单详情失败', error);
}
};
@ -124,17 +98,11 @@ exports.createMenu = async (req, res) => {
const { parentId, name, code, type, path, component, icon, sort, visible, status } = req.body;
if (!name || !code || !type) {
return res.status(400).json({
code: 400,
message: '菜单名称、编码和类型不能为空'
});
return response.badRequest(res, '菜单名称、编码和类型不能为空');
}
if (type === 'menu' && !path) {
return res.status(400).json({
code: 400,
message: '菜单类型必须填写路由路径'
});
return response.badRequest(res, '菜单类型必须填写路由路径');
}
const existingMenu = await Menu.findOne({
@ -142,10 +110,7 @@ exports.createMenu = async (req, res) => {
});
if (existingMenu) {
return res.status(400).json({
code: 400,
message: '菜单编码已存在'
});
return response.badRequest(res, '菜单编码已存在');
}
if (parentId) {
@ -153,10 +118,7 @@ exports.createMenu = async (req, res) => {
where: { isDeleted: false }
});
if (!parentMenu) {
return res.status(400).json({
code: 400,
message: '父菜单不存在'
});
return response.badRequest(res, '父菜单不存在');
}
}
@ -187,18 +149,10 @@ exports.createMenu = async (req, res) => {
status: 'success'
});
res.json({
code: 200,
message: '创建成功',
data: menu
});
response.success(res, '创建成功', menu);
} catch (error) {
console.error('创建菜单失败:', error);
res.status(500).json({
code: 500,
message: '创建菜单失败',
error: error.message
});
response.serverError(res, '创建菜单失败', error);
}
};
@ -213,10 +167,7 @@ exports.updateMenu = async (req, res) => {
});
if (!menu) {
return res.status(404).json({
code: 404,
message: '菜单不存在'
});
return response.notFound(res, '菜单不存在');
}
if (code && code !== menu.code) {
@ -225,29 +176,20 @@ exports.updateMenu = async (req, res) => {
});
if (existingMenu) {
return res.status(400).json({
code: 400,
message: '菜单编码已存在'
});
return response.badRequest(res, '菜单编码已存在');
}
}
if (parentId) {
if (parseInt(parentId) === parseInt(id)) {
return res.status(400).json({
code: 400,
message: '不能将菜单设置为自己的子菜单'
});
return response.badRequest(res, '不能将菜单设置为自己的子菜单');
}
const parentMenu = await Menu.findByPk(parentId, {
where: { isDeleted: false }
});
if (!parentMenu) {
return res.status(400).json({
code: 400,
message: '父菜单不存在'
});
return response.badRequest(res, '父菜单不存在');
}
}
@ -279,18 +221,10 @@ exports.updateMenu = async (req, res) => {
status: 'success'
});
res.json({
code: 200,
message: '更新成功',
data: menu
});
response.success(res, '更新成功', menu);
} catch (error) {
console.error('更新菜单失败:', error);
res.status(500).json({
code: 500,
message: '更新菜单失败',
error: error.message
});
response.serverError(res, '更新菜单失败', error);
}
};
@ -304,10 +238,7 @@ exports.deleteMenu = async (req, res) => {
});
if (!menu) {
return res.status(404).json({
code: 404,
message: '菜单不存在'
});
return response.notFound(res, '菜单不存在');
}
const children = await Menu.findAll({
@ -315,10 +246,7 @@ exports.deleteMenu = async (req, res) => {
});
if (children.length > 0) {
return res.status(400).json({
code: 400,
message: '该菜单下有子菜单,无法删除'
});
return response.badRequest(res, '该菜单下有子菜单,无法删除');
}
await menu.update({
@ -342,17 +270,10 @@ exports.deleteMenu = async (req, res) => {
status: 'success'
});
res.json({
code: 200,
message: '删除成功'
});
response.success(res, '删除成功');
} catch (error) {
console.error('删除菜单失败:', error);
res.status(500).json({
code: 500,
message: '删除菜单失败',
error: error.message
});
response.serverError(res, '删除菜单失败', error);
}
};
@ -369,10 +290,7 @@ exports.getRoleMenus = async (req, res) => {
});
if (!role) {
return res.status(404).json({
code: 404,
message: '角色不存在'
});
return response.notFound(res, '角色不存在');
}
// 获取角色的菜单权限
@ -388,18 +306,10 @@ exports.getRoleMenus = async (req, res) => {
const menus = roleData ? roleData.menus : [];
res.json({
code: 200,
message: '获取成功',
data: menus
});
response.success(res, '获取成功', menus);
} catch (error) {
console.error('获取角色菜单失败:', error);
res.status(500).json({
code: 500,
message: '获取角色菜单失败',
error: error.message
});
response.serverError(res, '获取角色菜单失败', error);
}
};
@ -410,20 +320,14 @@ exports.assignMenusToRole = async (req, res) => {
const { menuIds } = req.body;
if (!Array.isArray(menuIds)) {
return res.status(400).json({
code: 400,
message: '菜单ID必须是数组'
});
return response.badRequest(res, '菜单ID必须是数组');
}
const Role = require('../models/Role');
const role = await Role.findByPk(roleId);
if (!role) {
return res.status(404).json({
code: 404,
message: '角色不存在'
});
return response.notFound(res, '角色不存在');
}
await RoleMenu.destroy({
@ -450,17 +354,10 @@ exports.assignMenusToRole = async (req, res) => {
status: 'success'
});
res.json({
code: 200,
message: '分配成功'
});
response.success(res, '分配成功');
} catch (error) {
console.error('分配菜单权限失败:', error);
res.status(500).json({
code: 500,
message: '分配菜单权限失败',
error: error.message
});
response.serverError(res, '分配菜单权限失败', error);
}
};
@ -505,18 +402,11 @@ exports.getUserMenus = async (req, res) => {
const allMenus = [...menuList, ...buttonList];
const menuTree = buildTree(allMenus);
return res.json({
code: 200,
message: '获取成功',
data: menuTree
});
return response.success(res, '获取成功', menuTree);
}
if (!user.role) {
return res.status(403).json({
code: 403,
message: '用户没有分配角色'
});
return response.forbidden(res, '用户没有分配角色');
}
// 普通用户返回角色分配的菜单
@ -534,11 +424,7 @@ exports.getUserMenus = async (req, res) => {
});
if (!roleData || !roleData.menus) {
return res.json({
code: 200,
message: '获取成功',
data: []
});
return response.success(res, '获取成功', []);
}
// 按sort排序
@ -547,18 +433,10 @@ exports.getUserMenus = async (req, res) => {
// 构建菜单树
const menuTree = buildTree(menus);
res.json({
code: 200,
message: '获取成功',
data: menuTree
});
response.success(res, '获取成功', menuTree);
} catch (error) {
console.error('获取用户菜单失败:', error);
res.status(500).json({
code: 500,
message: '获取用户菜单失败',
error: error.message
});
response.serverError(res, '获取用户菜单失败', error);
}
};

View File

@ -1,5 +1,6 @@
const { MeterReading, Bill, Room, Renter, Rental } = require('../models');
const { Op } = require('sequelize');
const response = require('../utils/response');
// 生成账单编号
const generateBillNo = () => {
@ -98,16 +99,15 @@ const getAllMeterReadings = async (req, res) => {
const formattedReadings = rows.map(formatMeterReadingData);
res.status(200).json({
code: 200,
data: formattedReadings,
response.success(res, '获取成功', {
list: formattedReadings,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取抄表记录列表失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取抄表记录列表失败', error);
}
};
@ -135,17 +135,13 @@ const getMeterReadingById = async (req, res) => {
});
if (!reading) {
return res.status(404).json({ code: 404, error: '抄表记录不存在' });
return response.notFound(res, '抄表记录不存在');
}
res.status(200).json({
code: 200,
data: formatMeterReadingData(reading),
message: 'success'
});
response.success(res, '获取成功', formatMeterReadingData(reading));
} catch (error) {
console.error('获取抄表记录详情失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取抄表记录详情失败', error);
}
};
@ -221,17 +217,13 @@ const createMeterReading = async (req, res) => {
// 更新抄表记录的账单ID
await meterReading.update({ billId: bill.id });
res.status(201).json({
code: 201,
data: {
meterReading: formatMeterReadingData(meterReading),
bill: {
id: bill.id,
billNo: bill.billNo,
status: bill.status
}
},
message: '抄表记录创建成功,已自动生成账单'
response.created(res, '抄表记录创建成功,已自动生成账单', {
meterReading: formatMeterReadingData(meterReading),
bill: {
id: bill.id,
billNo: bill.billNo,
status: bill.status
}
});
} catch (error) {
console.error('创建抄表记录失败:', error);
@ -239,23 +231,17 @@ const createMeterReading = async (req, res) => {
if (error.name === 'SequelizeUniqueConstraintError') {
const field = error.errors[0]?.path || '未知字段';
if (field === 'uk_room_type_month') {
return res.status(409).json({
code: 409,
error: '该房间本月已存在此类型的抄表记录,请勿重复创建'
});
return response.error(res, '该房间本月已存在此类型的抄表记录,请勿重复创建', 409);
}
return res.status(409).json({
code: 409,
error: `数据重复: ${field} 必须唯一`
});
return response.error(res, `数据重复: ${field} 必须唯一`, 409);
}
// 输出详细的验证错误信息
if (error.name === 'SequelizeValidationError') {
const messages = error.errors.map(e => `${e.path}: ${e.message}`).join(', ');
console.error('验证错误详情:', messages);
return res.status(400).json({ code: 400, error: `Validation error: ${messages}` });
return response.badRequest(res, `Validation error: ${messages}`);
}
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '创建抄表记录失败', error);
}
};
@ -276,7 +262,7 @@ const updateMeterReading = async (req, res) => {
});
if (!meterReading) {
return res.status(404).json({ code: 404, error: '抄表记录不存在' });
return response.notFound(res, '抄表记录不存在');
}
// 重新计算用量和金额
@ -305,14 +291,10 @@ const updateMeterReading = async (req, res) => {
}
}
res.status(200).json({
code: 200,
data: formatMeterReadingData(meterReading),
message: '更新成功'
});
response.success(res, '更新成功', formatMeterReadingData(meterReading));
} catch (error) {
console.error('更新抄表记录失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '更新抄表记录失败', error);
}
};
@ -325,7 +307,7 @@ const deleteMeterReading = async (req, res) => {
});
if (!meterReading) {
return res.status(404).json({ code: 404, error: '抄表记录不存在' });
return response.notFound(res, '抄表记录不存在');
}
// 软删除抄表记录
@ -345,13 +327,10 @@ const deleteMeterReading = async (req, res) => {
}
}
res.status(200).json({
code: 200,
message: '抄表记录及关联账单删除成功'
});
response.success(res, '抄表记录及关联账单删除成功');
} catch (error) {
console.error('删除抄表记录失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '删除抄表记录失败', error);
}
};
@ -390,16 +369,15 @@ const getRoomMeterReadings = async (req, res) => {
const formattedReadings = rows.map(formatMeterReadingData);
res.status(200).json({
code: 200,
data: formattedReadings,
response.success(res, '获取成功', {
list: formattedReadings,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取房间抄表记录失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取房间抄表记录失败', error);
}
};
@ -418,16 +396,13 @@ const getLatestReading = async (req, res) => {
order: [['billMonth', 'DESC']]
});
res.status(200).json({
code: 200,
data: latestReading ? {
previousReading: latestReading.currentReading,
billMonth: latestReading.billMonth
} : null
});
response.success(res, '获取成功', latestReading ? {
previousReading: latestReading.currentReading,
billMonth: latestReading.billMonth
} : null);
} catch (error) {
console.error('获取最新读数失败:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取最新读数失败', error);
}
};

View File

@ -1,5 +1,6 @@
const { Rental, Room, Apartment, Bill, Transaction, Renter, MeterReading } = require('../models');
const { Op } = require('sequelize');
const response = require('../utils/response');
// 格式化时间(考虑时区,转换为北京时间)
const formatDate = (date) => {
@ -149,14 +150,14 @@ const getAllRentals = async (req, res) => {
const formattedRentals = rows.map(formatRentalData);
// 返回结果
res.status(200).json({
data: formattedRentals,
response.success(res, '获取成功', {
list: formattedRentals,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
res.status(500).json({ error: error.message });
response.serverError(res, '获取租房列表失败', error);
}
};
@ -183,16 +184,12 @@ const getRentalById = async (req, res) => {
]
});
if (!rental) {
return res.status(404).json({ error: '租房记录不存在' });
return response.notFound(res, '租房记录不存在');
}
const formattedRental = formatRentalData(rental);
res.status(200).json({
code: 200,
data: formattedRental,
message: 'success'
});
response.success(res, '获取成功', formattedRental);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取租房详情失败', error);
}
};
@ -206,34 +203,34 @@ const createRental = async (req, res) => {
// 检查请求体是否存在
if (!body) {
return res.status(400).json({ error: '请求体不能为空' });
return response.badRequest(res, '请求体不能为空');
}
// 检查所有必要参数
if (!body.roomId) {
return res.status(400).json({ error: '缺少房间ID' });
return response.badRequest(res, '缺少房间ID');
}
if (!body.renterId) {
return res.status(400).json({ error: '缺少租客ID' });
return response.badRequest(res, '缺少租客ID');
}
if (!body.startDate) {
return res.status(400).json({ error: '缺少开始日期' });
return response.badRequest(res, '缺少开始日期');
}
if (!body.endDate) {
return res.status(400).json({ error: '缺少结束日期' });
return response.badRequest(res, '缺少结束日期');
}
if (!body.rent) {
return res.status(400).json({ error: '缺少租金' });
return response.badRequest(res, '缺少租金');
}
// 转换roomId和renterId为整数类型
const parsedRoomId = parseInt(body.roomId);
const parsedRenterId = parseInt(body.renterId);
if (isNaN(parsedRoomId)) {
return res.status(400).json({ error: '无效的房间ID' });
return response.badRequest(res, '无效的房间ID');
}
if (isNaN(parsedRenterId)) {
return res.status(400).json({ error: '无效的租客ID' });
return response.badRequest(res, '无效的租客ID');
}
// 处理押金为空时设置为0
@ -317,14 +314,10 @@ const createRental = async (req, res) => {
});
}
res.status(201).json({
code: 201,
data: rental,
message: '创建成功'
});
response.created(res, '创建成功', rental);
} catch (error) {
console.error('创建租房记录时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '创建租房失败', error);
}
};
@ -337,7 +330,7 @@ const updateRental = async (req, res) => {
where: { id, isDeleted: 0 }
});
if (!rental) {
return res.status(404).json({ error: '租房记录不存在' });
return response.notFound(res, '租房记录不存在');
}
// 处理押金为空时设置为0
const updateDeposit = deposit || 0;
@ -358,13 +351,9 @@ const updateRental = async (req, res) => {
remark,
updateBy: req.user.id
});
res.status(200).json({
code: 200,
data: rental,
message: '更新成功'
});
response.success(res, '更新成功', rental);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '更新租房失败', error);
}
};
@ -376,18 +365,15 @@ const deleteRental = async (req, res) => {
where: { id, isDeleted: 0 }
});
if (!rental) {
return res.status(404).json({ error: '租房记录不存在' });
return response.notFound(res, '租房记录不存在');
}
await rental.update({
isDeleted: 1,
updateBy: req.user.id
});
res.status(200).json({
code: 200,
message: '租房记录删除成功'
});
response.success(res, '租房记录删除成功');
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '删除租房失败', error);
}
};
@ -417,11 +403,11 @@ const terminateRental = async (req, res) => {
});
if (!rental) {
return res.status(404).json({ error: '租房记录不存在' });
return response.notFound(res, '租房记录不存在');
}
if (rental.status !== 'active') {
return res.status(400).json({ error: '只有生效中的租约可以退租' });
return response.badRequest(res, '只有生效中的租约可以退租');
}
const room = rental.Room;
@ -484,14 +470,10 @@ const terminateRental = async (req, res) => {
{ where: { id: room.id } }
);
res.status(200).json({
code: 200,
data: rental,
message: '退租处理成功'
});
response.success(res, '退租处理成功', rental);
} catch (error) {
console.error('退租处理时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '退租处理失败', error);
}
};
@ -560,13 +542,9 @@ const listRentals = async (req, res) => {
const formattedRentals = rentals.map(formatRentalData);
// 返回结果
res.status(200).json({
code: 200,
data: formattedRentals,
message: 'success'
});
response.success(res, '获取成功', formattedRentals);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取租房列表失败', error);
}
};
@ -602,25 +580,25 @@ const createRentalWithRenter = async (req, res) => {
// 参数验证
if (!renterName) {
await transaction.rollback();
return res.status(400).json({ code: 400, error: '租客姓名不能为空' });
return response.badRequest(res, '租客姓名不能为空');
}
if (!roomId) {
await transaction.rollback();
return res.status(400).json({ code: 400, error: '房间ID不能为空' });
return response.badRequest(res, '房间ID不能为空');
}
if (!startDate || !endDate) {
await transaction.rollback();
return res.status(400).json({ code: 400, error: '开始日期和结束日期不能为空' });
return response.badRequest(res, '开始日期和结束日期不能为空');
}
if (!rent) {
await transaction.rollback();
return res.status(400).json({ code: 400, error: '租金不能为空' });
return response.badRequest(res, '租金不能为空');
}
const parsedRoomId = parseInt(roomId);
if (isNaN(parsedRoomId)) {
await transaction.rollback();
return res.status(400).json({ code: 400, error: '无效的房间ID' });
return response.badRequest(res, '无效的房间ID');
}
// 1. 创建租客
@ -775,21 +753,17 @@ const createRentalWithRenter = async (req, res) => {
// 提交事务
await transaction.commit();
res.status(201).json({
code: 201,
data: {
rentalId: rental.id,
renterId: renter.id,
roomId: parsedRoomId
},
message: '创建成功'
response.created(res, '创建成功', {
rentalId: rental.id,
renterId: renter.id,
roomId: parsedRoomId
});
} catch (error) {
// 回滚事务
await transaction.rollback();
console.error('创建租房(整合)时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '创建租房失败', error);
}
};

View File

@ -1,5 +1,6 @@
const { Renter, Rental, Room, Apartment } = require('../models');
const { Op } = require('sequelize');
const response = require('../utils/response');
// 获取租客列表(分页)
const getRenters = async (req, res) => {
@ -28,23 +29,15 @@ const getRenters = async (req, res) => {
limit: parseInt(pageSize)
});
res.json({
code: 200,
data: {
list: rows,
pagination: {
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
}
}
response.success(res, '获取成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取租客列表失败:', error);
res.status(500).json({
code: 500,
message: '获取租客列表失败'
});
response.serverError(res, '获取租客列表失败', error);
}
};
@ -73,16 +66,10 @@ const getRenterList = async (req, res) => {
order: [['createTime', 'DESC']]
});
res.json({
code: 200,
data: rows
});
response.success(res, '获取成功', rows);
} catch (error) {
console.error('获取租客列表失败:', error);
res.status(500).json({
code: 500,
message: '获取租客列表失败'
});
response.serverError(res, '获取租客列表失败', error);
}
};
@ -97,10 +84,7 @@ const getRenterById = async (req, res) => {
});
if (!renter) {
return res.status(404).json({
code: 404,
message: '租客不存在'
});
return response.notFound(res, '租客不存在');
}
// 获取租客的租赁记录
@ -121,20 +105,13 @@ const getRenterById = async (req, res) => {
order: [['createTime', 'DESC']]
});
res.json({
code: 200,
data: {
...renter.toJSON(),
rentals
}
response.success(res, '获取成功', {
...renter.toJSON(),
rentals
});
} catch (error) {
console.error('获取租客详情失败:', error);
res.status(500).json({
code: 500,
message: '获取租客详情失败',
error: error.message
});
response.serverError(res, '获取租客详情失败', error);
}
};
@ -160,10 +137,7 @@ const createRenter = async (req, res) => {
// 验证必填字段
if (!name) {
return res.status(400).json({
code: 400,
message: '租客姓名不能为空'
});
return response.badRequest(res, '租客姓名不能为空');
}
// 检查手机号是否已存在
@ -172,10 +146,7 @@ const createRenter = async (req, res) => {
where: { phone, tenantId, isDeleted: 0 }
});
if (existingRenter) {
return res.status(400).json({
code: 400,
message: '该手机号已存在'
});
return response.badRequest(res, '该手机号已存在');
}
}
@ -196,17 +167,10 @@ const createRenter = async (req, res) => {
status: 'active'
});
res.json({
code: 200,
message: '创建成功',
data: renter
});
response.created(res, '创建成功', renter);
} catch (error) {
console.error('创建租客失败:', error);
res.status(500).json({
code: 500,
message: '创建租客失败'
});
response.serverError(res, '创建租客失败', error);
}
};
@ -222,10 +186,7 @@ const updateRenter = async (req, res) => {
});
if (!renter) {
return res.status(404).json({
code: 404,
message: '租客不存在'
});
return response.notFound(res, '租客不存在');
}
const {
@ -249,10 +210,7 @@ const updateRenter = async (req, res) => {
where: { phone, tenantId, isDeleted: 0, id: { [Op.ne]: id } }
});
if (existingRenter) {
return res.status(400).json({
code: 400,
message: '该手机号已被其他租客使用'
});
return response.badRequest(res, '该手机号已被其他租客使用');
}
}
@ -272,17 +230,10 @@ const updateRenter = async (req, res) => {
updateBy
});
res.json({
code: 200,
message: '更新成功',
data: renter
});
response.success(res, '更新成功', renter);
} catch (error) {
console.error('更新租客失败:', error);
res.status(500).json({
code: 500,
message: '更新租客失败'
});
response.serverError(res, '更新租客失败', error);
}
};
@ -297,10 +248,7 @@ const deleteRenter = async (req, res) => {
});
if (!renter) {
return res.status(404).json({
code: 404,
message: '租客不存在'
});
return response.notFound(res, '租客不存在');
}
// 检查是否有进行中的租赁
@ -313,24 +261,15 @@ const deleteRenter = async (req, res) => {
});
if (activeRentals > 0) {
return res.status(400).json({
code: 400,
message: '该租客有进行中的租赁,无法删除'
});
return response.badRequest(res, '该租客有进行中的租赁,无法删除');
}
await renter.update({ isDeleted: 1 });
res.json({
code: 200,
message: '删除成功'
});
response.success(res, '删除成功');
} catch (error) {
console.error('删除租客失败:', error);
res.status(500).json({
code: 500,
message: '删除租客失败'
});
response.serverError(res, '删除租客失败', error);
}
};
@ -356,19 +295,13 @@ const getRenterOptions = async (req, res) => {
limit: 50
});
res.json({
code: 200,
data: renters.map(r => ({
value: r.id,
label: `${r.name} ${r.phone ? '(' + r.phone + ')' : ''}`
}))
});
response.success(res, '获取成功', renters.map(r => ({
value: r.id,
label: `${r.name} ${r.phone ? '(' + r.phone + ')' : ''}`
})));
} catch (error) {
console.error('获取租客选项失败:', error);
res.status(500).json({
code: 500,
message: '获取租客选项失败'
});
response.serverError(res, '获取租客选项失败', error);
}
};

View File

@ -1,6 +1,7 @@
const { Op } = require('sequelize');
const Role = require('../models/Role');
const { logOperation } = require('../utils/logger');
const response = require('../utils/response');
// 获取角色列表
exports.getRoles = async (req, res) => {
@ -25,15 +26,11 @@ exports.getRoles = async (req, res) => {
order: [['id', 'DESC']]
});
res.json({
code: 200,
message: '获取角色列表成功',
data: {
list: roles,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
}
response.success(res, '获取角色列表成功', {
list: roles,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
// 记录操作日志
@ -52,11 +49,7 @@ exports.getRoles = async (req, res) => {
} catch (error) {
console.error('获取角色列表错误:', error);
res.status(500).json({
code: 500,
message: '获取角色列表失败',
error: error.message
});
response.serverError(res, '获取角色列表失败', error);
}
};
@ -78,17 +71,10 @@ exports.getRoleById = async (req, res) => {
});
if (!role) {
return res.status(404).json({
code: 404,
message: '角色不存在'
});
return response.notFound(res, '角色不存在');
}
res.json({
code: 200,
message: '获取角色详情成功',
data: role
});
response.success(res, '获取角色详情成功', role);
// 记录操作日志
await logOperation({
@ -106,11 +92,7 @@ exports.getRoleById = async (req, res) => {
} catch (error) {
console.error('获取角色详情错误:', error);
res.status(500).json({
code: 500,
message: '获取角色详情失败',
error: error.message
});
response.serverError(res, '获取角色详情失败', error);
}
};
@ -122,10 +104,7 @@ exports.createRole = async (req, res) => {
// 参数验证
if (!name || !code) {
return res.status(400).json({
code: 400,
message: '角色名称和编码不能为空'
});
return response.badRequest(res, '角色名称和编码不能为空');
}
// 检查角色编码是否已存在(限制在当前租户内)
@ -138,10 +117,7 @@ exports.createRole = async (req, res) => {
});
if (existingRole) {
return res.status(400).json({
code: 400,
message: '角色编码已存在'
});
return response.badRequest(res, '角色编码已存在');
}
const role = await Role.create({
@ -155,11 +131,7 @@ exports.createRole = async (req, res) => {
updateBy: req.user.id
});
res.json({
code: 200,
message: '创建角色成功',
data: role
});
response.success(res, '创建角色成功', role);
// 记录操作日志
await logOperation({
@ -177,11 +149,7 @@ exports.createRole = async (req, res) => {
} catch (error) {
console.error('创建角色错误:', error);
res.status(500).json({
code: 500,
message: '创建角色失败',
error: error.message
});
response.serverError(res, '创建角色失败', error);
}
};
@ -202,10 +170,7 @@ exports.updateRole = async (req, res) => {
});
if (!role) {
return res.status(404).json({
code: 404,
message: '角色不存在'
});
return response.notFound(res, '角色不存在');
}
// 检查角色编码是否已存在(排除当前角色)
@ -220,10 +185,7 @@ exports.updateRole = async (req, res) => {
});
if (existingRole) {
return res.status(400).json({
code: 400,
message: '角色编码已存在'
});
return response.badRequest(res, '角色编码已存在');
}
}
@ -236,11 +198,7 @@ exports.updateRole = async (req, res) => {
updateBy: req.user.id
});
res.json({
code: 200,
message: '更新角色成功',
data: role
});
response.success(res, '更新角色成功', role);
// 记录操作日志
await logOperation({
@ -258,11 +216,7 @@ exports.updateRole = async (req, res) => {
} catch (error) {
console.error('更新角色错误:', error);
res.status(500).json({
code: 500,
message: '更新角色失败',
error: error.message
});
response.serverError(res, '更新角色失败', error);
}
};
@ -282,10 +236,7 @@ exports.deleteRole = async (req, res) => {
});
if (!role) {
return res.status(404).json({
code: 404,
message: '角色不存在'
});
return response.notFound(res, '角色不存在');
}
// 检查是否有用户使用此角色
@ -294,10 +245,7 @@ exports.deleteRole = async (req, res) => {
});
if (userCount > 0) {
return res.status(400).json({
code: 400,
message: '该角色下还有用户,无法删除'
});
return response.badRequest(res, '该角色下还有用户,无法删除');
}
// 软删除
@ -306,10 +254,7 @@ exports.deleteRole = async (req, res) => {
updateBy: req.user.id
});
res.json({
code: 200,
message: '删除角色成功'
});
response.success(res, '删除角色成功');
// 记录操作日志
await logOperation({
@ -327,11 +272,7 @@ exports.deleteRole = async (req, res) => {
} catch (error) {
console.error('删除角色错误:', error);
res.status(500).json({
code: 500,
message: '删除角色失败',
error: error.message
});
response.serverError(res, '删除角色失败', error);
}
};
@ -352,18 +293,10 @@ exports.getAllRoles = async (req, res) => {
attributes: ['id', 'name', 'code']
});
res.json({
code: 200,
message: '获取角色列表成功',
data: roles
});
response.success(res, '获取角色列表成功', roles);
} catch (error) {
console.error('获取角色列表错误:', error);
res.status(500).json({
code: 500,
message: '获取角色列表失败',
error: error.message
});
response.serverError(res, '获取角色列表失败', error);
}
};

View File

@ -1,6 +1,7 @@
const { Room, Apartment, Rental, Renter, Tenant } = require('../models');
const { Op } = require('sequelize');
const { logOperation } = require('../utils/logger');
const response = require('../utils/response');
// 格式化时间(考虑时区,转换为北京时间)
const formatDate = (date) => {
@ -179,14 +180,14 @@ const getAllRooms = async (req, res) => {
// 返回结果
res.status(200).json({
data: formattedRooms,
response.success(res, '获取成功', {
list: formattedRooms,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
res.status(500).json({ error: error.message });
response.serverError(res, '获取房间列表失败', error);
}
};
@ -202,7 +203,7 @@ const getRoomById = async (req, res) => {
include: [Apartment]
});
if (!room) {
return res.status(404).json({ error: '房间不存在' });
return response.notFound(res, '房间不存在');
}
// 格式化房间数据
@ -242,13 +243,9 @@ const getRoomById = async (req, res) => {
} else {
formattedRoom.Rentals = [];
}
res.status(200).json({
code: 200,
data: formattedRoom,
message: 'success'
});
response.success(res, '获取成功', formattedRoom);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取房间详情失败', error);
}
};
@ -302,14 +299,12 @@ const createRoom = async (req, res) => {
updateBy: req.user.id
};
const room = await Room.create(processedData);
res.status(201).json({
code: 201,
data: room,
message: '创建成功',
response.created(res, '创建成功', {
room,
warning: tenant && currentRoomCount >= tenant.maxRooms ? `当前已超出套餐限制(${tenant.maxRooms}间),续费时将收取超额费用` : null
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '创建房间失败', error);
}
};
@ -322,7 +317,7 @@ const updateRoom = async (req, res) => {
where: { id, isDeleted: 0 }
});
if (!room) {
return res.status(404).json({ error: '房间不存在' });
return response.notFound(res, '房间不存在');
}
// 处理空值
const processedData = {
@ -340,13 +335,9 @@ const updateRoom = async (req, res) => {
updateBy: req.user.id
};
await room.update(processedData);
res.status(200).json({
code: 200,
data: room,
message: '更新成功'
});
response.success(res, '更新成功', room);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '更新房间失败', error);
}
};
@ -358,18 +349,15 @@ const deleteRoom = async (req, res) => {
where: { id, isDeleted: 0 }
});
if (!room) {
return res.status(404).json({ error: '房间不存在' });
return response.notFound(res, '房间不存在');
}
await room.update({
isDeleted: 1,
updateBy: req.user.id
});
res.status(200).json({
code: 200,
message: '房间删除成功'
});
response.success(res, '房间删除成功');
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '删除房间失败', error);
}
};
@ -446,13 +434,9 @@ const listRooms = async (req, res) => {
}));
// 返回结果
res.status(200).json({
code: 200,
data: formattedRooms,
message: 'success'
});
response.success(res, '获取成功', formattedRooms);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取房间列表失败', error);
}
};

View File

@ -1,4 +1,5 @@
const { Setting, Category } = require('../models');
const response = require('../utils/response');
/**
* 获取系统设置
@ -24,18 +25,10 @@ const getSettings = async (req, res) => {
...settingsMap
};
res.json({
code: 200,
message: '获取成功',
data: defaultSettings
});
response.success(res, '获取成功', defaultSettings);
} catch (error) {
console.error('获取设置失败:', error);
res.status(500).json({
code: 500,
message: '获取设置失败',
error: error.message
});
response.serverError(res, '获取设置失败', error);
}
};
@ -71,17 +64,10 @@ const updateSettings = async (req, res) => {
}
}
res.json({
code: 200,
message: '设置保存成功'
});
response.success(res, '设置保存成功');
} catch (error) {
console.error('保存设置失败:', error);
res.status(500).json({
code: 500,
message: '保存设置失败',
error: error.message
});
response.serverError(res, '保存设置失败', error);
}
};
@ -108,18 +94,10 @@ const getCategories = async (req, res) => {
order: [['sort', 'ASC'], ['id', 'ASC']]
});
res.json({
code: 200,
message: '获取成功',
data: categories
});
response.success(res, '获取成功', categories);
} catch (error) {
console.error('获取类目失败:', error);
res.status(500).json({
code: 500,
message: '获取类目失败',
error: error.message
});
response.serverError(res, '获取类目失败', error);
}
};
@ -138,10 +116,7 @@ const createCategory = async (req, res) => {
});
if (existing) {
return res.status(400).json({
code: 400,
message: '类目编码已存在'
});
return response.badRequest(res, '类目编码已存在');
}
const category = await Category.create({
@ -154,18 +129,10 @@ const createCategory = async (req, res) => {
updateBy: userId
});
res.json({
code: 200,
message: '创建成功',
data: category
});
response.success(res, '创建成功', category);
} catch (error) {
console.error('创建类目失败:', error);
res.status(500).json({
code: 500,
message: '创建类目失败',
error: error.message
});
response.serverError(res, '创建类目失败', error);
}
};
@ -184,23 +151,17 @@ const updateCategory = async (req, res) => {
});
if (!category) {
return res.status(404).json({
code: 404,
message: '类目不存在'
});
return response.notFound(res, '类目不存在');
}
// 检查编码是否与其他类目冲突
if (code && code !== category.code) {
const existing = await Category.findOne({
where: { code, tenantId, isDeleted: 0, id: { $ne: id } }
where: { code, tenantId, isDeleted: 0, id: { [Op.ne]: id } }
});
if (existing) {
return res.status(400).json({
code: 400,
message: '类目编码已存在'
});
return response.badRequest(res, '类目编码已存在');
}
}
@ -213,18 +174,10 @@ const updateCategory = async (req, res) => {
updateBy: userId
});
res.json({
code: 200,
message: '更新成功',
data: category
});
response.success(res, '更新成功', category);
} catch (error) {
console.error('更新类目失败:', error);
res.status(500).json({
code: 500,
message: '更新类目失败',
error: error.message
});
response.serverError(res, '更新类目失败', error);
}
};
@ -242,18 +195,12 @@ const deleteCategory = async (req, res) => {
});
if (!category) {
return res.status(404).json({
code: 404,
message: '类目不存在'
});
return response.notFound(res, '类目不存在');
}
// 默认类目不允许删除
if (category.isDefault) {
return res.status(400).json({
code: 400,
message: '默认类目不能删除'
});
return response.badRequest(res, '默认类目不能删除');
}
await category.update({
@ -261,17 +208,10 @@ const deleteCategory = async (req, res) => {
updateBy: userId
});
res.json({
code: 200,
message: '删除成功'
});
response.success(res, '删除成功');
} catch (error) {
console.error('删除类目失败:', error);
res.status(500).json({
code: 500,
message: '删除类目失败',
error: error.message
});
response.serverError(res, '删除类目失败', error);
}
};

View File

@ -1,5 +1,6 @@
const { Room, Rental, Apartment, Bill } = require('../models');
const { Op } = require('sequelize');
const response = require('../utils/response');
// 租金统计
const getRentStatistics = async (req, res) => {
@ -105,14 +106,10 @@ const getRentStatistics = async (req, res) => {
}))
.sort((a, b) => b.month.localeCompare(a.month));
res.status(200).json({
code: 200,
data: rentStatistics,
message: 'success'
});
response.success(res, '获取成功', rentStatistics);
} catch (error) {
console.error('获取租金统计数据时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取租金统计数据失败', error);
}
};
@ -156,13 +153,9 @@ const getRoomStatusStatistics = async (req, res) => {
expired: expired
};
res.status(200).json({
code: 200,
data: roomStatusStatistics,
message: 'success'
});
response.success(res, '获取成功', roomStatusStatistics);
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取房间状态统计失败', error);
}
};
@ -223,14 +216,10 @@ const getDashboardStatistics = async (req, res) => {
collectedWaterAmount: parseFloat(collectedWaterAmount) || 0
};
res.status(200).json({
code: 200,
data: dashboardStatistics,
message: 'success'
});
response.success(res, '获取成功', dashboardStatistics);
} catch (error) {
console.error('获取Dashboard统计数据时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取Dashboard统计数据失败', error);
}
};
@ -280,14 +269,10 @@ const getApartmentRoomStatusStatistics = async (req, res) => {
};
});
res.status(200).json({
code: 200,
data: apartmentRoomStatusStatistics,
message: 'success'
});
response.success(res, '获取成功', apartmentRoomStatusStatistics);
} catch (error) {
console.error('获取公寓房间状态分布数据时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取公寓房间状态分布数据失败', error);
}
};
@ -323,14 +308,10 @@ const getEmptyRoomsByApartment = async (req, res) => {
};
});
res.status(200).json({
code: 200,
data: emptyRoomsByApartment,
message: 'success'
});
response.success(res, '获取成功', emptyRoomsByApartment);
} catch (error) {
console.error('获取空房分布数据时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取空房分布数据失败', error);
}
};
@ -366,14 +347,10 @@ const getRentedRoomsByApartment = async (req, res) => {
};
});
res.status(200).json({
code: 200,
data: rentedRoomsByApartment,
message: 'success'
});
response.success(res, '获取成功', rentedRoomsByApartment);
} catch (error) {
console.error('获取在租分布数据时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取在租分布数据失败', error);
}
};
@ -437,14 +414,10 @@ const getTenantRentalStats = async (req, res) => {
// 转换为数组
const tenantRentalStats = Array.from(tenantMap.values());
res.status(200).json({
code: 200,
data: tenantRentalStats,
message: 'success'
});
response.success(res, '获取成功', tenantRentalStats);
} catch (error) {
console.error('获取租客在租统计数据时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取租客在租统计数据失败', error);
}
};
@ -481,14 +454,10 @@ const getSoonExpireRoomsByApartment = async (req, res) => {
};
});
res.status(200).json({
code: 200,
data: soonExpireRoomsByApartment,
message: 'success'
});
response.success(res, '获取成功', soonExpireRoomsByApartment);
} catch (error) {
console.error('获取即将到期分布数据时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取即将到期分布数据失败', error);
}
};
@ -525,14 +494,10 @@ const getExpiredRoomsByApartment = async (req, res) => {
};
});
res.status(200).json({
code: 200,
data: expiredRoomsByApartment,
message: 'success'
});
response.success(res, '获取成功', expiredRoomsByApartment);
} catch (error) {
console.error('获取已到期分布数据时出错:', error);
res.status(500).json({ code: 500, error: error.message });
response.serverError(res, '获取已到期分布数据失败', error);
}
};
@ -546,4 +511,4 @@ module.exports = {
getSoonExpireRoomsByApartment,
getExpiredRoomsByApartment,
getTenantRentalStats
};
};

View File

@ -4,6 +4,7 @@ const User = require('../models/User');
const Role = require('../models/Role');
const Tenant = require('../models/Tenant');
const { logOperation } = require('../utils/logger');
const response = require('../utils/response');
// 获取用户列表
exports.getUserList = async (req, res) => {
@ -36,23 +37,15 @@ exports.getUserList = async (req, res) => {
limit: parseInt(pageSize)
});
res.json({
code: 200,
message: '获取成功',
data: {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
}
response.success(res, '获取成功', {
list: rows,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
console.error('获取用户列表错误:', error);
res.status(500).json({
code: 500,
message: '获取用户列表失败',
error: error.message
});
response.serverError(res, '获取用户列表失败', error);
}
};
@ -72,17 +65,10 @@ exports.getUserById = async (req, res) => {
});
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
});
return response.notFound(res, '用户不存在');
}
res.json({
code: 200,
message: '获取成功',
data: user
});
response.success(res, '获取成功', user);
// 记录操作日志
await logOperation({
@ -98,11 +84,7 @@ exports.getUserById = async (req, res) => {
});
} catch (error) {
console.error('获取用户详情错误:', error);
res.status(500).json({
code: 500,
message: '获取用户详情失败',
error: error.message
});
response.serverError(res, '获取用户详情失败', error);
}
};
@ -113,31 +95,19 @@ exports.createUser = async (req, res) => {
// 参数验证
if (!username || !password) {
return res.status(400).json({
code: 400,
message: '用户名和密码不能为空'
});
return response.badRequest(res, '用户名和密码不能为空');
}
if (username.length < 3 || username.length > 20) {
return res.status(400).json({
code: 400,
message: '用户名长度应在3-20个字符之间'
});
return response.badRequest(res, '用户名长度应在3-20个字符之间');
}
if (password.length < 6 || password.length > 20) {
return res.status(400).json({
code: 400,
message: '密码长度应在6-20个字符之间'
});
return response.badRequest(res, '密码长度应在6-20个字符之间');
}
if (!roleId) {
return res.status(400).json({
code: 400,
message: '角色不能为空'
});
return response.badRequest(res, '角色不能为空');
}
// 检查租户资源使用情况(仅记录日志,不阻止创建)
@ -174,19 +144,13 @@ exports.createUser = async (req, res) => {
where: { isDeleted: 0, status: 'active' }
});
if (!role) {
return res.status(400).json({
code: 400,
message: '角色不存在或已禁用'
});
return response.badRequest(res, '角色不存在或已禁用');
}
// 检查用户名是否已存在
const existingUser = await User.findOne({ where: { username, isDeleted: 0 } });
if (existingUser) {
return res.status(400).json({
code: 400,
message: '用户名已存在'
});
return response.badRequest(res, '用户名已存在');
}
// 加密密码
@ -203,16 +167,12 @@ exports.createUser = async (req, res) => {
updateBy: req.user.id
});
res.json({
code: 200,
message: '创建成功',
data: {
id: user.id,
username: user.username,
nickname: user.nickname,
roleId: user.roleId,
createTime: user.createTime
},
response.success(res, '创建成功', {
id: user.id,
username: user.username,
nickname: user.nickname,
roleId: user.roleId,
createTime: user.createTime,
warning: isOverage && tenant ? `当前已超出套餐限制(${tenant.maxUsers}人),续费时将收取超额费用` : null
});
@ -230,11 +190,7 @@ exports.createUser = async (req, res) => {
});
} catch (error) {
console.error('创建用户错误:', error);
res.status(500).json({
code: 500,
message: '创建用户失败',
error: error.message
});
response.serverError(res, '创建用户失败', error);
}
};
@ -249,10 +205,7 @@ exports.updateUser = async (req, res) => {
where: { isDeleted: 0 }
});
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
});
return response.notFound(res, '用户不存在');
}
// 检查角色是否存在
@ -261,10 +214,7 @@ exports.updateUser = async (req, res) => {
where: { isDeleted: 0, status: 'active' }
});
if (!role) {
return res.status(400).json({
code: 400,
message: '角色不存在或已禁用'
});
return response.badRequest(res, '角色不存在或已禁用');
}
}
@ -279,17 +229,13 @@ exports.updateUser = async (req, res) => {
// 更新用户
await user.update(updateData);
res.json({
code: 200,
message: '更新成功',
data: {
id: user.id,
username: user.username,
nickname: user.nickname,
roleId: user.roleId,
status: user.status,
updateTime: user.updateTime
}
response.success(res, '更新成功', {
id: user.id,
username: user.username,
nickname: user.nickname,
roleId: user.roleId,
status: user.status,
updateTime: user.updateTime
});
// 记录操作日志
@ -306,11 +252,7 @@ exports.updateUser = async (req, res) => {
});
} catch (error) {
console.error('更新用户错误:', error);
res.status(500).json({
code: 500,
message: '更新用户失败',
error: error.message
});
response.serverError(res, '更新用户失败', error);
}
};
@ -321,10 +263,7 @@ exports.deleteUser = async (req, res) => {
// 不能删除自己
if (parseInt(id) === req.user.id) {
return res.status(400).json({
code: 400,
message: '不能删除自己的账号'
});
return response.badRequest(res, '不能删除自己的账号');
}
// 查找用户
@ -332,10 +271,7 @@ exports.deleteUser = async (req, res) => {
where: { isDeleted: 0 }
});
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
});
return response.notFound(res, '用户不存在');
}
// 软删除
@ -344,10 +280,7 @@ exports.deleteUser = async (req, res) => {
updateBy: req.user.id
});
res.json({
code: 200,
message: '删除成功'
});
response.success(res, '删除成功');
// 记录操作日志
await logOperation({
@ -363,11 +296,7 @@ exports.deleteUser = async (req, res) => {
});
} catch (error) {
console.error('删除用户错误:', error);
res.status(500).json({
code: 500,
message: '删除用户失败',
error: error.message
});
response.serverError(res, '删除用户失败', error);
}
};
@ -382,10 +311,7 @@ exports.resetUserPassword = async (req, res) => {
where: { isDeleted: 0 }
});
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
});
return response.notFound(res, '用户不存在');
}
// 加密默认密码
@ -397,12 +323,8 @@ exports.resetUserPassword = async (req, res) => {
updateBy: req.user.id
});
res.json({
code: 200,
message: '密码重置成功',
data: {
defaultPassword
}
response.success(res, '密码重置成功', {
defaultPassword
});
// 记录操作日志
@ -419,11 +341,7 @@ exports.resetUserPassword = async (req, res) => {
});
} catch (error) {
console.error('重置密码错误:', error);
res.status(500).json({
code: 500,
message: '重置密码失败',
error: error.message
});
response.serverError(res, '重置密码失败', error);
}
};
@ -435,19 +353,10 @@ exports.getAllUsers = async (req, res) => {
attributes: ['id', 'username', 'nickname']
});
res.json({
code: 200,
message: '获取用户列表成功',
data: users
});
response.success(res, '获取用户列表成功', users);
} catch (error) {
console.error('获取用户列表错误:', error);
res.status(500).json({
code: 500,
message: '获取用户列表失败',
error: error.message
});
response.serverError(res, '获取用户列表失败', error);
}
};
@ -464,24 +373,13 @@ exports.getCurrentUserInfo = async (req, res) => {
});
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
});
return response.notFound(res, '用户不存在');
}
res.json({
code: 200,
message: '获取用户信息成功',
data: user
});
response.success(res, '获取用户信息成功', user);
} catch (error) {
console.error('获取用户信息失败:', error);
res.status(500).json({
code: 500,
message: '获取用户信息失败',
error: error.message
});
response.serverError(res, '获取用户信息失败', error);
}
};
@ -492,19 +390,13 @@ exports.updateUserProfile = async (req, res) => {
// 验证昵称
if (!nickname || nickname.trim().length === 0) {
return res.status(400).json({
code: 400,
message: '昵称不能为空'
});
return response.badRequest(res, '昵称不能为空');
}
// 更新用户信息
const user = await User.findByPk(req.user.id);
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
});
return response.notFound(res, '用户不存在');
}
await user.update({
@ -525,25 +417,17 @@ exports.updateUserProfile = async (req, res) => {
status: 'success'
});
res.json({
code: 200,
message: '个人资料更新成功',
data: {
id: user.id,
username: user.username,
nickname: user.nickname,
status: user.status,
createTime: user.createTime,
updateTime: user.updateTime
}
response.success(res, '个人资料更新成功', {
id: user.id,
username: user.username,
nickname: user.nickname,
status: user.status,
createTime: user.createTime,
updateTime: user.updateTime
});
} catch (error) {
console.error('更新个人资料失败:', error);
res.status(500).json({
code: 500,
message: '更新个人资料失败',
error: error.message
});
response.serverError(res, '更新个人资料失败', error);
}
};
@ -554,34 +438,22 @@ exports.changePassword = async (req, res) => {
// 验证参数
if (!oldPassword || !newPassword) {
return res.status(400).json({
code: 400,
message: '旧密码和新密码不能为空'
});
return response.badRequest(res, '旧密码和新密码不能为空');
}
if (newPassword.length < 6) {
return res.status(400).json({
code: 400,
message: '新密码长度至少6位'
});
return response.badRequest(res, '新密码长度至少6位');
}
// 验证旧密码
const user = await User.findByPk(req.user.id);
if (!user) {
return res.status(404).json({
code: 404,
message: '用户不存在'
});
return response.notFound(res, '用户不存在');
}
const isPasswordValid = await bcrypt.compare(oldPassword, user.password);
if (!isPasswordValid) {
return res.status(400).json({
code: 400,
message: '旧密码错误'
});
return response.badRequest(res, '旧密码错误');
}
// 更新密码
@ -604,16 +476,9 @@ exports.changePassword = async (req, res) => {
status: 'success'
});
res.json({
code: 200,
message: '密码修改成功'
});
response.success(res, '密码修改成功');
} catch (error) {
console.error('修改密码失败:', error);
res.status(500).json({
code: 500,
message: '修改密码失败',
error: error.message
});
response.serverError(res, '修改密码失败', error);
}
};

View File

@ -1,283 +0,0 @@
const { WaterBill, Room } = require('../models');
const { Op } = require('sequelize');
// 格式化时间(考虑时区,转换为北京时间)
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 formatWaterBillData = (bill) => {
const formattedBill = {
...bill.toJSON(),
startDate: formatDate(bill.startDate),
endDate: formatDate(bill.endDate),
createTime: formatDate(bill.createTime),
updateTime: formatDate(bill.updateTime)
};
// 格式化关联数据
if (formattedBill.Room) {
formattedBill.Room = {
...formattedBill.Room,
createTime: formatDate(formattedBill.Room.createTime),
updateTime: formatDate(formattedBill.Room.updateTime)
};
}
return formattedBill;
};
// 获取所有水费记录(支持搜索和分页)
const getAllWaterBills = async (req, res) => {
try {
const {
apartmentId,
roomId,
status,
startDateFrom,
endDateTo,
page = 1,
pageSize = 10
} = req.query;
const where = { isDeleted: 0 };
if (roomId) {
where.roomId = roomId;
}
if (status) {
where.status = status;
}
if (startDateFrom && endDateTo) {
where.startDate = { [Op.gte]: new Date(startDateFrom) };
where.endDate = { [Op.lte]: new Date(endDateTo) };
}
const include = [
{
model: Room,
where: {
isDeleted: 0,
...(apartmentId ? { apartmentId } : {})
}
}
];
const offset = (page - 1) * pageSize;
const { count, rows } = await WaterBill.findAndCountAll({
where,
include,
limit: parseInt(pageSize),
offset: parseInt(offset),
order: [['createTime', 'DESC']]
});
const formattedBills = rows.map(formatWaterBillData);
res.status(200).json({
data: formattedBills,
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize)
});
} catch (error) {
res.status(500).json({ error: error.message });
}
};
// 获取单个水费记录
const getWaterBillById = async (req, res) => {
try {
const { id } = req.params;
const bill = await WaterBill.findOne({
where: { id, isDeleted: 0 },
include: [
{
model: Room,
where: { isDeleted: 0 }
}
]
});
if (!bill) {
return res.status(404).json({ error: '水费记录不存在' });
}
const formattedBill = formatWaterBillData(bill);
res.status(200).json({
code: 200,
data: formattedBill,
message: 'success'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
// 创建水费记录
const createWaterBill = async (req, res) => {
try {
const { roomId, startDate, endDate, startReading, endReading, unitPrice, status } = req.body;
let usage = null;
let amount = null;
if (startReading && endReading && unitPrice) {
usage = parseFloat(endReading) - parseFloat(startReading);
amount = usage * parseFloat(unitPrice);
}
const bill = await WaterBill.create({
roomId,
startDate,
endDate,
startReading,
endReading,
usage,
unitPrice,
amount,
status: status || 'unpaid',
createBy: req.user.id,
updateBy: req.user.id
});
const formattedBill = formatWaterBillData(bill);
res.status(201).json({
code: 201,
data: formattedBill,
message: '创建成功'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
// 更新水费记录
const updateWaterBill = async (req, res) => {
try {
const { id } = req.params;
const { startDate, endDate, startReading, endReading, unitPrice, status } = req.body;
const bill = await WaterBill.findOne({
where: { id, isDeleted: 0 }
});
if (!bill) {
return res.status(404).json({ error: '水费记录不存在' });
}
let usage = bill.usage;
let amount = bill.amount;
if (startReading && endReading && unitPrice) {
usage = parseFloat(endReading) - parseFloat(startReading);
amount = usage * parseFloat(unitPrice);
}
await bill.update({
startDate,
endDate,
startReading,
endReading,
usage,
unitPrice,
amount,
status: status !== undefined ? status : bill.status,
updateBy: req.user.id
});
const formattedBill = formatWaterBillData(bill);
res.status(200).json({
code: 200,
data: formattedBill,
message: '更新成功'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
// 删除水费记录(软删除)
const deleteWaterBill = async (req, res) => {
try {
const { id } = req.params;
const bill = await WaterBill.findOne({
where: { id, isDeleted: 0 }
});
if (!bill) {
return res.status(404).json({ error: '水费记录不存在' });
}
await bill.update({
isDeleted: 1,
updateBy: req.user.id
});
res.status(200).json({
code: 200,
message: '水费记录删除成功'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
// 获取所有水费记录(不分页)
const listWaterBills = async (req, res) => {
try {
const {
apartmentId,
roomId,
status,
startDateFrom,
endDateTo
} = req.query;
const where = { isDeleted: 0 };
if (roomId) {
where.roomId = roomId;
}
if (status) {
where.status = status;
}
if (startDateFrom && endDateTo) {
where.startDate = { [Op.gte]: new Date(startDateFrom) };
where.endDate = { [Op.lte]: new Date(endDateTo) };
}
const include = [
{
model: Room,
where: {
isDeleted: 0,
...(apartmentId ? { apartmentId } : {})
}
}
];
const bills = await WaterBill.findAll({
where,
include,
order: [['createTime', 'DESC']]
});
const formattedBills = bills.map(formatWaterBillData);
res.status(200).json({
code: 200,
data: formattedBills,
message: 'success'
});
} catch (error) {
res.status(500).json({ code: 500, error: error.message });
}
};
module.exports = {
getAllWaterBills,
listWaterBills,
getWaterBillById,
createWaterBill,
updateWaterBill,
deleteWaterBill
};

View File

@ -134,14 +134,6 @@ INSERT IGNORE INTO `menus` (`id`, `parentId`, `name`, `code`, `type`, `path`, `c
INSERT IGNORE INTO `menus` (`id`, `name`, `code`, `type`, `path`, `component`, `icon`, `sort`, `visible`, `status`, `isBasic`, `isDeleted`, `createTime`, `updateTime`) VALUES
(13, '计费中心', 'billing_center', 'menu', '/billing/center', 'views/billing/BillingCenter', 'el-icon-wallet', 6, 'show', 'active', 1, 0, NOW(), NOW());
-- 7. 数据统计(父菜单)
INSERT IGNORE INTO `menus` (`id`, `name`, `code`, `type`, `path`, `component`, `icon`, `sort`, `visible`, `status`, `isBasic`, `isDeleted`, `createTime`, `updateTime`) VALUES
(14, '数据统计', 'statistics', 'menu', '/statistics', NULL, 'el-icon-s-data', 7, 'show', 'active', 1, 0, NOW(), NOW());
-- 7.1 收支统计
INSERT IGNORE INTO `menus` (`id`, `parentId`, `name`, `code`, `type`, `path`, `component`, `icon`, `sort`, `visible`, `status`, `isBasic`, `isDeleted`, `createTime`, `updateTime`) VALUES
(15, 14, '收支统计', 'finance_stats', 'menu', '/statistics/finance', 'views/statistics/Finance', 'el-icon-s-data', 1, 'show', 'active', 1, 0, NOW(), NOW());
-- 8. 系统设置(父菜单)
INSERT IGNORE INTO `menus` (`id`, `name`, `code`, `type`, `path`, `component`, `icon`, `sort`, `visible`, `status`, `isBasic`, `isDeleted`, `createTime`, `updateTime`) VALUES
(17, '系统设置', 'settings', 'menu', '/settings', NULL, 'el-icon-setting', 8, 'show', 'active', 1, 0, NOW(), NOW());

View File

@ -1,20 +0,0 @@
const express = require('express');
const router = express.Router();
const electricityBillController = require('../controllers/electricityBillController');
// 获取所有电费记录
router.get('/', electricityBillController.getAllElectricityBills);
// 获取单个电费记录
router.get('/:id', electricityBillController.getElectricityBillById);
// 创建电费记录
router.post('/', electricityBillController.createElectricityBill);
// 更新电费记录
router.put('/:id', electricityBillController.updateElectricityBill);
// 删除电费记录
router.delete('/:id', electricityBillController.deleteElectricityBill);
module.exports = router;

View File

@ -1,23 +0,0 @@
const express = require('express');
const router = express.Router();
const waterBillController = require('../controllers/waterBillController');
// 获取所有水费记录(分页)
router.get('/', waterBillController.getAllWaterBills);
// 获取所有水费记录(不分页)
router.get('/list', waterBillController.listWaterBills);
// 获取单个水费记录
router.get('/:id', waterBillController.getWaterBillById);
// 创建水费记录
router.post('/', waterBillController.createWaterBill);
// 更新水费记录
router.put('/:id', waterBillController.updateWaterBill);
// 删除水费记录
router.delete('/:id', waterBillController.deleteWaterBill);
module.exports = router;

114
utils/response.js Normal file
View File

@ -0,0 +1,114 @@
/**
* 统一响应工具函数
* 规范所有接口的返回数据格式
*/
/**
* 成功响应
* @param {object} res - Express响应对象
* @param {string} message - 成功消息
* @param {any} data - 响应数据
* @param {number} statusCode - HTTP状态码默认200
*/
const success = (res, message = '操作成功', data = null, statusCode = 200) => {
res.status(statusCode).json({
code: 200,
message,
data
});
};
/**
* 错误响应
* @param {object} res - Express响应对象
* @param {string} message - 错误消息
* @param {number} code - 错误码默认500
* @param {number} statusCode - HTTP状态码默认对应code
*/
const error = (res, message = '操作失败', code = 500, statusCode = null) => {
const httpStatus = statusCode || code;
res.status(httpStatus).json({
code,
message,
data: null
});
};
/**
* 参数错误响应 (400)
* @param {object} res - Express响应对象
* @param {string} message - 错误消息
*/
const badRequest = (res, message = '请求参数错误') => {
error(res, message, 400);
};
/**
* 未授权响应 (401)
* @param {object} res - Express响应对象
* @param {string} message - 错误消息
*/
const unauthorized = (res, message = '未授权,请先登录') => {
error(res, message, 401);
};
/**
* 禁止访问响应 (403)
* @param {object} res - Express响应对象
* @param {string} message - 错误消息
*/
const forbidden = (res, message = '没有权限执行此操作') => {
error(res, message, 403);
};
/**
* 资源不存在响应 (404)
* @param {object} res - Express响应对象
* @param {string} message - 错误消息
*/
const notFound = (res, message = '资源不存在') => {
error(res, message, 404);
};
/**
* 服务器错误响应 (500)
* @param {object} res - Express响应对象
* @param {string} message - 错误消息
* @param {Error} err - 错误对象仅在开发环境返回
*/
const serverError = (res, message = '服务器内部错误', err = null) => {
const response = {
code: 500,
message,
data: null
};
// 开发环境下返回错误详情
if (process.env.NODE_ENV === 'development' && err) {
response.error = err.message;
response.stack = err.stack;
}
res.status(500).json(response);
};
/**
* 创建成功响应 (201)
* @param {object} res - Express响应对象
* @param {string} message - 成功消息
* @param {any} data - 响应数据
*/
const created = (res, message = '创建成功', data = null) => {
success(res, message, data, 201);
};
module.exports = {
success,
error,
badRequest,
unauthorized,
forbidden,
notFound,
serverError,
created
};