From e712030e3e62b50d3d53b67a3e667e1911f9405c Mon Sep 17 00:00:00 2001 From: jsasg <735273025@qq.com> Date: Wed, 21 May 2025 16:59:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=80=E6=94=BEAPI=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/openapi/common.php | 68 +++++++++++++ app/openapi/controller/v1/Article.php | 96 +++++++++++++++++++ app/openapi/controller/v1/ArticleCategory.php | 50 ++++++++++ app/openapi/controller/v1/ProductCategory.php | 3 +- app/openapi/model/ArticleCategoryModel.php | 34 +++++++ app/openapi/model/ArticleModel.php | 40 ++++++++ app/openapi/route/v1.php | 16 ++-- 7 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 app/openapi/controller/v1/Article.php create mode 100644 app/openapi/controller/v1/ArticleCategory.php create mode 100644 app/openapi/model/ArticleCategoryModel.php create mode 100644 app/openapi/model/ArticleModel.php diff --git a/app/openapi/common.php b/app/openapi/common.php index 12436156..e31187a6 100644 --- a/app/openapi/common.php +++ b/app/openapi/common.php @@ -1,2 +1,70 @@ ]+src\s*=\s*([\'"])((?:(?!\1).)*)\1[^>]*>/i', + function($matches) { + $src = $matches[2]; + if (!empty($src) && !str_starts_with($src, 'http')) { + // 保留原始标签,只替换src属性 + return str_replace($src, image_domain_concat($src), $matches[0]); + } + return $matches[0]; + }, + $html + ); + } +} diff --git a/app/openapi/controller/v1/Article.php b/app/openapi/controller/v1/Article.php new file mode 100644 index 00000000..72cafb37 --- /dev/null +++ b/app/openapi/controller/v1/Article.php @@ -0,0 +1,96 @@ +get([ + 'category_id', + 'language' => 'zh-cn', + 'page/d' => 1, + 'size/d' => 50 + ]); + + if ($params['size'] > 200) { + // 每页不超过200条 + $params['size'] = 200; + } + + $articles = ArticleModel::with([ + 'category' => fn($query) => $query->field('id, name') + ]) + ->field([ + 'id', + 'language_id', + 'category_id', + 'title', + 'desc', + 'image', + 'deleted_at' + ]) + ->categoryId($params['category_id']??null) + ->language($params['language']??'zh-cn') + ->hidden(['language_id', 'category_id']) + ->paginate([ + 'list_rows' => $params['size'], + 'page' => $params['page'] + ]) + ->each(function($it) { + if (!empty($it['image']) && !str_starts_with($it['image'], 'http')) { + $it['image'] = image_domain_concat($it['image']); + } + + return $it; + }); + + return success('success', $articles); + } + + /** + * 文章详情 + */ + public function detail() + { + $id = request()->param('id'); + + $article = ArticleModel::with([ + 'category' => fn($query) => $query->field('id, name') + ]) + ->withoutField([ + 'language_id', + 'seo_title', + 'seo_keywords', + 'seo_desc', + 'created_at', + 'updated_at', + 'deleted_at' + ]) + ->bypk($id) + ->hidden(['category_id']) + ->find(); + + if (is_null($article)) { + return error('the article does not exist'); + } + + // 图片处理 + if (!empty($article['image']) && !str_starts_with($article['image'], 'http')) { + $article['image'] = image_domain_concat($article['image']); + } + + // 详情中图片处理 + if (!empty($article['content'])) { + $article['content'] = html_image_replace($article['content']); + } + + return success('success', $article); + } +} diff --git a/app/openapi/controller/v1/ArticleCategory.php b/app/openapi/controller/v1/ArticleCategory.php new file mode 100644 index 00000000..42d65b8e --- /dev/null +++ b/app/openapi/controller/v1/ArticleCategory.php @@ -0,0 +1,50 @@ +get([ + 'parent_id', + 'language' => 'zh-cn', + 'page/d' => 1, + 'size/d' => 50 + ]); + + if ($params['size'] > 200) { + // 每页不超过200条 + $params['size'] = 200; + } + + $categories = ArticleCategoryModel::withoutField([ + 'language_id', + 'unique_label', + 'created_at', + 'updated_at', + ]) + ->language($params['language']??'zh-cn') + ->parent($params['parent_id']??null) + ->order(['sort' => 'asc', 'id' => 'desc']) + ->paginate([ + 'list_rows' => $params['size'], + 'page' => $params['page'], + ]) + ->each(function($item) { + if (!empty($item['icon']) && !str_starts_with($item['icon'], 'http')){ + $item['icon'] = image_domain_concat($item['icon']); + } + + return $item; + }); + + return success('success', $categories); + } +} diff --git a/app/openapi/controller/v1/ProductCategory.php b/app/openapi/controller/v1/ProductCategory.php index 98722c89..183d7d1e 100644 --- a/app/openapi/controller/v1/ProductCategory.php +++ b/app/openapi/controller/v1/ProductCategory.php @@ -29,8 +29,7 @@ class ProductCategory 'unique_id', 'related_tco_category', 'created_at', - 'updated_at', - 'deleted_at' + 'updated_at' ]) ->language($params['language']??'zh-cn') ->parent($params['parent_id']??null) diff --git a/app/openapi/model/ArticleCategoryModel.php b/app/openapi/model/ArticleCategoryModel.php new file mode 100644 index 00000000..d10d8f02 --- /dev/null +++ b/app/openapi/model/ArticleCategoryModel.php @@ -0,0 +1,34 @@ +whereExists(function($subquery) use($language) { + $lang_model = new LanguageModel; + $subquery->model($lang_model) + ->name($lang_model->getName()) + ->field(['id']) + ->where('id', '=', Db::raw($this->getTable() . '.language_id')) + ->where('code', '=', $language); + }); + } + + // 所属上级分类范围查询 + public function scopeParent($query, $parent_id) + { + if (is_null($parent_id)) return; + $query->where('pid', '=', $parent_id); + } +} diff --git a/app/openapi/model/ArticleModel.php b/app/openapi/model/ArticleModel.php new file mode 100644 index 00000000..3a78374f --- /dev/null +++ b/app/openapi/model/ArticleModel.php @@ -0,0 +1,40 @@ +belongsTo(ArticleCategoryModel::class, 'category_id', 'id'); + } + + // 所属语言范围查询 + public function scopeLanguage($query, $language = 'zh-cn') + { + $query->whereExists(function($subquery) use($language) { + $lang_model = new LanguageModel; + $subquery->model($lang_model) + ->name($lang_model->getName()) + ->field(['id']) + ->where('id', '=', Db::raw($this->getTable() . '.language_id')) + ->where('code', '=', $language); + }); + } + + // 所属分类范围查询 + public function scopeCategoryId($query, $category_id) + { + if (is_null($category_id)) return; + $query->where('category_id', '=', $category_id); + } +} diff --git a/app/openapi/route/v1.php b/app/openapi/route/v1.php index 1c5fc6b7..63ed4d95 100644 --- a/app/openapi/route/v1.php +++ b/app/openapi/route/v1.php @@ -18,11 +18,14 @@ Route::group('v1', function() { Route::get('categories', 'v1.ProductCategory/list'); }); - // 获取新闻动态 - Route::get('news', 'v1.News/list'); - Route::group('news', function() { - // 获取新闻详情 - Route::get(':id', 'v1.News/detail'); + // 获取文章动态 + Route::get('articles', 'v1.Article/list'); + Route::group('article', function() { + // 获取文章详情 + Route::get(':id', 'v1.Article/detail')->when('id', 'number'); + + // 获取文章分类 + Route::get('categories', 'v1.ArticleCategory/list'); }); }) ->middleware(\app\openapi\middleware\Auth::class); @@ -32,4 +35,5 @@ Route::group('v1', function() { 'visit_fail_response' => function (\think\middleware\Throttle $throttle, \think\Request $request, int $wait_seconds) { return \think\Response::create('您的操作过于频繁, 请在 ' . $wait_seconds . ' 秒后再试。')->code(429); }, -]); \ No newline at end of file +]) +->completeMatch(true); \ No newline at end of file