feat: Initial commit of PDF Tools project

This commit is contained in:
2025-08-25 02:29:48 +08:00
parent af6827cd9e
commit 30180e50a2
48 changed files with 36364 additions and 1 deletions

327
server/routes/users.js Normal file
View 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;