const Router = require('@koa/router');
const router = new Router({ prefix: '/api/user' });
const util = require('../utils/util');
const userService = require('../service/user.service');
const projectService = require('../service/projects.service');
const projectUserService = require('../service/project.user.service');
const pageRoleService = require('../service/pagesRole.service');
const pageService = require('../service/pages.service');
const menuService = require('../service/menu.service');
const publishService = require('../service/publish.service');
const roleService = require('../service/roles.service');
const imgcloudService = require('../service/imgcloud.service');
const md5 = require('md5.js');
const nodemailer = require('nodemailer');
const config = require('../config');
const request = require('../utils/request');
const { Keyv } = require('keyv');
const keyv = new Keyv();
/**
* 用户登录
*/
router.post('/login', async (ctx) => {
const { userName, userPwd, openId } = ctx.request.body;
if (!userName || !userPwd) {
util.fail(ctx, '用户名或密码不能为空');
return;
}
const pwd = new md5().update(userPwd).digest('hex');
const res = await userService.findUser(userName, pwd, openId || userName);
if (!res) {
util.fail(ctx, '用户名或密码错误');
return;
}
if (!res.openId && openId) {
const cacheUser = await keyv.get(openId);
if (cacheUser) {
await userService.bindOpenId({ ...cacheUser, id: res.id });
}
}
console.log("user res信息")
console.log(res)
const token = util.createToken({ userName, userId: res.id, nickName: res.nickName });
userService.updateUserInfo(res.id);
util.success(ctx, {
userId: res.id,
userName,
token,
});
console.log("新的token:"+token)
});
/**
* 微信授权登录
*/
router.post('/wechat', async (ctx) => {
const { code } = ctx.request.body;
if (!code) {
util.fail(ctx, 'code不能为空');
return;
}
const response = await request.get(
`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${config.WECHAT_APP_ID}&secret=${config.WECHAT_APP_SECRET}&code=${code}&grant_type=authorization_code`,
{},
);
const { access_token, openid, unionid, errcode } = JSON.parse(response.data);
if (errcode) {
util.success(ctx, '');
return;
}
const wxUser = await userService.findUser(openid, openid, openid);
if (wxUser) {
userService.updateUserInfo(wxUser.id);
const token = util.createToken({ userName: wxUser.userName, userId: wxUser.id, nickName: wxUser.nickName });
util.success(ctx, {
userId: wxUser.id,
userName: wxUser.userName,
token,
});
return;
}
const res1 = await request.get(`https://api.weixin.qq.com/sns/userinfo?access_token=${access_token}&openid=${openid}`);
const { nickname, headimgurl } = JSON.parse(res1.data);
await keyv.set(
openid,
{
openid,
unionid,
nickname,
headimgurl,
},
3 * 60 * 1000,
);
util.success(ctx, {
openId: openid,
});
});
/**
* 获取用户信息
*/
router.get('/info', async (ctx) => {
const { userId } = util.decodeToken(ctx);
const res = await userService.profile(userId);
util.success(ctx, res);
});
/**
* 获取个人信息
*/
router.get('/profile', async (ctx) => {
const { userId } = util.decodeToken(ctx);
const res = await userService.profile(userId);
util.success(ctx, res);
});
/**
* 用户搜索
*/
router.post('/search', async (ctx) => {
const { keyword } = ctx.request.body;
if (!keyword) {
util.fail(ctx, '关键字不能为空');
return;
}
const res = await userService.search(keyword);
if (!res) {
util.fail(ctx, '当前用户名不存在');
return;
}
util.success(ctx, res);
});
/**
* 用户信息更新
*/
router.post('/update/profile', async (ctx) => {
const { nickName, avatar } = ctx.request.body;
if (!nickName && !avatar) {
util.fail(ctx, '参数异常,请重新提交');
return;
}
const { userId } = util.decodeToken(ctx);
await userService.updateUserInfo(userId, nickName, avatar);
util.success(ctx, '更新成功');
});
/**
* 用户注册 - 发送验证码
*/
router.post('/sendEmail', async (ctx) => {
try {
const { email } = ctx.request.body;
if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
util.fail(ctx, '邮箱不能为空或格式错误');
return;
}
const val = await keyv.get(email);
if (val) {
util.fail(ctx, '验证码已发送,请查收');
return;
}
let transporter = nodemailer.createTransport({
host: config.EMAIL_HOST,
port: config.EMAIL_PORT,
auth: {
user: config.EMAIL_USER, // 你的Gmail地址
pass: config.EMAIL_PASSWORD, // 你的Gmail密码或应用专用密码
},
});
const random = Math.random().toString().slice(2, 7).replace(/^(0)+/, '1');
let mailOptions = {
from: `"Marsview" <${config.EMAIL_USER}>`, // 发送者地址
to: email, // 接收者列表
subject: 'Marsview账号注册', // 主题行
text: '验证码发送', // 纯文字正文
html: `当前验证码为:${random},3分钟内有效。
感谢您体验 Marsview 搭建平台,线上平台不保证数据的稳定性,建议有条件用户,切换到 Marsview 私有化部署服务,您在使用过程中遇到任何问题均联系我。
邮 箱:marsview@163.com
微 信:17611021717`, // HTML正文
};
await transporter.sendMail(mailOptions);
await keyv.set(email, random, 3 * 60 * 1000);
util.success(ctx, '发送成功');
} catch (error) {
util.fail(ctx, error.message);
}
});
/**
* 用户注册
*/
router.post('/regist', async (ctx) => {
const { userName, code, userPwd } = ctx.request.body;
if (!userName || !userPwd) {
util.fail(ctx, '用户名或密码不能为空');
return;
}
if (!code) {
util.fail(ctx, '邮箱验证码不能为空');
return;
}
const val = await keyv.get(userName);
if (!val) {
util.fail(ctx, '验证码已过期');
return;
}
if (val != code) {
util.fail(ctx, '验证码错误');
return;
}
const user = await userService.search(userName);
if (user) {
util.fail(ctx, '当前用户已存在');
return;
}
const nickName = userName.split('@')[0];
const pwd = new md5().update(userPwd).digest('hex');
const res = await userService.create(nickName, userName, pwd);
if (res.affectedRows == 1) {
// 生成用户token
const token = util.createToken({ userName, userId: res.insertId });
util.success(ctx, {
userId: res.id,
userName,
token,
});
} else {
util.fail(ctx, '注册失败,请重试');
}
});
/**
* 忘记密码 - 生成链接
*/
router.post('/password/forget', async (ctx) => {
const { userEmail } = ctx.request.body;
if (!userEmail) {
util.fail(ctx, '邮箱不能为空');
return;
}
const user = await userService.search(userEmail);
if (!user) {
util.fail(ctx, '当前用户不存在');
return;
}
// 生成验证码,保存在redis中,用来验证链接有效期
const random = Math.random().toString().slice(2, 7);
await keyv.set(userEmail, random, 5 * 60 * 1000);
// 生成加密后token
const token = util.createToken({ userEmail });
// 发送邮件
let transporter = nodemailer.createTransport({
host: config.EMAIL_HOST,
port: config.EMAIL_PORT,
auth: {
user: config.EMAIL_USER, // 你的Gmail地址
pass: config.EMAIL_PASSWORD, // 你的Gmail密码或应用专用密码
},
});
let mailOptions = {
from: `"Marsview" <${config.EMAIL_USER}>`, // 发送者地址
to: userEmail, // 接收者列表
subject: 'Marsview密码找回', // 主题行
text: '验证码发送', // 纯文字正文
html: `Hello,${userEmail}!
我们收到了你重置密码的申请,请点击下方按链接行重置,重置密码
链接 3分钟内有效,请尽快操作,如不是你发起的请求,请忽略。`, // HTML正文
};
await transporter.sendMail(mailOptions);
util.success(ctx, '发送成功');
});
/**
* 忘记密码 - 获取账号
*/
router.post('/password/getUserByToken', async (ctx) => {
const { resetToken } = ctx.request.query;
const { userEmail } = util.decodeResetToken(resetToken);
const val = await keyv.get(userEmail);
if (!val) {
util.fail(ctx, '链接已失效,请重新操作');
return;
}
util.success(ctx, userEmail);
});
/**
* 忘记密码 - 重置密码
*/
router.post('/password/reset', async (ctx) => {
const { resetToken, userPwd } = ctx.request.body;
if (!resetToken) {
util.fail(ctx, '重置Token不能为空');
return;
}
if (!userPwd) {
util.fail(ctx, '重置密码不能为空');
return;
}
const { userEmail } = util.decodeResetToken(resetToken);
if (!userEmail) {
util.fail(ctx, 'Token 识别错误,请重新操作');
return;
}
const val = await keyv.get(userEmail);
if (!val) {
util.fail(ctx, '链接已失效,请重新操作');
return;
}
const pwd = new md5().update(userPwd).digest('hex');
await userService.resetPwd(userEmail, pwd);
await keyv.delete(userEmail);
util.success(ctx, '更新成功');
});
/**
* 密码修改
*/
router.post('/password/update', async (ctx) => {
const { oldPwd, userPwd, confirmPwd } = ctx.request.body;
if (!oldPwd || !userPwd || !confirmPwd) {
util.fail(ctx, '密码不能为空');
return;
}
if (userPwd !== confirmPwd) {
util.fail(ctx, '两次密码不一致');
return;
}
const { userName } = util.decodeToken(ctx);
try {
const res = await userService.verifyOldPwd(userName, oldPwd);
if (res) {
const pwd = new md5().update(userPwd).digest('hex');
await userService.resetPwd(userName, pwd);
util.success(ctx, '密码更改成功');
} else {
util.fail(ctx, '原密码输入错误');
}
} catch (error) {
util.fail(ctx, error.message);
}
});
/**
* 用户注销
*/
router.post('/logout', async (ctx) => {
const { userId, userName } = util.decodeToken(ctx);
if (userId == 50) {
util.fail(ctx, '管理员账号不支持注销');
return;
}
// 删除用户所有项目
await projectService.deleteAllProject(userId, userName);
// 删除用户所有关联
await projectUserService.deleteAllProjectUser(userId);
// 删除用户所有页面角色
await pageRoleService.deleteAllPageRole(userId);
// 删除用户所有页面
await pageService.deleteAllPage(userId, userName);
// 删除用户所有菜单
await menuService.deleteAllMenu(userId);
// 删除用户所有发布
await publishService.deleteAllPublish(userId);
// 删除用户所有角色
await roleService.deleteAllRole(userId);
// 删除用户
await userService.deleteUser(userId, userName);
// 删除用户图片
await imgcloudService.deleteAllImg(userId);
util.success(ctx, '注销成功');
});
/**
* 查询子用户列表
*/
router.get('/subUser/list', async (ctx) => {
const { userId } = util.decodeToken(ctx);
const { pageNum, pageSize, keyword } = ctx.request.query;
const { total } = await userService.getSubUsersCount(userId, keyword);
if (total == 0) {
return util.success(ctx, {
list: [],
total: 0,
pageSize: +pageSize || 12,
pageNum: +pageNum || 1,
});
}
const list = await userService.getSubUsersList(userId, pageNum || 1, pageSize || 12, keyword);
util.success(ctx, {
list,
total,
pageSize: +pageSize,
pageNum: +pageNum,
});
});
// 创建子用户
router.post('/subUser/create', async (ctx) => {
const { userName, userPwd } = ctx.request.body;
if (!userName || !userPwd) {
util.fail(ctx, '用户名或密码不能为空');
return;
}
const { userId } = util.decodeToken(ctx);
const user = await userService.search(userName);
if (user) {
util.fail(ctx, '当前用户已存在');
return;
}
const nickName = userName.split('@')[0];
const pwd = new md5().update(userPwd).digest('hex');
const res = await userService.create(nickName, userName, pwd, userId);
if (res.affectedRows == 1) {
util.success(ctx, '注册成功');
} else {
util.fail(ctx, '注册失败,请重试');
}
});
// 删除子用户
router.post('/subUser/delete', async (ctx) => {
const { id } = ctx.request.body;
if (!id) {
util.fail(ctx, '用户ID不能为空');
return;
}
const { userId } = util.decodeToken(ctx);
const res = await userService.deleteSubUser(id, userId);
if (res.affectedRows == 1) {
util.success(ctx, '删除成功');
} else {
util.fail(ctx, '删除失败,请重试');
}
});
//addbywanghao sso 20250512
router.post('/ssoLogin', async (ctx) => {
const { userIdno } = ctx.request.body;
if (!userIdno ) {
util.fail(ctx, 'userIdno不能为空');
return;
}
const res = await userService.findUserSso(userIdno);
if (!res) {
util.fail(ctx, 'userIdno 不存在,暂无权限');
return;
}
console.log("user res信息")
console.log(res)
const token = util.createToken({ userName: res.userName, userId: res.id, nickName: res.nickName });
userService.updateUserInfo(res.id);
util.success(ctx, {
userId: res.id,
userName: res.userName,
token,
});
console.log("sso新的token:"+token)
});
module.exports = router;