From b3a1dabf876002bfb5915a7b20247b1c75b6ab3f Mon Sep 17 00:00:00 2001 From: danaisuiyuan Date: Sun, 10 May 2026 15:47:48 +0800 Subject: [PATCH] feat(api): add sign required-article endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GET /api/sign/required_article returns one random article from the "签到广告" article category (status=1, is_del=0, hidden=0). Empty category or no articles returns null so clients can fall through to direct sign-in. Powers the pre-sign-in reading gate per docs/project-shaoyaoju/prd-require.md §6. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../app/controller/api/v1/user/UserSign.php | 23 ++++++++++++++ .../app/services/article/ArticleServices.php | 31 +++++++++++++++++++ pro_v3.5.1/route/api.php | 1 + 3 files changed, 55 insertions(+) diff --git a/pro_v3.5.1/app/controller/api/v1/user/UserSign.php b/pro_v3.5.1/app/controller/api/v1/user/UserSign.php index 2ea336ce..4966829d 100644 --- a/pro_v3.5.1/app/controller/api/v1/user/UserSign.php +++ b/pro_v3.5.1/app/controller/api/v1/user/UserSign.php @@ -6,6 +6,7 @@ namespace app\controller\api\v1\user; use app\Request; +use app\services\article\ArticleServices; use app\services\user\member\MemberCardServices; use app\services\user\UserServices; use app\services\user\UserSignServices; @@ -147,4 +148,26 @@ class UserSign $this->services->setSignRemind($uid, $status); return app('json')->success('设置成功'); } + + /** + * 签到前置阅读:从"签到广告"分类下随机返回一篇文章 + * 分类不存在 / 无文章 时返回 null,前端跳过门槛直接签到 + */ + public function required_article(ArticleServices $articleServices) + { + $article = $articleServices->getRandomByCategoryTitle('签到广告'); + if (!$article) { + return app('json')->successful(null); + } + $img = $article['image_input'] ?? ''; + if (is_array($img)) { + $img = $img[0] ?? ''; + } + return app('json')->successful([ + 'id' => (int)($article['id'] ?? 0), + 'title' => (string)($article['title'] ?? ''), + 'image' => (string)$img, + 'view_required_seconds' => 10, + ]); + } } diff --git a/pro_v3.5.1/app/services/article/ArticleServices.php b/pro_v3.5.1/app/services/article/ArticleServices.php index c917aca9..ed82cadd 100644 --- a/pro_v3.5.1/app/services/article/ArticleServices.php +++ b/pro_v3.5.1/app/services/article/ArticleServices.php @@ -119,6 +119,37 @@ class ArticleServices extends BaseServices return $this->dao->update($id, ['product_id' => $product_id]); } + /** + * 按分类标题获取一条随机文章(用于签到前置阅读门槛) + * @param string $categoryTitle 分类标题(如"签到广告") + * @return array|null id/title/image_input/visit;分类或文章不存在时返回 null + */ + public function getRandomByCategoryTitle(string $categoryTitle) + { + /** @var ArticleCategoryServices $categoryServices */ + $categoryServices = app()->make(ArticleCategoryServices::class); + $cat = $categoryServices->getOne([ + 'title' => $categoryTitle, + 'status' => 1, + 'is_del' => 0, + 'hidden' => 0, + ], 'id'); + if (!$cat) { + return null; + } + $where = ['cid' => (int)$cat['id'], 'status' => 1, 'hide' => 0]; + $ids = $this->dao->getColumn($where, 'id'); + if (!$ids) { + return null; + } + $pickId = (int)$ids[array_rand($ids)]; + $article = $this->dao->getOne(['id' => $pickId], 'id,title,image_input,visit,add_time'); + if (!$article) { + return null; + } + return is_array($article) ? $article : $article->toArray(); + } + /** * 获取数量 * @param array $where diff --git a/pro_v3.5.1/route/api.php b/pro_v3.5.1/route/api.php index fbe1383b..7da50e0a 100644 --- a/pro_v3.5.1/route/api.php +++ b/pro_v3.5.1/route/api.php @@ -275,6 +275,7 @@ Route::group('api', function () { Route::post('sign/integral', 'v1.user.UserSign/sign_integral')->middleware(BlockerMiddleware::class)->name('signIntegral');//签到 Route::get('sign/remind/:status', 'v1.user.UserSign/sign_remind')->name('signRemind');//用户设置签到提醒 Route::get('sign/calendar', 'v1.user.UserSign/sign_calendar')->name('signCalendar');//日历数据 + Route::get('sign/required_article', 'v1.user.UserSign/required_article')->name('signRequiredArticle');//签到前置阅读文章("签到广告"分类随机一条) //优惠券类 Route::post('coupon/receive', 'v1.activity.StoreCoupons/receive')->middleware(BlockerMiddleware::class)->name('couponReceive'); //领取优惠券 Route::post('coupon/receive/batch', 'v1.activity.StoreCoupons/receive_batch')->name('couponReceiveBatch'); //批量领取优惠券