110 lines
3.5 KiB
JavaScript
Executable File
110 lines
3.5 KiB
JavaScript
Executable File
const express = require('express');
|
|
const { getDb } = require('../db');
|
|
const { createUserNameResolver, normalizeUserKey } = require('../utils/accounting');
|
|
|
|
const router = express.Router();
|
|
|
|
function getUsers(db) {
|
|
return db.all('SELECT * FROM users ORDER BY sort_order, id');
|
|
}
|
|
|
|
function findNormalizedUserConflict(users, targetName, excludedId = null) {
|
|
const normalizedTarget = normalizeUserKey(targetName);
|
|
return users.find(
|
|
(user) => user.id !== excludedId && normalizeUserKey(user.name) === normalizedTarget
|
|
);
|
|
}
|
|
|
|
function getRelatedRecordAliases(db, userName) {
|
|
const users = getUsers(db).map((user) => ({ name: user.name }));
|
|
const resolveUserName = createUserNameResolver(users);
|
|
const aliases = db.all('SELECT DISTINCT user FROM records WHERE user IS NOT NULL AND user != ""');
|
|
|
|
return aliases
|
|
.map((row) => row.user)
|
|
.filter((name) => resolveUserName(name, '') === userName);
|
|
}
|
|
|
|
router.get('/', (req, res) => {
|
|
res.json(getUsers(getDb()));
|
|
});
|
|
|
|
router.post('/', (req, res) => {
|
|
const db = getDb();
|
|
const name = String(req.body.name ?? '').trim();
|
|
if (!name) {
|
|
return res.status(400).json({ error: '用户名为必填项' });
|
|
}
|
|
|
|
const users = getUsers(db);
|
|
const conflict = findNormalizedUserConflict(users, name);
|
|
if (conflict) {
|
|
return res.status(400).json({ error: '用户名已存在,或与现有用户名仅空格不同' });
|
|
}
|
|
|
|
const maxOrder = db.get('SELECT MAX(sort_order) AS max_order FROM users')?.max_order || 0;
|
|
const result = db.run('INSERT INTO users (name, sort_order) VALUES (?, ?)', name, maxOrder + 1);
|
|
db.run('INSERT INTO user_balance_settings (user_name, initial_balance) VALUES (?, 0)', name);
|
|
|
|
res.status(201).json(db.get('SELECT * FROM users WHERE id = ?', result.lastInsertRowid));
|
|
});
|
|
|
|
router.put('/:id', (req, res) => {
|
|
const db = getDb();
|
|
const id = Number.parseInt(req.params.id, 10);
|
|
const name = String(req.body.name ?? '').trim();
|
|
|
|
if (!name) {
|
|
return res.status(400).json({ error: '用户名为必填项' });
|
|
}
|
|
|
|
const user = db.get('SELECT * FROM users WHERE id = ?', id);
|
|
if (!user) {
|
|
return res.status(404).json({ error: '用户不存在' });
|
|
}
|
|
|
|
const users = getUsers(db);
|
|
const conflict = findNormalizedUserConflict(users, name, id);
|
|
if (conflict) {
|
|
return res.status(400).json({ error: '用户名已存在,或与现有用户名仅空格不同' });
|
|
}
|
|
|
|
const aliases = getRelatedRecordAliases(db, user.name);
|
|
|
|
db.run('UPDATE users SET name = ? WHERE id = ?', name, id);
|
|
db.run('UPDATE user_balance_settings SET user_name = ? WHERE user_name = ?', name, user.name);
|
|
|
|
aliases.forEach((alias) => {
|
|
db.run('UPDATE records SET user = ? WHERE user = ?', name, alias);
|
|
});
|
|
|
|
res.json(db.get('SELECT * FROM users WHERE id = ?', id));
|
|
});
|
|
|
|
router.delete('/:id', (req, res) => {
|
|
const db = getDb();
|
|
const id = Number.parseInt(req.params.id, 10);
|
|
const user = db.get('SELECT * FROM users WHERE id = ?', id);
|
|
|
|
if (!user) {
|
|
return res.status(404).json({ error: '用户不存在' });
|
|
}
|
|
|
|
const aliases = getRelatedRecordAliases(db, user.name);
|
|
const recordCount = aliases.reduce((total, alias) => {
|
|
const count = db.get('SELECT COUNT(*) AS count FROM records WHERE user = ?', alias)?.count || 0;
|
|
return total + count;
|
|
}, 0);
|
|
|
|
if (recordCount > 0) {
|
|
return res.status(400).json({ error: `该用户还有 ${recordCount} 条记录,无法删除` });
|
|
}
|
|
|
|
db.run('DELETE FROM users WHERE id = ?', id);
|
|
db.run('DELETE FROM user_balance_settings WHERE user_name = ?', user.name);
|
|
|
|
res.json({ message: '删除成功' });
|
|
});
|
|
|
|
module.exports = router;
|