306 行
10 KiB
PHP
306 行
10 KiB
PHP
<?php
|
||
|
||
namespace app\api\controller;
|
||
|
||
use think\Db;
|
||
|
||
/**
|
||
* 用户端 · 消息中心(Module-MESSAGE)
|
||
* 路由:
|
||
* GET /api/v1/message/list M1 消息列表(支持个人消息与系统广播)
|
||
* POST /api/v1/message/:id/read M2 标记单条已读
|
||
* GET /api/v1/message/unread-count M3 未读消息数(首页角标统计)
|
||
* POST /api/v1/message/read-all M4 一键已读(批量标记)
|
||
* POST /api/v1/message/clear M5 一键清理(批量软删除/屏蔽)
|
||
* POST /api/v1/message/:id/delete M6 删除单条消息(软删除/屏蔽)
|
||
*
|
||
* 说明:
|
||
* - user_id > 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]);
|
||
}
|
||
}
|