/** * 删除 GroupChat 表中前端不再读取的死字段 * * - lastActivityAt: 前端完全不读,后端已停止写入 * - avatarUrl: 前端完全不读,后端已停止写入(企微头像 URL 无用) * - ownerName: 前端从 ResponsibilityAssignment 读取负责人,不再读此字段 * * 保留字段说明: * - status: 仅群解散 webhook 写入 'dismissed',前端用于判定健康分(不删) * - messageCountToday / messageCountTotal / memberCount: 前端暂时仍读取,后续改为纯计算后再删 * * 用法: cd backend && npx tsx scripts/cleanup-groupchat-dead-fields.ts */ import 'dotenv/config'; import Parse from '../src/db/parse-client.js'; const DEAD_FIELDS = ['lastActivityAt', 'avatarUrl', 'ownerName', 'memberCount', 'messageCountToday', 'messageCountTotal']; async function main(): Promise { console.log('=== 清理 GroupChat 死字段 ===\n'); const schemas = await Parse.Schema.all({ useMasterKey: true }); const groupChat = schemas.find((s: any) => s.className === 'GroupChat'); if (!groupChat) { console.error('❌ GroupChat 表不存在'); process.exit(1); } const existingFields = Object.keys(groupChat.fields).filter((k: string) => !k.startsWith('_')); console.log(`当前 GroupChat 字段: ${existingFields.join(', ')}\n`); const deletable = DEAD_FIELDS.filter(f => existingFields.includes(f)); if (deletable.length === 0) { console.log('目标字段均已不存在,无需操作'); return; } console.log(`准备删除: ${deletable.join(', ')}\n`); const schema = new Parse.Schema('GroupChat'); for (const field of deletable) { schema.deleteField(field); console.log(` ✅ 已标记删除: ${field}`); } await schema.update({ useMasterKey: true }); // 验证 console.log('\n--- 验证 ---'); const afterSchemas = await Parse.Schema.all({ useMasterKey: true }); const after = afterSchemas.find((s: any) => s.className === 'GroupChat'); if (after) { const remaining = Object.keys(after.fields).filter((k: string) => !k.startsWith('_')).sort(); const stillThere = deletable.filter(f => remaining.includes(f)); if (stillThere.length > 0) { console.log(`❌ 残留字段: ${stillThere.join(', ')}`); } else { console.log(`✅ 全部清除成功`); } console.log(`现有字段 (${remaining.length}): ${remaining.join(', ')}`); } console.log('\n✅ 清理完成!'); } main().catch((err) => { console.error('❌ 失败:', err); process.exit(1); });