下单时间后面新增「是否种菜订单」列,逐行按(公司 + 标签)匹配财务维护的映射表:命中为是、未命中为否。 - 新表 jst_order_label_planting_rules + 模型 + 缓存服务,导入命令 jst-order-labels:import-planting-rules(读「判断种菜单.xlsx」) - 导出 CSV 同步新增该列,页面/导出同口径 - 本地构建通过;改动/新增 PHP 文件 php -l 通过
147 lines
5.1 KiB
PHP
147 lines
5.1 KiB
PHP
<?php
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use App\Business\JstOrderLabelPlantingRules;
|
||
use Illuminate\Console\Command;
|
||
use Illuminate\Support\Facades\DB;
|
||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||
use Throwable;
|
||
|
||
/**
|
||
* 导入「标签 | 是否种菜订单」映射表,供聚水潭订单标签明细的「是否种菜订单」列使用。
|
||
*/
|
||
class ImportJstOrderLabelPlantingRules extends Command
|
||
{
|
||
protected $signature = 'jst-order-labels:import-planting-rules
|
||
{path : xlsx/csv 文件}
|
||
{--company= : 公司ID(默认使用当前公司或 1)}
|
||
{--sheet=1 : 工作表序号(从 1 开始)或名称}
|
||
{--replace : 先清空该公司已有映射再导入(默认按标签覆盖)}';
|
||
|
||
protected $description = '导入聚水潭订单标签明细的「是否种菜订单」映射表';
|
||
|
||
public function handle(JstOrderLabelPlantingRules $rules): int
|
||
{
|
||
$path = (string) $this->argument('path');
|
||
if (! is_file($path)) {
|
||
$this->error('文件不存在:' . $path);
|
||
|
||
return self::FAILURE;
|
||
}
|
||
|
||
$companyId = (int) ($this->option('company') ?: (function_exists('company_id') && company_id() ? company_id() : 1));
|
||
if ($companyId <= 0) {
|
||
$this->error('公司ID无效,请用 --company 指定。');
|
||
|
||
return self::FAILURE;
|
||
}
|
||
|
||
try {
|
||
$rows = $this->readRows($path);
|
||
} catch (Throwable $e) {
|
||
$this->error('读取失败:' . $e->getMessage());
|
||
|
||
return self::FAILURE;
|
||
}
|
||
|
||
if ($rows === []) {
|
||
$this->error('没有解析到有效数据(需要表头:标签 / 是否种菜订单)。');
|
||
|
||
return self::FAILURE;
|
||
}
|
||
|
||
$now = now();
|
||
DB::transaction(function () use ($rows, $now, $companyId): void {
|
||
if ($this->option('replace')) {
|
||
DB::table('jst_order_label_planting_rules')->where('company_id', $companyId)->delete();
|
||
}
|
||
|
||
foreach (array_chunk($rows, 500) as $chunk) {
|
||
DB::table('jst_order_label_planting_rules')->upsert(
|
||
array_map(static fn (array $row): array => $row + [
|
||
'company_id' => $companyId,
|
||
'created_at' => $now,
|
||
'updated_at' => $now,
|
||
], $chunk),
|
||
['company_id', 'label'],
|
||
['is_planting', 'updated_at'],
|
||
);
|
||
}
|
||
});
|
||
|
||
$rules->forget($companyId);
|
||
|
||
$planting = count(array_filter($rows, static fn (array $row): bool => $row['is_planting'] === '是'));
|
||
|
||
$this->info(sprintf('已导入 %d 条「是否种菜订单」映射(公司 %d):种菜 %d 条,非种菜 %d 条。', count($rows), $companyId, $planting, count($rows) - $planting));
|
||
|
||
return self::SUCCESS;
|
||
}
|
||
|
||
/**
|
||
* @return list<array{label:string,is_planting:string}>
|
||
*/
|
||
private function readRows(string $path): array
|
||
{
|
||
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
|
||
$readerType = match ($extension) {
|
||
'xlsx' => 'Xlsx',
|
||
'xls' => 'Xls',
|
||
'csv' => 'Csv',
|
||
default => throw new \InvalidArgumentException('只支持 xlsx / xls / csv 文件。'),
|
||
};
|
||
|
||
$reader = IOFactory::createReader($readerType);
|
||
$reader->setReadDataOnly(true);
|
||
if ($readerType === 'Csv') {
|
||
$reader->setInputEncoding('UTF-8');
|
||
}
|
||
|
||
$book = $reader->load($path);
|
||
$sheetOption = trim((string) $this->option('sheet'));
|
||
if ($sheetOption !== '' && ctype_digit($sheetOption)) {
|
||
$index = (int) $sheetOption - 1;
|
||
if ($index < 0 || $index >= $book->getSheetCount()) {
|
||
throw new \InvalidArgumentException('工作表序号超出范围:' . $sheetOption);
|
||
}
|
||
$sheet = $book->getSheet($index);
|
||
} else {
|
||
$sheet = $sheetOption === '' ? $book->getActiveSheet() : $book->getSheetByName($sheetOption);
|
||
if ($sheet === null) {
|
||
throw new \InvalidArgumentException('找不到工作表:' . $sheetOption);
|
||
}
|
||
}
|
||
|
||
$rows = [];
|
||
$header = null;
|
||
foreach ($sheet->getRowIterator() as $row) {
|
||
$cells = [];
|
||
$cellIterator = $row->getCellIterator();
|
||
$cellIterator->setIterateOnlyExistingCells(false);
|
||
foreach ($cellIterator as $cell) {
|
||
$cells[] = trim((string) $cell->getValue());
|
||
}
|
||
|
||
if ($header === null) {
|
||
$cells[0] = preg_replace('/^\xEF\xBB\xBF/', '', $cells[0] ?? '');
|
||
$header = $cells;
|
||
continue;
|
||
}
|
||
|
||
$label = trim($cells[0] ?? '');
|
||
$flag = trim($cells[1] ?? '');
|
||
if ($label === '') {
|
||
continue;
|
||
}
|
||
|
||
$rows[] = [
|
||
'label' => mb_substr($label, 0, 191),
|
||
'is_planting' => in_array(mb_strtolower($flag), ['否', 'n', 'no', '0', 'false'], true) ? '否' : '是',
|
||
];
|
||
}
|
||
|
||
return $rows;
|
||
}
|
||
}
|