validate([ 'import' => ['required', 'file', 'mimes:xlsx,xls', 'max:' . (int) config('company_plan.max_upload_kb', 20480)], 'duplicate_mode' => ['required', 'in:update,skip'], ]); $token = (string) $request->session()->get('company_plan_preview_token', ''); if ($token !== '') { $importer->deletePreview($token); } try { $preview = $importer->preview( $request->file('import'), (int) (company_id() ?: 1), (int) (auth()->id() ?: 0), (string) $request->input('duplicate_mode', 'update'), ); $token = $importer->storePreview($preview); $request->session()->put('company_plan_preview_token', $token); } catch (ValidationException $exception) { return $this->redirectToPage()->withErrors($exception->errors()); } catch (Throwable $exception) { report($exception); return $this->redirectToPage()->with('error', '导入预览失败,请确认 Excel 可正常打开后重试。'); } return $this->redirectToPage()->with('success', sprintf( '已识别“%s”:新增 %s 行,更新 %s 行,跳过 %s 行,异常 %s 行。请确认后导入。', $preview['source_sheet'], number_format($preview['new_count']), number_format($preview['update_count']), number_format($preview['skip_count']), number_format($preview['invalid_count']), )); } public function confirmImport( Request $request, CompanyPlanWorkbookImporter $importer, ): RedirectResponse { $data = $request->validate([ 'preview_token' => ['required', 'string', 'size:40'], 'duplicate_mode' => ['required', 'in:update,skip'], ]); $sessionToken = (string) $request->session()->get('company_plan_preview_token', ''); if ($sessionToken === '' || ! hash_equals($sessionToken, $data['preview_token'])) { return $this->redirectToPage()->with('error', '导入预览已失效,请重新选择文件。'); } try { $result = $importer->confirm( $data['preview_token'], (int) (company_id() ?: 1), (int) (auth()->id() ?: 0), $data['duplicate_mode'], ); $request->session()->forget('company_plan_preview_token'); } catch (ValidationException $exception) { return $this->redirectToPage()->withErrors($exception->errors()); } catch (Throwable $exception) { report($exception); return $this->redirectToPage()->with('error', '公司盘点导入失败,原有数据未改变。请检查文件后重试。'); } return $this->redirectToPage()->with('success', sprintf( '公司盘点导入完成:新增 %s 条,更新 %s 条,跳过 %s 条。', number_format($result['created']), number_format($result['updated']), number_format($result['skipped']), )); } public function cancelImport( Request $request, CompanyPlanWorkbookImporter $importer, ): RedirectResponse { $token = (string) $request->session()->get('company_plan_preview_token', ''); $importer->deletePreview($token); $request->session()->forget('company_plan_preview_token'); return $this->redirectToPage()->with('success', '已取消本次导入,现有公司盘点数据未改变。'); } public function update( Request $request, CompanyPlanRepository $repository, int $row, ): RedirectResponse { $validator = Validator::make($request->all(), [ 'sequence_no' => ['nullable', 'integer', 'min:0', 'max:9999999'], 'company_name' => ['required', 'string', 'max:255'], 'company_type' => ['nullable', 'string', 'max:128'], 'taxpayer_type' => ['nullable', 'string', 'max:128'], 'registered_at' => ['nullable', 'date_format:Y-m-d'], 'business_registration_type' => ['nullable', 'string', 'max:128'], 'unified_social_credit_code' => ['nullable', 'string', 'max:64'], 'plan' => ['nullable', 'string', 'max:64'], 'company_status' => ['nullable', 'string', 'max:64'], 'tax_cancellation' => ['nullable', 'string', 'max:64'], 'business_cancellation' => ['nullable', 'string', 'max:64'], 'bank_cancellation' => ['nullable', 'string', 'max:64'], 'notes' => ['nullable', 'string', 'max:5000'], ]); $data = $validator->validate(); $companyId = (int) (company_id() ?: 1); if ($repository->findForCompany($companyId, $row) === null) { abort(404); } if ($repository->companyNameExists($companyId, (string) $data['company_name'], $row)) { throw ValidationException::withMessages([ 'company_name' => '另一家主体已使用该公司名称,不能产生重复记录。', ]); } $repository->update( $companyId, $row, $data, (int) (auth()->id() ?: 0), ); return back()->with('success', '公司盘点已保存。'); } public function export( Request $request, CompanyPlanRepository $repository, CompanyPlanWorkbookExporter $exporter, ) { $companyId = (int) (company_id() ?: 1); $filters = CompanyPlanPageData::filters($request); $rows = $repository->exportRows($companyId, $filters); $columns = array_values(array_filter( array_map('trim', explode(',', (string) $request->query('columns', ''))), )); return $exporter->download( $rows, $columns, '公司盘点_' . now()->format('Ymd_His') . '.xlsx', ); } public function template(CompanyPlanWorkbookExporter $exporter) { return $exporter->download( [], array_column(CompanyPlanRepository::FIELDS, 'name'), '公司盘点导入模板.xlsx', ); } private function redirectToPage(): RedirectResponse { $query = request()->except(['_token', 'import', 'duplicate_mode', 'preview_token', '_method']); return redirect()->route('business.pages.show', array_filter([ 'section' => 'company-management', 'page' => 'company-plan', ...$query, ], static fn (mixed $value): bool => $value !== null && $value !== '')); } }