- 批量解析:移除义工号强制纯数字校验(原 volunteerLooksLikeNo 逻辑错误导致 VOL-003、2024-A 等全部置空);改为列数驱动:3列时智能探测是否工作组命中,4+列保留义工号原值、剩余段统一合并为工作组解析 - 后端 batch:user_groups 插入语句改为事务内按用户编译;义工号判断改为 null/undefined 严格检查,避免真值判断丢弃空字符串或 0 开头的值 - 新增 DELETE /users/batch:事务性批量删除部员(含 user_groups/hours 级联),返回实际删除 count - 前端列表新增复选框列(表头 indeterminate 半选态),选中 1+ 条后工具栏显示「删除选中(N)」红色按钮,确认弹窗二次校验
This commit is contained in:
@@ -187,13 +187,14 @@ router.post('/batch', authMiddleware, (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
db.execCompat('BEGIN');
|
||||
const insertUser = db.prepareCompat('INSERT INTO users (class, name, volunteer_no, group_id) VALUES (?,?,?,?)');
|
||||
const insertUG = db.prepareCompat('INSERT OR IGNORE INTO user_groups (user_id, group_id) VALUES (?,?)');
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const raw = items[i] || {};
|
||||
const cls = String(raw.class || '').trim();
|
||||
const name = String(raw.name || '').trim();
|
||||
const volunteer_no = raw.volunteer_no ? String(raw.volunteer_no).trim() || null : null;
|
||||
const volunteer_no = (raw.volunteer_no === undefined || raw.volunteer_no === null)
|
||||
? null
|
||||
: (String(raw.volunteer_no).trim() || null);
|
||||
if (!cls || !name) {
|
||||
failed++;
|
||||
results.push({ idx: i, ok: false, error: '班级和姓名不能为空', item: raw });
|
||||
@@ -213,7 +214,10 @@ router.post('/batch', authMiddleware, (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const info = insertUser.run(cls, name, volunteer_no, firstGroup);
|
||||
const userId = Number(info.lastInsertRowid);
|
||||
for (const gid of groups) insertUG.run(userId, gid);
|
||||
if (groups.length > 0) {
|
||||
const insertUG = db.prepareCompat('INSERT OR IGNORE INTO user_groups (user_id, group_id) VALUES (?,?)');
|
||||
for (const gid of groups) insertUG.run(userId, gid);
|
||||
}
|
||||
success++;
|
||||
results.push({ idx: i, ok: true, id: userId, item: raw });
|
||||
} catch (e: any) {
|
||||
@@ -232,4 +236,35 @@ router.post('/batch', authMiddleware, (req: AuthRequest, res: Response) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/batch', authMiddleware, (req: AuthRequest, res: Response) => {
|
||||
const { ids } = req.body || {};
|
||||
if (!Array.isArray(ids) || ids.length === 0) {
|
||||
return res.status(400).json({ error: '请选择要删除的部员' });
|
||||
}
|
||||
const db = getDb();
|
||||
const list: number[] = [];
|
||||
for (const id of ids) {
|
||||
const n = Number(id);
|
||||
if (!isNaN(n) && n > 0 && !list.includes(n)) list.push(n);
|
||||
}
|
||||
if (list.length === 0) {
|
||||
return res.status(400).json({ error: '请选择有效的部员' });
|
||||
}
|
||||
try {
|
||||
db.execCompat('BEGIN');
|
||||
const del = db.prepareCompat('DELETE FROM users WHERE id = ?');
|
||||
let count = 0;
|
||||
for (const id of list) {
|
||||
const r = del.run(id);
|
||||
count += (r?.changes ?? 0);
|
||||
}
|
||||
db.execCompat('COMMIT');
|
||||
db.save();
|
||||
res.json({ ok: true, deleted: count, total: list.length });
|
||||
} catch (e: any) {
|
||||
try { db.execCompat('ROLLBACK'); } catch {}
|
||||
res.status(500).json({ error: e?.message || '批量删除失败' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user