validate([ 'file' => ['required', 'file', 'max:2048', 'mimes:png,jpg,jpeg,webp,gif,svg'], ]); $uploaded = $request->file('file'); $ext = strtolower((string) ($uploaded->getClientOriginalExtension() ?: $uploaded->extension() ?: 'png')); $dir = 'competitions/'.$competition->id; $filename = 'logo-'.bin2hex(random_bytes(4)).'.'.$ext; $this->deleteStoredLogos($competition); try { $path = $uploaded->storeAs($dir, $filename, 'public'); } catch (\Throwable $e) { Log::error('competition.logo.store_exception', [ 'competition_id' => $competition->id, 'error' => $e->getMessage(), ]); throw ValidationException::withMessages([ 'file' => ['Logo 保存失败,请稍后重试'], ]); } if (! is_string($path) || $path === '' || $path === '0' || ! Storage::disk('public')->exists($path)) { throw ValidationException::withMessages([ 'file' => ['Logo 保存失败,请稍后重试'], ]); } $url = '/storage/'.$path.'?t='.time(); $this->writeLogoUrl($competition, $url); return response()->json([ 'url' => $url, 'logoUrl' => $url, ]); } public function destroy(Competition $competition): JsonResponse { $this->deleteStoredLogos($competition); $this->writeLogoUrl($competition, ''); return response()->json([ 'url' => '', 'logoUrl' => '', ]); } private function writeLogoUrl(Competition $competition, string $url): void { $branding = is_array($competition->branding_json) ? $competition->branding_json : []; $login = is_array($branding['login'] ?? null) ? $branding['login'] : []; if ($url === '') { unset($login['logoUrl']); } else { $login['logoUrl'] = $url; } if ($login === []) { unset($branding['login']); } else { $branding['login'] = $login; } $competition->branding_json = $branding === [] ? null : $branding; $competition->save(); } private function deleteStoredLogos(Competition $competition): void { $dir = 'competitions/'.$competition->id; $disk = Storage::disk('public'); if (! $disk->exists($dir)) { return; } foreach ($disk->files($dir) as $file) { if (str_starts_with(basename($file), 'logo')) { $disk->delete($file); } } } }