diff --git a/app/Business/SystemizationTodoWorkbookImporter.php b/app/Business/SystemizationTodoWorkbookImporter.php index e66f5d8d..d3b1e723 100644 --- a/app/Business/SystemizationTodoWorkbookImporter.php +++ b/app/Business/SystemizationTodoWorkbookImporter.php @@ -33,13 +33,18 @@ class SystemizationTodoWorkbookImporter * * @return array{created:int,skipped:int,sheet:string} */ - public function import(string $path, int $companyId, ?int $userId = null): array + public function import( + string $path, + int $companyId, + ?int $userId = null, + ?string $originalName = null, + ): array { if (! is_file($path)) { throw new RuntimeException('找不到待办 Excel 文件。'); } - $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + $extension = $this->extension($path, $originalName); if ($extension !== 'xlsx') { throw new RuntimeException('系统化待办仅支持 .xlsx 文件。'); } @@ -120,13 +125,19 @@ class SystemizationTodoWorkbookImporter * * @return array{created:int,updated:int,retained:int,sheet:string} */ - public function sync(string $path, int $companyId, ?int $userId = null, bool $dryRun = false): array + public function sync( + string $path, + int $companyId, + ?int $userId = null, + bool $dryRun = false, + ?string $originalName = null, + ): array { if (! is_file($path)) { throw new RuntimeException('找不到待办 Excel 文件。'); } - $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + $extension = $this->extension($path, $originalName); if ($extension !== 'xlsx') { throw new RuntimeException('系统化待办仅支持 .xlsx 文件。'); } @@ -721,6 +732,16 @@ class SystemizationTodoWorkbookImporter return trim(str_replace("\u{00A0}", ' ', (string) $value)); } + private function extension(string $path, ?string $originalName): string + { + $name = trim((string) $originalName); + $extension = $name !== '' + ? pathinfo($name, PATHINFO_EXTENSION) + : pathinfo($path, PATHINFO_EXTENSION); + + return strtolower((string) $extension); + } + /** * @return array{0:string|null,1:string} */ diff --git a/app/Http/Controllers/Business/SystemizationTodos.php b/app/Http/Controllers/Business/SystemizationTodos.php index 2205c5ec..f017371b 100644 --- a/app/Http/Controllers/Business/SystemizationTodos.php +++ b/app/Http/Controllers/Business/SystemizationTodos.php @@ -741,6 +741,8 @@ class SystemizationTodos extends Controller $data['source']->getRealPath(), (int) company_id(), user_id(), + false, + $data['source']->getClientOriginalName(), ); } catch (Throwable $exception) { report($exception); diff --git a/tests/Feature/Business/SystemizationTodosTest.php b/tests/Feature/Business/SystemizationTodosTest.php index a21e9fa8..9b7b7213 100644 --- a/tests/Feature/Business/SystemizationTodosTest.php +++ b/tests/Feature/Business/SystemizationTodosTest.php @@ -860,6 +860,53 @@ class SystemizationTodosTest extends FeatureTestCase } } + public function test_uploaded_workbook_uses_original_filename_when_temp_path_has_no_extension(): void + { + $this->loginAs(); + + $sourcePath = sys_get_temp_dir() . '/systemization-upload-source-' . uniqid() . '.xlsx'; + $uploadPath = sys_get_temp_dir() . '/systemization-upload-' . uniqid(); + try { + $this->writeWorkbook($sourcePath, [[ + '收入', + '上传测试', + '浏览器上传的工作簿', + '晨曦', + '栎阳', + '2026-10-27', + '2026-10-30', + null, + null, + ]]); + copy($sourcePath, $uploadPath); + + $upload = new UploadedFile( + $uploadPath, + '10.19工作梳理.xlsx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + null, + true, + ); + + $this->post(route('business.systemization-todos.import'), [ + 'source' => $upload, + ])->assertRedirect() + ->assertSessionHas('success'); + + $this->assertDatabaseHas('business_systemization_todos', [ + 'company_id' => (int) company_id(), + 'title' => '浏览器上传的工作簿', + ]); + $this->assertDatabaseHas('business_systemization_todo_audit_logs', [ + 'company_id' => (int) company_id(), + 'action' => 'import', + ]); + } finally { + @unlink($sourcePath); + @unlink($uploadPath); + } + } + public function test_manual_changes_are_listed_in_operation_history_and_csv(): void { $this->loginAs();