auth->id; $binds = Db::name('family_bind') ->where('user_id', $userId) ->where('status', 'normal') ->order('id', 'desc') ->select(); $this->success('', [ 'binds' => array_map([$this, 'formatBind'], $binds), 'max' => self::MAX_BIND, 'can_invite' => count($binds) < self::MAX_BIND, 'points' => $this->pointsData($userId), 'scripts' => ContentService::lists($userId, ['type' => 'care', 'limit' => 3]), 'care_today' => $this->careToday($userId), 'member' => MemberService::status($userId), 'script_locked' => !MemberService::can($userId, 'family.script.full'), ]); } /** * 生成邀请(二维码/链接) * POST relation=partner|parent|friend, member_name */ public function invite() { $userId = $this->auth->id; $count = Db::name('family_bind') ->where('user_id', $userId) ->whereIn('status', ['pending', 'normal']) ->count(); if ($count >= self::MAX_BIND) { $this->error('最多绑定 ' . self::MAX_BIND . ' 位家人'); } $relation = $this->request->post('relation', 'partner'); if (!in_array($relation, ['partner', 'parent', 'friend'], true)) { $relation = 'partner'; } $code = strtoupper(Random::alnum(8)); $id = Db::name('family_bind')->insertGetId([ 'user_id' => $userId, 'member_name' => mb_substr((string)$this->request->post('member_name', ''), 0, 30), 'relation' => $relation, 'scope' => 'remind,care', 'invite_code' => $code, 'status' => 'pending', 'createtime' => time(), 'updatetime' => time(), ]); $this->success('邀请已生成', [ 'id' => (int)$id, 'invite_code' => $code, 'invite_text' => '邀请你成为我花期里的守护者,绑定码:' . $code, 'expire_days' => 7, ]); } /** * 确认绑定(家人端输入邀请码) * POST invite_code */ public function confirm() { $userId = $this->auth->id; $code = strtoupper(trim((string)$this->request->post('invite_code', ''))); if (!$code) { $this->error('请输入绑定码'); } $bind = Db::name('family_bind')->where('invite_code', $code)->find(); if (!$bind) { $this->error('绑定码不存在或已失效'); } if ((int)$bind['user_id'] === (int)$userId) { $this->error('不能与自己绑定'); } if ($bind['status'] === 'normal') { $this->error('该邀请已被使用'); } if ($bind['createtime'] < time() - 7 * 86400) { $this->error('绑定码已过期,请让对方重新生成'); } Db::name('family_bind')->where('id', $bind['id'])->update([ 'member_user_id' => $userId, 'status' => 'normal', 'confirm_time' => time(), 'updatetime' => time(), ]); $this->success('绑定成功', ['bind_id' => (int)$bind['id']]); } /** * 解绑 */ public function remove() { $id = (int)$this->request->post('id', 0); $row = Db::name('family_bind') ->where('id', $id) ->where(function ($query) { $query->where('user_id', $this->auth->id)->whereOr('member_user_id', $this->auth->id); }) ->find(); if (!$row) { $this->error('绑定不存在'); } Db::name('family_bind')->where('id', $id)->update(['status' => 'removed', 'updatetime' => time()]); $this->success('已解绑,对方将无法再看到你的提醒'); } /** * 话术库(暖心话术,完整库为会员权益) */ public function scripts() { $isMember = MemberService::can($this->auth->id, 'family.script.full'); $data = ContentService::lists($this->auth->id, ['type' => 'care', 'limit' => $isMember ? 30 : 4]); $data['locked'] = !$isMember; $data['tip'] = $isMember ? '' : '开通会员可查看完整话术库'; $this->success('', $data); } /** * 沟通空间:留言列表 * GET bind_id */ public function messages() { $bindId = (int)$this->request->param('bind_id', 0); $bind = $this->checkBind($bindId); $list = Db::name('care_message') ->where('bind_id', $bind['id']) ->order('id', 'desc') ->limit(50) ->select(); $list = array_map(function ($row) { return [ 'id' => (int)$row['id'], 'type' => $row['type'], 'content' => $row['content'], 'mine' => (int)$row['user_id'] === (int)$this->auth->id, 'time_text' => date('m-d H:i', (int)$row['createtime']), ]; }, $list); $this->success('', ['bind' => $this->formatBind($bind), 'list' => array_reverse($list)]); } /** * 沟通空间:发送留言 */ public function messageSend() { $bindId = (int)$this->request->post('bind_id', 0); $bind = $this->checkBind($bindId); $content = mb_substr(trim((string)$this->request->post('content', '')), 0, 500); if (!$content) { $this->error('留言不能为空'); } $id = Db::name('care_message')->insertGetId([ 'bind_id' => $bind['id'], 'user_id' => $this->auth->id, 'type' => 'text', 'content' => $content, 'createtime' => time(), ]); $this->success('已发送', ['id' => (int)$id]); } /** * 记录一次关怀行动(每日一次,+2 积分) */ public function careAction() { $userId = $this->auth->id; if ($this->careToday($userId)) { $this->success('今天已经记录过关怀啦', ['points' => $this->pointsData($userId)]); } Db::name('point_log')->insert([ 'user_id' => $userId, 'action' => 'care_daily', 'point' => 2, 'ref_id' => 0, 'remark' => '今日关怀行动', 'createtime' => time(), ]); $this->success('+2 爱心积分', ['points' => $this->pointsData($userId)]); } /** * 积分明细 */ public function points() { $userId = $this->auth->id; $log = Db::name('point_log') ->where('user_id', $userId) ->order('id', 'desc') ->limit(30) ->select(); $list = array_map(function ($row) { return [ 'id' => (int)$row['id'], 'action' => $row['action'], 'point' => (int)$row['point'], 'remark' => $row['remark'], 'date' => date('Y-m-d H:i', (int)$row['createtime']), ]; }, $log); $this->success('', ['points' => $this->pointsData($userId), 'list' => $list]); } /** * 家庭健康视图:谁在看护、当前阶段、共享待办 */ public function healthView() { $userId = $this->auth->id; $cycle = CycleService::current($userId); $binds = Db::name('family_bind') ->where(function ($query) use ($userId) { $query->where('user_id', $userId)->whereOr('member_user_id', $userId); }) ->where('status', 'normal') ->select(); $tasks = Db::name('task') ->where('user_id', $userId) ->where('scope', 'family') ->whereNull('deletetime') ->where('done', 0) ->select(); $this->success('', [ 'cycle' => [ 'has_data' => $cycle['has_data'], 'phase_text' => $cycle['phase_text'], 'day' => $cycle['day'], 'next_start' => $cycle['next_start'], 'days_to_next' => $cycle['days_to_next'], ], 'caregivers' => array_map([$this, 'formatBind'], $binds), 'tasks' => array_map(function ($row) { return ['id' => (int)$row['id'], 'title' => $row['title'], 'due_date' => $row['due_date']]; }, $tasks), 'privacy_note' => '家人仅可见阶段与提醒,看不到你的原始症状与情绪日记', ]); } // ---------------- 内部方法 ---------------- protected function checkBind($bindId) { $userId = $this->auth->id; $bind = Db::name('family_bind') ->where('id', $bindId) ->where('status', 'normal') ->where(function ($query) use ($userId) { $query->where('user_id', $userId)->whereOr('member_user_id', $userId); }) ->find(); if (!$bind) { $this->error('绑定关系不存在或已解除'); } return $bind; } protected function formatBind($row) { $relationText = ['partner' => '伴侣', 'parent' => '父母', 'friend' => '朋友']; return [ 'id' => (int)$row['id'], 'name' => $row['member_name'] ?: '待确认', 'relation' => $row['relation'], 'relation_text' => isset($relationText[$row['relation']]) ? $relationText[$row['relation']] : '家人', 'scope' => $row['scope'], 'status' => $row['status'], 'invite_code' => $row['status'] === 'pending' ? $row['invite_code'] : '', 'confirmed' => $row['status'] === 'normal', ]; } protected function pointsData($userId) { $total = (int)Db::name('point_log')->where('user_id', $userId)->sum('point'); $todayStart = strtotime(date('Y-m-d')); $today = (int)Db::name('point_log')->where('user_id', $userId)->where('createtime', '>=', $todayStart)->sum('point'); return [ 'total' => $total, 'today' => $today, 'can_earn' => $this->careToday($userId) ? 0 : 2, 'rules' => ['每日关怀行动 +2', '完成备孕任务 +2', '连续陪伴 7 天 +10'], ]; } protected function careToday($userId) { return Db::name('point_log') ->where('user_id', $userId) ->where('action', 'care_daily') ->where('createtime', '>=', strtotime(date('Y-m-d'))) ->count() > 0; } }