From 0ad27898cf31dcfca8384e8087000b503b02e9e4 Mon Sep 17 00:00:00 2001 From: nepiedg Date: Sun, 26 Apr 2026 22:05:21 +0800 Subject: [PATCH] refactor: trim unused smoke API fields --- app/smt/controller/v1/Smoke.php | 165 +------------------------------ app/smt/route/app.php | 8 -- app/smt/service/SmokeService.php | 94 +----------------- docs/smt_api.md | 9 +- route/app.php | 8 -- 5 files changed, 6 insertions(+), 278 deletions(-) diff --git a/app/smt/controller/v1/Smoke.php b/app/smt/controller/v1/Smoke.php index 3d73050..9d39858 100644 --- a/app/smt/controller/v1/Smoke.php +++ b/app/smt/controller/v1/Smoke.php @@ -44,51 +44,20 @@ class Smoke extends BaseController $homeSummary = $this->smokeService->getHomeSummary($uid, $now); $motivation = $this->smokeService->motivation($uid, $profileView['profile'], $now); - $adviceDate = Support::dateOnly($now->modify('-1 day')); - $adviceCard = [ - 'title' => '智能控烟建议', - 'date' => $adviceDate->format(Support::DATE_LAYOUT), - 'message' => '', - 'model' => '', - 'status' => 'empty', - ]; - - try { - $advice = $this->smokeAiService->getOrGenerateAdvice($user, $adviceDate, 'v2'); - $adviceCard['message'] = (string) ($advice['advice'] ?? ''); - $adviceCard['model'] = (string) ($advice['model'] ?? ''); - $adviceCard['status'] = 'available'; - } catch (\RuntimeException $e) { - if ($e->getCode() === 403) { - $adviceCard['status'] = 'locked'; - } elseif ($e->getCode() === 400) { - $adviceCard['status'] = 'no_data'; - } else { - $adviceCard['status'] = 'unavailable'; - } - } - $timer = [ - 'label' => '距上次抽烟', - 'last_smoke_at' => (string) ($homeSummary['last_smoke_at'] ?? ''), 'seconds_since_last' => (int) ($homeSummary['seconds_since_last'] ?? -1), 'next_suggested_at' => (string) ($defaultSuggestion['next_smoke_at'] ?? ''), 'next_suggested_clock' => Support::formatClock((string) ($defaultSuggestion['next_smoke_at'] ?? '')), - 'not_before_at' => (string) ($defaultSuggestion['next_smoke_at'] ?? ''), 'suggestion_source' => 'default', - 'suggestion_algorithm' => (string) ($defaultSuggestion['algorithm'] ?? ''), ]; $cachedAiNext = $this->smokeAiService->getCachedNextSmoke($user, $planDate, 'v1'); if ($cachedAiNext) { $timer['suggestion_source'] = 'ai'; - $timer['suggestion_algorithm'] = 'ai_next_smoke_v1'; $timer['next_suggested_at'] = (string) ($cachedAiNext['suggested_at'] ?? ''); $timer['next_suggested_clock'] = Support::formatClock((string) ($cachedAiNext['suggested_at'] ?? '')); - $timer['not_before_at'] = (string) ($cachedAiNext['not_before_at'] ?? ''); $timer['ai_time_nodes'] = $cachedAiNext['time_nodes'] ?? []; $timer['ai_advice'] = (string) ($cachedAiNext['advice'] ?? ''); - $timer['ai_model'] = (string) ($cachedAiNext['model'] ?? ''); } $dailySummaryRecord = $this->smokeAiService->getCachedByType($uid, SmokeAiService::TYPE_DAILY_SUMMARY, $planDate, 'v1'); @@ -103,14 +72,6 @@ class Smoke extends BaseController } return Response::success([ - 'greeting' => $this->buildGreeting((string) ($user['nickname'] ?? ''), (string) ($user['avatar_url'] ?? ''), $now), - 'profile' => $profileView, - 'advice_card' => $adviceCard, - 'campaign_card' => [ - 'title' => '绿色生活,从戒烟开始', - 'subtitle' => 'BRAND CAMPAIGN', - 'badge' => '广告', - ], 'timer' => $timer, 'summary' => [ 'today_count' => (int) ($homeSummary['today_count'] ?? 0), @@ -118,18 +79,9 @@ class Smoke extends BaseController 'resisted_count' => (int) ($homeSummary['resisted_count'] ?? 0), 'reduced_from_yesterday' => (int) ($homeSummary['reduced_from_yesterday'] ?? 0), 'exceeded_yesterday' => (bool) ($homeSummary['exceeded_yesterday'] ?? false), - 'profile_completed' => (bool) ($profileView['is_completed'] ?? false), ], 'daily_summary' => $dailySummary, 'motivation' => $motivation, - 'quick_actions' => [ - ['type' => 'log_smoke', 'title' => '记录抽烟', 'primary' => false], - ['type' => 'resist', 'title' => '想抽忍住了', 'primary' => true], - ], - 'data_sources' => [ - 'ai_advice_date' => $adviceDate->format(Support::DATE_LAYOUT), - 'plan_date' => $planDate->format(Support::DATE_LAYOUT), - ], ]); } catch (\Throwable $e) { return Response::error($e->getMessage(), $e->getCode() ?: 500); @@ -163,24 +115,6 @@ class Smoke extends BaseController } } - public function createResistedLog() - { - try { - return Response::success($this->smokeService->createLog($this->getCurrentSmtUserId(), $this->request->post(), true)); - } catch (\Throwable $e) { - return Response::error($e->getMessage(), $e->getCode() ?: 500); - } - } - - public function readLog(int $id) - { - try { - return Response::success($this->smokeService->getLog($this->getCurrentSmtUserId(), $id)); - } catch (\Throwable $e) { - return Response::error($e->getMessage(), $e->getCode() ?: 500); - } - } - public function logs() { try { @@ -190,15 +124,6 @@ class Smoke extends BaseController } } - public function latestLogs() - { - try { - return Response::success($this->smokeService->latestLogs($this->getCurrentSmtUserId(), (int) $this->request->get('limit', 20))); - } catch (\Throwable $e) { - return Response::error($e->getMessage(), $e->getCode() ?: 500); - } - } - public function updateLog(int $id) { try { @@ -217,15 +142,6 @@ class Smoke extends BaseController } } - public function dashboard() - { - try { - return Response::success($this->smokeService->dashboard($this->getCurrentSmtUserId(), $this->request->get())); - } catch (\Throwable $e) { - return Response::error($e->getMessage(), $e->getCode() ?: 500); - } - } - public function stats() { try { @@ -236,17 +152,7 @@ class Smoke extends BaseController } } - public function motivation() - { - try { - $uid = $this->getCurrentSmtUserId(); - return Response::success($this->smokeService->motivation($uid, $this->smokeService->getProfile($uid))); - } catch (\Throwable $e) { - return Response::error($e->getMessage(), $e->getCode() ?: 500); - } - } - - public function nextSmokeTime() + public function aiNextSmokeTime() { try { $user = $this->getCurrentSmtUser(); @@ -264,18 +170,11 @@ class Smoke extends BaseController $profileView = $this->smokeService->getProfileView($uid); $defaultSuggestion = $this->smokeService->getDefaultNextSuggestion($uid, $now, $planDate, $profileView); - $homeSummary = $this->smokeService->getHomeSummary($uid, $now); - $response = [ 'source' => 'default', - 'not_before_at' => (string) ($defaultSuggestion['next_smoke_at'] ?? ''), 'suggested_at' => (string) ($defaultSuggestion['next_smoke_at'] ?? ''), - 'last_smoke_at' => (string) ($homeSummary['last_smoke_at'] ?? ''), - 'today_count' => (int) ($homeSummary['today_count'] ?? 0), - 'resisted_count' => (int) ($homeSummary['resisted_count'] ?? 0), - 'reduced_from_yesterday' => (int) ($homeSummary['reduced_from_yesterday'] ?? 0), - 'exceeded_yesterday' => (bool) ($homeSummary['exceeded_yesterday'] ?? false), - 'default' => $defaultSuggestion, + 'time_nodes' => [], + 'advice' => '', ]; if ($mode !== 'default') { @@ -285,11 +184,9 @@ class Smoke extends BaseController if ($aiSuggestion) { $response['source'] = 'ai'; - $response['not_before_at'] = (string) ($aiSuggestion['not_before_at'] ?? ''); $response['suggested_at'] = (string) ($aiSuggestion['suggested_at'] ?? ''); $response['time_nodes'] = $aiSuggestion['time_nodes'] ?? []; $response['advice'] = (string) ($aiSuggestion['advice'] ?? ''); - $response['ai'] = $aiSuggestion; } } @@ -299,30 +196,6 @@ class Smoke extends BaseController } } - public function aiNextSmokeTime() - { - return $this->nextSmokeTime(); - } - - public function aiAdvice() - { - try { - $user = $this->getCurrentSmtUser(); - $date = !empty($this->request->get('date')) - ? Support::parseDate((string) $this->request->get('date'), 'date') - : Support::dateOnly(Support::now()->modify('-1 day')); - $record = $this->smokeAiService->getOrGenerateAdvice($user, $date, 'v2'); - - return Response::success([ - 'date' => (string) ($record['date'] ?? $date->format(Support::DATE_LAYOUT)), - 'advice' => (string) ($record['advice'] ?? ''), - 'model' => (string) ($record['model'] ?? ''), - ]); - } catch (\Throwable $e) { - return Response::error($e->getMessage(), $e->getCode() ?: 500); - } - } - public function unlockAiAdvice() { try { @@ -372,15 +245,6 @@ class Smoke extends BaseController } } - public function revokeShare(string $token) - { - try { - return Response::success($this->smokeService->revokeShare($this->getCurrentSmtUserId(), $token)); - } catch (\Throwable $e) { - return Response::error($e->getMessage(), $e->getCode() ?: 500); - } - } - public function generateQuitPlan() { try { @@ -458,27 +322,4 @@ class Smoke extends BaseController return Support::parseDate($value, 'date'); } - private function buildGreeting(string $nickname, string $avatarUrl, \DateTimeImmutable $now): array - { - $nickname = trim($nickname) !== '' ? trim($nickname) : '朋友'; - $hour = (int) $now->format('H'); - - if ($hour >= 5 && $hour < 11) { - [$timeOfDay, $title, $subtitle] = ['morning', '早安', '今天也是清爽的一天']; - } elseif ($hour >= 11 && $hour < 14) { - [$timeOfDay, $title, $subtitle] = ['noon', '午安', '补充水分和能量']; - } elseif ($hour >= 14 && $hour < 19) { - [$timeOfDay, $title, $subtitle] = ['afternoon', '下午好', '把烟瘾留在昨天']; - } else { - [$timeOfDay, $title, $subtitle] = ['evening', '晚上好', '今晚早点休息']; - } - - return [ - 'title' => $title . ',' . $nickname, - 'subtitle' => $subtitle, - 'nickname' => $nickname, - 'time_of_day' => $timeOfDay, - 'avatar_url' => $avatarUrl, - ]; - } } diff --git a/app/smt/route/app.php b/app/smt/route/app.php index 336262e..7b5d09b 100644 --- a/app/smt/route/app.php +++ b/app/smt/route/app.php @@ -23,25 +23,17 @@ Route::group('v1', function () { Route::get('smoke/home', [Smoke::class, 'home']); Route::get('smoke/profile', [Smoke::class, 'profile']); Route::post('smoke/profile', [Smoke::class, 'saveProfile']); - Route::get('smoke/next_smoke_time', [Smoke::class, 'nextSmokeTime']); - Route::get('smoke/dashboard', [Smoke::class, 'dashboard']); Route::get('smoke/stats', [Smoke::class, 'stats']); Route::post('smoke/logs', [Smoke::class, 'createLog']); - Route::post('smoke/logs/resisted', [Smoke::class, 'createResistedLog']); Route::get('smoke/logs', [Smoke::class, 'logs']); - Route::get('smoke/logs/latest', [Smoke::class, 'latestLogs']); - Route::get('smoke/logs/:id', [Smoke::class, 'readLog']); Route::post('smoke/logs/:id', [Smoke::class, 'updateLog']); Route::delete('smoke/logs/:id', [Smoke::class, 'deleteLog']); - Route::get('smoke/motivation', [Smoke::class, 'motivation']); - Route::get('smoke/ai/advice', [Smoke::class, 'aiAdvice']); Route::post('smoke/ai/advice_unlocks', [Smoke::class, 'unlockAiAdvice']); Route::get('smoke/ai/next_smoke_time', [Smoke::class, 'aiNextSmokeTime']); Route::get('smoke/ai/daily_summary', [Smoke::class, 'aiDailySummary']); Route::post('smoke/share', [Smoke::class, 'createShare']); - Route::post('smoke/share/:token/revoke', [Smoke::class, 'revokeShare']); Route::post('smoke/quit-plan/generate', [Smoke::class, 'generateQuitPlan']); Route::get('smoke/quit-plan', [Smoke::class, 'quitPlan']); diff --git a/app/smt/service/SmokeService.php b/app/smt/service/SmokeService.php index a820511..fae87b8 100644 --- a/app/smt/service/SmokeService.php +++ b/app/smt/service/SmokeService.php @@ -117,11 +117,8 @@ class SmokeService $smokeTime = Support::dateOnly(); } - $level = $resisted ? 0 : max(0, (int) ($data['level'] ?? 1)); $num = $resisted ? 0 : max(0, (int) ($data['num'] ?? 1)); - if (!$resisted && $num === 0) { - throw new \RuntimeException('num=0 请使用 /smoke/logs/resisted', 400); - } + $level = ($resisted || $num === 0) ? 0 : max(0, (int) ($data['level'] ?? 1)); $insertId = Db::connect('mysql')->name('fa_smoke_log')->insertGetId([ 'uid' => $userId, @@ -195,23 +192,6 @@ class SmokeService ]; } - public function latestLogs(int $userId, int $limit = 20): array - { - $limit = min(100, max(1, $limit)); - $rows = Db::connect('mysql')->name('fa_smoke_log') - ->where('uid', $userId) - ->whereRaw('(deletetime IS NULL OR deletetime = 0)') - ->orderRaw('COALESCE(smoke_at, FROM_UNIXTIME(createtime), smoke_time) DESC') - ->order('id', 'desc') - ->limit($limit) - ->select() - ->toArray(); - - return ['items' => array_map(static function ($row) { - return Support::formatLog($row); - }, $rows)]; - } - public function updateLog(int $userId, int $id, array $data): array { $this->getLog($userId, $id); @@ -267,61 +247,6 @@ class SmokeService return ['deleted' => true]; } - public function dashboard(int $userId, array $params = []): array - { - $now = Support::now(); - [$defaultStart, $defaultEnd] = Support::weekRange($now); - $start = !empty($params['start']) ? Support::parseDate((string) $params['start'], 'start') : $defaultStart; - $end = !empty($params['end']) ? Support::parseDate((string) $params['end'], 'end') : (!empty($params['start']) ? $start->modify('+6 day') : $defaultEnd); - if ($end < $start) { - throw new \RuntimeException('end 不能早于 start', 400); - } - - $rows = Db::connect('mysql')->name('fa_smoke_log') - ->field('smoke_time, SUM(num) AS total') - ->where('uid', $userId) - ->whereBetween('smoke_time', [$start->format(Support::DATE_LAYOUT), $end->format(Support::DATE_LAYOUT)]) - ->whereRaw('(deletetime IS NULL OR deletetime = 0)') - ->group('smoke_time') - ->select() - ->toArray(); - - $counts = []; - foreach ($rows as $row) { - $counts[(string) $row['smoke_time']] = (int) ($row['total'] ?? 0); - } - - $today = Support::dateOnly($now); - $todayKey = $today->format(Support::DATE_LAYOUT); - $todayCount = (int) Db::connect('mysql')->name('fa_smoke_log') - ->where('uid', $userId) - ->where('smoke_time', $todayKey) - ->whereRaw('(deletetime IS NULL OR deletetime = 0)') - ->sum('num'); - - $lastSmoke = $this->findLastActualSmoke($userId); - $minutesSinceLast = null; - if ($lastSmoke) { - $minutesSinceLast = max(0, (int) floor(($now->getTimestamp() - $lastSmoke->getTimestamp()) / 60)); - } - - $weekly = []; - for ($cursor = $start; $cursor <= $end; $cursor = $cursor->add(new DateInterval('P1D'))) { - $key = $cursor->format(Support::DATE_LAYOUT); - $weekly[] = [ - 'date' => $key, - 'count' => (int) ($counts[$key] ?? 0), - 'is_today' => $key === $todayKey, - ]; - } - - return [ - 'today_count' => $todayCount, - 'minutes_since_last' => $minutesSinceLast, - 'weekly' => $weekly, - ]; - } - public function getHomeSummary(int $userId, ?DateTimeImmutable $asOf = null): array { $asOf = $asOf ?: Support::now(); @@ -622,23 +547,6 @@ class SmokeService ]; } - public function revokeShare(int $userId, string $token): array - { - $share = SmokeShare::where('share_token', trim($token))->whereNull('deleted_at')->find(); - if (!$share) { - throw new \RuntimeException('分享不存在', 404); - } - if ((int) $share->uid !== $userId) { - throw new \RuntimeException('无权限操作该分享', 403); - } - - $share->revoked_at = Support::now()->format(Support::DATETIME_LAYOUT); - $share->updated_at = Support::now()->format(Support::DATETIME_LAYOUT); - $share->save(); - - return ['revoked' => true]; - } - private function formatProfileRow(array $row): array { return [ diff --git a/docs/smt_api.md b/docs/smt_api.md index aa6def3..7159675 100644 --- a/docs/smt_api.md +++ b/docs/smt_api.md @@ -10,22 +10,17 @@ - 更新用户资料:`PUT|POST /smt/v1/auth/profile` - 戒烟资料:`GET|POST /smt/v1/smoke/profile` - 抽烟记录:`/smt/v1/smoke/logs*` -- 首页、看板、统计、激励语: +- 首页与统计: - `GET /smt/v1/smoke/home` - - `GET /smt/v1/smoke/dashboard` - `GET /smt/v1/smoke/stats` - - `GET /smt/v1/smoke/motivation` - 下次抽烟建议: - - `GET /smt/v1/smoke/next_smoke_time` - `GET /smt/v1/smoke/ai/next_smoke_time` -- AI 建议与每日总结: - - `GET /smt/v1/smoke/ai/advice` +- AI 解锁与每日总结: - `POST /smt/v1/smoke/ai/advice_unlocks` - `GET /smt/v1/smoke/ai/daily_summary` - 分享: - `POST /smt/v1/smoke/share` - `GET /smt/v1/smoke/share/:token` - - `POST /smt/v1/smoke/share/:token/revoke` - 戒烟计划: - `POST /smt/v1/smoke/quit-plan/generate` - `GET /smt/v1/smoke/quit-plan` diff --git a/route/app.php b/route/app.php index e119efa..473aaed 100644 --- a/route/app.php +++ b/route/app.php @@ -33,25 +33,17 @@ Route::group('api/v1', function () { Route::get('smoke/home', [Smoke::class, 'home']); Route::get('smoke/profile', [Smoke::class, 'profile']); Route::post('smoke/profile', [Smoke::class, 'saveProfile']); - Route::get('smoke/next_smoke_time', [Smoke::class, 'nextSmokeTime']); - Route::get('smoke/dashboard', [Smoke::class, 'dashboard']); Route::get('smoke/stats', [Smoke::class, 'stats']); Route::post('smoke/logs', [Smoke::class, 'createLog']); - Route::post('smoke/logs/resisted', [Smoke::class, 'createResistedLog']); Route::get('smoke/logs', [Smoke::class, 'logs']); - Route::get('smoke/logs/latest', [Smoke::class, 'latestLogs']); - Route::get('smoke/logs/:id', [Smoke::class, 'readLog']); Route::post('smoke/logs/:id', [Smoke::class, 'updateLog']); Route::delete('smoke/logs/:id', [Smoke::class, 'deleteLog']); - Route::get('smoke/motivation', [Smoke::class, 'motivation']); - Route::get('smoke/ai/advice', [Smoke::class, 'aiAdvice']); Route::post('smoke/ai/advice_unlocks', [Smoke::class, 'unlockAiAdvice']); Route::get('smoke/ai/next_smoke_time', [Smoke::class, 'aiNextSmokeTime']); Route::get('smoke/ai/daily_summary', [Smoke::class, 'aiDailySummary']); Route::post('smoke/share', [Smoke::class, 'createShare']); - Route::post('smoke/share/:token/revoke', [Smoke::class, 'revokeShare']); Route::post('smoke/quit-plan/generate', [Smoke::class, 'generateQuitPlan']); Route::get('smoke/quit-plan', [Smoke::class, 'quitPlan']);