- 后端 /users/batch 返回每条成功记录的 groups_written/groups_expected/group_ids_out;失败记录返回 group_ids_seen/count - 前端 submitBatch:console.log 打印发送 payload 和响应;弹窗汇总工作组实际/期望写入数;任何异常的行都显示后端实际解析出的 group_ids_out,失败行同时显示后端收到的 group_ids_seen - 本地模拟后端 sql.js 写入 user_groups 100% 正确(场景A/B测试均 changes=1,聚合查询正确),此提交部署后通过控制台和弹窗即可精确定位问题在哪一跳(前端发送 vs 后端解析 vs 数据库写入) - npm run build 通过
This commit is contained in:
@@ -349,18 +349,29 @@ export default function Users() {
|
|||||||
volunteer_no: r.volunteer_no || null,
|
volunteer_no: r.volunteer_no || null,
|
||||||
group_ids: r.group_ids,
|
group_ids: r.group_ids,
|
||||||
}));
|
}));
|
||||||
|
console.log('[DEBUG] batch payload items (first 3):', JSON.stringify(items.slice(0, 3), null, 2));
|
||||||
const result = await usersApi.batch(items);
|
const result = await usersApi.batch(items);
|
||||||
|
console.log('[DEBUG] batch response:', result);
|
||||||
setBatchErrors('');
|
setBatchErrors('');
|
||||||
const msg = `批量添加完成:共 ${result.total} 条,成功 ${result.success} 条,失败 ${result.failed} 条`;
|
const totalActualWritten = result.results.filter(r => r.ok).reduce((sum: number, r: any) => sum + (r?.groups_written ?? 0), 0);
|
||||||
|
const totalExpectedWritten = result.results.filter(r => r.ok).reduce((sum: number, r: any) => sum + (r?.groups_expected ?? 0), 0);
|
||||||
|
const msg = `批量添加完成:共 ${result.total} 条,成功 ${result.success} 条,失败 ${result.failed} 条
|
||||||
|
工作组写入:实际 ${totalActualWritten} 条,期望 ${totalExpectedWritten} 条`;
|
||||||
if (result.failed === 0) {
|
if (result.failed === 0) {
|
||||||
alert(msg);
|
const mis = result.results.filter((r: any) => r.ok && (r?.groups_written ?? 0) !== (r?.groups_expected ?? 0));
|
||||||
|
if (mis.length === 0) {
|
||||||
|
alert(msg);
|
||||||
|
} else {
|
||||||
|
const lines = mis.slice(0, 20).map((r: any) => `第${r.idx + 1}行 ${r.item.name}:期望 ${r.groups_expected} 组,实际写入 ${r.groups_written} 组(后端解析 group_ids_out=${JSON.stringify(r.group_ids_out ?? [])})`).join('\n');
|
||||||
|
alert(`${msg}\n\n工作组未全部写入(前20):\n${lines}`);
|
||||||
|
}
|
||||||
setBatchOpen(false);
|
setBatchOpen(false);
|
||||||
setBatchText('');
|
setBatchText('');
|
||||||
load();
|
load();
|
||||||
} else {
|
} else {
|
||||||
const failLines = result.results
|
const failLines = result.results
|
||||||
.filter((r) => !r.ok)
|
.filter((r) => !r.ok)
|
||||||
.map((r) => `第${r.idx + 1}行 [${r.item.class} ${r.item.name}]:${r.error}`)
|
.map((r: any) => `第${r.idx + 1}行 [${r.item.class} ${r.item.name}]:${r.error}(后端接收 group_ids_count=${r.group_ids_count ?? 'N/A'},内容=${JSON.stringify(r.group_ids_seen ?? null)})`)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
alert(`${msg}\n\n失败明细:\n${failLines}`);
|
alert(`${msg}\n\n失败明细:\n${failLines}`);
|
||||||
load();
|
load();
|
||||||
|
|||||||
@@ -214,17 +214,36 @@ router.post('/batch', authMiddleware, (req: AuthRequest, res: Response) => {
|
|||||||
try {
|
try {
|
||||||
const info = insertUser.run(cls, name, volunteer_no, firstGroup);
|
const info = insertUser.run(cls, name, volunteer_no, firstGroup);
|
||||||
const userId = Number(info.lastInsertRowid);
|
const userId = Number(info.lastInsertRowid);
|
||||||
|
let ugCount = 0;
|
||||||
if (groups.length > 0) {
|
if (groups.length > 0) {
|
||||||
const insertUG = db.prepareCompat('INSERT OR IGNORE INTO user_groups (user_id, group_id) VALUES (?,?)');
|
const insertUG = db.prepareCompat('INSERT OR IGNORE INTO user_groups (user_id, group_id) VALUES (?,?)');
|
||||||
for (const gid of groups) insertUG.run(userId, gid);
|
for (const gid of groups) {
|
||||||
|
const ugInfo = insertUG.run(userId, gid);
|
||||||
|
if ((ugInfo?.changes ?? 0) > 0) ugCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
success++;
|
success++;
|
||||||
results.push({ idx: i, ok: true, id: userId, item: raw });
|
results.push({
|
||||||
|
idx: i,
|
||||||
|
ok: true,
|
||||||
|
id: userId,
|
||||||
|
item: raw,
|
||||||
|
groups_written: ugCount,
|
||||||
|
groups_expected: groups.length,
|
||||||
|
group_ids_out: groups.slice(),
|
||||||
|
} as any);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
failed++;
|
failed++;
|
||||||
let err = e?.message || '添加失败';
|
let err = e?.message || '添加失败';
|
||||||
if (String(err).includes('UNIQUE')) err = '该班级下已存在同名部员';
|
if (String(err).includes('UNIQUE')) err = '该班级下已存在同名部员';
|
||||||
results.push({ idx: i, ok: false, error: err, item: raw });
|
results.push({
|
||||||
|
idx: i,
|
||||||
|
ok: false,
|
||||||
|
error: err,
|
||||||
|
item: raw,
|
||||||
|
group_ids_seen: Array.isArray(raw.group_ids) ? raw.group_ids : null,
|
||||||
|
group_ids_count: Array.isArray(raw.group_ids) ? raw.group_ids.length : 0,
|
||||||
|
} as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.execCompat('COMMIT');
|
db.execCompat('COMMIT');
|
||||||
|
|||||||
Reference in New Issue
Block a user