ossSignedUrl($objectKey); $ret = ExcelReader::readSheetFromUrl($signedUrl, $sheet, $headerRow, $startRow); return $ret['rows'] ?? []; } /** * 使用你的 OssService 生成私有签名 URL * - 兼容你的现有写法:(new \app\common\service\OssService)->generatePrivateUrl($objectKey) */ protected function ossSignedUrl(string $objectKey): string { return (new \app\common\service\OssService())->generatePrivateUrl($objectKey); } /** * 将一行做字段映射 + 基础类型规范化(decimal/bool/date) * - $headerMap:表头映射(源列名 => 目标字段名) * - $decimalFields/$boolFields/$dateFields:需要做类型规范化的目标字段名列表 */ protected function mapAndNormalizeRow( array $row, array $headerMap, array $decimalFields = [], array $boolFields = [], array $dateFields = [] ): array { $rec = ExcelReader::remap($row, $headerMap); foreach ($decimalFields as $f) { if (array_key_exists($f, $rec)) { $rec[$f] = ExcelReader::toDecimal($rec[$f]); // 建议已升级为“去货币符号/千分位/括号负数”的版本 } } foreach ($boolFields as $f) { if (array_key_exists($f, $rec)) { $rec[$f] = ExcelReader::toBool($rec[$f]); } } foreach ($dateFields as $f) { if (array_key_exists($f, $rec)) { $rec[$f] = ExcelReader::toDate($rec[$f]); } } return $rec; } /** * 基于 VIN 的跳过规则:VIN 为空、或是“合计/总计”行 * - $vinAliases:VIN 列的候选表头(如 ['车架号','VIN NO']) */ protected function shouldSkipByVinAliases(array $row, array $vinAliases = ['车架号', 'VIN NO']): bool { $vin = $this->pickFirstNonEmpty($row, $vinAliases); if ($vin === null) return true; return (bool)preg_match('/^(合计|总计)/u', $vin); } /** * 在多个候选键里取第一个非空字符串 */ protected function pickFirstNonEmpty(array $row, array $keys): ?string { foreach ($keys as $k) { if (isset($row[$k])) { $v = trim((string)$row[$k]); if ($v !== '') return $v; } } return null; } /** * 统一补齐 created_at / updated_at 时间戳(int(11)) */ protected function stamp(array &$rec): void { $now = time(); $rec['created_at'] = $now; $rec['updated_at'] = $now; } /** * 批量入库 * - 返回 ['inserted'=>N, 'error'=>null|string] * - 发生异常时不抛出,返回 error 字符串,便于上层统一处理 */ protected function batchInsert(string $table, array $rows): array { if (!$rows) return ['inserted' => 0, 'error' => null]; try { Db::table($table)->insert($rows); return ['inserted' => count($rows), 'error' => null]; } catch (\Throwable $e) { return ['inserted' => 0, 'error' => $e->getMessage()]; } } }