feat: Initial commit of PDF Tools project
This commit is contained in:
327
server/routes/users.js
Normal file
327
server/routes/users.js
Normal file
@@ -0,0 +1,327 @@
|
||||
const express = require('express');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const { auth } = require('../middleware/auth');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 模拟用户数据存储(生产环境应使用数据库)
|
||||
const users = new Map();
|
||||
|
||||
// 用户注册
|
||||
router.post('/register', async (req, res) => {
|
||||
try {
|
||||
const { email, username, password } = req.body;
|
||||
|
||||
// 验证必要字段
|
||||
if (!email || !username || !password) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请提供邮箱、用户名和密码'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查邮箱格式
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '邮箱格式不正确'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查密码强度
|
||||
if (password.length < 6) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '密码长度至少6位'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查用户是否已存在
|
||||
for (const user of users.values()) {
|
||||
if (user.email === email) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '邮箱已被注册'
|
||||
});
|
||||
}
|
||||
if (user.username === username) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '用户名已被使用'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 加密密码
|
||||
const hashedPassword = await bcrypt.hash(password, 12);
|
||||
|
||||
// 创建用户
|
||||
const user = {
|
||||
userId: Date.now().toString(),
|
||||
email,
|
||||
username,
|
||||
password: hashedPassword,
|
||||
createdAt: new Date(),
|
||||
lastLoginAt: null,
|
||||
settings: {
|
||||
defaultOutputFormat: 'docx',
|
||||
imageQuality: 'medium',
|
||||
autoDownload: true,
|
||||
language: 'zh-CN'
|
||||
}
|
||||
};
|
||||
|
||||
users.set(user.userId, user);
|
||||
|
||||
// 生成JWT令牌
|
||||
const token = jwt.sign(
|
||||
{ userId: user.userId, email: user.email },
|
||||
process.env.JWT_SECRET,
|
||||
{ expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
|
||||
);
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: '注册成功',
|
||||
data: {
|
||||
user: {
|
||||
userId: user.userId,
|
||||
email: user.email,
|
||||
username: user.username,
|
||||
createdAt: user.createdAt
|
||||
},
|
||||
token
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('用户注册错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '注册失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 用户登录
|
||||
router.post('/login', async (req, res) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请提供邮箱和密码'
|
||||
});
|
||||
}
|
||||
|
||||
// 查找用户
|
||||
let foundUser = null;
|
||||
for (const user of users.values()) {
|
||||
if (user.email === email) {
|
||||
foundUser = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundUser) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '邮箱或密码错误'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
const isPasswordValid = await bcrypt.compare(password, foundUser.password);
|
||||
if (!isPasswordValid) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '邮箱或密码错误'
|
||||
});
|
||||
}
|
||||
|
||||
// 更新最后登录时间
|
||||
foundUser.lastLoginAt = new Date();
|
||||
users.set(foundUser.userId, foundUser);
|
||||
|
||||
// 生成JWT令牌
|
||||
const token = jwt.sign(
|
||||
{ userId: foundUser.userId, email: foundUser.email },
|
||||
process.env.JWT_SECRET,
|
||||
{ expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '登录成功',
|
||||
data: {
|
||||
user: {
|
||||
userId: foundUser.userId,
|
||||
email: foundUser.email,
|
||||
username: foundUser.username,
|
||||
lastLoginAt: foundUser.lastLoginAt
|
||||
},
|
||||
token
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('用户登录错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '登录失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取用户信息
|
||||
router.get('/profile', auth, async (req, res) => {
|
||||
try {
|
||||
const user = users.get(req.user.userId);
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '用户未找到'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
userId: user.userId,
|
||||
email: user.email,
|
||||
username: user.username,
|
||||
createdAt: user.createdAt,
|
||||
lastLoginAt: user.lastLoginAt,
|
||||
settings: user.settings
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取用户信息错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取用户信息失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 更新用户设置
|
||||
router.put('/settings', auth, async (req, res) => {
|
||||
try {
|
||||
const user = users.get(req.user.userId);
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '用户未找到'
|
||||
});
|
||||
}
|
||||
|
||||
const allowedSettings = [
|
||||
'defaultOutputFormat',
|
||||
'imageQuality',
|
||||
'autoDownload',
|
||||
'language',
|
||||
'autoDelete',
|
||||
'deleteDelay',
|
||||
'maxConcurrentTasks',
|
||||
'conversionTimeout'
|
||||
];
|
||||
|
||||
const updatedSettings = { ...user.settings };
|
||||
|
||||
for (const [key, value] of Object.entries(req.body)) {
|
||||
if (allowedSettings.includes(key)) {
|
||||
updatedSettings[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
user.settings = updatedSettings;
|
||||
users.set(user.userId, user);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '设置更新成功',
|
||||
data: {
|
||||
settings: user.settings
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('更新用户设置错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '更新设置失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取转换历史
|
||||
router.get('/history', auth, async (req, res) => {
|
||||
try {
|
||||
const { page = 1, limit = 10, status } = req.query;
|
||||
|
||||
// 模拟历史数据
|
||||
const mockHistory = [
|
||||
{
|
||||
taskId: 'task-1',
|
||||
fileName: '项目报告.pdf',
|
||||
outputFormat: 'docx',
|
||||
status: 'completed',
|
||||
createdAt: new Date(Date.now() - 86400000), // 1天前
|
||||
fileSize: '2.5MB'
|
||||
},
|
||||
{
|
||||
taskId: 'task-2',
|
||||
fileName: '用户手册.pdf',
|
||||
outputFormat: 'html',
|
||||
status: 'completed',
|
||||
createdAt: new Date(Date.now() - 172800000), // 2天前
|
||||
fileSize: '1.8MB'
|
||||
},
|
||||
{
|
||||
taskId: 'task-3',
|
||||
fileName: '技术文档.pdf',
|
||||
outputFormat: 'txt',
|
||||
status: 'failed',
|
||||
createdAt: new Date(Date.now() - 259200000), // 3天前
|
||||
fileSize: '3.2MB'
|
||||
}
|
||||
];
|
||||
|
||||
let filteredHistory = mockHistory;
|
||||
if (status && status !== 'all') {
|
||||
filteredHistory = mockHistory.filter(item => item.status === status);
|
||||
}
|
||||
|
||||
const startIndex = (page - 1) * limit;
|
||||
const endIndex = startIndex + parseInt(limit);
|
||||
const paginatedHistory = filteredHistory.slice(startIndex, endIndex);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
history: paginatedHistory,
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total: filteredHistory.length,
|
||||
pages: Math.ceil(filteredHistory.length / limit)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取转换历史错误:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取转换历史失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user