diff --git a/app/apis/controller/ArticleController.php b/app/apis/controller/ArticleController.php new file mode 100644 index 0000000..f20f9a5 --- /dev/null +++ b/app/apis/controller/ArticleController.php @@ -0,0 +1,107 @@ +generatePrivateUrl($item['cover']); + } + foreach ($item['comment'] as &$comment) { + + if ($comment['avatar']) { + $comment['avatar_full'] = (new \app\mzl\modules\upload\service\OssService())->generatePrivateUrl($comment['avatar']); + } + } + unset($comment); + } + + + return $item; + } + + /** + * 参数预处理 (根据场景处理) + * @param Request $request + * @param string $scene + * @return array + */ + protected function prepareParams(Request $request, string $scene): array + { + $params = parent::prepareParams($request, $scene); + + if ($scene === 'default') { + $params['filters'] = []; + $params['filters'][] = ['field' => 'status', 'operator' => '=', 'value' => 1]; + $params['filters'][] = ['field' => 'locale', 'operator' => '=', 'value' => locale()]; + + } + + return $params; + } + + /** + * 分页 + * + * @param Request $request 请求对象 + * @return Response 响应对象 + */ + public function index(Request $request, string $scene = 'default'): Response + { + try { + return parent::index($request, $scene); + } catch (\Throwable $th) { + return $this->errorResponse($th->getMessage()); + } + } + + public function detail(Request $request, int $id, string $scene = 'show'): Response + { + try { + $request->setGet(['id'=>$id]); + return parent::one($request, $scene); + } catch (\Throwable $th) { + return $this->errorResponse($th->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/apis/controller/CommentController.php b/app/apis/controller/CommentController.php new file mode 100644 index 0000000..12c3dda --- /dev/null +++ b/app/apis/controller/CommentController.php @@ -0,0 +1,81 @@ +errorResponse($th->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/apis/model/ArticleModel.php b/app/apis/model/ArticleModel.php new file mode 100644 index 0000000..e5254dc --- /dev/null +++ b/app/apis/model/ArticleModel.php @@ -0,0 +1,56 @@ + function ($params) { + return [ + 'filters' => $params['filters'], + 'fields' => ['id', 'locale', 'title', 'subtitle', 'cover', 'content', 'user_id', 'is_top', 'sort', 'status', 'publish_time', 'created_at', 'updated_at'], + 'relations' => [ + 'creater' => ['id', 'nickname',], + 'comment' => ['id', 'article_id', 'content', 'avatar', 'name',], +// 'translation' => ['model_id', 'name'], +// 'brand.translation' => ['brand_id', 'name'] + ], + 'sorts' => [ + ['field' => 'is_top', 'direction' => 'desc'], + ['field' => 'sort', 'direction' => 'desc'], + ['field' => 'publish_time', 'direction' => 'desc'], + ], + 'pagination' => [ + 'page' => $params['page'] ?? 1, + 'per_page' => $params['per_page'] ?? 10, + ] + ]; + }, + 'show' => function ($params) { + return [ + 'filters' => [ + ['field' => 'status', 'operator' => '=', 'value' => '1'], + ['field' => 'id', 'operator' => '=', 'value' => $params['id']] + ], + 'fields' => ['id', 'locale', 'title', 'subtitle', 'cover', 'content', 'user_id', 'is_top', 'sort', 'status', 'publish_time', 'created_at', 'updated_at'], + 'relations' => [ + 'comment' => ['id', 'article_id', 'content', 'avatar', 'name',], +// 'translation' => ['model_id', 'name'] + ], + ]; + } + ]; + } +} \ No newline at end of file diff --git a/app/apis/service/CommentService.php b/app/apis/service/CommentService.php new file mode 100644 index 0000000..f9abe2b --- /dev/null +++ b/app/apis/service/CommentService.php @@ -0,0 +1,59 @@ + function ($params) { + // $keyword = $params['keyword'] ?? ''; + // return [ + // 'filters' => [ + // ['field' => '***', 'operator' => '=', 'value' => '***'] + // ], + // 'fields' => ['id'], + // 'relations' => [], + // 'custom' => function(Builder $q) use ($keyword) { + // // 示例 + // if ($keyword) { + // $q->where(function($q2) use($keyword) { + // $q2->whereHas('***', function($q3) use($keyword) { + // $q3->where('***', 'like', "%{$keyword}%"); + // })->orWhereHas('***', function($q4) use($keyword) { + // $q4->where('***', 'like', "%{$keyword}%"); + // }); + // }); + // } + // }, + // 'sorts' => [ + // ['field' => 'created_at', 'direction' => 'desc'] + // ], + // 'pagination' => [ + // 'page' => $params['page'] ?? 1, + // 'per_page' => $params['per_page'] ?? 10, + // ] + // ]; + // } + ]; + } +} \ No newline at end of file diff --git a/app/apis/validate/ArticleValidator.php b/app/apis/validate/ArticleValidator.php new file mode 100644 index 0000000..947e633 --- /dev/null +++ b/app/apis/validate/ArticleValidator.php @@ -0,0 +1,29 @@ + [ + + ], + + 'update' => [ + + ] + ]; +} \ No newline at end of file diff --git a/app/apis/validate/CommentValidator.php b/app/apis/validate/CommentValidator.php new file mode 100644 index 0000000..732e7de --- /dev/null +++ b/app/apis/validate/CommentValidator.php @@ -0,0 +1,29 @@ + [ + + ], + + 'update' => [ + + ] + ]; +} \ No newline at end of file diff --git a/app/console/controller/ArticleController.php b/app/console/controller/ArticleController.php index 56e8262..ea04b21 100644 --- a/app/console/controller/ArticleController.php +++ b/app/console/controller/ArticleController.php @@ -46,7 +46,13 @@ class ArticleController extends BaseController if ($item['cover']) { $item['cover_full'] = (new \app\mzl\modules\upload\service\OssService())->generatePrivateUrl($item['cover']); } + foreach ($item['comment'] as &$comment) { + if ($comment['avatar']) { + $comment['avatar_full'] = (new \app\mzl\modules\upload\service\OssService())->generatePrivateUrl($comment['avatar']); + } + } + unset($comment); } return $item; diff --git a/app/console/controller/CommentController.php b/app/console/controller/CommentController.php new file mode 100644 index 0000000..743640b --- /dev/null +++ b/app/console/controller/CommentController.php @@ -0,0 +1,81 @@ +errorResponse($th->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/console/model/ArticleModel.php b/app/console/model/ArticleModel.php index d09cd5b..bc66b41 100644 --- a/app/console/model/ArticleModel.php +++ b/app/console/model/ArticleModel.php @@ -54,6 +54,11 @@ class ArticleModel extends Model */ protected $guarded = []; + public function comment() + { + return $this->hasMany(CommentModel::class, 'article_id', 'id'); + } + public function creater() { return $this->belongsTo(AdminsModel::class, 'user_id','id'); diff --git a/app/console/model/CommentAvatarModel.php b/app/console/model/CommentAvatarModel.php new file mode 100644 index 0000000..a245900 --- /dev/null +++ b/app/console/model/CommentAvatarModel.php @@ -0,0 +1,56 @@ + ['id', 'locale', 'title', 'subtitle', 'cover', 'content', 'user_id', 'is_top', 'sort', 'status', 'publish_time', 'created_at', 'updated_at'], 'relations' => [ 'creater' => ['id', 'nickname',], + 'comment' => ['id', 'article_id', 'content', 'avatar', 'name',], // 'translation' => ['model_id', 'name'], // 'brand.translation' => ['brand_id', 'name'] ], @@ -56,6 +57,7 @@ class ArticleService extends BaseService ], 'fields' => ['id', 'locale', 'title', 'subtitle', 'cover', 'content', 'user_id', 'is_top', 'sort', 'status', 'publish_time', 'created_at', 'updated_at'], 'relations' => [ + 'comment' => ['id', 'article_id', 'content', 'avatar', 'name',], // 'translation' => ['model_id', 'name'] ], ]; @@ -71,6 +73,8 @@ class ArticleService extends BaseService }else{ $params['publish_time'] = time(); } + $num = $params['num'] ?? 0; + unset($params['num']); Db::beginTransaction(); try { @@ -79,6 +83,10 @@ class ArticleService extends BaseService throw new BusinessException('提交失败'); } + if($num > 0){ + CommentService::createComment($info->id,$params['content'],$num); + } + Db::commit(); return true; } catch (\Throwable $th) { @@ -91,6 +99,8 @@ class ArticleService extends BaseService { $params['locale'] = locale(); $params['publish_time'] = strtotime($params['publish_time']); + $num = $params['num'] ?? 0; + unset($params['num']); Db::beginTransaction(); try { @@ -99,6 +109,9 @@ class ArticleService extends BaseService throw new BusinessException('提交失败'); } + if($num > 0){ + CommentService::createComment($id,$params['content'],$num); + } Db::commit(); return true; } catch (\Throwable $th) { diff --git a/app/console/service/CommentService.php b/app/console/service/CommentService.php new file mode 100644 index 0000000..3ee8eea --- /dev/null +++ b/app/console/service/CommentService.php @@ -0,0 +1,85 @@ + function ($params) { + // $keyword = $params['keyword'] ?? ''; + // return [ + // 'filters' => [ + // ['field' => '***', 'operator' => '=', 'value' => '***'] + // ], + // 'fields' => ['id'], + // 'relations' => [], + // 'custom' => function(Builder $q) use ($keyword) { + // // 示例 + // if ($keyword) { + // $q->where(function($q2) use($keyword) { + // $q2->whereHas('***', function($q3) use($keyword) { + // $q3->where('***', 'like', "%{$keyword}%"); + // })->orWhereHas('***', function($q4) use($keyword) { + // $q4->where('***', 'like', "%{$keyword}%"); + // }); + // }); + // } + // }, + // 'sorts' => [ + // ['field' => 'created_at', 'direction' => 'desc'] + // ], + // 'pagination' => [ + // 'page' => $params['page'] ?? 1, + // 'per_page' => $params['per_page'] ?? 10, + // ] + // ]; + // } + ]; + } + + public static function createComment($articleId, $articleContent, $num): array + { + + for ($i = 1; $i <= $num; $i++) { + // 生成模拟用户 + $user = \app\mzl\common\utils\ForeignUserGenerator::generateRandomName(); + $user['avatar'] = \app\mzl\common\utils\ForeignUserGenerator::generateAvatar(); + + // 调用讯飞星火生成评论内容 + $param = [['role' => 'user', 'content' => $articleContent]]; + $commentContent = \app\mzl\common\org\XunfeiSpark::comment($param); + + // 存入数据库 + $comment = new \app\console\model\CommentModel(); + $comment->content = $commentContent; + $comment->article_id = $articleId; + $comment->name = $user['name'] ?? 'Anonymous user'; + $comment->avatar = $user['avatar'] ?? ''; + $comment->save(); + } + + return $comment->toArray(); + } + +} \ No newline at end of file diff --git a/app/console/validate/CommentValidator.php b/app/console/validate/CommentValidator.php new file mode 100644 index 0000000..f514ca3 --- /dev/null +++ b/app/console/validate/CommentValidator.php @@ -0,0 +1,29 @@ + [ + + ], + + 'update' => [ + + ] + ]; +} \ No newline at end of file diff --git a/app/mzl/common/utils/ForeignUserGenerator.php b/app/mzl/common/utils/ForeignUserGenerator.php index 659781a..c8cc13d 100644 --- a/app/mzl/common/utils/ForeignUserGenerator.php +++ b/app/mzl/common/utils/ForeignUserGenerator.php @@ -2,6 +2,8 @@ namespace app\mzl\common\utils; +use app\console\model\CommentAvatarModel; + class ForeignUserGenerator { // 阿拉伯男性名字(迪拜) @@ -187,83 +189,14 @@ class ForeignUserGenerator } /** - * 生成真人风格头像(使用本地服务) - * - * 组合使用以下服务: - * 1. 随机用户API获取基础头像 - * 2. 使用ImageMagick进行本地处理增强真实感 + * 从hs_comment_avatar随机获取头像 */ - public static function generateAvatar(string $gender = 'random', string $ethnicity = 'random'): string + public static function generateAvatar(): string { - // 获取基础头像 - $baseAvatar = self::getRandomUserAvatar(); - - if (!$baseAvatar) { - // 如果API不可用,使用备用方法 - return self::generateFallbackAvatar($gender, $ethnicity); - } - - // 增强头像真实感 - return self::enhanceAvatar($baseAvatar); + $avatar = CommentAvatarModel::query()->inRandomOrder()->value('avatar'); + return $avatar ?: ''; } - /** - * 从随机用户API获取基础头像 - */ - private static function getRandomUserAvatar(): ?string - { - $nationalities = ['gb', 'fr', 'de', 'es', 'ir', 'tr', 'us', 'ca']; - $nationality = $nationalities[array_rand($nationalities)]; - - $url = "https://randomuser.me/api/?nat={$nationality}&inc=picture"; - - try { - $response = file_get_contents($url); - $data = json_decode($response, true); - - if (isset($data['results'][0]['picture']['large'])) { - return $data['results'][0]['picture']['large']; - } - } catch (Exception $e) { - // 记录错误或忽略 - } - - return null; - } - - /** - * 增强头像真实感 - */ - private static function enhanceAvatar(string $imageUrl): string - { - // 下载图像 - $imageData = file_get_contents($imageUrl); - $tempInput = tempnam(sys_get_temp_dir(), 'avatar') . '.jpg'; - file_put_contents($tempInput, $imageData); - - // 创建输出文件名 - $outputFile = 'avatars/' . uniqid('enhanced_') . '.jpg'; - - // 清理临时文件 - unlink($tempInput); - - return $outputFile; - } - - /** - * 备用头像生成方法 - */ - private static function generateFallbackAvatar(string $gender, string $ethnicity): string - { - // 使用ThisPersonDoesNotExist服务 - $url = 'https://thispersondoesnotexist.com/'; - $imageData = file_get_contents($url); - - $outputFile = 'avatars/' . uniqid('fallback_') . '.jpg'; - file_put_contents($outputFile, $imageData); - - return $outputFile; - } /** * 批量生成用户数据 diff --git a/config/route.php b/config/route.php index 8922cfa..2b757b7 100644 --- a/config/route.php +++ b/config/route.php @@ -54,6 +54,10 @@ Route::group('/apis', function() { Route::any('/vehicle/new/sku/list', [\app\apis\controller\VehicleNewSkusController::class, 'index']); // 能源列表 Route::any('/energy/preset', [\app\console\controller\EnergyController::class, 'presets']); + + //文章列表 + Route::any('/article/list', [\app\console\controller\ArticleController::class, 'index']); + Route::any('/article/{id}/detail', [\app\console\controller\ArticleController::class, 'detail']); }); // ====== ====== ====== 网站 ====== ====== ======