0 为用户专属通知,支持物理或软删除(deletetime)。 * - user_id = 0 为全站系统广播,利用 read_uids 和 deleted_uids 支持多用户独立已读与独立清理,互不影响。 */ class Message extends V1 { /** * M1 消息列表 * GET /api/v1/message/list 入参 {type?,page,size} * → 分页 {list:[{id,type,title,content,read,createdAt}],page,size,total,hasMore} * * @return void */ public function list() { $user = $this->auth(); $uid = (int)$user['id']; $type = $this->input('type', ''); // 闭包重建查询:TP5.0 的 count() 会清空 Query::options,不能复用同一对象 list($rows, $total, $page, $size) = $this->pageQuery(function ($forCount) use ($uid, $type) { $q = Db::name('fc_message') ->whereNull('deletetime') ->where(function ($sub) use ($uid) { $sub->where('user_id', $uid) ->whereOr(function ($sub2) use ($uid) { $sub2->where('user_id', 0) ->whereRaw("NOT FIND_IN_SET('{$uid}', IFNULL(deleted_uids, ''))"); }); }); if ($type !== '' && $type !== null && $type !== 'all') { $q->where('type', $type); } if ($forCount) { return $q; } return $q->order('createtime desc'); }); $list = []; foreach ($rows as $row) { // 计算当前用户下的已读状态(广播消息匹配 read_uids 集合) $isRead = false; if ((int)$row['user_id'] === $uid) { $isRead = (bool)(int)$row['isread']; } else { $readUids = array_filter(explode(',', (string)$row['read_uids'])); $isRead = (bool)(int)$row['isread'] || in_array((string)$uid, $readUids); } $list[] = [ 'id' => (int)$row['id'], 'type' => (string)$row['type'], 'title' => (string)$row['title'], 'content' => (string)$row['content'], 'read' => $isRead, 'createdAt' => $this->iso($row['createtime']), ]; } $this->ok($this->paginate($list, $total, $page, $size)); } /** * M2 标记单条已读 * POST /api/v1/message/:id/read → {read:true} * * @return void */ public function read() { $user = $this->auth(); $uid = (int)$user['id']; $id = (int)$this->request->param('id', 0); $msg = Db::name('fc_message')->where('id', $id)->whereNull('deletetime')->find(); if (!$msg) { $this->fail(404, '消息不存在或已删除'); } $now = time(); if ((int)$msg['user_id'] === $uid) { Db::name('fc_message')->where('id', $id)->update([ 'isread' => 1, 'readtime' => $now, 'updatetime' => $now, ]); } elseif ((int)$msg['user_id'] === 0) { // 系统广播:维护用户级已读集合 read_uids $readUids = array_filter(explode(',', (string)$msg['read_uids'])); if (!in_array((string)$uid, $readUids)) { $readUids[] = (string)$uid; Db::name('fc_message')->where('id', $id)->update([ 'read_uids' => implode(',', array_unique($readUids)), 'updatetime' => $now, ]); } } else { $this->fail(403, '无权操作此消息'); } $this->ok(['read' => true]); } /** * M3 未读消息数(首页消息角标) * GET /api/v1/message/unread-count → {count} * 规则:统计个人专属未读数 + 全体广播中未被当前用户读取的有效条数 * * @return void */ public function unreadCount() { $user = $this->auth(); $uid = (int)$user['id']; // 1. 专属个人消息未读数 $userCount = (int)Db::name('fc_message') ->where('user_id', $uid) ->where('isread', 0) ->whereNull('deletetime') ->count(); // 2. 系统广播未读数 $broadcastMsgs = Db::name('fc_message') ->where('user_id', 0) ->whereNull('deletetime') ->select(); $broadcastCount = 0; foreach ($broadcastMsgs as $b) { $deletedUids = array_filter(explode(',', (string)$b['deleted_uids'])); if (in_array((string)$uid, $deletedUids)) { continue; // 用户已删除该广播 } if ((int)$b['isread'] === 1) { continue; // 广播全局标记已读 } $readUids = array_filter(explode(',', (string)$b['read_uids'])); if (!in_array((string)$uid, $readUids)) { $broadcastCount++; } } $this->ok(['count' => $userCount + $broadcastCount]); } /** * M4 一键已读 * POST /api/v1/message/read-all 入参 {type?} * 规则:将当前分类下的专属未读消息及有效广播全部标记为已读 * * @return void */ public function readAll() { $user = $this->auth(); $uid = (int)$user['id']; $type = $this->input('type', ''); $now = time(); // 1. 批量标记专属个人消息 $q = Db::name('fc_message') ->where('user_id', $uid) ->where('isread', 0) ->whereNull('deletetime'); if ($type !== '' && $type !== null && $type !== 'all') { $q->where('type', $type); } $affected = $q->update([ 'isread' => 1, 'readtime' => $now, 'updatetime' => $now, ]); // 2. 批量将有效系统广播加入当前用户已读 $broadQ = Db::name('fc_message')->where('user_id', 0)->whereNull('deletetime'); if ($type !== '' && $type !== null && $type !== 'all') { $broadQ->where('type', $type); } $broadcasts = $broadQ->select(); foreach ($broadcasts as $b) { $delUids = array_filter(explode(',', (string)$b['deleted_uids'])); if (in_array((string)$uid, $delUids)) { continue; } $readUids = array_filter(explode(',', (string)$b['read_uids'])); if (!in_array((string)$uid, $readUids)) { $readUids[] = (string)$uid; Db::name('fc_message')->where('id', $b['id'])->update([ 'read_uids' => implode(',', array_unique($readUids)), 'updatetime' => $now, ]); $affected++; } } $this->ok(['success' => true, 'affected' => (int)$affected]); } /** * M5 一键清理 * POST /api/v1/message/clear 入参 {type?} * 规则:对专属通知执行软删除(deletetime);对广播消息记录当前用户已删除集合(deleted_uids) * * @return void */ public function clear() { $user = $this->auth(); $uid = (int)$user['id']; $type = $this->input('type', ''); $now = time(); // 1. 专属消息软删除 $q = Db::name('fc_message')->where('user_id', $uid)->whereNull('deletetime'); if ($type !== '' && $type !== null && $type !== 'all') { $q->where('type', $type); } $affected = $q->update([ 'deletetime' => $now, 'updatetime' => $now, ]); // 2. 广播消息:将 uid 追加到 deleted_uids $broadQ = Db::name('fc_message')->where('user_id', 0)->whereNull('deletetime'); if ($type !== '' && $type !== null && $type !== 'all') { $broadQ->where('type', $type); } $broadcasts = $broadQ->select(); foreach ($broadcasts as $b) { $delUids = array_filter(explode(',', (string)$b['deleted_uids'])); if (!in_array((string)$uid, $delUids)) { $delUids[] = (string)$uid; Db::name('fc_message')->where('id', $b['id'])->update([ 'deleted_uids' => implode(',', array_unique($delUids)), 'updatetime' => $now, ]); $affected++; } } $this->ok(['success' => true, 'affected' => (int)$affected]); } /** * M6 删除单条消息 * POST /api/v1/message/:id/delete * 规则:对专属消息软删除(deletetime);对广播消息加入 deleted_uids * * @return void */ public function delete() { $user = $this->auth(); $uid = (int)$user['id']; $id = (int)$this->request->param('id', 0); $now = time(); $msg = Db::name('fc_message')->where('id', $id)->whereNull('deletetime')->find(); if (!$msg) { $this->fail(404, '消息不存在或已删除'); } if ((int)$msg['user_id'] === $uid) { // 专属个人消息执行软删除 Db::name('fc_message')->where('id', $id)->update([ 'deletetime' => $now, 'updatetime' => $now, ]); } elseif ((int)$msg['user_id'] === 0) { // 广播消息:记录已删除该消息的用户 UID $delUids = array_filter(explode(',', (string)$msg['deleted_uids'])); if (!in_array((string)$uid, $delUids)) { $delUids[] = (string)$uid; Db::name('fc_message')->where('id', $id)->update([ 'deleted_uids' => implode(',', array_unique($delUids)), 'updatetime' => $now, ]); } } else { $this->fail(403, '无权操作此消息'); } $this->ok(['success' => true]); } }