- 创建统一的下载错误处理模块 (lib/download-errors.ts) - 实现13种错误类型分类和中文错误消息 - 后端统一使用 createDownloadError 创建标准化错误响应 - 前端统一使用 parseDownloadError 解析错误并显示 - 修复正式系统数据库Schema,添加产品全案相关字段和表 - 执行数据库迁移:添加 task_no, task_status, task_fetched_at 字段 - 创建 material_assets, api_keys, api_call_logs 表
139 lines
4.2 KiB
TypeScript
139 lines
4.2 KiB
TypeScript
/**
|
||
* 删除用户脚本
|
||
*
|
||
* 功能:根据用户名或真实姓名删除用户账号
|
||
*
|
||
* 使用方法:
|
||
* 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();
|
||
|