diff --git a/app/Console/Commands/UpdateBookIsbnData.php b/app/Console/Commands/UpdateBookIsbnData.php new file mode 100644 index 0000000..d715eaa --- /dev/null +++ b/app/Console/Commands/UpdateBookIsbnData.php @@ -0,0 +1,239 @@ +where('isbn', '!=', '') + ->whereNull('cover_id') + ->get(); + + if ($books->isEmpty()) { + $this->info('没有找到未处理封面的书籍'); + return 0; + } + + $this->info("找到 {$books->count()} 本书需要处理"); + + $bar = $this->output->createProgressBar($books->count()); + $bar->start(); + + $successCount = 0; + $failCount = 0; + + foreach ($books as $book) { + try { + $result = $this->processBook($book, $apiKey); + if ($result) { + $successCount++; + $this->line("\n✓ 成功处理书籍: {$book->title} (ISBN: {$book->isbn})"); + } else { + $failCount++; + $this->line("\n✗ 处理失败: {$book->title} (ISBN: {$book->isbn})"); + } + } catch (\Exception $e) { + $failCount++; + $this->line("\n✗ 处理异常: {$book->title} - {$e->getMessage()}"); + } + + $bar->advance(); + + // 添加延迟避免API请求过快 + sleep(1); + } + + $bar->finish(); + + $this->line(''); + $this->info("处理完成!成功: {$successCount}, 失败: {$failCount}"); + + return 0; + } + + /** + * 处理单本书籍 + * + * @param Book $book + * @param string $apiKey + * @return bool + */ + private function processBook(Book $book, string $apiKey): bool + { + // 调用ISBN接口 + $response = Http::timeout(30)->get('https://api.tanshuapi.com/api/isbn/v2/index', [ + 'key' => $apiKey, + 'isbn' => $book->isbn + ]); + + if (!$response->successful()) { + $this->error("API请求失败: HTTP {$response->status()}"); + return false; + } + + $data = $response->json(); + + if (!$data || $data['code'] !== 1) { + $this->error("API返回错误: " . ($data['msg'] ?? '未知错误')); + return false; + } + + $bookData = $data['data']; + + // 更新书籍的other_data字段 + $book->other_data = $bookData; + + // 如果有图片URL,下载图片 + if (!empty($bookData['img'])) { + $coverId = $this->downloadAndSaveImage($bookData['img'], $book); + if ($coverId) { + $book->cover_id = $coverId; + } + } + + $book->save(); + + return true; + } + + /** + * 下载图片并保存到本地 + * + * @param string $imageUrl + * @param Book $book + * @return int|null + */ + private function downloadAndSaveImage(string $imageUrl, Book $book): ?int + { + try { + // 下载图片 + $response = Http::timeout(30)->get($imageUrl); + + if (!$response->successful()) { + $this->error("图片下载失败: {$imageUrl}"); + return null; + } + + $imageContent = $response->body(); + + // 获取文件扩展名 + $extension = $this->getImageExtension($imageUrl, $response->header('Content-Type')); + + // 生成文件名 + $filename = 'book_cover_' . $book->id . '_' . time() . '.' . $extension; + + // 定义存储目录 + $folder = 'uploads/book_covers/' . date('Y/m'); + + // 确保目录存在 + $fullPath = public_path($folder); + if (!file_exists($fullPath)) { + mkdir($fullPath, 0755, true); + } + + // 保存文件 + $filePath = $folder . '/' . $filename; + file_put_contents(public_path($filePath), $imageContent); + + // 获取文件大小 + $fileSize = strlen($imageContent); + + // 创建uploads记录 + $upload = Upload::create([ + 'belongs_type' => 'App\\Models\\Book', + 'belongs_id' => $book->id, + 'original_name' => basename($imageUrl), + 'folder' => $folder, + 'name' => $filename, + 'extension' => $extension, + 'size' => $fileSize, + 'creator_type' => 'console', + 'creator_id' => null, + ]); + + return $upload->id; + + } catch (\Exception $e) { + $this->error("保存图片时出错: {$e->getMessage()}"); + return null; + } + } + + /** + * 获取图片扩展名 + * + * @param string $url + * @param string|null $contentType + * @return string + */ + private function getImageExtension(string $url, ?string $contentType = null): string + { + // 首先尝试从URL获取扩展名 + $pathInfo = pathinfo(parse_url($url, PHP_URL_PATH)); + if (!empty($pathInfo['extension'])) { + return strtolower($pathInfo['extension']); + } + + // 从Content-Type获取扩展名 + if ($contentType) { + $mimeToExt = [ + 'image/jpeg' => 'jpg', + 'image/jpg' => 'jpg', + 'image/png' => 'png', + 'image/gif' => 'gif', + 'image/webp' => 'webp', + 'image/bmp' => 'bmp', + ]; + + $contentType = strtolower(trim(explode(';', $contentType)[0])); + if (isset($mimeToExt[$contentType])) { + return $mimeToExt[$contentType]; + } + } + + // 默认返回jpg + return 'jpg'; + } +} diff --git a/app/Http/Controllers/Mobile/SupplyDemandController.php b/app/Http/Controllers/Mobile/SupplyDemandController.php index a7ae109..b6a276f 100755 --- a/app/Http/Controllers/Mobile/SupplyDemandController.php +++ b/app/Http/Controllers/Mobile/SupplyDemandController.php @@ -53,7 +53,9 @@ class SupplyDemandController extends CommonController $query->select('id', 'nickname', 'name', 'headimgurl', 'username'); } ])->where(function ($query) use ($all, $status) { - $query->where('status', $status); + if($status){ + $query->where('status', $status); + } if (isset($all['type'])) { $query->where('type', $all['type']); } diff --git a/app/Models/Book.php b/app/Models/Book.php index e40fbf0..6ea9e2c 100644 --- a/app/Models/Book.php +++ b/app/Models/Book.php @@ -4,6 +4,7 @@ namespace App\Models; class Book extends SoftDeletesModel { + protected $casts = ['other_data' => 'json']; public function cover() { diff --git a/database/migrations/2025_06_23_170000_create_books_table.php b/database/migrations/2025_06_23_170000_create_books_table.php index 18f611c..587d950 100644 --- a/database/migrations/2025_06_23_170000_create_books_table.php +++ b/database/migrations/2025_06_23_170000_create_books_table.php @@ -26,6 +26,7 @@ return new class extends Migration { $table->mediumText('description')->nullable()->comment('图书简介'); $table->integer('cover_id')->nullable()->comment('图书封面'); $table->tinyInteger('status')->default(0)->comment('状态0可借阅1已借出2维护中'); + $table->json('other_data')->nullable()->comment('其他数据'); $table->timestamps(); $table->softDeletes(); });