diff --git a/app/Http/Controllers/Admin/BookController.php b/app/Http/Controllers/Admin/BookController.php new file mode 100644 index 0000000..7999ce8 --- /dev/null +++ b/app/Http/Controllers/Admin/BookController.php @@ -0,0 +1,265 @@ +all(); + $list = $this->model->with('cover')->where(function ($query) use ($all) { + if (isset($all['filter']) && !empty($all['filter'])) { + foreach ($all['filter'] as $condition) { + $key = $condition['key'] ?? null; + $op = $condition['op'] ?? null; + $value = $condition['value'] ?? null; + if (!isset($key) || !isset($op) || !isset($value)) { + continue; + } + // 等于 + if ($op == 'eq') { + $query->where($key, $value); + } + // 不等于 + if ($op == 'neq') { + $query->where($key, '!=', $value); + } + // 大于 + if ($op == 'gt') { + $query->where($key, '>', $value); + } + // 大于等于 + if ($op == 'egt') { + $query->where($key, '>=', $value); + } + // 小于 + if ($op == 'lt') { + $query->where($key, '<', $value); + } + // 小于等于 + if ($op == 'elt') { + $query->where($key, '<=', $value); + } + // 模糊搜索 + if ($op == 'like') { + $query->where($key, 'like', '%' . $value . '%'); + } + // 否定模糊搜索 + if ($op == 'notlike') { + $query->where($key, 'not like', '%' . $value . '%'); + } + // 范围搜索 + if ($op == 'range') { + list($from, $to) = explode(',', $value); + if (empty($from) || empty($to)) { + continue; + } + $query->whereBetween($key, [$from, $to]); + } + } + } + })->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc'); + if (isset($all['is_export']) && !empty($all['is_export'])) { + $list = $list->get()->toArray(); + $export_fields = $all['export_fields'] ?? []; + // 导出文件名字 + $tableName = $this->model->getTable(); + $filename = (new CustomForm())->getTableComment($tableName); + return Excel::download(new BaseExport($export_fields, $list, $tableName), $filename . date('YmdHis') . '.xlsx'); + } else { + // 输出 + $list = $list->paginate($all['page_size'] ?? 20); + } + return $this->success($list); + } + + /** + * @OA\Get( + * path="/api/admin/book/show", + * tags={"图书管理"}, + * summary="详情", + * description="", + * @OA\Parameter(name="id", in="query", @OA\Schema(type="string"), required=true, description="id"), + * @OA\Parameter(name="show_relation", in="query", @OA\Schema(type="string"), required=false, description="需要输出的关联关系数组,填写输出指定数据"), + * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), + * @OA\Response( + * response="200", + * description="暂无" + * ) + * ) + */ + public function show() + { + $all = \request()->all(); + $messages = [ + 'id.required' => 'Id必填', + ]; + $validator = Validator::make($all, [ + 'id' => 'required' + ], $messages); + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + $detail = $this->model->with('cover')->find($all['id']); + return $this->success($detail); + } + + /** + * @OA\Post( + * path="/api/admin/book/save", + * tags={"图书管理"}, + * summary="保存图书信息", + * description="根据提供的图书信息进行新增或更新操作", + * @OA\Parameter(name="id", in="query", @OA\Schema(type="integer"), required=false, description="图书ID(存在时更新,不存在时新增)"), + * @OA\Parameter(name="title", in="query", @OA\Schema(type="string"), required=true, description="书名"), + * @OA\Parameter(name="author", in="query", @OA\Schema(type="string"), required=false, description="作者"), + * @OA\Parameter(name="isbn", in="query", @OA\Schema(type="string"), required=false, description="ISBN"), + * @OA\Parameter(name="publisher", in="query", @OA\Schema(type="string"), required=false, description="出版社"), + * @OA\Parameter(name="publish_year", in="query", @OA\Schema(type="string"), required=false, description="出版年份(格式:YYYY)"), + * @OA\Parameter(name="category", in="query", @OA\Schema(type="string"), required=false, description="分类"), + * @OA\Parameter(name="description", in="query", @OA\Schema(type="string"), required=false, description="图书简介"), + * @OA\Parameter(name="cover_id", in="query", @OA\Schema(type="integer"), required=false, description="图书封面ID"), + * @OA\Response( + * response="200", + * description="操作成功" + * ) + * ) + */ + public function save() + { + return parent::save(); + } + + /** + * @OA\Get( + * path="/api/admin/book/destroy", + * tags={"图书管理"}, + * summary="删除", + * description="", + * @OA\Parameter(name="id", in="query", @OA\Schema(type="string"), required=true, description="id"), + * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), + * @OA\Response( + * response="200", + * description="暂无" + * ) + * ) + */ + public function destroy() + { + return parent::destroy(); + } + + + /** + * @OA\Post( + * path="/api/admin/book/excel-show", + * tags={"图书管理"}, + * summary="导入预览", + * description="", + * @OA\Parameter(name="data", in="query", @OA\Schema(type="string"), required=true, description="统一数据键值对数组"), + * @OA\Parameter(name="file", in="query", @OA\Schema(type="string"), required=true, description="文件"), + * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), + * @OA\Response( + * response="200", + * description="暂无" + * ) + * ) + */ + public function excelShow() + { + $file = \request()->file('file'); + $data = \request('data', []); + //判断文件是否有效 + if (!(\request()->hasFile('file') && $file->isValid())) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '文件不存在或无效']); + } + //获取文件大小 + $img_size = floor($file->getSize() / 1024); + if ($img_size >= 50 * 1024) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '文件必须小于50M']); + } + //过滤文件后缀 + $ext = $file->getClientOriginalExtension(); + if (!in_array($ext, ['xls', 'xlsx', 'csv'])) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '仅支持xls/xlsx/csv格式']); + } + $tempFile = $file->getRealPath(); + $dataArray = (new FastExcel)->import($tempFile)->toArray(); + // 数据过滤,只能导入数据表有的字段 + $tableName = $this->model->getTable(); + $rowTableFieldByComment = (new CustomFormField)->getRowTableFieldsByComment($tableName); + $list = []; + foreach ($dataArray as $key => $value) { + foreach ($rowTableFieldByComment as $k => $v) { + if (isset($value[$v])) { + $list[$key][$k] = $value[$v]; + } + } + $list[$key] = array_merge($list[$key], $data); + } + return $this->success($list); + } + + /** + * @OA\Post( + * path="/api/admin/book/import", + * tags={"图书管理"}, + * summary="导入", + * description="", + * @OA\Parameter(name="data", in="query", @OA\Schema(type="string"), required=true, description="导入分析获取到的二维数组"), + * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), + * @OA\Response( + * response="200", + * description="暂无" + * ) + * ) + */ + public function import() + { + return parent::import(); + } + + +} diff --git a/app/Http/Controllers/Mobile/BookController.php b/app/Http/Controllers/Mobile/BookController.php new file mode 100644 index 0000000..c0ce6ca --- /dev/null +++ b/app/Http/Controllers/Mobile/BookController.php @@ -0,0 +1,72 @@ +all(); + $list = Book::where(function ($query) use ($all) { + if (isset($all['keyword'])) { + $query->where(function ($q) use ($all) { + $q->where('title', 'like', '%' . $all['keyword'] . '%') + ->orWhere('author', 'like', '%' . $all['keyword'] . '%') + ->orWhere('isbn', 'like', '%' . $all['keyword'] . '%'); + }); + } + })->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc') + ->paginate($all['page_size'] ?? 20); + return $this->success($list); + } + + /** + * @OA\Get( + * path="/api/mobile/book/detail", + * tags={"小程序-图书"}, + * summary="图书详情", + * @OA\Parameter(name="id", in="query", @OA\Schema(type="integer"), required=true, description="id"), + * @OA\Response( + * response=200, + * description="操作成功" + * ) + * ) + */ + public function detail() + { + $all = \request()->all(); + $messages = [ + 'id.required' => 'Id必填', + ]; + $validator = Validator::make($all, [ + 'id' => 'required' + ], $messages); + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + $book = Book::with('cover')->find($all['id']); + return $this->success($book); + } +} diff --git a/app/Http/Controllers/Mobile/SupplyDemandController.php b/app/Http/Controllers/Mobile/SupplyDemandController.php index ad0ed55..9f0dfd8 100755 --- a/app/Http/Controllers/Mobile/SupplyDemandController.php +++ b/app/Http/Controllers/Mobile/SupplyDemandController.php @@ -12,6 +12,7 @@ use App\Models\Banner; use App\Models\Config; use App\Models\Message; use App\Models\SupplyDemand; +use App\Models\SupplyDemandKeep; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; @@ -83,9 +84,11 @@ class SupplyDemandController extends CommonController if ($validator->fails()) { return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } - $detail = SupplyDemand::with(['user' => function ($query) { - $query->select('id', 'nickname', 'name', 'headimgurl'); - }])->find($all['id']); + $detail = SupplyDemand::with([ + 'user' => function ($query) { + $query->select('id', 'nickname', 'name', 'headimgurl'); + } + ])->find($all['id']); // 增加view_count $detail->increment('view_count'); $detail->save(); @@ -276,11 +279,14 @@ class SupplyDemandController extends CommonController if (empty($model)) { return $this->fail([ResponseCode::ERROR_BUSINESS, '供需数据不存在']); } - $message = Message::with(['user' => function ($query) { - $query->select('id', 'nickname', 'name', 'headimgurl'); - }, 'toUser' => function ($query) { - $query->select('id', 'nickname', 'name', 'headimgurl'); - }])->where(function ($query) use ($all) { + $message = Message::with([ + 'user' => function ($query) { + $query->select('id', 'nickname', 'name', 'headimgurl'); + }, + 'toUser' => function ($query) { + $query->select('id', 'nickname', 'name', 'headimgurl'); + } + ])->where(function ($query) use ($all) { })->where('supply_demand_id', $all['supply_demand_id']) ->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc') @@ -288,4 +294,87 @@ class SupplyDemandController extends CommonController return $this->success(compact('message')); } + /** + * @OA\Get( + * path="/api/mobile/supply-demand/keep-index", + * tags={"小程序-供需"}, + * summary="收藏列表", + * description="", + * @OA\Parameter(name="page_size", in="query", @OA\Schema(type="string"), required=false, description="每页显示的条数"), + * @OA\Parameter(name="page", in="query", @OA\Schema(type="string"), required=false, description="页码"), + * @OA\Parameter(name="sort_name", in="query", @OA\Schema(type="string"), required=false, description="排序字段名字"), + * @OA\Parameter(name="sort_type", in="query", @OA\Schema(type="string"), required=false, description="排序类型"), + * @OA\Response( + * response="200", + * description="暂无" + * ) + * ) + */ + public function keepIndex() + { + $all = request()->all(); + $supplyDemands = SupplyDemandKeep::where('user_id', $this->getUserId()) + ->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc') + ->paginate($all['page_size'] ?? 20); + return $this->success(compact('supplyDemands')); + } + + /** + * @OA\Post( + * path="/api/mobile/supply-demand/keep", + * tags={"小程序-供需"}, + * summary="收藏供需帖子", + * @OA\Parameter(name="supply_demand_id", in="query", @OA\Schema(type="integer"), required=true, description="供需帖子id"), + * @OA\Response(response=200, description="操作成功") + * ) + */ + public function keepSupplyDemand() + { + $all = \request()->all(); + $messages = [ + 'supply_demand_id.required' => '供需信息id必填' + ]; + $validator = Validator::make($all, [ + 'supply_demand_id' => 'required', + ], $messages); + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + $data = [ + 'user_id' => $this->getUserId(), + 'supply_demand_id' => $all['supply_demand_id'] + ]; + SupplyDemandKeep::firstOrCreate($data); + return $this->success('收藏成功'); + } + + /** + * @OA\Post( + * path="/api/mobile/supply-demand/unkeep", + * tags={"小程序-供需"}, + * summary="取消收藏供需帖子", + * @OA\Parameter(name="supply_demand_id", in="query", @OA\Schema(type="integer"), required=true, description="供需帖子id"), + * @OA\Response(response=200, description="操作成功") + * ) + */ + public function unkeepSupplyDemand() + { + $all = \request()->all(); + $messages = [ + 'supply_demand_id.required' => '供需信息id必填' + ]; + $validator = Validator::make($all, [ + 'supply_demand_id' => 'required', + ], $messages); + if ($validator->fails()) { + return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); + } + $keep = SupplyDemandKeep::where('user_id', $this->getUserId())->where('supply_demand_id', $all['supply_demand_id'])->first(); + if (empty($keep)) { + return $this->fail([ResponseCode::ERROR_BUSINESS, '该信息没有收藏']); + } + $keep->delete(); + return $this->success('取消收藏成功'); + } + } diff --git a/app/Models/Book.php b/app/Models/Book.php new file mode 100644 index 0000000..e40fbf0 --- /dev/null +++ b/app/Models/Book.php @@ -0,0 +1,13 @@ +hasOne(Upload::class, 'id', 'cover_id'); + } + +} diff --git a/app/Models/SupplyDemand.php b/app/Models/SupplyDemand.php index ad97423..af24f16 100755 --- a/app/Models/SupplyDemand.php +++ b/app/Models/SupplyDemand.php @@ -14,5 +14,10 @@ class SupplyDemand extends SoftDeletesModel return $this->hasOne(User::class, 'id', 'user_id'); } + public function keeps() + { + return $this->hasMany(SupplyDemandKeep::class, 'supply_demand_id', 'id'); + } + } diff --git a/app/Models/SupplyDemandKeep.php b/app/Models/SupplyDemandKeep.php new file mode 100644 index 0000000..2a19b2f --- /dev/null +++ b/app/Models/SupplyDemandKeep.php @@ -0,0 +1,16 @@ +hasOne(User::class, 'id', 'user_id'); + } + + public function supplyDemand() + { + return $this->hasOne(SupplyDemand::class, 'id', 'supply_demand_id'); + } +} \ No newline at end of file diff --git a/database/migrations/2025_06_23_160000_create_supply_demand_keeps_table.php b/database/migrations/2025_06_23_160000_create_supply_demand_keeps_table.php new file mode 100644 index 0000000..341eebf --- /dev/null +++ b/database/migrations/2025_06_23_160000_create_supply_demand_keeps_table.php @@ -0,0 +1,34 @@ +comment('供需收藏表'); + $table->increments('id'); + $table->integer('user_id')->nullable()->comment('用户id'); + $table->integer('supply_demand_id')->nullable()->comment('供需帖子id'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('supply_demand_keeps'); + } +}; diff --git a/database/migrations/2025_06_23_170000_create_books_table.php b/database/migrations/2025_06_23_170000_create_books_table.php new file mode 100644 index 0000000..89132c1 --- /dev/null +++ b/database/migrations/2025_06_23_170000_create_books_table.php @@ -0,0 +1,40 @@ +comment('图书表'); + $table->increments('id'); + $table->string('title')->comment('书名'); + $table->string('author')->nullable()->comment('作者'); + $table->string('isbn')->nullable()->comment('ISBN'); + $table->string('publisher')->nullable()->comment('出版社'); + $table->year('publish_year')->nullable()->comment('出版年份'); + $table->string('category')->nullable()->comment('分类'); + $table->mediumText('description')->nullable()->comment('图书简介'); + $table->integer('cover_id')->nullable()->comment('图书封面'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('books'); + } +}; diff --git a/routes/api.php b/routes/api.php index 0536cfa..e4c7aef 100755 --- a/routes/api.php +++ b/routes/api.php @@ -172,6 +172,14 @@ Route::group(["namespace" => "Admin", "prefix" => "admin"], function () { Route::post('supply-demand/save', [\App\Http\Controllers\Admin\SupplyDemandController::class, "save"]); Route::get('supply-demand/destroy', [\App\Http\Controllers\Admin\SupplyDemandController::class, "destroy"]); + // 图书管理 + Route::get('book/index', [\App\Http\Controllers\Admin\BookController::class, "index"]); + Route::get('book/show', [\App\Http\Controllers\Admin\BookController::class, "show"]); + Route::post('book/save', [\App\Http\Controllers\Admin\BookController::class, "save"]); + Route::get('book/destroy', [\App\Http\Controllers\Admin\BookController::class, "destroy"]); + Route::post('book/excel-show', [\App\Http\Controllers\Admin\BookController::class, "excelShow"]); + Route::post('book/import', [\App\Http\Controllers\Admin\BookController::class, "import"]); + }); }); @@ -230,9 +238,17 @@ Route::group(["namespace" => "Mobile", "prefix" => "mobile"], function () { Route::get('supply-demand/detail', [\App\Http\Controllers\Mobile\SupplyDemandController::class, "detail"]); Route::get('supply-demand/save', [\App\Http\Controllers\Mobile\SupplyDemandController::class, "save"]); Route::get('supply-demand/destroy', [\App\Http\Controllers\Mobile\SupplyDemandController::class, "destroy"]); - + // 供需信息留言 Route::get('supply-demand/send-message', [\App\Http\Controllers\Mobile\SupplyDemandController::class, "sendMessage"]); Route::get('supply-demand/message-list', [\App\Http\Controllers\Mobile\SupplyDemandController::class, "messageList"]); + // 供需信息收藏 + Route::get('supply-demand/keep-index', [\App\Http\Controllers\Mobile\SupplyDemandController::class, "keepIndex"]); + Route::get('supply-demand/keep', [\App\Http\Controllers\Mobile\SupplyDemandController::class, "keepSupplyDemand"]); + Route::get('supply-demand/unkeep', [\App\Http\Controllers\Mobile\SupplyDemandController::class, "unkeepSupplyDemand"]); + + // 图书前台接口 + Route::get('book/index', [\App\Http\Controllers\Mobile\BookController::class, "index"]); + Route::get('book/detail', [\App\Http\Controllers\Mobile\BookController::class, "detail"]); });