setName('sync_medicine_pinyin_abbr') ->setDescription('回填/刷新药材表 name_pinyin_abbr(需已执行迁移并 composer 安装 overtrue/pinyin)') ->addOption('all', null, Option::VALUE_NONE, '重算全部记录(默认只处理 abbr 为空的)') ->addOption('dry', null, Option::VALUE_NONE, '仅统计/预览,不写入数据库'); } protected function execute(Input $input, Output $output) { if (!class_exists(\Overtrue\Pinyin\Pinyin::class)) { $output->writeln('未检测到 overtrue/pinyin,请在 server 目录执行: composer update'); return 1; } $all = (bool) $input->getOption('all'); $dry = (bool) $input->getOption('dry'); $makeQuery = function () use ($all) { $q = Medicine::order('id', 'asc'); if (!$all) { $q->where('name_pinyin_abbr', ''); } return $q; }; $total = $makeQuery()->count(); if ($total === 0) { $output->writeln('没有需要处理的记录。'); return 0; } $output->writeln(($all ? '模式: 全部重算' : '模式: 仅空 abbr') . ",待处理 {$total} 条" . ($dry ? '(dry-run)' : '')); $updated = 0; $skipped = 0; $makeQuery()->chunk(200, function ($rows) use (&$updated, &$skipped, $dry) { foreach ($rows as $row) { $data = $row instanceof \think\Model ? $row->toArray() : (array) $row; $id = (int) ($data['id'] ?? 0); $name = trim((string) ($data['name'] ?? '')); if ($id <= 0 || $name === '') { ++$skipped; continue; } $abbr = MedicineNameAbbrService::build($name); if ($abbr === '') { ++$skipped; continue; } if ($dry) { ++$updated; continue; } Medicine::where('id', $id)->update([ 'name_pinyin_abbr' => $abbr, 'update_time' => time(), ]); ++$updated; } }); if ($dry) { $output->writeln("[预览] 将写入/覆盖拼音首字母: {$updated} 条,跳过(空名或无法生成): {$skipped} 条"); } else { $output->writeln("完成: 已更新 {$updated} 条,跳过 {$skipped} 条。"); } return 0; } }