auth->id; $today = date('Y-m-d'); $hour = (int)date('H'); if ($hour < 6) { $greeting = '夜深了'; } elseif ($hour < 11) { $greeting = '早上好'; } elseif ($hour < 14) { $greeting = '中午好'; } elseif ($hour < 18) { $greeting = '下午好'; } else { $greeting = '晚上好'; } $cycle = CycleService::current($userId); $loggedToday = Db::name('cycle_log') ->where('user_id', $userId) ->where('log_date', $today) ->whereNull('deletetime') ->count() > 0; $this->success('', [ 'greeting' => $greeting, 'nickname' => $this->auth->nickname ?: '亲爱的', 'today' => $today, 'date_text' => date('n月j日') . ' ' . $this->weekText($today), 'cycle' => $cycle, 'logged_today' => $loggedToday, 'phase_tip' => $this->phaseTip($cycle), 'jijing' => $this->pickJijing($cycle['phase'], $today), 'reminders' => $this->reminders($cycle, $loggedToday), 'mood' => $this->moodSummary($userId), 'member' => MemberService::status($userId), ]); } /** * 按阶段/日期稳定挑选一条心语(同一天结果不变) */ protected function pickJijing($phase, $today) { $pool = Db::name('content') ->where('type', 'jijing') ->where('status', 'normal') ->where('verify', 'passed') ->order('weigh', 'desc') ->select(); if (!$pool) { return null; } $matched = []; foreach ($pool as $item) { $phases = array_filter(explode(',', $item['phase'])); if (!$phase || in_array('all', $phases) || in_array($phase, $phases)) { $matched[] = $item; } } if (!$matched) { $matched = $pool; } $index = crc32($today . ($phase ?: 'all')) % count($matched); $item = $matched[$index]; return [ 'id' => (int)$item['id'], 'title' => $item['title'], 'summary' => $item['summary'], 'body' => $item['body'], 'emoji' => $item['cover_emoji'], 'access' => $item['access'], ]; } /** * 阶段建议文案 */ protected function phaseTip($cycle) { if (!$cycle['has_data']) { return [ 'title' => '先记录一次经期', 'desc' => '记录后即可获得阶段预测与个性化建议', 'action' => '去记录', ]; } $map = [ 'menstrual' => ['keyword' => '这几天适合放慢节奏', 'desc' => '注意保暖、补铁,减少高强度运动'], 'follicular' => ['keyword' => '能量回升期', 'desc' => '精力与情绪较好,适合安排计划与运动'], 'ovulation' => ['keyword' => '易孕期', 'desc' => '宫颈黏液变清亮,注意私处清洁与补水'], 'luteal' => ['keyword' => '黄体期', 'desc' => '情绪易波动,优先睡眠与温热饮食'], ]; $tip = $map[$cycle['phase']] ?: $map['follicular']; return [ 'title' => $tip['keyword'], 'desc' => $tip['desc'], 'action' => '', ]; } /** * 今日提醒(由周期与记录状态推导,非冗余推送) */ protected function reminders($cycle, $loggedToday) { $list = []; if (!$loggedToday) { $list[] = [ 'type' => 'record', 'icon' => '✍️', 'title' => '今天还没有记录', 'desc' => '花 10 秒记录身体感受,预测会更准', ]; } if ($cycle['has_data']) { if ($cycle['is_period']) { $list[] = [ 'type' => 'care', 'icon' => '🌡', 'title' => '经期第 ' . $cycle['day'] . ' 天', 'desc' => '小腹保暖 + 温热饮食,避免冰饮', ]; } elseif ($cycle['is_fertile']) { $list[] = [ 'type' => 'fertile', 'icon' => '🌱', 'title' => '易孕期', 'desc' => '排卵期前后,注意休息与营养', ]; } elseif ($cycle['days_to_next'] !== null && $cycle['days_to_next'] <= 3 && $cycle['days_to_next'] >= 1) { $list[] = [ 'type' => 'period', 'icon' => '📅', 'title' => '经期还有 ' . $cycle['days_to_next'] . ' 天', 'desc' => '可以提前准备卫生用品与暖贴', ]; } elseif ($cycle['phase'] === 'luteal') { $list[] = [ 'type' => 'mood', 'icon' => '🍂', 'title' => '黄体期留意情绪', 'desc' => '敏感易累是生理性的,允许自己慢一点', ]; } } // 自定义提醒(吃药 / 记录 / 复诊等) $custom = Db::name('reminder') ->where('user_id', $this->auth->id) ->where('enabled', 1) ->whereNull('deletetime') ->order('remind_time', 'asc') ->select(); $today = date('Y-m-d'); foreach ($custom as $item) { if ($item['repeat_rule'] === 'once' && $item['remind_date'] !== $today) { continue; } $list[] = [ 'type' => $item['type'] ?: 'custom', 'icon' => '⏰', 'title' => $item['title'], 'desc' => substr($item['remind_time'], 0, 5) . ' 提醒', ]; } return $list; } /** * 近 7 天情绪概览 */ protected function moodSummary($userId) { $start = date('Y-m-d', strtotime('-6 day')); $logs = Db::name('mood_log') ->where('user_id', $userId) ->whereNull('deletetime') ->where('log_date', '>=', $start) ->order('log_date', 'asc') ->select(); $scoreMap = ['happy' => 5, 'calm' => 4, 'low' => 2, 'anxious' => 2, 'angry' => 1]; $days = []; for ($i = 6; $i >= 0; $i--) { $d = date('Y-m-d', strtotime('-' . $i . ' day')); $days[$d] = ['date' => $d, 'score' => null, 'mood' => '']; } foreach ($logs as $log) { if (isset($days[$log['log_date']])) { $days[$log['log_date']]['score'] = isset($scoreMap[$log['mood']]) ? $scoreMap[$log['mood']] : 3; $days[$log['log_date']]['mood'] = $log['mood']; } } $recorded = array_values(array_filter($days, function ($d) { return $d['score'] !== null; })); $avg = $recorded ? round(array_sum(array_column($recorded, 'score')) / count($recorded), 1) : 0; return [ 'days' => array_values($days), 'recorded' => count($recorded), 'avg_score' => $avg, 'today_mood' => isset($days[date('Y-m-d')]) ? $days[date('Y-m-d')]['mood'] : '', ]; } protected function weekText($date) { $weeks = ['日', '一', '二', '三', '四', '五', '六']; return '星期' . $weeks[(int)date('w', strtotime($date))]; } }