diff --git a/app/Console/Commands/RefreshCompanyMarketStatus.php b/app/Console/Commands/RefreshCompanyMarketStatus.php new file mode 100644 index 0000000..4f937d8 --- /dev/null +++ b/app/Console/Commands/RefreshCompanyMarketStatus.php @@ -0,0 +1,91 @@ +option('company_id'); + $chunk = (int) $this->option('chunk'); + $chunk = $chunk > 0 ? $chunk : 500; + + $query = Company::query()->orderBy('id'); + + if (!empty($companyId)) { + $query->where('id', $companyId); + } + + $total = (clone $query)->count(); + if ($total == 0) { + return $this->info('没有需要处理的公司'); + } + + $this->info("开始重算 company_market,共 {$total} 家公司"); + $bar = $this->output->createProgressBar($total); + $bar->start(); + + $updatedCount = 0; + $unchangedCount = 0; + $failCount = 0; + + $query->chunkById($chunk, function ($companies) use (&$updatedCount, &$unchangedCount, &$failCount, $bar) { + foreach ($companies as $company) { + try { + $updated = Company::updateMarketStatus($company->id); + + if ($updated) { + $updatedCount++; + $bar->setMessage($company->company_name . ' 已更新', 'status'); + } else { + $unchangedCount++; + $bar->setMessage($company->company_name . ' 无变化', 'status'); + } + } catch (\Throwable $e) { + $failCount++; + $bar->setMessage($company->company_name . ' 失败: ' . $e->getMessage(), 'status'); + } + + $bar->advance(); + } + }); + + $bar->finish(); + $this->newLine(); + $this->info("处理完成:更新 {$updatedCount} 家,未变化 {$unchangedCount} 家,失败 {$failCount} 家"); + + return $this->info('company_market 全量重算完成'); + } +} diff --git a/app/Models/Company.php b/app/Models/Company.php index 778e43a..fde355a 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -73,7 +73,7 @@ class Company extends SoftDeletesModel if ($hasSuzhouOut) { // 苏州市外:排除 company_area 参数接口返回的苏州市内选项,以及虎丘区 $excludeAreas = Parameter::where('number', 'company_area') - ->with(['detail' => fn ($q) => $q->orderBy('sort', 'asc')]) + ->with(['detail' => fn($q) => $q->orderBy('sort', 'asc')]) ->first(); $excludeList = []; if ($excludeAreas && $excludeAreas->detail) { @@ -360,36 +360,29 @@ class Company extends SoftDeletesModel public static function updateMarketStatus($companyId) { $company = Company::find($companyId); - if (!$company || empty($company->company_tag)) { + if (!$company) { return false; } - // 上市代码正则:匹配全球各地上市公司股票代码后缀 - $stockCodePattern = '/\.(SWR|SW|WR|SS|RS|SB|PK|TO|AX|WS|PR|DB|UN|RT|WT|SH|SZ|BJ|TW|HK|SG|US|DE|FR|JP|KR|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|U|V|W|X|Y|Z)(?![A-Za-z0-9])/i'; + if (empty($company->company_tag)) { + $newMarketStatus = 0; - $hasStockCode = preg_match($stockCodePattern, $company->company_tag); + if ($company->company_market != $newMarketStatus) { + $company->company_market = $newMarketStatus; + $company->save(); + return true; + } - // 不属于新三板上市公司的关键字(需要排除) - $excludeXinsanbanKeywords = [ - '新三板摘牌', - '新三板挂牌审核', - '新三板终止', - '新三板退市', - '新三板撤销', - '新三板注销', - '新三板中止', - ]; + return false; + } - // 检查是否包含排除关键字 - $hasExcludeKeyword = array_reduce($excludeXinsanbanKeywords, function ($carry, $keyword) use ($company) { - return $carry || strpos($company->company_tag, $keyword) !== false; - }, false); + // 上市代码正则:匹配全球各地上市公司股票代码后缀 + $stockCodePattern = '/\.(SWR|SW|WR|SS|RS|SB|PK|TO|AX|WS|PR|DB|UN|RT|WT|SH|SZ|BJ|TW|HK|SG|US|DE|FR|JP|KR|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|U|V|W|X|Y|Z)(?![A-Za-z0-9])/i'; - // 检查是否包含"新三板",且不包含排除关键字 - $hasXinsanban = !$hasExcludeKeyword && strpos($company->company_tag, '新三板') !== false; + $hasStockCode = preg_match($stockCodePattern, $company->company_tag); - // 如果匹配到股票代码或包含"新三板"(且非排除关键字),则标记为上市 - $newMarketStatus = ($hasStockCode || $hasXinsanban) ? 1 : 0; + // 仅按股票代码判断上市状态,新三板标签不再计入上市公司 + $newMarketStatus = $hasStockCode ? 1 : 0; // 只有状态变化才更新 if ($company->company_market != $newMarketStatus) {