error('mp_user_points_details 缺少 script_id/script_name 字段,请先执行 php artisan migrate'); return 1; } $dryRun = (bool)$this->option('dry-run'); $force = (bool)$this->option('force'); $limit = (int)$this->option('limit'); if ($limit < 0) { $limit = 0; } $type = trim((string)$this->option('type')); $types = in_array($type, ['video', 'image', 'chat'], true) ? [$type] : ['video', 'image', 'chat']; $query = DB::table('mp_user_points_details') ->select('id', 'type', 'task_id', 'charge_info') ->whereIn('type', $types) ->orderBy('id'); if (!$force) { $query->where(function ($q) { $q->whereNull('anime_id') ->orWhereNull('anime_name') ->orWhereNull('script_id') ->orWhere('script_id', 0); }); } $total = (clone $query)->count(); $this->info('待回填明细总数: ' . $total . ($dryRun ? '(dry-run 模式,不更新)' : '')); if ($total <= 0) { return 0; } if ($limit > 0) { $this->info('本次最多处理: ' . $limit . ' 条'); } $scanned = 0; $filled = 0; $skipped = 0; $query->chunkById(self::CHUNK_SIZE, function ($rows) use ($pointsService, $dryRun, $limit, &$scanned, &$filled, &$skipped) { /** @var array 剧本 => 待更新明细ID */ $pending = []; foreach ($rows as $row) { if ($limit > 0 && $scanned >= $limit) { return false; } $scanned++; $chargeInfo = $row->charge_info; if (is_string($chargeInfo)) { $chargeInfo = json_decode($chargeInfo, true); } $chargeInfo = is_array($chargeInfo) ? $chargeInfo : []; $context = $pointsService->resolveScriptContext( $chargeInfo, $row->task_id === null ? null : (int)$row->task_id, (string)$row->type ); if (empty($context['anime_id']) && empty($context['script_id'])) { $skipped++; continue; } $key = (int)$context['anime_id'] . '|' . (string)$context['anime_name'] . '|' . (int)$context['script_id'] . '|' . (string)$context['script_name']; $pending[$key][] = (int)$row->id; } foreach ($pending as $key => $ids) { list($animeId, $animeName, $scriptId, $scriptName) = explode('|', $key, 4); $filled += count($ids); if ($dryRun) { continue; } DB::table('mp_user_points_details')->whereIn('id', $ids)->update([ 'anime_id' => (int)$animeId ?: null, 'anime_name' => $animeName !== '' ? $animeName : null, 'script_id' => (int)$scriptId ?: null, 'script_name' => $scriptName !== '' ? $scriptName : null, ]); } return true; }); $this->info('扫描明细: ' . $scanned . ' 条,可回填: ' . $filled . ' 条,与剧本无关: ' . $skipped . ' 条'); $this->info($dryRun ? 'dry-run 结束,未更新任何数据' : '回填完成'); return 0; } }