feat: 添加登录、用户管理和操作日志功能

This commit is contained in:
pipipigua 2024-10-31 20:50:02 +08:00
parent f31bf052a1
commit e45c367e15
12 changed files with 2559 additions and 1418 deletions

2
.env
View File

@ -1,5 +1,5 @@
# Port
PORT=3000
PORT=3001
# JWT_SECRET
JWT_SECRET = '708DD1DC5BC5A169'

BIN
data/teachers.xlsx Normal file

Binary file not shown.

View File

@ -33,5 +33,9 @@
"typescript": "^4.8.4",
"winston": "^3.8.2"
},
"repository": "https://github.com/xiaoxian521/pure-admin-backend"
"repository": "https://github.com/xiaoxian521/pure-admin-backend",
"dependencies": {
"@types/xlsx": "^0.0.36",
"xlsx": "^0.18.5"
}
}

2984
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@
window.onload = function () {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "http://localhost:3000/swagger.json",
url: "http://localhost:3001/swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [

View File

@ -15,7 +15,7 @@ export default {
options: {
swaggerDefinition: {
info: {
description: "pure-admin官方后端",
description: "HOUKONG",
title: "Swagger",
version: require("../../package.json").version,
},
@ -51,10 +51,11 @@ export default {
concurrency: parseInt(process.env.AGENDA_CONCURRENCY, 10),
},
mysql: {
host: "localhost",
host: "43.156.106.134",
charset: "utf8_general_ci",
user: "root",
password: "123456789",
user: "houkong",
password: "P@55w0rd",
database: "houkong",
},
mongodb: {},
sqlite: {},

View File

@ -1,5 +1,61 @@
/** 创建用户表 */
const user =
"CREATE TABLE if not EXISTS users(id int PRIMARY key auto_increment,username varchar(32),password varchar(32),time DATETIME)";
const user = `
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(100) NOT NULL COMMENT '用户名',
userid VARCHAR(100) NOT NULL COMMENT '企业微信用户ID',
name VARCHAR(100) NOT NULL COMMENT '用户名称',
password VARCHAR(100) NOT NULL COMMENT '密码',
department VARCHAR(255) COMMENT '部门',
position VARCHAR(100) COMMENT '职位',
mobile VARCHAR(20) COMMENT '手机号',
gender VARCHAR(10) COMMENT '性别',
email VARCHAR(100) COMMENT '邮箱',
avatar VARCHAR(255) COMMENT '头像URL',
status TINYINT DEFAULT 1 COMMENT '状态 1:启用 0:禁用',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'
`;
/** 创建角色表 */
const role = `
CREATE TABLE IF NOT EXISTS roles (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL COMMENT '角色名称',
code VARCHAR(50) NOT NULL COMMENT '角色编码',
status TINYINT DEFAULT 1 COMMENT '状态 1:启用 0:禁用',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY idx_code (code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'
`;
/** 创建用户角色关联表 */
const userRole = `
CREATE TABLE IF NOT EXISTS user_roles (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL COMMENT '用户ID',
role_id INT NOT NULL COMMENT '角色ID',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY idx_user_id (user_id),
KEY idx_role_id (role_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联表'
`;
/** 创建操作日志表 */
const operationLogs = `
CREATE TABLE IF NOT EXISTS operation_logs (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
username VARCHAR(255),
action VARCHAR(255) NOT NULL COMMENT '操作类型:新增、修改、删除等',
module VARCHAR(255) NOT NULL COMMENT '操作模块:用户管理、角色管理等',
description TEXT COMMENT '操作详细描述',
ip VARCHAR(50) COMMENT '操作IP',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表'
`;
export { operationLogs, role, user, userRole };
export { user };

139
src/router/excel.ts Normal file
View File

@ -0,0 +1,139 @@
import { createHash } from "crypto";
import { Request, Response } from "express";
import * as path from 'path';
import { promisify } from 'util';
import * as xlsx from 'xlsx';
import { connection } from "../utils/mysql";
const query = promisify(connection.query).bind(connection);
const beginTransaction = promisify(connection.beginTransaction).bind(connection);
const commit = promisify(connection.commit).bind(connection);
const rollback = promisify(connection.rollback).bind(connection);
export async function importUsersFromLocalExcel(req: Request, res: Response) {
try {
const filePath = path.join(__dirname, '../../data/teachers.xlsx');
console.log('Excel文件路径:', filePath);
const workbook = xlsx.readFile(filePath);
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
// 使用之前成功的格式
const rows = xlsx.utils.sheet_to_json<{
A: number; // 序号
B: string; // 姓名
C: string; // 工号
D: string; // 密码
E: string; // 角色
F: string; // 部门
}>(worksheet, {
range: 1, // 从第二行开始读取
header: 'A' // 使用字母作为键
});
console.log('读取到的数据行数:', rows.length);
console.log('第一行数据示例:', rows[0]);
await beginTransaction();
try {
let successCount = 0;
let errorCount = 0;
const errors: string[] = [];
// 获取默认教师角色ID
const DEFAULT_ROLE_ID = 2; // 教師角色ID
const roleMap = new Map<string, number>();
for (const row of rows) {
try {
// 验证必要字段
if (!row.B || !row.C || !row.D) {
throw new Error(`数据不完整: 姓名=${row.B}, 工号=${row.C}, 密码=${row.D}`);
}
// 获取角色ID
let roleId = DEFAULT_ROLE_ID; // 默认使用教师角色
if (row.E) {
if (!roleMap.has(row.E)) {
const existingRoles: any[] = await query(
"SELECT id FROM roles WHERE name = ?",
[row.E]
);
if (existingRoles.length > 0) {
roleMap.set(row.E, existingRoles[0].id);
roleId = existingRoles[0].id;
} else {
console.log(`找不到角色 ${row.E},使用默认教师角色`);
roleMap.set(row.E, DEFAULT_ROLE_ID);
}
} else {
roleId = roleMap.get(row.E)!;
}
}
const hashedPassword = createHash("md5")
.update(row.D)
.digest("hex");
// 插入用户
const result: any = await query(
`INSERT INTO users (
username, name, password, department,
position, status
) VALUES (?, ?, ?, ?, ?, 1)`,
[
row.C, // username (工号)
row.B, // name (姓名)
hashedPassword, // password
row.F || '', // department
row.E || '教師', // position
]
);
// 插入用户角色关联
await query(
"INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)",
[result.insertId, roleId]
);
successCount++;
} catch (error) {
console.error('处理用户错误:', error);
errorCount++;
errors.push(`${successCount + errorCount}: ${error.message}`);
}
}
await commit();
console.log('事务提交成功');
res.json({
success: true,
data: {
message: "导入完成",
stats: {
total: rows.length,
success: successCount,
error: errorCount
},
errors: errors
}
});
} catch (error) {
console.error('处理数据错误:', error);
await rollback();
throw error;
}
} catch (error) {
console.error('导入用户错误:', error);
res.json({
success: false,
data: {
message: "导入失败",
error: error.message
}
});
}
}

View File

@ -1,14 +1,15 @@
import * as fs from "fs";
import secret from "../config";
import * as mysql from "mysql2";
import * as jwt from "jsonwebtoken";
import { createHash } from "crypto";
import { Request, Response } from "express";
import * as fs from "fs";
import * as jwt from "jsonwebtoken";
import * as mysql from "mysql2";
import { OkPacket } from 'mysql2';
import { createMathExpr } from "svg-captcha";
import secret from "../config";
import Logger from "../loaders/logger";
import { Message } from "../utils/enums";
import getFormatDate from "../utils/date";
import { connection } from "../utils/mysql";
import { Request, Response } from "express";
import { createMathExpr } from "svg-captcha";
import { logOperation, ModuleType, OperationType } from "../utils/operationLog";
const utils = require("@pureadmin/utils");
@ -56,78 +57,153 @@ let expiresIn = 60000;
*/
const login = async (req: Request, res: Response) => {
// const { username, password, verify } = req.body;
// if (generateVerify !== verify) return res.json({
// success: false,
// data: {
// message: Message[0];
// }
// })
const { username, password } = req.body;
let sql: string =
"select * from users where username=" + "'" + username + "'";
connection.query(sql, async function (err, data: any) {
if (data.length == 0) {
console.log('Login attempt:', { username, password });
let sql = `
SELECT u.*, GROUP_CONCAT(r.code) as roles
FROM users u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN roles r ON ur.role_id = r.id
WHERE u.username = ? AND u.status = 1
GROUP BY u.id
`;
connection.query(sql, [username], async function (err, data: any) {
// console.log('Query result:', { err, data });
if (err) {
// Logger.error(err);
return res.json({
success: false,
data: { message: "数据库查询错误" }
});
}
if (data.length === 0) {
// 记录登录失败日志
logOperation({
userId: 0,
username: username,
action: OperationType.LOGIN,
module: ModuleType.AUTH,
description: `用户登录失败:用户不存在 (${username})`,
ip: req.ip || ''
});
await res.json({
success: false,
data: { message: Message[1] },
data: { message: Message[1] } // 用户不存在
});
} else {
if (
createHash("md5").update(password).digest("hex") == data[0].password
) {
const user = data[0];
// 验证密码
const hashedPassword = createHash("md5").update(password).digest("hex");
if (hashedPassword !== user.password) {
// 记录登录失败日志
logOperation({
userId: 0,
username: username,
action: OperationType.LOGIN,
module: ModuleType.AUTH,
description: `用户登录失败:密码错误 (${username})`,
ip: req.ip || ''
});
return res.json({
success: false,
data: { message: "密码错误" }
});
}
const accessToken = jwt.sign(
{
accountId: data[0].id,
id: user.id, // 用户ID
username: user.username, // 用户名
name: user.name
},
secret.jwtSecret,
{ expiresIn }
);
if (username === "admin") {
// 记录登录成功日志
logOperation({
userId: user.id,
username: user.username,
action: OperationType.LOGIN,
module: ModuleType.AUTH,
description: `用户登录成功 (${username})`,
ip: req.ip || ''
});
await res.json({
success: true,
data: {
message: Message[2],
username,
// 这里模拟角色,根据自己需求修改
roles: ["admin"],
username: user.name, // 返回 name 字段作为用户名
userid: user.userid, // 返回 userid
roles: user.roles ? user.roles.split(',') : [],
accessToken,
// 这里模拟刷新token根据自己需求修改
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
expires: new Date(new Date()).getTime() + expiresIn,
// 这个标识是真实后端返回的接口,只是为了演示
pureAdminBackend:
"这个标识是pure-admin-backend真实后端返回的接口只是为了演示",
},
});
} else {
await res.json({
success: true,
data: {
message: Message[2],
username,
// 这里模拟角色,根据自己需求修改
roles: ["common"],
accessToken,
// 这里模拟刷新token根据自己需求修改
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
expires: new Date(new Date()).getTime() + expiresIn,
// 这个标识是真实后端返回的接口,只是为了演示
pureAdminBackend:
"这个标识是pure-admin-backend真实后端返回的接口只是为了演示",
},
});
department: user.department,
position: user.position,
mobile: user.mobile,
email: user.email,
avatar: user.avatar
}
} else {
await res.json({
success: false,
data: { message: Message[3] },
});
}
}
});
};
// 刷新 token
const refreshToken = async (req: Request, res: Response) => {
const { refreshToken } = req.body;
try {
// 验证 refresh token
const decoded = jwt.verify(refreshToken, secret.jwtSecret) as any;
// 查询用户是否还有效
const sql = `SELECT * FROM users WHERE id = ? AND status = 1`;
connection.query(sql, [decoded.id], async function (err, data: any) {
if (err || data.length === 0) {
return res.json({
success: false,
data: { message: "用户不存在或已禁用" }
});
}
const user = data[0];
// 生成新的 access token
const accessToken = jwt.sign(
{
id: user.id,
username: user.username,
name: user.name
},
secret.jwtSecret,
{ expiresIn }
);
res.json({
success: true,
data: {
accessToken,
refreshToken: accessToken, // 简单起见,使用相同的 token
expires: new Date(new Date()).getTime() + expiresIn
}
});
});
} catch (error) {
res.json({
success: false,
data: {
message: "refresh token 无效"
}
});
}
};
// /**
// * @typedef Register
// * @property {string} username.required - 用户名
@ -153,58 +229,159 @@ const login = async (req: Request, res: Response) => {
* @headers {string} 200.X-Expires-After
* @security JWT
*/
const register = async (req: Request, res: Response) => {
// const { username, password, verify } = req.body;
const { username, password } = req.body;
// if (generateVerify !== verify)
// return res.json({
// success: false,
// data: { message: Message[0] },
// });
if (password.length < 6)
const userData = req.body;
if (userData.password.length < 6)
return res.json({
success: false,
data: { message: Message[4] },
});
let sql: string =
"select * from users where username=" + "'" + username + "'";
connection.query(sql, async (err, data: any) => {
let sql = "SELECT * FROM users WHERE username = ?";
connection.query(sql, [userData.username], async (err, data: any) => {
if (err) {
Logger.error(err);
return res.json({
success: false,
data: { message: "数据库查询错误" }
});
}
if (data.length > 0) {
await res.json({
success: false,
data: { message: Message[5] },
});
} else {
let time = await getFormatDate();
let sql: string =
"insert into users (username,password,time) value(" +
"'" +
username +
"'" +
"," +
"'" +
createHash("md5").update(password).digest("hex") +
"'" +
"," +
"'" +
time +
"'" +
")";
connection.query(sql, async function (err) {
const insertUserSql = `
INSERT INTO users (
username,
userid,
name,
password,
department,
position,
mobile,
gender,
email,
avatar,
status,
created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, NOW())
`;
const values = [
userData.username,
userData.userid || null,
userData.name || userData.username,
createHash("md5").update(userData.password).digest("hex"),
userData.department || null,
userData.position || null,
userData.mobile || null,
userData.gender || null,
userData.email || null,
userData.avatar || null
];
connection.query(insertUserSql, values, async function (err, result: OkPacket) { // 指定 result 类型为 OkPacket
if (err) {
Logger.error(err);
} else {
await res.json({
return res.json({
success: false,
data: { message: "注册失败" }
});
}
// 处理角色关联
if (userData.roles && userData.roles.length > 0) {
const userId = result.insertId; // 现在 TypeScript 知道 result 有 insertId 属性
const insertRolesSql = `
INSERT INTO user_roles (user_id, role_id)
SELECT ?, id FROM roles WHERE code IN (?)
`;
connection.query(insertRolesSql, [userId, userData.roles], function(err) {
if (err) {
Logger.error(err);
return res.json({
success: false,
data: { message: "添加用户角色失败" }
});
}
res.json({
success: true,
data: { message: Message[6] },
data: { message: Message[6] }
});
});
} else {
res.json({
success: true,
data: { message: Message[6] }
});
}
});
}
});
};
// 添加获取用户列表的处理函数
const getUserList = async (req: Request, res: Response) => {
try {
const authHeader = req.get("Authorization");
// console.log('收到的 Authorization header:', authHeader); // 添加日志看看请求头
if (!authHeader) {
return res.status(401).json({
success: false,
data: { message: "未登录" }
});
}
// 直接查询用户列表,不做 token 验证
const sql = `
SELECT
u.*,
GROUP_CONCAT(r.code) as roles
FROM users u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN roles r ON ur.role_id = r.id
GROUP BY u.id
`;
connection.query(sql, (err, data: any) => {
if (err) {
// Logger.error('查询用户列表错误:', err);
return res.json({
success: false,
data: { message: "获取用户列表失败" }
});
}
// console.log('查询到的用户数据:', data); // 添加日志看看查询结果
const users = data.map(user => ({
...user,
roles: user.roles ? user.roles.split(',') : []
}));
res.json({
success: true,
data: {
users
}
});
});
} catch (error) {
// console.error('获取用户列表错误:', error);
return res.status(401).json({
success: false,
data: { message: "获取用户列表失败" }
});
}
};
/**
* @typedef UpdateList
* @property {string} username.required - - eg: admin
@ -223,37 +400,135 @@ const register = async (req: Request, res: Response) => {
const updateList = async (req: Request, res: Response) => {
const { id } = req.params;
const { username } = req.body;
let payload = null;
const userData = req.body; // 获取所有更新字段
try {
// 验证 token
const authorizationHeader = req.get("Authorization") as string;
const accessToken = authorizationHeader.substr("Bearer ".length);
payload = jwt.verify(accessToken, secret.jwtSecret);
} catch (error) {
return res.status(401).end();
const payload = jwt.verify(accessToken, secret.jwtSecret);
// 构建更新字段
const updateFields = [];
const updateValues = [];
// 检查并添加每个可更新字段
if (userData.username) {
updateFields.push("username = ?");
updateValues.push(userData.username);
}
let modifySql: string = "UPDATE users SET username = ? WHERE id = ?";
let sql: string = "select * from users where id=" + id;
connection.query(sql, function (err, data) {
connection.query(sql, function (err) {
if (userData.name) {
updateFields.push("name = ?");
updateValues.push(userData.name);
}
if (userData.userid) {
updateFields.push("userid = ?");
updateValues.push(userData.userid);
}
if (userData.department) {
updateFields.push("department = ?");
updateValues.push(userData.department);
}
if (userData.position) {
updateFields.push("position = ?");
updateValues.push(userData.position);
}
if (userData.mobile) {
updateFields.push("mobile = ?");
updateValues.push(userData.mobile);
}
if (userData.gender) {
updateFields.push("gender = ?");
updateValues.push(userData.gender);
}
if (userData.email) {
updateFields.push("email = ?");
updateValues.push(userData.email);
}
if (userData.avatar) {
updateFields.push("avatar = ?");
updateValues.push(userData.avatar);
}
if (userData.status !== undefined) {
updateFields.push("status = ?");
updateValues.push(userData.status);
}
// 添加 ID 到 values 数组
updateValues.push(id);
const updateSql = `
UPDATE users
SET ${updateFields.join(", ")}
WHERE id = ?
`;
connection.query(updateSql, updateValues, async function(err) {
if (err) {
Logger.error(err);
} else {
let modifyParams: string[] = [username, id];
// 改
connection.query(modifySql, modifyParams, async function (err, result) {
return res.json({
success: false,
data: { message: "更新用户失败" }
});
}
// 直接使用更新的用户信息记录日志
logOperation({
userId: Number(id), // 转换为数字
username: userData.username || userData.name, // 使用更新的用户信息
action: OperationType.UPDATE,
module: ModuleType.USER,
description: `更新用户信息:ID=${id}, 字段:${updateFields.join(', ')}`,
ip: req.ip || ''
});
// 如果有角色信息,更新用户角色
if (userData.roles && userData.roles.length > 0) {
// 先删除原有角色
const deleteRolesSql = "DELETE FROM user_roles WHERE user_id = ?";
connection.query(deleteRolesSql, [id], async function(err) {
if (err) {
Logger.error(err);
} else {
await res.json({
return res.json({
success: false,
data: { message: "更新用户角色失败" }
});
}
// 插入新角色
const insertRolesSql = `
INSERT INTO user_roles (user_id, role_id)
SELECT ?, id FROM roles WHERE code IN (?)
`;
connection.query(insertRolesSql, [id, userData.roles], function(err) {
if (err) {
Logger.error(err);
return res.json({
success: false,
data: { message: "更新用户角色失败" }
});
}
res.json({
success: true,
data: { message: Message[7] },
data: { message: Message[7] }
});
});
});
} else {
res.json({
success: true,
data: { message: Message[7] }
});
}
});
} catch (error) {
Logger.error(error);
return res.status(401).json({
success: false,
data: { message: "未授权" }
});
}
});
});
};
/**
@ -273,27 +548,126 @@ const updateList = async (req: Request, res: Response) => {
const deleteList = async (req: Request, res: Response) => {
const { id } = req.params;
let payload = null;
try {
// 验证 token
const authorizationHeader = req.get("Authorization") as string;
const accessToken = authorizationHeader.substr("Bearer ".length);
payload = jwt.verify(accessToken, secret.jwtSecret);
} catch (error) {
return res.status(401).end();
}
let sql: string = "DELETE FROM users where id=" + "'" + id + "'";
connection.query(sql, async function (err, data) {
if (err) {
console.log(err);
} else {
await res.json({
success: true,
data: { message: Message[8] },
});
}
});
};
const payload = jwt.verify(accessToken, secret.jwtSecret);
// 开始事务
connection.beginTransaction(function(err) {
if (err) {
Logger.error(err);
return res.json({
success: false,
data: { message: "删除失败" }
});
}
// 先删除用户角色关联
const deleteRolesSql = "DELETE FROM user_roles WHERE user_id = ?";
connection.query(deleteRolesSql, [id], function(err) {
if (err) {
return connection.rollback(function() {
Logger.error(err);
res.json({
success: false,
data: { message: "删除用户角色失败" }
});
});
}
// 删除用户
const deleteUserSql = "DELETE FROM users WHERE id = ?";
connection.query(deleteUserSql, [id], function(err) {
if (err) {
return connection.rollback(function() {
Logger.error(err);
res.json({
success: false,
data: { message: "删除用户失败" }
});
});
}
// 提交事务
connection.commit(function(err) {
if (err) {
return connection.rollback(function() {
Logger.error(err);
res.json({
success: false,
data: { message: "删除失败" }
});
});
}
res.json({
success: true,
data: { message: Message[8] }
});
});
});
});
});
} catch (error) {
Logger.error(error);
return res.status(401).json({
success: false,
data: { message: "未授权" }
});
}
};
/**
* @route GET /api/roles
* @summary
* @group
* @returns {object} 200 -
* @security JWT
*/
const getRoleList = async (req: Request, res: Response) => {
try {
const authorizationHeader = req.get("Authorization");
const accessToken = authorizationHeader.replace("Bearer ", "");
const decoded = jwt.verify(accessToken, secret.jwtSecret);
console.log('开始查询角色数据'); // 添加日志
// 查询所有角色
const sql = `
SELECT r.id, r.name, r.code, r.status, r.created_at
FROM roles r
WHERE r.status = 1
ORDER BY r.id ASC
`;
console.log('执行 SQL:', sql); // 添加日志
connection.query(sql, function(err, roles) {
if (err) {
console.error('数据库查询错误:', err);
return res.json({
success: false,
data: { message: "获取角色列表失败" }
});
}
console.log('查询到的角色:', roles); // 添加日志
// 立即返回结果
return res.json({
success: true,
data: { roles }
});
});
} catch (error) {
console.error('获取角色列表错误:', error);
return res.status(401).json({
success: false,
data: { message: "未授权" }
});
}
};
/**
* @typedef SearchPage
* @property {integer} page.required - - eg: 1
@ -457,14 +831,38 @@ const captcha = async (req: Request, res: Response) => {
res.type("svg"); // 响应的类型
res.json({ success: true, data: { text: create.text, svg: create.data } });
};
export {
login,
register,
updateList,
deleteList,
searchPage,
searchVague,
upload,
captcha,
// 添加获取动态路由的处理函数
const getAsyncRoutes = async (req: Request, res: Response) => {
// 这里返回你的动态路由配置
res.json({
success: true,
data: {
// 示例路由配置
routes: [
{
path: "/permission",
meta: {
title: "权限管理",
icon: "lollipop"
},
children: [
{
path: "/permission/page/index",
name: "PermissionPage",
meta: {
title: "页面权限",
roles: ["admin"]
}
}
]
}
// ... 其他路由配置
]
}
});
};
export {
captcha, deleteList, getAsyncRoutes, getRoleList, getUserList, login, refreshToken, register, searchPage,
searchVague, updateList, upload
};

View File

@ -1,25 +1,29 @@
import app from "./app";
// import * as open from "open";
import config from "./config";
import * as dayjs from "dayjs";
import * as multer from "multer";
import { user } from "./models/mysql";
import config from "./config";
import Logger from "./loaders/logger";
import { queryTable } from "./utils/mysql";
import { importUsersFromLocalExcel } from "./router/excel";
import { getRoleList, getUserList } from "./router/http";
// import { queryTable } from "./utils/mysql";
const expressSwagger = require("express-swagger-generator")(app);
expressSwagger(config.options);
queryTable(user);
// 初始化数据库表
// queryTable(user);
// queryTable(role);
// queryTable(userRole);
// queryTable(operationLogs);
import {
captcha,
deleteList,
login,
register,
updateList,
deleteList,
searchPage,
searchVague,
updateList,
upload,
captcha,
} from "./router/http";
app.post("/login", (req, res) => {
@ -46,11 +50,27 @@ app.post("/searchVague", (req, res) => {
searchVague(req, res);
});
// 添加获取用户列表路由
app.get("/user/list", (req, res) => {
getUserList(req, res);
});
// 新建存放临时文件的文件夹
const upload_tmp = multer({ dest: "upload_tmp/" });
app.post("/upload", upload_tmp.any(), (req, res) => {
upload(req, res);
});
// 添加获取角色列表路由
app.get("/roles", (req, res) => { // 注意这里的路径
console.log("收到获取角色列表请求"); // 添加日志
getRoleList(req, res);
});
// Excel导入用户路由
app.post("/api/excel/import-local", (req, res) => {
importUsersFromLocalExcel(req, res);
});
app.get("/captcha", (req, res) => {
captcha(req, res);

View File

@ -4,7 +4,7 @@ import Logger from "../loaders/logger";
/** user数据库 */
export const connection = mysql.createConnection(
Object.assign({ database: "user" }, mysqlConfig.mysql)
Object.assign({ database: "houkong" }, mysqlConfig.mysql)
);
export function queryTable(s: string): void {

51
src/utils/operationLog.ts Normal file
View File

@ -0,0 +1,51 @@
import { connection } from "./mysql";
import Logger from "../loaders/logger";
// 定义操作类型
export enum OperationType {
CREATE = 'CREATE',
UPDATE = 'UPDATE',
DELETE = 'DELETE',
QUERY = 'QUERY',
LOGIN = 'LOGIN',
UPLOAD = 'UPLOAD'
}
// 定义模块类型
export enum ModuleType {
USER = '用户管理',
ROLE = '角色管理',
FILE = '文件管理',
AUTH = '认证管理'
}
// 记录操作日志
export const logOperation = (params: {
userId: number;
username: string;
action: OperationType;
module: ModuleType;
description: string;
ip: string;
}) => {
const sql = `
INSERT INTO operation_logs
(user_id, username, action, module, description, ip)
VALUES (?, ?, ?, ?, ?, ?)
`;
const values = [
params.userId,
params.username,
params.action,
params.module,
params.description,
params.ip
];
connection.query(sql, values, (err) => {
if (err) {
Logger.error('记录操作日志失败:', err);
}
});
};