auth->id; $baby = Db::name('baby')->where('user_id', $userId)->where('status', 'normal')->order('id', 'desc')->find(); $monthAge = $baby ? $this->monthAge($baby) : null; $this->success('', [ 'baby' => $this->formatBaby($baby), 'month_age' => $monthAge, 'activities' => ContentService::lists($userId, ['type' => 'activity', 'limit' => 6])['list'], 'courses' => ['list' => $this->coursesData()], 'co_tasks' => $this->coTasksData(), 'emotions' => ContentService::lists($userId, ['type' => 'emotion', 'limit' => 4])['list'], 'vaccines' => $this->vaccinePlan($baby), 'growth' => $this->growthListData($baby), 'assessments' => AssessmentService::lists('parenting', $userId), ]); } /** * 宝宝档案 */ public function babyInfo() { $baby = Db::name('baby')->where('user_id', $this->auth->id)->where('status', 'normal')->order('id', 'desc')->find(); $this->success('', ['baby' => $this->formatBaby($baby), 'month_age' => $baby ? $this->monthAge($baby) : null]); } public function babySave() { $userId = $this->auth->id; $data = [ 'user_id' => $userId, 'nickname' => mb_substr((string)$this->request->post('nickname', '宝宝'), 0, 30), 'gender' => min(2, max(0, (int)$this->request->post('gender', 0))), 'status' => 'normal', ]; $birthday = (string)$this->request->post('birthday', ''); $dueDate = (string)$this->request->post('due_date', ''); if ($birthday && strtotime($birthday)) { $data['birthday'] = date('Y-m-d', strtotime($birthday)); } if ($dueDate && strtotime($dueDate)) { $data['due_date'] = date('Y-m-d', strtotime($dueDate)); } $exist = Db::name('baby')->where('user_id', $userId)->where('status', 'normal')->find(); if ($exist) { Db::name('baby')->where('id', $exist['id'])->update($data); $id = $exist['id']; } else { $data['createtime'] = time(); $id = Db::name('baby')->insertGetId($data); } $baby = Db::name('baby')->where('id', $id)->find(); $this->success('已保存', ['baby' => $this->formatBaby($baby), 'month_age' => $this->monthAge($baby)]); } /** * 成长记录 */ protected function growthListData($baby = null) { if (!$baby) { $baby = Db::name('baby')->where('user_id', $this->auth->id)->where('status', 'normal')->order('id', 'desc')->find(); } if (!$baby) { return []; } $rows = Db::name('growth_record') ->where('baby_id', $baby['id']) ->order('record_date', 'desc') ->limit(30) ->select(); return array_map(function ($row) { return [ 'id' => (int)$row['id'], 'record_date' => $row['record_date'], 'height' => $row['height'] !== null ? (float)$row['height'] : null, 'weight' => $row['weight'] !== null ? (float)$row['weight'] : null, 'milestone' => $row['milestone'], 'note' => $row['note'], ]; }, $rows); } public function growthSave() { $userId = $this->auth->id; $baby = Db::name('baby')->where('user_id', $userId)->where('status', 'normal')->order('id', 'desc')->find(); if (!$baby) { $this->error('请先创建宝宝档案'); } $date = (string)$this->request->post('record_date', date('Y-m-d')); if (!strtotime($date)) { $this->error('日期格式不正确'); } $height = $this->request->post('height', ''); $weight = $this->request->post('weight', ''); Db::name('growth_record')->insert([ 'user_id' => $userId, 'baby_id' => $baby['id'], 'record_date' => $date, 'height' => is_numeric($height) ? round((float)$height, 1) : null, 'weight' => is_numeric($weight) ? round((float)$weight, 2) : null, 'milestone' => mb_substr((string)$this->request->post('milestone', ''), 0, 100), 'note' => mb_substr((string)$this->request->post('note', ''), 0, 300), 'createtime' => time(), ]); $this->success('已记录', ['list' => $this->growthListData($baby)]); } /** * 亲子活动(按月龄匹配) */ public function activities() { $userId = $this->auth->id; $baby = Db::name('baby')->where('user_id', $userId)->where('status', 'normal')->order('id', 'desc')->find(); $monthAge = $baby ? $this->monthAge($baby) : null; $data = ContentService::lists($userId, ['type' => 'activity', 'limit' => 30]); if ($monthAge !== null) { $matched = array_values(array_filter($data['list'], function ($item) use ($monthAge) { $extra = $item['extra'] ?: []; $from = isset($extra['month_from']) ? (int)$extra['month_from'] : 0; $to = isset($extra['month_to']) ? (int)$extra['month_to'] : 999; return $monthAge >= $from && $monthAge <= $to; })); if ($matched) { $data['list'] = $matched; } $data['matched_by_age'] = count($matched) > 0; } $data['month_age'] = $monthAge; $this->success('', $data); } /** * 课程 */ public function courses() { $list = $this->coursesData(); $this->success('', ['list' => $list, 'total' => count($list)]); } protected function coursesData() { $data = ContentService::lists($this->auth->id, ['type' => 'course', 'part' => 'parenting', 'limit' => 30]); return $data['list']; } /** * 共育任务 */ public function coTasks() { $this->success('', ['list' => $this->coTasksData()]); } protected function coTasksData() { $rows = Db::name('task') ->where('user_id', $this->auth->id) ->where('scope', 'parenting') ->whereNull('deletetime') ->order('done asc, id desc') ->select(); return array_map(function ($row) { return [ 'id' => (int)$row['id'], 'title' => $row['title'], 'category' => $row['category'], 'done' => (int)$row['done'], 'share_partner' => (int)$row['share_partner'], ]; }, $rows); } public function coTaskSave() { $userId = $this->auth->id; $title = mb_substr(trim((string)$this->request->post('title', '')), 0, 80); if (!$title) { $this->error('请填写任务内容'); } $id = Db::name('task')->insertGetId([ 'user_id' => $userId, 'scope' => 'parenting', 'title' => $title, 'category' => $this->request->post('category', 'care'), 'share_partner' => 1, 'createtime' => time(), 'updatetime' => time(), ]); $this->success('已添加', ['id' => (int)$id, 'list' => $this->coTasksData()]); } public function coTaskDone() { $id = (int)$this->request->post('id', 0); $row = Db::name('task') ->where('id', $id) ->where('user_id', $this->auth->id) ->where('scope', 'parenting') ->find(); if (!$row) { $this->error('任务不存在'); } $done = $row['done'] ? 0 : 1; Db::name('task')->where('id', $id)->update([ 'done' => $done, 'done_time' => $done ? time() : null, 'updatetime' => time(), ]); $this->success($done ? '已完成' : '已取消', ['done' => $done, 'list' => $this->coTasksData()]); } /** * 育儿情绪 */ public function emotions() { $this->success('', ContentService::lists($this->auth->id, ['type' => 'emotion', 'limit' => 30])); } /** * 疫苗与儿保计划(按宝宝生日推算) */ public function vaccines() { $baby = Db::name('baby')->where('user_id', $this->auth->id)->where('status', 'normal')->order('id', 'desc')->find(); $this->success('', ['list' => $this->vaccinePlan($baby), 'baby' => $this->formatBaby($baby)]); } // ---------------- 内部方法 ---------------- protected function formatBaby($baby) { if (!$baby) { return null; } return [ 'id' => (int)$baby['id'], 'nickname' => $baby['nickname'], 'gender' => (int)$baby['gender'], 'birthday' => $baby['birthday'], 'due_date' => $baby['due_date'], 'is_pregnant' => empty($baby['birthday']) && !empty($baby['due_date']), ]; } /** * 月龄(孕期返回负数:距离预产期天数用于展示) */ protected function monthAge($baby) { if (!$baby) { return null; } if (!empty($baby['birthday'])) { $birth = strtotime($baby['birthday']); $now = strtotime(date('Y-m-d')); if ($now < $birth) { return 0; } return (int)floor(($now - $birth) / (30.44 * 86400)); } if (!empty($baby['due_date'])) { $days = (int)ceil((strtotime($baby['due_date']) - strtotime(date('Y-m-d'))) / 86400); return -max(1, $days); } return null; } protected function vaccinePlan($baby) { $list = Db::name('vaccine')->order('weigh', 'desc')->select(); $birthday = $baby && !empty($baby['birthday']) ? strtotime($baby['birthday']) : null; $today = strtotime(date('Y-m-d')); $result = []; foreach ($list as $item) { $dueDate = $birthday ? date('Y-m-d', strtotime('+' . (int)$item['month_from'] . ' month', $birthday)) : null; $days = $dueDate ? (int)ceil((strtotime($dueDate) - $today) / 86400) : null; $result[] = [ 'id' => (int)$item['id'], 'name' => $item['name'], 'type' => $item['type'], 'month_from' => (int)$item['month_from'], 'note' => $item['note'], 'due_date' => $dueDate, 'days_left' => $days, 'status' => $days === null ? 'unknown' : ($days < 0 ? 'overdue' : ($days <= 30 ? 'upcoming' : 'later')), ]; } return $result; } }