gongxiangp2/scripts/delete-user.ts
chenpei ea9076df45 feat: 实现统一的下载错误处理系统并修复产品全案数据库Schema
- 创建统一的下载错误处理模块 (lib/download-errors.ts)
- 实现13种错误类型分类和中文错误消息
- 后端统一使用 createDownloadError 创建标准化错误响应
- 前端统一使用 parseDownloadError 解析错误并显示
- 修复正式系统数据库Schema,添加产品全案相关字段和表
- 执行数据库迁移:添加 task_no, task_status, task_fetched_at 字段
- 创建 material_assets, api_keys, api_call_logs 表
2026-01-05 17:52:42 +08:00

139 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 删除用户脚本
*
* 功能:根据用户名或真实姓名删除用户账号
*
* 使用方法:
* npx tsx scripts/delete-user.ts <username|realName>
*
* 示例:
* npx tsx scripts/delete-user.ts 玄女
*/
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function deleteUser(searchTerm: string) {
try {
console.log(`🔍 正在查找用户: "${searchTerm}"...\n`);
// 使用原始SQL查询,避免字段不匹配问题
const users = await prisma.$queryRaw<Array<{
id: string;
username: string;
email: string;
department: string;
role: string;
isactive: boolean;
realname?: string;
issuperadmin?: boolean;
}>>`
SELECT id, username, email, department, role, "isActive" as isactive, "realName" as realname, "isSuperAdmin" as issuperadmin
FROM users
WHERE username = ${searchTerm} OR "realName" = ${searchTerm}
LIMIT 1
`;
if (users.length === 0) {
console.log(`❌ 未找到用户: "${searchTerm}"`);
return;
}
const user = users[0];
if (!user) {
console.log(`❌ 未找到用户: "${searchTerm}"`);
return;
}
// 查询关联数据统计
const stats = await prisma.$queryRaw<Array<{
material_count: bigint;
like_count: bigint;
favorite_count: bigint;
download_log_count: bigint;
}>>`
SELECT
(SELECT COUNT(*) FROM materials WHERE "userId" = ${user.id} AND "deletedAt" IS NULL) as material_count,
(SELECT COUNT(*) FROM material_likes WHERE "userId" = ${user.id}) as like_count,
(SELECT COUNT(*) FROM material_favorites WHERE "userId" = ${user.id}) as favorite_count,
(SELECT COUNT(*) FROM material_download_logs WHERE "userId" = ${user.id}) as download_log_count
`;
const materialCount = Number(stats[0]?.material_count || 0);
const likeCount = Number(stats[0]?.like_count || 0);
const favoriteCount = Number(stats[0]?.favorite_count || 0);
const downloadLogCount = Number(stats[0]?.download_log_count || 0);
// 显示用户信息
console.log('📋 找到用户信息:');
console.log(` ID: ${user.id}`);
console.log(` 用户名: ${user.username}`);
console.log(` 真实姓名: ${user.realname || '(未设置)'}`);
console.log(` 邮箱: ${user.email}`);
console.log(` 部门: ${user.department || '(未设置)'}`);
console.log(` 角色: ${user.role}`);
console.log(` 是否激活: ${user.isactive ? '是' : '否'}`);
if (user.issuperadmin !== undefined) {
console.log(` 是否超级管理员: ${user.issuperadmin ? '是' : '否'}`);
}
console.log(`\n📊 关联数据统计:`);
console.log(` 素材数: ${materialCount}`);
console.log(` 点赞数: ${likeCount}`);
console.log(` 收藏数: ${favoriteCount}`);
console.log(` 下载日志数: ${downloadLogCount}`);
// 警告信息
if (materialCount > 0) {
console.log(`\n⚠️ 警告: 该用户有 ${materialCount} 个素材,删除用户会级联删除这些素材!`);
}
if (user.issuperadmin) {
console.log(`\n⚠️ 警告: 该用户是超级管理员!`);
}
// 执行删除
console.log(`\n🗑️ 正在删除用户...`);
await prisma.$executeRaw`
DELETE FROM users WHERE id = ${user.id}
`;
console.log(`✅ 用户 "${user.username}" (${user.realname || 'N/A'}) 已成功删除!`);
if (materialCount > 0) {
console.log(` 已级联删除 ${materialCount} 个素材`);
}
} catch (error: any) {
console.error('❌ 删除失败:', error.message);
if (error.code === 'P2003') {
console.error(' 错误: 存在外键约束,无法删除');
} else if (error.code === 'P2025') {
console.error(' 错误: 用户不存在');
}
process.exit(1);
} finally {
await prisma.$disconnect();
}
}
// 主函数
async function main() {
const searchTerm = process.argv[2];
if (!searchTerm) {
console.error('❌ 错误: 请提供用户名或真实姓名');
console.error(' 使用方法: npx tsx scripts/delete-user.ts <username|realName>');
process.exit(1);
}
await deleteUser(searchTerm);
}
main();