| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- /**
- * 项目阶段数据修复脚本
- *
- * 功能:将没有完成阶段工作的项目回退到正确的阶段
- *
- * 使用方法:
- * 1. 在浏览器控制台粘贴此脚本
- * 2. 调用 repairProjectStages() 预览需要修复的项目
- * 3. 调用 repairProjectStages(false) 执行实际修复
- */
- import { FmodeParse } from 'fmode-ng/core';
- const Parse = FmodeParse.with('nova');
- /**
- * 修复项目阶段数据
- * @param dryRun 是否为预览模式(默认true,只预览不修复)
- */
- export async function repairProjectStages(dryRun: boolean = true): Promise<void> {
- console.log('\n' + '='.repeat(80));
- console.log(dryRun ? '🔍 预览模式:查看需要修复的项目' : '🔧 执行模式:开始修复项目阶段数据');
- console.log('='.repeat(80) + '\n');
-
- try {
- // 查询所有未删除的项目
- const query = new Parse.Query('Project');
- query.notEqualTo('isDeleted', true);
- query.limit(1000);
- const projects = await query.find();
-
- console.log(`📊 共找到 ${projects.length} 个项目\n`);
-
- let needFixCount = 0;
- const fixedProjects: Array<{
- id: string;
- title: string;
- oldStage: string;
- newStage: string;
- reason: string;
- }> = [];
-
- for (const project of projects) {
- const currentStage = project.get('currentStage') || '订单分配';
- const correctStage = await getCorrectStage(project);
-
- // 如果当前阶段与正确阶段不一致
- if (currentStage !== correctStage) {
- const title = project.get('title') || '未命名项目';
- const reason = await getFixReason(project, correctStage);
-
- console.log(`\n${'─'.repeat(60)}`);
- console.log(`📋 项目: ${title}`);
- console.log(` ID: ${project.id}`);
- console.log(` 当前阶段: ${currentStage}`);
- console.log(` 应该阶段: ${correctStage}`);
- console.log(` 回退原因: ${reason}`);
-
- if (!dryRun) {
- // 执行修复
- project.set('currentStage', correctStage);
-
- // 清除不合理的审批状态
- const data = project.get('data') || {};
- if (correctStage === '订单分配' && data.approvalStatus === 'approved') {
- const isCompleted = await isOrderStageCompleted(project);
- if (!isCompleted) {
- data.approvalStatus = null;
- project.set('data', data);
- console.log(` 🧹 已清除错误的审批状态`);
- }
- }
-
- await project.save();
- console.log(` ✅ 已回退到"${correctStage}"阶段`);
- } else {
- console.log(` 🔍 [预览] 需要回退到"${correctStage}"阶段`);
- }
-
- fixedProjects.push({
- id: project.id || 'unknown',
- title,
- oldStage: currentStage,
- newStage: correctStage,
- reason
- });
-
- needFixCount++;
- }
- }
-
- console.log(`\n${'='.repeat(80)}`);
-
- if (needFixCount === 0) {
- console.log('✅ 所有项目的阶段状态都是正确的,无需修复!');
- } else {
- if (dryRun) {
- console.log(`🔍 预览完成!发现 ${needFixCount} 个项目需要修复`);
- console.log(`\n💡 提示:调用 repairProjectStages(false) 执行实际修复`);
- } else {
- console.log(`✅ 修复完成!共回退 ${needFixCount} 个项目到正确阶段`);
- }
-
- console.log('\n📋 修复详情:');
- console.table(fixedProjects);
- }
-
- console.log('='.repeat(80) + '\n');
-
- } catch (error) {
- console.error('❌ 操作失败:', error);
- throw error;
- }
- }
- /**
- * 获取项目应该处于的正确阶段
- */
- async function getCorrectStage(project: any): Promise<string> {
- // 检查订单分配阶段是否完成
- const orderCompleted = await isOrderStageCompleted(project);
- if (!orderCompleted) {
- return '订单分配';
- }
-
- // 检查确认需求阶段是否完成
- const requirementsCompleted = await isRequirementsStageCompleted(project);
- if (!requirementsCompleted) {
- return '确认需求';
- }
-
- // 检查交付执行阶段是否完成
- const deliveryCompleted = await isDeliveryStageCompleted(project);
- if (!deliveryCompleted) {
- return '交付执行';
- }
-
- // 所有阶段都完成了,应该在售后归档
- return '售后归档';
- }
- /**
- * 获取修复原因说明
- */
- async function getFixReason(project: any, correctStage: string): Promise<string> {
- const reasons: string[] = [];
-
- if (correctStage === '订单分配') {
- if (!project.get('title')?.trim()) reasons.push('缺少项目名称');
- if (!project.get('projectType')) reasons.push('缺少项目类型');
- if (!project.get('demoday')) reasons.push('缺少小图日期');
-
- const data = project.get('data') || {};
- if (!data.quotation || data.quotation.total <= 0) reasons.push('缺少报价数据');
-
- const query = new Parse.Query('ProjectTeam');
- query.equalTo('project', project.toPointer());
- query.notEqualTo('isDeleted', true);
- const teams = await query.find();
-
- if (teams.length === 0 && data.approvalStatus !== 'approved') {
- reasons.push('未分配设计师且未审批');
- }
- }
-
- if (correctStage === '确认需求') {
- const data = project.get('data') || {};
- if (!data.requirementsAnalysis || Object.keys(data.requirementsAnalysis).length === 0) {
- if (!data.spaceRequirements || Object.keys(data.spaceRequirements).length === 0) {
- reasons.push('缺少需求分析数据');
- }
- }
- }
-
- if (correctStage === '交付执行') {
- const data = project.get('data') || {};
- const deliveryStages = data.deliveryStages || {};
- const requiredStages = [
- { id: 'modeling', name: '建模' },
- { id: 'softDecor', name: '软装' },
- { id: 'rendering', name: '渲染' },
- { id: 'postProcess', name: '后期' }
- ];
-
- for (const stage of requiredStages) {
- if (!deliveryStages[stage.id] || deliveryStages[stage.id].approvalStatus !== 'approved') {
- reasons.push(`${stage.name}阶段未审批`);
- }
- }
- }
-
- return reasons.length > 0 ? reasons.join(', ') : '未知原因';
- }
- /**
- * 检查订单分配阶段是否完成
- */
- async function isOrderStageCompleted(project: any): Promise<boolean> {
- // 1. 检查基本信息
- if (!project.get('title')?.trim()) return false;
- if (!project.get('projectType')) return false;
- if (!project.get('demoday')) return false;
-
- // 2. 检查报价
- const data = project.get('data') || {};
- if (!data.quotation || data.quotation.total <= 0) return false;
-
- // 3. 检查设计师分配或审批状态
- const query = new Parse.Query('ProjectTeam');
- query.equalTo('project', project.toPointer());
- query.notEqualTo('isDeleted', true);
- const teams = await query.find();
-
- const hasDesigner = teams.length > 0;
- const isApproved = data.approvalStatus === 'approved';
-
- // 至少满足一个条件:已分配设计师 或 已审批通过
- return hasDesigner || isApproved;
- }
- /**
- * 检查确认需求阶段是否完成
- */
- async function isRequirementsStageCompleted(project: any): Promise<boolean> {
- const data = project.get('data') || {};
-
- // 检查是否有需求分析数据
- if (data.requirementsAnalysis && Object.keys(data.requirementsAnalysis).length > 0) {
- return true;
- }
-
- // 检查是否有空间需求数据
- if (data.spaceRequirements && Object.keys(data.spaceRequirements).length > 0) {
- return true;
- }
-
- // 如果没有任何需求数据,视为未完成
- return false;
- }
- /**
- * 检查交付执行阶段是否完成
- */
- async function isDeliveryStageCompleted(project: any): Promise<boolean> {
- const data = project.get('data') || {};
- const deliveryStages = data.deliveryStages || {};
-
- // 检查所有必需的交付阶段
- const requiredStages = ['modeling', 'softDecor', 'rendering', 'postProcess'];
-
- for (const stageId of requiredStages) {
- const stageData = deliveryStages[stageId];
-
- // 如果某个阶段不存在或未审批通过,则交付执行未完成
- if (!stageData || stageData.approvalStatus !== 'approved') {
- return false;
- }
- }
-
- // 所有阶段都已审批通过
- return true;
- }
- /**
- * 导出项目数据(用于备份)
- */
- export async function exportProjectsForBackup(): Promise<void> {
- console.log('📦 开始导出项目数据...');
-
- const query = new Parse.Query('Project');
- query.notEqualTo('isDeleted', true);
- query.limit(1000);
- const projects = await query.find();
-
- const backup = projects.map(p => ({
- id: p.id,
- title: p.get('title'),
- currentStage: p.get('currentStage'),
- projectType: p.get('projectType'),
- demoday: p.get('demoday'),
- data: p.get('data')
- }));
-
- console.log('✅ 导出完成,共', projects.length, '个项目');
- console.log('📋 备份数据:', JSON.stringify(backup, null, 2));
-
- // 下载为JSON文件
- const dataStr = JSON.stringify(backup, null, 2);
- const dataBlob = new Blob([dataStr], { type: 'application/json' });
- const url = URL.createObjectURL(dataBlob);
- const link = document.createElement('a');
- link.href = url;
- link.download = `projects-backup-${new Date().toISOString()}.json`;
- link.click();
-
- console.log('💾 备份文件已下载');
- }
- // 导出全局方法(用于浏览器控制台)
- if (typeof window !== 'undefined') {
- (window as any).repairProjectStages = repairProjectStages;
- (window as any).exportProjectsForBackup = exportProjectsForBackup;
-
- console.log('✅ 数据修复工具已加载');
- console.log('💡 使用方法:');
- console.log(' 1. repairProjectStages() - 预览需要修复的项目');
- console.log(' 2. repairProjectStages(false) - 执行实际修复');
- console.log(' 3. exportProjectsForBackup() - 导出备份数据');
- }
|