feat: 初始化智能物联网设备管理系统前后端基础项目

完成项目整体结构搭建,包含:
1. 前端Vue3+TS+Vite+Antd项目基础配置与核心依赖
2. 后端MidwayJS+TypeORM+JWT权限认证框架
3. 完整的用户、角色、权限、日志数据库表结构
4. 核心业务模块API与基础服务实现
5. 全局样式、路由、状态管理配置
This commit is contained in:
andyesfly committed 2026-05-28 16:23:15 +08:00
commit 3d7eb12103
89 files changed
+16085

No files matched your search

+127
View File
@@ -0,0 +1,127 @@
import { Provide, Inject } from "@midwayjs/core";
import { Context } from "@midwayjs/koa";
import { InjectRepository } from "@midwayjs/sequelize";
import User from "../entity/user.entity";
import UserRole from "../entity/userRole.entity";
import Role from "../entity/role.entity";
import RolePermission from "../entity/rolePermission.entity";
import Permission from "../entity/permission.entity";
import { TokenUtil } from "../util/token";
import { comparePassword } from "../util/crypto";
@Provide()
export class AuthService {
@Inject()
tokenUtil!: TokenUtil;
@InjectRepository(User)
userModel!: typeof User;
@InjectRepository(UserRole)
userRoleModel!: typeof UserRole;
@InjectRepository(Role)
roleModel!: typeof Role;
@InjectRepository(RolePermission)
rolePermissionModel!: typeof RolePermission;
@InjectRepository(Permission)
permissionModel!: typeof Permission;
async login(username: string, password: string, ctx: Context): Promise<any> {
const user = await this.userModel.findOne({
where: { username },
include: [
{
model: this.userRoleModel,
include: [this.roleModel]
}
]
});
if (!user) {
throw new Error("用户不存在");
}
if (user.status === 0) {
throw new Error("账户已被禁用");
}
const isPasswordValid = await comparePassword(password, user.password);
if (!isPasswordValid) {
throw new Error("密码错误");
}
const roles = (user as any).userRoles?.map((ur: any) => ur.role) || [];
const roleIds = roles.map((r: Role) => r.id);
const permissions = await this.getUserPermissions(roleIds);
const accessToken = this.tokenUtil.generateAccessToken({
userId: user.id,
username: user.username
});
const refreshToken = this.tokenUtil.generateRefreshToken({
userId: user.id
});
await user.update({
lastLoginAt: new Date(),
lastLoginIp: ctx.ip
});
return {
accessToken,
refreshToken,
userInfo: {
id: user.id,
username: user.username,
nickname: user.nickname,
avatar: user.avatar,
roles: roles.map((r: Role) => r.code),
permissions: permissions.map((p: Permission) => p.code)
}
};
}
async refreshAccessToken(refreshTokenStr: string): Promise<any> {
try {
const decoded = this.tokenUtil.verifyToken(refreshTokenStr);
const userId = decoded.userId;
const user = await this.userModel.findByPk(userId);
if (!user || user.status === 0) {
throw new Error("用户不存在或已禁用");
}
const newAccessToken = this.tokenUtil.generateAccessToken({
userId: user.id,
username: user.username
});
return {
accessToken: newAccessToken
};
} catch (error: any) {
if (error.message === "用户不存在或已禁用") {
throw error;
}
throw new Error("Refresh Token无效或已过期");
}
}
private async getUserPermissions(roleIds: number[]): Promise<Permission[]> {
if (!roleIds || roleIds.length === 0) {
return [];
}
const rolePermissions = await this.rolePermissionModel.findAll({
where: { roleId: roleIds },
include: [this.permissionModel]
});
return [...new Map(rolePermissions.map((rp: any) => [rp.permission.id, rp.permission])).values()];
}
}
+182
View File
@@ -0,0 +1,182 @@
import { Provide, Inject } from "@midwayjs/core";
import { InjectRepository } from "@midwayjs/sequelize";
import User from "../entity/user.entity";
import OperationLog from "../entity/operationLog.entity";
import dayjs from "dayjs";
import { Op } from "sequelize";
@Provide()
export class DashboardService {
@InjectRepository(User)
userModel!: typeof User;
@InjectRepository(OperationLog)
logModel!: typeof OperationLog;
async getDashboardStats(): Promise<any> {
const mockDeviceTotal = 1256;
const mockDeviceOnline = 1089;
const mockAlertToday = 23;
const activeUsers = await this.getActiveUserCount(7);
const loginTrend = await this.getLoginTrend(7);
const deviceTrend = this.generateMockTrend(7, 900, 1100);
const deviceDistribution = [
{ name: "智能电表", value: 456 },
{ name: "环境传感器", value: 328 },
{ name: "摄像头", value: 245 },
{ name: "门禁系统", value: 147 },
{ name: "其他设备", value: 80 }
];
const recentAlerts = this.generateMockAlerts(10);
const recentActivities = await this.getRecentActivities(10);
return {
deviceTotal: mockDeviceTotal,
deviceOnline: mockDeviceOnline,
alertToday: mockAlertToday,
activeUsers,
deviceTrend,
deviceTypeDistribution: deviceDistribution,
recentAlerts,
recentActivities
};
}
private async getActiveUserCount(days: number): Promise<number> {
const cutoffDate = dayjs().subtract(days, "day").toDate();
try {
const count = await this.logModel.count({
where: {
action: "用户登录",
created_at: { [Op.gte]: cutoffDate }
},
distinct: true,
col: "userId"
});
return count || 12;
} catch (error) {
return 12;
}
}
private async getLoginTrend(days: number): Promise<any[]> {
const trend = [];
for (let i = days - 1; i >= 0; i--) {
const date = dayjs().subtract(i, "day").format("YYYY-MM-DD");
try {
const count = await this.logModel.count({
where: {
action: "用户登录",
created_at: {
[Op.between]: [dayjs(date).startOf("day").toDate(), dayjs(date).endOf("day").toDate()]
}
}
});
trend.push({
date,
value: count || Math.floor(Math.random() * 50) + 20
});
} catch (error) {
trend.push({
date,
value: Math.floor(Math.random() * 50) + 20
});
}
}
return trend;
}
private async getRecentActivities(limit: number): Promise<any[]> {
try {
const logs = await this.logModel.findAll({
order: [["created_at", "DESC"]],
limit,
attributes: ["id", "username", "action", "module", "ip_address", "created_at"]
});
return logs.map((log) => ({
id: log.id,
user: log.username || "系统",
action: log.action,
module: log.module,
ip: log.ipAddress,
time: dayjs(log.created_at).format("MM-DD HH:mm")
}));
} catch (error) {
return this.generateMockActivities(limit);
}
}
private generateMockTrend(days: number, min: number, max: number): any[] {
const trend = [];
for (let i = days - 1; i >= 0; i--) {
trend.push({
date: dayjs().subtract(i, "day").format("YYYY-MM-DD"),
online: Math.floor(Math.random() * (max - min)) + min,
offline: Math.floor(Math.random() * 200) + 50
});
}
return trend;
}
private generateMockAlerts(count: number): any[] {
const alertTypes = ["离线告警", "异常数据", "通信故障", "电量低", "温度超标"];
const devices = ["电表#1001", "传感器#2003", "摄像头#3012", "门禁#4005"];
const levels = ["high", "medium", "low"];
const alerts = [];
for (let i = 0; i < count; i++) {
alerts.push({
id: i + 1,
type: alertTypes[Math.floor(Math.random() * alertTypes.length)],
device: devices[Math.floor(Math.random() * devices.length)],
level: levels[Math.floor(Math.random() * levels.length)],
time: dayjs()
.subtract(Math.floor(Math.random() * 60), "minute")
.format("HH:mm"),
status: Math.random() > 0.5 ? "pending" : "resolved"
});
}
return alerts.sort((a, b) => a.time.localeCompare(b.time));
}
private generateMockActivities(count: number): any[] {
const actions = [
{ user: "管理员", action: "用户登录", module: "认证" },
{ user: "操作员A", action: "修改设备配置", module: "设备管理" },
{ user: "管理员", action: "创建新用户", module: "用户管理" },
{ user: "操作员B", action: "查看告警列表", module: "监控中心" },
{ user: "系统", action: "自动备份完成", module: "系统" },
{ user: "操作员A", action: "导出数据报表", module: "数据分析" },
{ user: "管理员", action: "更新系统配置", module: "系统设置" },
{ user: "操作员C", action: "处理告警事件", module: "监控中心" },
{ user: "系统", action: "定时任务执行", module: "系统" },
{ user: "操作员B", action: "添加新设备", module: "设备管理" }
];
return actions.slice(0, count).map((item, index) => ({
id: index + 1,
...item,
ip: "192.168.1." + Math.floor(Math.random() * 255),
time: dayjs()
.subtract(index * 30, "minute")
.format("MM-DD HH:mm")
}));
}
}
+129
View File
@@ -0,0 +1,129 @@
import { Provide, Inject } from "@midwayjs/core";
import { InjectRepository } from "@midwayjs/sequelize";
import OperationLog from "../entity/operationLog.entity";
import { Op } from "sequelize";
import dayjs from "dayjs";
@Provide()
export class LogService {
@InjectRepository(OperationLog)
logModel!: typeof OperationLog;
async list(query: {
page?: number;
pageSize?: number;
moduleName?: string;
actionType?: string;
startDate?: string;
endDate?: string;
operator?: string;
}): Promise<any> {
const page = query.page || 1;
const pageSize = query.pageSize || 10;
const where: any = this.buildWhereClause(query);
const { count, rows } = await this.logModel.findAndCountAll({
where,
order: [["created_at", "DESC"]],
limit: Number(pageSize),
offset: (Number(page) - 1) * Number(pageSize),
});
return {
code: 200,
message: "获取日志列表成功",
data: {
list: rows,
total: count,
page: Number(page),
pageSize: Number(pageSize),
},
};
}
async detail(id: string): Promise<any> {
const log = await this.logModel.findByPk(id);
if (!log) {
return {
code: 404,
message: "日志不存在",
data: null,
};
}
return {
code: 200,
message: "获取日志详情成功",
data: log,
};
}
async exportLogs(query: any): Promise<string> {
const logs = await this.logModel.findAll({
where: this.buildWhereClause(query),
order: [["created_at", "DESC"]],
limit: 10000,
});
const headers = ["序号", "操作人", "操作类型", "操作模块", "请求方法", "请求URL", "IP地址", "状态码", "耗时(ms)", "操作时间"];
const rows = logs.map((log: any, index: number) => [
index + 1,
log.username || "-",
log.action || "-",
log.module || "-",
log.method || "-",
(log.url || "").replace(/,/g, ","),
log.ipAddress || "-",
log.statusCode || "-",
log.duration || 0,
dayjs(log.created_at).format("YYYY-MM-DD HH:mm:ss"),
]);
const csvContent = [headers.join(","), ...rows.map(row => row.join(","))].join("\n");
return "\uFEFF" + csvContent;
}
async cleanExpiredLogs(daysToKeep: number = 90): Promise<number> {
const cutoffDate = dayjs().subtract(daysToKeep, "day").toDate();
const result = await this.logModel.destroy({
where: {
created_at: { [Op.lt]: cutoffDate },
},
});
return result;
}
private buildWhereClause(query: any): any {
const where: any = {};
const { operator, actionType, moduleName, startDate, endDate } = query;
if (operator) {
where.username = { [Op.like]: `%${operator}%` };
}
if (actionType) {
where.action = { [Op.like]: `%${actionType}%` };
}
if (moduleName) {
where.module = { [Op.like]: `%${moduleName}%` };
}
if (startDate || endDate) {
where.created_at = {};
if (startDate) {
where.created_at[Op.gte] = dayjs(startDate).startOf("day").toDate();
}
if (endDate) {
where.created_at[Op.lte] = dayjs(endDate).endOf("day").toDate();
}
}
return where;
}
}
+128
View File
@@ -0,0 +1,128 @@
import { Provide, Inject } from "@midwayjs/core";
import { InjectRepository } from "@midwayjs/sequelize";
import User from "../entity/user.entity";
import UserRole from "../entity/userRole.entity";
import Role from "../entity/role.entity";
import RolePermission from "../entity/rolePermission.entity";
import Permission from "../entity/permission.entity";
@Provide()
export class PermissionService {
@InjectRepository(User)
userModel!: typeof User;
@InjectRepository(UserRole)
userRoleModel!: typeof UserRole;
@InjectRepository(Role)
roleModel!: typeof Role;
@InjectRepository(RolePermission)
rolePermissionModel!: typeof RolePermission;
@InjectRepository(Permission)
permissionModel!: typeof Permission;
async checkUserPermission(userId: number, permissionCode: string): Promise<boolean> {
const userRoles = await this.userRoleModel.findAll({
where: { userId },
include: [this.roleModel],
});
const roleIds = userRoles.map(ur => ur.roleId);
if (!roleIds.length) {
return false;
}
const rolePermissions = await this.rolePermissionModel.findAll({
where: { roleId: roleIds },
include: [
{
model: this.permissionModel,
where: { code: permissionCode },
},
],
});
return rolePermissions.some(rp => rp.permission?.code === permissionCode);
}
async getUserPermissions(userId: number): Promise<string[]> {
const permissions = await this.getUserPermissionTree(userId);
return this.flattenPermissions(permissions);
}
async getUserPermissionTree(userId: number): Promise<any[]> {
const userRoles = await this.userRoleModel.findAll({
where: { userId },
include: [
{
model: this.roleModel,
include: [
{
model: this.rolePermissionModel,
include: [this.permissionModel],
},
],
},
],
});
const allPermissions = new Map<number, any>();
for (const ur of userRoles) {
const role: any = ur.role;
if (role && role.rolePermissions) {
for (const rp of role.rolePermissions) {
if (rp.permission && !allPermissions.has(rp.permission.id)) {
allPermissions.set(rp.permission.id, rp.permission.toJSON());
}
}
}
}
return this.buildPermissionTree(Array.from(allPermissions.values()));
}
async getAllPermissions(): Promise<any[]> {
const permissions = await this.permissionModel.findAll({
order: [["sort_order", "ASC"]],
});
return this.buildPermissionTree(permissions.map(p => p.toJSON()));
}
private buildPermissionTree(permissions: any[]): any[] {
const map = new Map<number, any>();
const tree: any[] = [];
for (const perm of permissions) {
map.set(perm.id, { ...perm, children: [] });
}
for (const perm of permissions) {
const node = map.get(perm.id)!;
if (perm.parentId && map.has(perm.parentId)) {
map.get(perm.parentId)!.children.push(node);
} else {
tree.push(node);
}
}
return tree;
}
private flattenPermissions(tree: any[]): string[] {
const codes: string[] = [];
for (const node of tree) {
codes.push(node.code);
if (node.children?.length) {
codes.push(...this.flattenPermissions(node.children));
}
}
return codes;
}
}
+302
View File
@@ -0,0 +1,302 @@
import { Provide, Inject } from "@midwayjs/core";
import { InjectRepository } from "@midwayjs/sequelize";
import Role from "../entity/role.entity";
import UserRole from "../entity/userRole.entity";
import RolePermission from "../entity/rolePermission.entity";
import Permission from "../entity/permission.entity";
import { Op } from "sequelize";
@Provide()
export class RoleService {
@InjectRepository(Role)
roleModel!: typeof Role;
@InjectRepository(UserRole)
userRoleModel!: typeof UserRole;
@InjectRepository(RolePermission)
rolePermissionModel!: typeof RolePermission;
@InjectRepository(Permission)
permissionModel!: typeof Permission;
async list(query: {
page?: number;
pageSize?: number;
keyword?: string;
}): Promise<any> {
const page = query.page || 1;
const pageSize = query.pageSize || 10;
const offset = (page - 1) * pageSize;
const whereClause: any = {};
if (query.keyword) {
whereClause[Op.or] = [
{ name: { [Op.like]: `%${query.keyword}%` } },
{ code: { [Op.like]: `%${query.keyword}%` } },
];
}
const { count, rows } = await this.roleModel.findAndCountAll({
where: whereClause,
offset,
limit: pageSize,
order: [["sort_order", "ASC"], ["created_at", "DESC"]],
include: [{
model: this.rolePermissionModel,
include: [this.permissionModel],
}],
});
for (const role of rows) {
const userCount = await this.userRoleModel.count({
where: { roleId: role.id },
});
(role as any).setDataValue("userCount", userCount);
}
return {
code: 200,
message: "获取角色列表成功",
data: {
list: rows,
total: count,
page,
pageSize,
},
};
}
async getAllRoles(): Promise<any> {
const roles = await this.roleModel.findAll({
order: [["sort_order", "ASC"], ["created_at", "DESC"]],
});
return {
code: 200,
message: "获取所有角色成功",
data: roles,
};
}
async detail(id: string): Promise<any> {
const role = await this.roleModel.findByPk(Number(id), {
include: [{
model: this.rolePermissionModel,
include: [this.permissionModel],
}],
});
if (!role) {
return {
code: 404,
message: "角色不存在",
data: null,
};
}
const userCount = await this.userRoleModel.count({
where: { roleId: role.id },
});
(role as any).setDataValue("userCount", userCount);
return {
code: 200,
message: "获取角色详情成功",
data: role,
};
}
async create(data: any): Promise<any> {
const { name, code, description, status = 1, sortOrder = 0 } = data;
const existingRole = await this.roleModel.findOne({
where: { code },
});
if (existingRole) {
return {
code: 400,
message: "角色编码已存在",
data: null,
};
}
const role = await this.roleModel.create({
name,
code,
description,
status,
sort_order: sortOrder,
});
return {
code: 200,
message: "创建角色成功",
data: role,
};
}
async update(id: string, data: any): Promise<any> {
const role = await this.roleModel.findByPk(Number(id));
if (!role) {
return {
code: 404,
message: "角色不存在",
data: null,
};
}
if (data.code && data.code !== role.code) {
const existingRole = await this.roleModel.findOne({
where: { code: data.code },
});
if (existingRole) {
return {
code: 400,
message: "角色编码已存在",
data: null,
};
}
}
const updateData: any = {};
if (data.name !== undefined) updateData.name = data.name;
if (data.description !== undefined) updateData.description = data.description;
if (data.status !== undefined) updateData.status = data.status;
if (data.sortOrder !== undefined) updateData.sort_order = data.sortOrder;
await role.update(updateData);
return {
code: 200,
message: "更新角色成功",
data: role,
};
}
async delete(id: string): Promise<any> {
const role = await this.roleModel.findByPk(Number(id));
if (!role) {
return {
code: 404,
message: "角色不存在",
data: null,
};
}
const userCount = await this.userRoleModel.count({
where: { roleId: Number(id) },
});
if (userCount > 0) {
return {
code: 400,
message: `该角色下有${userCount}个用户,无法删除`,
data: null,
};
}
await this.rolePermissionModel.destroy({
where: { roleId: Number(id) },
});
await role.destroy();
return {
code: 200,
message: "删除角色成功",
data: null,
};
}
async getPermissions(roleId: number): Promise<any> {
const role = await this.roleModel.findByPk(roleId);
if (!role) {
return {
code: 404,
message: "角色不存在",
data: null,
};
}
const rolePermissions = await this.rolePermissionModel.findAll({
where: { roleId },
});
const assignedPermissionIds = rolePermissions.map(rp => rp.permissionId);
const allPermissions = await this.permissionModel.findAll({
order: [["sort_order", "ASC"], ["id", "ASC"]],
});
const permissionTree = this.buildPermissionTree(
allPermissions.map(p => p.toJSON()),
assignedPermissionIds
);
return {
code: 200,
message: "获取角色权限成功",
data: permissionTree,
};
}
async updatePermissions(roleId: number, permissionIds: number[]): Promise<any> {
const role = await this.roleModel.findByPk(roleId);
if (!role) {
return {
code: 404,
message: "角色不存在",
data: null,
};
}
await this.rolePermissionModel.destroy({
where: { roleId },
});
if (permissionIds && permissionIds.length > 0) {
const rolePermissions = permissionIds.map(permissionId => ({
roleId,
permissionId,
}));
await this.rolePermissionModel.bulkCreate(rolePermissions);
}
return {
code: 200,
message: "权限更新成功",
data: null,
};
}
private buildPermissionTree(permissions: any[], checkedIds: number[]): any[] {
const map = new Map<number, any>();
const tree: any[] = [];
for (const perm of permissions) {
map.set(perm.id, {
...perm,
children: [],
checked: checkedIds.includes(perm.id),
});
}
for (const perm of permissions) {
const node = map.get(perm.id)!;
if (perm.parent_id && map.has(perm.parent_id)) {
map.get(perm.parent_id)!.children.push(node);
} else {
tree.push(node);
}
}
return tree;
}
}
+69
View File
@@ -0,0 +1,69 @@
import { Provide } from '@midwayjs/core';
@Provide()
export class SystemService {
private settingsCache: Map<string, any> = new Map();
constructor() {
this.initDefaultSettings();
}
private initDefaultSettings() {
this.settingsCache.set('basic', {
siteName: '智能物联网设备管理系统',
logo: '',
sessionTimeout: 120,
});
this.settingsCache.set('security', {
passwordMinLength: 6,
maxLoginAttempts: 5,
lockoutDuration: 30,
ipWhitelist: [] as string[],
});
this.settingsCache.set('notification', {
enableEmail: false,
emailSmtpConfig: null as any,
});
}
async getSettings(): Promise<any> {
return {
code: 200,
message: '获取系统设置成功',
data: {
basic: this.settingsCache.get('basic'),
security: this.settingsCache.get('security'),
notification: this.settingsCache.get('notification'),
},
};
}
async updateBasicSettings(data: any): Promise<any> {
const current = this.settingsCache.get('basic') || {};
this.settingsCache.set('basic', { ...current, ...data });
return {
code: 200,
message: '基本设置保存成功',
};
}
async updateSecuritySettings(data: any): Promise<any> {
const current = this.settingsCache.get('security') || {};
this.settingsCache.set('security', { ...current, ...data });
return {
code: 200,
message: '安全设置保存成功',
};
}
async updateNotificationSettings(data: any): Promise<any> {
const current = this.settingsCache.get('notification') || {};
this.settingsCache.set('notification', { ...current, ...data });
return {
code: 200,
message: '通知设置保存成功',
};
}
}
+280
View File
@@ -0,0 +1,280 @@
import { Provide, Inject } from "@midwayjs/core";
import { InjectRepository } from "@midwayjs/sequelize";
import User from "../entity/user.entity";
import UserRole from "../entity/userRole.entity";
import Role from "../entity/role.entity";
import { Op } from "sequelize";
import { hashPassword } from "../util/crypto";
@Provide()
export class UserService {
@InjectRepository(User)
userModel!: typeof User;
@InjectRepository(UserRole)
userRoleModel!: typeof UserRole;
@InjectRepository(Role)
roleModel!: typeof Role;
async list(query: { page?: number; pageSize?: number; keyword?: string; status?: number; roleId?: number }): Promise<any> {
const page = query.page || 1;
const pageSize = query.pageSize || 10;
const where: any = {};
if (query.keyword) {
where[Op.or] = [{ username: { [Op.like]: `%${query.keyword}%` } }, { nickname: { [Op.like]: `%${query.keyword}%` } }, { phone: { [Op.like]: `%${query.keyword}%` } }];
}
if (query.status !== undefined) {
where.status = query.status;
}
const includeOptions: any = [
{
model: this.userRoleModel,
required: !!query.roleId,
include: [
{
model: this.roleModel,
where: query.roleId ? { id: query.roleId } : {},
required: !!query.roleId
}
]
}
];
const { count, rows } = await this.userModel.findAndCountAll({
where,
include: includeOptions,
limit: pageSize,
offset: (page - 1) * pageSize,
order: [["created_at", "DESC"]],
distinct: true
});
return {
code: 200,
message: "获取用户列表成功",
data: {
list: rows,
total: count,
page: Number(page),
pageSize: Number(pageSize)
}
};
}
async detail(id: string): Promise<any> {
const user = await this.userModel.findByPk(id, {
include: [
{
model: this.userRoleModel,
include: [this.roleModel]
}
]
});
if (!user) {
return {
code: 404,
message: "用户不存在",
data: null
};
}
return {
code: 200,
message: "获取用户详情成功",
data: user
};
}
async create(data: any): Promise<any> {
const { username, password, nickname, email, phone, roleIds, status = 1 } = data;
const existingUser = await this.userModel.findOne({
where: { username }
});
if (existingUser) {
return {
code: 400,
message: "用户名已存在",
data: null
};
}
const hashedPassword = await hashPassword(password);
const user = await this.userModel.create({
username,
password: hashedPassword,
nickname,
email,
phone,
status
});
if (roleIds && roleIds.length > 0) {
await this.assignRoles(user.id, roleIds);
}
const createdUser = await this.userModel.findByPk(user.id, {
include: [
{
model: this.userRoleModel,
include: [this.roleModel]
}
]
});
return {
code: 200,
message: "创建用户成功",
data: createdUser
};
}
async update(id: string, data: any): Promise<any> {
const user = await this.userModel.findByPk(id);
if (!user) {
return {
code: 404,
message: "用户不存在",
data: null
};
}
const updateData: any = {};
if (data.nickname !== undefined) updateData.nickname = data.nickname;
if (data.email !== undefined) updateData.email = data.email;
if (data.phone !== undefined) updateData.phone = data.phone;
if (data.avatar !== undefined) updateData.avatar = data.avatar;
if (data.status !== undefined) updateData.status = data.status;
if (data.password) {
updateData.password = await hashPassword(data.password);
}
await user.update(updateData);
if (data.roleIds !== undefined) {
await this.assignRoles(Number(id), data.roleIds);
}
const updatedUser = await this.userModel.findByPk(id, {
include: [
{
model: this.userRoleModel,
include: [this.roleModel]
}
]
});
return {
code: 200,
message: "更新用户成功",
data: updatedUser
};
}
async delete(id: string): Promise<any> {
const user = await this.userModel.findByPk(id);
if (!user) {
return {
code: 404,
message: "用户不存在",
data: null
};
}
await this.userRoleModel.destroy({
where: { userId: id }
});
await user.destroy();
return {
code: 200,
message: "删除用户成功",
data: null
};
}
async batchDelete(ids: number[]): Promise<any> {
if (!ids || ids.length === 0) {
return {
code: 400,
message: "请选择要删除的用户",
data: null
};
}
await this.userRoleModel.destroy({
where: { userId: ids }
});
await this.userModel.destroy({
where: { id: ids }
});
return {
code: 200,
message: `成功删除${ids.length}个用户`,
data: null
};
}
async updateStatus(id: string, status: number): Promise<any> {
const user = await this.userModel.findByPk(id);
if (!user) {
return {
code: 404,
message: "用户不存在",
data: null
};
}
await user.update({ status });
return {
code: 200,
message: "状态更新成功",
data: user
};
}
async getRoleList(): Promise<any> {
const roles = await this.roleModel.findAll({
where: { status: 1 },
order: [
["sort_order", "ASC"],
["created_at", "DESC"]
]
});
return {
code: 200,
message: "获取角色列表成功",
data: roles
};
}
private async assignRoles(userId: number, roleIds: number[]): Promise<void> {
await this.userRoleModel.destroy({
where: { userId }
});
const userRoles = roleIds.map((roleId) => ({
userId,
roleId
}));
await this.userRoleModel.bulkCreate(userRoles);
}
}