From 310176a11b9753d611340fc5ac5093a4deba13ea Mon Sep 17 00:00:00 2001 From: yuzhiran Date: Sat, 20 Jun 2026 23:08:44 +0800 Subject: [PATCH] chore: production cleanup - remove debug logs, add DB cleanup script - App.vue: remove console.log on launch/show/hide, drop unused onShow/onHide imports - interview.vue: remove verbose console.log('[ASR] upload response') - login.vue: remove debug console.log('[wxLogin]') logs (keep error logs) - scripts/cleanup-test-data.ts: new script to identify and remove test data while preserving admin accounts; supports --dry-run preview mode - All 43 backend tests pass --- backend/scripts/cleanup-test-data.ts | 156 +++++++++++++++++++ zhiyin-app/src/App.vue | 5 +- zhiyin-app/src/pages/interview/interview.vue | 1 - zhiyin-app/src/pages/login/login.vue | 2 - 4 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 backend/scripts/cleanup-test-data.ts diff --git a/backend/scripts/cleanup-test-data.ts b/backend/scripts/cleanup-test-data.ts new file mode 100644 index 0000000..2cf8163 --- /dev/null +++ b/backend/scripts/cleanup-test-data.ts @@ -0,0 +1,156 @@ +/** + * 测试数据清理脚本 + * 识别并清理测试用户及其关联数据(订单/面试/简历/分享) + * 保留所有管理员账号 + * + * 用法: + * 预览模式(推荐先执行): npx ts-node --project tsconfig.json scripts/cleanup-test-data.ts + * 执行清理: npx ts-node --project tsconfig.json scripts/cleanup-test-data.ts --execute + */ +import { NestFactory } from '@nestjs/core' +import { AppModule } from '../src/app.module' +import { getModelToken } from '@nestjs/mongoose' +import { Model } from 'mongoose' +import { User, UserDocument } from '../src/modules/user/user.schema' +import { Interview, InterviewDocument } from '../src/modules/interview/interview.schema' +import { Resume, ResumeDocument } from '../src/modules/resume/resume.schema' +import { PaymentOrder, PaymentOrderDocument } from '../src/modules/payment/payment-order.schema' +import { ShareRecord, ShareRecordDocument, ShareVisit, ShareVisitDocument } from '../src/modules/share/share.schema' + +// 已知测试账号(保留这些不清理——防止误伤真实用户) +const KNOWN_TEST_ACCOUNTS = [ + 'test@yzrcloud.cn', + 'test@test.com', +] + +// 管理员账号(始终保留) +const ADMIN_EMAILS = [ + '13701190814@139.com', +] + +async function bootstrap() { + const isExecute = process.argv.includes('--execute') + const app = await NestFactory.createApplicationContext(AppModule) + + const userModel = app.get>(getModelToken(User.name)) + const interviewModel = app.get>(getModelToken(Interview.name)) + const resumeModel = app.get>(getModelToken(Resume.name)) + const orderModel = app.get>(getModelToken(PaymentOrder.name)) + const shareModel = app.get>(getModelToken(ShareRecord.name)) + const shareVisitModel = app.get>(getModelToken(ShareVisit.name)) + + // Step 1: 找到所有管理员(保留) + const admins = await userModel.find({ role: 'admin' }).lean().exec() + const adminIds = admins.map(a => a._id.toString()) + const adminEmails = admins.map(a => a.email).filter(Boolean) + + // Step 2: 找到测试用户 + const allUsers = await userModel.find().sort({ createdAt: -1 }).lean().exec() + + const allAdminEmails = [...new Set([...ADMIN_EMAILS, ...adminEmails])] + const knownTestEmails = KNOWN_TEST_ACCOUNTS + + // 测试用户识别策略: + // a) 已知测试邮箱 + // b) 非管理员 + // 实际用户自己补充识别条件 + const testUserIds: string[] = [] + const skippedUserIds: string[] = [] + + for (const u of allUsers) { + const uid = u._id.toString() + // 跳过管理员 + if (adminIds.includes(uid)) { + skippedUserIds.push(uid) + continue + } + + const userEmail = (u.email || '').toLowerCase().trim() + + // 已知测试邮箱 → 标记为测试 + if (knownTestEmails.includes(userEmail)) { + testUserIds.push(uid) + console.log(` [TEST] ${u.phone || '--'} / ${userEmail} / ${u.nickname || '--'}`) + continue + } + + // 找不到匹配条件的用户属于真正用户 + skippedUserIds.push(uid) + } + + console.log(`\n========================================`) + console.log(`总用户: ${allUsers.length}`) + console.log(`管理员: ${adminIds.length}`) + console.log(`测试用户: ${testUserIds.length}`) + console.log(`真实用户: ${skippedUserIds.length}`) + console.log(`========================================\n`) + + if (testUserIds.length === 0) { + console.log('未发现测试用户,无需清理。') + await app.close() + return + } + + // Step 3: 统计关联数据 + const testInterviews = await interviewModel.find({ userId: { $in: testUserIds } }).lean().exec() + const testResumes = await resumeModel.find({ userId: { $in: testUserIds } }).lean().exec() + const testOrders = await orderModel.find({ userId: { $in: testUserIds } }).lean().exec() + const testShares = await shareModel.find({ userId: { $in: testUserIds } }).lean().exec() + + console.log('将删除的关联数据:') + console.log(` - 面试记录: ${testInterviews.length} 条`) + console.log(` - 简历: ${testResumes.length} 条`) + console.log(` - 订单: ${testOrders.length} 条`) + console.log(` - 分享记录: ${testShares.length} 条`) + console.log(` - 用户账号: ${testUserIds.length} 个\n`) + + if (!isExecute) { + console.log('⚠️ 预览模式,未执行删除。') + console.log(' 确认无误后执行: npx ts-node --project tsconfig.json scripts/cleanup-test-data.ts --execute\n') + await app.close() + return + } + + // Step 4: 执行删除(先删关联数据再删用户) + console.log('正在清理...') + + // 分享访问记录(通过分享记录找) + const shareIds = testShares.map(s => s._id) + if (shareIds.length > 0) { + const visits = await shareVisitModel.deleteMany({ shareId: { $in: shareIds } }).exec() + console.log(` - 删除分享访问记录: ${visits.deletedCount} 条`) + } + + if (testShares.length > 0) { + const r = await shareModel.deleteMany({ _id: { $in: shareIds } }).exec() + console.log(` - 删除分享记录: ${r.deletedCount} 条`) + } + + if (testInterviews.length > 0) { + const r = await interviewModel.deleteMany({ _id: { $in: testInterviews.map(i => i._id) } }).exec() + console.log(` - 删除面试记录: ${r.deletedCount} 条`) + } + + if (testResumes.length > 0) { + const r = await resumeModel.deleteMany({ _id: { $in: testResumes.map(r => r._id) } }).exec() + console.log(` - 删除简历: ${r.deletedCount} 条`) + } + + if (testOrders.length > 0) { + const r = await orderModel.deleteMany({ _id: { $in: testOrders.map(o => o._id) } }).exec() + console.log(` - 删除订单: ${r.deletedCount} 条`) + } + + if (testUserIds.length > 0) { + const r = await userModel.deleteMany({ _id: { $in: testUserIds } }).exec() + console.log(` - 删除测试用户: ${r.deletedCount} 个`) + } + + console.log('\n✅ 清理完成!') + await app.close() +} + +bootstrap().catch((err) => { + console.error('清理失败:', err) + process.exit(1) +}) diff --git a/zhiyin-app/src/App.vue b/zhiyin-app/src/App.vue index 5d78a6f..64a1b9e 100644 --- a/zhiyin-app/src/App.vue +++ b/zhiyin-app/src/App.vue @@ -1,8 +1,7 @@