| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /**
- * 数据迁移任务:为现有项目添加阶段截止时间
- *
- * 使用方法:
- * Parse.Cloud.startJob('migrateProjectPhaseDeadlines', {
- * dryRun: true, // 是否干跑(只计算不保存)
- * batchSize: 100 // 批量处理大小
- * })
- */
- Parse.Cloud.job("migrateProjectPhaseDeadlines", async (request) => {
- const { params, message } = request;
- const { dryRun = false, batchSize = 100 } = params || {};
-
- message(`开始迁移项目阶段截止时间数据...`);
- message(`干跑模式: ${dryRun ? '是' : '否'}`);
- message(`批处理大小: ${batchSize}`);
-
- // 阶段默认工期(天数)
- const DEFAULT_DURATIONS = {
- modeling: 1, // 建模默认1天(临时改为1天便于查看效果)
- softDecor: 1, // 软装默认1天(临时改为1天便于查看效果)
- rendering: 1, // 渲染默认1天(临时改为1天便于查看效果)
- postProcessing: 1 // 后期默认1天(临时改为1天便于查看效果)
- };
-
- try {
- // 查询所有未删除且没有阶段截止时间的项目
- const projectQuery = new Parse.Query("Project");
- projectQuery.notEqualTo("isDeleted", true);
- projectQuery.limit(10000); // 限制最大数量
-
- const totalCount = await projectQuery.count({ useMasterKey: true });
- message(`找到${totalCount}个项目待检查`);
-
- let processedCount = 0;
- let updatedCount = 0;
- let skippedCount = 0;
- let errorCount = 0;
-
- // 分批处理
- for (let skip = 0; skip < totalCount; skip += batchSize) {
- projectQuery.skip(skip);
- projectQuery.limit(batchSize);
-
- const projects = await projectQuery.find({ useMasterKey: true });
- message(`处理批次: ${skip}-${skip + projects.length}/${totalCount}`);
-
- for (const project of projects) {
- try {
- processedCount++;
-
- const data = project.get("data") || {};
-
- // 如果已经有phaseDeadlines,跳过
- if (data.phaseDeadlines) {
- skippedCount++;
- continue;
- }
-
- // 获取项目截止时间
- const deadline = project.get("deadline");
-
- // 如果没有截止时间,也跳过
- if (!deadline) {
- message(` 项目 ${project.id} (${project.get("title")}) 没有截止时间,跳过`);
- skippedCount++;
- continue;
- }
-
- // 根据项目deadline推算各阶段截止时间
- const deadlineTime = deadline.getTime();
-
- // 计算各阶段截止时间(从后往前推)
- const postProcessingDeadline = new Date(deadlineTime); // 后期:项目截止日
- const renderingDeadline = new Date(deadlineTime - DEFAULT_DURATIONS.postProcessing * 24 * 60 * 60 * 1000); // 渲染:提前3天
- const softDecorDeadline = new Date(deadlineTime - (DEFAULT_DURATIONS.postProcessing + DEFAULT_DURATIONS.rendering) * 24 * 60 * 60 * 1000); // 软装:提前9天
- const modelingDeadline = new Date(deadlineTime - (DEFAULT_DURATIONS.postProcessing + DEFAULT_DURATIONS.rendering + DEFAULT_DURATIONS.softDecor) * 24 * 60 * 60 * 1000); // 建模:提前13天
-
- // 构建phaseDeadlines对象
- const phaseDeadlines = {
- modeling: {
- deadline: modelingDeadline,
- estimatedDays: DEFAULT_DURATIONS.modeling,
- status: "not_started",
- priority: "medium"
- },
- softDecor: {
- deadline: softDecorDeadline,
- estimatedDays: DEFAULT_DURATIONS.softDecor,
- status: "not_started",
- priority: "medium"
- },
- rendering: {
- deadline: renderingDeadline,
- estimatedDays: DEFAULT_DURATIONS.rendering,
- status: "not_started",
- priority: "medium"
- },
- postProcessing: {
- deadline: postProcessingDeadline,
- estimatedDays: DEFAULT_DURATIONS.postProcessing,
- status: "not_started",
- priority: "medium"
- }
- };
-
- // 如果不是干跑模式,保存数据
- if (!dryRun) {
- data.phaseDeadlines = phaseDeadlines;
- project.set("data", data);
- await project.save(null, { useMasterKey: true });
- }
-
- updatedCount++;
-
- // 每10个项目输出一次详细日志
- if (updatedCount % 10 === 0) {
- message(` ✅ 已更新 ${updatedCount} 个项目`);
- }
-
- } catch (error) {
- errorCount++;
- message(` ❌ 处理项目 ${project.id} 失败: ${error.message}`);
- }
- }
- }
-
- // 输出最终统计
- message('');
- message('='.repeat(50));
- message('迁移完成!统计信息:');
- message(` 总处理数: ${processedCount}`);
- message(` 已更新: ${updatedCount}`);
- message(` 已跳过: ${skippedCount}`);
- message(` 失败数: ${errorCount}`);
- message(` 干跑模式: ${dryRun ? '是(未实际保存)' : '否(已保存)'}`);
- message('='.repeat(50));
-
- } catch (error) {
- message(`❌ 迁移失败: ${error.message}`);
- throw error;
- }
- });
- /**
- * 测试单个项目的阶段截止时间生成
- *
- * 使用方法:
- * Parse.Cloud.run('testProjectPhaseDeadlines', { projectId: 'xxx' })
- */
- Parse.Cloud.define("testProjectPhaseDeadlines", async (request) => {
- const { projectId } = request.params;
-
- if (!projectId) {
- throw new Error("缺少projectId参数");
- }
-
- const projectQuery = new Parse.Query("Project");
- const project = await projectQuery.get(projectId, { useMasterKey: true });
-
- const deadline = project.get("deadline");
- if (!deadline) {
- throw new Error("项目没有截止时间");
- }
-
- const data = project.get("data") || {};
-
- // 默认工期
- const DEFAULT_DURATIONS = {
- modeling: 1,
- softDecor: 1,
- rendering: 1,
- postProcessing: 1
- };
-
- // 计算阶段截止时间
- const deadlineTime = deadline.getTime();
- const postProcessingDeadline = new Date(deadlineTime);
- const renderingDeadline = new Date(deadlineTime - DEFAULT_DURATIONS.postProcessing * 24 * 60 * 60 * 1000);
- const softDecorDeadline = new Date(deadlineTime - (DEFAULT_DURATIONS.postProcessing + DEFAULT_DURATIONS.rendering) * 24 * 60 * 60 * 1000);
- const modelingDeadline = new Date(deadlineTime - (DEFAULT_DURATIONS.postProcessing + DEFAULT_DURATIONS.rendering + DEFAULT_DURATIONS.softDecor) * 24 * 60 * 60 * 1000);
-
- return {
- projectId: project.id,
- projectTitle: project.get("title"),
- projectDeadline: deadline,
- phaseDeadlines: {
- modeling: {
- deadline: modelingDeadline,
- estimatedDays: DEFAULT_DURATIONS.modeling,
- daysFromNow: Math.ceil((modelingDeadline.getTime() - Date.now()) / (24 * 60 * 60 * 1000))
- },
- softDecor: {
- deadline: softDecorDeadline,
- estimatedDays: DEFAULT_DURATIONS.softDecor,
- daysFromNow: Math.ceil((softDecorDeadline.getTime() - Date.now()) / (24 * 60 * 60 * 1000))
- },
- rendering: {
- deadline: renderingDeadline,
- estimatedDays: DEFAULT_DURATIONS.rendering,
- daysFromNow: Math.ceil((renderingDeadline.getTime() - Date.now()) / (24 * 60 * 60 * 1000))
- },
- postProcessing: {
- deadline: postProcessingDeadline,
- estimatedDays: DEFAULT_DURATIONS.postProcessing,
- daysFromNow: Math.ceil((postProcessingDeadline.getTime() - Date.now()) / (24 * 60 * 60 * 1000))
- }
- },
- currentData: data
- };
- });
|